summaryrefslogtreecommitdiff
path: root/utils/TableGen/DAGISelEmitter.cpp
diff options
context:
space:
mode:
authorDan Gohman <gohman@apple.com>2008-07-07 21:00:17 +0000
committerDan Gohman <gohman@apple.com>2008-07-07 21:00:17 +0000
commit95d110920e4ce9ded59934a432327a5343b1069d (patch)
treebc03b475cfc8ff11039e6aabf494d8c885666201 /utils/TableGen/DAGISelEmitter.cpp
parent667a68b96aad48c053d6678ee5cb6d440072e81a (diff)
downloadllvm-95d110920e4ce9ded59934a432327a5343b1069d.tar.gz
llvm-95d110920e4ce9ded59934a432327a5343b1069d.tar.bz2
llvm-95d110920e4ce9ded59934a432327a5343b1069d.tar.xz
Refactor the tablegen DAGISelEmitter code for outputing calls to
getTargetNode and SelectNodeTo to reduce duplication, and to make some of the getTargetNode code available to SelectNodeTo. Use SelectNodeTo instead of getTargetNode in several new interesting cases, as it mutates nodes in place instead of creating new ones. This triggers some scheduling behavior differences due to nodes being presented to the scheduler in a different order. Some of the arbitrary scheduling decisions it makes are now arbitrarily made differently. This is visible in CodeGen/PowerPC/LargeAbsoluteAddr.ll, where a trivial scheduling difference led to a trivial register allocation difference. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@53203 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils/TableGen/DAGISelEmitter.cpp')
-rw-r--r--utils/TableGen/DAGISelEmitter.cpp409
1 files changed, 208 insertions, 201 deletions
diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp
index c6cac7d16a..bdb7fcf35a 100644
--- a/utils/TableGen/DAGISelEmitter.cpp
+++ b/utils/TableGen/DAGISelEmitter.cpp
@@ -18,6 +18,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Streams.h"
#include <algorithm>
+#include <deque>
using namespace llvm;
//===----------------------------------------------------------------------===//
@@ -1033,230 +1034,236 @@ public:
}
unsigned ResNo = TmpNo++;
- if (!isRoot || InputHasChain || NodeHasChain || NodeHasOutFlag ||
- NodeHasOptInFlag || HasImpResults) {
- std::string Code;
- std::string Code2;
- std::string NodeName;
- if (!isRoot) {
- NodeName = "Tmp" + utostr(ResNo);
- Code2 = "SDOperand " + NodeName + "(";
- } else {
- NodeName = "ResNode";
- if (!ResNodeDecled) {
- Code2 = "SDNode *" + NodeName + " = ";
- ResNodeDecled = true;
- } else
- Code2 = NodeName + " = ";
- }
- Code += "CurDAG->getTargetNode(Opc" + utostr(OpcNo);
- unsigned OpsNo = OpcNo;
- emitOpcode(II.Namespace + "::" + II.TheDef->getName());
+ unsigned OpsNo = OpcNo;
+ std::string CodePrefix;
+ bool ChainAssignmentNeeded = NodeHasChain && !isRoot;
+ std::deque<std::string> After;
+ std::string NodeName;
+ if (!isRoot) {
+ NodeName = "Tmp" + utostr(ResNo);
+ CodePrefix = "SDOperand " + NodeName + "(";
+ } else {
+ NodeName = "ResNode";
+ if (!ResNodeDecled) {
+ CodePrefix = "SDNode *" + NodeName + " = ";
+ ResNodeDecled = true;
+ } else
+ CodePrefix = NodeName + " = ";
+ }
- // Output order: results, chain, flags
- // Result types.
- if (NumResults > 0 && N->getTypeNum(0) != MVT::isVoid) {
- Code += ", VT" + utostr(VTNo);
- emitVT(getEnumName(N->getTypeNum(0)));
- }
- // Add types for implicit results in physical registers, scheduler will
- // care of adding copyfromreg nodes.
- for (unsigned i = 0; i < NumDstRegs; i++) {
- Record *RR = DstRegs[i];
- if (RR->isSubClassOf("Register")) {
- MVT::SimpleValueType RVT = getRegisterValueType(RR, CGT);
- Code += ", " + getEnumName(RVT);
- }
- }
- if (NodeHasChain)
- Code += ", MVT::Other";
- if (NodeHasOutFlag)
- Code += ", MVT::Flag";
-
- // Inputs.
- if (IsVariadic) {
- for (unsigned i = 0, e = AllOps.size(); i != e; ++i)
- emitCode("Ops" + utostr(OpsNo) + ".push_back(" + AllOps[i] + ");");
- AllOps.clear();
-
- // Figure out whether any operands at the end of the op list are not
- // part of the variable section.
- std::string EndAdjust;
- if (NodeHasInFlag || HasImpInputs)
- EndAdjust = "-1"; // Always has one flag.
- else if (NodeHasOptInFlag)
- EndAdjust = "-(HasInFlag?1:0)"; // May have a flag.
-
- emitCode("for (unsigned i = NumInputRootOps + " + utostr(NodeHasChain) +
- ", e = N.getNumOperands()" + EndAdjust + "; i != e; ++i) {");
-
- emitCode(" AddToISelQueue(N.getOperand(i));");
- emitCode(" Ops" + utostr(OpsNo) + ".push_back(N.getOperand(i));");
- emitCode("}");
- }
+ std::string Code = "Opc" + utostr(OpcNo);
- // Generate MemOperandSDNodes nodes for each memory accesses covered by
- // this pattern.
- if (II.isSimpleLoad | II.mayLoad | II.mayStore) {
- std::vector<std::string>::const_iterator mi, mie;
- for (mi = LSI.begin(), mie = LSI.end(); mi != mie; ++mi) {
- emitCode("SDOperand LSI_" + *mi + " = "
- "CurDAG->getMemOperand(cast<MemSDNode>(" +
- *mi + ")->getMemOperand());");
- if (IsVariadic)
- emitCode("Ops" + utostr(OpsNo) + ".push_back(LSI_" + *mi + ");");
- else
- AllOps.push_back("LSI_" + *mi);
- }
+ emitOpcode(II.Namespace + "::" + II.TheDef->getName());
+
+ // Output order: results, chain, flags
+ // Result types.
+ if (NumResults > 0 && N->getTypeNum(0) != MVT::isVoid) {
+ Code += ", VT" + utostr(VTNo);
+ emitVT(getEnumName(N->getTypeNum(0)));
+ }
+ // Add types for implicit results in physical registers, scheduler will
+ // care of adding copyfromreg nodes.
+ for (unsigned i = 0; i < NumDstRegs; i++) {
+ Record *RR = DstRegs[i];
+ if (RR->isSubClassOf("Register")) {
+ MVT::SimpleValueType RVT = getRegisterValueType(RR, CGT);
+ Code += ", " + getEnumName(RVT);
}
+ }
+ if (NodeHasChain)
+ Code += ", MVT::Other";
+ if (NodeHasOutFlag)
+ Code += ", MVT::Flag";
+
+ // Inputs.
+ if (IsVariadic) {
+ for (unsigned i = 0, e = AllOps.size(); i != e; ++i)
+ emitCode("Ops" + utostr(OpsNo) + ".push_back(" + AllOps[i] + ");");
+ AllOps.clear();
+
+ // Figure out whether any operands at the end of the op list are not
+ // part of the variable section.
+ std::string EndAdjust;
+ if (NodeHasInFlag || HasImpInputs)
+ EndAdjust = "-1"; // Always has one flag.
+ else if (NodeHasOptInFlag)
+ EndAdjust = "-(HasInFlag?1:0)"; // May have a flag.
+
+ emitCode("for (unsigned i = NumInputRootOps + " + utostr(NodeHasChain) +
+ ", e = N.getNumOperands()" + EndAdjust + "; i != e; ++i) {");
+
+ emitCode(" AddToISelQueue(N.getOperand(i));");
+ emitCode(" Ops" + utostr(OpsNo) + ".push_back(N.getOperand(i));");
+ emitCode("}");
+ }
- if (NodeHasChain) {
+ // Generate MemOperandSDNodes nodes for each memory accesses covered by
+ // this pattern.
+ if (II.isSimpleLoad | II.mayLoad | II.mayStore) {
+ std::vector<std::string>::const_iterator mi, mie;
+ for (mi = LSI.begin(), mie = LSI.end(); mi != mie; ++mi) {
+ emitCode("SDOperand LSI_" + *mi + " = "
+ "CurDAG->getMemOperand(cast<MemSDNode>(" +
+ *mi + ")->getMemOperand());");
if (IsVariadic)
- emitCode("Ops" + utostr(OpsNo) + ".push_back(" + ChainName + ");");
+ emitCode("Ops" + utostr(OpsNo) + ".push_back(LSI_" + *mi + ");");
else
- AllOps.push_back(ChainName);
- }
-
- if (IsVariadic) {
- if (NodeHasInFlag || HasImpInputs)
- emitCode("Ops" + utostr(OpsNo) + ".push_back(InFlag);");
- else if (NodeHasOptInFlag) {
- emitCode("if (HasInFlag)");
- emitCode(" Ops" + utostr(OpsNo) + ".push_back(InFlag);");
- }
- Code += ", &Ops" + utostr(OpsNo) + "[0], Ops" + utostr(OpsNo) +
- ".size()";
- } else if (NodeHasInFlag || NodeHasOptInFlag || HasImpInputs)
- AllOps.push_back("InFlag");
-
- unsigned NumOps = AllOps.size();
- if (NumOps) {
- if (!NodeHasOptInFlag && NumOps < 4) {
- for (unsigned i = 0; i != NumOps; ++i)
- Code += ", " + AllOps[i];
- } else {
- std::string OpsCode = "SDOperand Ops" + utostr(OpsNo) + "[] = { ";
- for (unsigned i = 0; i != NumOps; ++i) {
- OpsCode += AllOps[i];
- if (i != NumOps-1)
- OpsCode += ", ";
- }
- emitCode(OpsCode + " };");
- Code += ", Ops" + utostr(OpsNo) + ", ";
- if (NodeHasOptInFlag) {
- Code += "HasInFlag ? ";
- Code += utostr(NumOps) + " : " + utostr(NumOps-1);
- } else
- Code += utostr(NumOps);
- }
+ AllOps.push_back("LSI_" + *mi);
}
-
- if (!isRoot)
- Code += "), 0";
- emitCode(Code2 + Code + ");");
+ }
- if (NodeHasChain) {
- // Remember which op produces the chain.
- if (!isRoot)
- emitCode(ChainName + " = SDOperand(" + NodeName +
- ".Val, " + utostr(NumResults+NumDstRegs) + ");");
- else
- emitCode(ChainName + " = SDOperand(" + NodeName +
- ", " + utostr(NumResults+NumDstRegs) + ");");
- }
+ if (NodeHasChain) {
+ if (IsVariadic)
+ emitCode("Ops" + utostr(OpsNo) + ".push_back(" + ChainName + ");");
+ else
+ AllOps.push_back(ChainName);
+ }
- if (!isRoot) {
- NodeOps.push_back("Tmp" + utostr(ResNo));
- return NodeOps;
+ if (IsVariadic) {
+ if (NodeHasInFlag || HasImpInputs)
+ emitCode("Ops" + utostr(OpsNo) + ".push_back(InFlag);");
+ else if (NodeHasOptInFlag) {
+ emitCode("if (HasInFlag)");
+ emitCode(" Ops" + utostr(OpsNo) + ".push_back(InFlag);");
}
-
- bool NeedReplace = false;
- if (NodeHasOutFlag) {
- if (!InFlagDecled) {
- emitCode("SDOperand InFlag(ResNode, " +
- utostr(NumResults+NumDstRegs+(unsigned)NodeHasChain) + ");");
- InFlagDecled = true;
+ Code += ", &Ops" + utostr(OpsNo) + "[0], Ops" + utostr(OpsNo) +
+ ".size()";
+ } else if (NodeHasInFlag || NodeHasOptInFlag || HasImpInputs)
+ AllOps.push_back("InFlag");
+
+ unsigned NumOps = AllOps.size();
+ if (NumOps) {
+ if (!NodeHasOptInFlag && NumOps < 4) {
+ for (unsigned i = 0; i != NumOps; ++i)
+ Code += ", " + AllOps[i];
+ } else {
+ std::string OpsCode = "SDOperand Ops" + utostr(OpsNo) + "[] = { ";
+ for (unsigned i = 0; i != NumOps; ++i) {
+ OpsCode += AllOps[i];
+ if (i != NumOps-1)
+ OpsCode += ", ";
+ }
+ emitCode(OpsCode + " };");
+ Code += ", Ops" + utostr(OpsNo) + ", ";
+ if (NodeHasOptInFlag) {
+ Code += "HasInFlag ? ";
+ Code += utostr(NumOps) + " : " + utostr(NumOps-1);
} else
- emitCode("InFlag = SDOperand(ResNode, " +
- utostr(NumResults+NumDstRegs+(unsigned)NodeHasChain) + ");");
+ Code += utostr(NumOps);
}
+ }
+
+ if (!isRoot)
+ Code += "), 0";
- if (FoldedChains.size() > 0) {
- std::string Code;
- for (unsigned j = 0, e = FoldedChains.size(); j < e; j++)
- emitCode("ReplaceUses(SDOperand(" +
- FoldedChains[j].first + ".Val, " +
- utostr(FoldedChains[j].second) + "), SDOperand(ResNode, " +
- utostr(NumResults+NumDstRegs) + "));");
- NeedReplace = true;
- }
+ bool NeedReplace = false;
+ if (!isRoot) {
+ NodeOps.push_back("Tmp" + utostr(ResNo));
+ } else {
- if (NodeHasOutFlag) {
- if (FoldedFlag.first != "") {
- emitCode("ReplaceUses(SDOperand(" + FoldedFlag.first + ".Val, " +
- utostr(FoldedFlag.second) + "), InFlag);");
- } else {
- assert(NodeHasProperty(Pattern, SDNPOutFlag, CGP));
- emitCode("ReplaceUses(SDOperand(N.Val, " +
- utostr(NumPatResults + (unsigned)InputHasChain)
- +"), InFlag);");
- }
- NeedReplace = true;
- }
+ if (NodeHasOutFlag) {
+ if (!InFlagDecled) {
+ After.push_back("SDOperand InFlag(ResNode, " +
+ utostr(NumResults+NumDstRegs+(unsigned)NodeHasChain) +
+ ");");
+ InFlagDecled = true;
+ } else
+ After.push_back("InFlag = SDOperand(ResNode, " +
+ utostr(NumResults+NumDstRegs+(unsigned)NodeHasChain) +
+ ");");
+ }
+
+ if (FoldedChains.size() > 0) {
+ std::string Code;
+ for (unsigned j = 0, e = FoldedChains.size(); j < e; j++)
+ After.push_back("ReplaceUses(SDOperand(" +
+ FoldedChains[j].first + ".Val, " +
+ utostr(FoldedChains[j].second) +
+ "), SDOperand(ResNode, " +
+ utostr(NumResults+NumDstRegs) + "));");
+ NeedReplace = true;
+ }
- if (NeedReplace && InputHasChain)
- emitCode("ReplaceUses(SDOperand(N.Val, " +
- utostr(NumPatResults) + "), SDOperand(" + ChainName
- + ".Val, " + ChainName + ".ResNo" + "));");
-
- // User does not expect the instruction would produce a chain!
- if ((!InputHasChain && NodeHasChain) && NodeHasOutFlag) {
- ;
- } else if (InputHasChain && !NodeHasChain) {
- // One of the inner node produces a chain.
- if (NodeHasOutFlag)
- emitCode("ReplaceUses(SDOperand(N.Val, " + utostr(NumPatResults+1) +
- "), SDOperand(ResNode, N.ResNo-1));");
- emitCode("ReplaceUses(SDOperand(N.Val, " + utostr(NumPatResults) +
- "), " + ChainName + ");");
+ if (NodeHasOutFlag) {
+ if (FoldedFlag.first != "") {
+ After.push_back("ReplaceUses(SDOperand(" + FoldedFlag.first +
+ ".Val, " +
+ utostr(FoldedFlag.second) + "), InFlag);");
+ } else {
+ assert(NodeHasProperty(Pattern, SDNPOutFlag, CGP));
+ After.push_back("ReplaceUses(SDOperand(N.Val, " +
+ utostr(NumPatResults + (unsigned)InputHasChain)
+ +"), InFlag);");
}
+ NeedReplace = true;
+ }
- emitCode("return ResNode;");
- } else {
- std::string Code = "return CurDAG->SelectNodeTo(N.Val, Opc" +
- utostr(OpcNo);
- if (N->getTypeNum(0) != MVT::isVoid)
- Code += ", VT" + utostr(VTNo);
+ if (NeedReplace && InputHasChain) {
+ After.push_back("ReplaceUses(SDOperand(N.Val, " +
+ utostr(NumPatResults) + "), SDOperand(" + ChainName
+ + ".Val, " + ChainName + ".ResNo" + "));");
+ ChainAssignmentNeeded |= NodeHasChain;
+ }
+
+ // User does not expect the instruction would produce a chain!
+ if ((!InputHasChain && NodeHasChain) && NodeHasOutFlag) {
+ ;
+ } else if (InputHasChain && !NodeHasChain) {
+ // One of the inner node produces a chain.
if (NodeHasOutFlag)
- Code += ", MVT::Flag";
+ After.push_back("ReplaceUses(SDOperand(N.Val, " +
+ utostr(NumPatResults+1) +
+ "), SDOperand(ResNode, N.ResNo-1));");
+ After.push_back("ReplaceUses(SDOperand(N.Val, " +
+ utostr(NumPatResults) + "), " + ChainName + ");");
+ NeedReplace = true;
+ }
+ }
- if (NodeHasInFlag || NodeHasOptInFlag || HasImpInputs)
- AllOps.push_back("InFlag");
+ if (ChainAssignmentNeeded) {
+ // Remember which op produces the chain.
+ std::string ChainAssign;
+ if (!isRoot)
+ ChainAssign = ChainName + " = SDOperand(" + NodeName +
+ ".Val, " + utostr(NumResults+NumDstRegs) + ");";
+ else
+ ChainAssign = ChainName + " = SDOperand(" + NodeName +
+ ", " + utostr(NumResults+NumDstRegs) + ");";
- unsigned NumOps = AllOps.size();
- if (NumOps) {
- if (!NodeHasOptInFlag && NumOps < 4) {
- for (unsigned i = 0; i != NumOps; ++i)
- Code += ", " + AllOps[i];
- } else {
- std::string OpsCode = "SDOperand Ops" + utostr(OpcNo) + "[] = { ";
- for (unsigned i = 0; i != NumOps; ++i) {
- OpsCode += AllOps[i];
- if (i != NumOps-1)
- OpsCode += ", ";
- }
- emitCode(OpsCode + " };");
- Code += ", Ops" + utostr(OpcNo) + ", ";
- Code += utostr(NumOps);
- }
- }
- emitCode(Code + ");");
- emitOpcode(II.Namespace + "::" + II.TheDef->getName());
- if (N->getTypeNum(0) != MVT::isVoid)
- emitVT(getEnumName(N->getTypeNum(0)));
+ After.push_front(ChainAssign);
}
+ // Use getTargetNode or SelectNodeTo? The safe choice is getTargetNode,
+ // but SelectNodeTo can be faster.
+ //
+ // SelectNodeTo is not safe in a non-root context, or if there is any
+ // replacement of results needed.
+ //
+ // SelectNodeTo is not profitable if it would require a dynamically
+ // allocated operand list in a situation where getTargetNode would be
+ // able to reuse a co-allocated operand list (as in a unary, binary or
+ // ternary SDNode, for example).
+ //
+ if (!isRoot || NeedReplace ||
+ (!IsVariadic && AllOps.size() < 4 &&
+ Pattern->getNumChildren() + InputHasChain + NodeHasInFlag <
+ AllOps.size())) {
+ Code = "CurDAG->getTargetNode(" + Code;
+ } else {
+ Code = "CurDAG->SelectNodeTo(N.Val, " + Code;
+ }
+ if (isRoot) {
+ if (After.empty())
+ CodePrefix = "return ";
+ else
+ After.push_back("return ResNode;");
+ }
+
+ emitCode(CodePrefix + Code + ");");
+ for (unsigned i = 0, e = After.size(); i != e; ++i)
+ emitCode(After[i]);
+
return NodeOps;
} else if (Op->isSubClassOf("SDNodeXForm")) {
assert(N->getNumChildren() == 1 && "node xform should have one child!");