X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=utils%2FTableGen%2FIntrinsicEmitter.cpp;h=e5e7cea1200f407ce18864fbbcb76d560920f85f;hb=a5d585685493d85d5cb72b831a68ec747ae55a86;hp=c3db273ce60706185edf1b25d1daa34e42e8757f;hpb=0fee3ff93ea0bf1ce6466fec1d8496514d76e289;p=oota-llvm.git diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp index c3db273ce60..e5e7cea1200 100644 --- a/utils/TableGen/IntrinsicEmitter.cpp +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -2,8 +2,8 @@ // // The LLVM Compiler Infrastructure // -// This file was developed by Chris Lattner and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // @@ -14,6 +14,7 @@ #include "CodeGenTarget.h" #include "IntrinsicEmitter.h" #include "Record.h" +#include "StringMatcher.h" #include "llvm/ADT/StringExtras.h" #include using namespace llvm; @@ -22,17 +23,25 @@ using namespace llvm; // IntrinsicEmitter Implementation //===----------------------------------------------------------------------===// -void IntrinsicEmitter::run(std::ostream &OS) { +void IntrinsicEmitter::run(raw_ostream &OS) { EmitSourceFileHeader("Intrinsic Function Source Fragment", OS); - std::vector Ints = LoadIntrinsics(Records); + std::vector Ints = LoadIntrinsics(Records, TargetOnly); + + if (TargetOnly && !Ints.empty()) + TargetPrefix = Ints[0].TargetPrefix; + + EmitPrefix(OS); // Emit the enum information. EmitEnumInfo(Ints, OS); // Emit the intrinsic ID -> name table. EmitIntrinsicToNameTable(Ints, OS); - + + // Emit the intrinsic ID -> overload table. + EmitIntrinsicToOverloadTable(Ints, OS); + // Emit the function name recognizer. EmitFnNameRecognizer(Ints, OS); @@ -42,24 +51,41 @@ void IntrinsicEmitter::run(std::ostream &OS) { // Emit the intrinsic declaration generator. EmitGenerator(Ints, OS); - // Emit mod/ref info for each function. - EmitModRefInfo(Ints, OS); - - // Emit table of non-memory accessing intrinsics. - EmitNoMemoryInfo(Ints, OS); - - // Emit side effect info for each intrinsic. - EmitSideEffectInfo(Ints, OS); + // Emit the intrinsic parameter attributes. + EmitAttributes(Ints, OS); + + // Emit intrinsic alias analysis mod/ref behavior. + EmitModRefBehavior(Ints, OS); // Emit a list of intrinsics with corresponding GCC builtins. EmitGCCBuiltinList(Ints, OS); // Emit code to translate GCC builtins into LLVM intrinsics. EmitIntrinsicToGCCBuiltinMap(Ints, OS); + + EmitSuffix(OS); +} + +void IntrinsicEmitter::EmitPrefix(raw_ostream &OS) { + OS << "// VisualStudio defines setjmp as _setjmp\n" + "#if defined(_MSC_VER) && defined(setjmp) && \\\n" + " !defined(setjmp_undefined_for_msvc)\n" + "# pragma push_macro(\"setjmp\")\n" + "# undef setjmp\n" + "# define setjmp_undefined_for_msvc\n" + "#endif\n\n"; +} + +void IntrinsicEmitter::EmitSuffix(raw_ostream &OS) { + OS << "#if defined(_MSC_VER) && defined(setjmp_undefined_for_msvc)\n" + "// let's return it to _setjmp state\n" + "# pragma pop_macro(\"setjmp\")\n" + "# undef setjmp_undefined_for_msvc\n" + "#endif\n\n"; } void IntrinsicEmitter::EmitEnumInfo(const std::vector &Ints, - std::ostream &OS) { + raw_ostream &OS) { OS << "// Enum values for Intrinsics.h\n"; OS << "#ifdef GET_INTRINSIC_ENUM_VALUES\n"; for (unsigned i = 0, e = Ints.size(); i != e; ++i) { @@ -73,45 +99,56 @@ void IntrinsicEmitter::EmitEnumInfo(const std::vector &Ints, void IntrinsicEmitter:: EmitFnNameRecognizer(const std::vector &Ints, - std::ostream &OS) { - // Build a function name -> intrinsic name mapping. - std::map IntMapping; + raw_ostream &OS) { + // Build a 'first character of function name' -> intrinsic # mapping. + std::map > IntMapping; for (unsigned i = 0, e = Ints.size(); i != e; ++i) - IntMapping[Ints[i].Name] = i; - + IntMapping[Ints[i].Name[5]].push_back(i); + OS << "// Function name -> enum value recognizer code.\n"; OS << "#ifdef GET_FUNCTION_RECOGNIZER\n"; - OS << " switch (Name[5]) {\n"; - OS << " default:\n"; - // Emit the intrinsics in sorted order. - char LastChar = 0; - for (std::map::iterator I = IntMapping.begin(), + OS << " StringRef NameR(Name+6, Len-6); // Skip over 'llvm.'\n"; + OS << " switch (Name[5]) { // Dispatch on first letter.\n"; + OS << " default: break;\n"; + // Emit the intrinsic matching stuff by first letter. + for (std::map >::iterator I = IntMapping.begin(), E = IntMapping.end(); I != E; ++I) { - if (I->first[5] != LastChar) { - LastChar = I->first[5]; - OS << " break;\n"; - OS << " case '" << LastChar << "':\n"; + OS << " case '" << I->first << "':\n"; + std::vector &IntList = I->second; + + // Emit all the overloaded intrinsics first, build a table of the + // non-overloaded ones. + std::vector MatchTable; + + for (unsigned i = 0, e = IntList.size(); i != e; ++i) { + unsigned IntNo = IntList[i]; + std::string Result = "return " + TargetPrefix + "Intrinsic::" + + Ints[IntNo].EnumName + ";"; + + if (!Ints[IntNo].isOverloaded) { + MatchTable.push_back(std::make_pair(Ints[IntNo].Name.substr(6),Result)); + continue; + } + + // For overloaded intrinsics, only the prefix needs to match + std::string TheStr = Ints[IntNo].Name.substr(6); + TheStr += '.'; // Require "bswap." instead of bswap. + OS << " if (NameR.startswith(\"" << TheStr << "\")) " + << Result << '\n'; } - // For overloaded intrinsics, only the prefix needs to match - if (Ints[I->second].isOverloaded) - OS << " if (Len > " << I->first.size() - << " && !memcmp(Name, \"" << I->first << ".\", " - << (I->first.size() + 1) << ")) return Intrinsic::" - << Ints[I->second].EnumName << ";\n"; - else - OS << " if (Len == " << I->first.size() - << " && !memcmp(Name, \"" << I->first << "\", " - << I->first.size() << ")) return Intrinsic::" - << Ints[I->second].EnumName << ";\n"; + // Emit the matcher logic for the fixed length strings. + StringMatcher("NameR", MatchTable, OS).Emit(1); + OS << " break; // end of '" << I->first << "' case.\n"; } + OS << " }\n"; OS << "#endif\n\n"; } void IntrinsicEmitter:: EmitIntrinsicToNameTable(const std::vector &Ints, - std::ostream &OS) { + raw_ostream &OS) { OS << "// Intrinsic ID to name table\n"; OS << "#ifdef GET_INTRINSIC_NAME_TABLE\n"; OS << " // Note that entry #0 is the invalid intrinsic!\n"; @@ -120,50 +157,116 @@ EmitIntrinsicToNameTable(const std::vector &Ints, OS << "#endif\n\n"; } -static void EmitTypeForValueType(std::ostream &OS, MVT::ValueType VT) { - if (MVT::isInteger(VT)) { - unsigned BitWidth = MVT::getSizeInBits(VT); - OS << "IntegerType::get(" << BitWidth << ")"; +void IntrinsicEmitter:: +EmitIntrinsicToOverloadTable(const std::vector &Ints, + raw_ostream &OS) { + OS << "// Intrinsic ID to overload table\n"; + OS << "#ifdef GET_INTRINSIC_OVERLOAD_TABLE\n"; + OS << " // Note that entry #0 is the invalid intrinsic!\n"; + for (unsigned i = 0, e = Ints.size(); i != e; ++i) { + OS << " "; + if (Ints[i].isOverloaded) + OS << "true"; + else + OS << "false"; + OS << ",\n"; + } + OS << "#endif\n\n"; +} + +static void EmitTypeForValueType(raw_ostream &OS, MVT::SimpleValueType VT) { + if (EVT(VT).isInteger()) { + unsigned BitWidth = EVT(VT).getSizeInBits(); + OS << "IntegerType::get(Context, " << BitWidth << ")"; } else if (VT == MVT::Other) { // MVT::OtherVT is used to mean the empty struct type here. - OS << "StructType::get(std::vector())"; + OS << "StructType::get(Context)"; } else if (VT == MVT::f32) { - OS << "Type::FloatTy"; + OS << "Type::getFloatTy(Context)"; } else if (VT == MVT::f64) { - OS << "Type::DoubleTy"; + OS << "Type::getDoubleTy(Context)"; + } else if (VT == MVT::f80) { + OS << "Type::getX86_FP80Ty(Context)"; + } else if (VT == MVT::f128) { + OS << "Type::getFP128Ty(Context)"; + } else if (VT == MVT::ppcf128) { + OS << "Type::getPPC_FP128Ty(Context)"; } else if (VT == MVT::isVoid) { - OS << "Type::VoidTy"; + OS << "Type::getVoidTy(Context)"; + } else if (VT == MVT::Metadata) { + OS << "Type::getMetadataTy(Context)"; + } else if (VT == MVT::x86mmx) { + OS << "Type::getX86_MMXTy(Context)"; } else { assert(false && "Unsupported ValueType!"); } } -static void EmitTypeGenerate(std::ostream &OS, Record *ArgType, +static void EmitTypeGenerate(raw_ostream &OS, const Record *ArgType, + unsigned &ArgNo); + +static void EmitTypeGenerate(raw_ostream &OS, + const std::vector &ArgTypes, unsigned &ArgNo) { - MVT::ValueType VT = getValueType(ArgType->getValueAsDef("VT")); + if (ArgTypes.empty()) + return EmitTypeForValueType(OS, MVT::isVoid); + + if (ArgTypes.size() == 1) + return EmitTypeGenerate(OS, ArgTypes.front(), ArgNo); + + OS << "StructType::get("; + + for (std::vector::const_iterator + I = ArgTypes.begin(), E = ArgTypes.end(); I != E; ++I) { + EmitTypeGenerate(OS, *I, ArgNo); + OS << ", "; + } + + OS << " NULL)"; +} + +static void EmitTypeGenerate(raw_ostream &OS, const Record *ArgType, + unsigned &ArgNo) { + MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT")); if (ArgType->isSubClassOf("LLVMMatchType")) { unsigned Number = ArgType->getValueAsInt("Number"); assert(Number < ArgNo && "Invalid matching number!"); - OS << "Tys[" << Number << "]"; - } else if (VT == MVT::iAny || VT == MVT::fAny) { + if (ArgType->isSubClassOf("LLVMExtendedElementVectorType")) + OS << "VectorType::getExtendedElementVectorType" + << "(dyn_cast(Tys[" << Number << "]))"; + else if (ArgType->isSubClassOf("LLVMTruncatedElementVectorType")) + OS << "VectorType::getTruncatedElementVectorType" + << "(dyn_cast(Tys[" << Number << "]))"; + else + OS << "Tys[" << Number << "]"; + } else if (VT == MVT::iAny || VT == MVT::fAny || VT == MVT::vAny) { // NOTE: The ArgNo variable here is not the absolute argument number, it is // the index of the "arbitrary" type in the Tys array passed to the // Intrinsic::getDeclaration function. Consequently, we only want to // increment it when we actually hit an overloaded type. Getting this wrong // leads to very subtle bugs! OS << "Tys[" << ArgNo++ << "]"; - } else if (MVT::isVector(VT)) { + } else if (EVT(VT).isVector()) { + EVT VVT = VT; OS << "VectorType::get("; - EmitTypeForValueType(OS, MVT::getVectorElementType(VT)); - OS << ", " << MVT::getVectorNumElements(VT) << ")"; + EmitTypeForValueType(OS, VVT.getVectorElementType().getSimpleVT().SimpleTy); + OS << ", " << VVT.getVectorNumElements() << ")"; } else if (VT == MVT::iPTR) { - OS << "PointerType::get("; + OS << "PointerType::getUnqual("; EmitTypeGenerate(OS, ArgType->getValueAsDef("ElTy"), ArgNo); OS << ")"; + } else if (VT == MVT::iPTRAny) { + // Make sure the user has passed us an argument type to overload. If not, + // treat it as an ordinary (not overloaded) intrinsic. + OS << "(" << ArgNo << " < Tys.size()) ? Tys[" << ArgNo + << "] : PointerType::getUnqual("; + EmitTypeGenerate(OS, ArgType->getValueAsDef("ElTy"), ArgNo); + OS << ")"; + ++ArgNo; } else if (VT == MVT::isVoid) { if (ArgNo == 0) - OS << "Type::VoidTy"; + OS << "Type::getVoidTy(Context)"; else // MVT::isVoid is used to mean varargs here. OS << "..."; @@ -172,26 +275,46 @@ static void EmitTypeGenerate(std::ostream &OS, Record *ArgType, } } -/// RecordListComparator - Provide a determinstic comparator for lists of +/// RecordListComparator - Provide a deterministic comparator for lists of /// records. namespace { + typedef std::pair, std::vector > RecPair; struct RecordListComparator { - bool operator()(const std::vector &LHS, - const std::vector &RHS) const { + bool operator()(const RecPair &LHS, + const RecPair &RHS) const { unsigned i = 0; - 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(); + const std::vector *LHSVec = &LHS.first; + const std::vector *RHSVec = &RHS.first; + unsigned RHSSize = RHSVec->size(); + unsigned LHSSize = LHSVec->size(); + + for (; 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(); + } + + if (i != RHSSize) return true; + + 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; } }; } void IntrinsicEmitter::EmitVerifier(const std::vector &Ints, - std::ostream &OS) { + raw_ostream &OS) { OS << "// Verifier::visitIntrinsicFunctionCall code.\n"; OS << "#ifdef GET_INTRINSIC_VERIFIER\n"; OS << " switch (ID) {\n"; @@ -200,38 +323,83 @@ void IntrinsicEmitter::EmitVerifier(const std::vector &Ints, // 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, - RecordListComparator> MapTy; + typedef std::map, 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 &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 &RetTys = ArgTypes.first; + const std::vector &ParamTys = ArgTypes.second; + std::vector OverloadedTypeIndices; + + 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 < OverloadedTypeIndices.size() && + "Invalid matching number!"); + Number = OverloadedTypeIndices[Number]; + if (ArgType->isSubClassOf("LLVMExtendedElementVectorType")) + OS << "~(ExtendedElementVectorType | " << Number << ")"; + else if (ArgType->isSubClassOf("LLVMTruncatedElementVectorType")) + OS << "~(TruncatedElementVectorType | " << Number << ")"; + else + OS << "~" << Number; + } else { + MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT")); + OS << getEnumName(VT); + + if (EVT(VT).isOverloaded()) + OverloadedTypeIndices.push_back(j); + + if (VT == MVT::isVoid && j != 0 && j != je - 1) + throw "Var arg type not last argument"; + } + } + + // 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 && "Invalid matching number!"); - OS << "~" << Number; + assert(Number < OverloadedTypeIndices.size() && + "Invalid matching number!"); + Number = OverloadedTypeIndices[Number]; + if (ArgType->isSubClassOf("LLVMExtendedElementVectorType")) + OS << "~(ExtendedElementVectorType | " << Number << ")"; + else if (ArgType->isSubClassOf("LLVMTruncatedElementVectorType")) + OS << "~(TruncatedElementVectorType | " << Number << ")"; + else + OS << "~" << Number; } else { - MVT::ValueType VT = getValueType(ArgType->getValueAsDef("VT")); + MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT")); OS << getEnumName(VT); - if (VT == MVT::isVoid && j != 0 && j != ArgTypes.size()-1) + + if (EVT(VT).isOverloaded()) + OverloadedTypeIndices.push_back(j + RetTys.size()); + + if (VT == MVT::isVoid && j != 0 && j != je - 1) throw "Var arg type not last argument"; } - if (j != ArgTypes.size()-1) - OS << ", "; } OS << ");\n"; @@ -242,7 +410,7 @@ void IntrinsicEmitter::EmitVerifier(const std::vector &Ints, } void IntrinsicEmitter::EmitGenerator(const std::vector &Ints, - std::ostream &OS) { + raw_ostream &OS) { OS << "// Code for generating Intrinsic function declarations.\n"; OS << "#ifdef GET_INTRINSIC_GENERATOR\n"; OS << " switch (id) {\n"; @@ -250,108 +418,229 @@ void IntrinsicEmitter::EmitGenerator(const std::vector &Ints, // Similar to GET_INTRINSIC_VERIFIER, batch up cases that have identical // types. - typedef std::map, std::vector, - RecordListComparator> MapTy; + typedef std::map, 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. + std::string IntrinsicStr = TargetPrefix + "Intrinsic::"; + for (MapTy::iterator I = UniqueArgInfos.begin(), E = UniqueArgInfos.end(); 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"; - } + for (unsigned i = 0, e = I->second.size(); i != e; ++i) + OS << " case " << IntrinsicStr << Ints[I->second[i]].EnumName + << ":\t\t// " << Ints[I->second[i]].Name << "\n"; - const std::vector &ArgTypes = I->first; - unsigned N = ArgTypes.size(); + const RecPair &ArgTypes = I->first; + const std::vector &RetTys = ArgTypes.first; + const std::vector &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"; } -void IntrinsicEmitter::EmitModRefInfo(const std::vector &Ints, - std::ostream &OS) { - OS << "// BasicAliasAnalysis code.\n"; - OS << "#ifdef GET_MODREF_BEHAVIOR\n"; - for (unsigned i = 0, e = Ints.size(); i != e; ++i) { - switch (Ints[i].ModRef) { - default: break; +namespace { + enum ModRefKind { + MRK_none, + MRK_readonly, + MRK_readnone + }; + + ModRefKind getModRefKind(const CodeGenIntrinsic &intrinsic) { + switch (intrinsic.ModRef) { case CodeGenIntrinsic::NoMem: - OS << " NoMemoryIntrinsics->set(Intrinsic::" << Ints[i].EnumName << ");\n"; - break; + return MRK_readnone; case CodeGenIntrinsic::ReadArgMem: case CodeGenIntrinsic::ReadMem: - OS << " OnlyReadsMemoryIntrinsics->set(Intrinsic::" << Ints[i].EnumName << ");\n"; - break; + return MRK_readonly; + case CodeGenIntrinsic::ReadWriteArgMem: + case CodeGenIntrinsic::ReadWriteMem: + return MRK_none; } + assert(0 && "bad mod-ref kind"); + return MRK_none; } - OS << "#endif\n\n"; + + struct AttributeComparator { + bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const { + // Sort throwing intrinsics after non-throwing intrinsics. + if (L->canThrow != R->canThrow) + return R->canThrow; + + // Try to order by readonly/readnone attribute. + ModRefKind LK = getModRefKind(*L); + ModRefKind RK = getModRefKind(*R); + if (LK != RK) return (LK > RK); + + // Order by argument attributes. + // This is reliable because each side is already sorted internally. + return (L->ArgumentAttributes < R->ArgumentAttributes); + } + }; } +/// EmitAttributes - This emits the Intrinsic::getAttributes method. void IntrinsicEmitter:: -EmitNoMemoryInfo(const std::vector &Ints, std::ostream &OS) { - OS << "// SelectionDAGIsel code.\n"; - OS << "#ifdef GET_NO_MEMORY_INTRINSICS\n"; - OS << " switch (IntrinsicID) {\n"; - OS << " default: break;\n"; +EmitAttributes(const std::vector &Ints, raw_ostream &OS) { + OS << "// Add parameter attributes that are not common to all intrinsics.\n"; + OS << "#ifdef GET_INTRINSIC_ATTRIBUTES\n"; + if (TargetOnly) + OS << "static AttrListPtr getAttributes(" << TargetPrefix + << "Intrinsic::ID id) {\n"; + else + OS << "AttrListPtr Intrinsic::getAttributes(ID id) {\n"; + + // Compute the maximum number of attribute arguments. + std::vector sortedIntrinsics(Ints.size()); + unsigned maxArgAttrs = 0; for (unsigned i = 0, e = Ints.size(); i != e; ++i) { - switch (Ints[i].ModRef) { - default: break; - case CodeGenIntrinsic::NoMem: - OS << " case Intrinsic::" << Ints[i].EnumName << ":\n"; - break; + const CodeGenIntrinsic &intrinsic = Ints[i]; + sortedIntrinsics[i] = &intrinsic; + maxArgAttrs = + std::max(maxArgAttrs, unsigned(intrinsic.ArgumentAttributes.size())); + } + + // Emit an array of AttributeWithIndex. Most intrinsics will have + // at least one entry, for the function itself (index ~1), which is + // usually nounwind. + OS << " AttributeWithIndex AWI[" << maxArgAttrs+1 << "];\n"; + OS << " unsigned NumAttrs = 0;\n"; + OS << " switch (id) {\n"; + OS << " default: break;\n"; + + AttributeComparator precedes; + + std::stable_sort(sortedIntrinsics.begin(), sortedIntrinsics.end(), precedes); + + for (unsigned i = 0, e = sortedIntrinsics.size(); i != e; ++i) { + const CodeGenIntrinsic &intrinsic = *sortedIntrinsics[i]; + OS << " case " << TargetPrefix << "Intrinsic::" + << intrinsic.EnumName << ":\n"; + + // Fill out the case if this is the last case for this range of + // intrinsics. + if (i + 1 != e && !precedes(&intrinsic, sortedIntrinsics[i + 1])) + continue; + + // Keep track of the number of attributes we're writing out. + unsigned numAttrs = 0; + + // The argument attributes are alreadys sorted by argument index. + for (unsigned ai = 0, ae = intrinsic.ArgumentAttributes.size(); ai != ae;) { + unsigned argNo = intrinsic.ArgumentAttributes[ai].first; + + OS << " AWI[" << numAttrs++ << "] = AttributeWithIndex::get(" + << argNo+1 << ", "; + + bool moreThanOne = false; + + do { + if (moreThanOne) OS << '|'; + + switch (intrinsic.ArgumentAttributes[ai].second) { + case CodeGenIntrinsic::NoCapture: + OS << "Attribute::NoCapture"; + break; + } + + ++ai; + moreThanOne = true; + } while (ai != ae && intrinsic.ArgumentAttributes[ai].first == argNo); + + OS << ");\n"; + } + + ModRefKind modRef = getModRefKind(intrinsic); + + if (!intrinsic.canThrow || modRef) { + OS << " AWI[" << numAttrs++ << "] = AttributeWithIndex::get(~0, "; + if (!intrinsic.canThrow) { + OS << "Attribute::NoUnwind"; + if (modRef) OS << '|'; + } + switch (modRef) { + case MRK_none: break; + case MRK_readonly: OS << "Attribute::ReadOnly"; break; + case MRK_readnone: OS << "Attribute::ReadNone"; break; + } + OS << ");\n"; + } + + if (numAttrs) { + OS << " NumAttrs = " << numAttrs << ";\n"; + OS << " break;\n"; + } else { + OS << " return AttrListPtr();\n"; } } - OS << " return true; // These intrinsics do not reference memory.\n"; + OS << " }\n"; - OS << "#endif\n\n"; + OS << " return AttrListPtr::get(AWI, NumAttrs);\n"; + OS << "}\n"; + OS << "#endif // GET_INTRINSIC_ATTRIBUTES\n\n"; } +/// EmitModRefBehavior - Determine intrinsic alias analysis mod/ref behavior. void IntrinsicEmitter:: -EmitSideEffectInfo(const std::vector &Ints, std::ostream &OS){ - OS << "// Return true if doesn't access or only reads memory.\n"; - OS << "#ifdef GET_SIDE_EFFECT_INFO\n"; - OS << " switch (IntrinsicID) {\n"; - OS << " default: break;\n"; +EmitModRefBehavior(const std::vector &Ints, raw_ostream &OS){ + OS << "// Determine intrinsic alias analysis mod/ref behavior.\n"; + OS << "#ifdef GET_INTRINSIC_MODREF_BEHAVIOR\n"; + OS << "switch (iid) {\n"; + OS << "default:\n return UnknownModRefBehavior;\n"; for (unsigned i = 0, e = Ints.size(); i != e; ++i) { + if (Ints[i].ModRef == CodeGenIntrinsic::ReadWriteMem) + continue; + OS << "case " << TargetPrefix << "Intrinsic::" << Ints[i].EnumName + << ":\n"; switch (Ints[i].ModRef) { - default: break; + default: + assert(false && "Unknown Mod/Ref type!"); case CodeGenIntrinsic::NoMem: + OS << " return DoesNotAccessMemory;\n"; + break; case CodeGenIntrinsic::ReadArgMem: + OS << " return OnlyReadsArgumentPointees;\n"; + break; case CodeGenIntrinsic::ReadMem: - OS << " case Intrinsic::" << Ints[i].EnumName << ":\n"; + OS << " return OnlyReadsMemory;\n"; + break; + case CodeGenIntrinsic::ReadWriteArgMem: + OS << " return OnlyAccessesArgumentPointees;\n"; break; } } - OS << " return true; // These intrinsics have no side effects.\n"; - OS << " }\n"; - OS << "#endif\n\n"; + OS << "}\n"; + OS << "#endif // GET_INTRINSIC_MODREF_BEHAVIOR\n\n"; } void IntrinsicEmitter:: -EmitGCCBuiltinList(const std::vector &Ints, std::ostream &OS){ +EmitGCCBuiltinList(const std::vector &Ints, raw_ostream &OS){ OS << "// Get the GCC builtin that corresponds to an LLVM intrinsic.\n"; OS << "#ifdef GET_GCC_BUILTIN_NAME\n"; OS << " switch (F->getIntrinsicID()) {\n"; @@ -366,16 +655,37 @@ EmitGCCBuiltinList(const std::vector &Ints, std::ostream &OS){ OS << "#endif\n\n"; } +/// EmitTargetBuiltins - All of the builtins in the specified map are for the +/// same target, and we already checked it. +static void EmitTargetBuiltins(const std::map &BIM, + const std::string &TargetPrefix, + raw_ostream &OS) { + + std::vector Results; + + for (std::map::const_iterator I = BIM.begin(), + E = BIM.end(); I != E; ++I) { + std::string ResultCode = + "return " + TargetPrefix + "Intrinsic::" + I->second + ";"; + Results.push_back(StringMatcher::StringPair(I->first, ResultCode)); + } + + StringMatcher("BuiltinName", Results, OS).Emit(); +} + + void IntrinsicEmitter:: EmitIntrinsicToGCCBuiltinMap(const std::vector &Ints, - std::ostream &OS) { - typedef std::map, std::string> BIMTy; + raw_ostream &OS) { + typedef std::map > BIMTy; BIMTy BuiltinMap; for (unsigned i = 0, e = Ints.size(); i != e; ++i) { if (!Ints[i].GCCBuiltinName.empty()) { - std::pair Key(Ints[i].GCCBuiltinName, - Ints[i].TargetPrefix); - if (!BuiltinMap.insert(std::make_pair(Key, Ints[i].EnumName)).second) + // Get the map for this target prefix. + std::map &BIM =BuiltinMap[Ints[i].TargetPrefix]; + + if (!BIM.insert(std::make_pair(Ints[i].GCCBuiltinName, + Ints[i].EnumName)).second) throw "Intrinsic '" + Ints[i].TheDef->getName() + "': duplicate GCC builtin name!"; } @@ -386,19 +696,36 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector &Ints, OS << "// in as BuiltinName, and a target prefix (e.g. 'ppc') is passed\n"; OS << "// in as TargetPrefix. The result is assigned to 'IntrinsicID'.\n"; OS << "#ifdef GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN\n"; - OS << " if (0);\n"; + + if (TargetOnly) { + OS << "static " << TargetPrefix << "Intrinsic::ID " + << "getIntrinsicForGCCBuiltin(const char " + << "*TargetPrefixStr, const char *BuiltinNameStr) {\n"; + } else { + OS << "Intrinsic::ID Intrinsic::getIntrinsicForGCCBuiltin(const char " + << "*TargetPrefixStr, const char *BuiltinNameStr) {\n"; + } + + OS << " StringRef BuiltinName(BuiltinNameStr);\n"; + OS << " StringRef TargetPrefix(TargetPrefixStr);\n\n"; + // Note: this could emit significantly better code if we cared. for (BIMTy::iterator I = BuiltinMap.begin(), E = BuiltinMap.end();I != E;++I){ - OS << " else if ("; - if (!I->first.second.empty()) { - // Emit this as a strcmp, so it can be constant folded by the FE. - OS << "!strcmp(TargetPrefix, \"" << I->first.second << "\") &&\n" - << " "; - } - OS << "!strcmp(BuiltinName, \"" << I->first.first << "\"))\n"; - OS << " IntrinsicID = Intrinsic::" << I->second << ";\n"; + OS << " "; + if (!I->first.empty()) + OS << "if (TargetPrefix == \"" << I->first << "\") "; + else + OS << "/* Target Independent Builtins */ "; + OS << "{\n"; + + // Emit the comparisons for this target prefix. + EmitTargetBuiltins(I->second, TargetPrefix, OS); + OS << " }\n"; } - OS << " else\n"; - OS << " IntrinsicID = Intrinsic::not_intrinsic;\n"; + OS << " return "; + if (!TargetPrefix.empty()) + OS << "(" << TargetPrefix << "Intrinsic::ID)"; + OS << "Intrinsic::not_intrinsic;\n"; + OS << "}\n"; OS << "#endif\n\n"; }