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