diff options
Diffstat (limited to 'llvm/lib/Target/Hexagon/MCTargetDesc')
11 files changed, 598 insertions, 351 deletions
diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp index 31da9fa06d0..b3ab6763281 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp @@ -655,7 +655,8 @@ public: assert(HexagonMCInstrInfo::isBundle(Inst) && "Hexagon relaxInstruction only works on bundles"); - Res = HexagonMCInstrInfo::createBundle(); + Res.setOpcode(Hexagon::BUNDLE); + Res.addOperand(MCOperand::createImm(Inst.getOperand(0).getImm())); // Copy the results into the bundle. bool Update = false; for (auto &I : HexagonMCInstrInfo::bundleInstructions(Inst)) { @@ -769,6 +770,6 @@ MCAsmBackend *llvm::createHexagonAsmBackend(Target const &T, const MCTargetOptions &Options) { uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS()); - StringRef CPUString = Hexagon_MC::selectHexagonCPU(TT, CPU); + StringRef CPUString = Hexagon_MC::selectHexagonCPU(CPU); return new HexagonAsmBackend(T, TT, OSABI, CPUString); } diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h index d1a6d38797d..f5a37603375 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h @@ -68,8 +68,8 @@ namespace HexagonII { SoloAXPos = 7, SoloAXMask = 0x1, // Only A-type instruction in first slot or nothing. - SoloAin1Pos = 8, - SoloAin1Mask = 0x1, + RestrictSlot1AOKPos = 8, + RestrictSlot1AOKMask = 0x1, // Predicated instructions. PredicatedPos = 9, @@ -122,6 +122,16 @@ namespace HexagonII { ExtentAlignPos = 33, ExtentAlignMask = 0x3, + CofMax1Pos = 35, + CofMax1Mask = 0x1, + CofRelax1Pos = 36, + CofRelax1Mask = 0x1, + CofRelax2Pos = 37, + CofRelax2Mask = 0x1, + + RestrictNoSlot1StorePos = 38, + RestrictNoSlot1StoreMask = 0x1, + // Addressing mode for load/store instructions. AddrModePos = 41, AddrModeMask = 0x7, @@ -152,8 +162,9 @@ namespace HexagonII { PrefersSlot3Pos = 56, PrefersSlot3Mask = 0x1, - CofMax1Pos = 60, - CofMax1Mask = 0x1, + // v65 + HasTmpDstPos = 59, + HasTmpDstMask = 0x1, CVINewPos = 61, CVINewMask = 0x1 diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.cpp index 142070ad73b..53f3cba052b 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.cpp @@ -179,35 +179,6 @@ void HexagonMCChecker::init(MCInst const &MCI) { } } - // Figure out register definitions that produce new values. - if (HexagonMCInstrInfo::hasNewValue(MCII, MCI)) { - unsigned R = HexagonMCInstrInfo::getNewValueOperand(MCII, MCI).getReg(); - - if (HexagonMCInstrInfo::isCompound(MCII, MCI)) - compoundRegisterMap(R); // Compound insns have a limited register range. - - for (MCRegAliasIterator SRI(R, &RI, !MCSubRegIterator(R, &RI).isValid()); - SRI.isValid(); ++SRI) - if (!MCSubRegIterator(*SRI, &RI).isValid()) - // No super-registers defined indirectly. - NewDefs[*SRI].push_back(NewSense::Def( - PredReg, HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI), - HexagonMCInstrInfo::isFloat(MCII, MCI))); - - // For fairly unique 2-dot-new producers, example: - // vdeal(V1, V9, R0) V1.new and V9.new can be used by consumers. - if (HexagonMCInstrInfo::hasNewValue2(MCII, MCI)) { - unsigned R2 = HexagonMCInstrInfo::getNewValueOperand2(MCII, MCI).getReg(); - - bool HasSubRegs = MCSubRegIterator(R2, &RI).isValid(); - for (MCRegAliasIterator SRI(R2, &RI, !HasSubRegs); SRI.isValid(); ++SRI) - if (!MCSubRegIterator(*SRI, &RI).isValid()) - NewDefs[*SRI].push_back(NewSense::Def( - PredReg, HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI), - HexagonMCInstrInfo::isFloat(MCII, MCI))); - } - } - // Figure out definitions of new predicate registers. if (HexagonMCInstrInfo::isPredicatedNew(MCII, MCI)) for (unsigned i = MCID.getNumDefs(); i < MCID.getNumOperands(); ++i) @@ -217,21 +188,6 @@ void HexagonMCChecker::init(MCInst const &MCI) { if (isPredicateRegister(P)) NewPreds.insert(P); } - - // Figure out uses of new values. - if (HexagonMCInstrInfo::isNewValue(MCII, MCI)) { - unsigned N = HexagonMCInstrInfo::getNewValueOperand(MCII, MCI).getReg(); - - if (!MCSubRegIterator(N, &RI).isValid()) { - // Super-registers cannot use new values. - if (MCID.isBranch()) - NewUses[N] = NewSense::Jmp( - HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeNCJ); - else - NewUses[N] = NewSense::Use( - PredReg, HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI)); - } - } } HexagonMCChecker::HexagonMCChecker(MCContext &Context, MCInstrInfo const &MCII, @@ -242,13 +198,17 @@ HexagonMCChecker::HexagonMCChecker(MCContext &Context, MCInstrInfo const &MCII, init(); } +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) {} + bool HexagonMCChecker::check(bool FullCheck) { - bool chkB = checkBranches(); bool chkP = checkPredicates(); bool chkNV = checkNewValues(); bool chkR = checkRegisters(); bool chkRRO = checkRegistersReadOnly(); - bool chkELB = checkEndloopBranches(); checkRegisterCurDefs(); bool chkS = checkSolo(); bool chkSh = true; @@ -258,30 +218,14 @@ bool HexagonMCChecker::check(bool FullCheck) { if (FullCheck) chkSl = checkSlots(); bool chkAXOK = checkAXOK(); - bool chk = chkB && chkP && chkNV && chkR && chkRRO && chkELB && chkS && - chkSh && chkSl && chkAXOK; + bool chkCofMax1 = checkCOFMax1(); + bool chkHWLoop = checkHWLoop(); + bool chk = chkP && chkNV && chkR && chkRRO && chkS && chkSh && chkSl && + chkAXOK && chkCofMax1 && chkHWLoop; return chk; } -bool HexagonMCChecker::checkEndloopBranches() { - for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCII, MCB)) { - MCInstrDesc const &Desc = HexagonMCInstrInfo::getDesc(MCII, I); - if (Desc.isBranch() || Desc.isCall()) { - auto Inner = HexagonMCInstrInfo::isInnerLoop(MCB); - if (Inner || HexagonMCInstrInfo::isOuterLoop(MCB)) { - reportError(I.getLoc(), - Twine("packet marked with `:endloop") + - (Inner ? "0" : "1") + "' " + - "cannot contain instructions that modify register " + "`" + - Twine(RI.getName(Hexagon::PC)) + "'"); - return false; - } - } - } - return true; -} - static bool isDuplexAGroup(unsigned Opcode) { switch (Opcode) { case Hexagon::SA1_addi: @@ -355,6 +299,65 @@ bool HexagonMCChecker::checkAXOK() { return true; } +void HexagonMCChecker::reportBranchErrors() { + for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCII, MCB)) { + MCInstrDesc const &Desc = HexagonMCInstrInfo::getDesc(MCII, I); + if (Desc.isBranch() || Desc.isCall() || Desc.isReturn()) + reportNote(I.getLoc(), "Branching instruction"); + } +} + +bool HexagonMCChecker::checkHWLoop() { + if (!HexagonMCInstrInfo::isInnerLoop(MCB) && + !HexagonMCInstrInfo::isOuterLoop(MCB)) + return true; + for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCII, MCB)) { + MCInstrDesc const &Desc = HexagonMCInstrInfo::getDesc(MCII, I); + if (Desc.isBranch() || Desc.isCall() || Desc.isReturn()) { + reportError(MCB.getLoc(), + "Branches cannot be in a packet with hardware loops"); + reportBranchErrors(); + return false; + } + } + return true; +} + +bool HexagonMCChecker::checkCOFMax1() { + SmallVector<MCInst const *, 2> BranchLocations; + for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCII, MCB)) { + MCInstrDesc const &Desc = HexagonMCInstrInfo::getDesc(MCII, I); + if (Desc.isBranch() || Desc.isCall() || Desc.isReturn()) + BranchLocations.push_back(&I); + } + for (unsigned J = 0, N = BranchLocations.size(); J < N; ++J) { + MCInst const &I = *BranchLocations[J]; + if (HexagonMCInstrInfo::isCofMax1(MCII, I)) { + bool Relax1 = HexagonMCInstrInfo::isCofRelax1(MCII, I); + bool Relax2 = HexagonMCInstrInfo::isCofRelax2(MCII, I); + if (N > 1 && !Relax1 && !Relax2) { + reportError(I.getLoc(), + "Instruction may not be in a packet with other branches"); + reportBranchErrors(); + return false; + } + if (N > 1 && J == 0 && !Relax1) { + reportError(I.getLoc(), + "Instruction may not be the first branch in packet"); + reportBranchErrors(); + return false; + } + if (N > 1 && J == 1 && !Relax2) { + reportError(I.getLoc(), + "Instruction may not be the second branch in packet"); + reportBranchErrors(); + return false; + } + } + } + return true; +} + bool HexagonMCChecker::checkSlots() { unsigned slotsUsed = 0; for (auto HMI : HexagonMCInstrInfo::bundleInstructions(MCB)) { @@ -374,45 +377,6 @@ bool HexagonMCChecker::checkSlots() { return true; } -// Check legal use of branches. -bool HexagonMCChecker::checkBranches() { - if (HexagonMCInstrInfo::isBundle(MCB)) { - bool hasConditional = false; - unsigned Branches = 0, Conditional = HEXAGON_PRESHUFFLE_PACKET_SIZE, - Unconditional = HEXAGON_PRESHUFFLE_PACKET_SIZE; - - for (unsigned i = HexagonMCInstrInfo::bundleInstructionsOffset; - i < MCB.size(); ++i) { - MCInst const &MCI = *MCB.begin()[i].getInst(); - - if (HexagonMCInstrInfo::isImmext(MCI)) - continue; - if (HexagonMCInstrInfo::getDesc(MCII, MCI).isBranch() || - HexagonMCInstrInfo::getDesc(MCII, MCI).isCall()) { - ++Branches; - if (HexagonMCInstrInfo::isPredicated(MCII, MCI) || - HexagonMCInstrInfo::isPredicatedNew(MCII, MCI)) { - hasConditional = true; - Conditional = i; // Record the position of the conditional branch. - } else { - Unconditional = i; // Record the position of the unconditional branch. - } - } - } - - if (Branches > 1) - if (!hasConditional || Conditional > Unconditional) { - // Error out if more than one unconditional branch or - // the conditional branch appears after the unconditional one. - reportError( - "unconditional branch cannot precede another branch in packet"); - return false; - } - } - - return true; -} - // Check legal use of predicate registers. bool HexagonMCChecker::checkPredicates() { // Check for proper use of new predicate registers. @@ -446,16 +410,85 @@ bool HexagonMCChecker::checkPredicates() { // Check legal use of new values. bool HexagonMCChecker::checkNewValues() { - for (auto &I : NewUses) { - unsigned R = I.first; - NewSense &US = I.second; - - if (!hasValidNewValueDef(US, NewDefs[R])) { - reportErrorNewValue(R); + for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCII, MCB)) { + if (!HexagonMCInstrInfo::isNewValue(MCII, I)) + continue; + auto Consumer = HexagonMCInstrInfo::predicateInfo(MCII, I); + bool Branch = HexagonMCInstrInfo::getDesc(MCII, I).isBranch(); + MCOperand const &Op = HexagonMCInstrInfo::getNewValueOperand(MCII, I); + assert(Op.isReg()); + auto Producer = registerProducer(Op.getReg(), Consumer); + if (std::get<0>(Producer) == nullptr) { + reportError(I.getLoc(), "New value register consumer has no producer"); + return false; + } + if (!RelaxNVChecks) { + // Checks that statically prove correct new value consumption + if (std::get<2>(Producer).isPredicated() && + (!Consumer.isPredicated() || + llvm::HexagonMCInstrInfo::getType(MCII, I) == HexagonII::TypeNCJ)) { + reportNote( + std::get<0>(Producer)->getLoc(), + "Register producer is predicated and consumer is unconditional"); + reportError(I.getLoc(), + "Instruction does not have a valid new register producer"); + return false; + } + if (std::get<2>(Producer).Register != Hexagon::NoRegister && + std::get<2>(Producer).Register != Consumer.Register) { + reportNote(std::get<0>(Producer)->getLoc(), + "Register producer does not use the same predicate " + "register as the consumer"); + reportError(I.getLoc(), + "Instruction does not have a valid new register producer"); + return false; + } + } + if (std::get<2>(Producer).Register == Consumer.Register && + Consumer.PredicatedTrue != std::get<2>(Producer).PredicatedTrue) { + reportNote( + std::get<0>(Producer)->getLoc(), + "Register producer has the opposite predicate sense as consumer"); + reportError(I.getLoc(), + "Instruction does not have a valid new register producer"); + return false; + } + MCInstrDesc const &Desc = + HexagonMCInstrInfo::getDesc(MCII, *std::get<0>(Producer)); + if (Desc.OpInfo[std::get<1>(Producer)].RegClass == + Hexagon::DoubleRegsRegClassID) { + reportNote(std::get<0>(Producer)->getLoc(), + "Double registers cannot be new-value producers"); + reportError(I.getLoc(), + "Instruction does not have a valid new register producer"); + return false; + } + if ((Desc.mayLoad() && std::get<1>(Producer) == 1) || + (Desc.mayStore() && std::get<1>(Producer) == 0)) { + unsigned Mode = + HexagonMCInstrInfo::getAddrMode(MCII, *std::get<0>(Producer)); + StringRef ModeError; + if (Mode == HexagonII::AbsoluteSet) + ModeError = "Absolute-set"; + if (Mode == HexagonII::PostInc) + ModeError = "Auto-increment"; + if (!ModeError.empty()) { + reportNote(std::get<0>(Producer)->getLoc(), + ModeError + " registers cannot be a new-value " + "producer"); + reportError(I.getLoc(), + "Instruction does not have a valid new register producer"); + return false; + } + } + if (Branch && HexagonMCInstrInfo::isFloat(MCII, *std::get<0>(Producer))) { + reportNote(std::get<0>(Producer)->getLoc(), + "FPU instructions cannot be new-value producers for jumps"); + reportError(I.getLoc(), + "Instruction does not have a valid new register producer"); return false; } } - return true; } @@ -489,6 +522,34 @@ bool HexagonMCChecker::registerUsed(unsigned Register) { return false; } +std::tuple<MCInst const *, unsigned, HexagonMCInstrInfo::PredicateInfo> +HexagonMCChecker::registerProducer( + unsigned Register, HexagonMCInstrInfo::PredicateInfo ConsumerPredicate) { + std::tuple<MCInst const *, unsigned, HexagonMCInstrInfo::PredicateInfo> + WrongSense; + for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCII, MCB)) { + MCInstrDesc const &Desc = HexagonMCInstrInfo::getDesc(MCII, I); + auto ProducerPredicate = HexagonMCInstrInfo::predicateInfo(MCII, I); + for (unsigned J = 0, N = Desc.getNumDefs(); J < N; ++J) + for (auto K = MCRegAliasIterator(I.getOperand(J).getReg(), &RI, true); + K.isValid(); ++K) + if (*K == Register) { + if (RelaxNVChecks || + (ProducerPredicate.Register == ConsumerPredicate.Register && + (ProducerPredicate.Register == Hexagon::NoRegister || + ProducerPredicate.PredicatedTrue == + ConsumerPredicate.PredicatedTrue))) + return std::make_tuple(&I, J, ProducerPredicate); + std::get<0>(WrongSense) = &I; + std::get<1>(WrongSense) = J; + std::get<2>(WrongSense) = ProducerPredicate; + } + if (Register == Hexagon::VTMP && HexagonMCInstrInfo::hasTmpDst(MCII, I)) + return std::make_tuple(&I, 0, HexagonMCInstrInfo::PredicateInfo()); + } + return WrongSense; +} + void HexagonMCChecker::checkRegisterCurDefs() { for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCII, MCB)) { if (HexagonMCInstrInfo::isCVINew(MCII, I) && @@ -638,35 +699,6 @@ void HexagonMCChecker::compoundRegisterMap(unsigned &Register) { } } -bool HexagonMCChecker::hasValidNewValueDef(const NewSense &Use, - const NewSenseList &Defs) const { - bool Strict = !RelaxNVChecks; - - for (unsigned i = 0, n = Defs.size(); i < n; ++i) { - const NewSense &Def = Defs[i]; - // NVJ cannot use a new FP value [7.6.1] - if (Use.IsNVJ && (Def.IsFloat || Def.PredReg != 0)) - continue; - // If the definition was not predicated, then it does not matter if - // the use is. - if (Def.PredReg == 0) - return true; - // With the strict checks, both the definition and the use must be - // predicated on the same register and condition. - if (Strict) { - if (Def.PredReg == Use.PredReg && Def.Cond == Use.Cond) - return true; - } else { - // With the relaxed checks, if the definition was predicated, the only - // detectable violation is if the use is predicated on the opposing - // condition, otherwise, it's ok. - if (Def.PredReg != Use.PredReg || Def.Cond == Use.Cond) - return true; - } - } - return false; -} - void HexagonMCChecker::reportErrorRegisters(unsigned Register) { reportError("register `" + Twine(RI.getName(Register)) + "' modified more than once"); @@ -687,6 +719,14 @@ void HexagonMCChecker::reportError(SMLoc Loc, Twine const &Msg) { Context.reportError(Loc, Msg); } +void HexagonMCChecker::reportNote(SMLoc Loc, llvm::Twine const &Msg) { + if (ReportErrors) { + auto SM = Context.getSourceManager(); + if (SM) + SM->PrintMessage(Loc, SourceMgr::DK_Note, Msg); + } +} + void HexagonMCChecker::reportWarning(Twine const &Msg) { if (ReportErrors) { auto SM = Context.getSourceManager(); diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.h b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.h index 957950156e8..7577baace20 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.h +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.h @@ -15,6 +15,7 @@ #ifndef LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONMCCHECKER_H #define LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONMCCHECKER_H +#include "MCTargetDesc/HexagonMCInstrInfo.h" #include "MCTargetDesc/HexagonMCTargetDesc.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" @@ -48,40 +49,6 @@ class HexagonMCChecker { using DefsIterator = DenseMap<unsigned, PredSet>::iterator; DenseMap<unsigned, PredSet> Defs; - /// Information about how a new-value register is defined or used: - /// PredReg = predicate register, 0 if use/def not predicated, - /// Cond = true/false for if(PredReg)/if(!PredReg) respectively, - /// IsFloat = true if definition produces a floating point value - /// (not valid for uses), - /// IsNVJ = true if the use is a new-value branch (not valid for - /// definitions). - struct NewSense { - unsigned PredReg; - bool IsFloat, IsNVJ, Cond; - - // The special-case "constructors": - static NewSense Jmp(bool isNVJ) { - NewSense NS = {/*PredReg=*/0, /*IsFloat=*/false, /*IsNVJ=*/isNVJ, - /*Cond=*/false}; - return NS; - } - static NewSense Use(unsigned PR, bool True) { - NewSense NS = {/*PredReg=*/PR, /*IsFloat=*/false, /*IsNVJ=*/false, - /*Cond=*/True}; - return NS; - } - static NewSense Def(unsigned PR, bool True, bool Float) { - NewSense NS = {/*PredReg=*/PR, /*IsFloat=*/Float, /*IsNVJ=*/false, - /*Cond=*/True}; - return NS; - } - }; - - /// Set of definitions that produce new register: - using NewSenseList = SmallVector<NewSense, 2>; - using NewDefsIterator = DenseMap<unsigned, NewSenseList>::iterator; - DenseMap<unsigned, NewSenseList> NewDefs; - /// Set of weak definitions whose clashes should be enforced selectively. using SoftDefsIterator = std::set<unsigned>::iterator; std::set<unsigned> SoftDefs; @@ -102,10 +69,6 @@ class HexagonMCChecker { using UsesIterator = std::set<unsigned>::iterator; std::set<unsigned> Uses; - /// Set of new values used: new register, if new-value jump. - using NewUsesIterator = DenseMap<unsigned, NewSense>::iterator; - DenseMap<unsigned, NewSense> NewUses; - /// Pre-defined set of read-only registers. using ReadOnlyIterator = std::set<unsigned>::iterator; std::set<unsigned> ReadOnly; @@ -115,6 +78,9 @@ class HexagonMCChecker { void initReg(MCInst const &, unsigned, unsigned &PredReg, bool &isTrue); bool registerUsed(unsigned Register); + std::tuple<MCInst const *, unsigned, HexagonMCInstrInfo::PredicateInfo> + registerProducer(unsigned Register, + HexagonMCInstrInfo::PredicateInfo Predicated); // Checks performed. bool checkBranches(); @@ -122,12 +88,13 @@ class HexagonMCChecker { bool checkNewValues(); bool checkRegisters(); bool checkRegistersReadOnly(); - bool checkEndloopBranches(); void checkRegisterCurDefs(); bool checkSolo(); bool checkShuffle(); bool checkSlots(); bool checkAXOK(); + bool checkHWLoop(); + bool checkCOFMax1(); static void compoundRegisterMap(unsigned &); @@ -141,19 +108,21 @@ class HexagonMCChecker { Hexagon::LC1 == R); } - bool hasValidNewValueDef(const NewSense &Use, const NewSenseList &Defs) const; - public: explicit HexagonMCChecker(MCContext &Context, MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst &mcb, const MCRegisterInfo &ri, bool ReportErrors = true); + explicit HexagonMCChecker(HexagonMCChecker const &Check, + MCSubtargetInfo const &STI, bool CopyReportErrors); bool check(bool FullCheck = true); void reportErrorRegisters(unsigned Register); void reportErrorNewValue(unsigned Register); void reportError(SMLoc Loc, Twine const &Msg); + void reportNote(SMLoc Loc, Twine const &Msg); void reportError(Twine const &Msg); void reportWarning(Twine const &Msg); + void reportBranchErrors(); }; } // end namespace llvm diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp index c5f3d434759..4c18af60efd 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp @@ -305,7 +305,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { case Hexagon::L4_return_tnew_pt: case Hexagon::L4_return_fnew_pt: // [if ([!]p0[.new])] dealloc_return - SrcReg = MCI.getOperand(0).getReg(); + SrcReg = MCI.getOperand(1).getReg(); if (Hexagon::P0 == SrcReg) { return HexagonII::HSIG_L2; } @@ -388,7 +388,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { } break; case Hexagon::S2_allocframe: - if (inRange<5, 3>(MCI, 0)) + if (inRange<5, 3>(MCI, 2)) return HexagonII::HSIG_S2; break; // @@ -742,7 +742,7 @@ MCInst HexagonMCInstrInfo::deriveSubInst(MCInst const &Inst) { break; // 1,2,3 SUBInst $Rx = add($_src_, $Rs) case Hexagon::S2_allocframe: Result.setOpcode(Hexagon::SS2_allocframe); - addOps(Result, Inst, 0); + addOps(Result, Inst, 2); break; // 1 SUBInst allocframe(#$u5_3) case Hexagon::A2_andir: if (minConstant(Inst, 2) == 255) { diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp index 94919b1e486..19308cd425e 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp @@ -33,6 +33,10 @@ using namespace llvm; +bool HexagonMCInstrInfo::PredicateInfo::isPredicated() const { + return Register != Hexagon::NoRegister; +} + Hexagon::PacketIterator::PacketIterator(MCInstrInfo const &MCII, MCInst const &Inst) : MCII(MCII), BundleCurrent(Inst.begin() + @@ -50,6 +54,7 @@ Hexagon::PacketIterator &Hexagon::PacketIterator::operator++() { if (DuplexCurrent == DuplexEnd) { DuplexCurrent = BundleEnd; DuplexEnd = BundleEnd; + ++BundleCurrent; } return *this; } @@ -90,6 +95,7 @@ void HexagonMCInstrInfo::addConstExtender(MCContext &Context, // Create the extender. MCInst *XMCI = new (Context) MCInst(HexagonMCInstrInfo::deriveExtender(MCII, MCI, exOp)); + XMCI->setLoc(MCI.getLoc()); MCB.addOperand(MCOperand::createInst(XMCI)); } @@ -131,7 +137,7 @@ bool HexagonMCInstrInfo::canonicalizePacket(MCInstrInfo const &MCII, // Examine the packet and convert pairs of instructions to duplex // instructions when possible. MCInst InstBundlePreDuplex = MCInst(MCB); - if (!HexagonDisableDuplex) { + if (STI.getFeatureBits() [Hexagon::FeatureDuplex]) { SmallVector<DuplexCandidate, 8> possibleDuplexes; possibleDuplexes = HexagonMCInstrInfo::getDuplexPossibilties(MCII, STI, MCB); @@ -169,13 +175,6 @@ void HexagonMCInstrInfo::clampExtended(MCInstrInfo const &MCII, } } -MCInst HexagonMCInstrInfo::createBundle() { - MCInst Result; - Result.setOpcode(Hexagon::BUNDLE); - Result.addOperand(MCOperand::createImm(0)); - return Result; -} - MCInst HexagonMCInstrInfo::deriveExtender(MCInstrInfo const &MCII, MCInst const &Inst, MCOperand const &MO) { @@ -233,6 +232,13 @@ unsigned HexagonMCInstrInfo::getMemAccessSize(MCInstrInfo const &MCII, return HexagonII::getMemAccessSizeInBytes(HexagonII::MemAccessSize(S)); } +unsigned HexagonMCInstrInfo::getAddrMode(MCInstrInfo const &MCII, + MCInst const &MCI) { + const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; + return static_cast<unsigned>((F >> HexagonII::AddrModePos) & + HexagonII::AddrModeMask); +} + MCInstrDesc const &HexagonMCInstrInfo::getDesc(MCInstrInfo const &MCII, MCInst const &MCI) { return MCII.get(MCI.getOpcode()); @@ -365,13 +371,20 @@ unsigned short HexagonMCInstrInfo::getNewValueOp(MCInstrInfo const &MCII, MCOperand const &HexagonMCInstrInfo::getNewValueOperand(MCInstrInfo const &MCII, MCInst const &MCI) { - unsigned O = HexagonMCInstrInfo::getNewValueOp(MCII, MCI); - MCOperand const &MCO = MCI.getOperand(O); - - assert((HexagonMCInstrInfo::isNewValue(MCII, MCI) || - HexagonMCInstrInfo::hasNewValue(MCII, MCI)) && - MCO.isReg()); - return (MCO); + if (HexagonMCInstrInfo::hasTmpDst(MCII, MCI)) { + // VTMP doesn't actually exist in the encodings for these 184 + // 3 instructions so go ahead and create it here. + static MCOperand MCO = MCOperand::createReg(Hexagon::VTMP); + return (MCO); + } else { + unsigned O = HexagonMCInstrInfo::getNewValueOp(MCII, MCI); + MCOperand const &MCO = MCI.getOperand(O); + + assert((HexagonMCInstrInfo::isNewValue(MCII, MCI) || + HexagonMCInstrInfo::hasNewValue(MCII, MCI)) && + MCO.isReg()); + return (MCO); + } } /// Return the new value or the newly produced value. @@ -439,8 +452,8 @@ bool HexagonMCInstrInfo::hasDuplex(MCInstrInfo const &MCII, MCInst const &MCI) { if (!HexagonMCInstrInfo::isBundle(MCI)) return false; - for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCII, MCI)) { - if (HexagonMCInstrInfo::isDuplex(MCII, I)) + for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCI)) { + if (HexagonMCInstrInfo::isDuplex(MCII, *I.getInst())) return true; } @@ -451,7 +464,7 @@ bool HexagonMCInstrInfo::hasExtenderForIndex(MCInst const &MCB, size_t Index) { return extenderForIndex(MCB, Index) != nullptr; } -bool HexagonMCInstrInfo::hasImmExt( MCInst const &MCI) { +bool HexagonMCInstrInfo::hasImmExt(MCInst const &MCI) { if (!HexagonMCInstrInfo::isBundle(MCI)) return false; @@ -540,6 +553,18 @@ bool HexagonMCInstrInfo::isCofMax1(MCInstrInfo const &MCII, MCInst const &MCI) { return ((F >> HexagonII::CofMax1Pos) & HexagonII::CofMax1Mask); } +bool HexagonMCInstrInfo::isCofRelax1(MCInstrInfo const &MCII, + MCInst const &MCI) { + const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; + return ((F >> HexagonII::CofRelax1Pos) & HexagonII::CofRelax1Mask); +} + +bool HexagonMCInstrInfo::isCofRelax2(MCInstrInfo const &MCII, + MCInst const &MCI) { + const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; + return ((F >> HexagonII::CofRelax2Pos) & HexagonII::CofRelax2Mask); +} + bool HexagonMCInstrInfo::isCompound(MCInstrInfo const &MCII, MCInst const &MCI) { return (getType(MCII, MCI) == HexagonII::TypeCJ); @@ -576,6 +601,11 @@ bool HexagonMCInstrInfo::isFloat(MCInstrInfo const &MCII, MCInst const &MCI) { return ((F >> HexagonII::FPPos) & HexagonII::FPMask); } +bool HexagonMCInstrInfo::isHVX(MCInstrInfo const &MCII, MCInst const &MCI) { + const uint64_t V = getType(MCII, MCI); + return HexagonII::TypeCVI_FIRST <= V && V <= HexagonII::TypeCVI_LAST; +} + bool HexagonMCInstrInfo::isImmext(MCInst const &MCI) { return MCI.getOpcode() == Hexagon::A4_ext; } @@ -655,10 +685,18 @@ bool HexagonMCInstrInfo::isSoloAX(MCInstrInfo const &MCII, MCInst const &MCI) { } /// Return whether the insn can be packaged only with an A-type insn in slot #1. -bool HexagonMCInstrInfo::isSoloAin1(MCInstrInfo const &MCII, - MCInst const &MCI) { +bool HexagonMCInstrInfo::isRestrictSlot1AOK(MCInstrInfo const &MCII, + MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; - return ((F >> HexagonII::SoloAin1Pos) & HexagonII::SoloAin1Mask); + return ((F >> HexagonII::RestrictSlot1AOKPos) & + HexagonII::RestrictSlot1AOKMask); +} + +bool HexagonMCInstrInfo::isRestrictNoSlot1Store(MCInstrInfo const &MCII, + MCInst const &MCI) { + const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; + return ((F >> HexagonII::RestrictNoSlot1StorePos) & + HexagonII::RestrictNoSlot1StoreMask); } /// Return whether the insn is solo, i.e., cannot be in a packet. @@ -673,12 +711,6 @@ bool HexagonMCInstrInfo::isMemReorderDisabled(MCInst const &MCI) { return (Flags & memReorderDisabledMask) != 0; } -bool HexagonMCInstrInfo::isMemStoreReorderEnabled(MCInst const &MCI) { - assert(isBundle(MCI)); - auto Flags = MCI.getOperand(0).getImm(); - return (Flags & memStoreReorderEnabledMask) != 0; -} - bool HexagonMCInstrInfo::isSubInstruction(MCInst const &MCI) { switch (MCI.getOpcode()) { default: @@ -800,12 +832,29 @@ void HexagonMCInstrInfo::padEndloop(MCInst &MCB, MCContext &Context) { MCB.addOperand(MCOperand::createInst(new (Context) MCInst(Nop))); } +HexagonMCInstrInfo::PredicateInfo +HexagonMCInstrInfo::predicateInfo(MCInstrInfo const &MCII, MCInst const &MCI) { + if (!isPredicated(MCII, MCI)) + return {0, 0, false}; + MCInstrDesc const &Desc = getDesc(MCII, MCI); + for (auto I = Desc.getNumDefs(), N = Desc.getNumOperands(); I != N; ++I) + if (Desc.OpInfo[I].RegClass == Hexagon::PredRegsRegClassID) + return {MCI.getOperand(I).getReg(), I, isPredicatedTrue(MCII, MCI)}; + return {0, 0, false}; +} + bool HexagonMCInstrInfo::prefersSlot3(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return (F >> HexagonII::PrefersSlot3Pos) & HexagonII::PrefersSlot3Mask; } +/// return true if instruction has hasTmpDst attribute. +bool HexagonMCInstrInfo::hasTmpDst(MCInstrInfo const &MCII, MCInst const &MCI) { + const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; + return (F >> HexagonII::HasTmpDstPos) & HexagonII::HasTmpDstMask; +} + void HexagonMCInstrInfo::replaceDuplex(MCContext &Context, MCInst &MCB, DuplexCandidate Candidate) { assert(Candidate.packetIndexI < MCB.size()); @@ -833,13 +882,6 @@ void HexagonMCInstrInfo::setMemReorderDisabled(MCInst &MCI) { assert(isMemReorderDisabled(MCI)); } -void HexagonMCInstrInfo::setMemStoreReorderEnabled(MCInst &MCI) { - assert(isBundle(MCI)); - MCOperand &Operand = MCI.getOperand(0); - Operand.setImm(Operand.getImm() | memStoreReorderEnabledMask); - assert(isMemStoreReorderEnabled(MCI)); -} - void HexagonMCInstrInfo::setOuterLoop(MCInst &MCI) { assert(isBundle(MCI)); MCOperand &Operand = MCI.getOperand(0); @@ -854,7 +896,7 @@ unsigned HexagonMCInstrInfo::SubregisterBit(unsigned Consumer, if (Producer >= Hexagon::W0 && Producer <= Hexagon::W15) if (Consumer >= Hexagon::V0 && Consumer <= Hexagon::V31) return (Consumer - Hexagon::V0) & 0x1; - if (Consumer == Producer2) - return 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 b6b01709a6c..28d89429266 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h @@ -75,10 +75,6 @@ int64_t const outerLoopMask = 1 << outerLoopOffset; size_t const memReorderDisabledOffset = 2; int64_t const memReorderDisabledMask = 1 << memReorderDisabledOffset; -// allow re-ordering of memory stores by default stores cannot be re-ordered -size_t const memStoreReorderEnabledOffset = 3; -int64_t const memStoreReorderEnabledMask = 1 << memStoreReorderEnabledOffset; - size_t const bundleInstructionsOffset = 1; void addConstant(MCInst &MI, uint64_t Value, MCContext &Context); @@ -110,8 +106,6 @@ MCInst deriveSubInst(MCInst const &Inst); // Clamp off upper 26 bits of extendable operand for emission void clampExtended(MCInstrInfo const &MCII, MCContext &Context, MCInst &MCI); -MCInst createBundle(); - // Return the extender for instruction at Index or nullptr if none MCInst const *extenderForIndex(MCInst const &MCB, size_t Index); void extendIfNeeded(MCContext &Context, MCInstrInfo const &MCII, MCInst &MCB, @@ -120,6 +114,9 @@ void extendIfNeeded(MCContext &Context, MCInstrInfo const &MCII, MCInst &MCB, // Return memory access size in bytes unsigned getMemAccessSize(MCInstrInfo const &MCII, MCInst const &MCI); +// Return memory access size +unsigned getAddrMode(MCInstrInfo const &MCII, MCInst const &MCI); + MCInstrDesc const &getDesc(MCInstrInfo const &MCII, MCInst const &MCI); // Return which duplex group this instruction belongs to @@ -184,6 +181,7 @@ bool hasImmExt(MCInst const &MCI); // Return whether the instruction is a legal new-value producer. bool hasNewValue(MCInstrInfo const &MCII, MCInst const &MCI); bool hasNewValue2(MCInstrInfo const &MCII, MCInst const &MCI); +bool hasTmpDst(MCInstrInfo const &MCII, MCInst const &MCI); unsigned iClassOfDuplexPair(unsigned Ga, unsigned Gb); int64_t minConstant(MCInst const &MCI, size_t Index); @@ -209,6 +207,8 @@ bool isBundle(MCInst const &MCI); // Return whether the insn is an actual insn. bool isCanon(MCInstrInfo const &MCII, MCInst const &MCI); bool isCofMax1(MCInstrInfo const &MCII, MCInst const &MCI); +bool isCofRelax1(MCInstrInfo const &MCII, MCInst const &MCI); +bool isCofRelax2(MCInstrInfo const &MCII, MCInst const &MCI); bool isCompound(MCInstrInfo const &MCII, MCInst const &MCI); // Return whether the instruction needs to be constant extended. @@ -236,6 +236,8 @@ bool isExtended(MCInstrInfo const &MCII, MCInst const &MCI); /// Return whether it is a floating-point insn. bool isFloat(MCInstrInfo const &MCII, MCInst const &MCI); +bool isHVX(MCInstrInfo const &MCII, MCInst const &MCI); + // Returns whether this instruction is an immediate extender bool isImmext(MCInst const &MCI); @@ -248,7 +250,6 @@ bool isIntReg(unsigned Reg); // Is this register suitable for use in a duplex subinst bool isIntRegForSubInst(unsigned Reg); bool isMemReorderDisabled(MCInst const &MCI); -bool isMemStoreReorderEnabled(MCInst const &MCI); // Return whether the insn is a new-value consumer. bool isNewValue(MCInstrInfo const &MCII, MCInst const &MCI); @@ -283,7 +284,8 @@ bool isSolo(MCInstrInfo const &MCII, MCInst const &MCI); bool isSoloAX(MCInstrInfo const &MCII, MCInst const &MCI); /// Return whether the insn can be packaged only with an A-type insn in slot #1. -bool isSoloAin1(MCInstrInfo const &MCII, MCInst const &MCI); +bool isRestrictSlot1AOK(MCInstrInfo const &MCII, MCInst const &MCI); +bool isRestrictNoSlot1Store(MCInstrInfo const &MCII, MCInst const &MCI); bool isSubInstruction(MCInst const &MCI); bool isVector(MCInstrInfo const &MCII, MCInst const &MCI); bool mustExtend(MCExpr const &Expr); @@ -291,6 +293,17 @@ bool mustNotExtend(MCExpr const &Expr); // Pad the bundle with nops to satisfy endloop requirements void padEndloop(MCInst &MCI, MCContext &Context); +class PredicateInfo { +public: + PredicateInfo() : Register(0), Operand(0), PredicatedTrue(false) {} + PredicateInfo(unsigned Register, unsigned Operand, bool PredicatedTrue) + : Register(Register), Operand(Operand), PredicatedTrue(PredicatedTrue) {} + bool isPredicated() const; + unsigned Register; + unsigned Operand; + bool PredicatedTrue; +}; +PredicateInfo predicateInfo(MCInstrInfo const &MCII, MCInst const &MCI); bool prefersSlot3(MCInstrInfo const &MCII, MCInst const &MCI); // Replace the instructions inside MCB, represented by Candidate @@ -300,7 +313,6 @@ bool s27_2_reloc(MCExpr const &Expr); // Marks a bundle as endloop0 void setInnerLoop(MCInst &MCI); void setMemReorderDisabled(MCInst &MCI); -void setMemStoreReorderEnabled(MCInst &MCI); void setMustExtend(MCExpr const &Expr, bool Val = true); void setMustNotExtend(MCExpr const &Expr, bool Val = true); void setS27_2_reloc(MCExpr const &Expr, bool Val = true); diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp index 6f48169be8c..c6f67d64b22 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp @@ -13,11 +13,13 @@ #include "MCTargetDesc/HexagonMCTargetDesc.h" #include "Hexagon.h" +#include "HexagonDepArch.h" #include "HexagonTargetStreamer.h" #include "MCTargetDesc/HexagonInstPrinter.h" #include "MCTargetDesc/HexagonMCAsmInfo.h" #include "MCTargetDesc/HexagonMCELFStreamer.h" #include "MCTargetDesc/HexagonMCInstrInfo.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCAsmBackend.h" @@ -57,41 +59,55 @@ cl::opt<bool> llvm::HexagonDisableDuplex ("mno-pairing", cl::desc("Disable looking for duplex instructions for Hexagon")); -static cl::opt<bool> HexagonV4ArchVariant("mv4", cl::Hidden, cl::init(false), - cl::desc("Build for Hexagon V4")); +namespace { // These flags are to be deprecated +cl::opt<bool> MV4("mv4", cl::Hidden, cl::desc("Build for Hexagon V4"), + cl::init(false)); +cl::opt<bool> MV5("mv5", cl::Hidden, cl::desc("Build for Hexagon V5"), + cl::init(false)); +cl::opt<bool> MV55("mv55", cl::Hidden, cl::desc("Build for Hexagon V55"), + cl::init(false)); +cl::opt<bool> MV60("mv60", cl::Hidden, cl::desc("Build for Hexagon V60"), + cl::init(false)); +cl::opt<bool> MV62("mv62", cl::Hidden, cl::desc("Build for Hexagon V62"), + cl::init(false)); +cl::opt<bool> MV65("mv65", cl::Hidden, cl::desc("Build for Hexagon V65"), + cl::init(false)); +} // namespace + +cl::opt<Hexagon::ArchEnum> + EnableHVX("mhvx", + cl::desc("Enable Hexagon Vector eXtensions"), + cl::values( + clEnumValN(Hexagon::ArchEnum::V60, "v60", "Build for HVX v60"), + clEnumValN(Hexagon::ArchEnum::V62, "v62", "Build for HVX v62"), + clEnumValN(Hexagon::ArchEnum::V65, "v65", "Build for HVX v65"), + // Sentinal for no value specified + clEnumValN(Hexagon::ArchEnum::V5, "", "")), + // Sentinal for flag not present + cl::init(Hexagon::ArchEnum::V4), cl::ValueOptional); +static cl::opt<bool> + DisableHVX("mno-hvx", cl::Hidden, cl::desc("Disable Hexagon Vector eXtensions")); -static cl::opt<bool> HexagonV5ArchVariant("mv5", cl::Hidden, cl::init(false), - cl::desc("Build for Hexagon V5")); - -static cl::opt<bool> HexagonV55ArchVariant("mv55", cl::Hidden, cl::init(false), - cl::desc("Build for Hexagon V55")); - -static cl::opt<bool> HexagonV60ArchVariant("mv60", cl::Hidden, cl::init(false), - cl::desc("Build for Hexagon V60")); - -static cl::opt<bool> HexagonV62ArchVariant("mv62", cl::Hidden, cl::init(false), - cl::desc("Build for Hexagon V62")); - -static cl::opt<bool> EnableHVX("mhvx", cl::Hidden, cl::init(false), - cl::desc("Enable Hexagon Vector Extension (HVX)")); static StringRef DefaultArch = "hexagonv60"; static StringRef HexagonGetArchVariant() { - if (HexagonV4ArchVariant) + if (MV4) return "hexagonv4"; - if (HexagonV5ArchVariant) + if (MV5) return "hexagonv5"; - if (HexagonV55ArchVariant) + if (MV55) return "hexagonv55"; - if (HexagonV60ArchVariant) + if (MV60) return "hexagonv60"; - if (HexagonV62ArchVariant) + if (MV62) return "hexagonv62"; + if (MV65) + return "hexagonv65"; return ""; } -StringRef Hexagon_MC::selectHexagonCPU(const Triple &TT, StringRef CPU) { +StringRef Hexagon_MC::selectHexagonCPU(StringRef CPU) { StringRef ArchV = HexagonGetArchVariant(); if (!ArchV.empty() && !CPU.empty()) { if (ArchV != CPU) @@ -146,7 +162,11 @@ public: OS << Indent << InstTxt << Separator; HeadTail = HeadTail.second.split('\n'); } - OS << "\t}" << PacketBundle.second; + + if (HexagonMCInstrInfo::isMemReorderDisabled(Inst)) + OS << "\n\t}:mem_noshuf" << PacketBundle.second; + else + OS << "\t}" << PacketBundle.second; } }; @@ -251,15 +271,37 @@ static bool LLVM_ATTRIBUTE_UNUSED checkFeature(MCSubtargetInfo* STI, uint64_t F) return (FB & (1ULL << F)) != 0; } -StringRef Hexagon_MC::ParseHexagonTriple(const Triple &TT, StringRef CPU) { - StringRef CPUName = Hexagon_MC::selectHexagonCPU(TT, CPU); - StringRef FS = ""; - if (EnableHVX) { - if (CPUName.equals_lower("hexagonv60") || - CPUName.equals_lower("hexagonv62")) - FS = "+hvx"; +namespace { +std::string selectHexagonFS(StringRef CPU, StringRef FS) { + SmallVector<StringRef, 3> Result; + if (!FS.empty()) + Result.push_back(FS); + + switch (EnableHVX) { + case Hexagon::ArchEnum::V55: + break; + case Hexagon::ArchEnum::V60: + Result.push_back("+hvxv60"); + break; + case Hexagon::ArchEnum::V62: + Result.push_back("+hvxv62"); + break; + case Hexagon::ArchEnum::V65: + Result.push_back("+hvxv65"); + break; + case Hexagon::ArchEnum::V5:{ + Result.push_back(StringSwitch<StringRef>(CPU) + .Case("hexagonv60", "+hvxv60") + .Case("hexagonv62", "+hvxv62") + .Case("hexagonv65", "+hvxv65")); + break; } - return FS; + case Hexagon::ArchEnum::V4: + // Sentinal if -mhvx isn't specified + break; + } + return join(Result.begin(), Result.end(), ","); +} } static bool isCPUValid(std::string CPU) @@ -271,16 +313,76 @@ static bool isCPUValid(std::string CPU) "hexagonv55", "hexagonv60", "hexagonv62", + "hexagonv65", }; return std::find(table.begin(), table.end(), CPU) != table.end(); } +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.second = selectHexagonFS(Result.first, FS); + return Result; +} +} + +FeatureBitset Hexagon_MC::completeHVXFeatures(const FeatureBitset &S) { + using namespace Hexagon; + // Make sure that +hvx-length turns hvx on, and that "hvx" alone + // turns on hvxvNN, corresponding to the existing ArchVNN. + FeatureBitset FB = S; + unsigned CpuArch = ArchV4; + for (unsigned F : {ArchV65, ArchV62, ArchV60, ArchV55, ArchV5, ArchV4}) { + if (!FB.test(F)) + continue; + CpuArch = F; + break; + } + bool UseHvx = false; + for (unsigned F : {ExtensionHVX, ExtensionHVX64B, ExtensionHVX128B, + ExtensionHVXDbl}) { + if (!FB.test(F)) + continue; + UseHvx = true; + break; + } + bool HasHvxVer = false; + for (unsigned F : {ExtensionHVXV60, ExtensionHVXV62, ExtensionHVXV65}) { + if (!FB.test(F)) + continue; + HasHvxVer = true; + UseHvx = true; + break; + } + + if (!UseHvx || HasHvxVer) + return FB; + + // HasHvxVer is false, and UseHvx is true. + switch (CpuArch) { + case ArchV60: + FB.set(ExtensionHVXV60); + break; + case ArchV62: + FB.set(ExtensionHVXV62); + break; + case ArchV65: + FB.set(ExtensionHVXV65); + break; + } + return FB; +} + MCSubtargetInfo *Hexagon_MC::createHexagonMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { - StringRef ArchFS = (FS.size()) ? FS : Hexagon_MC::ParseHexagonTriple(TT, CPU); - StringRef CPUName = Hexagon_MC::selectHexagonCPU(TT, CPU); + std::pair<std::string, std::string> Features = selectCPUAndFS(CPU, FS); + StringRef CPUName = Features.first; + StringRef ArchFS = Features.second; + if (!isCPUValid(CPUName.str())) { errs() << "error: invalid CPU \"" << CPUName.str().c_str() << "\" specified\n"; @@ -288,10 +390,12 @@ MCSubtargetInfo *Hexagon_MC::createHexagonMCSubtargetInfo(const Triple &TT, } MCSubtargetInfo *X = createHexagonMCSubtargetInfoImpl(TT, CPUName, ArchFS); - if (X->getFeatureBits()[Hexagon::ExtensionHVX128B]) { + if (HexagonDisableDuplex) { llvm::FeatureBitset Features = X->getFeatureBits(); - X->setFeatureBits(Features.set(Hexagon::ExtensionHVX)); + X->setFeatureBits(Features.set(Hexagon::FeatureDuplex, false)); } + + X->setFeatureBits(completeHVXFeatures(X->getFeatureBits())); return X; } @@ -302,6 +406,7 @@ unsigned Hexagon_MC::GetELFFlags(const MCSubtargetInfo &STI) { {"hexagonv55", ELF::EF_HEXAGON_MACH_V55}, {"hexagonv60", ELF::EF_HEXAGON_MACH_V60}, {"hexagonv62", ELF::EF_HEXAGON_MACH_V62}, + {"hexagonv65", ELF::EF_HEXAGON_MACH_V65}, }; auto F = ElfFlags.find(STI.getCPU()); diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h index 30d75dbc84e..e53208fffee 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h @@ -16,11 +16,13 @@ #include "llvm/Support/CommandLine.h" #include <cstdint> +#include <string> namespace llvm { struct InstrItinerary; struct InstrStage; +class FeatureBitset; class MCAsmBackend; class MCCodeEmitter; class MCContext; @@ -44,9 +46,9 @@ MCInstrInfo *createHexagonMCInstrInfo(); MCRegisterInfo *createHexagonMCRegisterInfo(StringRef TT); namespace Hexagon_MC { - StringRef ParseHexagonTriple(const Triple &TT, StringRef CPU); - StringRef selectHexagonCPU(const Triple &TT, StringRef CPU); + StringRef selectHexagonCPU(StringRef CPU); + FeatureBitset completeHVXFeatures(const FeatureBitset &FB); /// Create a Hexagon MCSubtargetInfo instance. This is exposed so Asm parser, /// etc. do not need to go through TargetRegistry. MCSubtargetInfo *createHexagonMCSubtargetInfo(const Triple &TT, StringRef CPU, diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp index 375a0bde32c..7709a0f6162 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp @@ -27,6 +27,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> @@ -115,6 +116,7 @@ void HexagonCVIResource::SetupTUL(TypeUnitsAndLanes *TUL, StringRef CPU) { (*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) @@ -128,6 +130,14 @@ void HexagonCVIResource::SetupTUL(TypeUnitsAndLanes *TUL, StringRef CPU) { (*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); } HexagonCVIResource::HexagonCVIResource(TypeUnitsAndLanes *TUL, @@ -211,30 +221,89 @@ static struct { } 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); + if (Type != HexagonII::TypeALU32_2op && + Type != HexagonII::TypeALU32_3op && + Type != HexagonII::TypeALU32_ADDI) { + unsigned Units = ISJ->Core.getUnits(); + if (Units & 2U) { + 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); + } + } + } +} + +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(); + } + } + 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( + RestrictLoc, "Instruction does not allow a store in slot 1")); + } +} + +void HexagonShuffler::applySlotRestrictions() { + restrictSlot1AOK(); + restrictNoSlot1Store(); +} + /// Check that the packet is legal and enforce relative insn order. bool HexagonShuffler::check() { // Descriptive slot masks. - const unsigned slotSingleLoad = 0x1, slotSingleStore = 0x1, slotOne = 0x2, + 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 branches, solo branches, indirect branches. - unsigned jumps = 0, jump1 = 0; // 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; // Number of duplex insns unsigned duplex = 0; - // Number of insns restricting other insns in slot #1 to A type. - unsigned onlyAin1 = 0; - // Number of insns restricting any insn in slot #1, except A2_nop. - unsigned onlyNo1 = 0; unsigned pSlot3Cnt = 0; - unsigned nvstores = 0; unsigned memops = 0; - unsigned deallocs = 0; iterator slot3ISJ = end(); std::vector<iterator> foundBranches; unsigned reservedSlots = 0; @@ -243,15 +312,11 @@ bool HexagonShuffler::check() { for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { MCInst const &ID = ISJ->getDesc(); - if (HexagonMCInstrInfo::isSoloAin1(MCII, ID)) - ++onlyAin1; if (HexagonMCInstrInfo::prefersSlot3(MCII, ID)) { ++pSlot3Cnt; slot3ISJ = ISJ; } reservedSlots |= HexagonMCInstrInfo::getOtherReservedSlots(MCII, STI, ID); - if (HexagonMCInstrInfo::isCofMax1(MCII, ID)) - ++jump1; switch (HexagonMCInstrInfo::getType(MCII, ID)) { case HexagonII::TypeS_2op: @@ -259,30 +324,30 @@ bool HexagonShuffler::check() { case HexagonII::TypeALU64: break; case HexagonII::TypeJ: - ++jumps; foundBranches.push_back(ISJ); break; case HexagonII::TypeCVI_VM_VP_LDU: - ++onlyNo1; - LLVM_FALLTHROUGH; case HexagonII::TypeCVI_VM_LD: case HexagonII::TypeCVI_VM_TMP_LD: + case HexagonII::TypeCVI_GATHER: + case HexagonII::TypeCVI_GATHER_RST: case HexagonII::TypeLD: ++loads; ++memory; if (ISJ->Core.getUnits() == slotSingleLoad || HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_VP_LDU) ++load0; - if (HexagonMCInstrInfo::getDesc(MCII, ID).isReturn()) { - ++deallocs, ++jumps, ++jump1; // DEALLOC_RETURN is of type LD. + if (HexagonMCInstrInfo::getDesc(MCII, ID).isReturn()) foundBranches.push_back(ISJ); - } break; case HexagonII::TypeCVI_VM_STU: - ++onlyNo1; - LLVM_FALLTHROUGH; case HexagonII::TypeCVI_VM_ST: case HexagonII::TypeCVI_VM_NEW_ST: + case HexagonII::TypeCVI_SCATTER: + case HexagonII::TypeCVI_SCATTER_DV: + case HexagonII::TypeCVI_SCATTER_RST: + case HexagonII::TypeCVI_SCATTER_NEW_RST: + case HexagonII::TypeCVI_SCATTER_NEW_ST: case HexagonII::TypeST: ++stores; ++memory; @@ -299,7 +364,6 @@ bool HexagonShuffler::check() { break; case HexagonII::TypeNCJ: ++memory; // NV insns are memory-like. - ++jumps, ++jump1; foundBranches.push_back(ISJ); break; case HexagonII::TypeV2LDST: @@ -314,65 +378,35 @@ bool HexagonShuffler::check() { assert(HexagonMCInstrInfo::getDesc(MCII, ID).mayStore()); ++memory; ++stores; - if (HexagonMCInstrInfo::isNewValue(MCII, ID)) - ++nvstores; } break; case HexagonII::TypeCR: // Legacy conditional branch predicated on a register. case HexagonII::TypeCJ: - if (HexagonMCInstrInfo::getDesc(MCII, ID).isBranch()) { - ++jumps; + if (HexagonMCInstrInfo::getDesc(MCII, ID).isBranch()) foundBranches.push_back(ISJ); - } break; case HexagonII::TypeDUPLEX: { ++duplex; MCInst const &Inst0 = *ID.getOperand(0).getInst(); MCInst const &Inst1 = *ID.getOperand(1).getInst(); - if (HexagonMCInstrInfo::isCofMax1(MCII, Inst0)) - ++jump1; - if (HexagonMCInstrInfo::isCofMax1(MCII, Inst1)) - ++jump1; - if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isBranch()) { - ++jumps; + if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isBranch()) foundBranches.push_back(ISJ); - } - if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isBranch()) { - ++jumps; + if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isBranch()) foundBranches.push_back(ISJ); - } - if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isReturn()) { - ++deallocs, ++jumps, ++jump1; // DEALLOC_RETURN is of type LD. + if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isReturn()) foundBranches.push_back(ISJ); - } - if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isReturn()) { - ++deallocs, ++jumps, ++jump1; // DEALLOC_RETURN is of type LD. + if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isReturn()) foundBranches.push_back(ISJ); - } break; } } } + applySlotRestrictions(); // Check if the packet is legal. - if ((load0 > 1 || store0 > 1) || - (duplex > 1 || (duplex && memory))) { - reportError(Twine("invalid instruction packet")); - return false; - } - - if (jump1 && jumps > 1) { - // Error if single branch with another branch. - reportError(Twine("too many branches in packet")); - return false; - } - if ((nvstores || memops) && stores > 1) { - reportError(Twine("slot 0 instruction does not allow slot 1 store")); - return false; - } - if (deallocs && stores) { - reportError(Twine("slot 0 instruction does not allow slot 1 store")); + if ((load0 > 1 || store0 > 1) || (duplex > 1 || (duplex && memory))) { + reportError(llvm::Twine("invalid instruction packet")); return false; } @@ -387,31 +421,46 @@ bool HexagonShuffler::check() { return false; } - // Exclude from slot #1 any insn but A2_nop. - if (HexagonMCInstrInfo::getDesc(MCII, ID).getOpcode() != Hexagon::A2_nop) - if (onlyNo1) - ISJ->Core.setUnits(ISJ->Core.getUnits() & ~slotOne); - - // Exclude from slot #1 any insn but A-type. - if (HexagonMCInstrInfo::getType(MCII, ID) != HexagonII::TypeALU32_2op && - HexagonMCInstrInfo::getType(MCII, ID) != HexagonII::TypeALU32_3op && - HexagonMCInstrInfo::getType(MCII, ID) != HexagonII::TypeALU32_ADDI) - if (onlyAin1) - ISJ->Core.setUnits(ISJ->Core.getUnits() & ~slotOne); - // 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. - ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleLoad); + 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; + } } // A single store must use slot #0. if (HexagonMCInstrInfo::getDesc(MCII, ID).mayStore()) { if (!store0) { - if (stores == 1) + 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) { + else if (stores >= 1) { if (slotLoadStore < slotLastLoadStore) { // Error if no more slots available for stores. reportError(Twine("invalid instruction packet: too many stores")); @@ -443,7 +492,7 @@ bool HexagonShuffler::check() { // preserve branch order bool validateSlots = true; - if (jumps > 1) { + if (foundBranches.size() > 1) { if (foundBranches.size() > 2) { reportError(Twine("too many branches in packet")); return false; @@ -487,7 +536,8 @@ bool HexagonShuffler::check() { } } - if (jumps <= 1 && !bOnlySlot3 && pSlot3Cnt == 1 && slot3ISJ != end()) { + 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 @@ -604,6 +654,12 @@ bool HexagonShuffler::shuffle() { } void HexagonShuffler::reportError(Twine const &Msg) { - if (ReportErrors) + if (ReportErrors) { + for (auto const &I : AppliedRestrictions) { + auto SM = Context.getSourceManager(); + if (SM) + SM->PrintMessage(I.first, SourceMgr::DK_Note, I.second); + } Context.reportError(Loc, Msg); + } } diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h index df3fb0a1efb..37f90bc46ac 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h @@ -16,6 +16,7 @@ #define LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONSHUFFLER_H #include "Hexagon.h" +#include "MCTargetDesc/HexagonMCInstrInfo.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -152,6 +153,10 @@ protected: MCSubtargetInfo const &STI; SMLoc Loc; bool ReportErrors; + std::vector<std::pair<SMLoc, std::string>> AppliedRestrictions; + void applySlotRestrictions(); + void restrictSlot1AOK(); + void restrictNoSlot1Store(); public: using iterator = HexagonPacket::iterator; @@ -168,6 +173,10 @@ public: unsigned size() const { return (Packet.size()); } + bool isMemReorderDisabled() const { + return (BundleFlags & HexagonMCInstrInfo::memReorderDisabledMask) != 0; + } + iterator begin() { return (Packet.begin()); } iterator end() { return (Packet.end()); } |