From e2ba8975883874633a1035c245af3b948b940b25 Mon Sep 17 00:00:00 2001 From: Evan Cheng Date: Wed, 1 Nov 2006 00:27:05 +0000 Subject: [PATCH] Add operand constraints to TargetInstrInfo. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@31333 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Target/TargetInstrInfo.h | 21 ++++++++++++ utils/TableGen/CodeGenInstruction.h | 8 +++++ utils/TableGen/CodeGenTarget.cpp | 48 +++++++++++++++++++++++++++ utils/TableGen/DAGISelEmitter.cpp | 6 +++- utils/TableGen/InstrInfoEmitter.cpp | 41 +++++++++++++++-------- utils/TableGen/InstrInfoEmitter.h | 2 +- 6 files changed, 110 insertions(+), 16 deletions(-) diff --git a/include/llvm/Target/TargetInstrInfo.h b/include/llvm/Target/TargetInstrInfo.h index b0ac41b34d1..0098870e66e 100644 --- a/include/llvm/Target/TargetInstrInfo.h +++ b/include/llvm/Target/TargetInstrInfo.h @@ -94,6 +94,9 @@ public: /// if the operand is a register. If not, this contains 0. unsigned short RegClass; unsigned short Flags; + /// Lower 16 bits are used to specify which constraints are set. The higher 16 + /// bits are used to specify the value of constraints (4 bits each). + unsigned int Constraints; /// Currently no other information. }; @@ -219,6 +222,24 @@ public: return get(Opcode).Flags & M_VARIABLE_OPS; } + // Operand constraints: only "tied_to" for now. + enum OperandConstraint { + TIED_TO = 0 // Must be allocated the same register as. + }; + + /// getOperandConstraint - Returns the value of the specific constraint if + /// it is set. Returns -1 if it is not set. + int getOperandConstraint(MachineOpCode Opcode, unsigned OpNum, + OperandConstraint Constraint) { + assert(OpNum < get(Opcode).numOperands && + "Invalid operand # of TargetInstrInfo"); + if (get(Opcode).OpInfo[OpNum].Constraints & (1 << Constraint)) { + unsigned Pos = 16 + Constraint * 4; + return (int)(get(Opcode).OpInfo[OpNum].Constraints >> Pos) & 0xf; + } + return -1; + } + /// getDWARF_LABELOpcode - Return the opcode of the target's DWARF_LABEL /// instruction if it has one. This is used by codegen passes that update /// DWARF line number info as they modify the code. diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h index 9ced62005ae..c5b4c3cf729 100644 --- a/utils/TableGen/CodeGenInstruction.h +++ b/utils/TableGen/CodeGenInstruction.h @@ -70,6 +70,14 @@ namespace llvm { /// type (which is a record). std::vector OperandList; + /// ConstraintStr - The operand constraints string. + /// + std::string ConstraintStr; + + /// ConstraintsList - List of constraints, encoded into one unsigned int per + /// operand. + std::vector ConstraintsList; + // Various boolean values we track for the instruction. bool isReturn; bool isBranch; diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index f5595d365f1..489aba98141 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -273,6 +273,51 @@ bool CodeGenTarget::isLittleEndianEncoding() const { return getInstructionSet()->getValueAsBit("isLittleEndianEncoding"); } +static std::pair parseConstraint(const std::string &CStr, + CodeGenInstruction *I) { + const std::string ops("="); // FIXME: Only supports TIED_TO for now. + std::string::size_type pos = CStr.find_first_of(ops); + assert(pos != std::string::npos && "Unrecognized constraint"); + std::string Name = CStr.substr(1, pos); // Skip '$' + + const std::string delims(" \t"); + std::string::size_type wpos = Name.find_first_of(delims); + if (wpos != std::string::npos) + Name = Name.substr(0, wpos); + unsigned FIdx = I->getOperandNamed(Name); + + Name = CStr.substr(pos+1); + wpos = Name.find_first_not_of(delims); + if (wpos != std::string::npos) + Name = Name.substr(wpos+1); + unsigned TIdx = I->getOperandNamed(Name); + return std::make_pair(FIdx, (TIdx << 16) | 1); +} + +static std::vector parseConstraints(const std::string &CStr, + CodeGenInstruction *I) { + unsigned NumOps = I->OperandList.size(); + std::vector Res(NumOps, 0); + if (CStr == "") + return Res; + + const std::string delims(","); + std::string::size_type bidx, eidx; + + bidx = CStr.find_first_not_of(delims); + while (bidx != std::string::npos) { + eidx = CStr.find_first_of(delims, bidx); + if (eidx == std::string::npos) + eidx = CStr.length(); + std::pair C = + parseConstraint(CStr.substr(bidx, eidx), I); + Res[C.first] = C.second; + bidx = CStr.find_first_not_of(delims, eidx); + } + + return Res; +} + CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr) : TheDef(R), AsmString(AsmStr) { Name = R->getValueAsString("Name"); @@ -338,6 +383,9 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr) MIOperandNo, NumOps, MIOpInfo)); MIOperandNo += NumOps; } + + ConstraintStr = R->getValueAsString("Constraints"); + ConstraintsList = parseConstraints(ConstraintStr, this); } diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp index 4f5a731736e..dfeea10d9e5 100644 --- a/utils/TableGen/DAGISelEmitter.cpp +++ b/utils/TableGen/DAGISelEmitter.cpp @@ -3552,11 +3552,14 @@ void DAGISelEmitter::EmitInstructionSelector(std::ostream &OS) { // Emit boilerplate. OS << "SDNode *Select_INLINEASM(SDOperand N) {\n" << " std::vector Ops(N.Val->op_begin(), N.Val->op_end());\n" - << " AddToISelQueue(N.getOperand(0)); // Select the chain.\n\n" + << " AddToISelQueue(N.getOperand(0)); // Select the chain.\n" << " // Select the flag operand.\n" << " if (Ops.back().getValueType() == MVT::Flag)\n" << " AddToISelQueue(Ops.back());\n" << " SelectInlineAsmMemoryOperands(Ops, *CurDAG);\n" + << " for (unsigned i = 2, e = Ops.size(); i < e; ++i)\n" + << " if (Ops[i].getOpcode() != ISD::Constant)\n" + << " AddToISelQueue(Ops[i]);\n" << " std::vector VTs;\n" << " VTs.push_back(MVT::Other);\n" << " VTs.push_back(MVT::Flag);\n" @@ -3582,6 +3585,7 @@ void DAGISelEmitter::EmitInstructionSelector(std::ostream &OS) { << " case ISD::TargetConstantPool:\n" << " case ISD::TargetFrameIndex:\n" << " case ISD::TargetJumpTable:\n" + << " case ISD::TargetExternalSymbol:\n" << " case ISD::TargetGlobalAddress: {\n" << " return NULL;\n" << " }\n" diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index 812e0215d1a..ed932db18b3 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -62,11 +62,13 @@ void InstrInfoEmitter::printDefList(const std::vector &Uses, OS << "0 };\n"; } -static std::vector GetOperandInfo(const CodeGenInstruction &Inst) { - std::vector Result; +static std::vector > +GetOperandInfo(const CodeGenInstruction &Inst) { + std::vector > Result; for (unsigned i = 0, e = Inst.OperandList.size(); i != e; ++i) { if (Inst.OperandList[i].Rec->isSubClassOf("RegisterClass")) { - Result.push_back(Inst.OperandList[i].Rec); + Result.push_back(std::make_pair(Inst.OperandList[i].Rec, + Inst.ConstraintsList[i])); } else { // This might be a multiple operand thing. // Targets like X86 have registers in their multi-operand operands. @@ -74,14 +76,21 @@ static std::vector GetOperandInfo(const CodeGenInstruction &Inst) { unsigned NumDefs = MIOI->getNumArgs(); for (unsigned j = 0, e = Inst.OperandList[i].MINumOperands; j != e; ++j) { if (NumDefs <= j) { - Result.push_back(0); + Result.push_back(std::make_pair((Record*)0, Inst.ConstraintsList[i])); } else { DefInit *Def = dynamic_cast(MIOI->getArg(j)); - Result.push_back(Def ? Def->getDef() : 0); + Result.push_back(std::make_pair(Def ? Def->getDef() : 0, + Inst.ConstraintsList[i])); } } } } + + // For backward compatibility: isTwoAddress means operand 1 is tied to + // operand 0. + if (Inst.isTwoAddress) + Result[1].second |= 1; + return Result; } @@ -117,29 +126,33 @@ void InstrInfoEmitter::run(std::ostream &OS) { } } - std::map, unsigned> OperandInfosEmitted; + std::map >, unsigned> + OperandInfosEmitted; unsigned OperandListNum = 0; - OperandInfosEmitted[std::vector()] = ++OperandListNum; + OperandInfosEmitted[std::vector >()] = + ++OperandListNum; // Emit all of the operand info records. OS << "\n"; for (CodeGenTarget::inst_iterator II = Target.inst_begin(), E = Target.inst_end(); II != E; ++II) { - std::vector OperandInfo = GetOperandInfo(II->second); + std::vector > OperandInfo = + GetOperandInfo(II->second); unsigned &N = OperandInfosEmitted[OperandInfo]; if (N == 0) { N = ++OperandListNum; OS << "static const TargetOperandInfo OperandInfo" << N << "[] = { "; for (unsigned i = 0, e = OperandInfo.size(); i != e; ++i) { - Record *RC = OperandInfo[i]; + Record *RC = OperandInfo[i].first; // FIXME: We only care about register operands for now. if (RC && RC->isSubClassOf("RegisterClass")) - OS << "{ " << getQualifiedName(RC) << "RegClassID, 0 }, "; + OS << "{ " << getQualifiedName(RC) << "RegClassID, 0, "; else if (RC && RC->getName() == "ptr_rc") // Ptr value whose register class is resolved via callback. - OS << "{ 0, 1 }, "; + OS << "{ 0, 1, "; else - OS << "{ 0, 0 }, "; + OS << "{ 0, 0, "; + OS << OperandInfo[i].second << " }, "; } OS << "};\n"; } @@ -162,7 +175,7 @@ void InstrInfoEmitter::run(std::ostream &OS) { void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, Record *InstrInfo, std::map, unsigned> &EmittedLists, - std::map, unsigned> &OpInfo, + std::map >, unsigned> &OpInfo, std::ostream &OS) { int MinOperands; if (!Inst.OperandList.empty()) @@ -247,7 +260,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, OS << "ImplicitList" << EmittedLists[DefList] << ", "; // Emit the operand info. - std::vector OperandInfo = GetOperandInfo(Inst); + std::vector > OperandInfo = GetOperandInfo(Inst); if (OperandInfo.empty()) OS << "0"; else diff --git a/utils/TableGen/InstrInfoEmitter.h b/utils/TableGen/InstrInfoEmitter.h index 2389f3a9514..b10c0e170fe 100644 --- a/utils/TableGen/InstrInfoEmitter.h +++ b/utils/TableGen/InstrInfoEmitter.h @@ -45,7 +45,7 @@ private: void emitRecord(const CodeGenInstruction &Inst, unsigned Num, Record *InstrInfo, std::map, unsigned> &EL, - std::map, unsigned> &OpInfo, + std::map >, unsigned> &OpInfo, std::ostream &OS); void GatherItinClasses(); unsigned ItinClassNumber(std::string ItinName); -- 2.34.1