diff options
Diffstat (limited to 'lib/CodeGen/MachineVerifier.cpp')
-rw-r--r-- | lib/CodeGen/MachineVerifier.cpp | 88 |
1 files changed, 72 insertions, 16 deletions
diff --git a/lib/CodeGen/MachineVerifier.cpp b/lib/CodeGen/MachineVerifier.cpp index 4a766b328c..bf4882044b 100644 --- a/lib/CodeGen/MachineVerifier.cpp +++ b/lib/CodeGen/MachineVerifier.cpp @@ -24,6 +24,7 @@ //===----------------------------------------------------------------------===// #include "llvm/BasicBlock.h" +#include "llvm/InlineAsm.h" #include "llvm/Instructions.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/LiveVariables.h" @@ -213,6 +214,9 @@ namespace { void report(const char *msg, const MachineBasicBlock *MBB, const LiveInterval &LI); + void verifyInlineAsm(const MachineInstr *MI); + void verifyTiedOperands(const MachineInstr *MI); + void checkLiveness(const MachineOperand *MO, unsigned MONum); void markReachable(const MachineBasicBlock *MBB); void calcRegsPassed(); @@ -695,42 +699,94 @@ void MachineVerifier::visitMachineBundleBefore(const MachineInstr *MI) { } } -void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) { - const MCInstrDesc &MCID = MI->getDesc(); - if (MI->getNumOperands() < MCID.getNumOperands()) { - report("Too few operands", MI); - *OS << MCID.getNumOperands() << " operands expected, but " - << MI->getNumExplicitOperands() << " given.\n"; +// The operands on an INLINEASM instruction must follow a template. +// Verify that the flag operands make sense. +void MachineVerifier::verifyInlineAsm(const MachineInstr *MI) { + // The first two operands on INLINEASM are the asm string and global flags. + if (MI->getNumOperands() < 2) { + report("Too few operands on inline asm", MI); + return; + } + if (!MI->getOperand(0).isSymbol()) + report("Asm string must be an external symbol", MI); + if (!MI->getOperand(1).isImm()) + report("Asm flags must be an immediate", MI); + // Allowed flags are Extra_HasSideEffects = 1, and Extra_IsAlignStack = 2. + if (!isUInt<2>(MI->getOperand(1).getImm())) + report("Unknown asm flags", &MI->getOperand(1), 1); + + assert(InlineAsm::MIOp_FirstOperand == 2 && "Asm format changed"); + + unsigned OpNo = InlineAsm::MIOp_FirstOperand; + unsigned NumOps; + for (unsigned e = MI->getNumOperands(); OpNo < e; OpNo += NumOps) { + const MachineOperand &MO = MI->getOperand(OpNo); + // There may be implicit ops after the fixed operands. + if (!MO.isImm()) + break; + NumOps = 1 + InlineAsm::getNumOperandRegisters(MO.getImm()); } - // Check the tied operands. - SmallVector<unsigned, 4> TiedDefs; - SmallVector<unsigned, 4> TiedUses; + if (OpNo > MI->getNumOperands()) + report("Missing operands in last group", MI); + + // An optional MDNode follows the groups. + if (OpNo < MI->getNumOperands() && MI->getOperand(OpNo).isMetadata()) + ++OpNo; + + // All trailing operands must be implicit registers. + for (unsigned e = MI->getNumOperands(); OpNo < e; ++OpNo) { + const MachineOperand &MO = MI->getOperand(OpNo); + if (!MO.isReg() || !MO.isImplicit()) + report("Expected implicit register after groups", &MO, OpNo); + } +} + +// Verify the consistency of tied operands. +void MachineVerifier::verifyTiedOperands(const MachineInstr *MI) { + const MCInstrDesc &MCID = MI->getDesc(); + SmallVector<unsigned, 4> Defs; + SmallVector<unsigned, 4> Uses; for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); if (!MO.isReg() || !MO.isTied()) continue; if (MO.isDef()) { - TiedDefs.push_back(i); + Defs.push_back(i); continue; } - TiedUses.push_back(i); - if (TiedDefs.size() < TiedUses.size()) { + Uses.push_back(i); + if (Defs.size() < Uses.size()) { report("No tied def for tied use", &MO, i); break; } if (i >= MCID.getNumOperands()) continue; int DefIdx = MCID.getOperandConstraint(i, MCOI::TIED_TO); - if (unsigned(DefIdx) != TiedDefs[TiedUses.size() - 1]) { - report("Tied def doesn't match MCInstrDesc", &MO, i); + if (unsigned(DefIdx) != Defs[Uses.size() - 1]) { + report(" def doesn't match MCInstrDesc", &MO, i); *OS << "Descriptor says tied def should be operand " << DefIdx << ".\n"; } } - if (TiedDefs.size() > TiedUses.size()) { - unsigned i = TiedDefs[TiedUses.size() - 1]; + if (Defs.size() > Uses.size()) { + unsigned i = Defs[Uses.size() - 1]; report("No tied use for tied def", &MI->getOperand(i), i); } +} + +void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) { + const MCInstrDesc &MCID = MI->getDesc(); + if (MI->getNumOperands() < MCID.getNumOperands()) { + report("Too few operands", MI); + *OS << MCID.getNumOperands() << " operands expected, but " + << MI->getNumExplicitOperands() << " given.\n"; + } + + // Check the tied operands. + if (MI->isInlineAsm()) + verifyInlineAsm(MI); + else + verifyTiedOperands(MI); // Check the MachineMemOperands for basic consistency. for (MachineInstr::mmo_iterator I = MI->memoperands_begin(), |