summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCShuffler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCShuffler.cpp')
-rw-r--r--llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCShuffler.cpp181
1 files changed, 181 insertions, 0 deletions
diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCShuffler.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCShuffler.cpp
new file mode 100644
index 00000000000..1d38761e374
--- /dev/null
+++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCShuffler.cpp
@@ -0,0 +1,181 @@
+//===----- HexagonMCShuffler.cpp - MC bundle shuffling --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This implements the shuffling of insns inside a bundle according to the
+// packet formation rules of the Hexagon ISA.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "hexagon-shuffle"
+
+#include "Hexagon.h"
+#include "MCTargetDesc/HexagonMCInstrInfo.h"
+#include "MCTargetDesc/HexagonMCShuffler.h"
+#include "MCTargetDesc/HexagonMCTargetDesc.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+static cl::opt<bool>
+ DisableShuffle("disable-hexagon-shuffle", cl::Hidden, cl::init(false),
+ cl::desc("Disable Hexagon instruction shuffling"));
+
+void HexagonMCShuffler::init(MCInst &MCB) {
+ if (HexagonMCInstrInfo::isBundle(MCB)) {
+ MCInst const *Extender = nullptr;
+ // Copy the bundle for the shuffling.
+ for (const auto &I : HexagonMCInstrInfo::bundleInstructions(MCB)) {
+ assert(!HexagonMCInstrInfo::getDesc(MCII, *I.getInst()).isPseudo());
+ MCInst *MI = const_cast<MCInst *>(I.getInst());
+
+ if (!HexagonMCInstrInfo::isImmext(*MI)) {
+ append(MI, Extender, HexagonMCInstrInfo::getUnits(MCII, STI, *MI),
+ false);
+ Extender = nullptr;
+ } else
+ Extender = MI;
+ }
+ }
+
+ BundleFlags = MCB.getOperand(0).getImm();
+}
+
+void HexagonMCShuffler::init(MCInst &MCB, MCInst const *AddMI,
+ bool bInsertAtFront) {
+ if (HexagonMCInstrInfo::isBundle(MCB)) {
+ if (bInsertAtFront && AddMI)
+ append(AddMI, nullptr, HexagonMCInstrInfo::getUnits(MCII, STI, *AddMI),
+ false);
+ MCInst const *Extender = nullptr;
+ // Copy the bundle for the shuffling.
+ for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCB)) {
+ assert(!HexagonMCInstrInfo::getDesc(MCII, *I.getInst()).isPseudo());
+ MCInst *MI = const_cast<MCInst *>(I.getInst());
+ if (!HexagonMCInstrInfo::isImmext(*MI)) {
+ append(MI, Extender, HexagonMCInstrInfo::getUnits(MCII, STI, *MI),
+ false);
+ Extender = nullptr;
+ } else
+ Extender = MI;
+ }
+ if (!bInsertAtFront && AddMI)
+ append(AddMI, nullptr, HexagonMCInstrInfo::getUnits(MCII, STI, *AddMI),
+ false);
+ }
+
+ BundleFlags = MCB.getOperand(0).getImm();
+}
+
+void HexagonMCShuffler::copyTo(MCInst &MCB) {
+ MCB.clear();
+ MCB.addOperand(MCOperand::createImm(BundleFlags));
+ // Copy the results into the bundle.
+ for (HexagonShuffler::iterator I = begin(); I != end(); ++I) {
+
+ MCInst const *MI = I->getDesc();
+ MCInst const *Extender = I->getExtender();
+ if (Extender)
+ MCB.addOperand(MCOperand::createInst(Extender));
+ MCB.addOperand(MCOperand::createInst(MI));
+ }
+}
+
+bool HexagonMCShuffler::reshuffleTo(MCInst &MCB) {
+ if (shuffle()) {
+ // Copy the results into the bundle.
+ copyTo(MCB);
+ } else
+ DEBUG(MCB.dump());
+
+ return (!getError());
+}
+
+bool llvm::HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
+ MCInst &MCB) {
+ HexagonMCShuffler MCS(MCII, STI, MCB);
+
+ if (DisableShuffle)
+ // Ignore if user chose so.
+ return false;
+
+ if (!HexagonMCInstrInfo::bundleSize(MCB)) {
+ // There once was a bundle:
+ // BUNDLE %D2<imp-def>, %R4<imp-def>, %R5<imp-def>, %D7<imp-def>, ...
+ // * %D2<def> = IMPLICIT_DEF; flags:
+ // * %D7<def> = IMPLICIT_DEF; flags:
+ // After the IMPLICIT_DEFs were removed by the asm printer, the bundle
+ // became empty.
+ DEBUG(dbgs() << "Skipping empty bundle");
+ return false;
+ } else if (!HexagonMCInstrInfo::isBundle(MCB)) {
+ DEBUG(dbgs() << "Skipping stand-alone insn");
+ return false;
+ }
+
+ // Reorder the bundle and copy the result.
+ if (!MCS.reshuffleTo(MCB)) {
+ // Unless there is any error, which should not happen at this point.
+ unsigned shuffleError = MCS.getError();
+ switch (shuffleError) {
+ default:
+ llvm_unreachable("unknown error");
+ case HexagonShuffler::SHUFFLE_ERROR_INVALID:
+ llvm_unreachable("invalid packet");
+ case HexagonShuffler::SHUFFLE_ERROR_STORES:
+ llvm_unreachable("too many stores");
+ case HexagonShuffler::SHUFFLE_ERROR_LOADS:
+ llvm_unreachable("too many loads");
+ case HexagonShuffler::SHUFFLE_ERROR_BRANCHES:
+ llvm_unreachable("too many branches");
+ case HexagonShuffler::SHUFFLE_ERROR_NOSLOTS:
+ llvm_unreachable("no suitable slot");
+ case HexagonShuffler::SHUFFLE_ERROR_SLOTS:
+ llvm_unreachable("over-subscribed slots");
+ case HexagonShuffler::SHUFFLE_SUCCESS: // Single instruction case.
+ return true;
+ }
+ }
+
+ return true;
+}
+
+bool llvm::HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
+ MCInst &MCB, MCInst const *AddMI, int fixupCount) {
+ if (!HexagonMCInstrInfo::isBundle(MCB) || !AddMI)
+ return false;
+
+ // if fixups present, make sure we don't insert too many nops that would
+ // later prevent an extender from being inserted.
+ unsigned int bundleSize = HexagonMCInstrInfo::bundleSize(MCB);
+ if (bundleSize >= HEXAGON_PACKET_SIZE)
+ return false;
+ if (fixupCount >= 2) {
+ return false;
+ } else {
+ if (bundleSize == HEXAGON_PACKET_SIZE - 1 && fixupCount)
+ return false;
+ }
+
+ if (DisableShuffle)
+ return false;
+
+ HexagonMCShuffler MCS(MCII, STI, MCB, AddMI);
+ if (!MCS.reshuffleTo(MCB)) {
+ unsigned shuffleError = MCS.getError();
+ switch (shuffleError) {
+ default:
+ return false;
+ case HexagonShuffler::SHUFFLE_SUCCESS: // single instruction case
+ return true;
+ }
+ }
+
+ return true;
+}
OpenPOWER on IntegriCloud