Instructions with variable operands (variable_ops) can have a number required

operands. e.g.
def CALL32r : I<0xFF, MRM2r, (ops GR32:$dst, variable_ops),
                "call {*}$dst", [(X86call GR32:$dst)]>;
TableGen should emit operand informations for the "required" operands.

Added a target instruction info flag M_VARIABLE_OPS to indicate the target
instruction may have more operands in addition to the minimum required
operands.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@28791 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evan Cheng 2006-06-15 07:22:16 +00:00
parent d7c2c86239
commit 8d3af5e7d0
4 changed files with 25 additions and 13 deletions

View File

@ -76,6 +76,10 @@ const unsigned M_TERMINATOR_FLAG = 1 << 10;
// block. // block.
const unsigned M_USES_CUSTOM_DAG_SCHED_INSERTION = 1 << 11; const unsigned M_USES_CUSTOM_DAG_SCHED_INSERTION = 1 << 11;
// M_VARIABLE_OPS - Set if this instruction can have a variable number of extra
// operands in addition to the minimum number operands specified.
const unsigned M_VARIABLE_OPS = 1 << 12;
// Machine operand flags // Machine operand flags
// M_LOOK_UP_PTR_REG_CLASS - Set if this operand is a pointer value and it // M_LOOK_UP_PTR_REG_CLASS - Set if this operand is a pointer value and it
// requires a callback to look up its register class. // requires a callback to look up its register class.
@ -97,7 +101,7 @@ public:
class TargetInstrDescriptor { class TargetInstrDescriptor {
public: public:
const char * Name; // Assembly language mnemonic for the opcode. const char * Name; // Assembly language mnemonic for the opcode.
int numOperands; // Number of args; -1 if variable #args unsigned numOperands; // Num of args (may be more if variable_ops).
InstrSchedClass schedClass; // enum identifying instr sched class InstrSchedClass schedClass; // enum identifying instr sched class
unsigned Flags; // flags identifying machine instr class unsigned Flags; // flags identifying machine instr class
unsigned TSFlags; // Target Specific Flag values unsigned TSFlags; // Target Specific Flag values
@ -144,6 +148,11 @@ public:
const TargetRegisterClass const TargetRegisterClass
*getInstrOperandRegClass(const TargetInstrDescriptor *II, unsigned Op) const { *getInstrOperandRegClass(const TargetInstrDescriptor *II, unsigned Op) const {
if (Op >= II->numOperands) {
if (II->Flags & M_VARIABLE_OPS)
return NULL;
assert(false && "Invalid operand # of instruction");
}
const TargetOperandInfo &toi = II->OpInfo[Op]; const TargetOperandInfo &toi = II->OpInfo[Op];
return (toi.Flags & M_LOOK_UP_PTR_REG_CLASS) return (toi.Flags & M_LOOK_UP_PTR_REG_CLASS)
? getPointerRegClass() : toi.RegClass; ? getPointerRegClass() : toi.RegClass;
@ -212,6 +221,10 @@ public:
return get(Opcode).Flags & M_USES_CUSTOM_DAG_SCHED_INSERTION; return get(Opcode).Flags & M_USES_CUSTOM_DAG_SCHED_INSERTION;
} }
bool hasVariableOperands(MachineOpCode Opcode) const {
return get(Opcode).Flags & M_VARIABLE_OPS;
}
/// Return true if the instruction is a register to register move /// Return true if the instruction is a register to register move
/// and leave the source and dest operands in the passed parameters. /// and leave the source and dest operands in the passed parameters.
virtual bool isMoveInstr(const MachineInstr& MI, virtual bool isMoveInstr(const MachineInstr& MI,

View File

@ -91,7 +91,8 @@ MachineInstr *MachineInstr::removeFromParent() {
/// ///
bool MachineInstr::OperandsComplete() const { bool MachineInstr::OperandsComplete() const {
int NumOperands = TargetInstrDescriptors[Opcode].numOperands; int NumOperands = TargetInstrDescriptors[Opcode].numOperands;
if (NumOperands >= 0 && getNumOperands() >= (unsigned)NumOperands) if ((TargetInstrDescriptors[Opcode].Flags & M_VARIABLE_OPS) == 0 &&
getNumOperands() >= (unsigned)NumOperands)
return true; // Broken: we have all the operands of this instruction! return true; // Broken: we have all the operands of this instruction!
return false; return false;
} }

View File

@ -358,7 +358,8 @@ void ScheduleDAG::EmitNode(SDNode *Node,
unsigned NodeOperands = CountOperands(Node); unsigned NodeOperands = CountOperands(Node);
unsigned NumMIOperands = NodeOperands + NumResults; unsigned NumMIOperands = NodeOperands + NumResults;
#ifndef NDEBUG #ifndef NDEBUG
assert((unsigned(II.numOperands) == NumMIOperands || II.numOperands == -1)&& assert((unsigned(II.numOperands) == NumMIOperands ||
(II.Flags & M_VARIABLE_OPS)) &&
"#operands for dag node doesn't match .td file!"); "#operands for dag node doesn't match .td file!");
#endif #endif

View File

@ -64,9 +64,6 @@ void InstrInfoEmitter::printDefList(const std::vector<Record*> &Uses,
static std::vector<Record*> GetOperandInfo(const CodeGenInstruction &Inst) { static std::vector<Record*> GetOperandInfo(const CodeGenInstruction &Inst) {
std::vector<Record*> Result; std::vector<Record*> Result;
if (Inst.hasVariableNumberOfOperands)
return Result; // No info for variable operand instrs.
for (unsigned i = 0, e = Inst.OperandList.size(); i != e; ++i) { for (unsigned i = 0, e = Inst.OperandList.size(); i != e; ++i) {
if (Inst.OperandList[i].Rec->isSubClassOf("RegisterClass")) { if (Inst.OperandList[i].Rec->isSubClassOf("RegisterClass")) {
Result.push_back(Inst.OperandList[i].Rec); Result.push_back(Inst.OperandList[i].Rec);
@ -170,15 +167,13 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
std::map<std::vector<Record*>, unsigned> &EmittedLists, std::map<std::vector<Record*>, unsigned> &EmittedLists,
std::map<std::vector<Record*>, unsigned> &OpInfo, std::map<std::vector<Record*>, unsigned> &OpInfo,
std::ostream &OS) { std::ostream &OS) {
int NumOperands; int MinOperands;
if (Inst.hasVariableNumberOfOperands) if (!Inst.OperandList.empty())
NumOperands = -1;
else if (!Inst.OperandList.empty())
// Each logical operand can be multiple MI operands. // Each logical operand can be multiple MI operands.
NumOperands = Inst.OperandList.back().MIOperandNo + MinOperands = Inst.OperandList.back().MIOperandNo +
Inst.OperandList.back().MINumOperands; Inst.OperandList.back().MINumOperands;
else else
NumOperands = 0; MinOperands = 0;
OS << " { \""; OS << " { \"";
if (Inst.Name.empty()) if (Inst.Name.empty())
@ -189,7 +184,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
unsigned ItinClass = !IsItineraries ? 0 : unsigned ItinClass = !IsItineraries ? 0 :
ItinClassNumber(Inst.TheDef->getValueAsDef("Itinerary")->getName()); ItinClassNumber(Inst.TheDef->getValueAsDef("Itinerary")->getName());
OS << "\",\t" << NumOperands << ", " << ItinClass OS << "\",\t" << MinOperands << ", " << ItinClass
<< ", 0"; << ", 0";
// Try to determine (from the pattern), if the instruction is a store. // Try to determine (from the pattern), if the instruction is a store.
@ -224,6 +219,8 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
if (Inst.isTerminator) OS << "|M_TERMINATOR_FLAG"; if (Inst.isTerminator) OS << "|M_TERMINATOR_FLAG";
if (Inst.usesCustomDAGSchedInserter) if (Inst.usesCustomDAGSchedInserter)
OS << "|M_USES_CUSTOM_DAG_SCHED_INSERTION"; OS << "|M_USES_CUSTOM_DAG_SCHED_INSERTION";
if (Inst.hasVariableNumberOfOperands)
OS << "|M_VARIABLE_OPS";
OS << ", 0"; OS << ", 0";
// Emit all of the target-specific flags... // Emit all of the target-specific flags...