[Frontend] Remove unused includes (NFC) (#116927)
[llvm-project.git] / llvm / utils / TableGen / IntrinsicEmitter.cpp
blob070d7522a97be9ff3e9a147082534ad1d2194143
1 //===- IntrinsicEmitter.cpp - Generate intrinsic information --------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This tablegen backend emits information about intrinsic functions.
11 //===----------------------------------------------------------------------===//
13 #include "Basic/CodeGenIntrinsics.h"
14 #include "Basic/SequenceToOffsetTable.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/SmallVector.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/FormatVariadic.h"
22 #include "llvm/Support/ModRef.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include "llvm/TableGen/Error.h"
25 #include "llvm/TableGen/Record.h"
26 #include "llvm/TableGen/StringToOffsetTable.h"
27 #include "llvm/TableGen/TableGenBackend.h"
28 #include <algorithm>
29 #include <array>
30 #include <cassert>
31 #include <cctype>
32 #include <map>
33 #include <optional>
34 #include <string>
35 #include <utility>
36 #include <vector>
37 using namespace llvm;
39 static cl::OptionCategory GenIntrinsicCat("Options for -gen-intrinsic-enums");
40 static cl::opt<std::string>
41 IntrinsicPrefix("intrinsic-prefix",
42 cl::desc("Generate intrinsics with this target prefix"),
43 cl::value_desc("target prefix"), cl::cat(GenIntrinsicCat));
45 namespace {
46 class IntrinsicEmitter {
47 const RecordKeeper &Records;
49 public:
50 IntrinsicEmitter(const RecordKeeper &R) : Records(R) {}
52 void run(raw_ostream &OS, bool Enums);
54 void EmitEnumInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
55 void EmitArgKind(raw_ostream &OS);
56 void EmitIITInfo(raw_ostream &OS);
57 void EmitTargetInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
58 void EmitIntrinsicToNameTable(const CodeGenIntrinsicTable &Ints,
59 raw_ostream &OS);
60 void EmitIntrinsicToOverloadTable(const CodeGenIntrinsicTable &Ints,
61 raw_ostream &OS);
62 void EmitGenerator(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
63 void EmitAttributes(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
64 void EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable &Ints,
65 bool IsClang, raw_ostream &OS);
68 // Helper class to use with `TableGen::Emitter::OptClass`.
69 template <bool Enums> class IntrinsicEmitterOpt : public IntrinsicEmitter {
70 public:
71 IntrinsicEmitterOpt(const RecordKeeper &R) : IntrinsicEmitter(R) {}
72 void run(raw_ostream &OS) { IntrinsicEmitter::run(OS, Enums); }
75 } // End anonymous namespace
77 //===----------------------------------------------------------------------===//
78 // IntrinsicEmitter Implementation
79 //===----------------------------------------------------------------------===//
81 void IntrinsicEmitter::run(raw_ostream &OS, bool Enums) {
82 emitSourceFileHeader("Intrinsic Function Source Fragment", OS);
84 CodeGenIntrinsicTable Ints(Records);
86 if (Enums) {
87 // Emit the enum information.
88 EmitEnumInfo(Ints, OS);
90 // Emit ArgKind for Intrinsics.h.
91 EmitArgKind(OS);
92 } else {
93 // Emit IIT_Info constants.
94 EmitIITInfo(OS);
96 // Emit the target metadata.
97 EmitTargetInfo(Ints, OS);
99 // Emit the intrinsic ID -> name table.
100 EmitIntrinsicToNameTable(Ints, OS);
102 // Emit the intrinsic ID -> overload table.
103 EmitIntrinsicToOverloadTable(Ints, OS);
105 // Emit the intrinsic declaration generator.
106 EmitGenerator(Ints, OS);
108 // Emit the intrinsic parameter attributes.
109 EmitAttributes(Ints, OS);
111 // Emit code to translate Clang builtins into LLVM intrinsics.
112 EmitIntrinsicToBuiltinMap(Ints, true, OS);
114 // Emit code to translate MS builtins into LLVM intrinsics.
115 EmitIntrinsicToBuiltinMap(Ints, false, OS);
119 void IntrinsicEmitter::EmitEnumInfo(const CodeGenIntrinsicTable &Ints,
120 raw_ostream &OS) {
121 // Find the TargetSet for which to generate enums. There will be an initial
122 // set with an empty target prefix which will include target independent
123 // intrinsics like dbg.value.
124 using TargetSet = CodeGenIntrinsicTable::TargetSet;
125 const TargetSet *Set = nullptr;
126 for (const auto &Target : Ints.getTargets()) {
127 if (Target.Name == IntrinsicPrefix) {
128 Set = &Target;
129 break;
132 if (!Set) {
133 // The first entry is for target independent intrinsics, so drop it.
134 auto KnowTargets = Ints.getTargets().drop_front();
135 PrintFatalError([KnowTargets](raw_ostream &OS) {
136 OS << "tried to generate intrinsics for unknown target "
137 << IntrinsicPrefix << "\nKnown targets are: ";
138 interleaveComma(KnowTargets, OS,
139 [&OS](const TargetSet &Target) { OS << Target.Name; });
140 OS << '\n';
144 // Generate a complete header for target specific intrinsics.
145 if (IntrinsicPrefix.empty()) {
146 OS << "#ifdef GET_INTRINSIC_ENUM_VALUES\n";
147 } else {
148 std::string UpperPrefix = StringRef(IntrinsicPrefix).upper();
149 OS << formatv("#ifndef LLVM_IR_INTRINSIC_{}_ENUMS_H\n", UpperPrefix);
150 OS << formatv("#define LLVM_IR_INTRINSIC_{}_ENUMS_H\n", UpperPrefix);
151 OS << "namespace llvm::Intrinsic {\n";
152 OS << formatv("enum {}Intrinsics : unsigned {{\n", UpperPrefix);
155 OS << "// Enum values for intrinsics.\n";
156 bool First = true;
157 for (const auto &Int : Ints[*Set]) {
158 OS << " " << Int.EnumName;
160 // Assign a value to the first intrinsic in this target set so that all
161 // intrinsic ids are distinct.
162 if (First) {
163 OS << " = " << Set->Offset + 1;
164 First = false;
167 OS << ", ";
168 if (Int.EnumName.size() < 40)
169 OS.indent(40 - Int.EnumName.size());
170 OS << formatv(" // {}\n", Int.Name);
173 // Emit num_intrinsics into the target neutral enum.
174 if (IntrinsicPrefix.empty()) {
175 OS << formatv(" num_intrinsics = {}\n", Ints.size() + 1);
176 OS << "#endif\n\n";
177 } else {
178 OS << R"(}; // enum
179 } // namespace llvm::Intrinsic
180 #endif
186 void IntrinsicEmitter::EmitArgKind(raw_ostream &OS) {
187 if (!IntrinsicPrefix.empty())
188 return;
189 OS << "// llvm::Intrinsic::IITDescriptor::ArgKind.\n";
190 OS << "#ifdef GET_INTRINSIC_ARGKIND\n";
191 if (const auto RecArgKind = Records.getDef("ArgKind")) {
192 for (const auto &RV : RecArgKind->getValues())
193 OS << " AK_" << RV.getName() << " = " << *RV.getValue() << ",\n";
194 } else {
195 OS << "#error \"ArgKind is not defined\"\n";
197 OS << "#endif\n\n";
200 void IntrinsicEmitter::EmitIITInfo(raw_ostream &OS) {
201 OS << "#ifdef GET_INTRINSIC_IITINFO\n";
202 std::array<StringRef, 256> RecsByNumber;
203 auto IIT_Base = Records.getAllDerivedDefinitionsIfDefined("IIT_Base");
204 for (const Record *Rec : IIT_Base) {
205 auto Number = Rec->getValueAsInt("Number");
206 assert(0 <= Number && Number < (int)RecsByNumber.size() &&
207 "IIT_Info.Number should be uint8_t");
208 assert(RecsByNumber[Number].empty() && "Duplicate IIT_Info.Number");
209 RecsByNumber[Number] = Rec->getName();
211 if (IIT_Base.size() > 0) {
212 for (unsigned I = 0, E = RecsByNumber.size(); I < E; ++I)
213 if (!RecsByNumber[I].empty())
214 OS << " " << RecsByNumber[I] << " = " << I << ",\n";
215 } else {
216 OS << "#error \"class IIT_Base is not defined\"\n";
218 OS << "#endif\n\n";
221 void IntrinsicEmitter::EmitTargetInfo(const CodeGenIntrinsicTable &Ints,
222 raw_ostream &OS) {
223 OS << R"(// Target mapping.
224 #ifdef GET_INTRINSIC_TARGET_DATA
225 struct IntrinsicTargetInfo {
226 StringLiteral Name;
227 size_t Offset;
228 size_t Count;
230 static constexpr IntrinsicTargetInfo TargetInfos[] = {
232 for (const auto [Name, Offset, Count] : Ints.getTargets())
233 OS << formatv(" {{\"{}\", {}, {}},\n", Name, Offset, Count);
234 OS << R"(};
235 #endif
240 void IntrinsicEmitter::EmitIntrinsicToNameTable(
241 const CodeGenIntrinsicTable &Ints, raw_ostream &OS) {
242 OS << R"(// Intrinsic ID to name table.
243 #ifdef GET_INTRINSIC_NAME_TABLE
244 // Note that entry #0 is the invalid intrinsic!
246 for (const auto &Int : Ints)
247 OS << " \"" << Int.Name << "\",\n";
248 OS << "#endif\n\n";
251 void IntrinsicEmitter::EmitIntrinsicToOverloadTable(
252 const CodeGenIntrinsicTable &Ints, raw_ostream &OS) {
253 OS << R"(// Intrinsic ID to overload bitset.
254 #ifdef GET_INTRINSIC_OVERLOAD_TABLE
255 static constexpr uint8_t OTable[] = {
258 for (auto [I, Int] : enumerate(Ints)) {
259 // Add one to the index so we emit a null bit for the invalid #0 intrinsic.
260 size_t Idx = I + 1;
262 if (Idx % 8 == 0)
263 OS << ",\n 0";
264 if (Int.isOverloaded)
265 OS << " | (1<<" << Idx % 8 << ')';
267 OS << "\n};\n\n";
268 // OTable contains a true bit at the position if the intrinsic is overloaded.
269 OS << "return (OTable[id/8] & (1 << (id%8))) != 0;\n";
270 OS << "#endif\n\n";
273 using TypeSigTy = SmallVector<unsigned char>;
275 /// Computes type signature of the intrinsic \p Int.
276 static TypeSigTy ComputeTypeSignature(const CodeGenIntrinsic &Int) {
277 TypeSigTy TypeSig;
278 const Record *TypeInfo = Int.TheDef->getValueAsDef("TypeInfo");
279 const ListInit *TypeList = TypeInfo->getValueAsListInit("TypeSig");
281 for (const auto *TypeListEntry : TypeList->getValues())
282 TypeSig.emplace_back(cast<IntInit>(TypeListEntry)->getValue());
283 return TypeSig;
286 // Pack the type signature into 32-bit fixed encoding word.
287 static std::optional<uint32_t> encodePacked(const TypeSigTy &TypeSig) {
288 if (TypeSig.size() > 8)
289 return std::nullopt;
291 uint32_t Result = 0;
292 for (unsigned char C : reverse(TypeSig)) {
293 if (C > 15)
294 return std::nullopt;
295 Result = (Result << 4) | C;
297 return Result;
300 void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints,
301 raw_ostream &OS) {
302 // Note: the code below can be switched to use 32-bit fixed encoding by
303 // flipping the flag below.
304 constexpr bool Use16BitFixedEncoding = true;
305 using FixedEncodingTy =
306 std::conditional_t<Use16BitFixedEncoding, uint16_t, uint32_t>;
307 constexpr unsigned FixedEncodingBits = sizeof(FixedEncodingTy) * CHAR_BIT;
308 // Mask with all bits 1 except the most significant bit.
309 const unsigned Mask = (1U << (FixedEncodingBits - 1)) - 1;
310 const unsigned MSBPostion = FixedEncodingBits - 1;
311 StringRef FixedEncodingTypeName =
312 Use16BitFixedEncoding ? "uint16_t" : "uint32_t";
314 // If we can compute a 16/32-bit fixed encoding for this intrinsic, do so and
315 // capture it in this vector, otherwise store a ~0U.
316 std::vector<FixedEncodingTy> FixedEncodings;
317 SequenceToOffsetTable<TypeSigTy> LongEncodingTable;
319 FixedEncodings.reserve(Ints.size());
321 // Compute the unique argument type info.
322 for (const CodeGenIntrinsic &Int : Ints) {
323 // Get the signature for the intrinsic.
324 TypeSigTy TypeSig = ComputeTypeSignature(Int);
326 // Check to see if we can encode it into a 16/32 bit word.
327 std::optional<uint32_t> Result = encodePacked(TypeSig);
328 if (Result && (*Result & Mask) == Result) {
329 FixedEncodings.push_back(static_cast<FixedEncodingTy>(*Result));
330 continue;
333 LongEncodingTable.add(TypeSig);
335 // This is a placehold that we'll replace after the table is laid out.
336 FixedEncodings.push_back(static_cast<FixedEncodingTy>(~0U));
339 LongEncodingTable.layout();
341 OS << formatv(R"(// Global intrinsic function declaration type table.
342 #ifdef GET_INTRINSIC_GENERATOR_GLOBAL
343 static constexpr {} IIT_Table[] = {{
345 FixedEncodingTypeName);
347 unsigned MaxOffset = 0;
348 for (auto [Idx, FixedEncoding, Int] : enumerate(FixedEncodings, Ints)) {
349 if ((Idx & 7) == 7)
350 OS << "\n ";
352 // If the entry fit in the table, just emit it.
353 if ((FixedEncoding & Mask) == FixedEncoding) {
354 OS << "0x" << Twine::utohexstr(FixedEncoding) << ", ";
355 continue;
358 TypeSigTy TypeSig = ComputeTypeSignature(Int);
359 unsigned Offset = LongEncodingTable.get(TypeSig);
360 MaxOffset = std::max(MaxOffset, Offset);
362 // Otherwise, emit the offset into the long encoding table. We emit it this
363 // way so that it is easier to read the offset in the .def file.
364 OS << formatv("(1U<<{}) | {}, ", MSBPostion, Offset);
367 OS << "0\n};\n\n";
369 // verify that all offsets will fit in 16/32 bits.
370 if ((MaxOffset & Mask) != MaxOffset)
371 PrintFatalError("Offset of long encoding table exceeds encoding bits");
373 // Emit the shared table of register lists.
374 OS << "static constexpr unsigned char IIT_LongEncodingTable[] = {\n";
375 if (!LongEncodingTable.empty())
376 LongEncodingTable.emit(
377 OS, [](raw_ostream &OS, unsigned char C) { OS << (unsigned)C; });
378 OS << " 255\n};\n";
379 OS << "#endif\n\n"; // End of GET_INTRINSIC_GENERATOR_GLOBAL
382 /// Returns the effective MemoryEffects for intrinsic \p Int.
383 static MemoryEffects getEffectiveME(const CodeGenIntrinsic &Int) {
384 MemoryEffects ME = Int.ME;
385 // TODO: IntrHasSideEffects should affect not only readnone intrinsics.
386 if (ME.doesNotAccessMemory() && Int.hasSideEffects)
387 ME = MemoryEffects::unknown();
388 return ME;
391 static bool compareFnAttributes(const CodeGenIntrinsic *L,
392 const CodeGenIntrinsic *R) {
393 auto TieBoolAttributes = [](const CodeGenIntrinsic *I) -> auto {
394 // Sort throwing intrinsics after non-throwing intrinsics.
395 return std::tie(I->canThrow, I->isNoDuplicate, I->isNoMerge, I->isNoReturn,
396 I->isNoCallback, I->isNoSync, I->isNoFree, I->isWillReturn,
397 I->isCold, I->isConvergent, I->isSpeculatable,
398 I->hasSideEffects, I->isStrictFP);
401 auto TieL = TieBoolAttributes(L);
402 auto TieR = TieBoolAttributes(R);
404 if (TieL != TieR)
405 return TieL < TieR;
407 // Try to order by readonly/readnone attribute.
408 uint32_t LME = getEffectiveME(*L).toIntValue();
409 uint32_t RME = getEffectiveME(*R).toIntValue();
410 if (LME != RME)
411 return LME > RME;
413 return false;
416 /// Returns true if \p Int has a non-empty set of function attributes. Note that
417 /// NoUnwind = !canThrow, so we need to negate it's sense to test if the
418 // intrinsic has NoUnwind attribute.
419 static bool hasFnAttributes(const CodeGenIntrinsic &Int) {
420 return !Int.canThrow || Int.isNoReturn || Int.isNoCallback || Int.isNoSync ||
421 Int.isNoFree || Int.isWillReturn || Int.isCold || Int.isNoDuplicate ||
422 Int.isNoMerge || Int.isConvergent || Int.isSpeculatable ||
423 Int.isStrictFP || getEffectiveME(Int) != MemoryEffects::unknown();
426 namespace {
427 struct FnAttributeComparator {
428 bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
429 return compareFnAttributes(L, R);
433 struct AttributeComparator {
434 bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
435 // Order all intrinsics with no functiona attributes before all intrinsics
436 // with function attributes.
437 bool HasFnAttrLHS = hasFnAttributes(*L);
438 bool HasFnAttrRHS = hasFnAttributes(*R);
440 // Order by argument attributes if function `hasFnAttributes` is equal.
441 // This is reliable because each side is already sorted internally.
442 return std::tie(HasFnAttrLHS, L->ArgumentAttributes) <
443 std::tie(HasFnAttrRHS, R->ArgumentAttributes);
446 } // End anonymous namespace
448 /// Returns the name of the IR enum for argument attribute kind \p Kind.
449 static StringRef getArgAttrEnumName(CodeGenIntrinsic::ArgAttrKind Kind) {
450 switch (Kind) {
451 case CodeGenIntrinsic::NoCapture:
452 return "NoCapture";
453 case CodeGenIntrinsic::NoAlias:
454 return "NoAlias";
455 case CodeGenIntrinsic::NoUndef:
456 return "NoUndef";
457 case CodeGenIntrinsic::NonNull:
458 return "NonNull";
459 case CodeGenIntrinsic::Returned:
460 return "Returned";
461 case CodeGenIntrinsic::ReadOnly:
462 return "ReadOnly";
463 case CodeGenIntrinsic::WriteOnly:
464 return "WriteOnly";
465 case CodeGenIntrinsic::ReadNone:
466 return "ReadNone";
467 case CodeGenIntrinsic::ImmArg:
468 return "ImmArg";
469 case CodeGenIntrinsic::Alignment:
470 return "Alignment";
471 case CodeGenIntrinsic::Dereferenceable:
472 return "Dereferenceable";
474 llvm_unreachable("Unknown CodeGenIntrinsic::ArgAttrKind enum");
477 /// EmitAttributes - This emits the Intrinsic::getAttributes method.
478 void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
479 raw_ostream &OS) {
480 OS << R"(// Add parameter attributes that are not common to all intrinsics.
481 #ifdef GET_INTRINSIC_ATTRIBUTES
482 static AttributeSet getIntrinsicArgAttributeSet(LLVMContext &C, unsigned ID) {
483 switch (ID) {
484 default: llvm_unreachable("Invalid attribute set number");)";
485 // Compute unique argument attribute sets.
486 std::map<SmallVector<CodeGenIntrinsic::ArgAttribute, 0>, unsigned>
487 UniqArgAttributes;
488 for (const CodeGenIntrinsic &Int : Ints) {
489 for (auto &Attrs : Int.ArgumentAttributes) {
490 if (Attrs.empty())
491 continue;
493 unsigned ID = UniqArgAttributes.size();
494 if (!UniqArgAttributes.try_emplace(Attrs, ID).second)
495 continue;
497 assert(is_sorted(Attrs) && "Argument attributes are not sorted");
499 OS << formatv(R"(
500 case {}:
501 return AttributeSet::get(C, {{
503 ID);
504 for (const CodeGenIntrinsic::ArgAttribute &Attr : Attrs) {
505 StringRef AttrName = getArgAttrEnumName(Attr.Kind);
506 if (Attr.Kind == CodeGenIntrinsic::Alignment ||
507 Attr.Kind == CodeGenIntrinsic::Dereferenceable)
508 OS << formatv(" Attribute::get(C, Attribute::{}, {}),\n",
509 AttrName, Attr.Value);
510 else
511 OS << formatv(" Attribute::get(C, Attribute::{}),\n", AttrName);
513 OS << " });";
516 OS << R"(
518 } // getIntrinsicArgAttributeSet
521 // Compute unique function attribute sets.
522 std::map<const CodeGenIntrinsic *, unsigned, FnAttributeComparator>
523 UniqFnAttributes;
524 OS << R"(
525 static AttributeSet getIntrinsicFnAttributeSet(LLVMContext &C, unsigned ID) {
526 switch (ID) {
527 default: llvm_unreachable("Invalid attribute set number");)";
529 for (const CodeGenIntrinsic &Int : Ints) {
530 if (!hasFnAttributes(Int))
531 continue;
532 unsigned ID = UniqFnAttributes.size();
533 if (!UniqFnAttributes.try_emplace(&Int, ID).second)
534 continue;
535 OS << formatv(R"(
536 case {}:
537 return AttributeSet::get(C, {{
539 ID);
540 auto addAttribute = [&OS](StringRef Attr) {
541 OS << formatv(" Attribute::get(C, Attribute::{}),\n", Attr);
543 if (!Int.canThrow)
544 addAttribute("NoUnwind");
545 if (Int.isNoReturn)
546 addAttribute("NoReturn");
547 if (Int.isNoCallback)
548 addAttribute("NoCallback");
549 if (Int.isNoSync)
550 addAttribute("NoSync");
551 if (Int.isNoFree)
552 addAttribute("NoFree");
553 if (Int.isWillReturn)
554 addAttribute("WillReturn");
555 if (Int.isCold)
556 addAttribute("Cold");
557 if (Int.isNoDuplicate)
558 addAttribute("NoDuplicate");
559 if (Int.isNoMerge)
560 addAttribute("NoMerge");
561 if (Int.isConvergent)
562 addAttribute("Convergent");
563 if (Int.isSpeculatable)
564 addAttribute("Speculatable");
565 if (Int.isStrictFP)
566 addAttribute("StrictFP");
568 const MemoryEffects ME = getEffectiveME(Int);
569 if (ME != MemoryEffects::unknown()) {
570 OS << formatv(" // {}\n", ME);
571 OS << formatv(" Attribute::getWithMemoryEffects(C, "
572 "MemoryEffects::createFromIntValue({})),\n",
573 ME.toIntValue());
575 OS << " });";
577 OS << R"(
579 } // getIntrinsicFnAttributeSet
581 AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id) {
584 // Compute the maximum number of attribute arguments and the map. For function
585 // attributes, we only consider whether the intrinsics has any function
586 // arguments or not.
587 std::map<const CodeGenIntrinsic *, unsigned, AttributeComparator>
588 UniqAttributes;
589 for (const CodeGenIntrinsic &Int : Ints) {
590 unsigned ID = UniqAttributes.size();
591 UniqAttributes.try_emplace(&Int, ID);
594 // Assign a 16-bit packed ID for each intrinsic. The lower 8-bits will be its
595 // "argument attribute ID" (index in UniqAttributes) and upper 8 bits will be
596 // its "function attribute ID" (index in UniqFnAttributes).
597 if (UniqAttributes.size() > 256)
598 PrintFatalError("Too many unique argument attributes for table!");
599 if (UniqFnAttributes.size() > 256)
600 PrintFatalError("Too many unique function attributes for table!");
602 // Emit an array of AttributeList. Most intrinsics will have at least one
603 // entry, for the function itself (index ~1), which is usually nounwind.
604 OS << " static constexpr uint16_t IntrinsicsToAttributesMap[] = {";
605 for (const CodeGenIntrinsic &Int : Ints) {
606 uint16_t FnAttrIndex = hasFnAttributes(Int) ? UniqFnAttributes[&Int] : 0;
607 OS << formatv("\n {} << 8 | {}, // {}", FnAttrIndex,
608 UniqAttributes[&Int], Int.Name);
611 OS << formatv(R"(
613 if (id == 0)
614 return AttributeList();
616 uint16_t PackedID = IntrinsicsToAttributesMap[id - 1];
617 uint8_t FnAttrID = PackedID >> 8;
618 switch(PackedID & 0xFF) {{
619 default: llvm_unreachable("Invalid attribute number");
620 )");
622 for (const auto [IntPtr, UniqueID] : UniqAttributes) {
623 OS << formatv(" case {}:\n", UniqueID);
624 const CodeGenIntrinsic &Int = *IntPtr;
626 // Keep track of the number of attributes we're writing out.
627 unsigned NumAttrs =
628 llvm::count_if(Int.ArgumentAttributes,
629 [](const auto &Attrs) { return !Attrs.empty(); });
630 NumAttrs += hasFnAttributes(Int);
631 if (NumAttrs == 0) {
632 OS << " return AttributeList();\n";
633 continue;
636 OS << " return AttributeList::get(C, {\n";
637 ListSeparator LS(",\n");
638 for (const auto &[AttrIdx, Attrs] : enumerate(Int.ArgumentAttributes)) {
639 if (Attrs.empty())
640 continue;
642 unsigned ArgAttrID = UniqArgAttributes.find(Attrs)->second;
643 OS << LS
644 << formatv(" {{{}, getIntrinsicArgAttributeSet(C, {})}", AttrIdx,
645 ArgAttrID);
648 if (hasFnAttributes(Int)) {
649 OS << LS
650 << " {AttributeList::FunctionIndex, "
651 "getIntrinsicFnAttributeSet(C, FnAttrID)}";
653 OS << "\n });\n";
656 OS << R"( }
658 #endif // GET_INTRINSIC_ATTRIBUTES
663 void IntrinsicEmitter::EmitIntrinsicToBuiltinMap(
664 const CodeGenIntrinsicTable &Ints, bool IsClang, raw_ostream &OS) {
665 StringRef CompilerName = IsClang ? "Clang" : "MS";
666 StringRef UpperCompilerName = IsClang ? "CLANG" : "MS";
668 // map<TargetPrefix, pair<map<BuiltinName, EnumName>, CommonPrefix>.
669 // Note that we iterate over both the maps in the code below and both
670 // iterations need to iterate in sorted key order. For the inner map, entries
671 // need to be emitted in the sorted order of `BuiltinName` with `CommonPrefix`
672 // rempved, because we use std::lower_bound to search these entries. For the
673 // outer map as well, entries need to be emitted in sorter order of
674 // `TargetPrefix` as we use std::lower_bound to search these entries.
675 using BIMEntryTy =
676 std::pair<std::map<StringRef, StringRef>, std::optional<StringRef>>;
677 std::map<StringRef, BIMEntryTy> BuiltinMap;
679 for (const CodeGenIntrinsic &Int : Ints) {
680 StringRef BuiltinName = IsClang ? Int.ClangBuiltinName : Int.MSBuiltinName;
681 if (BuiltinName.empty())
682 continue;
683 // Get the map for this target prefix.
684 auto &[Map, CommonPrefix] = BuiltinMap[Int.TargetPrefix];
686 if (!Map.insert({BuiltinName, Int.EnumName}).second)
687 PrintFatalError(Int.TheDef->getLoc(),
688 "Intrinsic '" + Int.TheDef->getName() + "': duplicate " +
689 CompilerName + " builtin name!");
691 // Update common prefix.
692 if (!CommonPrefix) {
693 // For the first builtin for this target, initialize the common prefix.
694 CommonPrefix = BuiltinName;
695 continue;
698 // Update the common prefix. Note that this assumes that `take_front` will
699 // never set the `Data` pointer in CommonPrefix to nullptr.
700 const char *Mismatch = mismatch(*CommonPrefix, BuiltinName).first;
701 *CommonPrefix = CommonPrefix->take_front(Mismatch - CommonPrefix->begin());
704 // Populate the string table with the names of all the builtins after
705 // removing this common prefix.
706 StringToOffsetTable Table;
707 for (const auto &[TargetPrefix, Entry] : BuiltinMap) {
708 auto &[Map, CommonPrefix] = Entry;
709 for (auto &[BuiltinName, EnumName] : Map) {
710 StringRef Suffix = BuiltinName.substr(CommonPrefix->size());
711 Table.GetOrAddStringOffset(Suffix);
715 OS << formatv(R"(
716 // Get the LLVM intrinsic that corresponds to a builtin. This is used by the
717 // C front-end. The builtin name is passed in as BuiltinName, and a target
718 // prefix (e.g. 'ppc') is passed in as TargetPrefix.
719 #ifdef GET_LLVM_INTRINSIC_FOR_{}_BUILTIN
720 Intrinsic::ID
721 Intrinsic::getIntrinsicFor{}Builtin(StringRef TargetPrefix,
722 StringRef BuiltinName) {{
723 using namespace Intrinsic;
725 UpperCompilerName, CompilerName);
727 if (BuiltinMap.empty()) {
728 OS << formatv(R"(
729 return not_intrinsic;
731 #endif // GET_LLVM_INTRINSIC_FOR_{}_BUILTIN
733 UpperCompilerName);
734 return;
737 if (!Table.empty()) {
738 Table.EmitStringLiteralDef(OS, "static constexpr char BuiltinNames[]");
740 OS << R"(
741 struct BuiltinEntry {
742 ID IntrinsicID;
743 unsigned StrTabOffset;
744 const char *getName() const { return &BuiltinNames[StrTabOffset]; }
745 bool operator<(StringRef RHS) const {
746 return strncmp(getName(), RHS.data(), RHS.size()) < 0;
753 // Emit a per target table of bultin names.
754 bool HasTargetIndependentBuiltins = false;
755 StringRef TargetIndepndentCommonPrefix;
756 for (const auto &[TargetPrefix, Entry] : BuiltinMap) {
757 const auto &[Map, CommonPrefix] = Entry;
758 if (!TargetPrefix.empty()) {
759 OS << formatv(" // Builtins for {0}.\n", TargetPrefix);
760 } else {
761 OS << " // Target independent builtins.\n";
762 HasTargetIndependentBuiltins = true;
763 TargetIndepndentCommonPrefix = *CommonPrefix;
766 // Emit the builtin table for this target prefix.
767 OS << formatv(" static constexpr BuiltinEntry {}Names[] = {{\n",
768 TargetPrefix);
769 for (const auto &[BuiltinName, EnumName] : Map) {
770 StringRef Suffix = BuiltinName.substr(CommonPrefix->size());
771 OS << formatv(" {{{}, {}}, // {}\n", EnumName,
772 *Table.GetStringOffset(Suffix), BuiltinName);
774 OS << formatv(" }; // {}Names\n\n", TargetPrefix);
777 // After emitting the builtin tables for all targets, emit a lookup table for
778 // all targets. We will use binary search, similar to the table for builtin
779 // names to lookup into this table.
780 OS << R"(
781 struct TargetEntry {
782 StringLiteral TargetPrefix;
783 ArrayRef<BuiltinEntry> Names;
784 StringLiteral CommonPrefix;
785 bool operator<(StringRef RHS) const {
786 return TargetPrefix < RHS;
789 static constexpr TargetEntry TargetTable[] = {
792 for (const auto &[TargetPrefix, Entry] : BuiltinMap) {
793 const auto &[Map, CommonPrefix] = Entry;
794 if (TargetPrefix.empty())
795 continue;
796 OS << formatv(R"( {{"{0}", {0}Names, "{1}"},)", TargetPrefix,
797 CommonPrefix)
798 << "\n";
800 OS << " };\n";
802 // Now for the actual lookup, first check the target independent table if
803 // we emitted one.
804 if (HasTargetIndependentBuiltins) {
805 OS << formatv(R"(
806 // Check if it's a target independent builtin.
807 // Copy the builtin name so we can use it in consume_front without clobbering
808 // if for the lookup in the target specific table.
809 StringRef Suffix = BuiltinName;
810 if (Suffix.consume_front("{}")) {{
811 auto II = lower_bound(Names, Suffix);
812 if (II != std::end(Names) && II->getName() == Suffix)
813 return II->IntrinsicID;
816 TargetIndepndentCommonPrefix);
819 // If a target independent builtin was not found, lookup the target specific.
820 OS << formatv(R"(
821 auto TI = lower_bound(TargetTable, TargetPrefix);
822 if (TI == std::end(TargetTable) || TI->TargetPrefix != TargetPrefix)
823 return not_intrinsic;
824 // This is the last use of BuiltinName, so no need to copy before using it in
825 // consume_front.
826 if (!BuiltinName.consume_front(TI->CommonPrefix))
827 return not_intrinsic;
828 auto II = lower_bound(TI->Names, BuiltinName);
829 if (II == std::end(TI->Names) || II->getName() != BuiltinName)
830 return not_intrinsic;
831 return II->IntrinsicID;
833 #endif // GET_LLVM_INTRINSIC_FOR_{}_BUILTIN
836 UpperCompilerName);
839 static TableGen::Emitter::OptClass<IntrinsicEmitterOpt</*Enums=*/true>>
840 X("gen-intrinsic-enums", "Generate intrinsic enums");
842 static TableGen::Emitter::OptClass<IntrinsicEmitterOpt</*Enums=*/false>>
843 Y("gen-intrinsic-impl", "Generate intrinsic implementation code");