diff options
Diffstat (limited to 'llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.cpp')
-rw-r--r-- | llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.cpp | 322 |
1 files changed, 181 insertions, 141 deletions
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(); |