| //===----- 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 "MCTargetDesc/HexagonMCShuffler.h" | |
| #include "Hexagon.h" | |
| #include "MCTargetDesc/HexagonMCInstrInfo.h" | |
| #include "MCTargetDesc/HexagonShuffler.h" | |
| #include "llvm/MC/MCInst.h" | |
| #include "llvm/MC/MCInstrDesc.h" | |
| #include "llvm/MC/MCInstrInfo.h" | |
| #include "llvm/Support/CommandLine.h" | |
| #include "llvm/Support/Debug.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| #include <cassert> | |
| 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)) { | |
| MCInst &MI = *const_cast<MCInst *>(I.getInst()); | |
| LLVM_DEBUG(dbgs() << "Shuffling: " << MCII.getName(MI.getOpcode()) | |
| << '\n'); | |
| assert(!HexagonMCInstrInfo::getDesc(MCII, MI).isPseudo()); | |
| if (!HexagonMCInstrInfo::isImmext(MI)) { | |
| append(MI, Extender, HexagonMCInstrInfo::getUnits(MCII, STI, MI)); | |
| Extender = nullptr; | |
| } else | |
| Extender = &MI; | |
| } | |
| } | |
| Loc = MCB.getLoc(); | |
| BundleFlags = MCB.getOperand(0).getImm(); | |
| } | |
| void HexagonMCShuffler::init(MCInst &MCB, MCInst const &AddMI, | |
| bool bInsertAtFront) { | |
| if (HexagonMCInstrInfo::isBundle(MCB)) { | |
| if (bInsertAtFront) | |
| append(AddMI, nullptr, HexagonMCInstrInfo::getUnits(MCII, STI, AddMI)); | |
| 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)); | |
| Extender = nullptr; | |
| } else | |
| Extender = &MI; | |
| } | |
| if (!bInsertAtFront) | |
| append(AddMI, nullptr, HexagonMCInstrInfo::getUnits(MCII, STI, AddMI)); | |
| } | |
| Loc = MCB.getLoc(); | |
| BundleFlags = MCB.getOperand(0).getImm(); | |
| } | |
| void HexagonMCShuffler::copyTo(MCInst &MCB) { | |
| MCB.clear(); | |
| MCB.addOperand(MCOperand::createImm(BundleFlags)); | |
| MCB.setLoc(Loc); | |
| // 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); | |
| return true; | |
| } | |
| LLVM_DEBUG(MCB.dump()); | |
| return false; | |
| } | |
| bool llvm::HexagonMCShuffle(MCContext &Context, bool Fatal, | |
| MCInstrInfo const &MCII, MCSubtargetInfo const &STI, | |
| MCInst &MCB) { | |
| HexagonMCShuffler MCS(Context, Fatal, MCII, STI, MCB); | |
| if (DisableShuffle) | |
| // Ignore if user chose so. | |
| return false; | |
| if (!HexagonMCInstrInfo::bundleSize(MCB)) { | |
| // There once was a bundle: | |
| // BUNDLE implicit-def %d2, implicit-def %r4, implicit-def %r5, | |
| // implicit-def %d7, ... | |
| // * %d2 = IMPLICIT_DEF; flags: | |
| // * %d7 = IMPLICIT_DEF; flags: | |
| // After the IMPLICIT_DEFs were removed by the asm printer, the bundle | |
| // became empty. | |
| LLVM_DEBUG(dbgs() << "Skipping empty bundle"); | |
| return false; | |
| } else if (!HexagonMCInstrInfo::isBundle(MCB)) { | |
| LLVM_DEBUG(dbgs() << "Skipping stand-alone insn"); | |
| return false; | |
| } | |
| return MCS.reshuffleTo(MCB); | |
| } | |
| bool | |
| llvm::HexagonMCShuffle(MCContext &Context, MCInstrInfo const &MCII, | |
| MCSubtargetInfo const &STI, MCInst &MCB, | |
| SmallVector<DuplexCandidate, 8> possibleDuplexes) { | |
| if (DisableShuffle) | |
| return false; | |
| if (!HexagonMCInstrInfo::bundleSize(MCB)) { | |
| // There once was a bundle: | |
| // BUNDLE implicit-def %d2, implicit-def %r4, implicit-def %r5, | |
| // implicit-def %d7, ... | |
| // * %d2 = IMPLICIT_DEF; flags: | |
| // * %d7 = IMPLICIT_DEF; flags: | |
| // After the IMPLICIT_DEFs were removed by the asm printer, the bundle | |
| // became empty. | |
| LLVM_DEBUG(dbgs() << "Skipping empty bundle"); | |
| return false; | |
| } else if (!HexagonMCInstrInfo::isBundle(MCB)) { | |
| LLVM_DEBUG(dbgs() << "Skipping stand-alone insn"); | |
| return false; | |
| } | |
| bool doneShuffling = false; | |
| while (possibleDuplexes.size() > 0 && (!doneShuffling)) { | |
| // case of Duplex Found | |
| DuplexCandidate duplexToTry = possibleDuplexes.pop_back_val(); | |
| MCInst Attempt(MCB); | |
| HexagonMCInstrInfo::replaceDuplex(Context, Attempt, duplexToTry); | |
| HexagonMCShuffler MCS(Context, false, MCII, STI, Attempt); // copy packet to the shuffler | |
| if (MCS.size() == 1) { // case of one duplex | |
| // copy the created duplex in the shuffler to the bundle | |
| MCS.copyTo(MCB); | |
| return false; | |
| } | |
| // try shuffle with this duplex | |
| doneShuffling = MCS.reshuffleTo(MCB); | |
| if (doneShuffling) | |
| break; | |
| } | |
| if (!doneShuffling) { | |
| HexagonMCShuffler MCS(Context, false, MCII, STI, MCB); | |
| doneShuffling = MCS.reshuffleTo(MCB); // shuffle | |
| } | |
| if (!doneShuffling) | |
| return true; | |
| return false; | |
| } | |
| bool llvm::HexagonMCShuffle(MCContext &Context, MCInstrInfo const &MCII, | |
| MCSubtargetInfo const &STI, MCInst &MCB, | |
| MCInst const &AddMI, int fixupCount) { | |
| if (!HexagonMCInstrInfo::isBundle(MCB)) | |
| 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; | |
| bool bhasDuplex = HexagonMCInstrInfo::hasDuplex(MCII, MCB); | |
| if (fixupCount >= 2) { | |
| if (bhasDuplex) { | |
| if (bundleSize >= HEXAGON_PACKET_SIZE - 1) { | |
| return false; | |
| } | |
| } else { | |
| return false; | |
| } | |
| } else { | |
| if (bundleSize == HEXAGON_PACKET_SIZE - 1 && fixupCount) | |
| return false; | |
| } | |
| if (DisableShuffle) | |
| return false; | |
| // mgl: temporary code (shuffler doesn't take into account the fact that | |
| // a duplex takes up two slots. for example, 3 nops can be put into a packet | |
| // containing a duplex oversubscribing slots by 1). | |
| unsigned maxBundleSize = (HexagonMCInstrInfo::hasImmExt(MCB)) | |
| ? HEXAGON_PACKET_SIZE | |
| : HEXAGON_PACKET_SIZE - 1; | |
| if (bhasDuplex && bundleSize >= maxBundleSize) | |
| return false; | |
| HexagonMCShuffler MCS(Context, false, MCII, STI, MCB, AddMI, false); | |
| return MCS.reshuffleTo(MCB); | |
| } |