MachineVerifier: Move verification of G_* instructions to function
llvm-svn: 353111
This commit is contained in:
parent
d2a42c3815
commit
46f9c6cf0b
|
@ -230,6 +230,8 @@ namespace {
|
||||||
void visitMachineFunctionBefore();
|
void visitMachineFunctionBefore();
|
||||||
void visitMachineBasicBlockBefore(const MachineBasicBlock *MBB);
|
void visitMachineBasicBlockBefore(const MachineBasicBlock *MBB);
|
||||||
void visitMachineBundleBefore(const MachineInstr *MI);
|
void visitMachineBundleBefore(const MachineInstr *MI);
|
||||||
|
|
||||||
|
void verifyPreISelGenericInstruction(const MachineInstr *MI);
|
||||||
void visitMachineInstrBefore(const MachineInstr *MI);
|
void visitMachineInstrBefore(const MachineInstr *MI);
|
||||||
void visitMachineOperand(const MachineOperand *MO, unsigned MONum);
|
void visitMachineOperand(const MachineOperand *MO, unsigned MONum);
|
||||||
void visitMachineInstrAfter(const MachineInstr *MI);
|
void visitMachineInstrAfter(const MachineInstr *MI);
|
||||||
|
@ -888,108 +890,58 @@ void MachineVerifier::verifyInlineAsm(const MachineInstr *MI) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
|
void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
|
||||||
|
if (isFunctionSelected)
|
||||||
|
report("Unexpected generic instruction in a Selected function", MI);
|
||||||
|
|
||||||
const MCInstrDesc &MCID = MI->getDesc();
|
const MCInstrDesc &MCID = MI->getDesc();
|
||||||
if (MI->getNumOperands() < MCID.getNumOperands()) {
|
unsigned NumOps = MI->getNumOperands();
|
||||||
report("Too few operands", MI);
|
|
||||||
errs() << MCID.getNumOperands() << " operands expected, but "
|
|
||||||
<< MI->getNumOperands() << " given.\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MI->isPHI()) {
|
// Check types.
|
||||||
if (MF->getProperties().hasProperty(
|
SmallVector<LLT, 4> Types;
|
||||||
MachineFunctionProperties::Property::NoPHIs))
|
for (unsigned I = 0, E = std::min(MCID.getNumOperands(), NumOps);
|
||||||
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) {
|
I != E; ++I) {
|
||||||
if ((*I)->isLoad() && !MI->mayLoad())
|
if (!MCID.OpInfo[I].isGenericType())
|
||||||
report("Missing mayLoad flag", MI);
|
continue;
|
||||||
if ((*I)->isStore() && !MI->mayStore())
|
// Generic instructions specify type equality constraints between some of
|
||||||
report("Missing mayStore flag", MI);
|
// their operands. Make sure these are consistent.
|
||||||
}
|
size_t TypeIdx = MCID.OpInfo[I].getGenericTypeIndex();
|
||||||
|
Types.resize(std::max(TypeIdx + 1, Types.size()));
|
||||||
|
|
||||||
// Debug values must not have a slot index.
|
const MachineOperand *MO = &MI->getOperand(I);
|
||||||
// Other instructions must have one, unless they are inside a bundle.
|
LLT OpTy = MRI->getType(MO->getReg());
|
||||||
if (LiveInts) {
|
// Don't report a type mismatch if there is no actual mismatch, only a
|
||||||
bool mapped = !LiveInts->isNotInMIMap(*MI);
|
// type missing, to reduce noise:
|
||||||
if (MI->isDebugInstr()) {
|
if (OpTy.isValid()) {
|
||||||
if (mapped)
|
// Only the first valid type for a type index will be printed: don't
|
||||||
report("Debug instruction has a slot index", MI);
|
// overwrite it later so it's always clear which type was expected:
|
||||||
} else if (MI->isInsideBundle()) {
|
if (!Types[TypeIdx].isValid())
|
||||||
if (mapped)
|
Types[TypeIdx] = OpTy;
|
||||||
report("Instruction inside bundle has a slot index", MI);
|
else if (Types[TypeIdx] != OpTy)
|
||||||
|
report("Type mismatch in generic instruction", MO, I, OpTy);
|
||||||
} else {
|
} else {
|
||||||
if (!mapped)
|
// Generic instructions must have types attached to their operands.
|
||||||
report("Missing slot index", MI);
|
report("Generic instruction is missing a virtual register type", MO, I);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPreISelGenericOpcode(MCID.getOpcode())) {
|
// Generic opcodes must not have physical register operands.
|
||||||
if (isFunctionSelected)
|
for (unsigned I = 0; I < MI->getNumOperands(); ++I) {
|
||||||
report("Unexpected generic instruction in a Selected function", MI);
|
const MachineOperand *MO = &MI->getOperand(I);
|
||||||
|
if (MO->isReg() && TargetRegisterInfo::isPhysicalRegister(MO->getReg()))
|
||||||
unsigned NumOps = MI->getNumOperands();
|
report("Generic instruction cannot have physical register", MO, I);
|
||||||
|
|
||||||
// Check types.
|
|
||||||
SmallVector<LLT, 4> Types;
|
|
||||||
for (unsigned I = 0, E = std::min(MCID.getNumOperands(), NumOps);
|
|
||||||
I != E; ++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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid out of bounds in checks below. This was already reported earlier.
|
|
||||||
if (MI->getNumOperands() < MCID.getNumOperands())
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Avoid out of bounds in checks below. This was already reported earlier.
|
||||||
|
if (MI->getNumOperands() < MCID.getNumOperands())
|
||||||
|
return;
|
||||||
|
|
||||||
StringRef ErrorInfo;
|
StringRef ErrorInfo;
|
||||||
if (!TII->verifyInstruction(*MI, ErrorInfo))
|
if (!TII->verifyInstruction(*MI, ErrorInfo))
|
||||||
report(ErrorInfo.data(), MI);
|
report(ErrorInfo.data(), MI);
|
||||||
|
|
||||||
// Verify properties of various specific instruction types
|
// Verify properties of various specific instruction types
|
||||||
switch(MI->getOpcode()) {
|
switch (MI->getOpcode()) {
|
||||||
default:
|
|
||||||
break;
|
|
||||||
case TargetOpcode::G_CONSTANT:
|
case TargetOpcode::G_CONSTANT:
|
||||||
case TargetOpcode::G_FCONSTANT: {
|
case TargetOpcode::G_FCONSTANT: {
|
||||||
if (MI->getNumOperands() < MCID.getNumOperands())
|
if (MI->getNumOperands() < MCID.getNumOperands())
|
||||||
|
@ -1238,6 +1190,81 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
|
||||||
report("G_CONCAT_VECTOR num dest and source elements should match", MI);
|
report("G_CONCAT_VECTOR num dest and source elements should match", MI);
|
||||||
break;
|
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;
|
||||||
|
}
|
||||||
|
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: {
|
case TargetOpcode::COPY: {
|
||||||
if (foundErrors)
|
if (foundErrors)
|
||||||
break;
|
break;
|
||||||
|
@ -1268,17 +1295,6 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
|
||||||
}
|
}
|
||||||
break;
|
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::STATEPOINT:
|
case TargetOpcode::STATEPOINT:
|
||||||
if (!MI->getOperand(StatepointOpers::IDPos).isImm() ||
|
if (!MI->getOperand(StatepointOpers::IDPos).isImm() ||
|
||||||
!MI->getOperand(StatepointOpers::NBytesPos).isImm() ||
|
!MI->getOperand(StatepointOpers::NBytesPos).isImm() ||
|
||||||
|
@ -1298,7 +1314,8 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
|
||||||
VerifyStackMapConstant(VarStart + StatepointOpers::NumDeoptOperandsOffset);
|
VerifyStackMapConstant(VarStart + StatepointOpers::NumDeoptOperandsOffset);
|
||||||
|
|
||||||
// TODO: verify we have properly encoded deopt arguments
|
// TODO: verify we have properly encoded deopt arguments
|
||||||
};
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
Loading…
Reference in New Issue