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