Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/IntrinsicEmitter.cpp
35258 views
//===- IntrinsicEmitter.cpp - Generate intrinsic information --------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This tablegen backend emits information about intrinsic functions.9//10//===----------------------------------------------------------------------===//1112#include "Basic/CodeGenIntrinsics.h"13#include "Basic/SequenceToOffsetTable.h"14#include "llvm/ADT/STLExtras.h"15#include "llvm/ADT/SmallVector.h"16#include "llvm/ADT/StringExtras.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/ADT/Twine.h"19#include "llvm/Support/CommandLine.h"20#include "llvm/Support/ErrorHandling.h"21#include "llvm/Support/ModRef.h"22#include "llvm/Support/raw_ostream.h"23#include "llvm/TableGen/Error.h"24#include "llvm/TableGen/Record.h"25#include "llvm/TableGen/StringToOffsetTable.h"26#include "llvm/TableGen/TableGenBackend.h"27#include <algorithm>28#include <array>29#include <cassert>30#include <map>31#include <optional>32#include <string>33#include <utility>34#include <vector>35using namespace llvm;3637cl::OptionCategory GenIntrinsicCat("Options for -gen-intrinsic-enums");38cl::opt<std::string>39IntrinsicPrefix("intrinsic-prefix",40cl::desc("Generate intrinsics with this target prefix"),41cl::value_desc("target prefix"), cl::cat(GenIntrinsicCat));4243namespace {44class IntrinsicEmitter {45RecordKeeper &Records;4647public:48IntrinsicEmitter(RecordKeeper &R) : Records(R) {}4950void run(raw_ostream &OS, bool Enums);5152void EmitEnumInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);53void EmitArgKind(raw_ostream &OS);54void EmitIITInfo(raw_ostream &OS);55void EmitTargetInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);56void EmitIntrinsicToNameTable(const CodeGenIntrinsicTable &Ints,57raw_ostream &OS);58void EmitIntrinsicToOverloadTable(const CodeGenIntrinsicTable &Ints,59raw_ostream &OS);60void EmitGenerator(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);61void EmitAttributes(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);62void EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable &Ints,63bool IsClang, raw_ostream &OS);64};65} // End anonymous namespace6667//===----------------------------------------------------------------------===//68// IntrinsicEmitter Implementation69//===----------------------------------------------------------------------===//7071void IntrinsicEmitter::run(raw_ostream &OS, bool Enums) {72emitSourceFileHeader("Intrinsic Function Source Fragment", OS);7374CodeGenIntrinsicTable Ints(Records);7576if (Enums) {77// Emit the enum information.78EmitEnumInfo(Ints, OS);7980// Emit ArgKind for Intrinsics.h.81EmitArgKind(OS);82} else {83// Emit IIT_Info constants.84EmitIITInfo(OS);8586// Emit the target metadata.87EmitTargetInfo(Ints, OS);8889// Emit the intrinsic ID -> name table.90EmitIntrinsicToNameTable(Ints, OS);9192// Emit the intrinsic ID -> overload table.93EmitIntrinsicToOverloadTable(Ints, OS);9495// Emit the intrinsic declaration generator.96EmitGenerator(Ints, OS);9798// Emit the intrinsic parameter attributes.99EmitAttributes(Ints, OS);100101// Emit code to translate GCC builtins into LLVM intrinsics.102EmitIntrinsicToBuiltinMap(Ints, true, OS);103104// Emit code to translate MS builtins into LLVM intrinsics.105EmitIntrinsicToBuiltinMap(Ints, false, OS);106}107}108109void IntrinsicEmitter::EmitEnumInfo(const CodeGenIntrinsicTable &Ints,110raw_ostream &OS) {111// Find the TargetSet for which to generate enums. There will be an initial112// set with an empty target prefix which will include target independent113// intrinsics like dbg.value.114const CodeGenIntrinsicTable::TargetSet *Set = nullptr;115for (const auto &Target : Ints.Targets) {116if (Target.Name == IntrinsicPrefix) {117Set = &Target;118break;119}120}121if (!Set) {122std::vector<std::string> KnownTargets;123for (const auto &Target : Ints.Targets)124if (!Target.Name.empty())125KnownTargets.push_back(Target.Name);126PrintFatalError("tried to generate intrinsics for unknown target " +127IntrinsicPrefix +128"\nKnown targets are: " + join(KnownTargets, ", ") + "\n");129}130131// Generate a complete header for target specific intrinsics.132if (IntrinsicPrefix.empty()) {133OS << "#ifdef GET_INTRINSIC_ENUM_VALUES\n";134} else {135std::string UpperPrefix = StringRef(IntrinsicPrefix).upper();136OS << "#ifndef LLVM_IR_INTRINSIC_" << UpperPrefix << "_ENUMS_H\n";137OS << "#define LLVM_IR_INTRINSIC_" << UpperPrefix << "_ENUMS_H\n\n";138OS << "namespace llvm {\n";139OS << "namespace Intrinsic {\n";140OS << "enum " << UpperPrefix << "Intrinsics : unsigned {\n";141}142143OS << "// Enum values for intrinsics\n";144for (unsigned i = Set->Offset, e = Set->Offset + Set->Count; i != e; ++i) {145OS << " " << Ints[i].EnumName;146147// Assign a value to the first intrinsic in this target set so that all148// intrinsic ids are distinct.149if (i == Set->Offset)150OS << " = " << (Set->Offset + 1);151152OS << ", ";153if (Ints[i].EnumName.size() < 40)154OS.indent(40 - Ints[i].EnumName.size());155OS << " // " << Ints[i].Name << "\n";156}157158// Emit num_intrinsics into the target neutral enum.159if (IntrinsicPrefix.empty()) {160OS << " num_intrinsics = " << (Ints.size() + 1) << "\n";161OS << "#endif\n\n";162} else {163OS << "}; // enum\n";164OS << "} // namespace Intrinsic\n";165OS << "} // namespace llvm\n\n";166OS << "#endif\n";167}168}169170void IntrinsicEmitter::EmitArgKind(raw_ostream &OS) {171if (!IntrinsicPrefix.empty())172return;173OS << "// llvm::Intrinsic::IITDescriptor::ArgKind\n";174OS << "#ifdef GET_INTRINSIC_ARGKIND\n";175if (auto RecArgKind = Records.getDef("ArgKind")) {176for (auto &RV : RecArgKind->getValues())177OS << " AK_" << RV.getName() << " = " << *RV.getValue() << ",\n";178} else {179OS << "#error \"ArgKind is not defined\"\n";180}181OS << "#endif\n\n";182}183184void IntrinsicEmitter::EmitIITInfo(raw_ostream &OS) {185OS << "#ifdef GET_INTRINSIC_IITINFO\n";186std::array<StringRef, 256> RecsByNumber;187auto IIT_Base = Records.getAllDerivedDefinitionsIfDefined("IIT_Base");188for (auto Rec : IIT_Base) {189auto Number = Rec->getValueAsInt("Number");190assert(0 <= Number && Number < (int)RecsByNumber.size() &&191"IIT_Info.Number should be uint8_t");192assert(RecsByNumber[Number].empty() && "Duplicate IIT_Info.Number");193RecsByNumber[Number] = Rec->getName();194}195if (IIT_Base.size() > 0) {196for (unsigned I = 0, E = RecsByNumber.size(); I < E; ++I)197if (!RecsByNumber[I].empty())198OS << " " << RecsByNumber[I] << " = " << I << ",\n";199} else {200OS << "#error \"class IIT_Base is not defined\"\n";201}202OS << "#endif\n\n";203}204205void IntrinsicEmitter::EmitTargetInfo(const CodeGenIntrinsicTable &Ints,206raw_ostream &OS) {207OS << "// Target mapping\n";208OS << "#ifdef GET_INTRINSIC_TARGET_DATA\n";209OS << "struct IntrinsicTargetInfo {\n"210<< " llvm::StringLiteral Name;\n"211<< " size_t Offset;\n"212<< " size_t Count;\n"213<< "};\n";214OS << "static constexpr IntrinsicTargetInfo TargetInfos[] = {\n";215for (const auto &Target : Ints.Targets)216OS << " {llvm::StringLiteral(\"" << Target.Name << "\"), " << Target.Offset217<< ", " << Target.Count << "},\n";218OS << "};\n";219OS << "#endif\n\n";220}221222void IntrinsicEmitter::EmitIntrinsicToNameTable(223const CodeGenIntrinsicTable &Ints, raw_ostream &OS) {224OS << "// Intrinsic ID to name table\n";225OS << "#ifdef GET_INTRINSIC_NAME_TABLE\n";226OS << " // Note that entry #0 is the invalid intrinsic!\n";227for (unsigned i = 0, e = Ints.size(); i != e; ++i)228OS << " \"" << Ints[i].Name << "\",\n";229OS << "#endif\n\n";230}231232void IntrinsicEmitter::EmitIntrinsicToOverloadTable(233const CodeGenIntrinsicTable &Ints, raw_ostream &OS) {234OS << "// Intrinsic ID to overload bitset\n";235OS << "#ifdef GET_INTRINSIC_OVERLOAD_TABLE\n";236OS << "static const uint8_t OTable[] = {\n";237OS << " 0";238for (unsigned i = 0, e = Ints.size(); i != e; ++i) {239// Add one to the index so we emit a null bit for the invalid #0 intrinsic.240if ((i + 1) % 8 == 0)241OS << ",\n 0";242if (Ints[i].isOverloaded)243OS << " | (1<<" << (i + 1) % 8 << ')';244}245OS << "\n};\n\n";246// OTable contains a true bit at the position if the intrinsic is overloaded.247OS << "return (OTable[id/8] & (1 << (id%8))) != 0;\n";248OS << "#endif\n\n";249}250251/// ComputeFixedEncoding - If we can encode the type signature for this252/// intrinsic into 32 bits, return it. If not, return ~0U.253static void ComputeFixedEncoding(const CodeGenIntrinsic &Int,254std::vector<unsigned char> &TypeSig) {255if (auto *R = Int.TheDef->getValue("TypeSig")) {256for (auto &a : cast<ListInit>(R->getValue())->getValues()) {257for (auto &b : cast<ListInit>(a)->getValues())258TypeSig.push_back(cast<IntInit>(b)->getValue());259}260}261}262263static void printIITEntry(raw_ostream &OS, unsigned char X) {264OS << (unsigned)X;265}266267void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints,268raw_ostream &OS) {269// If we can compute a 32-bit fixed encoding for this intrinsic, do so and270// capture it in this vector, otherwise store a ~0U.271std::vector<unsigned> FixedEncodings;272273SequenceToOffsetTable<std::vector<unsigned char>> LongEncodingTable;274275std::vector<unsigned char> TypeSig;276277// Compute the unique argument type info.278for (unsigned i = 0, e = Ints.size(); i != e; ++i) {279// Get the signature for the intrinsic.280TypeSig.clear();281ComputeFixedEncoding(Ints[i], TypeSig);282283// Check to see if we can encode it into a 32-bit word. We can only encode284// 8 nibbles into a 32-bit word.285if (TypeSig.size() <= 8) {286bool Failed = false;287unsigned Result = 0;288for (unsigned i = 0, e = TypeSig.size(); i != e; ++i) {289// If we had an unencodable argument, bail out.290if (TypeSig[i] > 15) {291Failed = true;292break;293}294Result = (Result << 4) | TypeSig[e - i - 1];295}296297// If this could be encoded into a 31-bit word, return it.298if (!Failed && (Result >> 31) == 0) {299FixedEncodings.push_back(Result);300continue;301}302}303304// Otherwise, we're going to unique the sequence into the305// LongEncodingTable, and use its offset in the 32-bit table instead.306LongEncodingTable.add(TypeSig);307308// This is a placehold that we'll replace after the table is laid out.309FixedEncodings.push_back(~0U);310}311312LongEncodingTable.layout();313314OS << "// Global intrinsic function declaration type table.\n";315OS << "#ifdef GET_INTRINSIC_GENERATOR_GLOBAL\n";316317OS << "static const unsigned IIT_Table[] = {\n ";318319for (unsigned i = 0, e = FixedEncodings.size(); i != e; ++i) {320if ((i & 7) == 7)321OS << "\n ";322323// If the entry fit in the table, just emit it.324if (FixedEncodings[i] != ~0U) {325OS << "0x" << Twine::utohexstr(FixedEncodings[i]) << ", ";326continue;327}328329TypeSig.clear();330ComputeFixedEncoding(Ints[i], TypeSig);331332// Otherwise, emit the offset into the long encoding table. We emit it this333// way so that it is easier to read the offset in the .def file.334OS << "(1U<<31) | " << LongEncodingTable.get(TypeSig) << ", ";335}336337OS << "0\n};\n\n";338339// Emit the shared table of register lists.340OS << "static const unsigned char IIT_LongEncodingTable[] = {\n";341if (!LongEncodingTable.empty())342LongEncodingTable.emit(OS, printIITEntry);343OS << " 255\n};\n\n";344345OS << "#endif\n\n"; // End of GET_INTRINSIC_GENERATOR_GLOBAL346}347348namespace {349std::optional<bool> compareFnAttributes(const CodeGenIntrinsic *L,350const CodeGenIntrinsic *R) {351// Sort throwing intrinsics after non-throwing intrinsics.352if (L->canThrow != R->canThrow)353return R->canThrow;354355if (L->isNoDuplicate != R->isNoDuplicate)356return R->isNoDuplicate;357358if (L->isNoMerge != R->isNoMerge)359return R->isNoMerge;360361if (L->isNoReturn != R->isNoReturn)362return R->isNoReturn;363364if (L->isNoCallback != R->isNoCallback)365return R->isNoCallback;366367if (L->isNoSync != R->isNoSync)368return R->isNoSync;369370if (L->isNoFree != R->isNoFree)371return R->isNoFree;372373if (L->isWillReturn != R->isWillReturn)374return R->isWillReturn;375376if (L->isCold != R->isCold)377return R->isCold;378379if (L->isConvergent != R->isConvergent)380return R->isConvergent;381382if (L->isSpeculatable != R->isSpeculatable)383return R->isSpeculatable;384385if (L->hasSideEffects != R->hasSideEffects)386return R->hasSideEffects;387388if (L->isStrictFP != R->isStrictFP)389return R->isStrictFP;390391// Try to order by readonly/readnone attribute.392uint32_t LK = L->ME.toIntValue();393uint32_t RK = R->ME.toIntValue();394if (LK != RK)395return (LK > RK);396397return std::nullopt;398}399400struct FnAttributeComparator {401bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {402return compareFnAttributes(L, R).value_or(false);403}404};405406struct AttributeComparator {407bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {408if (std::optional<bool> Res = compareFnAttributes(L, R))409return *Res;410411// Order by argument attributes.412// This is reliable because each side is already sorted internally.413return (L->ArgumentAttributes < R->ArgumentAttributes);414}415};416} // End anonymous namespace417418/// EmitAttributes - This emits the Intrinsic::getAttributes method.419void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,420raw_ostream &OS) {421OS << "// Add parameter attributes that are not common to all intrinsics.\n";422OS << "#ifdef GET_INTRINSIC_ATTRIBUTES\n";423424// Compute unique argument attribute sets.425std::map<SmallVector<CodeGenIntrinsic::ArgAttribute, 0>, unsigned>426UniqArgAttributes;427OS << "static AttributeSet getIntrinsicArgAttributeSet("428<< "LLVMContext &C, unsigned ID) {\n"429<< " switch (ID) {\n"430<< " default: llvm_unreachable(\"Invalid attribute set number\");\n";431for (const CodeGenIntrinsic &Int : Ints) {432for (auto &Attrs : Int.ArgumentAttributes) {433if (Attrs.empty())434continue;435436unsigned ID = UniqArgAttributes.size();437if (!UniqArgAttributes.try_emplace(Attrs, ID).second)438continue;439440assert(is_sorted(Attrs) && "Argument attributes are not sorted");441442OS << " case " << ID << ":\n";443OS << " return AttributeSet::get(C, {\n";444for (const CodeGenIntrinsic::ArgAttribute &Attr : Attrs) {445switch (Attr.Kind) {446case CodeGenIntrinsic::NoCapture:447OS << " Attribute::get(C, Attribute::NoCapture),\n";448break;449case CodeGenIntrinsic::NoAlias:450OS << " Attribute::get(C, Attribute::NoAlias),\n";451break;452case CodeGenIntrinsic::NoUndef:453OS << " Attribute::get(C, Attribute::NoUndef),\n";454break;455case CodeGenIntrinsic::NonNull:456OS << " Attribute::get(C, Attribute::NonNull),\n";457break;458case CodeGenIntrinsic::Returned:459OS << " Attribute::get(C, Attribute::Returned),\n";460break;461case CodeGenIntrinsic::ReadOnly:462OS << " Attribute::get(C, Attribute::ReadOnly),\n";463break;464case CodeGenIntrinsic::WriteOnly:465OS << " Attribute::get(C, Attribute::WriteOnly),\n";466break;467case CodeGenIntrinsic::ReadNone:468OS << " Attribute::get(C, Attribute::ReadNone),\n";469break;470case CodeGenIntrinsic::ImmArg:471OS << " Attribute::get(C, Attribute::ImmArg),\n";472break;473case CodeGenIntrinsic::Alignment:474OS << " Attribute::get(C, Attribute::Alignment, " << Attr.Value475<< "),\n";476break;477case CodeGenIntrinsic::Dereferenceable:478OS << " Attribute::get(C, Attribute::Dereferenceable, "479<< Attr.Value << "),\n";480break;481}482}483OS << " });\n";484}485}486OS << " }\n";487OS << "}\n\n";488489// Compute unique function attribute sets.490std::map<const CodeGenIntrinsic *, unsigned, FnAttributeComparator>491UniqFnAttributes;492OS << "static AttributeSet getIntrinsicFnAttributeSet("493<< "LLVMContext &C, unsigned ID) {\n"494<< " switch (ID) {\n"495<< " default: llvm_unreachable(\"Invalid attribute set number\");\n";496for (const CodeGenIntrinsic &Intrinsic : Ints) {497unsigned ID = UniqFnAttributes.size();498if (!UniqFnAttributes.try_emplace(&Intrinsic, ID).second)499continue;500501OS << " case " << ID << ":\n"502<< " return AttributeSet::get(C, {\n";503if (!Intrinsic.canThrow)504OS << " Attribute::get(C, Attribute::NoUnwind),\n";505if (Intrinsic.isNoReturn)506OS << " Attribute::get(C, Attribute::NoReturn),\n";507if (Intrinsic.isNoCallback)508OS << " Attribute::get(C, Attribute::NoCallback),\n";509if (Intrinsic.isNoSync)510OS << " Attribute::get(C, Attribute::NoSync),\n";511if (Intrinsic.isNoFree)512OS << " Attribute::get(C, Attribute::NoFree),\n";513if (Intrinsic.isWillReturn)514OS << " Attribute::get(C, Attribute::WillReturn),\n";515if (Intrinsic.isCold)516OS << " Attribute::get(C, Attribute::Cold),\n";517if (Intrinsic.isNoDuplicate)518OS << " Attribute::get(C, Attribute::NoDuplicate),\n";519if (Intrinsic.isNoMerge)520OS << " Attribute::get(C, Attribute::NoMerge),\n";521if (Intrinsic.isConvergent)522OS << " Attribute::get(C, Attribute::Convergent),\n";523if (Intrinsic.isSpeculatable)524OS << " Attribute::get(C, Attribute::Speculatable),\n";525if (Intrinsic.isStrictFP)526OS << " Attribute::get(C, Attribute::StrictFP),\n";527528MemoryEffects ME = Intrinsic.ME;529// TODO: IntrHasSideEffects should affect not only readnone intrinsics.530if (ME.doesNotAccessMemory() && Intrinsic.hasSideEffects)531ME = MemoryEffects::unknown();532if (ME != MemoryEffects::unknown()) {533OS << " Attribute::getWithMemoryEffects(C, "534<< "MemoryEffects::createFromIntValue(" << ME.toIntValue() << ")),\n";535}536OS << " });\n";537}538OS << " }\n";539OS << "}\n\n";540OS << "AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id) {\n";541542// Compute the maximum number of attribute arguments and the map543typedef std::map<const CodeGenIntrinsic *, unsigned, AttributeComparator>544UniqAttrMapTy;545UniqAttrMapTy UniqAttributes;546unsigned maxArgAttrs = 0;547unsigned AttrNum = 0;548for (unsigned i = 0, e = Ints.size(); i != e; ++i) {549const CodeGenIntrinsic &intrinsic = Ints[i];550maxArgAttrs =551std::max(maxArgAttrs, unsigned(intrinsic.ArgumentAttributes.size()));552unsigned &N = UniqAttributes[&intrinsic];553if (N)554continue;555N = ++AttrNum;556assert(N < 65536 && "Too many unique attributes for table!");557}558559// Emit an array of AttributeList. Most intrinsics will have at least one560// entry, for the function itself (index ~1), which is usually nounwind.561OS << " static const uint16_t IntrinsicsToAttributesMap[] = {\n";562563for (unsigned i = 0, e = Ints.size(); i != e; ++i) {564const CodeGenIntrinsic &intrinsic = Ints[i];565566OS << " " << UniqAttributes[&intrinsic] << ", // " << intrinsic.Name567<< "\n";568}569OS << " };\n\n";570571OS << " std::pair<unsigned, AttributeSet> AS[" << maxArgAttrs + 1 << "];\n";572OS << " unsigned NumAttrs = 0;\n";573OS << " if (id != 0) {\n";574OS << " switch(IntrinsicsToAttributesMap[id - 1]) {\n";575OS << " default: llvm_unreachable(\"Invalid attribute number\");\n";576for (auto UniqAttribute : UniqAttributes) {577OS << " case " << UniqAttribute.second << ": {\n";578579const CodeGenIntrinsic &Intrinsic = *(UniqAttribute.first);580581// Keep track of the number of attributes we're writing out.582unsigned numAttrs = 0;583584for (const auto &[AttrIdx, Attrs] :585enumerate(Intrinsic.ArgumentAttributes)) {586if (Attrs.empty())587continue;588589unsigned ID = UniqArgAttributes.find(Attrs)->second;590OS << " AS[" << numAttrs++ << "] = {" << AttrIdx591<< ", getIntrinsicArgAttributeSet(C, " << ID << ")};\n";592}593594if (!Intrinsic.canThrow ||595(Intrinsic.ME != MemoryEffects::unknown() &&596!Intrinsic.hasSideEffects) ||597Intrinsic.isNoReturn || Intrinsic.isNoCallback || Intrinsic.isNoSync ||598Intrinsic.isNoFree || Intrinsic.isWillReturn || Intrinsic.isCold ||599Intrinsic.isNoDuplicate || Intrinsic.isNoMerge ||600Intrinsic.isConvergent || Intrinsic.isSpeculatable ||601Intrinsic.isStrictFP) {602unsigned ID = UniqFnAttributes.find(&Intrinsic)->second;603OS << " AS[" << numAttrs++ << "] = {AttributeList::FunctionIndex, "604<< "getIntrinsicFnAttributeSet(C, " << ID << ")};\n";605}606607if (numAttrs) {608OS << " NumAttrs = " << numAttrs << ";\n";609OS << " break;\n";610OS << " }\n";611} else {612OS << " return AttributeList();\n";613OS << " }\n";614}615}616617OS << " }\n";618OS << " }\n";619OS << " return AttributeList::get(C, ArrayRef(AS, NumAttrs));\n";620OS << "}\n";621OS << "#endif // GET_INTRINSIC_ATTRIBUTES\n\n";622}623624void IntrinsicEmitter::EmitIntrinsicToBuiltinMap(625const CodeGenIntrinsicTable &Ints, bool IsClang, raw_ostream &OS) {626StringRef CompilerName = (IsClang ? "Clang" : "MS");627StringRef UpperCompilerName = (IsClang ? "CLANG" : "MS");628typedef std::map<std::string, std::map<std::string, std::string>> BIMTy;629BIMTy BuiltinMap;630StringToOffsetTable Table;631for (unsigned i = 0, e = Ints.size(); i != e; ++i) {632const std::string &BuiltinName =633IsClang ? Ints[i].ClangBuiltinName : Ints[i].MSBuiltinName;634if (!BuiltinName.empty()) {635// Get the map for this target prefix.636std::map<std::string, std::string> &BIM =637BuiltinMap[Ints[i].TargetPrefix];638639if (!BIM.insert(std::pair(BuiltinName, Ints[i].EnumName)).second)640PrintFatalError(Ints[i].TheDef->getLoc(),641"Intrinsic '" + Ints[i].TheDef->getName() +642"': duplicate " + CompilerName + " builtin name!");643Table.GetOrAddStringOffset(BuiltinName);644}645}646647OS << "// Get the LLVM intrinsic that corresponds to a builtin.\n";648OS << "// This is used by the C front-end. The builtin name is passed\n";649OS << "// in as BuiltinName, and a target prefix (e.g. 'ppc') is passed\n";650OS << "// in as TargetPrefix. The result is assigned to 'IntrinsicID'.\n";651OS << "#ifdef GET_LLVM_INTRINSIC_FOR_" << UpperCompilerName << "_BUILTIN\n";652653OS << "Intrinsic::ID Intrinsic::getIntrinsicFor" << CompilerName654<< "Builtin(const char "655<< "*TargetPrefixStr, StringRef BuiltinNameStr) {\n";656657if (Table.Empty()) {658OS << " return Intrinsic::not_intrinsic;\n";659OS << "}\n";660OS << "#endif\n\n";661return;662}663664OS << " static const char BuiltinNames[] = {\n";665Table.EmitCharArray(OS);666OS << " };\n\n";667668OS << " struct BuiltinEntry {\n";669OS << " Intrinsic::ID IntrinID;\n";670OS << " unsigned StrTabOffset;\n";671OS << " const char *getName() const {\n";672OS << " return &BuiltinNames[StrTabOffset];\n";673OS << " }\n";674OS << " bool operator<(StringRef RHS) const {\n";675OS << " return strncmp(getName(), RHS.data(), RHS.size()) < 0;\n";676OS << " }\n";677OS << " };\n";678679OS << " StringRef TargetPrefix(TargetPrefixStr);\n\n";680681// Note: this could emit significantly better code if we cared.682for (auto &I : BuiltinMap) {683OS << " ";684if (!I.first.empty())685OS << "if (TargetPrefix == \"" << I.first << "\") ";686else687OS << "/* Target Independent Builtins */ ";688OS << "{\n";689690// Emit the comparisons for this target prefix.691OS << " static const BuiltinEntry " << I.first << "Names[] = {\n";692for (const auto &P : I.second) {693OS << " {Intrinsic::" << P.second << ", "694<< Table.GetOrAddStringOffset(P.first) << "}, // " << P.first << "\n";695}696OS << " };\n";697OS << " auto I = std::lower_bound(std::begin(" << I.first << "Names),\n";698OS << " std::end(" << I.first << "Names),\n";699OS << " BuiltinNameStr);\n";700OS << " if (I != std::end(" << I.first << "Names) &&\n";701OS << " I->getName() == BuiltinNameStr)\n";702OS << " return I->IntrinID;\n";703OS << " }\n";704}705OS << " return ";706OS << "Intrinsic::not_intrinsic;\n";707OS << "}\n";708OS << "#endif\n\n";709}710711static void EmitIntrinsicEnums(RecordKeeper &RK, raw_ostream &OS) {712IntrinsicEmitter(RK).run(OS, /*Enums=*/true);713}714715static TableGen::Emitter::Opt X("gen-intrinsic-enums", EmitIntrinsicEnums,716"Generate intrinsic enums");717718static void EmitIntrinsicImpl(RecordKeeper &RK, raw_ostream &OS) {719IntrinsicEmitter(RK).run(OS, /*Enums=*/false);720}721722static TableGen::Emitter::Opt Y("gen-intrinsic-impl", EmitIntrinsicImpl,723"Generate intrinsic information");724725726