diff options
Diffstat (limited to 'lib/CodeGen/MachineVerifier.cpp')
| -rw-r--r-- | lib/CodeGen/MachineVerifier.cpp | 164 |
1 files changed, 135 insertions, 29 deletions
diff --git a/lib/CodeGen/MachineVerifier.cpp b/lib/CodeGen/MachineVerifier.cpp index 318776136e24..534d3699db29 100644 --- a/lib/CodeGen/MachineVerifier.cpp +++ b/lib/CodeGen/MachineVerifier.cpp @@ -23,6 +23,7 @@ // the verifier errors. //===----------------------------------------------------------------------===// +#include "LiveRangeCalc.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" @@ -108,6 +109,7 @@ namespace { using RegMap = DenseMap<unsigned, const MachineInstr *>; using BlockSet = SmallPtrSet<const MachineBasicBlock *, 8>; + const MachineInstr *FirstNonPHI; const MachineInstr *FirstTerminator; BlockSet FunctionBlocks; @@ -248,6 +250,7 @@ namespace { void report_context(const LiveRange::Segment &S) const; void report_context(const VNInfo &VNI) const; void report_context(SlotIndex Pos) const; + void report_context(MCPhysReg PhysReg) const; void report_context_liverange(const LiveRange &LR) const; void report_context_lanemask(LaneBitmask LaneMask) const; void report_context_vreg(unsigned VReg) const; @@ -261,6 +264,7 @@ namespace { LaneBitmask LaneMask = LaneBitmask::getNone()); void checkLivenessAtDef(const MachineOperand *MO, unsigned MONum, SlotIndex DefIdx, const LiveRange &LR, unsigned VRegOrUnit, + bool SubRangeCheck = false, LaneBitmask LaneMask = LaneBitmask::getNone()); void markReachable(const MachineBasicBlock *MBB); @@ -362,6 +366,13 @@ unsigned MachineVerifier::verify(MachineFunction &MF) { const bool isFunctionFailedISel = MF.getProperties().hasProperty( MachineFunctionProperties::Property::FailedISel); + + // If we're mid-GlobalISel and we already triggered the fallback path then + // it's expected that the MIR is somewhat broken but that's ok since we'll + // reset it and clear the FailedISel attribute in ResetMachineFunctions. + if (isFunctionFailedISel) + return foundErrors; + isFunctionRegBankSelected = !isFunctionFailedISel && MF.getProperties().hasProperty( @@ -530,6 +541,10 @@ void MachineVerifier::report_context_liverange(const LiveRange &LR) const { errs() << "- liverange: " << LR << '\n'; } +void MachineVerifier::report_context(MCPhysReg PReg) const { + errs() << "- p. register: " << printReg(PReg, TRI) << '\n'; +} + void MachineVerifier::report_context_vreg(unsigned VReg) const { errs() << "- v. register: " << printReg(VReg, TRI) << '\n'; } @@ -599,6 +614,7 @@ static bool matchPair(MachineBasicBlock::const_succ_iterator i, void MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) { FirstTerminator = nullptr; + FirstNonPHI = nullptr; if (!MF->getProperties().hasProperty( MachineFunctionProperties::Property::NoPHIs) && MRI->tracksLiveness()) { @@ -608,6 +624,7 @@ MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) { if (isAllocatable(LI.PhysReg) && !MBB->isEHPad() && MBB->getIterator() != MBB->getParent()->begin()) { report("MBB has allocatable live-in, but isn't entry or landing-pad.", MBB); + report_context(LI.PhysReg); } } } @@ -666,7 +683,7 @@ MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) { // out the bottom of the function. } else if (MBB->succ_size() == LandingPadSuccs.size()) { // It's possible that the block legitimately ends with a noreturn - // call or an unreachable, in which case it won't actuall fall + // call or an unreachable, in which case it won't actually fall // out of the block. } else if (MBB->succ_size() != 1+LandingPadSuccs.size()) { report("MBB exits via unconditional fall-through but doesn't have " @@ -767,7 +784,7 @@ MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) { "isn't a terminator instruction!", MBB); } if (Cond.empty()) { - report("MBB exits via conditinal branch/branch but there's no " + report("MBB exits via conditional branch/branch but there's no " "condition!", MBB); } } else { @@ -880,9 +897,15 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) { << MI->getNumOperands() << " given.\n"; } - if (MI->isPHI() && MF->getProperties().hasProperty( - MachineFunctionProperties::Property::NoPHIs)) - report("Found PHI instruction with NoPHIs property set", MI); + if (MI->isPHI()) { + if (MF->getProperties().hasProperty( + MachineFunctionProperties::Property::NoPHIs)) + report("Found PHI instruction with NoPHIs property set", MI); + + if (FirstNonPHI) + report("Found PHI instruction after non-PHI", MI); + } else if (FirstNonPHI == nullptr) + FirstNonPHI = MI; // Check the tied operands. if (MI->isInlineAsm()) @@ -1038,6 +1061,89 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) { } break; } + case TargetOpcode::G_MERGE_VALUES: { + // G_MERGE_VALUES should only be used to merge scalars into a larger scalar, + // e.g. s2N = MERGE sN, sN + // Merging multiple scalars into a vector is not allowed, should use + // G_BUILD_VECTOR for that. + LLT DstTy = MRI->getType(MI->getOperand(0).getReg()); + LLT SrcTy = MRI->getType(MI->getOperand(1).getReg()); + if (DstTy.isVector() || SrcTy.isVector()) + report("G_MERGE_VALUES cannot operate on vectors", MI); + break; + } + case TargetOpcode::G_UNMERGE_VALUES: { + LLT DstTy = MRI->getType(MI->getOperand(0).getReg()); + LLT SrcTy = MRI->getType(MI->getOperand(MI->getNumOperands()-1).getReg()); + // For now G_UNMERGE can split vectors. + for (unsigned i = 0; i < MI->getNumOperands()-1; ++i) { + if (MRI->getType(MI->getOperand(i).getReg()) != DstTy) + report("G_UNMERGE_VALUES destination types do not match", MI); + } + if (SrcTy.getSizeInBits() != + (DstTy.getSizeInBits() * (MI->getNumOperands() - 1))) { + report("G_UNMERGE_VALUES source operand does not cover dest operands", + MI); + } + break; + } + case TargetOpcode::G_BUILD_VECTOR: { + // Source types must be scalars, dest type a vector. Total size of scalars + // must match the dest vector size. + LLT DstTy = MRI->getType(MI->getOperand(0).getReg()); + LLT SrcEltTy = MRI->getType(MI->getOperand(1).getReg()); + if (!DstTy.isVector() || SrcEltTy.isVector()) + report("G_BUILD_VECTOR must produce a vector from scalar operands", MI); + for (unsigned i = 2; i < MI->getNumOperands(); ++i) { + if (MRI->getType(MI->getOperand(1).getReg()) != + MRI->getType(MI->getOperand(i).getReg())) + report("G_BUILD_VECTOR source operand types are not homogeneous", MI); + } + if (DstTy.getSizeInBits() != + SrcEltTy.getSizeInBits() * (MI->getNumOperands() - 1)) + report("G_BUILD_VECTOR src operands total size don't match dest " + "size.", + MI); + break; + } + case TargetOpcode::G_BUILD_VECTOR_TRUNC: { + // Source types must be scalars, dest type a vector. Scalar types must be + // larger than the dest vector elt type, as this is a truncating operation. + LLT DstTy = MRI->getType(MI->getOperand(0).getReg()); + LLT SrcEltTy = MRI->getType(MI->getOperand(1).getReg()); + if (!DstTy.isVector() || SrcEltTy.isVector()) + report("G_BUILD_VECTOR_TRUNC must produce a vector from scalar operands", + MI); + for (unsigned i = 2; i < MI->getNumOperands(); ++i) { + if (MRI->getType(MI->getOperand(1).getReg()) != + MRI->getType(MI->getOperand(i).getReg())) + report("G_BUILD_VECTOR_TRUNC source operand types are not homogeneous", + MI); + } + if (SrcEltTy.getSizeInBits() <= DstTy.getElementType().getSizeInBits()) + report("G_BUILD_VECTOR_TRUNC source operand types are not larger than " + "dest elt type", + MI); + break; + } + case TargetOpcode::G_CONCAT_VECTORS: { + // Source types should be vectors, and total size should match the dest + // vector size. + LLT DstTy = MRI->getType(MI->getOperand(0).getReg()); + LLT SrcTy = MRI->getType(MI->getOperand(1).getReg()); + if (!DstTy.isVector() || !SrcTy.isVector()) + report("G_CONCAT_VECTOR requires vector source and destination operands", + MI); + for (unsigned i = 2; i < MI->getNumOperands(); ++i) { + if (MRI->getType(MI->getOperand(1).getReg()) != + MRI->getType(MI->getOperand(i).getReg())) + report("G_CONCAT_VECTOR source operand types are not homogeneous", MI); + } + if (DstTy.getNumElements() != + SrcTy.getNumElements() * (MI->getNumOperands() - 1)) + report("G_CONCAT_VECTOR num dest and source elements should match", MI); + break; + } case TargetOpcode::COPY: { if (foundErrors) break; @@ -1395,7 +1501,7 @@ void MachineVerifier::checkLivenessAtUse(const MachineOperand *MO, void MachineVerifier::checkLivenessAtDef(const MachineOperand *MO, unsigned MONum, SlotIndex DefIdx, const LiveRange &LR, unsigned VRegOrUnit, - LaneBitmask LaneMask) { + bool SubRangeCheck, LaneBitmask LaneMask) { if (const VNInfo *VNI = LR.getVNInfoAt(DefIdx)) { assert(VNI && "NULL valno is not allowed"); if (VNI->def != DefIdx) { @@ -1419,25 +1525,14 @@ void MachineVerifier::checkLivenessAtDef(const MachineOperand *MO, 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) { + assert(TargetRegisterInfo::isVirtualRegister(VRegOrUnit) && + "Expecting a virtual register."); + // A dead subreg def only tells us that the specific subreg is dead. There + // could be other non-dead defs of other subregs, or we could have other + // parts of the register being live through the instruction. So unless we + // are checking liveness for a subrange it is ok for the live range to + // continue, given that we have a dead def of a subregister. + if (SubRangeCheck || MO->getSubReg() == 0) { report("Live range continues after dead def flag", MO, MONum); report_context_liverange(LR); report_context_vreg_regunit(VRegOrUnit); @@ -1532,10 +1627,12 @@ void MachineVerifier::checkLiveness(const MachineOperand *MO, unsigned MONum) { // get a report for its operand. if (Bad) { for (const MachineOperand &MOP : MI->uses()) { - if (!MOP.isReg()) + if (!MOP.isReg() || !MOP.isImplicit()) continue; - if (!MOP.isImplicit()) + + if (!TargetRegisterInfo::isPhysicalRegister(MOP.getReg())) continue; + for (MCSubRegIterator SubRegs(MOP.getReg(), TRI); SubRegs.isValid(); ++SubRegs) { if (*SubRegs == Reg) { @@ -1593,7 +1690,7 @@ void MachineVerifier::checkLiveness(const MachineOperand *MO, unsigned MONum) { for (const LiveInterval::SubRange &SR : LI.subranges()) { if ((SR.LaneMask & MOMask).none()) continue; - checkLivenessAtDef(MO, MONum, DefIdx, SR, Reg, SR.LaneMask); + checkLivenessAtDef(MO, MONum, DefIdx, SR, Reg, true, SR.LaneMask); } } } else { @@ -2116,6 +2213,13 @@ void MachineVerifier::verifyLiveRangeSegment(const LiveRange &LR, // Skip this block. ++MFI; } + + SmallVector<SlotIndex, 4> Undefs; + if (LaneMask.any()) { + LiveInterval &OwnerLI = LiveInts->getInterval(Reg); + OwnerLI.computeSubRangeUndefs(Undefs, LaneMask, *MRI, *Indexes); + } + while (true) { assert(LiveInts->isLiveInToMBB(LR, &*MFI)); // We don't know how to track physregs into a landing pad. @@ -2141,7 +2245,9 @@ void MachineVerifier::verifyLiveRangeSegment(const LiveRange &LR, // instruction with subregister intervals // only one of the subregisters (not necessarily the current one) needs to // be defined. - if (!PVNI && (LaneMask.none() || !IsPHI) ) { + if (!PVNI && (LaneMask.none() || !IsPHI)) { + if (LiveRangeCalc::isJointlyDominated(*PI, Undefs, *Indexes)) + continue; report("Register not marked live out of predecessor", *PI); report_context(LR, Reg, LaneMask); report_context(*VNI); |
