diff options
Diffstat (limited to 'llvm/lib/Target/Hexagon/MCTargetDesc')
17 files changed, 855 insertions, 456 deletions
diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp index 8f1e5c1c3a979..e7069819fa575 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp @@ -22,6 +22,7 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/EndianStream.h" #include "llvm/Support/TargetRegistry.h" #include <sstream> @@ -43,6 +44,7 @@ class HexagonAsmBackend : public MCAsmBackend { std::unique_ptr <MCInstrInfo> MCII; std::unique_ptr <MCInst *> RelaxTarget; MCInst * Extender; + unsigned MaxPacketSize; void ReplaceInstruction(MCCodeEmitter &E, MCRelaxableFragment &RF, MCInst &HMB) const { @@ -62,7 +64,8 @@ public: StringRef CPU) : MCAsmBackend(support::little), OSABI(OSABI), CPU(CPU), relaxedCnt(0), MCII(T.createMCInstrInfo()), RelaxTarget(new MCInst *), - Extender(nullptr) {} + Extender(nullptr), MaxPacketSize(HexagonMCInstrInfo::packetSize(CPU)) + {} std::unique_ptr<MCObjectTargetWriter> createObjectTargetWriter() const override { @@ -648,11 +651,12 @@ public: llvm_unreachable("Handled by fixupNeedsRelaxationAdvanced"); } - void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, - MCInst &Res) const override { + void relaxInstruction(MCInst &Inst, + const MCSubtargetInfo &STI) const override { assert(HexagonMCInstrInfo::isBundle(Inst) && "Hexagon relaxInstruction only works on bundles"); + MCInst Res; Res.setOpcode(Hexagon::BUNDLE); Res.addOperand(MCOperand::createImm(Inst.getOperand(0).getImm())); // Copy the results into the bundle. @@ -676,6 +680,8 @@ public: // now copy over the original instruction(the one we may have extended) Res.addOperand(MCOperand::createInst(I.getInst())); } + + Inst = std::move(Res); (void)Update; assert(Update && "Didn't find relaxation target"); } @@ -685,7 +691,7 @@ public: ParseIn = 0x00004000, // In packet parse-bits. ParseEnd = 0x0000c000; // End of packet parse-bits. - while(Count % HEXAGON_INSTR_SIZE) { + while (Count % HEXAGON_INSTR_SIZE) { LLVM_DEBUG(dbgs() << "Alignment not a multiple of the instruction size:" << Count % HEXAGON_INSTR_SIZE << "/" << HEXAGON_INSTR_SIZE << "\n"); @@ -693,11 +699,11 @@ public: OS << '\0'; } - while(Count) { + while (Count) { Count -= HEXAGON_INSTR_SIZE; // Close the packet whenever a multiple of the maximum packet size remains - uint32_t ParseBits = (Count % (HEXAGON_PACKET_SIZE * HEXAGON_INSTR_SIZE))? - ParseIn: ParseEnd; + uint32_t ParseBits = (Count % (MaxPacketSize * HEXAGON_INSTR_SIZE)) ? + ParseIn : ParseEnd; support::endian::write<uint32_t>(OS, Nopcode | ParseBits, Endian); } return true; @@ -728,7 +734,8 @@ public: MCContext &Context = Asm.getContext(); auto &RF = cast<MCRelaxableFragment>(*K); auto &Inst = const_cast<MCInst &>(RF.getInst()); - while (Size > 0 && HexagonMCInstrInfo::bundleSize(Inst) < 4) { + while (Size > 0 && + HexagonMCInstrInfo::bundleSize(Inst) < MaxPacketSize) { MCInst *Nop = new (Context) MCInst; Nop->setOpcode(Hexagon::A2_nop); Inst.addOperand(MCOperand::createInst(Nop)); diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h index 3c64893bae45e..4125566bc58a3 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h @@ -27,11 +27,6 @@ namespace HexagonII { unsigned const TypeCVI_FIRST = TypeCVI_4SLOT_MPY; unsigned const TypeCVI_LAST = TypeCVI_ZW; - enum SubTarget { - HasV55SubT = 0x3c, - HasV60SubT = 0x38, - }; - enum AddrMode { NoAddrMode = 0, // No addressing mode Absolute = 1, // Absolute addressing mode @@ -165,6 +160,9 @@ namespace HexagonII { CVINewPos = 62, CVINewMask = 0x1, + + isCVIPos = 63, + isCVIMask = 0x1, }; // *** The code above must match HexagonInstrFormat*.td *** // diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonELFObjectWriter.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonELFObjectWriter.cpp index cdbeae38b3a11..3dba6b07c4603 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonELFObjectWriter.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonELFObjectWriter.cpp @@ -64,7 +64,7 @@ unsigned HexagonELFObjectWriter::getRelocType(MCContext &Ctx, return ELF::R_HEX_IE_GOT_32; case MCSymbolRefExpr::VariantKind::VK_Hexagon_LD_GOT: return ELF::R_HEX_LD_GOT_32; - case MCSymbolRefExpr::VariantKind::VK_Hexagon_PCREL: + case MCSymbolRefExpr::VariantKind::VK_PCREL: return ELF::R_HEX_32_PCREL; case MCSymbolRefExpr::VariantKind::VK_TPREL: return ELF::R_HEX_TPREL_32; diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp index f3da675623209..e5e5d08937ef2 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp @@ -34,4 +34,5 @@ HexagonMCAsmInfo::HexagonMCAsmInfo(const Triple &TT) { UsesELFSectionDirectiveForBSS = true; ExceptionsType = ExceptionHandling::DwarfCFI; UseLogicalShr = false; + UseIntegratedAssembler = false; } diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.cpp index 8b262bd0248e0..fee1acdbbe8ab 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.cpp @@ -81,6 +81,9 @@ void HexagonMCChecker::initReg(MCInst const &MCI, unsigned R, unsigned &PredReg, if (!MCSubRegIterator(*SRI, &RI).isValid()) // Skip super-registers used indirectly. Uses.insert(*SRI); + + if (HexagonMCInstrInfo::IsReverseVecRegPair(R)) + ReversePairs.insert(R); } void HexagonMCChecker::init(MCInst const &MCI) { @@ -133,6 +136,9 @@ void HexagonMCChecker::init(MCInst const &MCI) { if (R == Hexagon::C8) R = Hexagon::USR; + if (HexagonMCInstrInfo::IsReverseVecRegPair(R)) + ReversePairs.insert(R); + // Note register definitions, direct ones as well as indirect side-effects. // Super-registers are not tracked directly, but their components. for (MCRegAliasIterator SRI(R, &RI, !MCSubRegIterator(R, &RI).isValid()); @@ -192,7 +198,7 @@ HexagonMCChecker::HexagonMCChecker(MCContext &Context, MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst &mcb, MCRegisterInfo const &ri, bool ReportErrors) : Context(Context), MCB(mcb), RI(ri), MCII(MCII), STI(STI), - ReportErrors(ReportErrors) { + ReportErrors(ReportErrors), ReversePairs() { init(); } @@ -200,7 +206,10 @@ HexagonMCChecker::HexagonMCChecker(HexagonMCChecker const &Other, MCSubtargetInfo const &STI, bool CopyReportErrors) : Context(Other.Context), MCB(Other.MCB), RI(Other.RI), MCII(Other.MCII), - STI(STI), ReportErrors(CopyReportErrors ? Other.ReportErrors : false) {} + STI(STI), ReportErrors(CopyReportErrors ? Other.ReportErrors : false), + ReversePairs() { + init(); +} bool HexagonMCChecker::check(bool FullCheck) { bool chkP = checkPredicates(); @@ -218,8 +227,9 @@ bool HexagonMCChecker::check(bool FullCheck) { bool chkAXOK = checkAXOK(); bool chkCofMax1 = checkCOFMax1(); bool chkHWLoop = checkHWLoop(); + bool chkLegalVecRegPair = checkLegalVecRegPair(); bool chk = chkP && chkNV && chkR && chkRRO && chkS && chkSh && chkSl && - chkAXOK && chkCofMax1 && chkHWLoop; + chkAXOK && chkCofMax1 && chkHWLoop && chkLegalVecRegPair; return chk; } @@ -381,7 +391,7 @@ bool HexagonMCChecker::checkPredicates() { for (const auto &I : NewPreds) { unsigned P = I; - if (!Defs.count(P) || LatePreds.count(P)) { + if (!Defs.count(P) || LatePreds.count(P) || Defs.count(Hexagon::P3_0)) { // Error out if the new predicate register is not defined, // or defined "late" // (e.g., "{ if (p3.new)... ; p3 = sp1loop0(#r7:2, Rs) }"). @@ -729,3 +739,16 @@ void HexagonMCChecker::reportWarning(Twine const &Msg) { if (ReportErrors) Context.reportWarning(MCB.getLoc(), Msg); } + +bool HexagonMCChecker::checkLegalVecRegPair() { + const bool IsPermitted = STI.getFeatureBits()[Hexagon::ArchV67]; + const bool HasReversePairs = ReversePairs.size() != 0; + + if (!IsPermitted && HasReversePairs) { + for (auto R : ReversePairs) + reportError("register pair `" + Twine(RI.getName(R)) + + "' is not permitted for this architecture"); + return false; + } + return true; +} diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.h b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.h index bc55ade9ccd78..00afdb664ba51 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.h +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.h @@ -72,6 +72,10 @@ class HexagonMCChecker { using ReadOnlyIterator = std::set<unsigned>::iterator; std::set<unsigned> ReadOnly; + // Contains the vector-pair-registers with the even number + // first ("v0:1", e.g.) used/def'd in this packet. + std::set<unsigned> ReversePairs; + void init(); void init(MCInst const &); void initReg(MCInst const &, unsigned, unsigned &PredReg, bool &isTrue); @@ -94,6 +98,7 @@ class HexagonMCChecker { bool checkAXOK(); bool checkHWLoop(); bool checkCOFMax1(); + bool checkLegalVecRegPair(); static void compoundRegisterMap(unsigned &); diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp index 95e23c99868a4..24169c83bdb93 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp @@ -147,7 +147,7 @@ static const std::map<unsigned, std::vector<unsigned>> ExtFixups = { _, _, _, _, _, _, _, _, _ }}, - { MCSymbolRefExpr::VK_Hexagon_PCREL, + { MCSymbolRefExpr::VK_PCREL, { _, _, _, _, _, _, P(_6_PCREL_X), _, _, P(_9_X), _, _, @@ -311,7 +311,7 @@ static const std::map<unsigned, std::vector<unsigned>> StdFixups = { _, _, _, _, _, _, _, _, _ }}, - { MCSymbolRefExpr::VK_Hexagon_PCREL, + { MCSymbolRefExpr::VK_PCREL, { _, _, _, _, _, _, _, _, _, _, _, _, @@ -391,15 +391,9 @@ void HexagonMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, static bool RegisterMatches(unsigned Consumer, unsigned Producer, unsigned Producer2) { - if (Consumer == Producer) - return true; - if (Consumer == Producer2) - return true; - // Calculate if we're a single vector consumer referencing a double producer - if (Producer >= Hexagon::W0 && Producer <= Hexagon::W15) - if (Consumer >= Hexagon::V0 && Consumer <= Hexagon::V31) - return ((Consumer - Hexagon::V0) >> 1) == (Producer - Hexagon::W0); - return false; + return (Consumer == Producer) || (Consumer == Producer2) || + HexagonMCInstrInfo::IsSingleConsumerRefPairProducer(Producer, + Consumer); } /// EncodeSingleInstruction - Emit a single @@ -497,7 +491,7 @@ Hexagon::Fixups HexagonMCCodeEmitter::getFixupNoBits( { MCSymbolRefExpr::VK_Hexagon_LD_GOT, fixup_Hexagon_LD_GOT_32_6_X }, { MCSymbolRefExpr::VK_Hexagon_IE, fixup_Hexagon_IE_32_6_X }, { MCSymbolRefExpr::VK_Hexagon_IE_GOT, fixup_Hexagon_IE_GOT_32_6_X }, - { MCSymbolRefExpr::VK_Hexagon_PCREL, fixup_Hexagon_B32_PCREL_X }, + { MCSymbolRefExpr::VK_PCREL, fixup_Hexagon_B32_PCREL_X }, { MCSymbolRefExpr::VK_Hexagon_GD_PLT, fixup_Hexagon_GD_PLT_B32_PCREL_X }, { MCSymbolRefExpr::VK_Hexagon_LD_PLT, fixup_Hexagon_LD_PLT_B32_PCREL_X }, }; @@ -735,7 +729,8 @@ HexagonMCCodeEmitter::getMachineOpValue(MCInst const &MI, MCOperand const &MO, unsigned SOffset = 0; unsigned VOffset = 0; unsigned UseReg = MO.getReg(); - unsigned DefReg1, DefReg2; + unsigned DefReg1 = Hexagon::NoRegister; + unsigned DefReg2 = Hexagon::NoRegister; auto Instrs = HexagonMCInstrInfo::bundleInstructions(*State.Bundle); const MCOperand *I = Instrs.begin() + State.Index - 1; @@ -746,7 +741,8 @@ HexagonMCCodeEmitter::getMachineOpValue(MCInst const &MI, MCOperand const &MO, if (HexagonMCInstrInfo::isImmext(Inst)) continue; - DefReg1 = DefReg2 = 0; + DefReg1 = Hexagon::NoRegister; + DefReg2 = Hexagon::NoRegister; ++SOffset; if (HexagonMCInstrInfo::isVector(MCII, Inst)) { // Vector instructions don't count scalars. diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp index 3cbb8600ce7aa..5154a0a1e46c1 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp @@ -10,12 +10,11 @@ // //===----------------------------------------------------------------------===// +#include "HexagonMCExpr.h" #include "MCTargetDesc/HexagonBaseInfo.h" #include "MCTargetDesc/HexagonMCInstrInfo.h" #include "MCTargetDesc/HexagonMCTargetDesc.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCInst.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -296,8 +295,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { DstReg = MCI.getOperand(1).getReg(); SrcReg = MCI.getOperand(0).getReg(); // [if ([!]p0[.new])] jumpr r31 - if ((HexagonMCInstrInfo::isPredReg(SrcReg) && (Hexagon::P0 == SrcReg)) && - (Hexagon::R31 == DstReg)) { + if ((Hexagon::P0 == SrcReg) && (Hexagon::R31 == DstReg)) { return HexagonII::HSIG_L2; } break; diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp index a799f7f7c0b97..53e76a8b9ed77 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp @@ -58,7 +58,7 @@ HexagonMCELFStreamer::HexagonMCELFStreamer( : MCELFStreamer(Context, std::move(TAB), std::move(OW), std::move(Emitter)), MCII(createHexagonMCInstrInfo()) {} -void HexagonMCELFStreamer::EmitInstruction(const MCInst &MCB, +void HexagonMCELFStreamer::emitInstruction(const MCInst &MCB, const MCSubtargetInfo &STI) { assert(MCB.getOpcode() == Hexagon::BUNDLE); assert(HexagonMCInstrInfo::bundleSize(MCB) <= HEXAGON_PACKET_SIZE); @@ -71,7 +71,7 @@ void HexagonMCELFStreamer::EmitInstruction(const MCInst &MCB, EmitSymbol(*MCI); } - MCObjectStreamer::EmitInstruction(MCB, STI); + MCObjectStreamer::emitInstruction(MCB, STI); } void HexagonMCELFStreamer::EmitSymbol(const MCInst &Inst) { @@ -110,9 +110,9 @@ void HexagonMCELFStreamer::HexagonMCEmitCommonSymbol(MCSymbol *Symbol, SwitchSection(&Section); if (ELFSymbol->isUndefined()) { - EmitValueToAlignment(ByteAlignment, 0, 1, 0); - EmitLabel(Symbol); - EmitZeros(Size); + emitValueToAlignment(ByteAlignment, 0, 1, 0); + emitLabel(Symbol); + emitZeros(Size); } // Update the maximum alignment of the section if necessary. diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.h b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.h index 6248bd25d433b..edf4ce29f908c 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.h +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.h @@ -30,7 +30,7 @@ public: std::unique_ptr<MCCodeEmitter> Emitter, MCAssembler *Assembler); - void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override; + void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override; void EmitSymbol(const MCInst &Inst); void HexagonMCEmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment, diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCExpr.h b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCExpr.h index 59b1326adf0cc..e88f46a04dae4 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCExpr.h +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCExpr.h @@ -12,7 +12,6 @@ #include "llvm/MC/MCExpr.h" namespace llvm { -class MCInst; class HexagonMCExpr : public MCTargetExpr { public: static HexagonMCExpr *create(MCExpr const *Expr, MCContext &Ctx); diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp index 0750bfe74f760..f9f342a07f6dd 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp @@ -17,6 +17,7 @@ #include "MCTargetDesc/HexagonMCShuffler.h" #include "MCTargetDesc/HexagonMCTargetDesc.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" @@ -119,10 +120,10 @@ size_t HexagonMCInstrInfo::bundleSize(MCInst const &MCI) { return (1); } -bool HexagonMCInstrInfo::canonicalizePacket(MCInstrInfo const &MCII, - MCSubtargetInfo const &STI, - MCContext &Context, MCInst &MCB, - HexagonMCChecker *Check) { +namespace { +bool canonicalizePacketImpl(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, + MCContext &Context, MCInst &MCB, + HexagonMCChecker *Check) { // Check the bundle for errors. bool CheckOk = Check ? Check->check(false) : true; if (!CheckOk) @@ -132,9 +133,9 @@ bool HexagonMCInstrInfo::canonicalizePacket(MCInstrInfo const &MCII, if (!HexagonDisableCompound) HexagonMCInstrInfo::tryCompound(MCII, STI, Context, MCB); HexagonMCShuffle(Context, false, MCII, STI, MCB); + // Examine the packet and convert pairs of instructions to duplex // instructions when possible. - MCInst InstBundlePreDuplex = MCInst(MCB); if (STI.getFeatureBits() [Hexagon::FeatureDuplex]) { SmallVector<DuplexCandidate, 8> possibleDuplexes; possibleDuplexes = @@ -146,8 +147,11 @@ bool HexagonMCInstrInfo::canonicalizePacket(MCInstrInfo const &MCII, HexagonMCInstrInfo::padEndloop(MCB, Context); // If compounding and duplexing didn't reduce the size below // 4 or less we have a packet that is too big. - if (HexagonMCInstrInfo::bundleSize(MCB) > HEXAGON_PACKET_SIZE) + if (HexagonMCInstrInfo::bundleSize(MCB) > HEXAGON_PACKET_SIZE) { + if (Check) + Check->reportError("invalid instruction packet: out of slots"); return false; + } // Check the bundle for errors. CheckOk = Check ? Check->check(true) : true; if (!CheckOk) @@ -155,6 +159,27 @@ bool HexagonMCInstrInfo::canonicalizePacket(MCInstrInfo const &MCII, HexagonMCShuffle(Context, true, MCII, STI, MCB); return true; } +} // namespace + +bool HexagonMCInstrInfo::canonicalizePacket(MCInstrInfo const &MCII, + MCSubtargetInfo const &STI, + MCContext &Context, MCInst &MCB, + HexagonMCChecker *Check, + bool AttemptCompatibility) { + auto ArchSTI = Hexagon_MC::getArchSubtarget(&STI); + if (!AttemptCompatibility || ArchSTI == nullptr) + return canonicalizePacketImpl(MCII, STI, Context, MCB, Check); + + const MCRegisterInfo *RI = Context.getRegisterInfo(); + HexagonMCChecker DefaultCheck(Context, MCII, STI, MCB, *RI, false); + HexagonMCChecker *BaseCheck = (Check == nullptr) ? &DefaultCheck : Check; + HexagonMCChecker PerfCheck(*BaseCheck, STI, false); + if (canonicalizePacketImpl(MCII, STI, Context, MCB, &PerfCheck)) + return true; + + HexagonMCChecker ArchCheck(*BaseCheck, *ArchSTI, true); + return canonicalizePacketImpl(MCII, *ArchSTI, Context, MCB, &ArchCheck); +} MCInst HexagonMCInstrInfo::deriveExtender(MCInstrInfo const &MCII, MCInst const &Inst, @@ -394,6 +419,26 @@ unsigned HexagonMCInstrInfo::getType(MCInstrInfo const &MCII, return ((F >> HexagonII::TypePos) & HexagonII::TypeMask); } +/// Return the resources used by this instruction +unsigned HexagonMCInstrInfo::getCVIResources(MCInstrInfo const &MCII, + MCSubtargetInfo const &STI, + MCInst const &MCI) { + + const InstrItinerary *II = STI.getSchedModel().InstrItineraries; + int SchedClass = HexagonMCInstrInfo::getDesc(MCII, MCI).getSchedClass(); + int Size = II[SchedClass].LastStage - II[SchedClass].FirstStage; + + // HVX resources used are currenty located at the second to last stage. + // This could also be done with a linear search of the stages looking for: + // CVI_ALL, CVI_MPY01, CVI_XLSHF, CVI_MPY0, CVI_MPY1, CVI_SHIFT, CVI_XLANE, + // CVI_ZW + unsigned Stage = II[SchedClass].LastStage - 1; + + if (Size < 2) + return 0; + return ((Stage + HexagonStages)->getUnits()); +} + /// Return the slots this instruction can execute out of unsigned HexagonMCInstrInfo::getUnits(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, @@ -473,7 +518,7 @@ bool HexagonMCInstrInfo::hasNewValue2(MCInstrInfo const &MCII, MCInst const &HexagonMCInstrInfo::instruction(MCInst const &MCB, size_t Index) { assert(isBundle(MCB)); - assert(Index < HEXAGON_PACKET_SIZE); + assert(Index < HEXAGON_PRESHUFFLE_PACKET_SIZE); return *MCB.getOperand(bundleInstructionsOffset + Index).getInst(); } @@ -613,6 +658,12 @@ bool HexagonMCInstrInfo::isNewValue(MCInstrInfo const &MCII, return ((F >> HexagonII::NewValuePos) & HexagonII::NewValueMask); } +bool HexagonMCInstrInfo::isNewValueStore(MCInstrInfo const &MCII, + MCInst const &MCI) { + const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; + return (F >> HexagonII::NVStorePos) & HexagonII::NVStoreMask; +} + /// Return whether the operand is extendable. bool HexagonMCInstrInfo::isOpExtendable(MCInstrInfo const &MCII, MCInst const &MCI, unsigned short O) { @@ -625,6 +676,45 @@ bool HexagonMCInstrInfo::isOuterLoop(MCInst const &MCI) { return (Flags & outerLoopMask) != 0; } +bool HexagonMCInstrInfo::IsVecRegPair(unsigned VecReg) { + return (VecReg >= Hexagon::W0 && VecReg <= Hexagon::W15) || + (VecReg >= Hexagon::WR0 && VecReg <= Hexagon::WR15); +} + +bool HexagonMCInstrInfo::IsReverseVecRegPair(unsigned VecReg) { + return (VecReg >= Hexagon::WR0 && VecReg <= Hexagon::WR15); +} + +bool HexagonMCInstrInfo::IsVecRegSingle(unsigned VecReg) { + return (VecReg >= Hexagon::V0 && VecReg <= Hexagon::V31); +} + +std::pair<unsigned, unsigned> +HexagonMCInstrInfo::GetVecRegPairIndices(unsigned VecRegPair) { + assert(IsVecRegPair(VecRegPair) && + "VecRegPair must be a vector register pair"); + + const bool IsRev = IsReverseVecRegPair(VecRegPair); + const unsigned PairIndex = + 2 * (IsRev ? VecRegPair - Hexagon::WR0 : VecRegPair - Hexagon::W0); + + return IsRev ? std::make_pair(PairIndex, PairIndex + 1) + : std::make_pair(PairIndex + 1, PairIndex); +} + +bool HexagonMCInstrInfo::IsSingleConsumerRefPairProducer(unsigned Producer, + unsigned Consumer) { + if (IsVecRegPair(Producer) && IsVecRegSingle(Consumer)) { + const unsigned ProdPairIndex = IsReverseVecRegPair(Producer) + ? Producer - Hexagon::WR0 + : Producer - Hexagon::W0; + const unsigned ConsumerSingleIndex = (Consumer - Hexagon::V0) >> 1; + + return ConsumerSingleIndex == ProdPairIndex; + } + return false; +} + bool HexagonMCInstrInfo::isPredicated(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; @@ -655,8 +745,17 @@ bool HexagonMCInstrInfo::isPredicatedTrue(MCInstrInfo const &MCII, !((F >> HexagonII::PredicatedFalsePos) & HexagonII::PredicatedFalseMask)); } -bool HexagonMCInstrInfo::isPredReg(unsigned Reg) { - return (Reg >= Hexagon::P0 && Reg <= Hexagon::P3_0); +bool HexagonMCInstrInfo::isPredReg(MCRegisterInfo const &MRI, unsigned Reg) { + auto &PredRegClass = MRI.getRegClass(Hexagon::PredRegsRegClassID); + return PredRegClass.contains(Reg); +} + +bool HexagonMCInstrInfo::isPredRegister(MCInstrInfo const &MCII, + MCInst const &Inst, unsigned I) { + MCInstrDesc const &Desc = HexagonMCInstrInfo::getDesc(MCII, Inst); + + return Inst.getOperand(I).isReg() && + Desc.OpInfo[I].RegClass == Hexagon::PredRegsRegClassID; } /// Return whether the insn can be packaged only with A and X-type insns. @@ -753,10 +852,8 @@ bool HexagonMCInstrInfo::isSubInstruction(MCInst const &MCI) { } bool HexagonMCInstrInfo::isVector(MCInstrInfo const &MCII, MCInst const &MCI) { - if ((getType(MCII, MCI) <= HexagonII::TypeCVI_LAST) && - (getType(MCII, MCI) >= HexagonII::TypeCVI_FIRST)) - return true; - return false; + const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; + return (F >> HexagonII::isCVIPos) & HexagonII::isCVIMask; } int64_t HexagonMCInstrInfo::minConstant(MCInst const &MCI, size_t Index) { @@ -802,6 +899,18 @@ bool HexagonMCInstrInfo::s27_2_reloc(MCExpr const &Expr) { return HExpr->s27_2_reloc(); } +unsigned HexagonMCInstrInfo::packetSizeSlots(MCSubtargetInfo const &STI) { + const bool IsTiny = STI.getFeatureBits()[Hexagon::ProcTinyCore]; + + return IsTiny ? (HEXAGON_PACKET_SIZE - 1) : HEXAGON_PACKET_SIZE; +} + +unsigned HexagonMCInstrInfo::packetSize(StringRef CPU) { + return llvm::StringSwitch<unsigned>(CPU) + .Case("hexagonv67t", 3) + .Default(4); +} + void HexagonMCInstrInfo::padEndloop(MCInst &MCB, MCContext &Context) { MCInst Nop; Nop.setOpcode(Hexagon::A2_nop); @@ -836,6 +945,33 @@ bool HexagonMCInstrInfo::hasTmpDst(MCInstrInfo const &MCII, MCInst const &MCI) { return (F >> HexagonII::HasTmpDstPos) & HexagonII::HasTmpDstMask; } +bool HexagonMCInstrInfo::requiresSlot(MCSubtargetInfo const &STI, + MCInst const &MCI) { + const unsigned OpCode = MCI.getOpcode(); + const bool IsTiny = STI.getFeatureBits() [Hexagon::ProcTinyCore]; + const bool NoSlotReqd = Hexagon::A4_ext == OpCode || + (IsTiny && Hexagon::A2_nop == OpCode) || + (IsTiny && Hexagon::J4_hintjumpr == OpCode); + + return !NoSlotReqd; +} + +unsigned HexagonMCInstrInfo::slotsConsumed(MCInstrInfo const &MCII, + MCSubtargetInfo const &STI, + MCInst const &MCI) { + unsigned slotsUsed = 0; + for (auto HMI : bundleInstructions(MCI)) { + MCInst const &MCI = *HMI.getInst(); + if (!requiresSlot(STI, MCI)) + continue; + if (isDuplex(MCII, MCI)) + slotsUsed += 2; + else + ++slotsUsed; + } + return slotsUsed; +} + void HexagonMCInstrInfo::replaceDuplex(MCContext &Context, MCInst &MCB, DuplexCandidate Candidate) { assert(Candidate.packetIndexI < MCB.size()); @@ -874,9 +1010,8 @@ unsigned HexagonMCInstrInfo::SubregisterBit(unsigned Consumer, unsigned Producer2) { // If we're a single vector consumer of a double producer, set subreg bit // based on if we're accessing the lower or upper register component - if (Producer >= Hexagon::W0 && Producer <= Hexagon::W15) - if (Consumer >= Hexagon::V0 && Consumer <= Hexagon::V31) - return (Consumer - Hexagon::V0) & 0x1; + if (IsVecRegPair(Producer) && IsVecRegSingle(Consumer)) + return (Consumer - Hexagon::V0) & 0x1; if (Producer2 != Hexagon::NoRegister) return Consumer == Producer; return 0; diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h index 829f872c453e4..7b3c079880f8d 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h @@ -28,6 +28,7 @@ class MCContext; class MCExpr; class MCInstrDesc; class MCInstrInfo; +class MCRegisterInfo; class MCSubtargetInfo; class DuplexCandidate { @@ -91,7 +92,8 @@ size_t bundleSize(MCInst const &MCI); // Put the packet in to canonical form, compound, duplex, pad, and shuffle bool canonicalizePacket(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCContext &Context, MCInst &MCB, - HexagonMCChecker *Checker); + HexagonMCChecker *Checker, + bool AttemptCompatibility = false); // Create a duplex instruction given the two subinsts MCInst *deriveDuplex(MCContext &Context, unsigned iClass, MCInst const &inst0, @@ -165,6 +167,11 @@ MCOperand const &getNewValueOperand2(MCInstrInfo const &MCII, // Return the Hexagon ISA class for the insn. unsigned getType(MCInstrInfo const &MCII, MCInst const &MCI); +/// Return the resources used by this instruction +unsigned getCVIResources(MCInstrInfo const &MCII, + MCSubtargetInfo const &STI, + MCInst const &MCI); + /// Return the slots used by the insn. unsigned getUnits(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst const &MCI); @@ -252,6 +259,8 @@ bool isMemReorderDisabled(MCInst const &MCI); // Return whether the insn is a new-value consumer. bool isNewValue(MCInstrInfo const &MCII, MCInst const &MCI); +/// Return true if the operand is a new-value store insn. +bool isNewValueStore(MCInstrInfo const &MCII, MCInst const &MCI); bool isOpExtendable(MCInstrInfo const &MCII, MCInst const &MCI, unsigned short); // Can these two instructions be duplexed @@ -270,8 +279,11 @@ bool isPredicatedNew(MCInstrInfo const &MCII, MCInst const &MCI); // Return whether the predicate sense is true bool isPredicatedTrue(MCInstrInfo const &MCII, MCInst const &MCI); -// Is this a predicate register -bool isPredReg(unsigned Reg); +// Return true if this is a scalar predicate register. +bool isPredReg(MCRegisterInfo const &MRI, unsigned Reg); + +// Returns true if the Ith operand is a predicate register. +bool isPredRegister(MCInstrInfo const &MCII, MCInst const &Inst, unsigned I); // Return whether the insn is a prefix. bool isPrefix(MCInstrInfo const &MCII, MCInst const &MCI); @@ -290,6 +302,21 @@ bool isVector(MCInstrInfo const &MCII, MCInst const &MCI); bool mustExtend(MCExpr const &Expr); bool mustNotExtend(MCExpr const &Expr); +// Returns true if this instruction requires a slot to execute. +bool requiresSlot(MCSubtargetInfo const &STI, MCInst const &MCI); + +unsigned packetSize(StringRef CPU); + +// Returns the maximum number of slots available in the given +// subtarget's packets. +unsigned packetSizeSlots(MCSubtargetInfo const &STI); + +// Returns the number of slots consumed by this packet, considering duplexed +// and compound instructions. +unsigned slotsConsumed(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, + MCInst const &MCI); + + // Pad the bundle with nops to satisfy endloop requirements void padEndloop(MCInst &MCI, MCContext &Context); class PredicateInfo { @@ -324,6 +351,16 @@ bool subInstWouldBeExtended(MCInst const &potentialDuplex); unsigned SubregisterBit(unsigned Consumer, unsigned Producer, unsigned Producer2); +bool IsVecRegSingle(unsigned VecReg); +bool IsVecRegPair(unsigned VecReg); +bool IsReverseVecRegPair(unsigned VecReg); +bool IsSingleConsumerRefPairProducer(unsigned Producer, unsigned Consumer); + +/// Returns an ordered pair of the constituent register ordinals for +/// each of the elements of \a VecRegPair. For example, Hexagon::W0 ("v0:1") +/// returns { 0, 1 } and Hexagon::W1 ("v3:2") returns { 3, 2 }. +std::pair<unsigned, unsigned> GetVecRegPairIndices(unsigned VecRegPair); + // Attempt to find and replace compound pairs void tryCompound(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCContext &Context, MCInst &MCI); diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp index f8dc0547baad9..7514d0e677449 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp @@ -10,13 +10,13 @@ // //===----------------------------------------------------------------------===// -#include "MCTargetDesc/HexagonMCTargetDesc.h" -#include "HexagonDepArch.h" +#include "HexagonArch.h" #include "HexagonTargetStreamer.h" #include "MCTargetDesc/HexagonInstPrinter.h" #include "MCTargetDesc/HexagonMCAsmInfo.h" #include "MCTargetDesc/HexagonMCELFStreamer.h" #include "MCTargetDesc/HexagonMCInstrInfo.h" +#include "MCTargetDesc/HexagonMCTargetDesc.h" #include "TargetInfo/HexagonTargetInfo.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" @@ -37,8 +37,10 @@ #include "llvm/Support/raw_ostream.h" #include <cassert> #include <cstdint> +#include <mutex> #include <new> #include <string> +#include <unordered_map> using namespace llvm; @@ -72,6 +74,10 @@ cl::opt<bool> MV65("mv65", cl::Hidden, cl::desc("Build for Hexagon V65"), cl::init(false)); cl::opt<bool> MV66("mv66", cl::Hidden, cl::desc("Build for Hexagon V66"), cl::init(false)); +cl::opt<bool> MV67("mv67", cl::Hidden, cl::desc("Build for Hexagon V67"), + cl::init(false)); +cl::opt<bool> MV67T("mv67t", cl::Hidden, cl::desc("Build for Hexagon V67T"), + cl::init(false)); cl::opt<Hexagon::ArchEnum> EnableHVX("mhvx", @@ -81,6 +87,7 @@ cl::opt<Hexagon::ArchEnum> clEnumValN(Hexagon::ArchEnum::V62, "v62", "Build for HVX v62"), clEnumValN(Hexagon::ArchEnum::V65, "v65", "Build for HVX v65"), clEnumValN(Hexagon::ArchEnum::V66, "v66", "Build for HVX v66"), + clEnumValN(Hexagon::ArchEnum::V67, "v67", "Build for HVX v67"), // Sentinel for no value specified. clEnumValN(Hexagon::ArchEnum::Generic, "", "")), // Sentinel for flag not present. @@ -107,14 +114,22 @@ static StringRef HexagonGetArchVariant() { return "hexagonv65"; if (MV66) return "hexagonv66"; + if (MV67) + return "hexagonv67"; + if (MV67T) + return "hexagonv67t"; return ""; } StringRef Hexagon_MC::selectHexagonCPU(StringRef CPU) { StringRef ArchV = HexagonGetArchVariant(); if (!ArchV.empty() && !CPU.empty()) { - if (ArchV != CPU) - report_fatal_error("conflicting architectures specified."); + // Tiny cores have a "t" suffix that is discarded when creating a secondary + // non-tiny subtarget. See: addArchSubtarget + std::pair<StringRef,StringRef> ArchP = ArchV.split('t'); + std::pair<StringRef,StringRef> CPUP = CPU.split('t'); + if (!ArchP.first.equals(CPUP.first)) + report_fatal_error("conflicting architectures specified."); return CPU; } if (ArchV.empty()) { @@ -127,6 +142,56 @@ StringRef Hexagon_MC::selectHexagonCPU(StringRef CPU) { unsigned llvm::HexagonGetLastSlot() { return HexagonItinerariesV5FU::SLOT3; } +unsigned llvm::HexagonConvertUnits(unsigned ItinUnits, unsigned *Lanes) { + enum { + CVI_NONE = 0, + CVI_XLANE = 1 << 0, + CVI_SHIFT = 1 << 1, + CVI_MPY0 = 1 << 2, + CVI_MPY1 = 1 << 3, + CVI_ZW = 1 << 4 + }; + + if (ItinUnits == HexagonItinerariesV62FU::CVI_ALL || + ItinUnits == HexagonItinerariesV62FU::CVI_ALL_NOMEM) + return (*Lanes = 4, CVI_XLANE); + else if (ItinUnits & HexagonItinerariesV62FU::CVI_MPY01 && + ItinUnits & HexagonItinerariesV62FU::CVI_XLSHF) + return (*Lanes = 2, CVI_XLANE | CVI_MPY0); + else if (ItinUnits & HexagonItinerariesV62FU::CVI_MPY01) + return (*Lanes = 2, CVI_MPY0); + else if (ItinUnits & HexagonItinerariesV62FU::CVI_XLSHF) + return (*Lanes = 2, CVI_XLANE); + else if (ItinUnits & HexagonItinerariesV62FU::CVI_XLANE && + ItinUnits & HexagonItinerariesV62FU::CVI_SHIFT && + ItinUnits & HexagonItinerariesV62FU::CVI_MPY0 && + ItinUnits & HexagonItinerariesV62FU::CVI_MPY1) + return (*Lanes = 1, CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1); + else if (ItinUnits & HexagonItinerariesV62FU::CVI_XLANE && + ItinUnits & HexagonItinerariesV62FU::CVI_SHIFT) + return (*Lanes = 1, CVI_XLANE | CVI_SHIFT); + else if (ItinUnits & HexagonItinerariesV62FU::CVI_MPY0 && + ItinUnits & HexagonItinerariesV62FU::CVI_MPY1) + return (*Lanes = 1, CVI_MPY0 | CVI_MPY1); + else if (ItinUnits == HexagonItinerariesV62FU::CVI_ZW) + return (*Lanes = 1, CVI_ZW); + else if (ItinUnits == HexagonItinerariesV62FU::CVI_XLANE) + return (*Lanes = 1, CVI_XLANE); + else if (ItinUnits == HexagonItinerariesV62FU::CVI_SHIFT) + return (*Lanes = 1, CVI_SHIFT); + + return (*Lanes = 0, CVI_NONE); +} + + +namespace llvm { +namespace HexagonFUnits { +bool isSlot0Only(unsigned units) { + return HexagonItinerariesV62FU::SLOT0 == units; +} +} // namespace HexagonFUnits +} // namespace llvm + namespace { class HexagonTargetAsmStreamer : public HexagonTargetStreamer { @@ -186,7 +251,7 @@ public: } - void EmitCommonSymbolSorted(MCSymbol *Symbol, uint64_t Size, + void emitCommonSymbolSorted(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment, unsigned AccessSize) override { HexagonMCELFStreamer &HexagonELFStreamer = @@ -195,7 +260,7 @@ public: AccessSize); } - void EmitLocalCommonSymbolSorted(MCSymbol *Symbol, uint64_t Size, + void emitLocalCommonSymbolSorted(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment, unsigned AccessSize) override { HexagonMCELFStreamer &HexagonELFStreamer = @@ -225,9 +290,8 @@ static MCAsmInfo *createHexagonMCAsmInfo(const MCRegisterInfo &MRI, MCAsmInfo *MAI = new HexagonMCAsmInfo(TT); // VirtualFP = (R30 + #0). - MCCFIInstruction Inst = - MCCFIInstruction::createDefCfa(nullptr, - MRI.getDwarfRegNum(Hexagon::R30, true), 0); + MCCFIInstruction Inst = MCCFIInstruction::cfiDefCfa( + nullptr, MRI.getDwarfRegNum(Hexagon::R30, true), 0); MAI->addInitialFrameState(Inst); return MAI; @@ -296,40 +360,51 @@ std::string selectHexagonFS(StringRef CPU, StringRef FS) { case Hexagon::ArchEnum::V66: Result.push_back("+hvxv66"); break; + case Hexagon::ArchEnum::V67: + Result.push_back("+hvxv67"); + break; case Hexagon::ArchEnum::Generic:{ Result.push_back(StringSwitch<StringRef>(CPU) .Case("hexagonv60", "+hvxv60") .Case("hexagonv62", "+hvxv62") .Case("hexagonv65", "+hvxv65") - .Case("hexagonv66", "+hvxv66")); + .Case("hexagonv66", "+hvxv66") + .Case("hexagonv67", "+hvxv67") + .Case("hexagonv67t", "+hvxv67")); break; } case Hexagon::ArchEnum::NoArch: - // Sentinal if -mhvx isn't specified + // Sentinel if -mhvx isn't specified break; } return join(Result.begin(), Result.end(), ","); } } -static bool isCPUValid(std::string CPU) -{ - std::vector<std::string> table { - "generic", "hexagonv5", "hexagonv55", "hexagonv60", - "hexagonv62", "hexagonv65", "hexagonv66", - }; - - return std::find(table.begin(), table.end(), CPU) != table.end(); +static bool isCPUValid(const std::string &CPU) { + return Hexagon::CpuTable.find(CPU) != Hexagon::CpuTable.cend(); } namespace { std::pair<std::string, std::string> selectCPUAndFS(StringRef CPU, StringRef FS) { std::pair<std::string, std::string> Result; - Result.first = Hexagon_MC::selectHexagonCPU(CPU); + Result.first = std::string(Hexagon_MC::selectHexagonCPU(CPU)); Result.second = selectHexagonFS(Result.first, FS); return Result; } +std::mutex ArchSubtargetMutex; +std::unordered_map<std::string, std::unique_ptr<MCSubtargetInfo const>> + ArchSubtarget; +} // namespace + +MCSubtargetInfo const * +Hexagon_MC::getArchSubtarget(MCSubtargetInfo const *STI) { + std::lock_guard<std::mutex> Lock(ArchSubtargetMutex); + auto Existing = ArchSubtarget.find(std::string(STI->getCPU())); + if (Existing == ArchSubtarget.end()) + return nullptr; + return Existing->second.get(); } FeatureBitset Hexagon_MC::completeHVXFeatures(const FeatureBitset &S) { @@ -338,7 +413,8 @@ FeatureBitset Hexagon_MC::completeHVXFeatures(const FeatureBitset &S) { // turns on hvxvNN, corresponding to the existing ArchVNN. FeatureBitset FB = S; unsigned CpuArch = ArchV5; - for (unsigned F : {ArchV66, ArchV65, ArchV62, ArchV60, ArchV55, ArchV5}) { + for (unsigned F : {ArchV67, ArchV66, ArchV65, ArchV62, ArchV60, ArchV55, + ArchV5}) { if (!FB.test(F)) continue; CpuArch = F; @@ -353,7 +429,7 @@ FeatureBitset Hexagon_MC::completeHVXFeatures(const FeatureBitset &S) { } bool HasHvxVer = false; for (unsigned F : {ExtensionHVXV60, ExtensionHVXV62, ExtensionHVXV65, - ExtensionHVXV66}) { + ExtensionHVXV66, ExtensionHVXV67}) { if (!FB.test(F)) continue; HasHvxVer = true; @@ -366,6 +442,9 @@ FeatureBitset Hexagon_MC::completeHVXFeatures(const FeatureBitset &S) { // HasHvxVer is false, and UseHvx is true. switch (CpuArch) { + case ArchV67: + FB.set(ExtensionHVXV67); + LLVM_FALLTHROUGH; case ArchV66: FB.set(ExtensionHVXV66); LLVM_FALLTHROUGH; @@ -389,22 +468,52 @@ MCSubtargetInfo *Hexagon_MC::createHexagonMCSubtargetInfo(const Triple &TT, StringRef CPUName = Features.first; StringRef ArchFS = Features.second; + MCSubtargetInfo *X = createHexagonMCSubtargetInfoImpl(TT, CPUName, ArchFS); + if (X != nullptr && (CPUName == "hexagonv67t")) + addArchSubtarget(X, ArchFS); + + if (CPU.equals("help")) + exit(0); + if (!isCPUValid(CPUName.str())) { errs() << "error: invalid CPU \"" << CPUName.str().c_str() << "\" specified\n"; return nullptr; } - MCSubtargetInfo *X = createHexagonMCSubtargetInfoImpl(TT, CPUName, ArchFS); if (HexagonDisableDuplex) { llvm::FeatureBitset Features = X->getFeatureBits(); X->setFeatureBits(Features.reset(Hexagon::FeatureDuplex)); } X->setFeatureBits(completeHVXFeatures(X->getFeatureBits())); + + // The Z-buffer instructions are grandfathered in for current + // architectures but omitted for new ones. Future instruction + // sets may introduce new/conflicting z-buffer instructions. + const bool ZRegOnDefault = + (CPUName == "hexagonv67") || (CPUName == "hexagonv66"); + if (ZRegOnDefault) { + llvm::FeatureBitset Features = X->getFeatureBits(); + X->setFeatureBits(Features.set(Hexagon::ExtensionZReg)); + } + return X; } +void Hexagon_MC::addArchSubtarget(MCSubtargetInfo const *STI, + StringRef FS) { + assert(STI != nullptr); + if (STI->getCPU().contains("t")) { + auto ArchSTI = createHexagonMCSubtargetInfo( + STI->getTargetTriple(), + STI->getCPU().substr(0, STI->getCPU().size() - 1), FS); + std::lock_guard<std::mutex> Lock(ArchSubtargetMutex); + ArchSubtarget[std::string(STI->getCPU())] = + std::unique_ptr<MCSubtargetInfo const>(ArchSTI); + } +} + unsigned Hexagon_MC::GetELFFlags(const MCSubtargetInfo &STI) { static std::map<StringRef,unsigned> ElfFlags = { {"hexagonv5", ELF::EF_HEXAGON_MACH_V5}, @@ -413,6 +522,8 @@ unsigned Hexagon_MC::GetELFFlags(const MCSubtargetInfo &STI) { {"hexagonv62", ELF::EF_HEXAGON_MACH_V62}, {"hexagonv65", ELF::EF_HEXAGON_MACH_V65}, {"hexagonv66", ELF::EF_HEXAGON_MACH_V66}, + {"hexagonv67", ELF::EF_HEXAGON_MACH_V67}, + {"hexagonv67t", ELF::EF_HEXAGON_MACH_V67T}, }; auto F = ElfFlags.find(STI.getCPU()); @@ -420,6 +531,10 @@ unsigned Hexagon_MC::GetELFFlags(const MCSubtargetInfo &STI) { return F->second; } +llvm::ArrayRef<MCPhysReg> Hexagon_MC::GetVectRegRev() { + return makeArrayRef(VectRegRev); +} + namespace { class HexagonMCInstrAnalysis : public MCInstrAnalysis { public: @@ -437,6 +552,10 @@ public: bool evaluateBranch(MCInst const &Inst, uint64_t Addr, uint64_t Size, uint64_t &Target) const override { + if (!(isCall(Inst) || isUnconditionalBranch(Inst) || + isConditionalBranch(Inst))) + return false; + //assert(!HexagonMCInstrInfo::isBundle(Inst)); if(!HexagonMCInstrInfo::isExtendable(*Info, Inst)) return false; diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h index 7b42460a2a1ce..5bf7c9a1a908d 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h @@ -13,6 +13,7 @@ #ifndef LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONMCTARGETDESC_H #define LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONMCTARGETDESC_H +#include "llvm/MC/MCRegisterInfo.h" #include "llvm/Support/CommandLine.h" #include <cstdint> #include <string> @@ -46,7 +47,6 @@ namespace llvm { -struct InstrItinerary; struct InstrStage; class FeatureBitset; class MCAsmBackend; @@ -60,8 +60,6 @@ class MCTargetOptions; class Target; class Triple; class StringRef; -class raw_ostream; -class raw_pwrite_stream; extern cl::opt<bool> HexagonDisableCompound; extern cl::opt<bool> HexagonDisableDuplex; @@ -78,7 +76,12 @@ namespace Hexagon_MC { /// etc. do not need to go through TargetRegistry. MCSubtargetInfo *createHexagonMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS); + MCSubtargetInfo const *getArchSubtarget(MCSubtargetInfo const *STI); + void addArchSubtarget(MCSubtargetInfo const *STI, + StringRef FS); unsigned GetELFFlags(const MCSubtargetInfo &STI); + + llvm::ArrayRef<MCPhysReg> GetVectRegRev(); } MCCodeEmitter *createHexagonMCCodeEmitter(const MCInstrInfo &MCII, @@ -94,6 +97,7 @@ std::unique_ptr<MCObjectTargetWriter> createHexagonELFObjectWriter(uint8_t OSABI, StringRef CPU); unsigned HexagonGetLastSlot(); +unsigned HexagonConvertUnits(unsigned ItinUnits, unsigned *Lanes); } // End llvm namespace diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp index 18c7790a17cc1..2788b86181e27 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp @@ -105,62 +105,30 @@ unsigned HexagonResource::setWeight(unsigned s) { return Weight; } -void HexagonCVIResource::SetupTUL(TypeUnitsAndLanes *TUL, StringRef CPU) { - (*TUL)[HexagonII::TypeCVI_VA] = - UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1); - (*TUL)[HexagonII::TypeCVI_VA_DV] = UnitsAndLanes(CVI_XLANE | CVI_MPY0, 2); - (*TUL)[HexagonII::TypeCVI_VX] = UnitsAndLanes(CVI_MPY0 | CVI_MPY1, 1); - (*TUL)[HexagonII::TypeCVI_VX_LATE] = UnitsAndLanes(CVI_MPY0 | CVI_MPY1, 1); - (*TUL)[HexagonII::TypeCVI_VX_DV] = UnitsAndLanes(CVI_MPY0, 2); - (*TUL)[HexagonII::TypeCVI_VP] = UnitsAndLanes(CVI_XLANE, 1); - (*TUL)[HexagonII::TypeCVI_VP_VS] = UnitsAndLanes(CVI_XLANE, 2); - (*TUL)[HexagonII::TypeCVI_VS] = UnitsAndLanes(CVI_SHIFT, 1); - (*TUL)[HexagonII::TypeCVI_VS_VX] = UnitsAndLanes(CVI_XLANE | CVI_SHIFT, 1); - (*TUL)[HexagonII::TypeCVI_VINLANESAT] = - (CPU == "hexagonv60") - ? UnitsAndLanes(CVI_SHIFT, 1) - : UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1); - (*TUL)[HexagonII::TypeCVI_VM_LD] = - UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1); - (*TUL)[HexagonII::TypeCVI_VM_TMP_LD] = UnitsAndLanes(CVI_NONE, 0); - (*TUL)[HexagonII::TypeCVI_VM_VP_LDU] = UnitsAndLanes(CVI_XLANE, 1); - (*TUL)[HexagonII::TypeCVI_VM_ST] = - UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1); - (*TUL)[HexagonII::TypeCVI_VM_NEW_ST] = UnitsAndLanes(CVI_NONE, 0); - (*TUL)[HexagonII::TypeCVI_VM_STU] = UnitsAndLanes(CVI_XLANE, 1); - (*TUL)[HexagonII::TypeCVI_HIST] = UnitsAndLanes(CVI_XLANE, 4); - (*TUL)[HexagonII::TypeCVI_GATHER] = - UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1); - (*TUL)[HexagonII::TypeCVI_SCATTER] = - UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1); - (*TUL)[HexagonII::TypeCVI_SCATTER_DV] = - UnitsAndLanes(CVI_XLANE | CVI_MPY0, 2); - (*TUL)[HexagonII::TypeCVI_SCATTER_NEW_ST] = - UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1); - (*TUL)[HexagonII::TypeCVI_4SLOT_MPY] = UnitsAndLanes(CVI_XLANE, 4); - (*TUL)[HexagonII::TypeCVI_ZW] = UnitsAndLanes(CVI_ZW, 1); -} - -HexagonCVIResource::HexagonCVIResource(TypeUnitsAndLanes *TUL, - MCInstrInfo const &MCII, unsigned s, +HexagonCVIResource::HexagonCVIResource(MCInstrInfo const &MCII, + MCSubtargetInfo const &STI, + unsigned s, MCInst const *id) : HexagonResource(s) { - unsigned T = HexagonMCInstrInfo::getType(MCII, *id); - if (TUL->count(T)) { - // For an HVX insn. - Valid = true; - setUnits((*TUL)[T].first); - setLanes((*TUL)[T].second); - setLoad(HexagonMCInstrInfo::getDesc(MCII, *id).mayLoad()); - setStore(HexagonMCInstrInfo::getDesc(MCII, *id).mayStore()); - } else { + const unsigned ItinUnits = HexagonMCInstrInfo::getCVIResources(MCII, STI, *id); + unsigned Lanes; + const unsigned Units = HexagonConvertUnits(ItinUnits, &Lanes); + + if (Units == 0 && Lanes == 0) { // For core insns. Valid = false; setUnits(0); setLanes(0); setLoad(false); setStore(false); + } else { + // For an HVX insn. + Valid = true; + setUnits(Units); + setLanes(Lanes); + setLoad(HexagonMCInstrInfo::getDesc(MCII, *id).mayLoad()); + setStore(HexagonMCInstrInfo::getDesc(MCII, *id).mayStore()); } } @@ -201,124 +169,293 @@ HexagonShuffler::HexagonShuffler(MCContext &Context, bool ReportErrors, MCSubtargetInfo const &STI) : Context(Context), MCII(MCII), STI(STI), ReportErrors(ReportErrors) { reset(); - HexagonCVIResource::SetupTUL(&TUL, STI.getCPU()); } void HexagonShuffler::reset() { Packet.clear(); BundleFlags = 0; + CheckFailure = false; } void HexagonShuffler::append(MCInst const &ID, MCInst const *Extender, unsigned S) { - HexagonInstr PI(&TUL, MCII, &ID, Extender, S); + HexagonInstr PI(MCII, STI, &ID, Extender, S); Packet.push_back(PI); } -static struct { - unsigned first; - unsigned second; -} jumpSlots[] = {{8, 4}, {8, 2}, {8, 1}, {4, 2}, {4, 1}, {2, 1}}; -#define MAX_JUMP_SLOTS (sizeof(jumpSlots) / sizeof(jumpSlots[0])) -void HexagonShuffler::restrictSlot1AOK() { - bool HasRestrictSlot1AOK = false; - SMLoc RestrictLoc; - for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { - MCInst const &Inst = ISJ->getDesc(); - if (HexagonMCInstrInfo::isRestrictSlot1AOK(MCII, Inst)) { - HasRestrictSlot1AOK = true; - RestrictLoc = Inst.getLoc(); - } - } - if (HasRestrictSlot1AOK) - for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { - MCInst const &Inst = ISJ->getDesc(); - unsigned Type = HexagonMCInstrInfo::getType(MCII, Inst); +static const unsigned Slot0Mask = 1 << 0; +static const unsigned Slot1Mask = 1 << 1; +static const unsigned Slot3Mask = 1 << 3; +static const unsigned slotSingleLoad = Slot0Mask; +static const unsigned slotSingleStore = Slot0Mask; + +void HexagonShuffler::restrictSlot1AOK(HexagonPacketSummary const &Summary) { + if (Summary.Slot1AOKLoc) + for (HexagonInstr &ISJ : insts()) { + MCInst const &Inst = ISJ.getDesc(); + const unsigned Type = HexagonMCInstrInfo::getType(MCII, Inst); if (Type != HexagonII::TypeALU32_2op && Type != HexagonII::TypeALU32_3op && Type != HexagonII::TypeALU32_ADDI) { - unsigned Units = ISJ->Core.getUnits(); - if (Units & 2U) { + const unsigned Units = ISJ.Core.getUnits(); + + if (Units & Slot1Mask) { AppliedRestrictions.push_back(std::make_pair( Inst.getLoc(), "Instruction was restricted from being in slot 1")); - AppliedRestrictions.push_back( - std::make_pair(RestrictLoc, "Instruction can only be combine " - "with an ALU instruction in slot 1")); - ISJ->Core.setUnits(Units & ~2U); + AppliedRestrictions.push_back(std::make_pair( + *Summary.Slot1AOKLoc, "Instruction can only be combined " + "with an ALU instruction in slot 1")); + ISJ.Core.setUnits(Units & ~Slot1Mask); } } } } -void HexagonShuffler::restrictNoSlot1Store() { - bool HasRestrictNoSlot1Store = false; - SMLoc RestrictLoc; - for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { - MCInst const &Inst = ISJ->getDesc(); - if (HexagonMCInstrInfo::isRestrictNoSlot1Store(MCII, Inst)) { - HasRestrictNoSlot1Store = true; - RestrictLoc = Inst.getLoc(); +void HexagonShuffler::restrictNoSlot1Store( + HexagonPacketSummary const &Summary) { + // If this packet contains an instruction that bars slot-1 stores, + // we should mask off slot 1 from all of the store instructions in + // this packet. + + if (!Summary.NoSlot1StoreLoc) + return; + + bool AppliedRestriction = false; + + for (HexagonInstr &ISJ : insts()) { + MCInst const &Inst = ISJ.getDesc(); + if (HexagonMCInstrInfo::getDesc(MCII, Inst).mayStore()) { + unsigned Units = ISJ.Core.getUnits(); + if (Units & Slot1Mask) { + AppliedRestriction = true; + AppliedRestrictions.push_back(std::make_pair( + Inst.getLoc(), "Instruction was restricted from being in slot 1")); + ISJ.Core.setUnits(Units & ~Slot1Mask); + } } } - if (HasRestrictNoSlot1Store) { - bool AppliedRestriction = false; - for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { - MCInst const &Inst = ISJ->getDesc(); - if (HexagonMCInstrInfo::getDesc(MCII, Inst).mayStore()) { - unsigned Units = ISJ->Core.getUnits(); - if (Units & 2U) { - AppliedRestriction = true; - AppliedRestrictions.push_back(std::make_pair( - Inst.getLoc(), - "Instruction was restricted from being in slot 1")); - ISJ->Core.setUnits(Units & ~2U); + + if (AppliedRestriction) + AppliedRestrictions.push_back( + std::make_pair(*Summary.NoSlot1StoreLoc, + "Instruction does not allow a store in slot 1")); +} + +bool HexagonShuffler::applySlotRestrictions( + HexagonPacketSummary const &Summary) { + // These restrictions can modify the slot masks in the instructions + // in the Packet member. They should run unconditionally and their + // order does not matter. + restrictSlot1AOK(Summary); + restrictNoSlot1Store(Summary); + + permitNonSlot(); + + // These restrictions can modify the slot masks in the instructions + // in the Packet member, but they can also detect constraint failures + // which are fatal. + if (!CheckFailure) + restrictStoreLoadOrder(Summary); + if (!CheckFailure) + restrictBranchOrder(Summary); + if (!CheckFailure) + restrictPreferSlot3(Summary); + return !CheckFailure; +} + +void HexagonShuffler::restrictBranchOrder(HexagonPacketSummary const &Summary) { + // preserve branch order + const bool HasMultipleBranches = Summary.branchInsts.size() > 1; + if (!HasMultipleBranches) + return; + + if (Summary.branchInsts.size() > 2) { + reportError(Twine("too many branches in packet")); + return; + } + + const static std::pair<unsigned, unsigned> jumpSlots[] = { + {8, 4}, {8, 2}, {8, 1}, {4, 2}, {4, 1}, {2, 1}}; + // try all possible choices + for (std::pair<unsigned, unsigned> jumpSlot : jumpSlots) { + // validate first jump with this slot rule + if (!(jumpSlot.first & Summary.branchInsts[0]->Core.getUnits())) + continue; + + // validate second jump with this slot rule + if (!(jumpSlot.second & Summary.branchInsts[1]->Core.getUnits())) + continue; + + // both valid for this configuration, set new slot rules + const HexagonPacket PacketSave = Packet; + Summary.branchInsts[0]->Core.setUnits(jumpSlot.first); + Summary.branchInsts[1]->Core.setUnits(jumpSlot.second); + + const bool HasShuffledPacket = tryAuction(Summary).hasValue(); + if (HasShuffledPacket) + return; + + // if yes, great, if not then restore original slot mask + // restore original values + Packet = PacketSave; + } + + reportError("invalid instruction packet: out of slots"); +} + + +void HexagonShuffler::permitNonSlot() { + for (HexagonInstr &ISJ : insts()) { + const bool RequiresSlot = HexagonMCInstrInfo::requiresSlot(STI, *ISJ.ID); + if (!RequiresSlot) + ISJ.Core.setAllUnits(); + } +} + +bool HexagonShuffler::ValidResourceUsage(HexagonPacketSummary const &Summary) { + Optional<HexagonPacket> ShuffledPacket = tryAuction(Summary); + + if (!ShuffledPacket) { + reportError("invalid instruction packet: slot error"); + return false; + } else { + Packet = *ShuffledPacket; + } + + // Verify the CVI slot subscriptions. + std::stable_sort(begin(), end(), HexagonInstr::lessCVI); + // create vector of hvx instructions to check + HVXInstsT hvxInsts; + hvxInsts.clear(); + for (const_iterator I = cbegin(); I != cend(); ++I) { + struct CVIUnits inst; + inst.Units = I->CVI.getUnits(); + inst.Lanes = I->CVI.getLanes(); + if (inst.Units == 0) + continue; // not an hvx inst or an hvx inst that doesn't uses any pipes + hvxInsts.push_back(inst); + } + + // if there are any hvx instructions in this packet, check pipe usage + if (hvxInsts.size() > 0) { + unsigned startIdx, usedUnits; + startIdx = usedUnits = 0x0; + if (!checkHVXPipes(hvxInsts, startIdx, usedUnits)) { + // too many pipes used to be valid + reportError(Twine("invalid instruction packet: slot error")); + return false; + } + } + return true; +} + +bool HexagonShuffler::restrictStoreLoadOrder( + HexagonPacketSummary const &Summary) { + // Modify packet accordingly. + // TODO: need to reserve slots #0 and #1 for duplex insns. + static const unsigned slotFirstLoadStore = Slot1Mask; + static const unsigned slotLastLoadStore = Slot0Mask; + unsigned slotLoadStore = slotFirstLoadStore; + + for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { + MCInst const &ID = ISJ->getDesc(); + + if (!ISJ->Core.getUnits()) + // Error if insn may not be executed in any slot. + return false; + + // A single load must use slot #0. + if (HexagonMCInstrInfo::getDesc(MCII, ID).mayLoad()) { + if (Summary.loads == 1 && Summary.loads == Summary.memory && + Summary.memops == 0) + // Pin the load to slot #0. + switch (ID.getOpcode()) { + case Hexagon::V6_vgathermw: + case Hexagon::V6_vgathermh: + case Hexagon::V6_vgathermhw: + case Hexagon::V6_vgathermwq: + case Hexagon::V6_vgathermhq: + case Hexagon::V6_vgathermhwq: + // Slot1 only loads + break; + default: + ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleLoad); + break; + } + else if (Summary.loads >= 1 && isMemReorderDisabled()) { // }:mem_noshuf + // Loads must keep the original order ONLY if + // isMemReorderDisabled() == true + if (slotLoadStore < slotLastLoadStore) { + // Error if no more slots available for loads. + reportError("invalid instruction packet: too many loads"); + return false; + } + // Pin the load to the highest slot available to it. + ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore); + // Update the next highest slot available to loads. + slotLoadStore >>= 1; + } + } + + // A single store must use slot #0. + if (HexagonMCInstrInfo::getDesc(MCII, ID).mayStore()) { + if (!Summary.store0) { + const bool PacketHasNoOnlySlot0 = + llvm::none_of(insts(), [&](HexagonInstr const &I) { + return I.Core.getUnits() == Slot0Mask && + I.ID->getOpcode() != ID.getOpcode(); + }); + const bool SafeToMoveToSlot0 = + (Summary.loads == 0) || + (!isMemReorderDisabled() && PacketHasNoOnlySlot0); + + if (Summary.stores == 1 && SafeToMoveToSlot0) + // Pin the store to slot #0 only if isMemReorderDisabled() == false + ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleStore); + else if (Summary.stores >= 1) { + if (slotLoadStore < slotLastLoadStore) { + // Error if no more slots available for stores. + reportError("invalid instruction packet: too many stores"); + return false; + } + // Pin the store to the highest slot available to it. + ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore); + // Update the next highest slot available to stores. + slotLoadStore >>= 1; } } + if (Summary.store1 && Summary.stores > 1) { + // Error if a single store with another store. + reportError("invalid instruction packet: too many stores"); + return false; + } } - if (AppliedRestriction) - AppliedRestrictions.push_back(std::make_pair( - RestrictLoc, "Instruction does not allow a store in slot 1")); } -} -void HexagonShuffler::applySlotRestrictions() { - restrictSlot1AOK(); - restrictNoSlot1Store(); + return true; } -/// Check that the packet is legal and enforce relative insn order. -bool HexagonShuffler::check() { - // Descriptive slot masks. - const unsigned slotSingleLoad = 0x1, slotSingleStore = 0x1, - slotThree = 0x8, // slotFirstJump = 0x8, - slotFirstLoadStore = 0x2, slotLastLoadStore = 0x1; - // Highest slots for branches and stores used to keep their original order. - // unsigned slotJump = slotFirstJump; - unsigned slotLoadStore = slotFirstLoadStore; - // Number of memory operations, loads, solo loads, stores, solo stores, single - // stores. - unsigned memory = 0, loads = 0, load0 = 0, stores = 0, store0 = 0, store1 = 0; - unsigned NonZCVIloads = 0, AllCVIloads = 0, CVIstores = 0; - // Number of duplex insns - unsigned duplex = 0; - unsigned pSlot3Cnt = 0; - unsigned memops = 0; - iterator slot3ISJ = end(); - std::vector<iterator> foundBranches; - unsigned reservedSlots = 0; +HexagonShuffler::HexagonPacketSummary HexagonShuffler::GetPacketSummary() { + HexagonPacketSummary Summary = HexagonPacketSummary(); // Collect information from the insns in the packet. for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { MCInst const &ID = ISJ->getDesc(); + if (HexagonMCInstrInfo::isRestrictSlot1AOK(MCII, ID)) + Summary.Slot1AOKLoc = ID.getLoc(); + if (HexagonMCInstrInfo::isRestrictNoSlot1Store(MCII, ID)) + Summary.NoSlot1StoreLoc = ID.getLoc(); + if (HexagonMCInstrInfo::prefersSlot3(MCII, ID)) { - ++pSlot3Cnt; - slot3ISJ = ISJ; + ++Summary.pSlot3Cnt; + Summary.PrefSlot3Inst = ISJ; } - reservedSlots |= HexagonMCInstrInfo::getOtherReservedSlots(MCII, STI, ID); + Summary.ReservedSlotMask |= + HexagonMCInstrInfo::getOtherReservedSlots(MCII, STI, ID); switch (HexagonMCInstrInfo::getType(MCII, ID)) { case HexagonII::TypeS_2op: @@ -326,26 +463,27 @@ bool HexagonShuffler::check() { case HexagonII::TypeALU64: break; case HexagonII::TypeJ: - foundBranches.push_back(ISJ); + Summary.branchInsts.push_back(ISJ); break; case HexagonII::TypeCVI_VM_VP_LDU: case HexagonII::TypeCVI_VM_LD: case HexagonII::TypeCVI_VM_TMP_LD: case HexagonII::TypeCVI_GATHER: + case HexagonII::TypeCVI_GATHER_DV: case HexagonII::TypeCVI_GATHER_RST: - ++NonZCVIloads; + ++Summary.NonZCVIloads; LLVM_FALLTHROUGH; case HexagonII::TypeCVI_ZW: - ++AllCVIloads; + ++Summary.AllCVIloads; LLVM_FALLTHROUGH; case HexagonII::TypeLD: - ++loads; - ++memory; + ++Summary.loads; + ++Summary.memory; if (ISJ->Core.getUnits() == slotSingleLoad || HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_VP_LDU) - ++load0; + ++Summary.load0; if (HexagonMCInstrInfo::getDesc(MCII, ID).isReturn()) - foundBranches.push_back(ISJ); + Summary.branchInsts.push_back(ISJ); break; case HexagonII::TypeCVI_VM_STU: case HexagonII::TypeCVI_VM_ST: @@ -355,266 +493,143 @@ bool HexagonShuffler::check() { case HexagonII::TypeCVI_SCATTER_RST: case HexagonII::TypeCVI_SCATTER_NEW_RST: case HexagonII::TypeCVI_SCATTER_NEW_ST: - ++CVIstores; + ++Summary.CVIstores; LLVM_FALLTHROUGH; case HexagonII::TypeST: - ++stores; - ++memory; + ++Summary.stores; + ++Summary.memory; if (ISJ->Core.getUnits() == slotSingleStore || HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_STU) - ++store0; + ++Summary.store0; break; case HexagonII::TypeV4LDST: - ++loads; - ++stores; - ++store1; - ++memops; - ++memory; + ++Summary.loads; + ++Summary.stores; + ++Summary.store1; + ++Summary.memops; + ++Summary.memory; break; case HexagonII::TypeNCJ: - ++memory; // NV insns are memory-like. - foundBranches.push_back(ISJ); + ++Summary.memory; // NV insns are memory-like. + Summary.branchInsts.push_back(ISJ); break; case HexagonII::TypeV2LDST: if (HexagonMCInstrInfo::getDesc(MCII, ID).mayLoad()) { - ++loads; - ++memory; + ++Summary.loads; + ++Summary.memory; if (ISJ->Core.getUnits() == slotSingleLoad || HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_VP_LDU) - ++load0; + ++Summary.load0; } else { assert(HexagonMCInstrInfo::getDesc(MCII, ID).mayStore()); - ++memory; - ++stores; + ++Summary.memory; + ++Summary.stores; } break; case HexagonII::TypeCR: // Legacy conditional branch predicated on a register. case HexagonII::TypeCJ: if (HexagonMCInstrInfo::getDesc(MCII, ID).isBranch()) - foundBranches.push_back(ISJ); + Summary.branchInsts.push_back(ISJ); break; case HexagonII::TypeDUPLEX: { - ++duplex; + ++Summary.duplex; MCInst const &Inst0 = *ID.getOperand(0).getInst(); MCInst const &Inst1 = *ID.getOperand(1).getInst(); if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isBranch()) - foundBranches.push_back(ISJ); + Summary.branchInsts.push_back(ISJ); if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isBranch()) - foundBranches.push_back(ISJ); + Summary.branchInsts.push_back(ISJ); if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isReturn()) - foundBranches.push_back(ISJ); + Summary.branchInsts.push_back(ISJ); if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isReturn()) - foundBranches.push_back(ISJ); + Summary.branchInsts.push_back(ISJ); break; } } } - applySlotRestrictions(); + return Summary; +} +bool HexagonShuffler::ValidPacketMemoryOps( + HexagonPacketSummary const &Summary) const { // Check if the packet is legal. - const unsigned ZCVIloads = AllCVIloads - NonZCVIloads; + const unsigned ZCVIloads = Summary.AllCVIloads - Summary.NonZCVIloads; const bool ValidHVXMem = - NonZCVIloads <= 1 && ZCVIloads <= 1 && CVIstores <= 1; - if ((load0 > 1 || store0 > 1 || !ValidHVXMem) || - (duplex > 1 || (duplex && memory))) { - reportError(llvm::Twine("invalid instruction packet")); - return false; - } - - // Modify packet accordingly. - // TODO: need to reserve slots #0 and #1 for duplex insns. - bool bOnlySlot3 = false; - for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { - MCInst const &ID = ISJ->getDesc(); - - if (!ISJ->Core.getUnits()) { - // Error if insn may not be executed in any slot. - return false; - } - - // A single load must use slot #0. - if (HexagonMCInstrInfo::getDesc(MCII, ID).mayLoad()) { - if (loads == 1 && loads == memory && memops == 0) - // Pin the load to slot #0. - switch (ID.getOpcode()) { - case Hexagon::V6_vgathermw: - case Hexagon::V6_vgathermh: - case Hexagon::V6_vgathermhw: - case Hexagon::V6_vgathermwq: - case Hexagon::V6_vgathermhq: - case Hexagon::V6_vgathermhwq: - // Slot1 only loads - break; - default: - ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleLoad); - break; - } - else if (loads >= 1 && isMemReorderDisabled()) { // }:mem_noshuf - // Loads must keep the original order ONLY if - // isMemReorderDisabled() == true - if (slotLoadStore < slotLastLoadStore) { - // Error if no more slots available for loads. - reportError( - llvm::Twine("invalid instruction packet: too many loads")); - return false; - } - // Pin the load to the highest slot available to it. - ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore); - // Update the next highest slot available to loads. - slotLoadStore >>= 1; - } - } + Summary.NonZCVIloads <= 1 && ZCVIloads <= 1 && Summary.CVIstores <= 1; + const bool InvalidPacket = + ((Summary.load0 > 1 || Summary.store0 > 1 || !ValidHVXMem) || + (Summary.duplex > 1 || (Summary.duplex && Summary.memory))); - // A single store must use slot #0. - if (HexagonMCInstrInfo::getDesc(MCII, ID).mayStore()) { - if (!store0) { - if (stores == 1 && (loads == 0 || !isMemReorderDisabled())) - // Pin the store to slot #0 only if isMemReorderDisabled() == false - ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleStore); - else if (stores >= 1) { - if (slotLoadStore < slotLastLoadStore) { - // Error if no more slots available for stores. - reportError(Twine("invalid instruction packet: too many stores")); - return false; - } - // Pin the store to the highest slot available to it. - ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore); - // Update the next highest slot available to stores. - slotLoadStore >>= 1; - } - } - if (store1 && stores > 1) { - // Error if a single store with another store. - reportError(Twine("invalid instruction packet: too many stores")); - return false; - } - } - - // flag if an instruction requires to be in slot 3 - if (ISJ->Core.getUnits() == slotThree) - bOnlySlot3 = true; - - if (!ISJ->Core.getUnits()) { - // Error if insn may not be executed in any slot. - reportError(Twine("invalid instruction packet: out of slots")); - return false; - } - } - - // preserve branch order - bool validateSlots = true; - if (foundBranches.size() > 1) { - if (foundBranches.size() > 2) { - reportError(Twine("too many branches in packet")); - return false; - } - - // try all possible choices - for (unsigned int i = 0; i < MAX_JUMP_SLOTS; ++i) { - // validate first jump with this slot rule - if (!(jumpSlots[i].first & foundBranches[0]->Core.getUnits())) - continue; - - // validate second jump with this slot rule - if (!(jumpSlots[i].second & foundBranches[1]->Core.getUnits())) - continue; - - // both valid for this configuration, set new slot rules - PacketSave = Packet; - foundBranches[0]->Core.setUnits(jumpSlots[i].first); - foundBranches[1]->Core.setUnits(jumpSlots[i].second); - - HexagonUnitAuction AuctionCore(reservedSlots); - std::stable_sort(begin(), end(), HexagonInstr::lessCore); - - // see if things ok with that instruction being pinned to slot "slotJump" - bool bFail = false; - for (iterator I = begin(); I != end() && !bFail; ++I) - if (!AuctionCore.bid(I->Core.getUnits())) - bFail = true; - - // if yes, great, if not then restore original slot mask - if (!bFail) { - validateSlots = false; // all good, no need to re-do auction - break; - } else - // restore original values - Packet = PacketSave; - } - if (validateSlots) { - reportError(Twine("invalid instruction packet: out of slots")); - return false; - } - } - - if (foundBranches.size() <= 1 && bOnlySlot3 == false && pSlot3Cnt == 1 && - slot3ISJ != end()) { - validateSlots = true; - // save off slot mask of instruction marked with A_PREFER_SLOT3 - // and then pin it to slot #3 - unsigned saveUnits = slot3ISJ->Core.getUnits(); - slot3ISJ->Core.setUnits(saveUnits & slotThree); + return !InvalidPacket; +} - HexagonUnitAuction AuctionCore(reservedSlots); - std::stable_sort(begin(), end(), HexagonInstr::lessCore); +void HexagonShuffler::restrictPreferSlot3(HexagonPacketSummary const &Summary) { + // flag if an instruction requires to be in slot 3 + const bool HasOnlySlot3 = llvm::any_of(insts(), [&](HexagonInstr const &I) { + return (I.Core.getUnits() == Slot3Mask); + }); + const bool NeedsPrefSlot3Shuffle = + (Summary.branchInsts.size() <= 1 && !HasOnlySlot3 && + Summary.pSlot3Cnt == 1 && Summary.PrefSlot3Inst); + + if (!NeedsPrefSlot3Shuffle) + return; + + HexagonInstr *PrefSlot3Inst = *Summary.PrefSlot3Inst; + // save off slot mask of instruction marked with A_PREFER_SLOT3 + // and then pin it to slot #3 + const unsigned saveUnits = PrefSlot3Inst->Core.getUnits(); + PrefSlot3Inst->Core.setUnits(saveUnits & Slot3Mask); + const bool HasShuffledPacket = tryAuction(Summary).hasValue(); + if (HasShuffledPacket) + return; + + PrefSlot3Inst->Core.setUnits(saveUnits); +} - // see if things ok with that instruction being pinned to slot #3 - bool bFail = false; - for (iterator I = begin(); I != end() && !bFail; ++I) - if (!AuctionCore.bid(I->Core.getUnits())) - bFail = true; +/// Check that the packet is legal and enforce relative insn order. +bool HexagonShuffler::check() { + const HexagonPacketSummary Summary = GetPacketSummary(); + if (!applySlotRestrictions(Summary)) + return false; - // if yes, great, if not then restore original slot mask - if (!bFail) - validateSlots = false; // all good, no need to re-do auction - else - for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { - MCInst const &ID = ISJ->getDesc(); - if (HexagonMCInstrInfo::prefersSlot3(MCII, ID)) - ISJ->Core.setUnits(saveUnits); - } + if (!ValidPacketMemoryOps(Summary)) { + reportError("invalid instruction packet"); + return false; } - // Check if any slot, core or CVI, is over-subscribed. - // Verify the core slot subscriptions. - if (validateSlots) { - HexagonUnitAuction AuctionCore(reservedSlots); + ValidResourceUsage(Summary); - std::stable_sort(begin(), end(), HexagonInstr::lessCore); - - for (iterator I = begin(); I != end(); ++I) - if (!AuctionCore.bid(I->Core.getUnits())) { - reportError(Twine("invalid instruction packet: slot error")); - return false; - } - } - // Verify the CVI slot subscriptions. - std::stable_sort(begin(), end(), HexagonInstr::lessCVI); - // create vector of hvx instructions to check - HVXInstsT hvxInsts; - hvxInsts.clear(); - for (iterator I = begin(); I != end(); ++I) { - struct CVIUnits inst; - inst.Units = I->CVI.getUnits(); - inst.Lanes = I->CVI.getLanes(); - if (inst.Units == 0) - continue; // not an hvx inst or an hvx inst that doesn't uses any pipes - hvxInsts.push_back(inst); - } - // if there are any hvx instructions in this packet, check pipe usage - if (hvxInsts.size() > 0) { - unsigned startIdx, usedUnits; - startIdx = usedUnits = 0x0; - if (!checkHVXPipes(hvxInsts, startIdx, usedUnits)) { - // too many pipes used to be valid - reportError(Twine("invalid instruction packet: slot error")); - return false; - } - } + return !CheckFailure; +} - return true; +llvm::Optional<HexagonShuffler::HexagonPacket> +HexagonShuffler::tryAuction(HexagonPacketSummary const &Summary) const { + HexagonPacket PacketResult = Packet; + HexagonUnitAuction AuctionCore(Summary.ReservedSlotMask); + std::stable_sort(PacketResult.begin(), PacketResult.end(), + HexagonInstr::lessCore); + + const bool ValidSlots = + llvm::all_of(insts(PacketResult), [&AuctionCore](HexagonInstr const &I) { + return AuctionCore.bid(I.Core.getUnits()); + }); + + LLVM_DEBUG( + dbgs() << "Shuffle attempt: " << (ValidSlots ? "passed" : "failed") + << "\n"; + for (HexagonInstr const &ISJ : insts(PacketResult)) + dbgs() << "\t" << HexagonMCInstrInfo::getName(MCII, *ISJ.ID) << ": " + << llvm::format_hex(ISJ.Core.getUnits(), 4, true) << "\n"; + ); + + Optional<HexagonPacket> Res; + if (ValidSlots) + Res = PacketResult; + + return Res; } bool HexagonShuffler::shuffle() { @@ -653,20 +668,25 @@ bool HexagonShuffler::shuffle() { ++emptySlots; } - for (iterator ISJ = begin(); ISJ != end(); ++ISJ) - LLVM_DEBUG(dbgs().write_hex(ISJ->Core.getUnits()); if (ISJ->CVI.isValid()) { - dbgs() << '/'; - dbgs().write_hex(ISJ->CVI.getUnits()) << '|'; - dbgs() << ISJ->CVI.getLanes(); - } dbgs() << ':' - << HexagonMCInstrInfo::getDesc(MCII, ISJ->getDesc()).getOpcode(); - dbgs() << '\n'); - LLVM_DEBUG(dbgs() << '\n'); + LLVM_DEBUG( + for (HexagonInstr const &ISJ : insts()) { + dbgs().write_hex(ISJ.Core.getUnits()); + if (ISJ.CVI.isValid()) { + dbgs() << '/'; + dbgs().write_hex(ISJ.CVI.getUnits()) << '|'; + dbgs() << ISJ.CVI.getLanes(); + } + dbgs() << ':' + << HexagonMCInstrInfo::getDesc(MCII, ISJ.getDesc()).getOpcode() + << '\n'; + } dbgs() << '\n'; + ); return Ok; } void HexagonShuffler::reportError(Twine const &Msg) { + CheckFailure = true; if (ReportErrors) { for (auto const &I : AppliedRestrictions) { auto SM = Context.getSourceManager(); diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h index bf3bad36dfe55..1b4ebc5111dba 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h @@ -17,11 +17,13 @@ #include "MCTargetDesc/HexagonMCInstrInfo.h" #include "MCTargetDesc/HexagonMCTargetDesc.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SMLoc.h" #include <cstdint> +#include <functional> #include <utility> namespace llvm { @@ -45,6 +47,9 @@ public: setWeight(s); } + void setAllUnits() { + setUnits(((1u << HEXAGON_PACKET_SIZE) - 1)); + } unsigned setWeight(unsigned s); unsigned getUnits() const { return (Slots); } @@ -65,7 +70,6 @@ public: class HexagonCVIResource : public HexagonResource { public: using UnitsAndLanes = std::pair<unsigned, unsigned>; - using TypeUnitsAndLanes = DenseMap<unsigned, UnitsAndLanes>; private: // Available HVX slots. @@ -90,11 +94,10 @@ private: void setStore(bool f = true) { Store = f; } public: - HexagonCVIResource(TypeUnitsAndLanes *TUL, MCInstrInfo const &MCII, + HexagonCVIResource(MCInstrInfo const &MCII, + MCSubtargetInfo const &STI, unsigned s, MCInst const *id); - static void SetupTUL(TypeUnitsAndLanes *TUL, StringRef CPU); - bool isValid() const { return Valid; } unsigned getLanes() const { return Lanes; } bool mayLoad() const { return Load; } @@ -111,10 +114,10 @@ class HexagonInstr { HexagonCVIResource CVI; public: - HexagonInstr(HexagonCVIResource::TypeUnitsAndLanes *T, - MCInstrInfo const &MCII, MCInst const *id, + HexagonInstr(MCInstrInfo const &MCII, + MCSubtargetInfo const &STI, MCInst const *id, MCInst const *Extender, unsigned s) - : ID(id), Extender(Extender), Core(s), CVI(T, MCII, s, id) {} + : ID(id), Extender(Extender), Core(s), CVI(MCII, STI, s, id){}; MCInst const &getDesc() const { return *ID; } MCInst const *getExtender() const { return Extender; } @@ -140,11 +143,30 @@ class HexagonShuffler { using HexagonPacket = SmallVector<HexagonInstr, HEXAGON_PRESHUFFLE_PACKET_SIZE>; + struct HexagonPacketSummary { + // Number of memory operations, loads, solo loads, stores, solo stores, + // single stores. + unsigned memory; + unsigned loads; + unsigned load0; + unsigned stores; + unsigned store0; + unsigned store1; + unsigned NonZCVIloads; + unsigned AllCVIloads; + unsigned CVIstores; + // Number of duplex insns + unsigned duplex; + unsigned pSlot3Cnt; + Optional<HexagonInstr *> PrefSlot3Inst; + unsigned memops; + unsigned ReservedSlotMask; + SmallVector<HexagonInstr *, HEXAGON_PRESHUFFLE_PACKET_SIZE> branchInsts; + Optional<SMLoc> Slot1AOKLoc; + Optional<SMLoc> NoSlot1StoreLoc; + }; // Insn handles in a bundle. HexagonPacket Packet; - HexagonPacket PacketSave; - - HexagonCVIResource::TypeUnitsAndLanes TUL; protected: MCContext &Context; @@ -153,13 +175,29 @@ protected: MCSubtargetInfo const &STI; SMLoc Loc; bool ReportErrors; + bool CheckFailure; std::vector<std::pair<SMLoc, std::string>> AppliedRestrictions; - void applySlotRestrictions(); - void restrictSlot1AOK(); - void restrictNoSlot1Store(); + bool applySlotRestrictions(HexagonPacketSummary const &Summary); + void restrictSlot1AOK(HexagonPacketSummary const &Summary); + void restrictNoSlot1Store(HexagonPacketSummary const &Summary); + void restrictNoSlot1(); + bool restrictStoreLoadOrder(HexagonPacketSummary const &Summary); + void restrictBranchOrder(HexagonPacketSummary const &Summary); + void restrictPreferSlot3(HexagonPacketSummary const &Summary); + void permitNonSlot(); + + Optional<HexagonPacket> tryAuction(HexagonPacketSummary const &Summary) const; + + HexagonPacketSummary GetPacketSummary(); + bool ValidPacketMemoryOps(HexagonPacketSummary const &Summary) const; + bool ValidResourceUsage(HexagonPacketSummary const &Summary); + bool validPacketInsts() const; public: using iterator = HexagonPacket::iterator; + using const_iterator = HexagonPacket::const_iterator; + using packet_range = iterator_range<HexagonPacket::iterator>; + using const_packet_range = iterator_range<HexagonPacket::const_iterator>; HexagonShuffler(MCContext &Context, bool ReportErrors, MCInstrInfo const &MCII, MCSubtargetInfo const &STI); @@ -179,6 +217,25 @@ public: iterator begin() { return (Packet.begin()); } iterator end() { return (Packet.end()); } + const_iterator cbegin() const { return (Packet.begin()); } + const_iterator cend() const { return (Packet.end()); } + packet_range insts(HexagonPacket &P) { + return make_range(P.begin(), P.end()); + } + const_packet_range insts(HexagonPacket const &P) const { + return make_range(P.begin(), P.end()); + } + packet_range insts() { return make_range(begin(), end()); } + const_packet_range insts() const { return make_range(cbegin(), cend()); } + + using InstPredicate = bool (*)(MCInstrInfo const &, MCInst const &); + + bool HasInstWith(InstPredicate Pred) const { + return llvm::any_of(insts(), [&](HexagonInstr const &I) { + MCInst const &Inst = I.getDesc(); + return (*Pred)(MCII, Inst); + }); + } // Add insn handle to the bundle . void append(MCInst const &ID, MCInst const *Extender, unsigned S); |