1//===- CodeGenIntrinsics.cpp - Intrinsic Class Wrapper --------------------===//
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 file defines a wrapper class for the 'Intrinsic' TableGen class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CodeGenIntrinsics.h"
14#include "llvm/ADT/ArrayRef.h"
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/StringSwitch.h"
17#include "llvm/ADT/Twine.h"
18#include "llvm/Support/ErrorHandling.h"
19#include "llvm/Support/FormatVariadic.h"
20#include "llvm/TableGen/Error.h"
21#include "llvm/TableGen/Record.h"
22#include <algorithm>
23#include <cassert>
24using namespace llvm;
25
26// As the type of more than one return values is represented as an anonymous
27// struct, which is encoded with `IIT_STRUCT` followed by a byte specifying
28// the number of return values, starting from 2 (encoded as 0) to 257
29// (encoded as 255). So, the maximum number of values that an intrinsic can
30// return is 257.
31static constexpr unsigned MaxNumReturn = 257;
32
33//===----------------------------------------------------------------------===//
34// CodeGenIntrinsic Implementation
35//===----------------------------------------------------------------------===//
36
37CodeGenIntrinsicContext::CodeGenIntrinsicContext(const RecordKeeper &RC) {
38 for (const Record *Rec : RC.getAllDerivedDefinitions(ClassName: "IntrinsicProperty"))
39 if (Rec->getValueAsBit(FieldName: "IsDefault"))
40 DefaultProperties.push_back(x: Rec);
41}
42
43CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC) {
44 CodeGenIntrinsicContext Ctx(RC);
45
46 ArrayRef<const Record *> Defs = RC.getAllDerivedDefinitions(ClassName: "Intrinsic");
47 Intrinsics.reserve(n: Defs.size());
48
49 for (const Record *Def : Defs)
50 Intrinsics.emplace_back(args: CodeGenIntrinsic(Def, Ctx));
51
52 llvm::sort(C&: Intrinsics,
53 Comp: [](const CodeGenIntrinsic &LHS, const CodeGenIntrinsic &RHS) {
54 // Order target independent intrinsics before target dependent
55 // ones.
56 bool LHSHasTarget = !LHS.TargetPrefix.empty();
57 bool RHSHasTarget = !RHS.TargetPrefix.empty();
58
59 // To ensure deterministic sorted order when duplicates are
60 // present, use record ID as a tie-breaker similar to
61 // sortAndReportDuplicates in Utils.cpp.
62 unsigned LhsID = LHS.TheDef->getID();
63 unsigned RhsID = RHS.TheDef->getID();
64
65 return std::tie(args&: LHSHasTarget, args: LHS.Name, args&: LhsID) <
66 std::tie(args&: RHSHasTarget, args: RHS.Name, args&: RhsID);
67 });
68
69 Targets.push_back(x: {.Name: "", .Offset: 0, .Count: 0});
70 for (size_t I = 0, E = Intrinsics.size(); I < E; ++I)
71 if (Intrinsics[I].TargetPrefix != Targets.back().Name) {
72 Targets.back().Count = I - Targets.back().Offset;
73 Targets.push_back(x: {.Name: Intrinsics[I].TargetPrefix, .Offset: I, .Count: 0});
74 }
75 Targets.back().Count = Intrinsics.size() - Targets.back().Offset;
76
77 CheckDuplicateIntrinsics();
78 CheckTargetIndependentIntrinsics();
79 CheckOverloadSuffixConflicts();
80}
81
82// Check for duplicate intrinsic names.
83void CodeGenIntrinsicTable::CheckDuplicateIntrinsics() const {
84 // Since the Intrinsics vector is already sorted by name, if there are 2 or
85 // more intrinsics with duplicate names, they will appear adjacent in sorted
86 // order. Note that if the intrinsic name was derived from the record name
87 // there cannot be be duplicate as TableGen parser would have flagged that.
88 // However, if the name was specified in the intrinsic definition, then its
89 // possible to have duplicate names.
90 auto I = std::adjacent_find(
91 first: Intrinsics.begin(), last: Intrinsics.end(),
92 binary_pred: [](const CodeGenIntrinsic &Int1, const CodeGenIntrinsic &Int2) {
93 return Int1.Name == Int2.Name;
94 });
95 if (I == Intrinsics.end())
96 return;
97
98 // Found a duplicate intrinsics.
99 const CodeGenIntrinsic &First = *I;
100 const CodeGenIntrinsic &Second = *(I + 1);
101 PrintError(Rec: Second.TheDef,
102 Msg: Twine("Intrinsic `") + First.Name + "` is already defined");
103 PrintFatalNote(Rec: First.TheDef, Msg: "Previous definition here");
104}
105
106// For target independent intrinsics, check that their second dotted component
107// does not match any target name.
108void CodeGenIntrinsicTable::CheckTargetIndependentIntrinsics() const {
109 SmallDenseSet<StringRef> TargetNames;
110 for (const auto &Target : ArrayRef(Targets).drop_front())
111 TargetNames.insert(V: Target.Name);
112
113 // Set of target independent intrinsics.
114 const auto &Set = Targets[0];
115 for (const auto &Int : ArrayRef(&Intrinsics[Set.Offset], Set.Count)) {
116 StringRef Name = Int.Name;
117 StringRef Prefix = Name.drop_front(N: 5).split(Separator: '.').first;
118 if (!TargetNames.contains(V: Prefix))
119 continue;
120 PrintFatalError(Rec: Int.TheDef,
121 Msg: "target independent intrinsic `" + Name +
122 "' has prefix `llvm." + Prefix +
123 "` that conflicts with intrinsics for target `" +
124 Prefix + "`");
125 }
126}
127
128// Return true if the given Suffix looks like a mangled type. Note that this
129// check is conservative, but allows all existing LLVM intrinsic suffixes to be
130// considered as not looking like a mangling suffix.
131static bool doesSuffixLookLikeMangledType(StringRef Suffix) {
132 // Try to match against possible mangling suffixes for various types.
133 // See getMangledTypeStr() for the mangling suffixes possible. It includes
134 // pointer : p[0-9]+
135 // array : a[0-9]+.+
136 // struct: : s_/sl_.+
137 // function : f_.+
138 // vector : v/nxv[0-9]+.+
139 // target type : t.+
140 // integer : i[0-9]+
141 // named types : See `NamedTypes` below.
142
143 // Match anything with an _, so match function and struct types.
144 if (Suffix.contains(C: '_'))
145 return true;
146
147 // [av][0-9]+.+, simplified to [av][0-9].+
148 if (Suffix.size() >= 2 && is_contained(Range: "av", Element: Suffix[0]) && isDigit(C: Suffix[1]))
149 return true;
150
151 // nxv[0-9]+.+, simplified to nxv[0-9].+
152 if (Suffix.size() >= 4 && Suffix.starts_with(Prefix: "nxv") && isDigit(C: Suffix[3]))
153 return true;
154
155 // t.+
156 if (Suffix.size() > 1 && Suffix.starts_with(Prefix: 't'))
157 return false;
158
159 // [pi][0-9]+
160 if (Suffix.size() > 1 && is_contained(Range: "pi", Element: Suffix[0]) &&
161 all_of(Range: Suffix.drop_front(), P: isDigit))
162 return true;
163
164 // Match one of the named types.
165 static constexpr StringLiteral NamedTypes[] = {
166 "isVoid", "Metadata", "f16", "f32", "f64",
167 "f80", "f128", "bf16", "ppcf128", "x86amx"};
168 return is_contained(Range: NamedTypes, Element: Suffix);
169}
170
171// Check for conflicts with overloaded intrinsics. If there exists an overloaded
172// intrinsic with base name `llvm.target.foo`, LLVM will add a mangling suffix
173// to it to encode the overload types. This mangling suffix is 1 or more .
174// prefixed mangled type string as defined in `getMangledTypeStr`. If there
175// exists another intrinsic `llvm.target.foo[.<suffixN>]+`, which has the same
176// prefix as the overloaded intrinsic, its possible that there may be a name
177// conflict with the overloaded intrinsic and either one may interfere with name
178// lookup for the other, leading to wrong intrinsic ID being assigned.
179//
180// The actual name lookup in the intrinsic name table is done by a search
181// on each successive '.' separted component of the intrinsic name (see
182// `lookupLLVMIntrinsicByName`). Consider first the case where there exists a
183// non-overloaded intrinsic `llvm.target.foo[.suffix]+`. For the non-overloaded
184// intrinsics, the name lookup is an exact match, so the presence of the
185// overloaded intrinsic with the same prefix will not interfere with the
186// search. However, a lookup intended to match the overloaded intrinsic might be
187// affected by the presence of another entry in the name table with the same
188// prefix.
189//
190// Since LLVM's name lookup first selects the target specific (or target
191// independent) slice of the name table to look into, intrinsics in 2 different
192// targets cannot conflict with each other. Within a specific target,
193// if we have an overloaded intrinsic with name `llvm.target.foo` and another
194// one with same prefix and one or more suffixes `llvm.target.foo[.<suffixN>]+`,
195// then the name search will try to first match against suffix0, then suffix1
196// etc. If suffix0 can match a mangled type, then the search for an
197// `llvm.target.foo` with a mangling suffix can match against suffix0,
198// preventing a match with `llvm.target.foo`. If suffix0 cannot match a mangled
199// type, then that cannot happen, so we do not need to check for later suffixes.
200//
201// Generalizing, the `llvm.target.foo[.suffixN]+` will cause a conflict if the
202// first suffix (.suffix0) can match a mangled type (and then we do not need to
203// check later suffixes) and will not cause a conflict if it cannot (and then
204// again, we do not need to check for later suffixes).
205void CodeGenIntrinsicTable::CheckOverloadSuffixConflicts() const {
206 for (const TargetSet &Set : Targets) {
207 const CodeGenIntrinsic *Overloaded = nullptr;
208 for (const CodeGenIntrinsic &Int : (*this)[Set]) {
209 // If we do not have an overloaded intrinsic to check against, nothing
210 // to do except potentially identifying this as a candidate for checking
211 // against in future iteration.
212 if (!Overloaded) {
213 if (Int.isOverloaded)
214 Overloaded = &Int;
215 continue;
216 }
217
218 StringRef Name = Int.Name;
219 StringRef OverloadName = Overloaded->Name;
220 // If we have an overloaded intrinsic to check again, check if its name is
221 // a proper prefix of this intrinsic.
222 if (Name.starts_with(Prefix: OverloadName) && Name[OverloadName.size()] == '.') {
223 // If yes, verify suffixes and flag an error.
224 StringRef Suffixes = Name.drop_front(N: OverloadName.size() + 1);
225
226 // Only need to look at the first suffix.
227 StringRef Suffix0 = Suffixes.split(Separator: '.').first;
228
229 if (!doesSuffixLookLikeMangledType(Suffix: Suffix0))
230 continue;
231
232 unsigned SuffixSize = OverloadName.size() + 1 + Suffix0.size();
233 // If suffix looks like mangling suffix, flag it as an error.
234 PrintError(ErrorLoc: Int.TheDef->getLoc(),
235 Msg: "intrinsic `" + Name + "` cannot share prefix `" +
236 Name.take_front(N: SuffixSize) +
237 "` with another overloaded intrinsic `" + OverloadName +
238 "`");
239 PrintNote(NoteLoc: Overloaded->TheDef->getLoc(),
240 Msg: "Overloaded intrinsic `" + OverloadName + "` defined here");
241 continue;
242 }
243
244 // If we find an intrinsic that is not a proper prefix, any later
245 // intrinsic is also not going to be a proper prefix, so invalidate the
246 // overloaded to check against.
247 Overloaded = nullptr;
248 }
249 }
250}
251
252const CodeGenIntrinsic &CodeGenIntrinsicMap::operator[](const Record *Record) {
253 if (!Record->isSubClassOf(Name: "Intrinsic"))
254 PrintFatalError(Msg: "Intrinsic defs should be subclass of 'Intrinsic' class");
255
256 auto [Iter, Inserted] = Map.try_emplace(Key: Record);
257 if (Inserted)
258 Iter->second = std::make_unique<CodeGenIntrinsic>(args&: Record, args: Ctx);
259 return *Iter->second;
260}
261
262CodeGenIntrinsic::CodeGenIntrinsic(const Record *R,
263 const CodeGenIntrinsicContext &Ctx)
264 : TheDef(R) {
265 StringRef DefName = TheDef->getName();
266 ArrayRef<SMLoc> DefLoc = R->getLoc();
267
268 if (!DefName.starts_with(Prefix: "int_"))
269 PrintFatalError(ErrorLoc: DefLoc,
270 Msg: "Intrinsic '" + DefName + "' does not start with 'int_'!");
271
272 EnumName = DefName.substr(Start: 4);
273
274 // Ignore a missing ClangBuiltinName field.
275 ClangBuiltinName =
276 R->getValueAsOptionalString(FieldName: "ClangBuiltinName").value_or(u: "");
277 // Ignore a missing MSBuiltinName field.
278 MSBuiltinName = R->getValueAsOptionalString(FieldName: "MSBuiltinName").value_or(u: "");
279
280 TargetPrefix = R->getValueAsString(FieldName: "TargetPrefix");
281 Name = R->getValueAsString(FieldName: "LLVMName").str();
282
283 std::string DefaultName = "llvm." + EnumName.str();
284 llvm::replace(Range&: DefaultName, OldValue: '_', NewValue: '.');
285
286 if (Name == "") {
287 // If an explicit name isn't specified, derive one from the DefName.
288 Name = std::move(DefaultName);
289 } else {
290 // Verify it starts with "llvm.".
291 if (!StringRef(Name).starts_with(Prefix: "llvm."))
292 PrintFatalError(ErrorLoc: DefLoc, Msg: "Intrinsic '" + DefName +
293 "'s name does not start with 'llvm.'!");
294
295 if (Name == DefaultName)
296 PrintNote(NoteLoc: DefLoc, Msg: "Explicitly specified name matches default name, "
297 "consider dropping it");
298 }
299
300 // If TargetPrefix is specified, make sure that Name starts with
301 // "llvm.<targetprefix>.".
302 if (!TargetPrefix.empty()) {
303 StringRef Prefix = StringRef(Name).drop_front(N: 5); // Drop llvm.
304 if (!Prefix.consume_front(Prefix: TargetPrefix) || !Prefix.starts_with(Prefix: '.'))
305 PrintFatalError(ErrorLoc: DefLoc, Msg: "Intrinsic '" + DefName +
306 "' does not start with 'llvm." +
307 TargetPrefix + ".'!");
308 }
309
310 unsigned NumRet = R->getValueAsListInit(FieldName: "RetTypes")->size();
311 unsigned NumParam = R->getValueAsListInit(FieldName: "ParamTypes")->size();
312
313 if (NumRet > MaxNumReturn)
314 PrintFatalError(ErrorLoc: DefLoc, Msg: "intrinsics can only return upto " +
315 Twine(MaxNumReturn) + " values, '" + DefName +
316 "' returns " + Twine(NumRet) + " values");
317
318 const Record *TypeInfo = R->getValueAsDef(FieldName: "TypeInfo");
319 if (!TypeInfo->isSubClassOf(Name: "TypeInfoGen"))
320 PrintFatalError(ErrorLoc: DefLoc, Msg: "TypeInfo field in " + DefName +
321 " should be of subclass of TypeInfoGen!");
322
323 isOverloaded = TypeInfo->getValueAsBit(FieldName: "isOverloaded");
324 std::vector<const Record *> AllTypes =
325 TypeInfo->getValueAsListOfDefs(FieldName: "AllTypes");
326
327 // Validate overload index values in dependent types.
328 if (isOverloaded) {
329 const ListInit *OverloadedTypes =
330 TypeInfo->getValueAsListInit(FieldName: "OverloadTypes");
331 unsigned NumOverloadedTypes = OverloadedTypes->size();
332 for (const auto &[Idx, Ty] : enumerate(First&: AllTypes)) {
333 if (!Ty->isSubClassOf(Name: "LLVMDependentType"))
334 continue;
335 unsigned OverloadIndex = Ty->getValueAsInt(FieldName: "OverloadIndex");
336 if (OverloadIndex >= NumOverloadedTypes)
337 PrintFatalError(
338 Rec: Ty, Msg: formatv(Fmt: "for intrinsic {} overload index {} is invalid, "
339 "intrinsic only has {} overloaded types",
340 Vals&: DefName, Vals&: OverloadIndex, Vals&: NumOverloadedTypes));
341 const Record *OTy = OverloadedTypes->getElementAsRecord(Idx: OverloadIndex);
342 if (!OTy->isSubClassOf(Name: "LLVMAnyType"))
343 PrintFatalError(Rec: Ty, Msg: formatv(Fmt: "for intrinsic {} overload index {} is "
344 "invalid, dependent types must reference "
345 "an overload index of an \'llvm_any\' type",
346 Vals&: DefName, Vals&: OverloadIndex));
347
348 // Replace the dependent type with the overloaded type it references.
349 AllTypes[Idx] = OTy;
350 }
351 }
352
353 ArrayRef<const Record *> AllTypesRef = AllTypes;
354
355 // Types field is a concatenation of Return types followed by Param types.
356 for (const Record *RetTy : AllTypesRef.take_front(N: NumRet)) {
357 if (RetTy->getName() == "llvm_vararg_ty")
358 PrintFatalError(ErrorLoc: DefLoc, Msg: "cannot use llvm_vararg_ty as a return type");
359 IS.RetTys.push_back(x: RetTy);
360 }
361
362 for (const auto &[Idx, ParamTy] : enumerate(First: AllTypesRef.drop_front(N: NumRet))) {
363 if (Idx != NumParam - 1 && ParamTy->getName() == "llvm_vararg_ty")
364 PrintFatalError(ErrorLoc: DefLoc,
365 Msg: "llvm_vararg_ty can only be the last parameter type");
366 IS.ParamTys.push_back(x: ParamTy);
367 }
368
369 // Parse the intrinsic properties.
370 const ListInit *PropList = R->getValueAsListInit(FieldName: "IntrProperties");
371 for (unsigned i = 0, e = PropList->size(); i != e; ++i) {
372 const Record *Property = PropList->getElementAsRecord(Idx: i);
373 assert(Property->isSubClassOf("IntrinsicProperty") &&
374 "Expected a property!");
375
376 setProperty(Property);
377 }
378
379 // Set default properties to true.
380 setDefaultProperties(Ctx.DefaultProperties);
381
382 // Also record the SDPatternOperator Properties.
383 Properties = parseSDPatternOperatorProperties(R);
384
385 // Sort the argument attributes for later benefit.
386 for (auto &Attrs : ArgumentAttributes)
387 llvm::sort(C&: Attrs);
388}
389
390void CodeGenIntrinsic::setDefaultProperties(
391 ArrayRef<const Record *> DefaultProperties) {
392 // opt-out of using default attributes.
393 if (TheDef->getValueAsBit(FieldName: "DisableDefaultAttributes"))
394 return;
395
396 for (const Record *Rec : DefaultProperties)
397 setProperty(Rec);
398}
399
400void CodeGenIntrinsic::setProperty(const Record *R) {
401 if (R->getName() == "IntrNoMem")
402 ME = MemoryEffects::none();
403 else if (R->getName() == "IntrReadMem") {
404 if (ME.onlyWritesMemory())
405 PrintFatalError(ErrorLoc: TheDef->getLoc(),
406 Msg: Twine("IntrReadMem cannot be used after IntrNoMem or "
407 "IntrWriteMem. Default is ReadWrite"));
408 ME &= MemoryEffects::readOnly();
409 } else if (R->getName() == "IntrWriteMem") {
410 if (ME.onlyReadsMemory())
411 PrintFatalError(ErrorLoc: TheDef->getLoc(),
412 Msg: Twine("IntrWriteMem cannot be used after IntrNoMem or "
413 "IntrReadMem. Default is ReadWrite"));
414 ME &= MemoryEffects::writeOnly();
415 } else if (R->getName() == "IntrArgMemOnly")
416 ME &= MemoryEffects::argMemOnly();
417 else if (R->getName() == "IntrInaccessibleMemOnly")
418 ME &= MemoryEffects::inaccessibleMemOnly();
419 else if (R->isSubClassOf(Name: "IntrRead")) {
420 MemoryEffects ReadMask = MemoryEffects::writeOnly();
421 for (const Record *RLoc : R->getValueAsListOfDefs(FieldName: "MemLoc"))
422 ReadMask = ReadMask.getWithModRef(Loc: getValueAsIRMemLocation(R: RLoc),
423 MR: ModRefInfo::ModRef);
424 ME &= ReadMask;
425 } else if (R->isSubClassOf(Name: "IntrWrite")) {
426 MemoryEffects WriteMask = MemoryEffects::readOnly();
427 for (const Record *WLoc : R->getValueAsListOfDefs(FieldName: "MemLoc"))
428 WriteMask = WriteMask.getWithModRef(Loc: getValueAsIRMemLocation(R: WLoc),
429 MR: ModRefInfo::ModRef);
430 ME &= WriteMask;
431 } else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly")
432 ME &= MemoryEffects::inaccessibleOrArgMemOnly();
433 else if (R->getName() == "Commutative")
434 isCommutative = true;
435 else if (R->getName() == "Throws")
436 canThrow = true;
437 else if (R->getName() == "IntrNoDuplicate")
438 isNoDuplicate = true;
439 else if (R->getName() == "IntrNoMerge")
440 isNoMerge = true;
441 else if (R->getName() == "IntrConvergent")
442 isConvergent = true;
443 else if (R->getName() == "IntrNoReturn")
444 isNoReturn = true;
445 else if (R->getName() == "IntrNoCallback")
446 isNoCallback = true;
447 else if (R->getName() == "IntrNoSync")
448 isNoSync = true;
449 else if (R->getName() == "IntrNoFree")
450 isNoFree = true;
451 else if (R->getName() == "IntrWillReturn")
452 isWillReturn = !isNoReturn;
453 else if (R->getName() == "IntrCold")
454 isCold = true;
455 else if (R->getName() == "IntrSpeculatable")
456 isSpeculatable = true;
457 else if (R->getName() == "IntrHasSideEffects")
458 hasSideEffects = true;
459 else if (R->getName() == "IntrStrictFP")
460 isStrictFP = true;
461 else if (R->getName() == "IntrNoCreateUndefOrPoison")
462 isNoCreateUndefOrPoison = true;
463 else if (R->getName() == "IntrTriviallyScalarizable")
464 isTriviallyScalarizable = true;
465 else if (R->isSubClassOf(Name: "NoCapture")) {
466 unsigned ArgNo = R->getValueAsInt(FieldName: "ArgNo");
467 addArgAttribute(Idx: ArgNo, AK: NoCapture);
468 } else if (R->isSubClassOf(Name: "NoAlias")) {
469 unsigned ArgNo = R->getValueAsInt(FieldName: "ArgNo");
470 addArgAttribute(Idx: ArgNo, AK: NoAlias);
471 } else if (R->isSubClassOf(Name: "NoUndef")) {
472 unsigned ArgNo = R->getValueAsInt(FieldName: "ArgNo");
473 addArgAttribute(Idx: ArgNo, AK: NoUndef);
474 } else if (R->isSubClassOf(Name: "NonNull")) {
475 unsigned ArgNo = R->getValueAsInt(FieldName: "ArgNo");
476 addArgAttribute(Idx: ArgNo, AK: NonNull);
477 } else if (R->isSubClassOf(Name: "Returned")) {
478 unsigned ArgNo = R->getValueAsInt(FieldName: "ArgNo");
479 addArgAttribute(Idx: ArgNo, AK: Returned);
480 } else if (R->isSubClassOf(Name: "ReadOnly")) {
481 unsigned ArgNo = R->getValueAsInt(FieldName: "ArgNo");
482 addArgAttribute(Idx: ArgNo, AK: ReadOnly);
483 } else if (R->isSubClassOf(Name: "WriteOnly")) {
484 unsigned ArgNo = R->getValueAsInt(FieldName: "ArgNo");
485 addArgAttribute(Idx: ArgNo, AK: WriteOnly);
486 } else if (R->isSubClassOf(Name: "ReadNone")) {
487 unsigned ArgNo = R->getValueAsInt(FieldName: "ArgNo");
488 addArgAttribute(Idx: ArgNo, AK: ReadNone);
489 } else if (R->isSubClassOf(Name: "ImmArg")) {
490 unsigned ArgNo = R->getValueAsInt(FieldName: "ArgNo");
491 addArgAttribute(Idx: ArgNo, AK: ImmArg);
492 } else if (R->isSubClassOf(Name: "Align")) {
493 unsigned ArgNo = R->getValueAsInt(FieldName: "ArgNo");
494 uint64_t Align = R->getValueAsInt(FieldName: "Align");
495 addArgAttribute(Idx: ArgNo, AK: Alignment, V: Align);
496 } else if (R->isSubClassOf(Name: "Dereferenceable")) {
497 unsigned ArgNo = R->getValueAsInt(FieldName: "ArgNo");
498 uint64_t Bytes = R->getValueAsInt(FieldName: "Bytes");
499 addArgAttribute(Idx: ArgNo, AK: Dereferenceable, V: Bytes);
500 } else if (R->isSubClassOf(Name: "Range")) {
501 unsigned ArgNo = R->getValueAsInt(FieldName: "ArgNo");
502 int64_t Lower = R->getValueAsInt(FieldName: "Lower");
503 int64_t Upper = R->getValueAsInt(FieldName: "Upper");
504 addArgAttribute(Idx: ArgNo, AK: Range, V: Lower, V2: Upper);
505 } else if (R->isSubClassOf(Name: "ArgInfo")) {
506 unsigned ArgNo = R->getValueAsInt(FieldName: "ArgNo");
507 if (ArgNo < 1)
508 PrintFatalError(ErrorLoc: R->getLoc(),
509 Msg: "ArgInfo requires ArgNo >= 1 (0 is return value)");
510 const ListInit *Properties = R->getValueAsListInit(FieldName: "Properties");
511 StringRef ArgName;
512 StringRef FuncName;
513
514 for (const Init *PropInit : Properties->getElements()) {
515 if (const auto *PropDef = dyn_cast<DefInit>(Val: PropInit)) {
516 const Record *PropRec = PropDef->getDef();
517
518 if (PropRec->isSubClassOf(Name: "ArgName"))
519 ArgName = PropRec->getValueAsString(FieldName: "Name");
520 else if (PropRec->isSubClassOf(Name: "ImmArgPrinter"))
521 FuncName = PropRec->getValueAsString(FieldName: "FuncName");
522 else
523 PrintFatalError(ErrorLoc: PropRec->getLoc(),
524 Msg: "Unknown ArgProperty type: " + PropRec->getName());
525 }
526 }
527 addPrettyPrintFunction(ArgIdx: ArgNo - 1, ArgName, FuncName);
528 } else {
529 llvm_unreachable("Unknown property!");
530 }
531}
532
533llvm::IRMemLocation
534CodeGenIntrinsic::getValueAsIRMemLocation(const Record *R) const {
535 StringRef Name = R->getName();
536 IRMemLocation Loc =
537 StringSwitch<IRMemLocation>(Name)
538 .Case(S: "ArgMem", Value: IRMemLocation::ArgMem)
539 .Case(S: "TargetMem0", Value: IRMemLocation::TargetMem0)
540 .Case(S: "TargetMem1", Value: IRMemLocation::TargetMem1)
541 .Case(S: "InaccessibleMem", Value: IRMemLocation::InaccessibleMem)
542 .Default(Value: IRMemLocation::Other); // fallback enum
543
544 if (Loc == IRMemLocation::Other)
545 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "unknown IRMemLocation: " + Name);
546
547 return Loc;
548}
549
550bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const {
551 if (ParamIdx >= IS.ParamTys.size())
552 return false;
553 return IS.ParamTys[ParamIdx]->isSubClassOf(Name: "LLVMQualPointerType") ||
554 IS.ParamTys[ParamIdx]->isSubClassOf(Name: "LLVMAnyPointerType");
555}
556
557bool CodeGenIntrinsic::isParamImmArg(unsigned ParamIdx) const {
558 // Convert argument index to attribute index starting from `FirstArgIndex`.
559 ++ParamIdx;
560 if (ParamIdx >= ArgumentAttributes.size())
561 return false;
562 ArgAttribute Val{ImmArg, 0, 0};
563 return llvm::binary_search(Range: ArgumentAttributes[ParamIdx], Value&: Val);
564}
565
566void CodeGenIntrinsic::addArgAttribute(unsigned Idx, ArgAttrKind AK, uint64_t V,
567 uint64_t V2) {
568 if (Idx >= ArgumentAttributes.size())
569 ArgumentAttributes.resize(N: Idx + 1);
570 ArgumentAttributes[Idx].emplace_back(Args&: AK, Args&: V, Args&: V2);
571}
572
573void CodeGenIntrinsic::addPrettyPrintFunction(unsigned ArgIdx,
574 StringRef ArgName,
575 StringRef FuncName) {
576 auto It = llvm::find_if(Range&: PrettyPrintFunctions, P: [ArgIdx](const auto &Info) {
577 return Info.ArgIdx == ArgIdx;
578 });
579 if (It != PrettyPrintFunctions.end())
580 PrintFatalError(ErrorLoc: TheDef->getLoc(), Msg: "ArgInfo for argument " + Twine(ArgIdx) +
581 " is already defined as '" +
582 It->FuncName + "'");
583 PrettyPrintFunctions.emplace_back(Args&: ArgIdx, Args&: ArgName, Args&: FuncName);
584}
585