mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-10-20 09:24:58 +00:00
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
This commit is contained in:
parent
b99e2e20b2
commit
d35121ad00
@ -259,6 +259,12 @@ def ins;
|
|||||||
/// of operands.
|
/// of operands.
|
||||||
def variable_ops;
|
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
|
/// ptr_rc definition - Mark this operand as being a pointer value whose
|
||||||
/// register class is resolved dynamically via a callback to TargetInstrInfo.
|
/// register class is resolved dynamically via a callback to TargetInstrInfo.
|
||||||
/// FIXME: We should probably change this to a class which contain a list of
|
/// FIXME: We should probably change this to a class which contain a list of
|
||||||
|
@ -470,6 +470,7 @@ class PatLeaf<dag frag, code pred = [{}], SDNodeXForm xform = NOOP_SDNodeXForm>
|
|||||||
def vtInt : PatLeaf<(vt), [{ return MVT::isInteger(N->getVT()); }]>;
|
def vtInt : PatLeaf<(vt), [{ return MVT::isInteger(N->getVT()); }]>;
|
||||||
def vtFP : PatLeaf<(vt), [{ return MVT::isFloatingPoint(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 immAllOnes : PatLeaf<(imm), [{ return N->isAllOnesValue(); }]>;
|
||||||
def immAllOnesV: PatLeaf<(build_vector), [{
|
def immAllOnesV: PatLeaf<(build_vector), [{
|
||||||
return ISD::isBuildVectorAllOnes(N);
|
return ISD::isBuildVectorAllOnes(N);
|
||||||
|
@ -1175,35 +1175,6 @@ SDNode *X86DAGToDAGISel::Select(SDOperand N) {
|
|||||||
case X86ISD::GlobalBaseReg:
|
case X86ISD::GlobalBaseReg:
|
||||||
return getGlobalBaseReg();
|
return getGlobalBaseReg();
|
||||||
|
|
||||||
// FIXME: This is a workaround for a tblgen problem: rdar://5791600
|
|
||||||
case X86ISD::RET_FLAG:
|
|
||||||
if (ConstantSDNode *Amt = dyn_cast<ConstantSDNode>(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<SDOperand, 8> 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: {
|
case ISD::ADD: {
|
||||||
// Turn ADD X, c to MOV32ri X+c. This cannot be done with tblgen'd
|
// 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
|
// code and is matched first so to prevent it from being turned into
|
||||||
|
@ -45,7 +45,7 @@ def SDT_X86CallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>;
|
|||||||
def SDT_X86CallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>,
|
def SDT_X86CallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>,
|
||||||
SDTCisVT<1, 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>]>;
|
def SDTX86RepStr : SDTypeProfile<0, 1, [SDTCisVT<0, OtherVT>]>;
|
||||||
|
|
||||||
@ -322,9 +322,9 @@ let neverHasSideEffects = 1, isNotDuplicable = 1 in
|
|||||||
// Return instructions.
|
// Return instructions.
|
||||||
let isTerminator = 1, isReturn = 1, isBarrier = 1,
|
let isTerminator = 1, isReturn = 1, isBarrier = 1,
|
||||||
hasCtrlDep = 1, FPForm = SpecialFP, FPFormBits = SpecialFP.Value in {
|
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",
|
"ret",
|
||||||
[/*(X86retflag 0)*/ /*FIXME: Disabled: rdar://5791600*/]>;
|
[(X86retflag immAllZeros:$amt)]>;
|
||||||
def RETI : Ii16<0xC2, RawFrm, (outs), (ins i16imm:$amt, variable_ops),
|
def RETI : Ii16<0xC2, RawFrm, (outs), (ins i16imm:$amt, variable_ops),
|
||||||
"ret\t$amt",
|
"ret\t$amt",
|
||||||
[(X86retflag imm:$amt)]>;
|
[(X86retflag imm:$amt)]>;
|
||||||
|
@ -916,6 +916,8 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
|
|||||||
MadeChange |= Child->UpdateNodeType(MVT::iPTR, TP);
|
MadeChange |= Child->UpdateNodeType(MVT::iPTR, TP);
|
||||||
} else if (OperandNode->getName() == "unknown") {
|
} else if (OperandNode->getName() == "unknown") {
|
||||||
MadeChange |= Child->UpdateNodeType(MVT::isUnknown, TP);
|
MadeChange |= Child->UpdateNodeType(MVT::isUnknown, TP);
|
||||||
|
} else if (OperandNode->getName() == "discard") {
|
||||||
|
MadeChange |= Child->UpdateNodeType(MVT::isUnknown, TP);
|
||||||
} else {
|
} else {
|
||||||
assert(0 && "Unknown operand type!");
|
assert(0 && "Unknown operand type!");
|
||||||
abort();
|
abort();
|
||||||
|
@ -163,7 +163,8 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr)
|
|||||||
isVariadic = true;
|
isVariadic = true;
|
||||||
continue;
|
continue;
|
||||||
} else if (!Rec->isSubClassOf("RegisterClass") &&
|
} 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() +
|
throw "Unknown operand class '" + Rec->getName() +
|
||||||
"' in instruction '" + R->getName() + "' instruction!";
|
"' in instruction '" + R->getName() + "' instruction!";
|
||||||
|
|
||||||
|
@ -947,22 +947,20 @@ public:
|
|||||||
// instruction operands to do this.
|
// instruction operands to do this.
|
||||||
std::vector<std::string> AllOps;
|
std::vector<std::string> AllOps;
|
||||||
unsigned NumEAInputs = 0; // # of synthesized 'execute always' inputs.
|
unsigned NumEAInputs = 0; // # of synthesized 'execute always' inputs.
|
||||||
|
unsigned NumDiscardedInputs = 0; // # of 'discard' inputs to skip.
|
||||||
for (unsigned ChildNo = 0, InstOpNo = NumResults;
|
for (unsigned ChildNo = 0, InstOpNo = NumResults;
|
||||||
InstOpNo != II.OperandList.size(); ++InstOpNo) {
|
InstOpNo != II.OperandList.size(); ++InstOpNo) {
|
||||||
std::vector<std::string> Ops;
|
std::vector<std::string> Ops;
|
||||||
|
|
||||||
// If this is a normal operand or a predicate operand without
|
// Determine what to emit for this operand.
|
||||||
// 'execute always', emit it.
|
|
||||||
Record *OperandNode = II.OperandList[InstOpNo].Rec;
|
Record *OperandNode = II.OperandList[InstOpNo].Rec;
|
||||||
if ((!OperandNode->isSubClassOf("PredicateOperand") &&
|
if (OperandNode->getName() == "discard") {
|
||||||
!OperandNode->isSubClassOf("OptionalDefOperand")) ||
|
// This is a "discard" operand; emit nothing. Just note it.
|
||||||
CGP.getDefaultOperand(OperandNode).DefaultOps.empty()) {
|
++NumDiscardedInputs;
|
||||||
Ops = EmitResultCode(N->getChild(ChildNo), DstRegs,
|
} else if ((OperandNode->isSubClassOf("PredicateOperand") ||
|
||||||
InFlagDecled, ResNodeDecled);
|
OperandNode->isSubClassOf("OptionalDefOperand")) &&
|
||||||
AllOps.insert(AllOps.end(), Ops.begin(), Ops.end());
|
!CGP.getDefaultOperand(OperandNode).DefaultOps.empty()) {
|
||||||
++ChildNo;
|
// This is a predicate or optional def operand; emit the
|
||||||
} else {
|
|
||||||
// Otherwise, this is a predicate or optional def operand, emit the
|
|
||||||
// 'default ops' operands.
|
// 'default ops' operands.
|
||||||
const DAGDefaultOperand &DefaultOp =
|
const DAGDefaultOperand &DefaultOp =
|
||||||
CGP.getDefaultOperand(II.OperandList[InstOpNo].Rec);
|
CGP.getDefaultOperand(II.OperandList[InstOpNo].Rec);
|
||||||
@ -972,6 +970,13 @@ public:
|
|||||||
AllOps.insert(AllOps.end(), Ops.begin(), Ops.end());
|
AllOps.insert(AllOps.end(), Ops.begin(), Ops.end());
|
||||||
NumEAInputs += Ops.size();
|
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)
|
if (NodeHasOutFlag)
|
||||||
Code += ", MVT::Flag";
|
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.
|
// Inputs.
|
||||||
if (HasVarOps) {
|
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)
|
for (unsigned i = 0, e = AllOps.size(); i != e; ++i)
|
||||||
emitCode("Ops" + utostr(OpsNo) + ".push_back(" + AllOps[i] + ");");
|
emitCode("Ops" + utostr(OpsNo) + ".push_back(" + AllOps[i] + ");");
|
||||||
AllOps.clear();
|
AllOps.clear();
|
||||||
}
|
|
||||||
|
|
||||||
if (HasVarOps) {
|
|
||||||
// Figure out whether any operands at the end of the op list are not
|
// Figure out whether any operands at the end of the op list are not
|
||||||
// part of the variable section.
|
// part of the variable section.
|
||||||
std::string EndAdjust;
|
std::string EndAdjust;
|
||||||
@ -1070,7 +1079,7 @@ public:
|
|||||||
else if (NodeHasOptInFlag)
|
else if (NodeHasOptInFlag)
|
||||||
EndAdjust = "-(HasInFlag?1:0)"; // May have a flag.
|
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) {");
|
", e = N.getNumOperands()" + EndAdjust + "; i != e; ++i) {");
|
||||||
|
|
||||||
emitCode(" AddToISelQueue(N.getOperand(i));");
|
emitCode(" AddToISelQueue(N.getOperand(i));");
|
||||||
|
@ -85,6 +85,10 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
|
|||||||
Record *OpR = OperandList[j].Rec;
|
Record *OpR = OperandList[j].Rec;
|
||||||
std::string Res;
|
std::string Res;
|
||||||
|
|
||||||
|
// Discard "discard" operands.
|
||||||
|
if (OpR->getName() == "discard")
|
||||||
|
continue;
|
||||||
|
|
||||||
if (OpR->isSubClassOf("RegisterClass"))
|
if (OpR->isSubClassOf("RegisterClass"))
|
||||||
Res += getQualifiedName(OpR) + "RegClassID, ";
|
Res += getQualifiedName(OpR) + "RegClassID, ";
|
||||||
else
|
else
|
||||||
@ -202,6 +206,14 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
|
|||||||
MinOperands = Inst.OperandList.back().MIOperandNo +
|
MinOperands = Inst.OperandList.back().MIOperandNo +
|
||||||
Inst.OperandList.back().MINumOperands;
|
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 << " { ";
|
||||||
OS << Num << ",\t" << MinOperands << ",\t"
|
OS << Num << ",\t" << MinOperands << ",\t"
|
||||||
<< Inst.NumDefs << ",\t" << getItinClassNumber(Inst.TheDef)
|
<< Inst.NumDefs << ",\t" << getItinClassNumber(Inst.TheDef)
|
||||||
|
Loading…
Reference in New Issue
Block a user