| //===----- 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" |
| #include "llvm/Support/raw_ostream.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; |
| } |
| |
| unsigned |
| llvm::HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, |
| MCContext &Context, MCInst &MCB, |
| SmallVector<DuplexCandidate, 8> possibleDuplexes) { |
| |
| if (DisableShuffle) |
| return HexagonShuffler::SHUFFLE_SUCCESS; |
| |
| 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 HexagonShuffler::SHUFFLE_SUCCESS; |
| } else if (!HexagonMCInstrInfo::isBundle(MCB)) { |
| DEBUG(dbgs() << "Skipping stand-alone insn"); |
| return HexagonShuffler::SHUFFLE_SUCCESS; |
| } |
| |
| bool doneShuffling = false; |
| unsigned shuffleError; |
| 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(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); |
| doneShuffling = true; |
| return HexagonShuffler::SHUFFLE_SUCCESS; |
| } |
| // try shuffle with this duplex |
| doneShuffling = MCS.reshuffleTo(MCB); |
| shuffleError = MCS.getError(); |
| |
| if (doneShuffling) |
| break; |
| } |
| |
| if (doneShuffling == false) { |
| HexagonMCShuffler MCS(MCII, STI, MCB); |
| doneShuffling = MCS.reshuffleTo(MCB); // shuffle |
| shuffleError = MCS.getError(); |
| } |
| if (!doneShuffling) |
| return shuffleError; |
| |
| return HexagonShuffler::SHUFFLE_SUCCESS; |
| } |
| |
| 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; |
| } |