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