Modify the intrinsics pattern to separate out the "return" types from the
"parameter" types. An intrinsic can now return a multiple return values like
this:
def add_with_overflow : Intrinsic<[llvm_i32_ty, llvm_i1_ty],
[LLVMMatchType<0>, LLVMMatchType<0>]>;
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@59237 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
index e987c2b..859a8cc 100644
--- a/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -471,7 +471,8 @@
}
if (getExtTypeNum(0) == MVT::iPTR || getExtTypeNum(0) == MVT::iPTRAny) {
- if (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny || ExtVTs[0] == EMVT::isInt)
+ if (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny ||
+ ExtVTs[0] == EMVT::isInt)
return false;
if (EMVT::isExtIntegerInVTs(ExtVTs)) {
std::vector<unsigned char> FVTs = FilterEVTs(ExtVTs, isInteger);
@@ -885,18 +886,22 @@
bool MadeChange = false;
// Apply the result type to the node.
- MadeChange = UpdateNodeType(Int->ArgVTs[0], TP);
+ unsigned NumRetVTs = Int->IS.RetVTs.size();
+ unsigned NumParamVTs = Int->IS.ParamVTs.size();
- if (getNumChildren() != Int->ArgVTs.size())
+ for (unsigned i = 0, e = NumRetVTs; i != e; ++i)
+ MadeChange |= UpdateNodeType(Int->IS.RetVTs[i], TP);
+
+ if (getNumChildren() != NumParamVTs + NumRetVTs)
TP.error("Intrinsic '" + Int->Name + "' expects " +
- utostr(Int->ArgVTs.size()-1) + " operands, not " +
- utostr(getNumChildren()-1) + " operands!");
+ utostr(NumParamVTs + NumRetVTs - 1) + " operands, not " +
+ utostr(getNumChildren() - 1) + " operands!");
// Apply type info to the intrinsic ID.
MadeChange |= getChild(0)->UpdateNodeType(MVT::iPTR, TP);
- for (unsigned i = 1, e = getNumChildren(); i != e; ++i) {
- MVT::SimpleValueType OpVT = Int->ArgVTs[i];
+ for (unsigned i = NumRetVTs, e = getNumChildren(); i != e; ++i) {
+ MVT::SimpleValueType OpVT = Int->IS.ParamVTs[i - NumRetVTs];
MadeChange |= getChild(i)->UpdateNodeType(OpVT, TP);
MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters);
}
@@ -1232,7 +1237,7 @@
// If this intrinsic returns void, it must have side-effects and thus a
// chain.
- if (Int.ArgVTs[0] == MVT::isVoid) {
+ if (Int.IS.RetVTs[0] == MVT::isVoid) {
Operator = getDAGPatterns().get_intrinsic_void_sdnode();
} else if (Int.ModRef != CodeGenIntrinsic::NoMem) {
// Has side-effects, requires chain.
diff --git a/utils/TableGen/CodeGenIntrinsics.h b/utils/TableGen/CodeGenIntrinsics.h
index 4de9386..1170da0 100644
--- a/utils/TableGen/CodeGenIntrinsics.h
+++ b/utils/TableGen/CodeGenIntrinsics.h
@@ -30,16 +30,34 @@
std::string GCCBuiltinName;// Name of the corresponding GCC builtin, or "".
std::string TargetPrefix; // Target prefix, e.g. "ppc" for t-s intrinsics.
- /// ArgVTs - The MVT::SimpleValueType for each argument type. Note that
- /// this list is only populated when in the context of a target .td file.
- /// When building Intrinsics.td, this isn't available, because we don't know
- /// the target pointer size.
- std::vector<MVT::SimpleValueType> ArgVTs;
+ /// IntrinsicSignature - This structure holds the return values and
+ /// parameter values of an intrinsic. If the number of return values is > 1,
+ /// then the intrinsic implicitly returns a first-class aggregate. The
+ /// numbering of the types starts at 0 with the first return value and
+ /// continues from there throug the parameter list. This is useful for
+ /// "matching" types.
+ struct IntrinsicSignature {
+ /// RetVTs - The MVT::SimpleValueType for each return type. Note that this
+ /// list is only populated when in the context of a target .td file. When
+ /// building Intrinsics.td, this isn't available, because we don't know
+ /// the target pointer size.
+ std::vector<MVT::SimpleValueType> RetVTs;
- /// ArgTypeDefs - The records for each argument type.
- ///
- std::vector<Record*> ArgTypeDefs;
-
+ /// RetTypeDefs - The records for each return type.
+ std::vector<Record*> RetTypeDefs;
+
+ /// ParamVTs - The MVT::SimpleValueType for each parameter type. Note that
+ /// this list is only populated when in the context of a target .td file.
+ /// When building Intrinsics.td, this isn't available, because we don't
+ /// know the target pointer size.
+ std::vector<MVT::SimpleValueType> ParamVTs;
+
+ /// ParamTypeDefs - The records for each parameter type.
+ std::vector<Record*> ParamTypeDefs;
+ };
+
+ IntrinsicSignature IS;
+
// Memory mod/ref behavior of this intrinsic.
enum {
NoMem, ReadArgMem, ReadMem, WriteArgMem, WriteMem
diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp
index 4e7a10c..2ff1b19 100644
--- a/utils/TableGen/CodeGenTarget.cpp
+++ b/utils/TableGen/CodeGenTarget.cpp
@@ -438,25 +438,27 @@
isCommutative = false;
if (DefName.size() <= 4 ||
- std::string(DefName.begin(), DefName.begin()+4) != "int_")
+ std::string(DefName.begin(), DefName.begin() + 4) != "int_")
throw "Intrinsic '" + DefName + "' does not start with 'int_'!";
+
EnumName = std::string(DefName.begin()+4, DefName.end());
+
if (R->getValue("GCCBuiltinName")) // Ignore a missing GCCBuiltinName field.
GCCBuiltinName = R->getValueAsString("GCCBuiltinName");
- TargetPrefix = R->getValueAsString("TargetPrefix");
+
+ TargetPrefix = R->getValueAsString("TargetPrefix");
Name = R->getValueAsString("LLVMName");
+
if (Name == "") {
// If an explicit name isn't specified, derive one from the DefName.
Name = "llvm.";
+
for (unsigned i = 0, e = EnumName.size(); i != e; ++i)
- if (EnumName[i] == '_')
- Name += '.';
- else
- Name += EnumName[i];
+ Name += (EnumName[i] == '_') ? '.' : EnumName[i];
} else {
// Verify it starts with "llvm.".
if (Name.size() <= 5 ||
- std::string(Name.begin(), Name.begin()+5) != "llvm.")
+ std::string(Name.begin(), Name.begin() + 5) != "llvm.")
throw "Intrinsic '" + DefName + "'s name does not start with 'llvm.'!";
}
@@ -464,26 +466,37 @@
// "llvm.<targetprefix>.".
if (!TargetPrefix.empty()) {
if (Name.size() < 6+TargetPrefix.size() ||
- std::string(Name.begin()+5, Name.begin()+6+TargetPrefix.size())
- != (TargetPrefix+"."))
- throw "Intrinsic '" + DefName + "' does not start with 'llvm." +
+ std::string(Name.begin() + 5, Name.begin() + 6 + TargetPrefix.size())
+ != (TargetPrefix + "."))
+ throw "Intrinsic '" + DefName + "' does not start with 'llvm." +
TargetPrefix + ".'!";
}
- // Parse the list of argument types.
- ListInit *TypeList = R->getValueAsListInit("Types");
+ // Parse the list of return types.
+ ListInit *TypeList = R->getValueAsListInit("RetTypes");
for (unsigned i = 0, e = TypeList->getSize(); i != e; ++i) {
Record *TyEl = TypeList->getElementAsRecord(i);
assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!");
MVT::SimpleValueType VT = getValueType(TyEl->getValueAsDef("VT"));
isOverloaded |= VT == MVT::iAny || VT == MVT::fAny || VT == MVT::iPTRAny;
- ArgVTs.push_back(VT);
- ArgTypeDefs.push_back(TyEl);
+ IS.RetVTs.push_back(VT);
+ IS.RetTypeDefs.push_back(TyEl);
}
- if (ArgVTs.size() == 0)
+
+ if (IS.RetVTs.size() == 0)
throw "Intrinsic '"+DefName+"' needs at least a type for the ret value!";
-
+ // Parse the list of parameter types.
+ TypeList = R->getValueAsListInit("ParamTypes");
+ for (unsigned i = 0, e = TypeList->getSize(); i != e; ++i) {
+ Record *TyEl = TypeList->getElementAsRecord(i);
+ assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!");
+ MVT::SimpleValueType VT = getValueType(TyEl->getValueAsDef("VT"));
+ isOverloaded |= VT == MVT::iAny || VT == MVT::fAny || VT == MVT::iPTRAny;
+ IS.ParamVTs.push_back(VT);
+ IS.ParamTypeDefs.push_back(TyEl);
+ }
+
// Parse the intrinsic properties.
ListInit *PropList = R->getValueAsListInit("Properties");
for (unsigned i = 0, e = PropList->getSize(); i != e; ++i) {
diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp
index ade1c8c..9247a85 100644
--- a/utils/TableGen/IntrinsicEmitter.cpp
+++ b/utils/TableGen/IntrinsicEmitter.cpp
@@ -138,7 +138,27 @@
}
}
-static void EmitTypeGenerate(std::ostream &OS, Record *ArgType,
+static void EmitTypeGenerate(std::ostream &OS, const Record *ArgType,
+ unsigned &ArgNo);
+
+static void EmitTypeGenerate(std::ostream &OS,
+ const std::vector<Record*> &ArgTypes,
+ unsigned &ArgNo) {
+ if (ArgTypes.size() == 1) {
+ EmitTypeGenerate(OS, ArgTypes.front(), ArgNo);
+ return;
+ }
+
+ OS << "StructType::get(";
+
+ for (std::vector<Record*>::const_iterator
+ I = ArgTypes.begin(), E = ArgTypes.end(); I != E; ++I)
+ EmitTypeGenerate(OS, *I, ArgNo);
+
+ OS << ", NULL)";
+}
+
+static void EmitTypeGenerate(std::ostream &OS, const Record *ArgType,
unsigned &ArgNo) {
MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT"));
@@ -184,17 +204,37 @@
/// RecordListComparator - Provide a determinstic comparator for lists of
/// records.
namespace {
+ typedef std::pair<std::vector<Record*>, std::vector<Record*> > RecPair;
struct RecordListComparator {
- bool operator()(const std::vector<Record*> &LHS,
- const std::vector<Record*> &RHS) const {
+ bool operator()(const RecPair &LHS,
+ const RecPair &RHS) const {
unsigned i = 0;
+ const std::vector<Record*> *LHSVec = &LHS.first;
+ const std::vector<Record*> *RHSVec = &RHS.first;
+ unsigned RHSSize = RHSVec->size();
+ unsigned LHSSize = LHSVec->size();
+
do {
- if (i == RHS.size()) return false; // RHS is shorter than LHS.
- if (LHS[i] != RHS[i])
- return LHS[i]->getName() < RHS[i]->getName();
- } while (++i != LHS.size());
-
- return i != RHS.size();
+ if (i == RHSSize) return false; // RHS is shorter than LHS.
+ if ((*LHSVec)[i] != (*RHSVec)[i])
+ return (*LHSVec)[i]->getName() < (*RHSVec)[i]->getName();
+ } while (++i != LHSSize);
+
+ if (i != RHSSize) return false;
+
+ i = 0;
+ LHSVec = &LHS.second;
+ RHSVec = &RHS.second;
+ RHSSize = RHSVec->size();
+ LHSSize = LHSVec->size();
+
+ for (i = 0; i != LHSSize; ++i) {
+ if (i == RHSSize) return false; // RHS is shorter than LHS.
+ if ((*LHSVec)[i] != (*RHSVec)[i])
+ return (*LHSVec)[i]->getName() < (*RHSVec)[i]->getName();
+ }
+
+ return i != RHSSize;
}
};
}
@@ -209,26 +249,33 @@
// This checking can emit a lot of very common code. To reduce the amount of
// code that we emit, batch up cases that have identical types. This avoids
// problems where GCC can run out of memory compiling Verifier.cpp.
- typedef std::map<std::vector<Record*>, std::vector<unsigned>,
- RecordListComparator> MapTy;
+ typedef std::map<RecPair, std::vector<unsigned>, RecordListComparator> MapTy;
MapTy UniqueArgInfos;
// Compute the unique argument type info.
for (unsigned i = 0, e = Ints.size(); i != e; ++i)
- UniqueArgInfos[Ints[i].ArgTypeDefs].push_back(i);
+ UniqueArgInfos[make_pair(Ints[i].IS.RetTypeDefs,
+ Ints[i].IS.ParamTypeDefs)].push_back(i);
// Loop through the array, emitting one comparison for each batch.
for (MapTy::iterator I = UniqueArgInfos.begin(),
E = UniqueArgInfos.end(); I != E; ++I) {
- for (unsigned i = 0, e = I->second.size(); i != e; ++i) {
+ for (unsigned i = 0, e = I->second.size(); i != e; ++i)
OS << " case Intrinsic::" << Ints[I->second[i]].EnumName << ":\t\t// "
<< Ints[I->second[i]].Name << "\n";
- }
- const std::vector<Record*> &ArgTypes = I->first;
- OS << " VerifyIntrinsicPrototype(ID, IF, " << ArgTypes.size() << ", ";
- for (unsigned j = 0; j != ArgTypes.size(); ++j) {
- Record *ArgType = ArgTypes[j];
+ const RecPair &ArgTypes = I->first;
+ const std::vector<Record*> &RetTys = ArgTypes.first;
+ const std::vector<Record*> &ParamTys = ArgTypes.second;
+
+ OS << " VerifyIntrinsicPrototype(ID, IF, " << RetTys.size() << ", "
+ << ParamTys.size();
+
+ // Emit return types.
+ for (unsigned j = 0, je = RetTys.size(); j != je; ++j) {
+ Record *ArgType = RetTys[j];
+ OS << ", ";
+
if (ArgType->isSubClassOf("LLVMMatchType")) {
unsigned Number = ArgType->getValueAsInt("Number");
assert(Number < j && "Invalid matching number!");
@@ -236,11 +283,28 @@
} else {
MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT"));
OS << getEnumName(VT);
- if (VT == MVT::isVoid && j != 0 && j != ArgTypes.size()-1)
+
+ if (VT == MVT::isVoid && j != 0 && j != je - 1)
throw "Var arg type not last argument";
}
- if (j != ArgTypes.size()-1)
- OS << ", ";
+ }
+
+ // Emit the parameter types.
+ for (unsigned j = 0, je = ParamTys.size(); j != je; ++j) {
+ Record *ArgType = ParamTys[j];
+ OS << ", ";
+
+ if (ArgType->isSubClassOf("LLVMMatchType")) {
+ unsigned Number = ArgType->getValueAsInt("Number");
+ assert(Number < j + RetTys.size() && "Invalid matching number!");
+ OS << "~" << Number;
+ } else {
+ MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT"));
+ OS << getEnumName(VT);
+
+ if (VT == MVT::isVoid && j != 0 && j != je - 1)
+ throw "Var arg type not last argument";
+ }
}
OS << ");\n";
@@ -259,43 +323,47 @@
// Similar to GET_INTRINSIC_VERIFIER, batch up cases that have identical
// types.
- typedef std::map<std::vector<Record*>, std::vector<unsigned>,
- RecordListComparator> MapTy;
+ typedef std::map<RecPair, std::vector<unsigned>, RecordListComparator> MapTy;
MapTy UniqueArgInfos;
// Compute the unique argument type info.
for (unsigned i = 0, e = Ints.size(); i != e; ++i)
- UniqueArgInfos[Ints[i].ArgTypeDefs].push_back(i);
+ UniqueArgInfos[make_pair(Ints[i].IS.RetTypeDefs,
+ Ints[i].IS.ParamTypeDefs)].push_back(i);
// Loop through the array, emitting one generator for each batch.
for (MapTy::iterator I = UniqueArgInfos.begin(),
E = UniqueArgInfos.end(); I != E; ++I) {
- for (unsigned i = 0, e = I->second.size(); i != e; ++i) {
+ for (unsigned i = 0, e = I->second.size(); i != e; ++i)
OS << " case Intrinsic::" << Ints[I->second[i]].EnumName << ":\t\t// "
<< Ints[I->second[i]].Name << "\n";
- }
- const std::vector<Record*> &ArgTypes = I->first;
- unsigned N = ArgTypes.size();
+ const RecPair &ArgTypes = I->first;
+ const std::vector<Record*> &RetTys = ArgTypes.first;
+ const std::vector<Record*> &ParamTys = ArgTypes.second;
+
+ unsigned N = ParamTys.size();
if (N > 1 &&
- getValueType(ArgTypes[N-1]->getValueAsDef("VT")) == MVT::isVoid) {
+ getValueType(ParamTys[N - 1]->getValueAsDef("VT")) == MVT::isVoid) {
OS << " IsVarArg = true;\n";
--N;
}
-
+
unsigned ArgNo = 0;
OS << " ResultTy = ";
- EmitTypeGenerate(OS, ArgTypes[0], ArgNo);
+ EmitTypeGenerate(OS, RetTys, ArgNo);
OS << ";\n";
- for (unsigned j = 1; j != N; ++j) {
+ for (unsigned j = 0; j != N; ++j) {
OS << " ArgTys.push_back(";
- EmitTypeGenerate(OS, ArgTypes[j], ArgNo);
+ EmitTypeGenerate(OS, ParamTys[j], ArgNo);
OS << ");\n";
}
+
OS << " break;\n";
}
+
OS << " }\n";
OS << "#endif\n\n";
}