From d35121ad00667d93ea779a722dbee7d022410815 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 29 May 2008 19:57:41 +0000 Subject: [PATCH] Fix a tblgen problem handling variable_ops in tblgen instruction definitions. This adds a new construct, "discard", for indicating that a named node in the input matching pattern is to be discarded, instead of corresponding to a node in the output pattern. This allows tblgen to know where the arguments for the varaible_ops are supposed to begin. This fixes "rdar://5791600", whatever that is ;-). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@51699 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Target.td | 6 ++++ lib/Target/TargetSelectionDAG.td | 1 + lib/Target/X86/X86ISelDAGToDAG.cpp | 29 ----------------- lib/Target/X86/X86InstrInfo.td | 6 ++-- utils/TableGen/CodeGenDAGPatterns.cpp | 2 ++ utils/TableGen/CodeGenInstruction.cpp | 3 +- utils/TableGen/DAGISelEmitter.cpp | 47 ++++++++++++++++----------- utils/TableGen/InstrInfoEmitter.cpp | 12 +++++++ 8 files changed, 54 insertions(+), 52 deletions(-) diff --git a/lib/Target/Target.td b/lib/Target/Target.td index a268e164107..92c40570af3 100644 --- a/lib/Target/Target.td +++ b/lib/Target/Target.td @@ -259,6 +259,12 @@ def ins; /// of operands. def variable_ops; +/// discard definition - Mark this operand as being matched in the input +/// but omitted from the output. This is necessary in some situations +/// involving variable_ops to help the pattern matcher determine which +/// input nodes to forward on to the variable_ops portion of the output. +def discard; + /// ptr_rc definition - Mark this operand as being a pointer value whose /// register class is resolved dynamically via a callback to TargetInstrInfo. /// FIXME: We should probably change this to a class which contain a list of diff --git a/lib/Target/TargetSelectionDAG.td b/lib/Target/TargetSelectionDAG.td index f1944437de8..9def220337f 100644 --- a/lib/Target/TargetSelectionDAG.td +++ b/lib/Target/TargetSelectionDAG.td @@ -470,6 +470,7 @@ class PatLeaf def vtInt : PatLeaf<(vt), [{ return MVT::isInteger(N->getVT()); }]>; def vtFP : PatLeaf<(vt), [{ return MVT::isFloatingPoint(N->getVT()); }]>; +def immAllZeros : PatLeaf<(imm), [{ return N->isNullValue(); }]>; def immAllOnes : PatLeaf<(imm), [{ return N->isAllOnesValue(); }]>; def immAllOnesV: PatLeaf<(build_vector), [{ return ISD::isBuildVectorAllOnes(N); diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp index 576661df2e3..bb8c58ac140 100644 --- a/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -1175,35 +1175,6 @@ SDNode *X86DAGToDAGISel::Select(SDOperand N) { case X86ISD::GlobalBaseReg: return getGlobalBaseReg(); - // FIXME: This is a workaround for a tblgen problem: rdar://5791600 - case X86ISD::RET_FLAG: - if (ConstantSDNode *Amt = dyn_cast(N.getOperand(1))) { - if (Amt->getSignExtended() != 0) break; - - // Match (X86retflag 0). - SDOperand Chain = N.getOperand(0); - bool HasInFlag = N.getOperand(N.getNumOperands()-1).getValueType() - == MVT::Flag; - SmallVector Ops0; - AddToISelQueue(Chain); - SDOperand InFlag(0, 0); - if (HasInFlag) { - InFlag = N.getOperand(N.getNumOperands()-1); - AddToISelQueue(InFlag); - } - for (unsigned i = 2, e = N.getNumOperands()-(HasInFlag?1:0); i != e; - ++i) { - AddToISelQueue(N.getOperand(i)); - Ops0.push_back(N.getOperand(i)); - } - Ops0.push_back(Chain); - if (HasInFlag) - Ops0.push_back(InFlag); - return CurDAG->getTargetNode(X86::RET, MVT::Other, - &Ops0[0], Ops0.size()); - } - break; - case ISD::ADD: { // Turn ADD X, c to MOV32ri X+c. This cannot be done with tblgen'd // code and is matched first so to prevent it from being turned into diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 843fbd0791f..d0bd9552d06 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -45,7 +45,7 @@ def SDT_X86CallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>; def SDT_X86CallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>, SDTCisVT<1, i32> ]>; -def SDT_X86Call : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>; +def SDT_X86Call : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>; def SDTX86RepStr : SDTypeProfile<0, 1, [SDTCisVT<0, OtherVT>]>; @@ -322,9 +322,9 @@ let neverHasSideEffects = 1, isNotDuplicable = 1 in // Return instructions. let isTerminator = 1, isReturn = 1, isBarrier = 1, hasCtrlDep = 1, FPForm = SpecialFP, FPFormBits = SpecialFP.Value in { - def RET : I <0xC3, RawFrm, (outs), (ins variable_ops), + def RET : I <0xC3, RawFrm, (outs), (ins discard:$amt, variable_ops), "ret", - [/*(X86retflag 0)*/ /*FIXME: Disabled: rdar://5791600*/]>; + [(X86retflag immAllZeros:$amt)]>; def RETI : Ii16<0xC2, RawFrm, (outs), (ins i16imm:$amt, variable_ops), "ret\t$amt", [(X86retflag imm:$amt)]>; diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index 8c46b35fa19..006c067e8fd 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -916,6 +916,8 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { MadeChange |= Child->UpdateNodeType(MVT::iPTR, TP); } else if (OperandNode->getName() == "unknown") { MadeChange |= Child->UpdateNodeType(MVT::isUnknown, TP); + } else if (OperandNode->getName() == "discard") { + MadeChange |= Child->UpdateNodeType(MVT::isUnknown, TP); } else { assert(0 && "Unknown operand type!"); abort(); diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp index 37c2069ec72..d52037823f6 100644 --- a/utils/TableGen/CodeGenInstruction.cpp +++ b/utils/TableGen/CodeGenInstruction.cpp @@ -163,7 +163,8 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr) isVariadic = true; continue; } else if (!Rec->isSubClassOf("RegisterClass") && - Rec->getName() != "ptr_rc" && Rec->getName() != "unknown") + Rec->getName() != "ptr_rc" && Rec->getName() != "unknown" && + Rec->getName() != "discard") throw "Unknown operand class '" + Rec->getName() + "' in instruction '" + R->getName() + "' instruction!"; diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp index 72bd5bdb2fb..b112b7e8e0b 100644 --- a/utils/TableGen/DAGISelEmitter.cpp +++ b/utils/TableGen/DAGISelEmitter.cpp @@ -947,22 +947,20 @@ public: // instruction operands to do this. std::vector AllOps; unsigned NumEAInputs = 0; // # of synthesized 'execute always' inputs. + unsigned NumDiscardedInputs = 0; // # of 'discard' inputs to skip. for (unsigned ChildNo = 0, InstOpNo = NumResults; InstOpNo != II.OperandList.size(); ++InstOpNo) { std::vector Ops; - // If this is a normal operand or a predicate operand without - // 'execute always', emit it. + // Determine what to emit for this operand. Record *OperandNode = II.OperandList[InstOpNo].Rec; - if ((!OperandNode->isSubClassOf("PredicateOperand") && - !OperandNode->isSubClassOf("OptionalDefOperand")) || - CGP.getDefaultOperand(OperandNode).DefaultOps.empty()) { - Ops = EmitResultCode(N->getChild(ChildNo), DstRegs, - InFlagDecled, ResNodeDecled); - AllOps.insert(AllOps.end(), Ops.begin(), Ops.end()); - ++ChildNo; - } else { - // Otherwise, this is a predicate or optional def operand, emit the + if (OperandNode->getName() == "discard") { + // This is a "discard" operand; emit nothing. Just note it. + ++NumDiscardedInputs; + } else if ((OperandNode->isSubClassOf("PredicateOperand") || + OperandNode->isSubClassOf("OptionalDefOperand")) && + !CGP.getDefaultOperand(OperandNode).DefaultOps.empty()) { + // This is a predicate or optional def operand; emit the // 'default ops' operands. const DAGDefaultOperand &DefaultOp = CGP.getDefaultOperand(II.OperandList[InstOpNo].Rec); @@ -972,6 +970,13 @@ public: AllOps.insert(AllOps.end(), Ops.begin(), Ops.end()); NumEAInputs += Ops.size(); } + } else { + // Otherwise this is a normal operand or a predicate operand without + // 'execute always'; emit it. + Ops = EmitResultCode(N->getChild(ChildNo), DstRegs, + InFlagDecled, ResNodeDecled); + AllOps.insert(AllOps.end(), Ops.begin(), Ops.end()); + ++ChildNo; } } @@ -1049,19 +1054,23 @@ public: if (NodeHasOutFlag) Code += ", MVT::Flag"; - // Figure out how many fixed inputs the node has. This is important to - // know which inputs are the variable ones if present. - unsigned NumInputs = AllOps.size(); - NumInputs += NodeHasChain; - // Inputs. if (HasVarOps) { + // Figure out how many fixed inputs the node has. This is important + // to know which inputs are the variable ones if present. Include + // the 'discard' and chain inputs in the count, and adjust for the + // number of operands that are 'execute always'. This is the index + // where we should start copying operands into the 'variable_ops' + // portion of the output. + unsigned InputIndex = AllOps.size() + + NumDiscardedInputs + + NodeHasChain - + NumEAInputs; + for (unsigned i = 0, e = AllOps.size(); i != e; ++i) emitCode("Ops" + utostr(OpsNo) + ".push_back(" + AllOps[i] + ");"); AllOps.clear(); - } - if (HasVarOps) { // Figure out whether any operands at the end of the op list are not // part of the variable section. std::string EndAdjust; @@ -1070,7 +1079,7 @@ public: else if (NodeHasOptInFlag) EndAdjust = "-(HasInFlag?1:0)"; // May have a flag. - emitCode("for (unsigned i = " + utostr(NumInputs - NumEAInputs) + + emitCode("for (unsigned i = " + utostr(InputIndex) + ", e = N.getNumOperands()" + EndAdjust + "; i != e; ++i) {"); emitCode(" AddToISelQueue(N.getOperand(i));"); diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index 028fbeb88b2..8390c906604 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -85,6 +85,10 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { Record *OpR = OperandList[j].Rec; std::string Res; + // Discard "discard" operands. + if (OpR->getName() == "discard") + continue; + if (OpR->isSubClassOf("RegisterClass")) Res += getQualifiedName(OpR) + "RegClassID, "; else @@ -201,6 +205,14 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, // Each logical operand can be multiple MI operands. MinOperands = Inst.OperandList.back().MIOperandNo + Inst.OperandList.back().MINumOperands; + + // Subtract the number of "discard" operands, which we'll be skipping + // when emitting OperandInfo records. + for (unsigned j = 0, e = Inst.OperandList.size(); j != e; ++j) { + Record *OpR = Inst.OperandList[j].Rec; + if (OpR->getName() == "discard") + --MinOperands; + } OS << " { "; OS << Num << ",\t" << MinOperands << ",\t"