//===----- HexagonMCChecker.cpp - Instruction bundle checking -------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This implements the checking of insns inside a bundle according to the // packet constraint rules of the Hexagon ISA. // //===----------------------------------------------------------------------===// #include "HexagonMCChecker.h" #include "HexagonBaseInfo.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; static cl::opt<bool> RelaxNVChecks("relax-nv-checks", cl::init(false), cl::ZeroOrMore, cl::Hidden, cl::desc("Relax checks of new-value validity")); const HexagonMCChecker::PredSense HexagonMCChecker::Unconditional(Hexagon::NoRegister, false); void HexagonMCChecker::init() { // Initialize read-only registers set. ReadOnly.insert(Hexagon::PC); // Figure out the loop-registers definitions. if (HexagonMCInstrInfo::isInnerLoop(MCB)) { Defs[Hexagon::SA0].insert(Unconditional); // FIXME: define or change SA0? Defs[Hexagon::LC0].insert(Unconditional); } if (HexagonMCInstrInfo::isOuterLoop(MCB)) { Defs[Hexagon::SA1].insert(Unconditional); // FIXME: define or change SA0? Defs[Hexagon::LC1].insert(Unconditional); } if (HexagonMCInstrInfo::isBundle(MCB)) // Unfurl a bundle. for (auto const&I : HexagonMCInstrInfo::bundleInstructions(MCB)) { init(*I.getInst()); } else init(MCB); } void HexagonMCChecker::init(MCInst const& MCI) { const MCInstrDesc& MCID = HexagonMCInstrInfo::getDesc(MCII, MCI); unsigned PredReg = Hexagon::NoRegister; bool isTrue = false; // Get used registers. for (unsigned i = MCID.getNumDefs(); i < MCID.getNumOperands(); ++i) if (MCI.getOperand(i).isReg()) { unsigned R = MCI.getOperand(i).getReg(); if (HexagonMCInstrInfo::isPredicated(MCII, MCI) && isPredicateRegister(R)) { // Note an used predicate register. PredReg = R; isTrue = HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI); // Note use of new predicate register. if (HexagonMCInstrInfo::isPredicatedNew(MCII, MCI)) NewPreds.insert(PredReg); } else // Note register use. Super-registers are not tracked directly, // but their components. for(MCRegAliasIterator SRI(R, &RI, !MCSubRegIterator(R, &RI).isValid()); SRI.isValid(); ++SRI) if (!MCSubRegIterator(*SRI, &RI).isValid()) // Skip super-registers used indirectly. Uses.insert(*SRI); } // Get implicit register definitions. if (const MCPhysReg *ImpDef = MCID.getImplicitDefs()) for (; *ImpDef; ++ImpDef) { unsigned R = *ImpDef; if (Hexagon::R31 != R && MCID.isCall()) // Any register other than the LR and the PC are actually volatile ones // as defined by the ABI, not modified implicitly by the call insn. continue; if (Hexagon::PC == R) // Branches are the only insns that can change the PC, // otherwise a read-only register. continue; if (Hexagon::USR_OVF == R) // Many insns change the USR implicitly, but only one or another flag. // The instruction table models the USR.OVF flag, which can be implicitly // modified more than once, but cannot be modified in the same packet // with an instruction that modifies is explicitly. Deal with such situ- // ations individually. SoftDefs.insert(R); else if (isPredicateRegister(R) && HexagonMCInstrInfo::isPredicateLate(MCII, MCI)) // Include implicit late predicates. LatePreds.insert(R); else Defs[R].insert(PredSense(PredReg, isTrue)); } // Figure out explicit register definitions. for (unsigned i = 0; i < MCID.getNumDefs(); ++i) { unsigned R = MCI.getOperand(i).getReg(), S = Hexagon::NoRegister; // USR has subregisters (while C8 does not for technical reasons), so // reset R to USR, since we know how to handle multiple defs of USR, // taking into account its subregisters. if (R == Hexagon::C8) R = Hexagon::USR; // 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()); SRI.isValid(); ++SRI) { if (MCSubRegIterator(*SRI, &RI).isValid()) // Skip super-registers defined indirectly. continue; if (R == *SRI) { if (S == R) // Avoid scoring the defined register multiple times. continue; else // Note that the defined register has already been scored. S = R; } if (Hexagon::P3_0 != R && Hexagon::P3_0 == *SRI) // P3:0 is a special case, since multiple predicate register definitions // in a packet is allowed as the equivalent of their logical "and". // Only an explicit definition of P3:0 is noted as such; if a // side-effect, then note as a soft definition. SoftDefs.insert(*SRI); else if (HexagonMCInstrInfo::isPredicateLate(MCII, MCI) && isPredicateRegister(*SRI)) // Some insns produce predicates too late to be used in the same packet. LatePreds.insert(*SRI); else if (i == 0 && llvm::HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeCVI_VM_CUR_LD) // Current loads should be used in the same packet. // TODO: relies on the impossibility of a current and a temporary loads // in the same packet. CurDefs.insert(*SRI), Defs[*SRI].insert(PredSense(PredReg, isTrue)); else if (i == 0 && llvm::HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeCVI_VM_TMP_LD) // Temporary loads should be used in the same packet, but don't commit // results, so it should be disregarded if another insn changes the same // register. // TODO: relies on the impossibility of a current and a temporary loads // in the same packet. TmpDefs.insert(*SRI); else if (i <= 1 && llvm::HexagonMCInstrInfo::hasNewValue2(MCII, MCI) ) // vshuff(Vx, Vy, Rx) <- Vx(0) and Vy(1) are both source and // destination registers with this instruction. same for vdeal(Vx,Vy,Rx) Uses.insert(*SRI); else Defs[*SRI].insert(PredSense(PredReg, isTrue)); } } // 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(); for(MCRegAliasIterator SRI(R2, &RI, !MCSubRegIterator(R2, &RI).isValid()); 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) if (MCI.getOperand(i).isReg()) { unsigned P = MCI.getOperand(i).getReg(); 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(llvm::HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeNV); else NewUses[N] = NewSense::Use(PredReg, HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI)); } } } HexagonMCChecker::HexagonMCChecker(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst &mcb, MCInst &mcbdx, MCRegisterInfo const &ri) : MCB(mcb), MCBDX(mcbdx), RI(ri), MCII(MCII), STI(STI), bLoadErrInfo(false) { init(); } bool HexagonMCChecker::check() { bool chkB = checkBranches(); bool chkP = checkPredicates(); bool chkNV = checkNewValues(); bool chkR = checkRegisters(); bool chkS = checkSolo(); bool chkSh = checkShuffle(); bool chkSl = checkSlots(); bool chk = chkB && chkP && chkNV && chkR && chkS && chkSh && chkSl; return chk; } bool HexagonMCChecker::checkSlots() { unsigned slotsUsed = 0; for (auto HMI: HexagonMCInstrInfo::bundleInstructions(MCBDX)) { MCInst const& MCI = *HMI.getInst(); if (HexagonMCInstrInfo::isImmext(MCI)) continue; if (HexagonMCInstrInfo::isDuplex(MCII, MCI)) slotsUsed += 2; else ++slotsUsed; } if (slotsUsed > HEXAGON_PACKET_SIZE) { HexagonMCErrInfo errInfo; errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_NOSLOTS); addErrInfo(errInfo); return false; } return true; } // Check legal use of branches. bool HexagonMCChecker::checkBranches() { HexagonMCErrInfo errInfo; if (HexagonMCInstrInfo::isBundle(MCB)) { bool hasConditional = false; unsigned Branches = 0, Returns = 0, NewIndirectBranches = 0, NewValueBranches = 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::getDesc(MCII, MCI).isIndirectBranch() && HexagonMCInstrInfo::isPredicatedNew(MCII, MCI)) ++NewIndirectBranches; if (HexagonMCInstrInfo::isNewValue(MCII, MCI)) ++NewValueBranches; 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 (HexagonMCInstrInfo::getDesc(MCII, MCI).isReturn() && HexagonMCInstrInfo::getDesc(MCII, MCI).mayLoad()) ++Returns; } if (Branches) // FIXME: should "Defs.count(Hexagon::PC)" be here too? if (HexagonMCInstrInfo::isInnerLoop(MCB) || HexagonMCInstrInfo::isOuterLoop(MCB)) { // Error out if there's any branch in a loop-end packet. errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_ENDLOOP, Hexagon::PC); addErrInfo(errInfo); return false; } if (Branches > 1) if (!hasConditional || Conditional > Unconditional) { // Error out if more than one unconditional branch or // the conditional branch appears after the unconditional one. errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_BRANCHES); addErrInfo(errInfo); return false; } } return true; } // Check legal use of predicate registers. bool HexagonMCChecker::checkPredicates() { HexagonMCErrInfo errInfo; // Check for proper use of new predicate registers. for (const auto& I : NewPreds) { unsigned P = I; if (!Defs.count(P) || LatePreds.count(P)) { // Error out if the new predicate register is not defined, // or defined "late" // (e.g., "{ if (p3.new)... ; p3 = sp1loop0(#r7:2, Rs) }"). errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_NEWP, P); addErrInfo(errInfo); return false; } } // Check for proper use of auto-anded of predicate registers. for (const auto& I : LatePreds) { unsigned P = I; if (LatePreds.count(P) > 1 || Defs.count(P)) { // Error out if predicate register defined "late" multiple times or // defined late and regularly defined // (e.g., "{ p3 = sp1loop0(...); p3 = cmp.eq(...) }". errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, P); addErrInfo(errInfo); return false; } } return true; } // Check legal use of new values. bool HexagonMCChecker::checkNewValues() { HexagonMCErrInfo errInfo; memset(&errInfo, 0, sizeof(errInfo)); for (auto& I : NewUses) { unsigned R = I.first; NewSense &US = I.second; if (!hasValidNewValueDef(US, NewDefs[R])) { errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_NEWV, R); addErrInfo(errInfo); return false; } } return true; } // Check for legal register uses and definitions. bool HexagonMCChecker::checkRegisters() { HexagonMCErrInfo errInfo; // Check for proper register definitions. for (const auto& I : Defs) { unsigned R = I.first; if (ReadOnly.count(R)) { // Error out for definitions of read-only registers. errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_READONLY, R); addErrInfo(errInfo); return false; } if (isLoopRegister(R) && Defs.count(R) > 1 && (HexagonMCInstrInfo::isInnerLoop(MCB) || HexagonMCInstrInfo::isOuterLoop(MCB))) { // Error out for definitions of loop registers at the end of a loop. errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_LOOP, R); addErrInfo(errInfo); return false; } if (SoftDefs.count(R)) { // Error out for explicit changes to registers also weakly defined // (e.g., "{ usr = r0; r0 = sfadd(...) }"). unsigned UsrR = Hexagon::USR; // Silence warning about mixed types in ?:. unsigned BadR = RI.isSubRegister(Hexagon::USR, R) ? UsrR : R; errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, BadR); addErrInfo(errInfo); return false; } if (!isPredicateRegister(R) && Defs[R].size() > 1) { // Check for multiple register definitions. PredSet &PM = Defs[R]; // Check for multiple unconditional register definitions. if (PM.count(Unconditional)) { // Error out on an unconditional change when there are any other // changes, conditional or not. unsigned UsrR = Hexagon::USR; unsigned BadR = RI.isSubRegister(Hexagon::USR, R) ? UsrR : R; errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, BadR); addErrInfo(errInfo); return false; } // Check for multiple conditional register definitions. for (const auto& J : PM) { PredSense P = J; // Check for multiple uses of the same condition. if (PM.count(P) > 1) { // Error out on conditional changes based on the same predicate // (e.g., "{ if (!p0) r0 =...; if (!p0) r0 =... }"). errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, R); addErrInfo(errInfo); return false; } // Check for the use of the complementary condition. P.second = !P.second; if (PM.count(P) && PM.size() > 2) { // Error out on conditional changes based on the same predicate // multiple times // (e.g., "{ if (p0) r0 =...; if (!p0) r0 =... }; if (!p0) r0 =... }"). errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, R); addErrInfo(errInfo); return false; } } } } // Check for use of current definitions. for (const auto& I : CurDefs) { unsigned R = I; if (!Uses.count(R)) { // Warn on an unused current definition. errInfo.setWarning(HexagonMCErrInfo::CHECK_WARN_CURRENT, R); addErrInfo(errInfo); return true; } } // Check for use of temporary definitions. for (const auto& I : TmpDefs) { unsigned R = I; if (!Uses.count(R)) { // special case for vhist bool vHistFound = false; for (auto const&HMI : HexagonMCInstrInfo::bundleInstructions(MCB)) { if(llvm::HexagonMCInstrInfo::getType(MCII, *HMI.getInst()) == HexagonII::TypeCVI_HIST) { vHistFound = true; // vhist() implicitly uses ALL REGxx.tmp break; } } // Warn on an unused temporary definition. if (vHistFound == false) { errInfo.setWarning(HexagonMCErrInfo::CHECK_WARN_TEMPORARY, R); addErrInfo(errInfo); return true; } } } return true; } // Check for legal use of solo insns. bool HexagonMCChecker::checkSolo() { HexagonMCErrInfo errInfo; if (HexagonMCInstrInfo::isBundle(MCB) && HexagonMCInstrInfo::bundleSize(MCB) > 1) { for (auto const&I : HexagonMCInstrInfo::bundleInstructions(MCB)) { if (llvm::HexagonMCInstrInfo::isSolo(MCII, *I.getInst())) { errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_SOLO); addErrInfo(errInfo); return false; } } } return true; } bool HexagonMCChecker::checkShuffle() { HexagonMCErrInfo errInfo; // Branch info is lost when duplexing. The unduplexed insns must be // checked and only branch errors matter for this case. HexagonMCShuffler MCS(MCII, STI, MCB); if (!MCS.check()) { if (MCS.getError() == HexagonShuffler::SHUFFLE_ERROR_BRANCHES) { errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_SHUFFLE); errInfo.setShuffleError(MCS.getError()); addErrInfo(errInfo); return false; } } HexagonMCShuffler MCSDX(MCII, STI, MCBDX); if (!MCSDX.check()) { errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_SHUFFLE); errInfo.setShuffleError(MCSDX.getError()); addErrInfo(errInfo); return false; } return true; } void HexagonMCChecker::compoundRegisterMap(unsigned& Register) { switch (Register) { default: break; case Hexagon::R15: Register = Hexagon::R23; break; case Hexagon::R14: Register = Hexagon::R22; break; case Hexagon::R13: Register = Hexagon::R21; break; case Hexagon::R12: Register = Hexagon::R20; break; case Hexagon::R11: Register = Hexagon::R19; break; case Hexagon::R10: Register = Hexagon::R18; break; case Hexagon::R9: Register = Hexagon::R17; break; case Hexagon::R8: Register = Hexagon::R16; break; } } 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; }