aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/MachineVerifier.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
commite6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch)
tree599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/CodeGen/MachineVerifier.cpp
parent1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff)
Diffstat (limited to 'lib/CodeGen/MachineVerifier.cpp')
-rw-r--r--lib/CodeGen/MachineVerifier.cpp510
1 files changed, 403 insertions, 107 deletions
diff --git a/lib/CodeGen/MachineVerifier.cpp b/lib/CodeGen/MachineVerifier.cpp
index 534d3699db29..0ad792ac62cf 100644
--- a/lib/CodeGen/MachineVerifier.cpp
+++ b/lib/CodeGen/MachineVerifier.cpp
@@ -1,9 +1,8 @@
//===- MachineVerifier.cpp - Machine Code Verifier ------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -219,7 +218,7 @@ namespace {
bool isAllocatable(unsigned Reg) const {
return Reg < TRI->getNumRegs() && TRI->isInAllocatableClass(Reg) &&
- !regsReserved.test(Reg);
+ !regsReserved.test(Reg);
}
// Analysis information if available
@@ -231,6 +230,9 @@ namespace {
void visitMachineFunctionBefore();
void visitMachineBasicBlockBefore(const MachineBasicBlock *MBB);
void visitMachineBundleBefore(const MachineInstr *MI);
+
+ bool verifyVectorElementMatch(LLT Ty0, LLT Ty1, const MachineInstr *MI);
+ void verifyPreISelGenericInstruction(const MachineInstr *MI);
void visitMachineInstrBefore(const MachineInstr *MI);
void visitMachineOperand(const MachineOperand *MO, unsigned MONum);
void visitMachineInstrAfter(const MachineInstr *MI);
@@ -838,7 +840,7 @@ void MachineVerifier::visitMachineBundleBefore(const MachineInstr *MI) {
if (MI->isTerminator() && !TII->isPredicated(*MI)) {
if (!FirstTerminator)
FirstTerminator = MI;
- } else if (FirstTerminator) {
+ } else if (FirstTerminator && !MI->isDebugEntryValue()) {
report("Non-terminator instruction after the first terminator", MI);
errs() << "First terminator was:\t" << *FirstTerminator;
}
@@ -889,109 +891,150 @@ void MachineVerifier::verifyInlineAsm(const MachineInstr *MI) {
}
}
-void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
- const MCInstrDesc &MCID = MI->getDesc();
- if (MI->getNumOperands() < MCID.getNumOperands()) {
- report("Too few operands", MI);
- errs() << MCID.getNumOperands() << " operands expected, but "
- << MI->getNumOperands() << " given.\n";
+/// Check that types are consistent when two operands need to have the same
+/// number of vector elements.
+/// \return true if the types are valid.
+bool MachineVerifier::verifyVectorElementMatch(LLT Ty0, LLT Ty1,
+ const MachineInstr *MI) {
+ if (Ty0.isVector() != Ty1.isVector()) {
+ report("operand types must be all-vector or all-scalar", MI);
+ // Generally we try to report as many issues as possible at once, but in
+ // this case it's not clear what should we be comparing the size of the
+ // scalar with: the size of the whole vector or its lane. Instead of
+ // making an arbitrary choice and emitting not so helpful message, let's
+ // avoid the extra noise and stop here.
+ return false;
}
- if (MI->isPHI()) {
- if (MF->getProperties().hasProperty(
- MachineFunctionProperties::Property::NoPHIs))
- report("Found PHI instruction with NoPHIs property set", MI);
+ if (Ty0.isVector() && Ty0.getNumElements() != Ty1.getNumElements()) {
+ report("operand types must preserve number of vector elements", MI);
+ return false;
+ }
- if (FirstNonPHI)
- report("Found PHI instruction after non-PHI", MI);
- } else if (FirstNonPHI == nullptr)
- FirstNonPHI = MI;
+ return true;
+}
- // Check the tied operands.
- if (MI->isInlineAsm())
- verifyInlineAsm(MI);
+void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
+ if (isFunctionSelected)
+ report("Unexpected generic instruction in a Selected function", MI);
- // Check the MachineMemOperands for basic consistency.
- for (MachineInstr::mmo_iterator I = MI->memoperands_begin(),
- E = MI->memoperands_end();
+ const MCInstrDesc &MCID = MI->getDesc();
+ unsigned NumOps = MI->getNumOperands();
+
+ // Check types.
+ SmallVector<LLT, 4> Types;
+ for (unsigned I = 0, E = std::min(MCID.getNumOperands(), NumOps);
I != E; ++I) {
- if ((*I)->isLoad() && !MI->mayLoad())
- report("Missing mayLoad flag", MI);
- if ((*I)->isStore() && !MI->mayStore())
- report("Missing mayStore flag", MI);
- }
+ if (!MCID.OpInfo[I].isGenericType())
+ continue;
+ // Generic instructions specify type equality constraints between some of
+ // their operands. Make sure these are consistent.
+ size_t TypeIdx = MCID.OpInfo[I].getGenericTypeIndex();
+ Types.resize(std::max(TypeIdx + 1, Types.size()));
+
+ const MachineOperand *MO = &MI->getOperand(I);
+ if (!MO->isReg()) {
+ report("generic instruction must use register operands", MI);
+ continue;
+ }
- // 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);
- if (MI->isDebugInstr()) {
- if (mapped)
- report("Debug instruction has a slot index", MI);
- } else if (MI->isInsideBundle()) {
- if (mapped)
- report("Instruction inside bundle has a slot index", MI);
+ LLT OpTy = MRI->getType(MO->getReg());
+ // Don't report a type mismatch if there is no actual mismatch, only a
+ // type missing, to reduce noise:
+ if (OpTy.isValid()) {
+ // Only the first valid type for a type index will be printed: don't
+ // overwrite it later so it's always clear which type was expected:
+ if (!Types[TypeIdx].isValid())
+ Types[TypeIdx] = OpTy;
+ else if (Types[TypeIdx] != OpTy)
+ report("Type mismatch in generic instruction", MO, I, OpTy);
} else {
- if (!mapped)
- report("Missing slot index", MI);
+ // Generic instructions must have types attached to their operands.
+ report("Generic instruction is missing a virtual register type", MO, I);
}
}
- if (isPreISelGenericOpcode(MCID.getOpcode())) {
- if (isFunctionSelected)
- report("Unexpected generic instruction in a Selected function", MI);
-
- // Check types.
- SmallVector<LLT, 4> Types;
- for (unsigned I = 0; I < MCID.getNumOperands(); ++I) {
- if (!MCID.OpInfo[I].isGenericType())
- continue;
- // Generic instructions specify type equality constraints between some of
- // their operands. Make sure these are consistent.
- size_t TypeIdx = MCID.OpInfo[I].getGenericTypeIndex();
- Types.resize(std::max(TypeIdx + 1, Types.size()));
-
- const MachineOperand *MO = &MI->getOperand(I);
- LLT OpTy = MRI->getType(MO->getReg());
- // Don't report a type mismatch if there is no actual mismatch, only a
- // type missing, to reduce noise:
- if (OpTy.isValid()) {
- // Only the first valid type for a type index will be printed: don't
- // overwrite it later so it's always clear which type was expected:
- if (!Types[TypeIdx].isValid())
- Types[TypeIdx] = OpTy;
- else if (Types[TypeIdx] != OpTy)
- report("Type mismatch in generic instruction", MO, I, OpTy);
- } else {
- // Generic instructions must have types attached to their operands.
- report("Generic instruction is missing a virtual register type", MO, I);
- }
- }
-
- // Generic opcodes must not have physical register operands.
- for (unsigned I = 0; I < MI->getNumOperands(); ++I) {
- const MachineOperand *MO = &MI->getOperand(I);
- if (MO->isReg() && TargetRegisterInfo::isPhysicalRegister(MO->getReg()))
- report("Generic instruction cannot have physical register", MO, I);
- }
+ // Generic opcodes must not have physical register operands.
+ for (unsigned I = 0; I < MI->getNumOperands(); ++I) {
+ const MachineOperand *MO = &MI->getOperand(I);
+ if (MO->isReg() && TargetRegisterInfo::isPhysicalRegister(MO->getReg()))
+ report("Generic instruction cannot have physical register", MO, I);
}
+ // Avoid out of bounds in checks below. This was already reported earlier.
+ if (MI->getNumOperands() < MCID.getNumOperands())
+ return;
+
StringRef ErrorInfo;
if (!TII->verifyInstruction(*MI, ErrorInfo))
report(ErrorInfo.data(), MI);
// Verify properties of various specific instruction types
- switch(MI->getOpcode()) {
- default:
+ switch (MI->getOpcode()) {
+ case TargetOpcode::G_CONSTANT:
+ case TargetOpcode::G_FCONSTANT: {
+ if (MI->getNumOperands() < MCID.getNumOperands())
+ break;
+
+ LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
+ if (DstTy.isVector())
+ report("Instruction cannot use a vector result type", MI);
+
+ if (MI->getOpcode() == TargetOpcode::G_CONSTANT) {
+ if (!MI->getOperand(1).isCImm()) {
+ report("G_CONSTANT operand must be cimm", MI);
+ break;
+ }
+
+ const ConstantInt *CI = MI->getOperand(1).getCImm();
+ if (CI->getBitWidth() != DstTy.getSizeInBits())
+ report("inconsistent constant size", MI);
+ } else {
+ if (!MI->getOperand(1).isFPImm()) {
+ report("G_FCONSTANT operand must be fpimm", MI);
+ break;
+ }
+ const ConstantFP *CF = MI->getOperand(1).getFPImm();
+
+ if (APFloat::getSizeInBits(CF->getValueAPF().getSemantics()) !=
+ DstTy.getSizeInBits()) {
+ report("inconsistent constant size", MI);
+ }
+ }
+
break;
+ }
case TargetOpcode::G_LOAD:
case TargetOpcode::G_STORE:
+ case TargetOpcode::G_ZEXTLOAD:
+ case TargetOpcode::G_SEXTLOAD: {
+ LLT ValTy = MRI->getType(MI->getOperand(0).getReg());
+ LLT PtrTy = MRI->getType(MI->getOperand(1).getReg());
+ if (!PtrTy.isPointer())
+ report("Generic memory instruction must access a pointer", MI);
+
// Generic loads and stores must have a single MachineMemOperand
// describing that access.
- if (!MI->hasOneMemOperand())
+ if (!MI->hasOneMemOperand()) {
report("Generic instruction accessing memory must have one mem operand",
MI);
+ } else {
+ const MachineMemOperand &MMO = **MI->memoperands_begin();
+ if (MI->getOpcode() == TargetOpcode::G_ZEXTLOAD ||
+ MI->getOpcode() == TargetOpcode::G_SEXTLOAD) {
+ if (MMO.getSizeInBits() >= ValTy.getSizeInBits())
+ report("Generic extload must have a narrower memory type", MI);
+ } else if (MI->getOpcode() == TargetOpcode::G_LOAD) {
+ if (MMO.getSize() > ValTy.getSizeInBytes())
+ report("load memory size cannot exceed result size", MI);
+ } else if (MI->getOpcode() == TargetOpcode::G_STORE) {
+ if (ValTy.getSizeInBytes() < MMO.getSize())
+ report("store memory size cannot exceed value size", MI);
+ }
+ }
+
break;
+ }
case TargetOpcode::G_PHI: {
LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
if (!DstTy.isValid() ||
@@ -1009,6 +1052,70 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
MI);
break;
}
+ case TargetOpcode::G_BITCAST: {
+ LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
+ LLT SrcTy = MRI->getType(MI->getOperand(1).getReg());
+ if (!DstTy.isValid() || !SrcTy.isValid())
+ break;
+
+ if (SrcTy.isPointer() != DstTy.isPointer())
+ report("bitcast cannot convert between pointers and other types", MI);
+
+ if (SrcTy.getSizeInBits() != DstTy.getSizeInBits())
+ report("bitcast sizes must match", MI);
+ break;
+ }
+ case TargetOpcode::G_INTTOPTR:
+ case TargetOpcode::G_PTRTOINT:
+ case TargetOpcode::G_ADDRSPACE_CAST: {
+ LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
+ LLT SrcTy = MRI->getType(MI->getOperand(1).getReg());
+ if (!DstTy.isValid() || !SrcTy.isValid())
+ break;
+
+ verifyVectorElementMatch(DstTy, SrcTy, MI);
+
+ DstTy = DstTy.getScalarType();
+ SrcTy = SrcTy.getScalarType();
+
+ if (MI->getOpcode() == TargetOpcode::G_INTTOPTR) {
+ if (!DstTy.isPointer())
+ report("inttoptr result type must be a pointer", MI);
+ if (SrcTy.isPointer())
+ report("inttoptr source type must not be a pointer", MI);
+ } else if (MI->getOpcode() == TargetOpcode::G_PTRTOINT) {
+ if (!SrcTy.isPointer())
+ report("ptrtoint source type must be a pointer", MI);
+ if (DstTy.isPointer())
+ report("ptrtoint result type must not be a pointer", MI);
+ } else {
+ assert(MI->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST);
+ if (!SrcTy.isPointer() || !DstTy.isPointer())
+ report("addrspacecast types must be pointers", MI);
+ else {
+ if (SrcTy.getAddressSpace() == DstTy.getAddressSpace())
+ report("addrspacecast must convert different address spaces", MI);
+ }
+ }
+
+ break;
+ }
+ case TargetOpcode::G_GEP: {
+ LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
+ LLT PtrTy = MRI->getType(MI->getOperand(1).getReg());
+ LLT OffsetTy = MRI->getType(MI->getOperand(2).getReg());
+ if (!DstTy.isValid() || !PtrTy.isValid() || !OffsetTy.isValid())
+ break;
+
+ if (!PtrTy.getScalarType().isPointer())
+ report("gep first operand must be a pointer", MI);
+
+ if (OffsetTy.getScalarType().isPointer())
+ report("gep offset operand must not be a pointer", MI);
+
+ // TODO: Is the offset allowed to be a scalar with a vector?
+ break;
+ }
case TargetOpcode::G_SEXT:
case TargetOpcode::G_ZEXT:
case TargetOpcode::G_ANYEXT:
@@ -1021,30 +1128,18 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
// instructions aren't guaranteed to have the right number of operands or
// types attached to them at this point
assert(MCID.getNumOperands() == 2 && "Expected 2 operands G_*{EXT,TRUNC}");
- if (MI->getNumOperands() < MCID.getNumOperands())
- break;
LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
LLT SrcTy = MRI->getType(MI->getOperand(1).getReg());
if (!DstTy.isValid() || !SrcTy.isValid())
break;
- LLT DstElTy = DstTy.isVector() ? DstTy.getElementType() : DstTy;
- LLT SrcElTy = SrcTy.isVector() ? SrcTy.getElementType() : SrcTy;
+ LLT DstElTy = DstTy.getScalarType();
+ LLT SrcElTy = SrcTy.getScalarType();
if (DstElTy.isPointer() || SrcElTy.isPointer())
report("Generic extend/truncate can not operate on pointers", MI);
- if (DstTy.isVector() != SrcTy.isVector()) {
- report("Generic extend/truncate must be all-vector or all-scalar", MI);
- // Generally we try to report as many issues as possible at once, but in
- // this case it's not clear what should we be comparing the size of the
- // scalar with: the size of the whole vector or its lane. Instead of
- // making an arbitrary choice and emitting not so helpful message, let's
- // avoid the extra noise and stop here.
- break;
- }
- if (DstTy.isVector() && DstTy.getNumElements() != SrcTy.getNumElements())
- report("Generic vector extend/truncate must preserve number of lanes",
- MI);
+ verifyVectorElementMatch(DstTy, SrcTy, MI);
+
unsigned DstSize = DstElTy.getSizeInBits();
unsigned SrcSize = SrcElTy.getSizeInBits();
switch (MI->getOpcode()) {
@@ -1061,6 +1156,17 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
}
break;
}
+ case TargetOpcode::G_SELECT: {
+ LLT SelTy = MRI->getType(MI->getOperand(0).getReg());
+ LLT CondTy = MRI->getType(MI->getOperand(1).getReg());
+ if (!SelTy.isValid() || !CondTy.isValid())
+ break;
+
+ // Scalar condition select on a vector is valid.
+ if (CondTy.isVector())
+ verifyVectorElementMatch(SelTy, CondTy, 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
@@ -1070,6 +1176,16 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
LLT SrcTy = MRI->getType(MI->getOperand(1).getReg());
if (DstTy.isVector() || SrcTy.isVector())
report("G_MERGE_VALUES cannot operate on vectors", MI);
+
+ const unsigned NumOps = MI->getNumOperands();
+ if (DstTy.getSizeInBits() != SrcTy.getSizeInBits() * (NumOps - 1))
+ report("G_MERGE_VALUES result size is inconsistent", MI);
+
+ for (unsigned I = 2; I != NumOps; ++I) {
+ if (MRI->getType(MI->getOperand(I).getReg()) != SrcTy)
+ report("G_MERGE_VALUES source types do not match", MI);
+ }
+
break;
}
case TargetOpcode::G_UNMERGE_VALUES: {
@@ -1092,18 +1208,23 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
// 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())
+ if (!DstTy.isVector() || SrcEltTy.isVector()) {
report("G_BUILD_VECTOR must produce a vector from scalar operands", MI);
+ break;
+ }
+
+ if (DstTy.getElementType() != SrcEltTy)
+ report("G_BUILD_VECTOR result element type must match source type", MI);
+
+ if (DstTy.getNumElements() != MI->getNumOperands() - 1)
+ report("G_BUILD_VECTOR must have an operand for each elemement", 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: {
@@ -1144,6 +1265,176 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
report("G_CONCAT_VECTOR num dest and source elements should match", MI);
break;
}
+ case TargetOpcode::G_ICMP:
+ case TargetOpcode::G_FCMP: {
+ LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
+ LLT SrcTy = MRI->getType(MI->getOperand(2).getReg());
+
+ if ((DstTy.isVector() != SrcTy.isVector()) ||
+ (DstTy.isVector() && DstTy.getNumElements() != SrcTy.getNumElements()))
+ report("Generic vector icmp/fcmp must preserve number of lanes", MI);
+
+ break;
+ }
+ case TargetOpcode::G_EXTRACT: {
+ const MachineOperand &SrcOp = MI->getOperand(1);
+ if (!SrcOp.isReg()) {
+ report("extract source must be a register", MI);
+ break;
+ }
+
+ const MachineOperand &OffsetOp = MI->getOperand(2);
+ if (!OffsetOp.isImm()) {
+ report("extract offset must be a constant", MI);
+ break;
+ }
+
+ unsigned DstSize = MRI->getType(MI->getOperand(0).getReg()).getSizeInBits();
+ unsigned SrcSize = MRI->getType(SrcOp.getReg()).getSizeInBits();
+ if (SrcSize == DstSize)
+ report("extract source must be larger than result", MI);
+
+ if (DstSize + OffsetOp.getImm() > SrcSize)
+ report("extract reads past end of register", MI);
+ break;
+ }
+ case TargetOpcode::G_INSERT: {
+ const MachineOperand &SrcOp = MI->getOperand(2);
+ if (!SrcOp.isReg()) {
+ report("insert source must be a register", MI);
+ break;
+ }
+
+ const MachineOperand &OffsetOp = MI->getOperand(3);
+ if (!OffsetOp.isImm()) {
+ report("insert offset must be a constant", MI);
+ break;
+ }
+
+ unsigned DstSize = MRI->getType(MI->getOperand(0).getReg()).getSizeInBits();
+ unsigned SrcSize = MRI->getType(SrcOp.getReg()).getSizeInBits();
+
+ if (DstSize <= SrcSize)
+ report("inserted size must be smaller than total register", MI);
+
+ if (SrcSize + OffsetOp.getImm() > DstSize)
+ report("insert writes past end of register", MI);
+
+ break;
+ }
+ case TargetOpcode::G_JUMP_TABLE: {
+ if (!MI->getOperand(1).isJTI())
+ report("G_JUMP_TABLE source operand must be a jump table index", MI);
+ LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
+ if (!DstTy.isPointer())
+ report("G_JUMP_TABLE dest operand must have a pointer type", MI);
+ break;
+ }
+ case TargetOpcode::G_BRJT: {
+ if (!MRI->getType(MI->getOperand(0).getReg()).isPointer())
+ report("G_BRJT src operand 0 must be a pointer type", MI);
+
+ if (!MI->getOperand(1).isJTI())
+ report("G_BRJT src operand 1 must be a jump table index", MI);
+
+ const auto &IdxOp = MI->getOperand(2);
+ if (!IdxOp.isReg() || MRI->getType(IdxOp.getReg()).isPointer())
+ report("G_BRJT src operand 2 must be a scalar reg type", MI);
+ break;
+ }
+ case TargetOpcode::G_INTRINSIC:
+ case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: {
+ // TODO: Should verify number of def and use operands, but the current
+ // interface requires passing in IR types for mangling.
+ const MachineOperand &IntrIDOp = MI->getOperand(MI->getNumExplicitDefs());
+ if (!IntrIDOp.isIntrinsicID()) {
+ report("G_INTRINSIC first src operand must be an intrinsic ID", MI);
+ break;
+ }
+
+ bool NoSideEffects = MI->getOpcode() == TargetOpcode::G_INTRINSIC;
+ unsigned IntrID = IntrIDOp.getIntrinsicID();
+ if (IntrID != 0 && IntrID < Intrinsic::num_intrinsics) {
+ AttributeList Attrs
+ = Intrinsic::getAttributes(MF->getFunction().getContext(),
+ static_cast<Intrinsic::ID>(IntrID));
+ bool DeclHasSideEffects = !Attrs.hasFnAttribute(Attribute::ReadNone);
+ if (NoSideEffects && DeclHasSideEffects) {
+ report("G_INTRINSIC used with intrinsic that accesses memory", MI);
+ break;
+ }
+ if (!NoSideEffects && !DeclHasSideEffects) {
+ report("G_INTRINSIC_W_SIDE_EFFECTS used with readnone intrinsic", MI);
+ break;
+ }
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
+ const MCInstrDesc &MCID = MI->getDesc();
+ if (MI->getNumOperands() < MCID.getNumOperands()) {
+ report("Too few operands", MI);
+ errs() << MCID.getNumOperands() << " operands expected, but "
+ << MI->getNumOperands() << " given.\n";
+ }
+
+ 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())
+ verifyInlineAsm(MI);
+
+ // Check the MachineMemOperands for basic consistency.
+ for (MachineInstr::mmo_iterator I = MI->memoperands_begin(),
+ E = MI->memoperands_end();
+ I != E; ++I) {
+ if ((*I)->isLoad() && !MI->mayLoad())
+ report("Missing mayLoad flag", MI);
+ if ((*I)->isStore() && !MI->mayStore())
+ report("Missing mayStore flag", 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);
+ if (MI->isDebugInstr()) {
+ if (mapped)
+ report("Debug instruction has a slot index", MI);
+ } else if (MI->isInsideBundle()) {
+ if (mapped)
+ report("Instruction inside bundle has a slot index", MI);
+ } else {
+ if (!mapped)
+ report("Missing slot index", MI);
+ }
+ }
+
+ if (isPreISelGenericOpcode(MCID.getOpcode())) {
+ verifyPreISelGenericInstruction(MI);
+ return;
+ }
+
+ StringRef ErrorInfo;
+ if (!TII->verifyInstruction(*MI, ErrorInfo))
+ report(ErrorInfo.data(), MI);
+
+ // Verify properties of various specific instruction types
+ switch (MI->getOpcode()) {
case TargetOpcode::COPY: {
if (foundErrors)
break;
@@ -1193,7 +1484,8 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
VerifyStackMapConstant(VarStart + StatepointOpers::NumDeoptOperandsOffset);
// TODO: verify we have properly encoded deopt arguments
- };
+ break;
+ }
}
void
@@ -1356,7 +1648,7 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) {
return;
}
if (SubIdx) {
- report("Generic virtual register does not subregister index", MO,
+ report("Generic virtual register does not allow subregister index", MO,
MONum);
return;
}
@@ -1911,6 +2203,10 @@ void MachineVerifier::visitMachineFunctionAfter() {
verifyLiveVariables();
if (LiveInts)
verifyLiveIntervals();
+
+ for (auto CSInfo : MF->getCallSitesInfo())
+ if (!CSInfo.first->isCall())
+ report("Call site info referencing instruction that is not call", MF);
}
void MachineVerifier::verifyLiveVariables() {