//===----- HexagonMCShuffler.cpp - MC bundle shuffling --------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This implements the shuffling of insns inside a bundle according to the // packet formation rules of the Hexagon ISA. // //===----------------------------------------------------------------------===// #include "MCTargetDesc/HexagonMCShuffler.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 #define DEBUG_TYPE "hexagon-shuffle" using namespace llvm; static cl::opt 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(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(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 (auto &I : *this) { 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 ReportErrors, MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst &MCB) { HexagonMCShuffler MCS(Context, ReportErrors, 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 possibleDuplexes) { if (DisableShuffle || possibleDuplexes.size() == 0) 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 } return doneShuffling; } 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); }