diff options
Diffstat (limited to 'contrib/llvm/lib/CodeGen/MachineVerifier.cpp')
-rw-r--r-- | contrib/llvm/lib/CodeGen/MachineVerifier.cpp | 341 |
1 files changed, 256 insertions, 85 deletions
diff --git a/contrib/llvm/lib/CodeGen/MachineVerifier.cpp b/contrib/llvm/lib/CodeGen/MachineVerifier.cpp index 428295e..a70adb0 100644 --- a/contrib/llvm/lib/CodeGen/MachineVerifier.cpp +++ b/contrib/llvm/lib/CodeGen/MachineVerifier.cpp @@ -58,7 +58,7 @@ namespace { Banner(b) {} - bool runOnMachineFunction(MachineFunction &MF); + unsigned verify(MachineFunction &MF); Pass *const PASS; const char *Banner; @@ -217,10 +217,22 @@ namespace { LaneBitmask LaneMask) const; void report_context(const LiveRange::Segment &S) const; void report_context(const VNInfo &VNI) const; + void report_context(SlotIndex Pos) const; + void report_context_liverange(const LiveRange &LR) const; + void report_context_lanemask(LaneBitmask LaneMask) const; + void report_context_vreg(unsigned VReg) const; + void report_context_vreg_regunit(unsigned VRegOrRegUnit) const; void verifyInlineAsm(const MachineInstr *MI); void checkLiveness(const MachineOperand *MO, unsigned MONum); + void checkLivenessAtUse(const MachineOperand *MO, unsigned MONum, + SlotIndex UseIdx, const LiveRange &LR, unsigned Reg, + LaneBitmask LaneMask = 0); + void checkLivenessAtDef(const MachineOperand *MO, unsigned MONum, + SlotIndex DefIdx, const LiveRange &LR, unsigned Reg, + LaneBitmask LaneMask = 0); + void markReachable(const MachineBasicBlock *MBB); void calcRegsPassed(); void checkPHIOps(const MachineBasicBlock *MBB); @@ -239,6 +251,7 @@ namespace { void verifyStackFrame(); void verifySlotIndexes() const; + void verifyProperties(const MachineFunction &MF); }; struct MachineVerifierPass : public MachineFunctionPass { @@ -256,7 +269,9 @@ namespace { } bool runOnMachineFunction(MachineFunction &MF) override { - MF.verify(this, Banner.c_str()); + unsigned FoundErrors = MachineVerifier(this, Banner.c_str()).verify(MF); + if (FoundErrors) + report_fatal_error("Found "+Twine(FoundErrors)+" machine code errors."); return false; } }; @@ -271,9 +286,13 @@ FunctionPass *llvm::createMachineVerifierPass(const std::string &Banner) { return new MachineVerifierPass(Banner); } -void MachineFunction::verify(Pass *p, const char *Banner) const { - MachineVerifier(p, Banner) - .runOnMachineFunction(const_cast<MachineFunction&>(*this)); +bool MachineFunction::verify(Pass *p, const char *Banner, bool AbortOnErrors) + const { + MachineFunction &MF = const_cast<MachineFunction&>(*this); + unsigned FoundErrors = MachineVerifier(p, Banner).verify(MF); + if (AbortOnErrors && FoundErrors) + report_fatal_error("Found "+Twine(FoundErrors)+" machine code errors."); + return FoundErrors == 0; } void MachineVerifier::verifySlotIndexes() const { @@ -289,7 +308,20 @@ void MachineVerifier::verifySlotIndexes() const { } } -bool MachineVerifier::runOnMachineFunction(MachineFunction &MF) { +void MachineVerifier::verifyProperties(const MachineFunction &MF) { + // If a pass has introduced virtual registers without clearing the + // AllVRegsAllocated property (or set it without allocating the vregs) + // then report an error. + if (MF.getProperties().hasProperty( + MachineFunctionProperties::Property::AllVRegsAllocated) && + MRI->getNumVirtRegs()) { + report( + "Function has AllVRegsAllocated property but there are VReg operands", + &MF); + } +} + +unsigned MachineVerifier::verify(MachineFunction &MF) { foundErrors = 0; this->MF = &MF; @@ -313,6 +345,8 @@ bool MachineVerifier::runOnMachineFunction(MachineFunction &MF) { verifySlotIndexes(); + verifyProperties(MF); + visitMachineFunctionBefore(); for (MachineFunction::const_iterator MFI = MF.begin(), MFE = MF.end(); MFI!=MFE; ++MFI) { @@ -374,9 +408,6 @@ bool MachineVerifier::runOnMachineFunction(MachineFunction &MF) { } visitMachineFunctionAfter(); - if (foundErrors) - report_fatal_error("Found "+Twine(foundErrors)+" machine code errors."); - // Clean up. regsLive.clear(); regsDefined.clear(); @@ -386,7 +417,7 @@ bool MachineVerifier::runOnMachineFunction(MachineFunction &MF) { regsLiveInButUnused.clear(); MBBInfoMap.clear(); - return false; // no changes + return foundErrors; } void MachineVerifier::report(const char *msg, const MachineFunction *MF) { @@ -420,8 +451,8 @@ void MachineVerifier::report(const char *msg, const MachineInstr *MI) { assert(MI); report(msg, MI->getParent()); errs() << "- instruction: "; - if (Indexes && Indexes->hasIndex(MI)) - errs() << Indexes->getInstructionIndex(MI) << '\t'; + if (Indexes && Indexes->hasIndex(*MI)) + errs() << Indexes->getInstructionIndex(*MI) << '\t'; MI->print(errs(), /*SkipOpers=*/true); errs() << '\n'; } @@ -435,16 +466,20 @@ void MachineVerifier::report(const char *msg, errs() << "\n"; } +void MachineVerifier::report_context(SlotIndex Pos) const { + errs() << "- at: " << Pos << '\n'; +} + void MachineVerifier::report_context(const LiveInterval &LI) const { errs() << "- interval: " << LI << '\n'; } void MachineVerifier::report_context(const LiveRange &LR, unsigned Reg, LaneBitmask LaneMask) const { + report_context_liverange(LR); errs() << "- register: " << PrintReg(Reg, TRI) << '\n'; if (LaneMask != 0) - errs() << "- lanemask: " << PrintLaneMask(LaneMask) << '\n'; - errs() << "- liverange: " << LR << '\n'; + report_context_lanemask(LaneMask); } void MachineVerifier::report_context(const LiveRange::Segment &S) const { @@ -455,6 +490,26 @@ void MachineVerifier::report_context(const VNInfo &VNI) const { errs() << "- ValNo: " << VNI.id << " (def " << VNI.def << ")\n"; } +void MachineVerifier::report_context_liverange(const LiveRange &LR) const { + errs() << "- liverange: " << LR << '\n'; +} + +void MachineVerifier::report_context_vreg(unsigned VReg) const { + errs() << "- v. register: " << PrintReg(VReg, TRI) << '\n'; +} + +void MachineVerifier::report_context_vreg_regunit(unsigned VRegOrUnit) const { + if (TargetRegisterInfo::isVirtualRegister(VRegOrUnit)) { + report_context_vreg(VRegOrUnit); + } else { + errs() << "- regunit: " << PrintRegUnit(VRegOrUnit, TRI) << '\n'; + } +} + +void MachineVerifier::report_context_lanemask(LaneBitmask LaneMask) const { + errs() << "- lanemask: " << PrintLaneMask(LaneMask) << '\n'; +} + void MachineVerifier::markReachable(const MachineBasicBlock *MBB) { BBInfo &MInfo = MBBInfoMap[MBB]; if (!MInfo.reachable) { @@ -521,7 +576,7 @@ MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) { // it is an entry block or landing pad. for (const auto &LI : MBB->liveins()) { if (isAllocatable(LI.PhysReg) && !MBB->isEHPad() && - MBB != MBB->getParent()->begin()) { + MBB->getIterator() != MBB->getParent()->begin()) { report("MBB has allocable live-in, but isn't entry or landing-pad.", MBB); } } @@ -567,8 +622,8 @@ MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) { // Call AnalyzeBranch. If it succeeds, there several more conditions to check. MachineBasicBlock *TBB = nullptr, *FBB = nullptr; SmallVector<MachineOperand, 4> Cond; - if (!TII->AnalyzeBranch(*const_cast<MachineBasicBlock *>(MBB), - TBB, FBB, Cond)) { + if (!TII->analyzeBranch(*const_cast<MachineBasicBlock *>(MBB), TBB, FBB, + Cond)) { // Ok, AnalyzeBranch thinks it knows what's going on with this block. Let's // check whether its answers match up with reality. if (!TBB && !FBB) { @@ -591,7 +646,7 @@ MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) { "differs from its CFG successor!", MBB); } if (!MBB->empty() && MBB->back().isBarrier() && - !TII->isPredicated(&MBB->back())) { + !TII->isPredicated(MBB->back())) { report("MBB exits via unconditional fall-through but ends with a " "barrier instruction!", MBB); } @@ -721,8 +776,8 @@ MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) { // This function gets called for all bundle headers, including normal // stand-alone unbundled instructions. void MachineVerifier::visitMachineBundleBefore(const MachineInstr *MI) { - if (Indexes && Indexes->hasIndex(MI)) { - SlotIndex idx = Indexes->getInstructionIndex(MI); + if (Indexes && Indexes->hasIndex(*MI)) { + SlotIndex idx = Indexes->getInstructionIndex(*MI); if (!(idx > lastIndex)) { report("Instruction index out of order", MI); errs() << "Last instruction was at " << lastIndex << '\n'; @@ -733,7 +788,7 @@ void MachineVerifier::visitMachineBundleBefore(const MachineInstr *MI) { // Ensure non-terminators don't follow terminators. // Ignore predicated terminators formed by if conversion. // FIXME: If conversion shouldn't need to violate this rule. - if (MI->isTerminator() && !TII->isPredicated(MI)) { + if (MI->isTerminator() && !TII->isPredicated(*MI)) { if (!FirstTerminator) FirstTerminator = MI; } else if (FirstTerminator) { @@ -755,8 +810,9 @@ void MachineVerifier::verifyInlineAsm(const MachineInstr *MI) { if (!MI->getOperand(1).isImm()) report("Asm flags must be an immediate", MI); // Allowed flags are Extra_HasSideEffects = 1, Extra_IsAlignStack = 2, - // Extra_AsmDialect = 4, Extra_MayLoad = 8, and Extra_MayStore = 16. - if (!isUInt<5>(MI->getOperand(1).getImm())) + // Extra_AsmDialect = 4, Extra_MayLoad = 8, and Extra_MayStore = 16, + // and Extra_IsConvergent = 32. + if (!isUInt<6>(MI->getOperand(1).getImm())) report("Unknown asm flags", &MI->getOperand(1), 1); static_assert(InlineAsm::MIOp_FirstOperand == 2, "Asm format changed"); @@ -810,7 +866,7 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) { // Debug values must not have a slot index. // Other instructions must have one, unless they are inside a bundle. if (LiveInts) { - bool mapped = !LiveInts->isNotInMIMap(MI); + bool mapped = !LiveInts->isNotInMIMap(*MI); if (MI->isDebugValue()) { if (mapped) report("Debug instruction has a slot index", MI); @@ -824,7 +880,7 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) { } StringRef ErrorInfo; - if (!TII->verifyInstruction(MI, ErrorInfo)) + if (!TII->verifyInstruction(*MI, ErrorInfo)) report(ErrorInfo.data(), MI); } @@ -929,7 +985,30 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { } } else { // Virtual register. - const TargetRegisterClass *RC = MRI->getRegClass(Reg); + const TargetRegisterClass *RC = MRI->getRegClassOrNull(Reg); + if (!RC) { + // This is a generic virtual register. + // It must have a size and it must not have a SubIdx. + unsigned Size = MRI->getSize(Reg); + if (!Size) { + report("Generic virtual register must have a size", MO, MONum); + return; + } + // Make sure the register fits into its register bank if any. + const RegisterBank *RegBank = MRI->getRegBankOrNull(Reg); + if (RegBank && RegBank->getSize() < Size) { + report("Register bank is too small for virtual register", MO, + MONum); + errs() << "Register bank " << RegBank->getName() << " too small(" + << RegBank->getSize() << ") to fit " << Size << "-bits\n"; + return; + } + if (SubIdx) { + report("Generic virtual register does not subregister index", MO, MONum); + return; + } + break; + } if (SubIdx) { const TargetRegisterClass *SRC = TRI->getSubClassWithSubReg(RC, SubIdx); @@ -984,10 +1063,10 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { case MachineOperand::MO_FrameIndex: if (LiveStks && LiveStks->hasInterval(MO->getIndex()) && - LiveInts && !LiveInts->isNotInMIMap(MI)) { + LiveInts && !LiveInts->isNotInMIMap(*MI)) { int FI = MO->getIndex(); LiveInterval &LI = LiveStks->getInterval(FI); - SlotIndex Idx = LiveInts->getInstructionIndex(MI); + SlotIndex Idx = LiveInts->getInstructionIndex(*MI); bool stores = MI->mayStore(); bool loads = MI->mayLoad(); @@ -1028,6 +1107,83 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { } } +void MachineVerifier::checkLivenessAtUse(const MachineOperand *MO, + unsigned MONum, SlotIndex UseIdx, const LiveRange &LR, unsigned VRegOrUnit, + LaneBitmask LaneMask) { + LiveQueryResult LRQ = LR.Query(UseIdx); + // Check if we have a segment at the use, note however that we only need one + // live subregister range, the others may be dead. + if (!LRQ.valueIn() && LaneMask == 0) { + report("No live segment at use", MO, MONum); + report_context_liverange(LR); + report_context_vreg_regunit(VRegOrUnit); + report_context(UseIdx); + } + if (MO->isKill() && !LRQ.isKill()) { + report("Live range continues after kill flag", MO, MONum); + report_context_liverange(LR); + report_context_vreg_regunit(VRegOrUnit); + if (LaneMask != 0) + report_context_lanemask(LaneMask); + report_context(UseIdx); + } +} + +void MachineVerifier::checkLivenessAtDef(const MachineOperand *MO, + unsigned MONum, SlotIndex DefIdx, const LiveRange &LR, unsigned VRegOrUnit, + LaneBitmask LaneMask) { + if (const VNInfo *VNI = LR.getVNInfoAt(DefIdx)) { + assert(VNI && "NULL valno is not allowed"); + if (VNI->def != DefIdx) { + report("Inconsistent valno->def", MO, MONum); + report_context_liverange(LR); + report_context_vreg_regunit(VRegOrUnit); + if (LaneMask != 0) + report_context_lanemask(LaneMask); + report_context(*VNI); + report_context(DefIdx); + } + } else { + report("No live segment at def", MO, MONum); + report_context_liverange(LR); + report_context_vreg_regunit(VRegOrUnit); + if (LaneMask != 0) + report_context_lanemask(LaneMask); + report_context(DefIdx); + } + // Check that, if the dead def flag is present, LiveInts agree. + if (MO->isDead()) { + LiveQueryResult LRQ = LR.Query(DefIdx); + if (!LRQ.isDeadDef()) { + // In case of physregs we can have a non-dead definition on another + // operand. + bool otherDef = false; + if (!TargetRegisterInfo::isVirtualRegister(VRegOrUnit)) { + const MachineInstr &MI = *MO->getParent(); + for (const MachineOperand &MO : MI.operands()) { + if (!MO.isReg() || !MO.isDef() || MO.isDead()) + continue; + unsigned Reg = MO.getReg(); + for (MCRegUnitIterator Units(Reg, TRI); Units.isValid(); ++Units) { + if (*Units == VRegOrUnit) { + otherDef = true; + break; + } + } + } + } + + if (!otherDef) { + report("Live range continues after dead def flag", MO, MONum); + report_context_liverange(LR); + report_context_vreg_regunit(VRegOrUnit); + if (LaneMask != 0) + report_context_lanemask(LaneMask); + } + } + } +} + void MachineVerifier::checkLiveness(const MachineOperand *MO, unsigned MONum) { const MachineInstr *MI = MO->getParent(); const unsigned Reg = MO->getReg(); @@ -1048,23 +1204,13 @@ void MachineVerifier::checkLiveness(const MachineOperand *MO, unsigned MONum) { } // Check LiveInts liveness and kill. - if (LiveInts && !LiveInts->isNotInMIMap(MI)) { - SlotIndex UseIdx = LiveInts->getInstructionIndex(MI); + if (LiveInts && !LiveInts->isNotInMIMap(*MI)) { + SlotIndex UseIdx = LiveInts->getInstructionIndex(*MI); // Check the cached regunit intervals. if (TargetRegisterInfo::isPhysicalRegister(Reg) && !isReserved(Reg)) { for (MCRegUnitIterator Units(Reg, TRI); Units.isValid(); ++Units) { - if (const LiveRange *LR = LiveInts->getCachedRegUnit(*Units)) { - LiveQueryResult LRQ = LR->Query(UseIdx); - if (!LRQ.valueIn()) { - report("No live segment at use", MO, MONum); - errs() << UseIdx << " is not live in " << PrintRegUnit(*Units, TRI) - << ' ' << *LR << '\n'; - } - if (MO->isKill() && !LRQ.isKill()) { - report("Live range continues after kill flag", MO, MONum); - errs() << PrintRegUnit(*Units, TRI) << ' ' << *LR << '\n'; - } - } + if (const LiveRange *LR = LiveInts->getCachedRegUnit(*Units)) + checkLivenessAtUse(MO, MONum, UseIdx, *LR, *Units); } } @@ -1072,16 +1218,28 @@ void MachineVerifier::checkLiveness(const MachineOperand *MO, unsigned MONum) { if (LiveInts->hasInterval(Reg)) { // This is a virtual register interval. const LiveInterval &LI = LiveInts->getInterval(Reg); - LiveQueryResult LRQ = LI.Query(UseIdx); - if (!LRQ.valueIn()) { - report("No live segment at use", MO, MONum); - errs() << UseIdx << " is not live in " << LI << '\n'; - } - // Check for extra kill flags. - // Note that we allow missing kill flags for now. - if (MO->isKill() && !LRQ.isKill()) { - report("Live range continues after kill flag", MO, MONum); - errs() << "Live range: " << LI << '\n'; + checkLivenessAtUse(MO, MONum, UseIdx, LI, Reg); + + if (LI.hasSubRanges() && !MO->isDef()) { + unsigned SubRegIdx = MO->getSubReg(); + LaneBitmask MOMask = SubRegIdx != 0 + ? TRI->getSubRegIndexLaneMask(SubRegIdx) + : MRI->getMaxLaneMaskForVReg(Reg); + LaneBitmask LiveInMask = 0; + for (const LiveInterval::SubRange &SR : LI.subranges()) { + if ((MOMask & SR.LaneMask) == 0) + continue; + checkLivenessAtUse(MO, MONum, UseIdx, SR, Reg, SR.LaneMask); + LiveQueryResult LRQ = SR.Query(UseIdx); + if (LRQ.valueIn()) + LiveInMask |= SR.LaneMask; + } + // At least parts of the register has to be live at the use. + if ((LiveInMask & MOMask) == 0) { + report("No live subrange at use", MO, MONum); + report_context(LI); + report_context(UseIdx); + } } } else { report("Virtual register has no live interval", MO, MONum); @@ -1154,33 +1312,29 @@ void MachineVerifier::checkLiveness(const MachineOperand *MO, unsigned MONum) { report("Multiple virtual register defs in SSA form", MO, MONum); // Check LiveInts for a live segment, but only for virtual registers. - if (LiveInts && TargetRegisterInfo::isVirtualRegister(Reg) && - !LiveInts->isNotInMIMap(MI)) { - SlotIndex DefIdx = LiveInts->getInstructionIndex(MI); + if (LiveInts && !LiveInts->isNotInMIMap(*MI)) { + SlotIndex DefIdx = LiveInts->getInstructionIndex(*MI); DefIdx = DefIdx.getRegSlot(MO->isEarlyClobber()); - if (LiveInts->hasInterval(Reg)) { - const LiveInterval &LI = LiveInts->getInterval(Reg); - if (const VNInfo *VNI = LI.getVNInfoAt(DefIdx)) { - assert(VNI && "NULL valno is not allowed"); - if (VNI->def != DefIdx) { - report("Inconsistent valno->def", MO, MONum); - errs() << "Valno " << VNI->id << " is not defined at " - << DefIdx << " in " << LI << '\n'; + + if (TargetRegisterInfo::isVirtualRegister(Reg)) { + if (LiveInts->hasInterval(Reg)) { + const LiveInterval &LI = LiveInts->getInterval(Reg); + checkLivenessAtDef(MO, MONum, DefIdx, LI, Reg); + + if (LI.hasSubRanges()) { + unsigned SubRegIdx = MO->getSubReg(); + LaneBitmask MOMask = SubRegIdx != 0 + ? TRI->getSubRegIndexLaneMask(SubRegIdx) + : MRI->getMaxLaneMaskForVReg(Reg); + for (const LiveInterval::SubRange &SR : LI.subranges()) { + if ((SR.LaneMask & MOMask) == 0) + continue; + checkLivenessAtDef(MO, MONum, DefIdx, SR, Reg, SR.LaneMask); + } } } else { - report("No live segment at def", MO, MONum); - errs() << DefIdx << " is not live in " << LI << '\n'; - } - // Check that, if the dead def flag is present, LiveInts agree. - if (MO->isDead()) { - LiveQueryResult LRQ = LI.Query(DefIdx); - if (!LRQ.isDeadDef()) { - report("Live range continues after dead def flag", MO, MONum); - errs() << "Live range: " << LI << '\n'; - } + report("Virtual register has no Live interval", MO, MONum); } - } else { - report("Virtual register has no Live interval", MO, MONum); } } } @@ -1360,9 +1514,10 @@ void MachineVerifier::visitMachineFunctionAfter() { BBInfo &MInfo = MBBInfoMap[&MF->front()]; for (RegSet::iterator I = MInfo.vregsRequired.begin(), E = MInfo.vregsRequired.end(); I != E; - ++I) - report("Virtual register def doesn't dominate all uses.", - MRI->getVRegDef(*I)); + ++I) { + report("Virtual register defs don't dominate all uses.", MF); + report_context_vreg(*I); + } } if (LiveVars) @@ -1474,7 +1629,7 @@ void MachineVerifier::verifyLiveRangeValue(const LiveRange &LR, if (Reg != 0) { bool hasDef = false; bool isEarlyClobber = false; - for (ConstMIBundleOperands MOI(MI); MOI.isValid(); ++MOI) { + for (ConstMIBundleOperands MOI(*MI); MOI.isValid(); ++MOI) { if (!MOI->isReg() || !MOI->isDef()) continue; if (TargetRegisterInfo::isVirtualRegister(Reg)) { @@ -1613,18 +1768,33 @@ void MachineVerifier::verifyLiveRangeSegment(const LiveRange &LR, // use, or a dead flag on a def. bool hasRead = false; bool hasSubRegDef = false; - for (ConstMIBundleOperands MOI(MI); MOI.isValid(); ++MOI) { + bool hasDeadDef = false; + for (ConstMIBundleOperands MOI(*MI); MOI.isValid(); ++MOI) { if (!MOI->isReg() || MOI->getReg() != Reg) continue; if (LaneMask != 0 && (LaneMask & TRI->getSubRegIndexLaneMask(MOI->getSubReg())) == 0) continue; - if (MOI->isDef() && MOI->getSubReg() != 0) - hasSubRegDef = true; + if (MOI->isDef()) { + if (MOI->getSubReg() != 0) + hasSubRegDef = true; + if (MOI->isDead()) + hasDeadDef = true; + } if (MOI->readsReg()) hasRead = true; } - if (!S.end.isDead()) { + if (S.end.isDead()) { + // Make sure that the corresponding machine operand for a "dead" live + // range has the dead flag. We cannot perform this check for subregister + // liveranges as partially dead values are allowed. + if (LaneMask == 0 && !hasDeadDef) { + report("Instruction ending live segment on dead slot has no dead flag", + MI); + report_context(LR, Reg, LaneMask); + report_context(S); + } + } else { if (!hasRead) { // When tracking subregister liveness, the main range must start new // values on partial register writes, even if there is no read. @@ -1670,8 +1840,9 @@ void MachineVerifier::verifyLiveRangeSegment(const LiveRange &LR, SlotIndex PEnd = LiveInts->getMBBEndIdx(*PI); const VNInfo *PVNI = LR.getVNInfoBefore(PEnd); - // All predecessors must have a live-out value. - if (!PVNI) { + // All predecessors must have a live-out value if this is not a + // subregister liverange. + if (!PVNI && LaneMask == 0) { report("Register not marked live out of predecessor", *PI); report_context(LR, Reg, LaneMask); report_context(*VNI); |