X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=utils%2FTableGen%2FIntrinsicEmitter.cpp;h=fabb7e7714304c637d94c4d3e603263931f1af83;hb=03507f53c495e5a91e3c83120bdcb5be5d024950;hp=074a8dbfc86bc0d9e9d9c0c18d78d6f653966ab2;hpb=022f64fbbc4669623e79b805379266fed519017d;p=oota-llvm.git diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp index 074a8dbfc86..fabb7e77143 100644 --- a/utils/TableGen/IntrinsicEmitter.cpp +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -14,75 +14,9 @@ #include "IntrinsicEmitter.h" #include "Record.h" #include "llvm/ADT/StringExtras.h" +#include using namespace llvm; -//===----------------------------------------------------------------------===// -// CodeGenIntrinsic Implementation -//===----------------------------------------------------------------------===// - -std::vector llvm::LoadIntrinsics(const RecordKeeper &RC) { - std::vector I = RC.getAllDerivedDefinitions("Intrinsic"); - return std::vector(I.begin(), I.end()); -} - -CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { - std::string DefName = R->getName(); - ModRef = WriteMem; - - if (DefName.size() <= 4 || - std::string(DefName.begin(), DefName.begin()+4) != "int_") - throw "Intrinsic '" + DefName + "' does not start with 'int_'!"; - EnumName = std::string(DefName.begin()+4, DefName.end()); - GCCBuiltinName = R->getValueAsString("GCCBuiltinName"); - - 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]; - } - - // Parse the list of argument types. - ListInit *TypeList = R->getValueAsListInit("Types"); - for (unsigned i = 0, e = TypeList->getSize(); i != e; ++i) { - DefInit *DI = dynamic_cast(TypeList->getElement(i)); - assert(DI && "Invalid list type!"); - Record *TyEl = DI->getDef(); - assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!"); - ArgTypes.push_back(TyEl->getValueAsString("TypeVal")); - ArgTypeDefs.push_back(TyEl); - } - if (ArgTypes.size() == 0) - throw "Intrinsic '"+DefName+"' needs at least a type for the ret value!"; - - // Parse the intrinsic properties. - ListInit *PropList = R->getValueAsListInit("Properties"); - for (unsigned i = 0, e = PropList->getSize(); i != e; ++i) { - DefInit *DI = dynamic_cast(PropList->getElement(i)); - assert(DI && "Invalid list type!"); - Record *Property = DI->getDef(); - assert(Property->isSubClassOf("IntrinsicProperty") && - "Expected a property!"); - - if (Property->getName() == "InstrNoMem") - ModRef = NoMem; - else if (Property->getName() == "InstrReadArgMem") - ModRef = ReadArgMem; - else if (Property->getName() == "IntrReadMem") - ModRef = ReadMem; - else if (Property->getName() == "InstrWriteArgMem") - ModRef = WriteArgMem; - else if (Property->getName() == "IntrWriteMem") - ModRef = WriteMem; - else - assert(0 && "Unknown property!"); - } -} - //===----------------------------------------------------------------------===// // IntrinsicEmitter Implementation //===----------------------------------------------------------------------===// @@ -94,21 +28,30 @@ void IntrinsicEmitter::run(std::ostream &OS) { // Emit the enum information. EmitEnumInfo(Ints, OS); + + // Emit the intrinsic ID -> name table. + EmitIntrinsicToNameTable(Ints, OS); // Emit the function name recognizer. EmitFnNameRecognizer(Ints, OS); - + // Emit the intrinsic verifier. EmitVerifier(Ints, OS); // Emit mod/ref info for each function. EmitModRefInfo(Ints, OS); - // Emit side effect info for each function. + // Emit table of non-memory accessing intrinsics. + EmitNoMemoryInfo(Ints, OS); + + // Emit side effect info for each intrinsic. EmitSideEffectInfo(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); } void IntrinsicEmitter::EmitEnumInfo(const std::vector &Ints, @@ -140,9 +83,6 @@ EmitFnNameRecognizer(const std::vector &Ints, char LastChar = 0; for (std::map::iterator I = IntMapping.begin(), E = IntMapping.end(); I != E; ++I) { - assert(I->first.size() > 5 && std::string(I->first.begin(), - I->first.begin()+5) == "llvm." && - "Invalid intrinsic name!"); if (I->first[5] != LastChar) { LastChar = I->first[5]; OS << " case '" << LastChar << "':\n"; @@ -157,41 +97,77 @@ EmitFnNameRecognizer(const std::vector &Ints, OS << "#endif\n\n"; } -static void EmitTypeVerify(std::ostream &OS, const std::string &Val, - Record *ArgType) { - OS << " Assert1(" << Val << "->getTypeID() == " - << ArgType->getValueAsString("TypeVal") << ",\n" - << " \"Illegal intrinsic type!\", IF);\n"; +void IntrinsicEmitter:: +EmitIntrinsicToNameTable(const std::vector &Ints, + std::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"; + for (unsigned i = 0, e = Ints.size(); i != e; ++i) + OS << " \"" << Ints[i].Name << "\",\n"; + OS << "#endif\n\n"; +} + +static void EmitTypeVerify(std::ostream &OS, Record *ArgType) { + OS << "(int)" << ArgType->getValueAsString("TypeVal") << ", "; // If this is a packed type, check that the subtype and size are correct. if (ArgType->isSubClassOf("LLVMPackedType")) { Record *SubType = ArgType->getValueAsDef("ElTy"); - OS << " Assert1(cast(" << Val - << ")->getElementType()->getTypeID() == " - << SubType->getValueAsString("TypeVal") << ",\n" - << " \"Illegal intrinsic type!\", IF);\n"; - OS << " Assert1(cast(" << Val << ")->getNumElements() == " - << ArgType->getValueAsInt("NumElts") << ",\n" - << " \"Illegal intrinsic type!\", IF);\n"; + OS << "(int)" << SubType->getValueAsString("TypeVal") << ", " + << ArgType->getValueAsInt("NumElts") << ", "; } } +/// RecordListComparator - Provide a determinstic comparator for lists of +/// records. +namespace { + struct RecordListComparator { + bool operator()(const std::vector &LHS, + const std::vector &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(); + } + }; +} + void IntrinsicEmitter::EmitVerifier(const std::vector &Ints, std::ostream &OS) { OS << "// Verifier::visitIntrinsicFunctionCall code.\n"; OS << "#ifdef GET_INTRINSIC_VERIFIER\n"; OS << " switch (ID) {\n"; OS << " default: assert(0 && \"Invalid intrinsic!\");\n"; - for (unsigned i = 0, e = Ints.size(); i != e; ++i) { - OS << " case Intrinsic::" << Ints[i].EnumName << ":\t\t// " - << Ints[i].Name << "\n"; - OS << " Assert1(FTy->getNumParams() == " << Ints[i].ArgTypes.size()-1 - << ",\n" - << " \"Illegal # arguments for intrinsic function!\", IF);\n"; - EmitTypeVerify(OS, "FTy->getReturnType()", Ints[i].ArgTypeDefs[0]); - for (unsigned j = 1; j != Ints[i].ArgTypes.size(); ++j) - EmitTypeVerify(OS, "FTy->getParamType(" + utostr(j-1) + ")", - Ints[i].ArgTypeDefs[j]); + + // 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; + 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); + + // 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) { + OS << " case Intrinsic::" << Ints[I->second[i]].EnumName << ":\t\t// " + << Ints[I->second[i]].Name << "\n"; + } + + const std::vector &ArgTypes = I->first; + OS << " VerifyIntrinsicPrototype(IF, "; + for (unsigned j = 0; j != ArgTypes.size(); ++j) + EmitTypeVerify(OS, ArgTypes[j]); + OS << "-1);\n"; OS << " break;\n"; } OS << " }\n"; @@ -206,22 +182,41 @@ void IntrinsicEmitter::EmitModRefInfo(const std::vector &Ints, switch (Ints[i].ModRef) { default: break; case CodeGenIntrinsic::NoMem: - OS << " NoMemoryTable.push_back(\"" << Ints[i].Name << "\");\n"; + OS << " NoMemoryTable->push_back(\"" << Ints[i].Name << "\");\n"; break; case CodeGenIntrinsic::ReadArgMem: case CodeGenIntrinsic::ReadMem: - OS << " OnlyReadsMemoryTable.push_back(\"" << Ints[i].Name << "\");\n"; + OS << " OnlyReadsMemoryTable->push_back(\"" << Ints[i].Name << "\");\n"; break; } } OS << "#endif\n\n"; } +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"; + 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; + } + } + OS << " return true; // These intrinsics have no side effects.\n"; + OS << " }\n"; + OS << "#endif\n\n"; +} + void IntrinsicEmitter:: EmitSideEffectInfo(const std::vector &Ints, std::ostream &OS){ - OS << "// isInstructionTriviallyDead code.\n"; + OS << "// Return true if doesn't access or only reads memory.\n"; OS << "#ifdef GET_SIDE_EFFECT_INFO\n"; - OS << " switch (F->getIntrinsicID()) {\n"; + OS << " switch (IntrinsicID) {\n"; OS << " default: break;\n"; for (unsigned i = 0, e = Ints.size(); i != e; ++i) { switch (Ints[i].ModRef) { @@ -252,4 +247,41 @@ EmitGCCBuiltinList(const std::vector &Ints, std::ostream &OS){ } OS << " }\n"; OS << "#endif\n\n"; -} \ No newline at end of file +} + +void IntrinsicEmitter:: +EmitIntrinsicToGCCBuiltinMap(const std::vector &Ints, + std::ostream &OS) { + typedef std::map, std::string> 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) + throw "Intrinsic '" + Ints[i].TheDef->getName() + + "': duplicate GCC builtin name!"; + } + } + + OS << "// Get the LLVM intrinsic that corresponds to a GCC builtin.\n"; + OS << "// This is used by the C front-end. The GCC builtin name is passed\n"; + 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"; + // 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 << " else\n"; + OS << " IntrinsicID = Intrinsic::not_intrinsic;\n"; + OS << "#endif\n\n"; +}