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 "Basic/CodeGenIntrinsics.h" |
14 | #include "Basic/SequenceToOffsetTable.h" |
15 | #include "llvm/ADT/STLExtras.h" |
16 | #include "llvm/ADT/SmallVector.h" |
17 | #include "llvm/ADT/StringExtras.h" |
18 | #include "llvm/ADT/StringRef.h" |
19 | #include "llvm/ADT/Twine.h" |
20 | #include "llvm/Support/CommandLine.h" |
21 | #include "llvm/Support/ErrorHandling.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 <map> |
32 | #include <optional> |
33 | #include <string> |
34 | #include <utility> |
35 | #include <vector> |
36 | using namespace llvm; |
37 | |
38 | cl::OptionCategory GenIntrinsicCat("Options for -gen-intrinsic-enums" ); |
39 | cl::opt<std::string> |
40 | IntrinsicPrefix("intrinsic-prefix" , |
41 | cl::desc("Generate intrinsics with this target prefix" ), |
42 | cl::value_desc("target prefix" ), cl::cat(GenIntrinsicCat)); |
43 | |
44 | namespace { |
45 | class IntrinsicEmitter { |
46 | RecordKeeper &Records; |
47 | |
48 | public: |
49 | IntrinsicEmitter(RecordKeeper &R) : Records(R) {} |
50 | |
51 | void run(raw_ostream &OS, bool Enums); |
52 | |
53 | void EmitEnumInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); |
54 | void EmitArgKind(raw_ostream &OS); |
55 | void EmitIITInfo(raw_ostream &OS); |
56 | void EmitTargetInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); |
57 | void EmitIntrinsicToNameTable(const CodeGenIntrinsicTable &Ints, |
58 | raw_ostream &OS); |
59 | void EmitIntrinsicToOverloadTable(const CodeGenIntrinsicTable &Ints, |
60 | raw_ostream &OS); |
61 | void EmitGenerator(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); |
62 | void EmitAttributes(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); |
63 | void EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable &Ints, |
64 | bool IsClang, raw_ostream &OS); |
65 | }; |
66 | } // End anonymous namespace |
67 | |
68 | //===----------------------------------------------------------------------===// |
69 | // IntrinsicEmitter Implementation |
70 | //===----------------------------------------------------------------------===// |
71 | |
72 | void IntrinsicEmitter::run(raw_ostream &OS, bool Enums) { |
73 | emitSourceFileHeader(Desc: "Intrinsic Function Source Fragment" , OS); |
74 | |
75 | CodeGenIntrinsicTable Ints(Records); |
76 | |
77 | if (Enums) { |
78 | // Emit the enum information. |
79 | EmitEnumInfo(Ints, OS); |
80 | |
81 | // Emit ArgKind for Intrinsics.h. |
82 | EmitArgKind(OS); |
83 | } else { |
84 | // Emit IIT_Info constants. |
85 | EmitIITInfo(OS); |
86 | |
87 | // Emit the target metadata. |
88 | EmitTargetInfo(Ints, OS); |
89 | |
90 | // Emit the intrinsic ID -> name table. |
91 | EmitIntrinsicToNameTable(Ints, OS); |
92 | |
93 | // Emit the intrinsic ID -> overload table. |
94 | EmitIntrinsicToOverloadTable(Ints, OS); |
95 | |
96 | // Emit the intrinsic declaration generator. |
97 | EmitGenerator(Ints, OS); |
98 | |
99 | // Emit the intrinsic parameter attributes. |
100 | EmitAttributes(Ints, OS); |
101 | |
102 | // Emit code to translate GCC builtins into LLVM intrinsics. |
103 | EmitIntrinsicToBuiltinMap(Ints, IsClang: true, OS); |
104 | |
105 | // Emit code to translate MS builtins into LLVM intrinsics. |
106 | EmitIntrinsicToBuiltinMap(Ints, IsClang: false, OS); |
107 | } |
108 | } |
109 | |
110 | void IntrinsicEmitter::EmitEnumInfo(const CodeGenIntrinsicTable &Ints, |
111 | raw_ostream &OS) { |
112 | // Find the TargetSet for which to generate enums. There will be an initial |
113 | // set with an empty target prefix which will include target independent |
114 | // intrinsics like dbg.value. |
115 | const CodeGenIntrinsicTable::TargetSet *Set = nullptr; |
116 | for (const auto &Target : Ints.Targets) { |
117 | if (Target.Name == IntrinsicPrefix) { |
118 | Set = &Target; |
119 | break; |
120 | } |
121 | } |
122 | if (!Set) { |
123 | std::vector<std::string> KnownTargets; |
124 | for (const auto &Target : Ints.Targets) |
125 | if (!Target.Name.empty()) |
126 | KnownTargets.push_back(x: Target.Name); |
127 | PrintFatalError(Msg: "tried to generate intrinsics for unknown target " + |
128 | IntrinsicPrefix + |
129 | "\nKnown targets are: " + join(R&: KnownTargets, Separator: ", " ) + "\n" ); |
130 | } |
131 | |
132 | // Generate a complete header for target specific intrinsics. |
133 | if (IntrinsicPrefix.empty()) { |
134 | OS << "#ifdef GET_INTRINSIC_ENUM_VALUES\n" ; |
135 | } else { |
136 | std::string UpperPrefix = StringRef(IntrinsicPrefix).upper(); |
137 | OS << "#ifndef LLVM_IR_INTRINSIC_" << UpperPrefix << "_ENUMS_H\n" ; |
138 | OS << "#define LLVM_IR_INTRINSIC_" << UpperPrefix << "_ENUMS_H\n\n" ; |
139 | OS << "namespace llvm {\n" ; |
140 | OS << "namespace Intrinsic {\n" ; |
141 | OS << "enum " << UpperPrefix << "Intrinsics : unsigned {\n" ; |
142 | } |
143 | |
144 | OS << "// Enum values for intrinsics\n" ; |
145 | for (unsigned i = Set->Offset, e = Set->Offset + Set->Count; i != e; ++i) { |
146 | OS << " " << Ints[i].EnumName; |
147 | |
148 | // Assign a value to the first intrinsic in this target set so that all |
149 | // intrinsic ids are distinct. |
150 | if (i == Set->Offset) |
151 | OS << " = " << (Set->Offset + 1); |
152 | |
153 | OS << ", " ; |
154 | if (Ints[i].EnumName.size() < 40) |
155 | OS.indent(NumSpaces: 40 - Ints[i].EnumName.size()); |
156 | OS << " // " << Ints[i].Name << "\n" ; |
157 | } |
158 | |
159 | // Emit num_intrinsics into the target neutral enum. |
160 | if (IntrinsicPrefix.empty()) { |
161 | OS << " num_intrinsics = " << (Ints.size() + 1) << "\n" ; |
162 | OS << "#endif\n\n" ; |
163 | } else { |
164 | OS << "}; // enum\n" ; |
165 | OS << "} // namespace Intrinsic\n" ; |
166 | OS << "} // namespace llvm\n\n" ; |
167 | OS << "#endif\n" ; |
168 | } |
169 | } |
170 | |
171 | void IntrinsicEmitter::EmitArgKind(raw_ostream &OS) { |
172 | if (!IntrinsicPrefix.empty()) |
173 | return; |
174 | OS << "// llvm::Intrinsic::IITDescriptor::ArgKind\n" ; |
175 | OS << "#ifdef GET_INTRINSIC_ARGKIND\n" ; |
176 | if (auto RecArgKind = Records.getDef(Name: "ArgKind" )) { |
177 | for (auto &RV : RecArgKind->getValues()) |
178 | OS << " AK_" << RV.getName() << " = " << *RV.getValue() << ",\n" ; |
179 | } else { |
180 | OS << "#error \"ArgKind is not defined\"\n" ; |
181 | } |
182 | OS << "#endif\n\n" ; |
183 | } |
184 | |
185 | void IntrinsicEmitter::EmitIITInfo(raw_ostream &OS) { |
186 | OS << "#ifdef GET_INTRINSIC_IITINFO\n" ; |
187 | std::array<StringRef, 256> RecsByNumber; |
188 | auto IIT_Base = Records.getAllDerivedDefinitionsIfDefined(ClassName: "IIT_Base" ); |
189 | for (auto Rec : IIT_Base) { |
190 | auto Number = Rec->getValueAsInt(FieldName: "Number" ); |
191 | assert(0 <= Number && Number < (int)RecsByNumber.size() && |
192 | "IIT_Info.Number should be uint8_t" ); |
193 | assert(RecsByNumber[Number].empty() && "Duplicate IIT_Info.Number" ); |
194 | RecsByNumber[Number] = Rec->getName(); |
195 | } |
196 | if (IIT_Base.size() > 0) { |
197 | for (unsigned I = 0, E = RecsByNumber.size(); I < E; ++I) |
198 | if (!RecsByNumber[I].empty()) |
199 | OS << " " << RecsByNumber[I] << " = " << I << ",\n" ; |
200 | } else { |
201 | OS << "#error \"class IIT_Base is not defined\"\n" ; |
202 | } |
203 | OS << "#endif\n\n" ; |
204 | } |
205 | |
206 | void IntrinsicEmitter::EmitTargetInfo(const CodeGenIntrinsicTable &Ints, |
207 | raw_ostream &OS) { |
208 | OS << "// Target mapping\n" ; |
209 | OS << "#ifdef GET_INTRINSIC_TARGET_DATA\n" ; |
210 | OS << "struct IntrinsicTargetInfo {\n" |
211 | << " llvm::StringLiteral Name;\n" |
212 | << " size_t Offset;\n" |
213 | << " size_t Count;\n" |
214 | << "};\n" ; |
215 | OS << "static constexpr IntrinsicTargetInfo TargetInfos[] = {\n" ; |
216 | for (const auto &Target : Ints.Targets) |
217 | OS << " {llvm::StringLiteral(\"" << Target.Name << "\"), " << Target.Offset |
218 | << ", " << Target.Count << "},\n" ; |
219 | OS << "};\n" ; |
220 | OS << "#endif\n\n" ; |
221 | } |
222 | |
223 | void IntrinsicEmitter::EmitIntrinsicToNameTable( |
224 | const CodeGenIntrinsicTable &Ints, raw_ostream &OS) { |
225 | OS << "// Intrinsic ID to name table\n" ; |
226 | OS << "#ifdef GET_INTRINSIC_NAME_TABLE\n" ; |
227 | OS << " // Note that entry #0 is the invalid intrinsic!\n" ; |
228 | for (unsigned i = 0, e = Ints.size(); i != e; ++i) |
229 | OS << " \"" << Ints[i].Name << "\",\n" ; |
230 | OS << "#endif\n\n" ; |
231 | } |
232 | |
233 | void IntrinsicEmitter::EmitIntrinsicToOverloadTable( |
234 | const CodeGenIntrinsicTable &Ints, raw_ostream &OS) { |
235 | OS << "// Intrinsic ID to overload bitset\n" ; |
236 | OS << "#ifdef GET_INTRINSIC_OVERLOAD_TABLE\n" ; |
237 | OS << "static const uint8_t OTable[] = {\n" ; |
238 | OS << " 0" ; |
239 | for (unsigned i = 0, e = Ints.size(); i != e; ++i) { |
240 | // Add one to the index so we emit a null bit for the invalid #0 intrinsic. |
241 | if ((i + 1) % 8 == 0) |
242 | OS << ",\n 0" ; |
243 | if (Ints[i].isOverloaded) |
244 | OS << " | (1<<" << (i + 1) % 8 << ')'; |
245 | } |
246 | OS << "\n};\n\n" ; |
247 | // OTable contains a true bit at the position if the intrinsic is overloaded. |
248 | OS << "return (OTable[id/8] & (1 << (id%8))) != 0;\n" ; |
249 | OS << "#endif\n\n" ; |
250 | } |
251 | |
252 | /// ComputeFixedEncoding - If we can encode the type signature for this |
253 | /// intrinsic into 32 bits, return it. If not, return ~0U. |
254 | static void ComputeFixedEncoding(const CodeGenIntrinsic &Int, |
255 | std::vector<unsigned char> &TypeSig) { |
256 | if (auto *R = Int.TheDef->getValue(Name: "TypeSig" )) { |
257 | for (auto &a : cast<ListInit>(Val: R->getValue())->getValues()) { |
258 | for (auto &b : cast<ListInit>(Val: a)->getValues()) |
259 | TypeSig.push_back(x: cast<IntInit>(Val: b)->getValue()); |
260 | } |
261 | } |
262 | } |
263 | |
264 | static void printIITEntry(raw_ostream &OS, unsigned char X) { |
265 | OS << (unsigned)X; |
266 | } |
267 | |
268 | void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints, |
269 | raw_ostream &OS) { |
270 | // If we can compute a 32-bit fixed encoding for this intrinsic, do so and |
271 | // capture it in this vector, otherwise store a ~0U. |
272 | std::vector<unsigned> FixedEncodings; |
273 | |
274 | SequenceToOffsetTable<std::vector<unsigned char>> LongEncodingTable; |
275 | |
276 | std::vector<unsigned char> TypeSig; |
277 | |
278 | // Compute the unique argument type info. |
279 | for (unsigned i = 0, e = Ints.size(); i != e; ++i) { |
280 | // Get the signature for the intrinsic. |
281 | TypeSig.clear(); |
282 | ComputeFixedEncoding(Int: Ints[i], TypeSig); |
283 | |
284 | // Check to see if we can encode it into a 32-bit word. We can only encode |
285 | // 8 nibbles into a 32-bit word. |
286 | if (TypeSig.size() <= 8) { |
287 | bool Failed = false; |
288 | unsigned Result = 0; |
289 | for (unsigned i = 0, e = TypeSig.size(); i != e; ++i) { |
290 | // If we had an unencodable argument, bail out. |
291 | if (TypeSig[i] > 15) { |
292 | Failed = true; |
293 | break; |
294 | } |
295 | Result = (Result << 4) | TypeSig[e - i - 1]; |
296 | } |
297 | |
298 | // If this could be encoded into a 31-bit word, return it. |
299 | if (!Failed && (Result >> 31) == 0) { |
300 | FixedEncodings.push_back(x: Result); |
301 | continue; |
302 | } |
303 | } |
304 | |
305 | // Otherwise, we're going to unique the sequence into the |
306 | // LongEncodingTable, and use its offset in the 32-bit table instead. |
307 | LongEncodingTable.add(Seq: TypeSig); |
308 | |
309 | // This is a placehold that we'll replace after the table is laid out. |
310 | FixedEncodings.push_back(x: ~0U); |
311 | } |
312 | |
313 | LongEncodingTable.layout(); |
314 | |
315 | OS << "// Global intrinsic function declaration type table.\n" ; |
316 | OS << "#ifdef GET_INTRINSIC_GENERATOR_GLOBAL\n" ; |
317 | |
318 | OS << "static const unsigned IIT_Table[] = {\n " ; |
319 | |
320 | for (unsigned i = 0, e = FixedEncodings.size(); i != e; ++i) { |
321 | if ((i & 7) == 7) |
322 | OS << "\n " ; |
323 | |
324 | // If the entry fit in the table, just emit it. |
325 | if (FixedEncodings[i] != ~0U) { |
326 | OS << "0x" << Twine::utohexstr(Val: FixedEncodings[i]) << ", " ; |
327 | continue; |
328 | } |
329 | |
330 | TypeSig.clear(); |
331 | ComputeFixedEncoding(Int: Ints[i], TypeSig); |
332 | |
333 | // Otherwise, emit the offset into the long encoding table. We emit it this |
334 | // way so that it is easier to read the offset in the .def file. |
335 | OS << "(1U<<31) | " << LongEncodingTable.get(Seq: TypeSig) << ", " ; |
336 | } |
337 | |
338 | OS << "0\n};\n\n" ; |
339 | |
340 | // Emit the shared table of register lists. |
341 | OS << "static const unsigned char IIT_LongEncodingTable[] = {\n" ; |
342 | if (!LongEncodingTable.empty()) |
343 | LongEncodingTable.emit(OS, Print: printIITEntry); |
344 | OS << " 255\n};\n\n" ; |
345 | |
346 | OS << "#endif\n\n" ; // End of GET_INTRINSIC_GENERATOR_GLOBAL |
347 | } |
348 | |
349 | namespace { |
350 | std::optional<bool> compareFnAttributes(const CodeGenIntrinsic *L, |
351 | const CodeGenIntrinsic *R) { |
352 | // Sort throwing intrinsics after non-throwing intrinsics. |
353 | if (L->canThrow != R->canThrow) |
354 | return R->canThrow; |
355 | |
356 | if (L->isNoDuplicate != R->isNoDuplicate) |
357 | return R->isNoDuplicate; |
358 | |
359 | if (L->isNoMerge != R->isNoMerge) |
360 | return R->isNoMerge; |
361 | |
362 | if (L->isNoReturn != R->isNoReturn) |
363 | return R->isNoReturn; |
364 | |
365 | if (L->isNoCallback != R->isNoCallback) |
366 | return R->isNoCallback; |
367 | |
368 | if (L->isNoSync != R->isNoSync) |
369 | return R->isNoSync; |
370 | |
371 | if (L->isNoFree != R->isNoFree) |
372 | return R->isNoFree; |
373 | |
374 | if (L->isWillReturn != R->isWillReturn) |
375 | return R->isWillReturn; |
376 | |
377 | if (L->isCold != R->isCold) |
378 | return R->isCold; |
379 | |
380 | if (L->isConvergent != R->isConvergent) |
381 | return R->isConvergent; |
382 | |
383 | if (L->isSpeculatable != R->isSpeculatable) |
384 | return R->isSpeculatable; |
385 | |
386 | if (L->hasSideEffects != R->hasSideEffects) |
387 | return R->hasSideEffects; |
388 | |
389 | if (L->isStrictFP != R->isStrictFP) |
390 | return R->isStrictFP; |
391 | |
392 | // Try to order by readonly/readnone attribute. |
393 | uint32_t LK = L->ME.toIntValue(); |
394 | uint32_t RK = R->ME.toIntValue(); |
395 | if (LK != RK) |
396 | return (LK > RK); |
397 | |
398 | return std::nullopt; |
399 | } |
400 | |
401 | struct FnAttributeComparator { |
402 | bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const { |
403 | return compareFnAttributes(L, R).value_or(u: false); |
404 | } |
405 | }; |
406 | |
407 | struct AttributeComparator { |
408 | bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const { |
409 | if (std::optional<bool> Res = compareFnAttributes(L, R)) |
410 | return *Res; |
411 | |
412 | // Order by argument attributes. |
413 | // This is reliable because each side is already sorted internally. |
414 | return (L->ArgumentAttributes < R->ArgumentAttributes); |
415 | } |
416 | }; |
417 | } // End anonymous namespace |
418 | |
419 | /// EmitAttributes - This emits the Intrinsic::getAttributes method. |
420 | void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints, |
421 | raw_ostream &OS) { |
422 | OS << "// Add parameter attributes that are not common to all intrinsics.\n" ; |
423 | OS << "#ifdef GET_INTRINSIC_ATTRIBUTES\n" ; |
424 | |
425 | // Compute unique argument attribute sets. |
426 | std::map<SmallVector<CodeGenIntrinsic::ArgAttribute, 0>, unsigned> |
427 | UniqArgAttributes; |
428 | OS << "static AttributeSet getIntrinsicArgAttributeSet(" |
429 | << "LLVMContext &C, unsigned ID) {\n" |
430 | << " switch (ID) {\n" |
431 | << " default: llvm_unreachable(\"Invalid attribute set number\");\n" ; |
432 | for (const CodeGenIntrinsic &Int : Ints) { |
433 | for (auto &Attrs : Int.ArgumentAttributes) { |
434 | if (Attrs.empty()) |
435 | continue; |
436 | |
437 | unsigned ID = UniqArgAttributes.size(); |
438 | if (!UniqArgAttributes.try_emplace(k: Attrs, args&: ID).second) |
439 | continue; |
440 | |
441 | assert(is_sorted(Attrs) && "Argument attributes are not sorted" ); |
442 | |
443 | OS << " case " << ID << ":\n" ; |
444 | OS << " return AttributeSet::get(C, {\n" ; |
445 | for (const CodeGenIntrinsic::ArgAttribute &Attr : Attrs) { |
446 | switch (Attr.Kind) { |
447 | case CodeGenIntrinsic::NoCapture: |
448 | OS << " Attribute::get(C, Attribute::NoCapture),\n" ; |
449 | break; |
450 | case CodeGenIntrinsic::NoAlias: |
451 | OS << " Attribute::get(C, Attribute::NoAlias),\n" ; |
452 | break; |
453 | case CodeGenIntrinsic::NoUndef: |
454 | OS << " Attribute::get(C, Attribute::NoUndef),\n" ; |
455 | break; |
456 | case CodeGenIntrinsic::NonNull: |
457 | OS << " Attribute::get(C, Attribute::NonNull),\n" ; |
458 | break; |
459 | case CodeGenIntrinsic::Returned: |
460 | OS << " Attribute::get(C, Attribute::Returned),\n" ; |
461 | break; |
462 | case CodeGenIntrinsic::ReadOnly: |
463 | OS << " Attribute::get(C, Attribute::ReadOnly),\n" ; |
464 | break; |
465 | case CodeGenIntrinsic::WriteOnly: |
466 | OS << " Attribute::get(C, Attribute::WriteOnly),\n" ; |
467 | break; |
468 | case CodeGenIntrinsic::ReadNone: |
469 | OS << " Attribute::get(C, Attribute::ReadNone),\n" ; |
470 | break; |
471 | case CodeGenIntrinsic::ImmArg: |
472 | OS << " Attribute::get(C, Attribute::ImmArg),\n" ; |
473 | break; |
474 | case CodeGenIntrinsic::Alignment: |
475 | OS << " Attribute::get(C, Attribute::Alignment, " << Attr.Value |
476 | << "),\n" ; |
477 | break; |
478 | case CodeGenIntrinsic::Dereferenceable: |
479 | OS << " Attribute::get(C, Attribute::Dereferenceable, " |
480 | << Attr.Value << "),\n" ; |
481 | break; |
482 | } |
483 | } |
484 | OS << " });\n" ; |
485 | } |
486 | } |
487 | OS << " }\n" ; |
488 | OS << "}\n\n" ; |
489 | |
490 | // Compute unique function attribute sets. |
491 | std::map<const CodeGenIntrinsic *, unsigned, FnAttributeComparator> |
492 | UniqFnAttributes; |
493 | OS << "static AttributeSet getIntrinsicFnAttributeSet(" |
494 | << "LLVMContext &C, unsigned ID) {\n" |
495 | << " switch (ID) {\n" |
496 | << " default: llvm_unreachable(\"Invalid attribute set number\");\n" ; |
497 | for (const CodeGenIntrinsic &Intrinsic : Ints) { |
498 | unsigned ID = UniqFnAttributes.size(); |
499 | if (!UniqFnAttributes.try_emplace(k: &Intrinsic, args&: ID).second) |
500 | continue; |
501 | |
502 | OS << " case " << ID << ":\n" |
503 | << " return AttributeSet::get(C, {\n" ; |
504 | if (!Intrinsic.canThrow) |
505 | OS << " Attribute::get(C, Attribute::NoUnwind),\n" ; |
506 | if (Intrinsic.isNoReturn) |
507 | OS << " Attribute::get(C, Attribute::NoReturn),\n" ; |
508 | if (Intrinsic.isNoCallback) |
509 | OS << " Attribute::get(C, Attribute::NoCallback),\n" ; |
510 | if (Intrinsic.isNoSync) |
511 | OS << " Attribute::get(C, Attribute::NoSync),\n" ; |
512 | if (Intrinsic.isNoFree) |
513 | OS << " Attribute::get(C, Attribute::NoFree),\n" ; |
514 | if (Intrinsic.isWillReturn) |
515 | OS << " Attribute::get(C, Attribute::WillReturn),\n" ; |
516 | if (Intrinsic.isCold) |
517 | OS << " Attribute::get(C, Attribute::Cold),\n" ; |
518 | if (Intrinsic.isNoDuplicate) |
519 | OS << " Attribute::get(C, Attribute::NoDuplicate),\n" ; |
520 | if (Intrinsic.isNoMerge) |
521 | OS << " Attribute::get(C, Attribute::NoMerge),\n" ; |
522 | if (Intrinsic.isConvergent) |
523 | OS << " Attribute::get(C, Attribute::Convergent),\n" ; |
524 | if (Intrinsic.isSpeculatable) |
525 | OS << " Attribute::get(C, Attribute::Speculatable),\n" ; |
526 | if (Intrinsic.isStrictFP) |
527 | OS << " Attribute::get(C, Attribute::StrictFP),\n" ; |
528 | |
529 | MemoryEffects ME = Intrinsic.ME; |
530 | // TODO: IntrHasSideEffects should affect not only readnone intrinsics. |
531 | if (ME.doesNotAccessMemory() && Intrinsic.hasSideEffects) |
532 | ME = MemoryEffects::unknown(); |
533 | if (ME != MemoryEffects::unknown()) { |
534 | OS << " Attribute::getWithMemoryEffects(C, " |
535 | << "MemoryEffects::createFromIntValue(" << ME.toIntValue() << ")),\n" ; |
536 | } |
537 | OS << " });\n" ; |
538 | } |
539 | OS << " }\n" ; |
540 | OS << "}\n\n" ; |
541 | OS << "AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id) {\n" ; |
542 | |
543 | // Compute the maximum number of attribute arguments and the map |
544 | typedef std::map<const CodeGenIntrinsic *, unsigned, AttributeComparator> |
545 | UniqAttrMapTy; |
546 | UniqAttrMapTy UniqAttributes; |
547 | unsigned maxArgAttrs = 0; |
548 | unsigned AttrNum = 0; |
549 | for (unsigned i = 0, e = Ints.size(); i != e; ++i) { |
550 | const CodeGenIntrinsic &intrinsic = Ints[i]; |
551 | maxArgAttrs = |
552 | std::max(a: maxArgAttrs, b: unsigned(intrinsic.ArgumentAttributes.size())); |
553 | unsigned &N = UniqAttributes[&intrinsic]; |
554 | if (N) |
555 | continue; |
556 | N = ++AttrNum; |
557 | assert(N < 65536 && "Too many unique attributes for table!" ); |
558 | } |
559 | |
560 | // Emit an array of AttributeList. Most intrinsics will have at least one |
561 | // entry, for the function itself (index ~1), which is usually nounwind. |
562 | OS << " static const uint16_t IntrinsicsToAttributesMap[] = {\n" ; |
563 | |
564 | for (unsigned i = 0, e = Ints.size(); i != e; ++i) { |
565 | const CodeGenIntrinsic &intrinsic = Ints[i]; |
566 | |
567 | OS << " " << UniqAttributes[&intrinsic] << ", // " << intrinsic.Name |
568 | << "\n" ; |
569 | } |
570 | OS << " };\n\n" ; |
571 | |
572 | OS << " std::pair<unsigned, AttributeSet> AS[" << maxArgAttrs + 1 << "];\n" ; |
573 | OS << " unsigned NumAttrs = 0;\n" ; |
574 | OS << " if (id != 0) {\n" ; |
575 | OS << " switch(IntrinsicsToAttributesMap[id - 1]) {\n" ; |
576 | OS << " default: llvm_unreachable(\"Invalid attribute number\");\n" ; |
577 | for (auto UniqAttribute : UniqAttributes) { |
578 | OS << " case " << UniqAttribute.second << ": {\n" ; |
579 | |
580 | const CodeGenIntrinsic &Intrinsic = *(UniqAttribute.first); |
581 | |
582 | // Keep track of the number of attributes we're writing out. |
583 | unsigned numAttrs = 0; |
584 | |
585 | for (const auto &[AttrIdx, Attrs] : |
586 | enumerate(First: Intrinsic.ArgumentAttributes)) { |
587 | if (Attrs.empty()) |
588 | continue; |
589 | |
590 | unsigned ID = UniqArgAttributes.find(x: Attrs)->second; |
591 | OS << " AS[" << numAttrs++ << "] = {" << AttrIdx |
592 | << ", getIntrinsicArgAttributeSet(C, " << ID << ")};\n" ; |
593 | } |
594 | |
595 | if (!Intrinsic.canThrow || |
596 | (Intrinsic.ME != MemoryEffects::unknown() && |
597 | !Intrinsic.hasSideEffects) || |
598 | Intrinsic.isNoReturn || Intrinsic.isNoCallback || Intrinsic.isNoSync || |
599 | Intrinsic.isNoFree || Intrinsic.isWillReturn || Intrinsic.isCold || |
600 | Intrinsic.isNoDuplicate || Intrinsic.isNoMerge || |
601 | Intrinsic.isConvergent || Intrinsic.isSpeculatable || |
602 | Intrinsic.isStrictFP) { |
603 | unsigned ID = UniqFnAttributes.find(x: &Intrinsic)->second; |
604 | OS << " AS[" << numAttrs++ << "] = {AttributeList::FunctionIndex, " |
605 | << "getIntrinsicFnAttributeSet(C, " << ID << ")};\n" ; |
606 | } |
607 | |
608 | if (numAttrs) { |
609 | OS << " NumAttrs = " << numAttrs << ";\n" ; |
610 | OS << " break;\n" ; |
611 | OS << " }\n" ; |
612 | } else { |
613 | OS << " return AttributeList();\n" ; |
614 | OS << " }\n" ; |
615 | } |
616 | } |
617 | |
618 | OS << " }\n" ; |
619 | OS << " }\n" ; |
620 | OS << " return AttributeList::get(C, ArrayRef(AS, NumAttrs));\n" ; |
621 | OS << "}\n" ; |
622 | OS << "#endif // GET_INTRINSIC_ATTRIBUTES\n\n" ; |
623 | } |
624 | |
625 | void IntrinsicEmitter::EmitIntrinsicToBuiltinMap( |
626 | const CodeGenIntrinsicTable &Ints, bool IsClang, raw_ostream &OS) { |
627 | StringRef CompilerName = (IsClang ? "Clang" : "MS" ); |
628 | StringRef UpperCompilerName = (IsClang ? "CLANG" : "MS" ); |
629 | typedef std::map<std::string, std::map<std::string, std::string>> BIMTy; |
630 | BIMTy BuiltinMap; |
631 | StringToOffsetTable Table; |
632 | for (unsigned i = 0, e = Ints.size(); i != e; ++i) { |
633 | const std::string &BuiltinName = |
634 | IsClang ? Ints[i].ClangBuiltinName : Ints[i].MSBuiltinName; |
635 | if (!BuiltinName.empty()) { |
636 | // Get the map for this target prefix. |
637 | std::map<std::string, std::string> &BIM = |
638 | BuiltinMap[Ints[i].TargetPrefix]; |
639 | |
640 | if (!BIM.insert(x: std::pair(BuiltinName, Ints[i].EnumName)).second) |
641 | PrintFatalError(ErrorLoc: Ints[i].TheDef->getLoc(), |
642 | Msg: "Intrinsic '" + Ints[i].TheDef->getName() + |
643 | "': duplicate " + CompilerName + " builtin name!" ); |
644 | Table.GetOrAddStringOffset(Str: BuiltinName); |
645 | } |
646 | } |
647 | |
648 | OS << "// Get the LLVM intrinsic that corresponds to a builtin.\n" ; |
649 | OS << "// This is used by the C front-end. The builtin name is passed\n" ; |
650 | OS << "// in as BuiltinName, and a target prefix (e.g. 'ppc') is passed\n" ; |
651 | OS << "// in as TargetPrefix. The result is assigned to 'IntrinsicID'.\n" ; |
652 | OS << "#ifdef GET_LLVM_INTRINSIC_FOR_" << UpperCompilerName << "_BUILTIN\n" ; |
653 | |
654 | OS << "Intrinsic::ID Intrinsic::getIntrinsicFor" << CompilerName |
655 | << "Builtin(const char " |
656 | << "*TargetPrefixStr, StringRef BuiltinNameStr) {\n" ; |
657 | |
658 | if (Table.Empty()) { |
659 | OS << " return Intrinsic::not_intrinsic;\n" ; |
660 | OS << "}\n" ; |
661 | OS << "#endif\n\n" ; |
662 | return; |
663 | } |
664 | |
665 | OS << " static const char BuiltinNames[] = {\n" ; |
666 | Table.EmitCharArray(O&: OS); |
667 | OS << " };\n\n" ; |
668 | |
669 | OS << " struct BuiltinEntry {\n" ; |
670 | OS << " Intrinsic::ID IntrinID;\n" ; |
671 | OS << " unsigned StrTabOffset;\n" ; |
672 | OS << " const char *getName() const {\n" ; |
673 | OS << " return &BuiltinNames[StrTabOffset];\n" ; |
674 | OS << " }\n" ; |
675 | OS << " bool operator<(StringRef RHS) const {\n" ; |
676 | OS << " return strncmp(getName(), RHS.data(), RHS.size()) < 0;\n" ; |
677 | OS << " }\n" ; |
678 | OS << " };\n" ; |
679 | |
680 | OS << " StringRef TargetPrefix(TargetPrefixStr);\n\n" ; |
681 | |
682 | // Note: this could emit significantly better code if we cared. |
683 | for (auto &I : BuiltinMap) { |
684 | OS << " " ; |
685 | if (!I.first.empty()) |
686 | OS << "if (TargetPrefix == \"" << I.first << "\") " ; |
687 | else |
688 | OS << "/* Target Independent Builtins */ " ; |
689 | OS << "{\n" ; |
690 | |
691 | // Emit the comparisons for this target prefix. |
692 | OS << " static const BuiltinEntry " << I.first << "Names[] = {\n" ; |
693 | for (const auto &P : I.second) { |
694 | OS << " {Intrinsic::" << P.second << ", " |
695 | << Table.GetOrAddStringOffset(Str: P.first) << "}, // " << P.first << "\n" ; |
696 | } |
697 | OS << " };\n" ; |
698 | OS << " auto I = std::lower_bound(std::begin(" << I.first << "Names),\n" ; |
699 | OS << " std::end(" << I.first << "Names),\n" ; |
700 | OS << " BuiltinNameStr);\n" ; |
701 | OS << " if (I != std::end(" << I.first << "Names) &&\n" ; |
702 | OS << " I->getName() == BuiltinNameStr)\n" ; |
703 | OS << " return I->IntrinID;\n" ; |
704 | OS << " }\n" ; |
705 | } |
706 | OS << " return " ; |
707 | OS << "Intrinsic::not_intrinsic;\n" ; |
708 | OS << "}\n" ; |
709 | OS << "#endif\n\n" ; |
710 | } |
711 | |
712 | static void EmitIntrinsicEnums(RecordKeeper &RK, raw_ostream &OS) { |
713 | IntrinsicEmitter(RK).run(OS, /*Enums=*/true); |
714 | } |
715 | |
716 | static TableGen::Emitter::Opt X("gen-intrinsic-enums" , EmitIntrinsicEnums, |
717 | "Generate intrinsic enums" ); |
718 | |
719 | static void EmitIntrinsicImpl(RecordKeeper &RK, raw_ostream &OS) { |
720 | IntrinsicEmitter(RK).run(OS, /*Enums=*/false); |
721 | } |
722 | |
723 | static TableGen::Emitter::Opt Y("gen-intrinsic-impl" , EmitIntrinsicImpl, |
724 | "Generate intrinsic information" ); |
725 | |