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. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "CodeGenIntrinsics.h" |
14 | #include "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; |
38 | |
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)); |
44 | |
45 | namespace { |
46 | class IntrinsicEmitter { |
47 | const RecordKeeper &Records; |
48 | |
49 | public: |
50 | IntrinsicEmitter(const RecordKeeper &R) : Records(R) {} |
51 | |
52 | void run(raw_ostream &OS, bool Enums); |
53 | |
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); |
66 | }; |
67 | |
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); } |
73 | }; |
74 | |
75 | } // End anonymous namespace |
76 | |
77 | //===----------------------------------------------------------------------===// |
78 | // IntrinsicEmitter Implementation |
79 | //===----------------------------------------------------------------------===// |
80 | |
81 | void IntrinsicEmitter::run(raw_ostream &OS, bool Enums) { |
82 | emitSourceFileHeader(Desc: "Intrinsic Function Source Fragment" , OS); |
83 | |
84 | CodeGenIntrinsicTable Ints(Records); |
85 | |
86 | if (Enums) { |
87 | // Emit the enum information. |
88 | EmitEnumInfo(Ints, OS); |
89 | |
90 | // Emit ArgKind for Intrinsics.h. |
91 | EmitArgKind(OS); |
92 | } else { |
93 | // Emit IIT_Info constants. |
94 | EmitIITInfo(OS); |
95 | |
96 | // Emit the target metadata. |
97 | EmitTargetInfo(Ints, OS); |
98 | |
99 | // Emit the intrinsic ID -> name table. |
100 | EmitIntrinsicToNameTable(Ints, OS); |
101 | |
102 | // Emit the intrinsic ID -> overload table. |
103 | EmitIntrinsicToOverloadTable(Ints, OS); |
104 | |
105 | // Emit the intrinsic declaration generator. |
106 | EmitGenerator(Ints, OS); |
107 | |
108 | // Emit the intrinsic parameter attributes. |
109 | EmitAttributes(Ints, OS); |
110 | |
111 | // Emit code to translate Clang builtins into LLVM intrinsics. |
112 | EmitIntrinsicToBuiltinMap(Ints, IsClang: true, OS); |
113 | |
114 | // Emit code to translate MS builtins into LLVM intrinsics. |
115 | EmitIntrinsicToBuiltinMap(Ints, IsClang: false, OS); |
116 | } |
117 | } |
118 | |
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; |
130 | } |
131 | } |
132 | if (!Set) { |
133 | // The first entry is for target independent intrinsics, so drop it. |
134 | auto KnowTargets = Ints.getTargets().drop_front(); |
135 | PrintFatalError(PrintMsg: [KnowTargets](raw_ostream &OS) { |
136 | OS << "tried to generate intrinsics for unknown target " |
137 | << IntrinsicPrefix << "\nKnown targets are: " ; |
138 | interleaveComma(c: KnowTargets, os&: OS, |
139 | each_fn: [&OS](const TargetSet &Target) { OS << Target.Name; }); |
140 | OS << '\n'; |
141 | }); |
142 | } |
143 | |
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(Fmt: "#ifndef LLVM_IR_INTRINSIC_{}_ENUMS_H\n" , Vals&: UpperPrefix); |
150 | OS << formatv(Fmt: "#define LLVM_IR_INTRINSIC_{}_ENUMS_H\n" , Vals&: UpperPrefix); |
151 | OS << "namespace llvm::Intrinsic {\n" ; |
152 | OS << formatv(Fmt: "enum {}Intrinsics : unsigned {{\n" , Vals&: UpperPrefix); |
153 | } |
154 | |
155 | OS << "// Enum values for intrinsics.\n" ; |
156 | bool First = true; |
157 | for (const auto &Int : Ints[*Set]) { |
158 | OS << " " << Int.EnumName; |
159 | |
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; |
165 | } |
166 | |
167 | OS << ", " ; |
168 | if (Int.EnumName.size() < 40) |
169 | OS.indent(NumSpaces: 40 - Int.EnumName.size()); |
170 | OS << formatv(Fmt: " // {}\n" , Vals: Int.Name); |
171 | } |
172 | |
173 | // Emit num_intrinsics into the target neutral enum. |
174 | if (IntrinsicPrefix.empty()) { |
175 | OS << formatv(Fmt: " num_intrinsics = {}\n" , Vals: Ints.size() + 1); |
176 | OS << "#endif\n\n" ; |
177 | } else { |
178 | OS << R"(}; // enum |
179 | } // namespace llvm::Intrinsic |
180 | #endif |
181 | |
182 | )" ; |
183 | } |
184 | } |
185 | |
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(Name: "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" ; |
196 | } |
197 | OS << "#endif\n\n" ; |
198 | } |
199 | |
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(ClassName: "IIT_Base" ); |
204 | for (const Record *Rec : IIT_Base) { |
205 | auto Number = Rec->getValueAsInt(FieldName: "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(); |
210 | } |
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" ; |
217 | } |
218 | OS << "#endif\n\n" ; |
219 | } |
220 | |
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; |
229 | }; |
230 | static constexpr IntrinsicTargetInfo TargetInfos[] = { |
231 | )" ; |
232 | for (const auto [Name, Offset, Count] : Ints.getTargets()) |
233 | OS << formatv(Fmt: " {{\"{}\", {}, {}},\n" , Vals: Name, Vals: Offset, Vals: Count); |
234 | OS << R"(}; |
235 | #endif |
236 | |
237 | )" ; |
238 | } |
239 | |
240 | void IntrinsicEmitter::EmitIntrinsicToNameTable( |
241 | const CodeGenIntrinsicTable &Ints, raw_ostream &OS) { |
242 | // Built up a table of the intrinsic names. |
243 | constexpr StringLiteral NotIntrinsic = "not_intrinsic" ; |
244 | StringToOffsetTable Table; |
245 | Table.GetOrAddStringOffset(Str: NotIntrinsic); |
246 | for (const auto &Int : Ints) |
247 | Table.GetOrAddStringOffset(Str: Int.Name); |
248 | |
249 | OS << R"(// Intrinsic ID to name table. |
250 | #ifdef GET_INTRINSIC_NAME_TABLE |
251 | // Note that entry #0 is the invalid intrinsic! |
252 | |
253 | )" ; |
254 | |
255 | Table.EmitStringTableDef(OS, Name: "IntrinsicNameTable" , /*Indent=*/"" ); |
256 | |
257 | OS << R"( |
258 | static constexpr unsigned IntrinsicNameOffsetTable[] = { |
259 | )" ; |
260 | |
261 | OS << formatv(Fmt: " {}, // {}\n" , Vals: Table.GetStringOffset(Str: NotIntrinsic), |
262 | Vals: NotIntrinsic); |
263 | for (const auto &Int : Ints) |
264 | OS << formatv(Fmt: " {}, // {}\n" , Vals: Table.GetStringOffset(Str: Int.Name), Vals: Int.Name); |
265 | |
266 | OS << R"( |
267 | }; // IntrinsicNameOffsetTable |
268 | |
269 | #endif |
270 | |
271 | )" ; |
272 | } |
273 | |
274 | void IntrinsicEmitter::EmitIntrinsicToOverloadTable( |
275 | const CodeGenIntrinsicTable &Ints, raw_ostream &OS) { |
276 | OS << R"(// Intrinsic ID to overload bitset. |
277 | #ifdef GET_INTRINSIC_OVERLOAD_TABLE |
278 | static constexpr uint8_t OTable[] = { |
279 | 0 |
280 | )" ; |
281 | for (auto [I, Int] : enumerate(First: Ints)) { |
282 | // Add one to the index so we emit a null bit for the invalid #0 intrinsic. |
283 | size_t Idx = I + 1; |
284 | |
285 | if (Idx % 8 == 0) |
286 | OS << ",\n 0" ; |
287 | if (Int.isOverloaded) |
288 | OS << " | (1<<" << Idx % 8 << ')'; |
289 | } |
290 | OS << "\n};\n\n" ; |
291 | // OTable contains a true bit at the position if the intrinsic is overloaded. |
292 | OS << "return (OTable[id/8] & (1 << (id%8))) != 0;\n" ; |
293 | OS << "#endif\n\n" ; |
294 | } |
295 | |
296 | using TypeSigTy = SmallVector<unsigned char>; |
297 | |
298 | /// Computes type signature of the intrinsic \p Int. |
299 | static TypeSigTy ComputeTypeSignature(const CodeGenIntrinsic &Int) { |
300 | TypeSigTy TypeSig; |
301 | const Record *TypeInfo = Int.TheDef->getValueAsDef(FieldName: "TypeInfo" ); |
302 | const ListInit *TypeList = TypeInfo->getValueAsListInit(FieldName: "TypeSig" ); |
303 | |
304 | for (const auto *TypeListEntry : TypeList->getElements()) |
305 | TypeSig.emplace_back(Args: cast<IntInit>(Val: TypeListEntry)->getValue()); |
306 | return TypeSig; |
307 | } |
308 | |
309 | // Pack the type signature into 32-bit fixed encoding word. |
310 | static std::optional<uint32_t> encodePacked(const TypeSigTy &TypeSig) { |
311 | if (TypeSig.size() > 8) |
312 | return std::nullopt; |
313 | |
314 | uint32_t Result = 0; |
315 | for (unsigned char C : reverse(C: TypeSig)) { |
316 | if (C > 15) |
317 | return std::nullopt; |
318 | Result = (Result << 4) | C; |
319 | } |
320 | return Result; |
321 | } |
322 | |
323 | void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints, |
324 | raw_ostream &OS) { |
325 | // Note: the code below can be switched to use 32-bit fixed encoding by |
326 | // flipping the flag below. |
327 | constexpr bool Use16BitFixedEncoding = true; |
328 | using FixedEncodingTy = |
329 | std::conditional_t<Use16BitFixedEncoding, uint16_t, uint32_t>; |
330 | constexpr unsigned FixedEncodingBits = sizeof(FixedEncodingTy) * CHAR_BIT; |
331 | // Mask with all bits 1 except the most significant bit. |
332 | const unsigned Mask = (1U << (FixedEncodingBits - 1)) - 1; |
333 | const unsigned MSBPostion = FixedEncodingBits - 1; |
334 | StringRef FixedEncodingTypeName = |
335 | Use16BitFixedEncoding ? "uint16_t" : "uint32_t" ; |
336 | |
337 | // If we can compute a 16/32-bit fixed encoding for this intrinsic, do so and |
338 | // capture it in this vector, otherwise store a ~0U. |
339 | std::vector<FixedEncodingTy> FixedEncodings; |
340 | SequenceToOffsetTable<TypeSigTy> LongEncodingTable; |
341 | |
342 | FixedEncodings.reserve(n: Ints.size()); |
343 | |
344 | // Compute the unique argument type info. |
345 | for (const CodeGenIntrinsic &Int : Ints) { |
346 | // Get the signature for the intrinsic. |
347 | TypeSigTy TypeSig = ComputeTypeSignature(Int); |
348 | |
349 | // Check to see if we can encode it into a 16/32 bit word. |
350 | std::optional<uint32_t> Result = encodePacked(TypeSig); |
351 | if (Result && (*Result & Mask) == Result) { |
352 | FixedEncodings.push_back(x: static_cast<FixedEncodingTy>(*Result)); |
353 | continue; |
354 | } |
355 | |
356 | LongEncodingTable.add(Seq: TypeSig); |
357 | |
358 | // This is a placehold that we'll replace after the table is laid out. |
359 | FixedEncodings.push_back(x: static_cast<FixedEncodingTy>(~0U)); |
360 | } |
361 | |
362 | LongEncodingTable.layout(); |
363 | |
364 | OS << formatv(Fmt: R"(// Global intrinsic function declaration type table. |
365 | #ifdef GET_INTRINSIC_GENERATOR_GLOBAL |
366 | static constexpr {} IIT_Table[] = {{ |
367 | )" , |
368 | Vals&: FixedEncodingTypeName); |
369 | |
370 | unsigned MaxOffset = 0; |
371 | for (auto [Idx, FixedEncoding, Int] : enumerate(First&: FixedEncodings, Rest: Ints)) { |
372 | if ((Idx & 7) == 7) |
373 | OS << "\n " ; |
374 | |
375 | // If the entry fit in the table, just emit it. |
376 | if ((FixedEncoding & Mask) == FixedEncoding) { |
377 | OS << "0x" << Twine::utohexstr(Val: FixedEncoding) << ", " ; |
378 | continue; |
379 | } |
380 | |
381 | TypeSigTy TypeSig = ComputeTypeSignature(Int); |
382 | unsigned Offset = LongEncodingTable.get(Seq: TypeSig); |
383 | MaxOffset = std::max(a: MaxOffset, b: Offset); |
384 | |
385 | // Otherwise, emit the offset into the long encoding table. We emit it this |
386 | // way so that it is easier to read the offset in the .def file. |
387 | OS << formatv(Fmt: "(1U<<{}) | {}, " , Vals: MSBPostion, Vals&: Offset); |
388 | } |
389 | |
390 | OS << "0\n};\n\n" ; |
391 | |
392 | // verify that all offsets will fit in 16/32 bits. |
393 | if ((MaxOffset & Mask) != MaxOffset) |
394 | PrintFatalError(Msg: "Offset of long encoding table exceeds encoding bits" ); |
395 | |
396 | // Emit the shared table of register lists. |
397 | OS << "static constexpr unsigned char IIT_LongEncodingTable[] = {\n" ; |
398 | if (!LongEncodingTable.empty()) |
399 | LongEncodingTable.emit( |
400 | OS, Print: [](raw_ostream &OS, unsigned char C) { OS << (unsigned)C; }); |
401 | OS << " 255\n};\n" ; |
402 | OS << "#endif\n\n" ; // End of GET_INTRINSIC_GENERATOR_GLOBAL |
403 | } |
404 | |
405 | /// Returns the effective MemoryEffects for intrinsic \p Int. |
406 | static MemoryEffects getEffectiveME(const CodeGenIntrinsic &Int) { |
407 | MemoryEffects ME = Int.ME; |
408 | // TODO: IntrHasSideEffects should affect not only readnone intrinsics. |
409 | if (ME.doesNotAccessMemory() && Int.hasSideEffects) |
410 | ME = MemoryEffects::unknown(); |
411 | return ME; |
412 | } |
413 | |
414 | static bool compareFnAttributes(const CodeGenIntrinsic *L, |
415 | const CodeGenIntrinsic *R) { |
416 | auto TieBoolAttributes = [](const CodeGenIntrinsic *I) -> auto { |
417 | // Sort throwing intrinsics after non-throwing intrinsics. |
418 | return std::tie(args: I->canThrow, args: I->isNoDuplicate, args: I->isNoMerge, args: I->isNoReturn, |
419 | args: I->isNoCallback, args: I->isNoSync, args: I->isNoFree, args: I->isWillReturn, |
420 | args: I->isCold, args: I->isConvergent, args: I->isSpeculatable, |
421 | args: I->hasSideEffects, args: I->isStrictFP); |
422 | }; |
423 | |
424 | auto TieL = TieBoolAttributes(L); |
425 | auto TieR = TieBoolAttributes(R); |
426 | |
427 | if (TieL != TieR) |
428 | return TieL < TieR; |
429 | |
430 | // Try to order by readonly/readnone attribute. |
431 | uint32_t LME = getEffectiveME(Int: *L).toIntValue(); |
432 | uint32_t RME = getEffectiveME(Int: *R).toIntValue(); |
433 | if (LME != RME) |
434 | return LME > RME; |
435 | |
436 | return false; |
437 | } |
438 | |
439 | /// Returns true if \p Int has a non-empty set of function attributes. Note that |
440 | /// NoUnwind = !canThrow, so we need to negate it's sense to test if the |
441 | // intrinsic has NoUnwind attribute. |
442 | static bool hasFnAttributes(const CodeGenIntrinsic &Int) { |
443 | return !Int.canThrow || Int.isNoReturn || Int.isNoCallback || Int.isNoSync || |
444 | Int.isNoFree || Int.isWillReturn || Int.isCold || Int.isNoDuplicate || |
445 | Int.isNoMerge || Int.isConvergent || Int.isSpeculatable || |
446 | Int.isStrictFP || getEffectiveME(Int) != MemoryEffects::unknown(); |
447 | } |
448 | |
449 | namespace { |
450 | struct FnAttributeComparator { |
451 | bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const { |
452 | return compareFnAttributes(L, R); |
453 | } |
454 | }; |
455 | |
456 | struct AttributeComparator { |
457 | bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const { |
458 | // Order all intrinsics with no functiona attributes before all intrinsics |
459 | // with function attributes. |
460 | bool HasFnAttrLHS = hasFnAttributes(Int: *L); |
461 | bool HasFnAttrRHS = hasFnAttributes(Int: *R); |
462 | |
463 | // Order by argument attributes if function `hasFnAttributes` is equal. |
464 | // This is reliable because each side is already sorted internally. |
465 | return std::tie(args&: HasFnAttrLHS, args: L->ArgumentAttributes) < |
466 | std::tie(args&: HasFnAttrRHS, args: R->ArgumentAttributes); |
467 | } |
468 | }; |
469 | } // End anonymous namespace |
470 | |
471 | /// Returns the name of the IR enum for argument attribute kind \p Kind. |
472 | static StringRef getArgAttrEnumName(CodeGenIntrinsic::ArgAttrKind Kind) { |
473 | switch (Kind) { |
474 | case CodeGenIntrinsic::NoCapture: |
475 | llvm_unreachable("Handled separately" ); |
476 | case CodeGenIntrinsic::NoAlias: |
477 | return "NoAlias" ; |
478 | case CodeGenIntrinsic::NoUndef: |
479 | return "NoUndef" ; |
480 | case CodeGenIntrinsic::NonNull: |
481 | return "NonNull" ; |
482 | case CodeGenIntrinsic::Returned: |
483 | return "Returned" ; |
484 | case CodeGenIntrinsic::ReadOnly: |
485 | return "ReadOnly" ; |
486 | case CodeGenIntrinsic::WriteOnly: |
487 | return "WriteOnly" ; |
488 | case CodeGenIntrinsic::ReadNone: |
489 | return "ReadNone" ; |
490 | case CodeGenIntrinsic::ImmArg: |
491 | return "ImmArg" ; |
492 | case CodeGenIntrinsic::Alignment: |
493 | return "Alignment" ; |
494 | case CodeGenIntrinsic::Dereferenceable: |
495 | return "Dereferenceable" ; |
496 | case CodeGenIntrinsic::Range: |
497 | return "Range" ; |
498 | } |
499 | llvm_unreachable("Unknown CodeGenIntrinsic::ArgAttrKind enum" ); |
500 | } |
501 | |
502 | /// EmitAttributes - This emits the Intrinsic::getAttributes method. |
503 | void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints, |
504 | raw_ostream &OS) { |
505 | OS << R"(// Add parameter attributes that are not common to all intrinsics. |
506 | #ifdef GET_INTRINSIC_ATTRIBUTES |
507 | static AttributeSet getIntrinsicArgAttributeSet(LLVMContext &C, unsigned ID, |
508 | Type *ArgType) { |
509 | unsigned BitWidth = ArgType->getScalarSizeInBits(); |
510 | switch (ID) { |
511 | default: llvm_unreachable("Invalid attribute set number");)" ; |
512 | // Compute unique argument attribute sets. |
513 | std::map<SmallVector<CodeGenIntrinsic::ArgAttribute, 0>, unsigned> |
514 | UniqArgAttributes; |
515 | for (const CodeGenIntrinsic &Int : Ints) { |
516 | for (auto &Attrs : Int.ArgumentAttributes) { |
517 | if (Attrs.empty()) |
518 | continue; |
519 | |
520 | unsigned ID = UniqArgAttributes.size(); |
521 | if (!UniqArgAttributes.try_emplace(k: Attrs, args&: ID).second) |
522 | continue; |
523 | |
524 | assert(is_sorted(Attrs) && "Argument attributes are not sorted" ); |
525 | |
526 | OS << formatv(Fmt: R"( |
527 | case {}: |
528 | return AttributeSet::get(C, {{ |
529 | )" , |
530 | Vals&: ID); |
531 | for (const CodeGenIntrinsic::ArgAttribute &Attr : Attrs) { |
532 | if (Attr.Kind == CodeGenIntrinsic::NoCapture) { |
533 | OS << " Attribute::getWithCaptureInfo(C, " |
534 | "CaptureInfo::none()),\n" ; |
535 | continue; |
536 | } |
537 | StringRef AttrName = getArgAttrEnumName(Kind: Attr.Kind); |
538 | if (Attr.Kind == CodeGenIntrinsic::Alignment || |
539 | Attr.Kind == CodeGenIntrinsic::Dereferenceable) |
540 | OS << formatv(Fmt: " Attribute::get(C, Attribute::{}, {}),\n" , |
541 | Vals&: AttrName, Vals: Attr.Value); |
542 | else if (Attr.Kind == CodeGenIntrinsic::Range) |
543 | // This allows implicitTrunc because the range may only fit the |
544 | // type based on rules implemented in the IR verifier. E.g. the |
545 | // [-1, 1] range for ucmp/scmp intrinsics requires a minimum i2 type. |
546 | // Give the verifier a chance to diagnose this instead of asserting |
547 | // here. |
548 | OS << formatv(Fmt: " Attribute::get(C, Attribute::{}, " |
549 | "ConstantRange(APInt(BitWidth, {}, /*isSigned=*/true, " |
550 | "/*implicitTrunc=*/true), APInt(BitWidth, {}, " |
551 | "/*isSigned=*/true, /*implicitTrunc=*/true))),\n" , |
552 | Vals&: AttrName, Vals: (int64_t)Attr.Value, Vals: (int64_t)Attr.Value2); |
553 | else |
554 | OS << formatv(Fmt: " Attribute::get(C, Attribute::{}),\n" , Vals&: AttrName); |
555 | } |
556 | OS << " });" ; |
557 | } |
558 | } |
559 | OS << R"( |
560 | } |
561 | } // getIntrinsicArgAttributeSet |
562 | )" ; |
563 | |
564 | // Compute unique function attribute sets. |
565 | std::map<const CodeGenIntrinsic *, unsigned, FnAttributeComparator> |
566 | UniqFnAttributes; |
567 | OS << R"( |
568 | static AttributeSet getIntrinsicFnAttributeSet(LLVMContext &C, unsigned ID) { |
569 | switch (ID) { |
570 | default: llvm_unreachable("Invalid attribute set number");)" ; |
571 | |
572 | for (const CodeGenIntrinsic &Int : Ints) { |
573 | unsigned ID = UniqFnAttributes.size(); |
574 | if (!UniqFnAttributes.try_emplace(k: &Int, args&: ID).second) |
575 | continue; |
576 | OS << formatv(Fmt: R"( |
577 | case {}: |
578 | return AttributeSet::get(C, {{ |
579 | )" , |
580 | Vals&: ID); |
581 | auto addAttribute = [&OS](StringRef Attr) { |
582 | OS << formatv(Fmt: " Attribute::get(C, Attribute::{}),\n" , Vals&: Attr); |
583 | }; |
584 | if (!Int.canThrow) |
585 | addAttribute("NoUnwind" ); |
586 | if (Int.isNoReturn) |
587 | addAttribute("NoReturn" ); |
588 | if (Int.isNoCallback) |
589 | addAttribute("NoCallback" ); |
590 | if (Int.isNoSync) |
591 | addAttribute("NoSync" ); |
592 | if (Int.isNoFree) |
593 | addAttribute("NoFree" ); |
594 | if (Int.isWillReturn) |
595 | addAttribute("WillReturn" ); |
596 | if (Int.isCold) |
597 | addAttribute("Cold" ); |
598 | if (Int.isNoDuplicate) |
599 | addAttribute("NoDuplicate" ); |
600 | if (Int.isNoMerge) |
601 | addAttribute("NoMerge" ); |
602 | if (Int.isConvergent) |
603 | addAttribute("Convergent" ); |
604 | if (Int.isSpeculatable) |
605 | addAttribute("Speculatable" ); |
606 | if (Int.isStrictFP) |
607 | addAttribute("StrictFP" ); |
608 | |
609 | const MemoryEffects ME = getEffectiveME(Int); |
610 | if (ME != MemoryEffects::unknown()) { |
611 | OS << formatv(Fmt: " // {}\n" , Vals: ME); |
612 | OS << formatv(Fmt: " Attribute::getWithMemoryEffects(C, " |
613 | "MemoryEffects::createFromIntValue({})),\n" , |
614 | Vals: ME.toIntValue()); |
615 | } |
616 | OS << " });" ; |
617 | } |
618 | OS << R"( |
619 | } |
620 | } // getIntrinsicFnAttributeSet |
621 | |
622 | static constexpr uint16_t IntrinsicsToAttributesMap[] = {)" ; |
623 | |
624 | // Compute the maximum number of attribute arguments and the map. For function |
625 | // attributes, we only consider whether the intrinsics has any function |
626 | // arguments or not. |
627 | std::map<const CodeGenIntrinsic *, unsigned, AttributeComparator> |
628 | UniqAttributes; |
629 | for (const CodeGenIntrinsic &Int : Ints) { |
630 | unsigned ID = UniqAttributes.size(); |
631 | UniqAttributes.try_emplace(k: &Int, args&: ID); |
632 | } |
633 | |
634 | // Emit an array of AttributeList. Most intrinsics will have at least one |
635 | // entry, for the function itself (index ~1), which is usually nounwind. |
636 | for (const CodeGenIntrinsic &Int : Ints) { |
637 | uint16_t FnAttrIndex = UniqFnAttributes[&Int]; |
638 | OS << formatv(Fmt: "\n {} << 8 | {}, // {}" , Vals&: FnAttrIndex, |
639 | Vals&: UniqAttributes[&Int], Vals: Int.Name); |
640 | } |
641 | |
642 | // Assign a 16-bit packed ID for each intrinsic. The lower 8-bits will be its |
643 | // "argument attribute ID" (index in UniqAttributes) and upper 8 bits will be |
644 | // its "function attribute ID" (index in UniqFnAttributes). |
645 | if (UniqAttributes.size() > 256) |
646 | PrintFatalError(Msg: "Too many unique argument attributes for table!" ); |
647 | if (UniqFnAttributes.size() > 256) |
648 | PrintFatalError(Msg: "Too many unique function attributes for table!" ); |
649 | |
650 | OS << R"( |
651 | }; |
652 | |
653 | AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id, |
654 | FunctionType *FT) {)" ; |
655 | |
656 | OS << formatv(Fmt: R"( |
657 | if (id == 0) |
658 | return AttributeList(); |
659 | |
660 | uint16_t PackedID = IntrinsicsToAttributesMap[id - 1]; |
661 | uint8_t FnAttrID = PackedID >> 8; |
662 | switch(PackedID & 0xFF) {{ |
663 | default: llvm_unreachable("Invalid attribute number"); |
664 | )" ); |
665 | |
666 | for (const auto [IntPtr, UniqueID] : UniqAttributes) { |
667 | OS << formatv(Fmt: " case {}:\n" , Vals: UniqueID); |
668 | const CodeGenIntrinsic &Int = *IntPtr; |
669 | |
670 | // Keep track of the number of attributes we're writing out. |
671 | unsigned NumAttrs = |
672 | llvm::count_if(Range: Int.ArgumentAttributes, |
673 | P: [](const auto &Attrs) { return !Attrs.empty(); }); |
674 | NumAttrs += hasFnAttributes(Int); |
675 | if (NumAttrs == 0) { |
676 | OS << " return AttributeList();\n" ; |
677 | continue; |
678 | } |
679 | |
680 | OS << " return AttributeList::get(C, {\n" ; |
681 | ListSeparator LS(",\n" ); |
682 | for (const auto &[AttrIdx, Attrs] : enumerate(First: Int.ArgumentAttributes)) { |
683 | if (Attrs.empty()) |
684 | continue; |
685 | |
686 | unsigned ArgAttrID = UniqArgAttributes.find(x: Attrs)->second; |
687 | OS << LS |
688 | << formatv(Fmt: " {{{}, getIntrinsicArgAttributeSet(C, {}, " |
689 | "FT->getContainedType({}))}" , |
690 | Vals&: AttrIdx, Vals&: ArgAttrID, Vals&: AttrIdx); |
691 | } |
692 | |
693 | if (hasFnAttributes(Int)) { |
694 | OS << LS |
695 | << " {AttributeList::FunctionIndex, " |
696 | "getIntrinsicFnAttributeSet(C, FnAttrID)}" ; |
697 | } |
698 | OS << "\n });\n" ; |
699 | } |
700 | |
701 | OS << R"( } |
702 | } |
703 | #endif // GET_INTRINSIC_ATTRIBUTES |
704 | |
705 | )" ; |
706 | } |
707 | |
708 | void IntrinsicEmitter::EmitIntrinsicToBuiltinMap( |
709 | const CodeGenIntrinsicTable &Ints, bool IsClang, raw_ostream &OS) { |
710 | StringRef CompilerName = IsClang ? "Clang" : "MS" ; |
711 | StringRef UpperCompilerName = IsClang ? "CLANG" : "MS" ; |
712 | |
713 | // map<TargetPrefix, pair<map<BuiltinName, EnumName>, CommonPrefix>. |
714 | // Note that we iterate over both the maps in the code below and both |
715 | // iterations need to iterate in sorted key order. For the inner map, entries |
716 | // need to be emitted in the sorted order of `BuiltinName` with `CommonPrefix` |
717 | // rempved, because we use std::lower_bound to search these entries. For the |
718 | // outer map as well, entries need to be emitted in sorter order of |
719 | // `TargetPrefix` as we use std::lower_bound to search these entries. |
720 | using BIMEntryTy = |
721 | std::pair<std::map<StringRef, StringRef>, std::optional<StringRef>>; |
722 | std::map<StringRef, BIMEntryTy> BuiltinMap; |
723 | |
724 | for (const CodeGenIntrinsic &Int : Ints) { |
725 | StringRef BuiltinName = IsClang ? Int.ClangBuiltinName : Int.MSBuiltinName; |
726 | if (BuiltinName.empty()) |
727 | continue; |
728 | // Get the map for this target prefix. |
729 | auto &[Map, CommonPrefix] = BuiltinMap[Int.TargetPrefix]; |
730 | |
731 | if (!Map.try_emplace(k: BuiltinName, args: Int.EnumName).second) |
732 | PrintFatalError(ErrorLoc: Int.TheDef->getLoc(), |
733 | Msg: "Intrinsic '" + Int.TheDef->getName() + "': duplicate " + |
734 | CompilerName + " builtin name!" ); |
735 | |
736 | // Update common prefix. |
737 | if (!CommonPrefix) { |
738 | // For the first builtin for this target, initialize the common prefix. |
739 | CommonPrefix = BuiltinName; |
740 | continue; |
741 | } |
742 | |
743 | // Update the common prefix. Note that this assumes that `take_front` will |
744 | // never set the `Data` pointer in CommonPrefix to nullptr. |
745 | const char *Mismatch = mismatch(Range1&: *CommonPrefix, Range2&: BuiltinName).first; |
746 | *CommonPrefix = CommonPrefix->take_front(N: Mismatch - CommonPrefix->begin()); |
747 | } |
748 | |
749 | // Populate the string table with the names of all the builtins after |
750 | // removing this common prefix. |
751 | StringToOffsetTable Table; |
752 | for (const auto &[TargetPrefix, Entry] : BuiltinMap) { |
753 | auto &[Map, CommonPrefix] = Entry; |
754 | for (auto &[BuiltinName, EnumName] : Map) { |
755 | StringRef Suffix = BuiltinName.substr(Start: CommonPrefix->size()); |
756 | Table.GetOrAddStringOffset(Str: Suffix); |
757 | } |
758 | } |
759 | |
760 | OS << formatv(Fmt: R"( |
761 | // Get the LLVM intrinsic that corresponds to a builtin. This is used by the |
762 | // C front-end. The builtin name is passed in as BuiltinName, and a target |
763 | // prefix (e.g. 'ppc') is passed in as TargetPrefix. |
764 | #ifdef GET_LLVM_INTRINSIC_FOR_{}_BUILTIN |
765 | Intrinsic::ID |
766 | Intrinsic::getIntrinsicFor{}Builtin(StringRef TargetPrefix, |
767 | StringRef BuiltinName) {{ |
768 | using namespace Intrinsic; |
769 | )" , |
770 | Vals&: UpperCompilerName, Vals&: CompilerName); |
771 | |
772 | if (BuiltinMap.empty()) { |
773 | OS << formatv(Fmt: R"( |
774 | return not_intrinsic; |
775 | } |
776 | #endif // GET_LLVM_INTRINSIC_FOR_{}_BUILTIN |
777 | )" , |
778 | Vals&: UpperCompilerName); |
779 | return; |
780 | } |
781 | |
782 | if (!Table.empty()) { |
783 | Table.EmitStringTableDef(OS, Name: "BuiltinNames" ); |
784 | |
785 | OS << R"( |
786 | struct BuiltinEntry { |
787 | ID IntrinsicID; |
788 | unsigned StrTabOffset; |
789 | const char *getName() const { return BuiltinNames[StrTabOffset].data(); } |
790 | bool operator<(StringRef RHS) const { |
791 | return strncmp(getName(), RHS.data(), RHS.size()) < 0; |
792 | } |
793 | }; |
794 | |
795 | )" ; |
796 | } |
797 | |
798 | // Emit a per target table of bultin names. |
799 | bool HasTargetIndependentBuiltins = false; |
800 | StringRef TargetIndepndentCommonPrefix; |
801 | for (const auto &[TargetPrefix, Entry] : BuiltinMap) { |
802 | const auto &[Map, CommonPrefix] = Entry; |
803 | if (!TargetPrefix.empty()) { |
804 | OS << formatv(Fmt: " // Builtins for {0}.\n" , Vals: TargetPrefix); |
805 | } else { |
806 | OS << " // Target independent builtins.\n" ; |
807 | HasTargetIndependentBuiltins = true; |
808 | TargetIndepndentCommonPrefix = *CommonPrefix; |
809 | } |
810 | |
811 | // Emit the builtin table for this target prefix. |
812 | OS << formatv(Fmt: " static constexpr BuiltinEntry {}Names[] = {{\n" , |
813 | Vals: TargetPrefix); |
814 | for (const auto &[BuiltinName, EnumName] : Map) { |
815 | StringRef Suffix = BuiltinName.substr(Start: CommonPrefix->size()); |
816 | OS << formatv(Fmt: " {{{}, {}}, // {}\n" , Vals: EnumName, |
817 | Vals: *Table.GetStringOffset(Str: Suffix), Vals: BuiltinName); |
818 | } |
819 | OS << formatv(Fmt: " }; // {}Names\n\n" , Vals: TargetPrefix); |
820 | } |
821 | |
822 | // After emitting the builtin tables for all targets, emit a lookup table for |
823 | // all targets. We will use binary search, similar to the table for builtin |
824 | // names to lookup into this table. |
825 | OS << R"( |
826 | struct TargetEntry { |
827 | StringLiteral TargetPrefix; |
828 | ArrayRef<BuiltinEntry> Names; |
829 | StringLiteral CommonPrefix; |
830 | bool operator<(StringRef RHS) const { |
831 | return TargetPrefix < RHS; |
832 | }; |
833 | }; |
834 | static constexpr TargetEntry TargetTable[] = { |
835 | )" ; |
836 | |
837 | for (const auto &[TargetPrefix, Entry] : BuiltinMap) { |
838 | const auto &[Map, CommonPrefix] = Entry; |
839 | if (TargetPrefix.empty()) |
840 | continue; |
841 | OS << formatv(Fmt: R"( {{"{0}", {0}Names, "{1}"},)" , Vals: TargetPrefix, |
842 | Vals: CommonPrefix) |
843 | << "\n" ; |
844 | } |
845 | OS << " };\n" ; |
846 | |
847 | // Now for the actual lookup, first check the target independent table if |
848 | // we emitted one. |
849 | if (HasTargetIndependentBuiltins) { |
850 | OS << formatv(Fmt: R"( |
851 | // Check if it's a target independent builtin. |
852 | // Copy the builtin name so we can use it in consume_front without clobbering |
853 | // if for the lookup in the target specific table. |
854 | StringRef Suffix = BuiltinName; |
855 | if (Suffix.consume_front("{}")) {{ |
856 | auto II = lower_bound(Names, Suffix); |
857 | if (II != std::end(Names) && II->getName() == Suffix) |
858 | return II->IntrinsicID; |
859 | } |
860 | )" , |
861 | Vals&: TargetIndepndentCommonPrefix); |
862 | } |
863 | |
864 | // If a target independent builtin was not found, lookup the target specific. |
865 | OS << formatv(Fmt: R"( |
866 | auto TI = lower_bound(TargetTable, TargetPrefix); |
867 | if (TI == std::end(TargetTable) || TI->TargetPrefix != TargetPrefix) |
868 | return not_intrinsic; |
869 | // This is the last use of BuiltinName, so no need to copy before using it in |
870 | // consume_front. |
871 | if (!BuiltinName.consume_front(TI->CommonPrefix)) |
872 | return not_intrinsic; |
873 | auto II = lower_bound(TI->Names, BuiltinName); |
874 | if (II == std::end(TI->Names) || II->getName() != BuiltinName) |
875 | return not_intrinsic; |
876 | return II->IntrinsicID; |
877 | } |
878 | #endif // GET_LLVM_INTRINSIC_FOR_{}_BUILTIN |
879 | |
880 | )" , |
881 | Vals&: UpperCompilerName); |
882 | } |
883 | |
884 | static TableGen::Emitter::OptClass<IntrinsicEmitterOpt</*Enums=*/true>> |
885 | X("gen-intrinsic-enums" , "Generate intrinsic enums" ); |
886 | |
887 | static TableGen::Emitter::OptClass<IntrinsicEmitterOpt</*Enums=*/false>> |
888 | Y("gen-intrinsic-impl" , "Generate intrinsic implementation code" ); |
889 | |