1//===- Attributes.cpp - Implement AttributesList --------------------------===//
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// \file
10// This file implements the Attribute, AttributeImpl, AttrBuilder,
11// AttributeListImpl, and AttributeList classes.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/IR/Attributes.h"
16#include "AttributeImpl.h"
17#include "LLVMContextImpl.h"
18#include "llvm/ADT/ArrayRef.h"
19#include "llvm/ADT/FoldingSet.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/ADT/StringRef.h"
24#include "llvm/ADT/StringSwitch.h"
25#include "llvm/Config/llvm-config.h"
26#include "llvm/IR/AttributeMask.h"
27#include "llvm/IR/ConstantRange.h"
28#include "llvm/IR/ConstantRangeList.h"
29#include "llvm/IR/Function.h"
30#include "llvm/IR/LLVMContext.h"
31#include "llvm/IR/Operator.h"
32#include "llvm/IR/Type.h"
33#include "llvm/Support/Compiler.h"
34#include "llvm/Support/ErrorHandling.h"
35#include "llvm/Support/ModRef.h"
36#include "llvm/Support/raw_ostream.h"
37#include <algorithm>
38#include <cassert>
39#include <cstddef>
40#include <cstdint>
41#include <limits>
42#include <optional>
43#include <string>
44#include <tuple>
45#include <utility>
46
47using namespace llvm;
48
49//===----------------------------------------------------------------------===//
50// Attribute Construction Methods
51//===----------------------------------------------------------------------===//
52
53// allocsize has two integer arguments, but because they're both 32 bits, we can
54// pack them into one 64-bit value, at the cost of making said value
55// nonsensical.
56//
57// In order to do this, we need to reserve one value of the second (optional)
58// allocsize argument to signify "not present."
59static const unsigned AllocSizeNumElemsNotPresent = -1;
60
61static uint64_t packAllocSizeArgs(unsigned ElemSizeArg,
62 const std::optional<unsigned> &NumElemsArg) {
63 assert((!NumElemsArg || *NumElemsArg != AllocSizeNumElemsNotPresent) &&
64 "Attempting to pack a reserved value");
65
66 return uint64_t(ElemSizeArg) << 32 |
67 NumElemsArg.value_or(u: AllocSizeNumElemsNotPresent);
68}
69
70static std::pair<unsigned, std::optional<unsigned>>
71unpackAllocSizeArgs(uint64_t Num) {
72 unsigned NumElems = Num & std::numeric_limits<unsigned>::max();
73 unsigned ElemSizeArg = Num >> 32;
74
75 std::optional<unsigned> NumElemsArg;
76 if (NumElems != AllocSizeNumElemsNotPresent)
77 NumElemsArg = NumElems;
78 return std::make_pair(x&: ElemSizeArg, y&: NumElemsArg);
79}
80
81static uint64_t packVScaleRangeArgs(unsigned MinValue,
82 std::optional<unsigned> MaxValue) {
83 return uint64_t(MinValue) << 32 | MaxValue.value_or(u: 0);
84}
85
86static std::pair<unsigned, std::optional<unsigned>>
87unpackVScaleRangeArgs(uint64_t Value) {
88 unsigned MaxValue = Value & std::numeric_limits<unsigned>::max();
89 unsigned MinValue = Value >> 32;
90
91 return std::make_pair(x&: MinValue,
92 y: MaxValue > 0 ? MaxValue : std::optional<unsigned>());
93}
94
95Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
96 uint64_t Val) {
97 bool IsIntAttr = Attribute::isIntAttrKind(Kind);
98 assert((IsIntAttr || Attribute::isEnumAttrKind(Kind)) &&
99 "Not an enum or int attribute");
100
101 LLVMContextImpl *pImpl = Context.pImpl;
102 FoldingSetNodeID ID;
103 ID.AddInteger(I: Kind);
104 if (IsIntAttr)
105 ID.AddInteger(I: Val);
106 else
107 assert(Val == 0 && "Value must be zero for enum attributes");
108
109 void *InsertPoint;
110 AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPos&: InsertPoint);
111
112 if (!PA) {
113 // If we didn't find any existing attributes of the same shape then create a
114 // new one and insert it.
115 if (!IsIntAttr)
116 PA = new (pImpl->Alloc) EnumAttributeImpl(Kind);
117 else
118 PA = new (pImpl->Alloc) IntAttributeImpl(Kind, Val);
119 pImpl->AttrsSet.InsertNode(N: PA, InsertPos: InsertPoint);
120 }
121
122 // Return the Attribute that we found or created.
123 return Attribute(PA);
124}
125
126Attribute Attribute::get(LLVMContext &Context, StringRef Kind, StringRef Val) {
127 LLVMContextImpl *pImpl = Context.pImpl;
128 FoldingSetNodeID ID;
129 ID.AddString(String: Kind);
130 if (!Val.empty()) ID.AddString(String: Val);
131
132 void *InsertPoint;
133 AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPos&: InsertPoint);
134
135 if (!PA) {
136 // If we didn't find any existing attributes of the same shape then create a
137 // new one and insert it.
138 void *Mem =
139 pImpl->Alloc.Allocate(Size: StringAttributeImpl::totalSizeToAlloc(Kind, Val),
140 Alignment: alignof(StringAttributeImpl));
141 PA = new (Mem) StringAttributeImpl(Kind, Val);
142 pImpl->AttrsSet.InsertNode(N: PA, InsertPos: InsertPoint);
143 }
144
145 // Return the Attribute that we found or created.
146 return Attribute(PA);
147}
148
149Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
150 Type *Ty) {
151 assert(Attribute::isTypeAttrKind(Kind) && "Not a type attribute");
152 LLVMContextImpl *pImpl = Context.pImpl;
153 FoldingSetNodeID ID;
154 ID.AddInteger(I: Kind);
155 ID.AddPointer(Ptr: Ty);
156
157 void *InsertPoint;
158 AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPos&: InsertPoint);
159
160 if (!PA) {
161 // If we didn't find any existing attributes of the same shape then create a
162 // new one and insert it.
163 PA = new (pImpl->Alloc) TypeAttributeImpl(Kind, Ty);
164 pImpl->AttrsSet.InsertNode(N: PA, InsertPos: InsertPoint);
165 }
166
167 // Return the Attribute that we found or created.
168 return Attribute(PA);
169}
170
171Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
172 const ConstantRange &CR) {
173 assert(Attribute::isConstantRangeAttrKind(Kind) &&
174 "Not a ConstantRange attribute");
175 assert(!CR.isFullSet() && "ConstantRange attribute must not be full");
176 LLVMContextImpl *pImpl = Context.pImpl;
177 FoldingSetNodeID ID;
178 ID.AddInteger(I: Kind);
179 CR.getLower().Profile(id&: ID);
180 CR.getUpper().Profile(id&: ID);
181
182 void *InsertPoint;
183 AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPos&: InsertPoint);
184
185 if (!PA) {
186 // If we didn't find any existing attributes of the same shape then create a
187 // new one and insert it.
188 PA = new (pImpl->ConstantRangeAttributeAlloc.Allocate())
189 ConstantRangeAttributeImpl(Kind, CR);
190 pImpl->AttrsSet.InsertNode(N: PA, InsertPos: InsertPoint);
191 }
192
193 // Return the Attribute that we found or created.
194 return Attribute(PA);
195}
196
197Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
198 ArrayRef<ConstantRange> Val) {
199 assert(Attribute::isConstantRangeListAttrKind(Kind) &&
200 "Not a ConstantRangeList attribute");
201 LLVMContextImpl *pImpl = Context.pImpl;
202 FoldingSetNodeID ID;
203 ID.AddInteger(I: Kind);
204 ID.AddInteger(I: Val.size());
205 for (auto &CR : Val) {
206 CR.getLower().Profile(id&: ID);
207 CR.getUpper().Profile(id&: ID);
208 }
209
210 void *InsertPoint;
211 AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPos&: InsertPoint);
212
213 if (!PA) {
214 // If we didn't find any existing attributes of the same shape then create a
215 // new one and insert it.
216 // ConstantRangeListAttributeImpl is a dynamically sized class and cannot
217 // use SpecificBumpPtrAllocator. Instead, we use normal Alloc for
218 // allocation and record the allocated pointer in
219 // `ConstantRangeListAttributes`. LLVMContext destructor will call the
220 // destructor of the allocated pointer explicitly.
221 void *Mem = pImpl->Alloc.Allocate(
222 Size: ConstantRangeListAttributeImpl::totalSizeToAlloc(Val),
223 Alignment: alignof(ConstantRangeListAttributeImpl));
224 PA = new (Mem) ConstantRangeListAttributeImpl(Kind, Val);
225 pImpl->AttrsSet.InsertNode(N: PA, InsertPos: InsertPoint);
226 pImpl->ConstantRangeListAttributes.push_back(
227 x: reinterpret_cast<ConstantRangeListAttributeImpl *>(PA));
228 }
229
230 // Return the Attribute that we found or created.
231 return Attribute(PA);
232}
233
234Attribute Attribute::getWithAlignment(LLVMContext &Context, Align A) {
235 assert(A <= llvm::Value::MaximumAlignment && "Alignment too large.");
236 return get(Context, Kind: Alignment, Val: A.value());
237}
238
239Attribute Attribute::getWithStackAlignment(LLVMContext &Context, Align A) {
240 assert(A <= 0x100 && "Alignment too large.");
241 return get(Context, Kind: StackAlignment, Val: A.value());
242}
243
244Attribute Attribute::getWithDereferenceableBytes(LLVMContext &Context,
245 uint64_t Bytes) {
246 assert(Bytes && "Bytes must be non-zero.");
247 return get(Context, Kind: Dereferenceable, Val: Bytes);
248}
249
250Attribute Attribute::getWithDereferenceableOrNullBytes(LLVMContext &Context,
251 uint64_t Bytes) {
252 assert(Bytes && "Bytes must be non-zero.");
253 return get(Context, Kind: DereferenceableOrNull, Val: Bytes);
254}
255
256Attribute Attribute::getWithByValType(LLVMContext &Context, Type *Ty) {
257 return get(Context, Kind: ByVal, Ty);
258}
259
260Attribute Attribute::getWithStructRetType(LLVMContext &Context, Type *Ty) {
261 return get(Context, Kind: StructRet, Ty);
262}
263
264Attribute Attribute::getWithByRefType(LLVMContext &Context, Type *Ty) {
265 return get(Context, Kind: ByRef, Ty);
266}
267
268Attribute Attribute::getWithPreallocatedType(LLVMContext &Context, Type *Ty) {
269 return get(Context, Kind: Preallocated, Ty);
270}
271
272Attribute Attribute::getWithInAllocaType(LLVMContext &Context, Type *Ty) {
273 return get(Context, Kind: InAlloca, Ty);
274}
275
276Attribute Attribute::getWithUWTableKind(LLVMContext &Context,
277 UWTableKind Kind) {
278 return get(Context, Kind: UWTable, Val: uint64_t(Kind));
279}
280
281Attribute Attribute::getWithMemoryEffects(LLVMContext &Context,
282 MemoryEffects ME) {
283 return get(Context, Kind: Memory, Val: ME.toIntValue());
284}
285
286Attribute Attribute::getWithNoFPClass(LLVMContext &Context,
287 FPClassTest ClassMask) {
288 return get(Context, Kind: NoFPClass, Val: ClassMask);
289}
290
291Attribute Attribute::getWithCaptureInfo(LLVMContext &Context, CaptureInfo CI) {
292 return get(Context, Kind: Captures, Val: CI.toIntValue());
293}
294
295Attribute
296Attribute::getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg,
297 const std::optional<unsigned> &NumElemsArg) {
298 assert(!(ElemSizeArg == 0 && NumElemsArg == 0) &&
299 "Invalid allocsize arguments -- given allocsize(0, 0)");
300 return get(Context, Kind: AllocSize, Val: packAllocSizeArgs(ElemSizeArg, NumElemsArg));
301}
302
303Attribute Attribute::getWithAllocKind(LLVMContext &Context, AllocFnKind Kind) {
304 return get(Context, Kind: AllocKind, Val: static_cast<uint64_t>(Kind));
305}
306
307Attribute Attribute::getWithVScaleRangeArgs(LLVMContext &Context,
308 unsigned MinValue,
309 unsigned MaxValue) {
310 return get(Context, Kind: VScaleRange, Val: packVScaleRangeArgs(MinValue, MaxValue));
311}
312
313Attribute::AttrKind Attribute::getAttrKindFromName(StringRef AttrName) {
314 return StringSwitch<Attribute::AttrKind>(AttrName)
315#define GET_ATTR_NAMES
316#define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) \
317 .Case(#DISPLAY_NAME, Attribute::ENUM_NAME)
318#include "llvm/IR/Attributes.inc"
319 .Default(Value: Attribute::None);
320}
321
322StringRef Attribute::getNameFromAttrKind(Attribute::AttrKind AttrKind) {
323 switch (AttrKind) {
324#define GET_ATTR_NAMES
325#define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) \
326 case Attribute::ENUM_NAME: \
327 return #DISPLAY_NAME;
328#include "llvm/IR/Attributes.inc"
329 case Attribute::None:
330 return "none";
331 default:
332 llvm_unreachable("invalid Kind");
333 }
334}
335
336bool Attribute::isExistingAttribute(StringRef Name) {
337 return StringSwitch<bool>(Name)
338#define GET_ATTR_NAMES
339#define ATTRIBUTE_ALL(ENUM_NAME, DISPLAY_NAME) .Case(#DISPLAY_NAME, true)
340#include "llvm/IR/Attributes.inc"
341 .Default(Value: false);
342}
343
344//===----------------------------------------------------------------------===//
345// Attribute Accessor Methods
346//===----------------------------------------------------------------------===//
347
348bool Attribute::isEnumAttribute() const {
349 return pImpl && pImpl->isEnumAttribute();
350}
351
352bool Attribute::isIntAttribute() const {
353 return pImpl && pImpl->isIntAttribute();
354}
355
356bool Attribute::isStringAttribute() const {
357 return pImpl && pImpl->isStringAttribute();
358}
359
360bool Attribute::isTypeAttribute() const {
361 return pImpl && pImpl->isTypeAttribute();
362}
363
364bool Attribute::isConstantRangeAttribute() const {
365 return pImpl && pImpl->isConstantRangeAttribute();
366}
367
368bool Attribute::isConstantRangeListAttribute() const {
369 return pImpl && pImpl->isConstantRangeListAttribute();
370}
371
372Attribute::AttrKind Attribute::getKindAsEnum() const {
373 if (!pImpl) return None;
374 assert(hasKindAsEnum() &&
375 "Invalid attribute type to get the kind as an enum!");
376 return pImpl->getKindAsEnum();
377}
378
379uint64_t Attribute::getValueAsInt() const {
380 if (!pImpl) return 0;
381 assert(isIntAttribute() &&
382 "Expected the attribute to be an integer attribute!");
383 return pImpl->getValueAsInt();
384}
385
386bool Attribute::getValueAsBool() const {
387 if (!pImpl) return false;
388 assert(isStringAttribute() &&
389 "Expected the attribute to be a string attribute!");
390 return pImpl->getValueAsBool();
391}
392
393StringRef Attribute::getKindAsString() const {
394 if (!pImpl) return {};
395 assert(isStringAttribute() &&
396 "Invalid attribute type to get the kind as a string!");
397 return pImpl->getKindAsString();
398}
399
400StringRef Attribute::getValueAsString() const {
401 if (!pImpl) return {};
402 assert(isStringAttribute() &&
403 "Invalid attribute type to get the value as a string!");
404 return pImpl->getValueAsString();
405}
406
407Type *Attribute::getValueAsType() const {
408 if (!pImpl) return {};
409 assert(isTypeAttribute() &&
410 "Invalid attribute type to get the value as a type!");
411 return pImpl->getValueAsType();
412}
413
414const ConstantRange &Attribute::getValueAsConstantRange() const {
415 assert(isConstantRangeAttribute() &&
416 "Invalid attribute type to get the value as a ConstantRange!");
417 return pImpl->getValueAsConstantRange();
418}
419
420ArrayRef<ConstantRange> Attribute::getValueAsConstantRangeList() const {
421 assert(isConstantRangeListAttribute() &&
422 "Invalid attribute type to get the value as a ConstantRangeList!");
423 return pImpl->getValueAsConstantRangeList();
424}
425
426bool Attribute::hasAttribute(AttrKind Kind) const {
427 return (pImpl && pImpl->hasAttribute(A: Kind)) || (!pImpl && Kind == None);
428}
429
430bool Attribute::hasAttribute(StringRef Kind) const {
431 if (!isStringAttribute()) return false;
432 return pImpl && pImpl->hasAttribute(Kind);
433}
434
435MaybeAlign Attribute::getAlignment() const {
436 assert(hasAttribute(Attribute::Alignment) &&
437 "Trying to get alignment from non-alignment attribute!");
438 return MaybeAlign(pImpl->getValueAsInt());
439}
440
441MaybeAlign Attribute::getStackAlignment() const {
442 assert(hasAttribute(Attribute::StackAlignment) &&
443 "Trying to get alignment from non-alignment attribute!");
444 return MaybeAlign(pImpl->getValueAsInt());
445}
446
447uint64_t Attribute::getDereferenceableBytes() const {
448 assert(hasAttribute(Attribute::Dereferenceable) &&
449 "Trying to get dereferenceable bytes from "
450 "non-dereferenceable attribute!");
451 return pImpl->getValueAsInt();
452}
453
454uint64_t Attribute::getDereferenceableOrNullBytes() const {
455 assert(hasAttribute(Attribute::DereferenceableOrNull) &&
456 "Trying to get dereferenceable bytes from "
457 "non-dereferenceable attribute!");
458 return pImpl->getValueAsInt();
459}
460
461std::pair<unsigned, std::optional<unsigned>>
462Attribute::getAllocSizeArgs() const {
463 assert(hasAttribute(Attribute::AllocSize) &&
464 "Trying to get allocsize args from non-allocsize attribute");
465 return unpackAllocSizeArgs(Num: pImpl->getValueAsInt());
466}
467
468unsigned Attribute::getVScaleRangeMin() const {
469 assert(hasAttribute(Attribute::VScaleRange) &&
470 "Trying to get vscale args from non-vscale attribute");
471 return unpackVScaleRangeArgs(Value: pImpl->getValueAsInt()).first;
472}
473
474std::optional<unsigned> Attribute::getVScaleRangeMax() const {
475 assert(hasAttribute(Attribute::VScaleRange) &&
476 "Trying to get vscale args from non-vscale attribute");
477 return unpackVScaleRangeArgs(Value: pImpl->getValueAsInt()).second;
478}
479
480UWTableKind Attribute::getUWTableKind() const {
481 assert(hasAttribute(Attribute::UWTable) &&
482 "Trying to get unwind table kind from non-uwtable attribute");
483 return UWTableKind(pImpl->getValueAsInt());
484}
485
486AllocFnKind Attribute::getAllocKind() const {
487 assert(hasAttribute(Attribute::AllocKind) &&
488 "Trying to get allockind value from non-allockind attribute");
489 return AllocFnKind(pImpl->getValueAsInt());
490}
491
492MemoryEffects Attribute::getMemoryEffects() const {
493 assert(hasAttribute(Attribute::Memory) &&
494 "Can only call getMemoryEffects() on memory attribute");
495 return MemoryEffects::createFromIntValue(Data: pImpl->getValueAsInt());
496}
497
498CaptureInfo Attribute::getCaptureInfo() const {
499 assert(hasAttribute(Attribute::Captures) &&
500 "Can only call getCaptureInfo() on captures attribute");
501 return CaptureInfo::createFromIntValue(Data: pImpl->getValueAsInt());
502}
503
504FPClassTest Attribute::getNoFPClass() const {
505 assert(hasAttribute(Attribute::NoFPClass) &&
506 "Can only call getNoFPClass() on nofpclass attribute");
507 return static_cast<FPClassTest>(pImpl->getValueAsInt());
508}
509
510const ConstantRange &Attribute::getRange() const {
511 assert(hasAttribute(Attribute::Range) &&
512 "Trying to get range args from non-range attribute");
513 return pImpl->getValueAsConstantRange();
514}
515
516ArrayRef<ConstantRange> Attribute::getInitializes() const {
517 assert(hasAttribute(Attribute::Initializes) &&
518 "Trying to get initializes attr from non-ConstantRangeList attribute");
519 return pImpl->getValueAsConstantRangeList();
520}
521
522static const char *getModRefStr(ModRefInfo MR) {
523 switch (MR) {
524 case ModRefInfo::NoModRef:
525 return "none";
526 case ModRefInfo::Ref:
527 return "read";
528 case ModRefInfo::Mod:
529 return "write";
530 case ModRefInfo::ModRef:
531 return "readwrite";
532 }
533 llvm_unreachable("Invalid ModRefInfo");
534}
535
536std::string Attribute::getAsString(bool InAttrGrp) const {
537 if (!pImpl) return {};
538
539 if (isEnumAttribute())
540 return getNameFromAttrKind(AttrKind: getKindAsEnum()).str();
541
542 if (isTypeAttribute()) {
543 std::string Result = getNameFromAttrKind(AttrKind: getKindAsEnum()).str();
544 Result += '(';
545 raw_string_ostream OS(Result);
546 getValueAsType()->print(O&: OS, IsForDebug: false, NoDetails: true);
547 OS.flush();
548 Result += ')';
549 return Result;
550 }
551
552 // FIXME: These should be output like this:
553 //
554 // align=4
555 // alignstack=8
556 //
557 if (hasAttribute(Kind: Attribute::Alignment))
558 return (InAttrGrp ? "align=" + Twine(getValueAsInt())
559 : "align " + Twine(getValueAsInt()))
560 .str();
561
562 auto AttrWithBytesToString = [&](const char *Name) {
563 return (InAttrGrp ? Name + ("=" + Twine(getValueAsInt()))
564 : Name + ("(" + Twine(getValueAsInt())) + ")")
565 .str();
566 };
567
568 if (hasAttribute(Kind: Attribute::StackAlignment))
569 return AttrWithBytesToString("alignstack");
570
571 if (hasAttribute(Kind: Attribute::Dereferenceable))
572 return AttrWithBytesToString("dereferenceable");
573
574 if (hasAttribute(Kind: Attribute::DereferenceableOrNull))
575 return AttrWithBytesToString("dereferenceable_or_null");
576
577 if (hasAttribute(Kind: Attribute::AllocSize)) {
578 unsigned ElemSize;
579 std::optional<unsigned> NumElems;
580 std::tie(args&: ElemSize, args&: NumElems) = getAllocSizeArgs();
581
582 return (NumElems
583 ? "allocsize(" + Twine(ElemSize) + "," + Twine(*NumElems) + ")"
584 : "allocsize(" + Twine(ElemSize) + ")")
585 .str();
586 }
587
588 if (hasAttribute(Kind: Attribute::VScaleRange)) {
589 unsigned MinValue = getVScaleRangeMin();
590 std::optional<unsigned> MaxValue = getVScaleRangeMax();
591 return ("vscale_range(" + Twine(MinValue) + "," +
592 Twine(MaxValue.value_or(u: 0)) + ")")
593 .str();
594 }
595
596 if (hasAttribute(Kind: Attribute::UWTable)) {
597 UWTableKind Kind = getUWTableKind();
598 assert(Kind != UWTableKind::None && "uwtable attribute should not be none");
599 return Kind == UWTableKind::Default ? "uwtable" : "uwtable(sync)";
600 }
601
602 if (hasAttribute(Kind: Attribute::AllocKind)) {
603 AllocFnKind Kind = getAllocKind();
604 SmallVector<StringRef> parts;
605 if ((Kind & AllocFnKind::Alloc) != AllocFnKind::Unknown)
606 parts.push_back(Elt: "alloc");
607 if ((Kind & AllocFnKind::Realloc) != AllocFnKind::Unknown)
608 parts.push_back(Elt: "realloc");
609 if ((Kind & AllocFnKind::Free) != AllocFnKind::Unknown)
610 parts.push_back(Elt: "free");
611 if ((Kind & AllocFnKind::Uninitialized) != AllocFnKind::Unknown)
612 parts.push_back(Elt: "uninitialized");
613 if ((Kind & AllocFnKind::Zeroed) != AllocFnKind::Unknown)
614 parts.push_back(Elt: "zeroed");
615 if ((Kind & AllocFnKind::Aligned) != AllocFnKind::Unknown)
616 parts.push_back(Elt: "aligned");
617 return ("allockind(\"" +
618 Twine(llvm::join(Begin: parts.begin(), End: parts.end(), Separator: ",")) + "\")")
619 .str();
620 }
621
622 if (hasAttribute(Kind: Attribute::Memory)) {
623 std::string Result;
624 raw_string_ostream OS(Result);
625 bool First = true;
626 OS << "memory(";
627
628 MemoryEffects ME = getMemoryEffects();
629
630 // Print access kind for "other" as the default access kind. This way it
631 // will apply to any new location kinds that get split out of "other".
632 ModRefInfo OtherMR = ME.getModRef(Loc: IRMemLocation::Other);
633 if (OtherMR != ModRefInfo::NoModRef || ME.getModRef() == OtherMR) {
634 First = false;
635 OS << getModRefStr(MR: OtherMR);
636 }
637
638 for (auto Loc : MemoryEffects::locations()) {
639 ModRefInfo MR = ME.getModRef(Loc);
640 if (MR == OtherMR)
641 continue;
642
643 if (!First)
644 OS << ", ";
645 First = false;
646
647 switch (Loc) {
648 case IRMemLocation::ArgMem:
649 OS << "argmem: ";
650 break;
651 case IRMemLocation::InaccessibleMem:
652 OS << "inaccessiblemem: ";
653 break;
654 case IRMemLocation::ErrnoMem:
655 OS << "errnomem: ";
656 break;
657 case IRMemLocation::Other:
658 llvm_unreachable("This is represented as the default access kind");
659 }
660 OS << getModRefStr(MR);
661 }
662 OS << ")";
663 OS.flush();
664 return Result;
665 }
666
667 if (hasAttribute(Kind: Attribute::Captures)) {
668 std::string Result;
669 raw_string_ostream OS(Result);
670 OS << getCaptureInfo();
671 return Result;
672 }
673
674 if (hasAttribute(Kind: Attribute::NoFPClass)) {
675 std::string Result = "nofpclass";
676 raw_string_ostream OS(Result);
677 OS << getNoFPClass();
678 return Result;
679 }
680
681 if (hasAttribute(Kind: Attribute::Range)) {
682 std::string Result;
683 raw_string_ostream OS(Result);
684 const ConstantRange &CR = getValueAsConstantRange();
685 OS << "range(";
686 OS << "i" << CR.getBitWidth() << " ";
687 OS << CR.getLower() << ", " << CR.getUpper();
688 OS << ")";
689 OS.flush();
690 return Result;
691 }
692
693 if (hasAttribute(Kind: Attribute::Initializes)) {
694 std::string Result;
695 raw_string_ostream OS(Result);
696 ConstantRangeList CRL = getInitializes();
697 OS << "initializes(";
698 CRL.print(OS);
699 OS << ")";
700 OS.flush();
701 return Result;
702 }
703
704 // Convert target-dependent attributes to strings of the form:
705 //
706 // "kind"
707 // "kind" = "value"
708 //
709 if (isStringAttribute()) {
710 std::string Result;
711 {
712 raw_string_ostream OS(Result);
713 OS << '"' << getKindAsString() << '"';
714
715 // Since some attribute strings contain special characters that cannot be
716 // printable, those have to be escaped to make the attribute value
717 // printable as is. e.g. "\01__gnu_mcount_nc"
718 const auto &AttrVal = pImpl->getValueAsString();
719 if (!AttrVal.empty()) {
720 OS << "=\"";
721 printEscapedString(Name: AttrVal, Out&: OS);
722 OS << "\"";
723 }
724 }
725 return Result;
726 }
727
728 llvm_unreachable("Unknown attribute");
729}
730
731bool Attribute::hasParentContext(LLVMContext &C) const {
732 assert(isValid() && "invalid Attribute doesn't refer to any context");
733 FoldingSetNodeID ID;
734 pImpl->Profile(ID);
735 void *Unused;
736 return C.pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPos&: Unused) == pImpl;
737}
738
739int Attribute::cmpKind(Attribute A) const {
740 if (!pImpl && !A.pImpl)
741 return 0;
742 if (!pImpl)
743 return 1;
744 if (!A.pImpl)
745 return -1;
746 return pImpl->cmp(AI: *A.pImpl, /*KindOnly=*/true);
747}
748
749bool Attribute::operator<(Attribute A) const {
750 if (!pImpl && !A.pImpl) return false;
751 if (!pImpl) return true;
752 if (!A.pImpl) return false;
753 return *pImpl < *A.pImpl;
754}
755
756void Attribute::Profile(FoldingSetNodeID &ID) const {
757 ID.AddPointer(Ptr: pImpl);
758}
759
760enum AttributeProperty {
761 FnAttr = (1 << 0),
762 ParamAttr = (1 << 1),
763 RetAttr = (1 << 2),
764 IntersectPreserve = (0 << 3),
765 IntersectAnd = (1 << 3),
766 IntersectMin = (2 << 3),
767 IntersectCustom = (3 << 3),
768 IntersectPropertyMask = (3 << 3),
769};
770
771#define GET_ATTR_PROP_TABLE
772#include "llvm/IR/Attributes.inc"
773
774static unsigned getAttributeProperties(Attribute::AttrKind Kind) {
775 unsigned Index = Kind - 1;
776 assert(Index < std::size(AttrPropTable) && "Invalid attribute kind");
777 return AttrPropTable[Index];
778}
779
780static bool hasAttributeProperty(Attribute::AttrKind Kind,
781 AttributeProperty Prop) {
782 return getAttributeProperties(Kind) & Prop;
783}
784
785bool Attribute::canUseAsFnAttr(AttrKind Kind) {
786 return hasAttributeProperty(Kind, Prop: AttributeProperty::FnAttr);
787}
788
789bool Attribute::canUseAsParamAttr(AttrKind Kind) {
790 return hasAttributeProperty(Kind, Prop: AttributeProperty::ParamAttr);
791}
792
793bool Attribute::canUseAsRetAttr(AttrKind Kind) {
794 return hasAttributeProperty(Kind, Prop: AttributeProperty::RetAttr);
795}
796
797static bool hasIntersectProperty(Attribute::AttrKind Kind,
798 AttributeProperty Prop) {
799 assert((Prop == AttributeProperty::IntersectPreserve ||
800 Prop == AttributeProperty::IntersectAnd ||
801 Prop == AttributeProperty::IntersectMin ||
802 Prop == AttributeProperty::IntersectCustom) &&
803 "Unknown intersect property");
804 return (getAttributeProperties(Kind) &
805 AttributeProperty::IntersectPropertyMask) == Prop;
806}
807
808bool Attribute::intersectMustPreserve(AttrKind Kind) {
809 return hasIntersectProperty(Kind, Prop: AttributeProperty::IntersectPreserve);
810}
811bool Attribute::intersectWithAnd(AttrKind Kind) {
812 return hasIntersectProperty(Kind, Prop: AttributeProperty::IntersectAnd);
813}
814bool Attribute::intersectWithMin(AttrKind Kind) {
815 return hasIntersectProperty(Kind, Prop: AttributeProperty::IntersectMin);
816}
817bool Attribute::intersectWithCustom(AttrKind Kind) {
818 return hasIntersectProperty(Kind, Prop: AttributeProperty::IntersectCustom);
819}
820
821//===----------------------------------------------------------------------===//
822// AttributeImpl Definition
823//===----------------------------------------------------------------------===//
824
825bool AttributeImpl::hasAttribute(Attribute::AttrKind A) const {
826 if (isStringAttribute()) return false;
827 return getKindAsEnum() == A;
828}
829
830bool AttributeImpl::hasAttribute(StringRef Kind) const {
831 if (!isStringAttribute()) return false;
832 return getKindAsString() == Kind;
833}
834
835Attribute::AttrKind AttributeImpl::getKindAsEnum() const {
836 assert(isEnumAttribute() || isIntAttribute() || isTypeAttribute() ||
837 isConstantRangeAttribute() || isConstantRangeListAttribute());
838 return static_cast<const EnumAttributeImpl *>(this)->getEnumKind();
839}
840
841uint64_t AttributeImpl::getValueAsInt() const {
842 assert(isIntAttribute());
843 return static_cast<const IntAttributeImpl *>(this)->getValue();
844}
845
846bool AttributeImpl::getValueAsBool() const {
847 assert(getValueAsString().empty() || getValueAsString() == "false" || getValueAsString() == "true");
848 return getValueAsString() == "true";
849}
850
851StringRef AttributeImpl::getKindAsString() const {
852 assert(isStringAttribute());
853 return static_cast<const StringAttributeImpl *>(this)->getStringKind();
854}
855
856StringRef AttributeImpl::getValueAsString() const {
857 assert(isStringAttribute());
858 return static_cast<const StringAttributeImpl *>(this)->getStringValue();
859}
860
861Type *AttributeImpl::getValueAsType() const {
862 assert(isTypeAttribute());
863 return static_cast<const TypeAttributeImpl *>(this)->getTypeValue();
864}
865
866const ConstantRange &AttributeImpl::getValueAsConstantRange() const {
867 assert(isConstantRangeAttribute());
868 return static_cast<const ConstantRangeAttributeImpl *>(this)
869 ->getConstantRangeValue();
870}
871
872ArrayRef<ConstantRange> AttributeImpl::getValueAsConstantRangeList() const {
873 assert(isConstantRangeListAttribute());
874 return static_cast<const ConstantRangeListAttributeImpl *>(this)
875 ->getConstantRangeListValue();
876}
877
878int AttributeImpl::cmp(const AttributeImpl &AI, bool KindOnly) const {
879 if (this == &AI)
880 return 0;
881
882 // This sorts the attributes with Attribute::AttrKinds coming first (sorted
883 // relative to their enum value) and then strings.
884 if (!isStringAttribute()) {
885 if (AI.isStringAttribute())
886 return -1;
887
888 if (getKindAsEnum() != AI.getKindAsEnum())
889 return getKindAsEnum() < AI.getKindAsEnum() ? -1 : 1;
890 else if (KindOnly)
891 return 0;
892
893 assert(!AI.isEnumAttribute() && "Non-unique attribute");
894 assert(!AI.isTypeAttribute() && "Comparison of types would be unstable");
895 assert(!AI.isConstantRangeAttribute() && "Unclear how to compare ranges");
896 assert(!AI.isConstantRangeListAttribute() &&
897 "Unclear how to compare range list");
898 // TODO: Is this actually needed?
899 assert(AI.isIntAttribute() && "Only possibility left");
900 if (getValueAsInt() < AI.getValueAsInt())
901 return -1;
902 return getValueAsInt() == AI.getValueAsInt() ? 0 : 1;
903 }
904 if (!AI.isStringAttribute())
905 return 1;
906 if (KindOnly)
907 return getKindAsString().compare(RHS: AI.getKindAsString());
908 if (getKindAsString() == AI.getKindAsString())
909 return getValueAsString().compare(RHS: AI.getValueAsString());
910 return getKindAsString().compare(RHS: AI.getKindAsString());
911}
912
913bool AttributeImpl::operator<(const AttributeImpl &AI) const {
914 return cmp(AI, /*KindOnly=*/false) < 0;
915}
916
917//===----------------------------------------------------------------------===//
918// AttributeSet Definition
919//===----------------------------------------------------------------------===//
920
921AttributeSet AttributeSet::get(LLVMContext &C, const AttrBuilder &B) {
922 return AttributeSet(AttributeSetNode::get(C, B));
923}
924
925AttributeSet AttributeSet::get(LLVMContext &C, ArrayRef<Attribute> Attrs) {
926 return AttributeSet(AttributeSetNode::get(C, Attrs));
927}
928
929AttributeSet AttributeSet::addAttribute(LLVMContext &C,
930 Attribute::AttrKind Kind) const {
931 if (hasAttribute(Kind)) return *this;
932 AttrBuilder B(C);
933 B.addAttribute(Val: Kind);
934 return addAttributes(C, AS: AttributeSet::get(C, B));
935}
936
937AttributeSet AttributeSet::addAttribute(LLVMContext &C, StringRef Kind,
938 StringRef Value) const {
939 AttrBuilder B(C);
940 B.addAttribute(A: Kind, V: Value);
941 return addAttributes(C, AS: AttributeSet::get(C, B));
942}
943
944AttributeSet AttributeSet::addAttributes(LLVMContext &C,
945 const AttributeSet AS) const {
946 if (!hasAttributes())
947 return AS;
948
949 if (!AS.hasAttributes())
950 return *this;
951
952 AttrBuilder B(C, *this);
953 B.merge(B: AttrBuilder(C, AS));
954 return get(C, B);
955}
956
957AttributeSet AttributeSet::removeAttribute(LLVMContext &C,
958 Attribute::AttrKind Kind) const {
959 if (!hasAttribute(Kind)) return *this;
960 AttrBuilder B(C, *this);
961 B.removeAttribute(Val: Kind);
962 return get(C, B);
963}
964
965AttributeSet AttributeSet::removeAttribute(LLVMContext &C,
966 StringRef Kind) const {
967 if (!hasAttribute(Kind)) return *this;
968 AttrBuilder B(C, *this);
969 B.removeAttribute(A: Kind);
970 return get(C, B);
971}
972
973AttributeSet AttributeSet::removeAttributes(LLVMContext &C,
974 const AttributeMask &Attrs) const {
975 AttrBuilder B(C, *this);
976 // If there is nothing to remove, directly return the original set.
977 if (!B.overlaps(AM: Attrs))
978 return *this;
979
980 B.remove(AM: Attrs);
981 return get(C, B);
982}
983
984std::optional<AttributeSet>
985AttributeSet::intersectWith(LLVMContext &C, AttributeSet Other) const {
986 if (*this == Other)
987 return *this;
988
989 AttrBuilder Intersected(C);
990 // Iterate over both attr sets at once.
991 auto ItBegin0 = begin();
992 auto ItEnd0 = end();
993 auto ItBegin1 = Other.begin();
994 auto ItEnd1 = Other.end();
995
996 while (ItBegin0 != ItEnd0 || ItBegin1 != ItEnd1) {
997 // Loop through all attributes in both this and Other in sorted order. If
998 // the attribute is only present in one of the sets, it will be set in
999 // Attr0. If it is present in both sets both Attr0 and Attr1 will be set.
1000 Attribute Attr0, Attr1;
1001 if (ItBegin1 == ItEnd1)
1002 Attr0 = *ItBegin0++;
1003 else if (ItBegin0 == ItEnd0)
1004 Attr0 = *ItBegin1++;
1005 else {
1006 int Cmp = ItBegin0->cmpKind(A: *ItBegin1);
1007 if (Cmp == 0) {
1008 Attr0 = *ItBegin0++;
1009 Attr1 = *ItBegin1++;
1010 } else if (Cmp < 0)
1011 Attr0 = *ItBegin0++;
1012 else
1013 Attr0 = *ItBegin1++;
1014 }
1015 assert(Attr0.isValid() && "Iteration should always yield a valid attr");
1016
1017 auto IntersectEq = [&]() {
1018 if (!Attr1.isValid())
1019 return false;
1020 if (Attr0 != Attr1)
1021 return false;
1022 Intersected.addAttribute(A: Attr0);
1023 return true;
1024 };
1025
1026 // Non-enum assume we must preserve. Handle early so we can unconditionally
1027 // use Kind below.
1028 if (!Attr0.hasKindAsEnum()) {
1029 if (!IntersectEq())
1030 return std::nullopt;
1031 continue;
1032 }
1033
1034 Attribute::AttrKind Kind = Attr0.getKindAsEnum();
1035 // If we don't have both attributes, then fail if the attribute is
1036 // must-preserve or drop it otherwise.
1037 if (!Attr1.isValid()) {
1038 if (Attribute::intersectMustPreserve(Kind))
1039 return std::nullopt;
1040 continue;
1041 }
1042
1043 // We have both attributes so apply the intersection rule.
1044 assert(Attr1.hasKindAsEnum() && Kind == Attr1.getKindAsEnum() &&
1045 "Iterator picked up two different attributes in the same iteration");
1046
1047 // Attribute we can intersect with "and"
1048 if (Attribute::intersectWithAnd(Kind)) {
1049 assert(Attribute::isEnumAttrKind(Kind) &&
1050 "Invalid attr type of intersectAnd");
1051 Intersected.addAttribute(Val: Kind);
1052 continue;
1053 }
1054
1055 // Attribute we can intersect with "min"
1056 if (Attribute::intersectWithMin(Kind)) {
1057 assert(Attribute::isIntAttrKind(Kind) &&
1058 "Invalid attr type of intersectMin");
1059 uint64_t NewVal = std::min(a: Attr0.getValueAsInt(), b: Attr1.getValueAsInt());
1060 Intersected.addRawIntAttr(Kind, Value: NewVal);
1061 continue;
1062 }
1063 // Attribute we can intersect but need a custom rule for.
1064 if (Attribute::intersectWithCustom(Kind)) {
1065 switch (Kind) {
1066 case Attribute::Alignment:
1067 // If `byval` is present, alignment become must-preserve. This is
1068 // handled below if we have `byval`.
1069 Intersected.addAlignmentAttr(
1070 Align: std::min(a: Attr0.getAlignment().valueOrOne(),
1071 b: Attr1.getAlignment().valueOrOne()));
1072 break;
1073 case Attribute::Memory:
1074 Intersected.addMemoryAttr(ME: Attr0.getMemoryEffects() |
1075 Attr1.getMemoryEffects());
1076 break;
1077 case Attribute::Captures:
1078 Intersected.addCapturesAttr(CI: Attr0.getCaptureInfo() |
1079 Attr1.getCaptureInfo());
1080 break;
1081 case Attribute::NoFPClass:
1082 Intersected.addNoFPClassAttr(NoFPClassMask: Attr0.getNoFPClass() &
1083 Attr1.getNoFPClass());
1084 break;
1085 case Attribute::Range: {
1086 ConstantRange Range0 = Attr0.getRange();
1087 ConstantRange Range1 = Attr1.getRange();
1088 ConstantRange NewRange = Range0.unionWith(CR: Range1);
1089 if (!NewRange.isFullSet())
1090 Intersected.addRangeAttr(CR: NewRange);
1091 } break;
1092 default:
1093 llvm_unreachable("Unknown attribute with custom intersection rule");
1094 }
1095 continue;
1096 }
1097
1098 // Attributes with no intersection rule. Only intersect if they are equal.
1099 // Otherwise fail.
1100 if (!IntersectEq())
1101 return std::nullopt;
1102
1103 // Special handling of `byval`. `byval` essentially turns align attr into
1104 // must-preserve
1105 if (Kind == Attribute::ByVal &&
1106 getAttribute(Kind: Attribute::Alignment) !=
1107 Other.getAttribute(Kind: Attribute::Alignment))
1108 return std::nullopt;
1109 }
1110
1111 return get(C, B: Intersected);
1112}
1113
1114unsigned AttributeSet::getNumAttributes() const {
1115 return SetNode ? SetNode->getNumAttributes() : 0;
1116}
1117
1118bool AttributeSet::hasAttribute(Attribute::AttrKind Kind) const {
1119 return SetNode ? SetNode->hasAttribute(Kind) : false;
1120}
1121
1122bool AttributeSet::hasAttribute(StringRef Kind) const {
1123 return SetNode ? SetNode->hasAttribute(Kind) : false;
1124}
1125
1126Attribute AttributeSet::getAttribute(Attribute::AttrKind Kind) const {
1127 return SetNode ? SetNode->getAttribute(Kind) : Attribute();
1128}
1129
1130Attribute AttributeSet::getAttribute(StringRef Kind) const {
1131 return SetNode ? SetNode->getAttribute(Kind) : Attribute();
1132}
1133
1134MaybeAlign AttributeSet::getAlignment() const {
1135 return SetNode ? SetNode->getAlignment() : std::nullopt;
1136}
1137
1138MaybeAlign AttributeSet::getStackAlignment() const {
1139 return SetNode ? SetNode->getStackAlignment() : std::nullopt;
1140}
1141
1142uint64_t AttributeSet::getDereferenceableBytes() const {
1143 return SetNode ? SetNode->getDereferenceableBytes() : 0;
1144}
1145
1146uint64_t AttributeSet::getDereferenceableOrNullBytes() const {
1147 return SetNode ? SetNode->getDereferenceableOrNullBytes() : 0;
1148}
1149
1150Type *AttributeSet::getByRefType() const {
1151 return SetNode ? SetNode->getAttributeType(Kind: Attribute::ByRef) : nullptr;
1152}
1153
1154Type *AttributeSet::getByValType() const {
1155 return SetNode ? SetNode->getAttributeType(Kind: Attribute::ByVal) : nullptr;
1156}
1157
1158Type *AttributeSet::getStructRetType() const {
1159 return SetNode ? SetNode->getAttributeType(Kind: Attribute::StructRet) : nullptr;
1160}
1161
1162Type *AttributeSet::getPreallocatedType() const {
1163 return SetNode ? SetNode->getAttributeType(Kind: Attribute::Preallocated) : nullptr;
1164}
1165
1166Type *AttributeSet::getInAllocaType() const {
1167 return SetNode ? SetNode->getAttributeType(Kind: Attribute::InAlloca) : nullptr;
1168}
1169
1170Type *AttributeSet::getElementType() const {
1171 return SetNode ? SetNode->getAttributeType(Kind: Attribute::ElementType) : nullptr;
1172}
1173
1174std::optional<std::pair<unsigned, std::optional<unsigned>>>
1175AttributeSet::getAllocSizeArgs() const {
1176 if (SetNode)
1177 return SetNode->getAllocSizeArgs();
1178 return std::nullopt;
1179}
1180
1181unsigned AttributeSet::getVScaleRangeMin() const {
1182 return SetNode ? SetNode->getVScaleRangeMin() : 1;
1183}
1184
1185std::optional<unsigned> AttributeSet::getVScaleRangeMax() const {
1186 return SetNode ? SetNode->getVScaleRangeMax() : std::nullopt;
1187}
1188
1189UWTableKind AttributeSet::getUWTableKind() const {
1190 return SetNode ? SetNode->getUWTableKind() : UWTableKind::None;
1191}
1192
1193AllocFnKind AttributeSet::getAllocKind() const {
1194 return SetNode ? SetNode->getAllocKind() : AllocFnKind::Unknown;
1195}
1196
1197MemoryEffects AttributeSet::getMemoryEffects() const {
1198 return SetNode ? SetNode->getMemoryEffects() : MemoryEffects::unknown();
1199}
1200
1201CaptureInfo AttributeSet::getCaptureInfo() const {
1202 return SetNode ? SetNode->getCaptureInfo() : CaptureInfo::all();
1203}
1204
1205FPClassTest AttributeSet::getNoFPClass() const {
1206 return SetNode ? SetNode->getNoFPClass() : fcNone;
1207}
1208
1209std::string AttributeSet::getAsString(bool InAttrGrp) const {
1210 return SetNode ? SetNode->getAsString(InAttrGrp) : "";
1211}
1212
1213bool AttributeSet::hasParentContext(LLVMContext &C) const {
1214 assert(hasAttributes() && "empty AttributeSet doesn't refer to any context");
1215 FoldingSetNodeID ID;
1216 SetNode->Profile(ID);
1217 void *Unused;
1218 return C.pImpl->AttrsSetNodes.FindNodeOrInsertPos(ID, InsertPos&: Unused) == SetNode;
1219}
1220
1221AttributeSet::iterator AttributeSet::begin() const {
1222 return SetNode ? SetNode->begin() : nullptr;
1223}
1224
1225AttributeSet::iterator AttributeSet::end() const {
1226 return SetNode ? SetNode->end() : nullptr;
1227}
1228
1229#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1230LLVM_DUMP_METHOD void AttributeSet::dump() const {
1231 dbgs() << "AS =\n";
1232 dbgs() << " { ";
1233 dbgs() << getAsString(true) << " }\n";
1234}
1235#endif
1236
1237//===----------------------------------------------------------------------===//
1238// AttributeSetNode Definition
1239//===----------------------------------------------------------------------===//
1240
1241AttributeSetNode::AttributeSetNode(ArrayRef<Attribute> Attrs)
1242 : NumAttrs(Attrs.size()) {
1243 // There's memory after the node where we can store the entries in.
1244 llvm::copy(Range&: Attrs, Out: getTrailingObjects());
1245
1246 for (const auto &I : *this) {
1247 if (I.isStringAttribute())
1248 StringAttrs.insert(KV: { I.getKindAsString(), I });
1249 else
1250 AvailableAttrs.addAttribute(Kind: I.getKindAsEnum());
1251 }
1252}
1253
1254AttributeSetNode *AttributeSetNode::get(LLVMContext &C,
1255 ArrayRef<Attribute> Attrs) {
1256 SmallVector<Attribute, 8> SortedAttrs(Attrs);
1257 llvm::sort(C&: SortedAttrs);
1258 return getSorted(C, SortedAttrs);
1259}
1260
1261AttributeSetNode *AttributeSetNode::getSorted(LLVMContext &C,
1262 ArrayRef<Attribute> SortedAttrs) {
1263 if (SortedAttrs.empty())
1264 return nullptr;
1265
1266 // Build a key to look up the existing attributes.
1267 LLVMContextImpl *pImpl = C.pImpl;
1268 FoldingSetNodeID ID;
1269
1270 assert(llvm::is_sorted(SortedAttrs) && "Expected sorted attributes!");
1271 for (const auto &Attr : SortedAttrs)
1272 Attr.Profile(ID);
1273
1274 void *InsertPoint;
1275 AttributeSetNode *PA =
1276 pImpl->AttrsSetNodes.FindNodeOrInsertPos(ID, InsertPos&: InsertPoint);
1277
1278 // If we didn't find any existing attributes of the same shape then create a
1279 // new one and insert it.
1280 if (!PA) {
1281 // Coallocate entries after the AttributeSetNode itself.
1282 void *Mem = ::operator new(totalSizeToAlloc<Attribute>(Counts: SortedAttrs.size()));
1283 PA = new (Mem) AttributeSetNode(SortedAttrs);
1284 pImpl->AttrsSetNodes.InsertNode(N: PA, InsertPos: InsertPoint);
1285 }
1286
1287 // Return the AttributeSetNode that we found or created.
1288 return PA;
1289}
1290
1291AttributeSetNode *AttributeSetNode::get(LLVMContext &C, const AttrBuilder &B) {
1292 return getSorted(C, SortedAttrs: B.attrs());
1293}
1294
1295bool AttributeSetNode::hasAttribute(StringRef Kind) const {
1296 return StringAttrs.count(Val: Kind);
1297}
1298
1299std::optional<Attribute>
1300AttributeSetNode::findEnumAttribute(Attribute::AttrKind Kind) const {
1301 // Do a quick presence check.
1302 if (!hasAttribute(Kind))
1303 return std::nullopt;
1304
1305 // Attributes in a set are sorted by enum value, followed by string
1306 // attributes. Binary search the one we want.
1307 const Attribute *I =
1308 std::lower_bound(first: begin(), last: end() - StringAttrs.size(), val: Kind,
1309 comp: [](Attribute A, Attribute::AttrKind Kind) {
1310 return A.getKindAsEnum() < Kind;
1311 });
1312 assert(I != end() && I->hasAttribute(Kind) && "Presence check failed?");
1313 return *I;
1314}
1315
1316Attribute AttributeSetNode::getAttribute(Attribute::AttrKind Kind) const {
1317 if (auto A = findEnumAttribute(Kind))
1318 return *A;
1319 return {};
1320}
1321
1322Attribute AttributeSetNode::getAttribute(StringRef Kind) const {
1323 return StringAttrs.lookup(Val: Kind);
1324}
1325
1326MaybeAlign AttributeSetNode::getAlignment() const {
1327 if (auto A = findEnumAttribute(Kind: Attribute::Alignment))
1328 return A->getAlignment();
1329 return std::nullopt;
1330}
1331
1332MaybeAlign AttributeSetNode::getStackAlignment() const {
1333 if (auto A = findEnumAttribute(Kind: Attribute::StackAlignment))
1334 return A->getStackAlignment();
1335 return std::nullopt;
1336}
1337
1338Type *AttributeSetNode::getAttributeType(Attribute::AttrKind Kind) const {
1339 if (auto A = findEnumAttribute(Kind))
1340 return A->getValueAsType();
1341 return nullptr;
1342}
1343
1344uint64_t AttributeSetNode::getDereferenceableBytes() const {
1345 if (auto A = findEnumAttribute(Kind: Attribute::Dereferenceable))
1346 return A->getDereferenceableBytes();
1347 return 0;
1348}
1349
1350uint64_t AttributeSetNode::getDereferenceableOrNullBytes() const {
1351 if (auto A = findEnumAttribute(Kind: Attribute::DereferenceableOrNull))
1352 return A->getDereferenceableOrNullBytes();
1353 return 0;
1354}
1355
1356std::optional<std::pair<unsigned, std::optional<unsigned>>>
1357AttributeSetNode::getAllocSizeArgs() const {
1358 if (auto A = findEnumAttribute(Kind: Attribute::AllocSize))
1359 return A->getAllocSizeArgs();
1360 return std::nullopt;
1361}
1362
1363unsigned AttributeSetNode::getVScaleRangeMin() const {
1364 if (auto A = findEnumAttribute(Kind: Attribute::VScaleRange))
1365 return A->getVScaleRangeMin();
1366 return 1;
1367}
1368
1369std::optional<unsigned> AttributeSetNode::getVScaleRangeMax() const {
1370 if (auto A = findEnumAttribute(Kind: Attribute::VScaleRange))
1371 return A->getVScaleRangeMax();
1372 return std::nullopt;
1373}
1374
1375UWTableKind AttributeSetNode::getUWTableKind() const {
1376 if (auto A = findEnumAttribute(Kind: Attribute::UWTable))
1377 return A->getUWTableKind();
1378 return UWTableKind::None;
1379}
1380
1381AllocFnKind AttributeSetNode::getAllocKind() const {
1382 if (auto A = findEnumAttribute(Kind: Attribute::AllocKind))
1383 return A->getAllocKind();
1384 return AllocFnKind::Unknown;
1385}
1386
1387MemoryEffects AttributeSetNode::getMemoryEffects() const {
1388 if (auto A = findEnumAttribute(Kind: Attribute::Memory))
1389 return A->getMemoryEffects();
1390 return MemoryEffects::unknown();
1391}
1392
1393CaptureInfo AttributeSetNode::getCaptureInfo() const {
1394 if (auto A = findEnumAttribute(Kind: Attribute::Captures))
1395 return A->getCaptureInfo();
1396 return CaptureInfo::all();
1397}
1398
1399FPClassTest AttributeSetNode::getNoFPClass() const {
1400 if (auto A = findEnumAttribute(Kind: Attribute::NoFPClass))
1401 return A->getNoFPClass();
1402 return fcNone;
1403}
1404
1405std::string AttributeSetNode::getAsString(bool InAttrGrp) const {
1406 std::string Str;
1407 for (iterator I = begin(), E = end(); I != E; ++I) {
1408 if (I != begin())
1409 Str += ' ';
1410 Str += I->getAsString(InAttrGrp);
1411 }
1412 return Str;
1413}
1414
1415//===----------------------------------------------------------------------===//
1416// AttributeListImpl Definition
1417//===----------------------------------------------------------------------===//
1418
1419/// Map from AttributeList index to the internal array index. Adding one happens
1420/// to work, because -1 wraps around to 0.
1421static unsigned attrIdxToArrayIdx(unsigned Index) {
1422 return Index + 1;
1423}
1424
1425AttributeListImpl::AttributeListImpl(ArrayRef<AttributeSet> Sets)
1426 : NumAttrSets(Sets.size()) {
1427 assert(!Sets.empty() && "pointless AttributeListImpl");
1428
1429 // There's memory after the node where we can store the entries in.
1430 llvm::copy(Range&: Sets, Out: getTrailingObjects());
1431
1432 // Initialize AvailableFunctionAttrs and AvailableSomewhereAttrs
1433 // summary bitsets.
1434 for (const auto &I : Sets[attrIdxToArrayIdx(Index: AttributeList::FunctionIndex)])
1435 if (!I.isStringAttribute())
1436 AvailableFunctionAttrs.addAttribute(Kind: I.getKindAsEnum());
1437
1438 for (const auto &Set : Sets)
1439 for (const auto &I : Set)
1440 if (!I.isStringAttribute())
1441 AvailableSomewhereAttrs.addAttribute(Kind: I.getKindAsEnum());
1442}
1443
1444void AttributeListImpl::Profile(FoldingSetNodeID &ID) const {
1445 Profile(ID, Nodes: ArrayRef(begin(), end()));
1446}
1447
1448void AttributeListImpl::Profile(FoldingSetNodeID &ID,
1449 ArrayRef<AttributeSet> Sets) {
1450 for (const auto &Set : Sets)
1451 ID.AddPointer(Ptr: Set.SetNode);
1452}
1453
1454bool AttributeListImpl::hasAttrSomewhere(Attribute::AttrKind Kind,
1455 unsigned *Index) const {
1456 if (!AvailableSomewhereAttrs.hasAttribute(Kind))
1457 return false;
1458
1459 if (Index) {
1460 for (unsigned I = 0, E = NumAttrSets; I != E; ++I) {
1461 if (begin()[I].hasAttribute(Kind)) {
1462 *Index = I - 1;
1463 break;
1464 }
1465 }
1466 }
1467
1468 return true;
1469}
1470
1471
1472#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1473LLVM_DUMP_METHOD void AttributeListImpl::dump() const {
1474 AttributeList(const_cast<AttributeListImpl *>(this)).dump();
1475}
1476#endif
1477
1478//===----------------------------------------------------------------------===//
1479// AttributeList Construction and Mutation Methods
1480//===----------------------------------------------------------------------===//
1481
1482AttributeList AttributeList::getImpl(LLVMContext &C,
1483 ArrayRef<AttributeSet> AttrSets) {
1484 assert(!AttrSets.empty() && "pointless AttributeListImpl");
1485
1486 LLVMContextImpl *pImpl = C.pImpl;
1487 FoldingSetNodeID ID;
1488 AttributeListImpl::Profile(ID, Sets: AttrSets);
1489
1490 void *InsertPoint;
1491 AttributeListImpl *PA =
1492 pImpl->AttrsLists.FindNodeOrInsertPos(ID, InsertPos&: InsertPoint);
1493
1494 // If we didn't find any existing attributes of the same shape then
1495 // create a new one and insert it.
1496 if (!PA) {
1497 // Coallocate entries after the AttributeListImpl itself.
1498 void *Mem = pImpl->Alloc.Allocate(
1499 Size: AttributeListImpl::totalSizeToAlloc<AttributeSet>(Counts: AttrSets.size()),
1500 Alignment: alignof(AttributeListImpl));
1501 PA = new (Mem) AttributeListImpl(AttrSets);
1502 pImpl->AttrsLists.InsertNode(N: PA, InsertPos: InsertPoint);
1503 }
1504
1505 // Return the AttributesList that we found or created.
1506 return AttributeList(PA);
1507}
1508
1509AttributeList
1510AttributeList::get(LLVMContext &C,
1511 ArrayRef<std::pair<unsigned, Attribute>> Attrs) {
1512 // If there are no attributes then return a null AttributesList pointer.
1513 if (Attrs.empty())
1514 return {};
1515
1516 assert(llvm::is_sorted(Attrs, llvm::less_first()) &&
1517 "Misordered Attributes list!");
1518 assert(llvm::all_of(Attrs,
1519 [](const std::pair<unsigned, Attribute> &Pair) {
1520 return Pair.second.isValid();
1521 }) &&
1522 "Pointless attribute!");
1523
1524 // Create a vector if (unsigned, AttributeSetNode*) pairs from the attributes
1525 // list.
1526 SmallVector<std::pair<unsigned, AttributeSet>, 8> AttrPairVec;
1527 for (ArrayRef<std::pair<unsigned, Attribute>>::iterator I = Attrs.begin(),
1528 E = Attrs.end(); I != E; ) {
1529 unsigned Index = I->first;
1530 SmallVector<Attribute, 4> AttrVec;
1531 while (I != E && I->first == Index) {
1532 AttrVec.push_back(Elt: I->second);
1533 ++I;
1534 }
1535
1536 AttrPairVec.emplace_back(Args&: Index, Args: AttributeSet::get(C, Attrs: AttrVec));
1537 }
1538
1539 return get(C, Attrs: AttrPairVec);
1540}
1541
1542AttributeList
1543AttributeList::get(LLVMContext &C,
1544 ArrayRef<std::pair<unsigned, AttributeSet>> Attrs) {
1545 // If there are no attributes then return a null AttributesList pointer.
1546 if (Attrs.empty())
1547 return {};
1548
1549 assert(llvm::is_sorted(Attrs, llvm::less_first()) &&
1550 "Misordered Attributes list!");
1551 assert(llvm::none_of(Attrs,
1552 [](const std::pair<unsigned, AttributeSet> &Pair) {
1553 return !Pair.second.hasAttributes();
1554 }) &&
1555 "Pointless attribute!");
1556
1557 unsigned MaxIndex = Attrs.back().first;
1558 // If the MaxIndex is FunctionIndex and there are other indices in front
1559 // of it, we need to use the largest of those to get the right size.
1560 if (MaxIndex == FunctionIndex && Attrs.size() > 1)
1561 MaxIndex = Attrs[Attrs.size() - 2].first;
1562
1563 SmallVector<AttributeSet, 4> AttrVec(attrIdxToArrayIdx(Index: MaxIndex) + 1);
1564 for (const auto &Pair : Attrs)
1565 AttrVec[attrIdxToArrayIdx(Index: Pair.first)] = Pair.second;
1566
1567 return getImpl(C, AttrSets: AttrVec);
1568}
1569
1570AttributeList AttributeList::get(LLVMContext &C, AttributeSet FnAttrs,
1571 AttributeSet RetAttrs,
1572 ArrayRef<AttributeSet> ArgAttrs) {
1573 // Scan from the end to find the last argument with attributes. Most
1574 // arguments don't have attributes, so it's nice if we can have fewer unique
1575 // AttributeListImpls by dropping empty attribute sets at the end of the list.
1576 unsigned NumSets = 0;
1577 for (size_t I = ArgAttrs.size(); I != 0; --I) {
1578 if (ArgAttrs[I - 1].hasAttributes()) {
1579 NumSets = I + 2;
1580 break;
1581 }
1582 }
1583 if (NumSets == 0) {
1584 // Check function and return attributes if we didn't have argument
1585 // attributes.
1586 if (RetAttrs.hasAttributes())
1587 NumSets = 2;
1588 else if (FnAttrs.hasAttributes())
1589 NumSets = 1;
1590 }
1591
1592 // If all attribute sets were empty, we can use the empty attribute list.
1593 if (NumSets == 0)
1594 return {};
1595
1596 SmallVector<AttributeSet, 8> AttrSets;
1597 AttrSets.reserve(N: NumSets);
1598 // If we have any attributes, we always have function attributes.
1599 AttrSets.push_back(Elt: FnAttrs);
1600 if (NumSets > 1)
1601 AttrSets.push_back(Elt: RetAttrs);
1602 if (NumSets > 2) {
1603 // Drop the empty argument attribute sets at the end.
1604 ArgAttrs = ArgAttrs.take_front(N: NumSets - 2);
1605 llvm::append_range(C&: AttrSets, R&: ArgAttrs);
1606 }
1607
1608 return getImpl(C, AttrSets);
1609}
1610
1611AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
1612 AttributeSet Attrs) {
1613 if (!Attrs.hasAttributes())
1614 return {};
1615 Index = attrIdxToArrayIdx(Index);
1616 SmallVector<AttributeSet, 8> AttrSets(Index + 1);
1617 AttrSets[Index] = Attrs;
1618 return getImpl(C, AttrSets);
1619}
1620
1621AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
1622 const AttrBuilder &B) {
1623 return get(C, Index, Attrs: AttributeSet::get(C, B));
1624}
1625
1626AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
1627 ArrayRef<Attribute::AttrKind> Kinds) {
1628 SmallVector<std::pair<unsigned, Attribute>, 8> Attrs;
1629 for (const auto K : Kinds)
1630 Attrs.emplace_back(Args&: Index, Args: Attribute::get(Context&: C, Kind: K));
1631 return get(C, Attrs);
1632}
1633
1634AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
1635 ArrayRef<Attribute::AttrKind> Kinds,
1636 ArrayRef<uint64_t> Values) {
1637 assert(Kinds.size() == Values.size() && "Mismatched attribute values.");
1638 SmallVector<std::pair<unsigned, Attribute>, 8> Attrs;
1639 auto VI = Values.begin();
1640 for (const auto K : Kinds)
1641 Attrs.emplace_back(Args&: Index, Args: Attribute::get(Context&: C, Kind: K, Val: *VI++));
1642 return get(C, Attrs);
1643}
1644
1645AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
1646 ArrayRef<StringRef> Kinds) {
1647 SmallVector<std::pair<unsigned, Attribute>, 8> Attrs;
1648 for (const auto &K : Kinds)
1649 Attrs.emplace_back(Args&: Index, Args: Attribute::get(Context&: C, Kind: K));
1650 return get(C, Attrs);
1651}
1652
1653AttributeList AttributeList::get(LLVMContext &C,
1654 ArrayRef<AttributeList> Attrs) {
1655 if (Attrs.empty())
1656 return {};
1657 if (Attrs.size() == 1)
1658 return Attrs[0];
1659
1660 unsigned MaxSize = 0;
1661 for (const auto &List : Attrs)
1662 MaxSize = std::max(a: MaxSize, b: List.getNumAttrSets());
1663
1664 // If every list was empty, there is no point in merging the lists.
1665 if (MaxSize == 0)
1666 return {};
1667
1668 SmallVector<AttributeSet, 8> NewAttrSets(MaxSize);
1669 for (unsigned I = 0; I < MaxSize; ++I) {
1670 AttrBuilder CurBuilder(C);
1671 for (const auto &List : Attrs)
1672 CurBuilder.merge(B: AttrBuilder(C, List.getAttributes(Index: I - 1)));
1673 NewAttrSets[I] = AttributeSet::get(C, B: CurBuilder);
1674 }
1675
1676 return getImpl(C, AttrSets: NewAttrSets);
1677}
1678
1679AttributeList
1680AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index,
1681 Attribute::AttrKind Kind) const {
1682 AttributeSet Attrs = getAttributes(Index);
1683 if (Attrs.hasAttribute(Kind))
1684 return *this;
1685 // TODO: Insert at correct position and avoid sort.
1686 SmallVector<Attribute, 8> NewAttrs(Attrs.begin(), Attrs.end());
1687 NewAttrs.push_back(Elt: Attribute::get(Context&: C, Kind));
1688 return setAttributesAtIndex(C, Index, Attrs: AttributeSet::get(C, Attrs: NewAttrs));
1689}
1690
1691AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index,
1692 StringRef Kind,
1693 StringRef Value) const {
1694 AttrBuilder B(C);
1695 B.addAttribute(A: Kind, V: Value);
1696 return addAttributesAtIndex(C, Index, B);
1697}
1698
1699AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index,
1700 Attribute A) const {
1701 AttrBuilder B(C);
1702 B.addAttribute(A);
1703 return addAttributesAtIndex(C, Index, B);
1704}
1705
1706AttributeList AttributeList::setAttributesAtIndex(LLVMContext &C,
1707 unsigned Index,
1708 AttributeSet Attrs) const {
1709 Index = attrIdxToArrayIdx(Index);
1710 SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());
1711 if (Index >= AttrSets.size())
1712 AttrSets.resize(N: Index + 1);
1713 AttrSets[Index] = Attrs;
1714
1715 // Remove trailing empty attribute sets.
1716 while (!AttrSets.empty() && !AttrSets.back().hasAttributes())
1717 AttrSets.pop_back();
1718 if (AttrSets.empty())
1719 return {};
1720 return AttributeList::getImpl(C, AttrSets);
1721}
1722
1723AttributeList AttributeList::addAttributesAtIndex(LLVMContext &C,
1724 unsigned Index,
1725 const AttrBuilder &B) const {
1726 if (!B.hasAttributes())
1727 return *this;
1728
1729 if (!pImpl)
1730 return AttributeList::get(C, Attrs: {{Index, AttributeSet::get(C, B)}});
1731
1732 AttrBuilder Merged(C, getAttributes(Index));
1733 Merged.merge(B);
1734 return setAttributesAtIndex(C, Index, Attrs: AttributeSet::get(C, B: Merged));
1735}
1736
1737AttributeList AttributeList::addParamAttribute(LLVMContext &C,
1738 ArrayRef<unsigned> ArgNos,
1739 Attribute A) const {
1740 assert(llvm::is_sorted(ArgNos));
1741
1742 SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());
1743 unsigned MaxIndex = attrIdxToArrayIdx(Index: ArgNos.back() + FirstArgIndex);
1744 if (MaxIndex >= AttrSets.size())
1745 AttrSets.resize(N: MaxIndex + 1);
1746
1747 for (unsigned ArgNo : ArgNos) {
1748 unsigned Index = attrIdxToArrayIdx(Index: ArgNo + FirstArgIndex);
1749 AttrBuilder B(C, AttrSets[Index]);
1750 B.addAttribute(A);
1751 AttrSets[Index] = AttributeSet::get(C, B);
1752 }
1753
1754 return getImpl(C, AttrSets);
1755}
1756
1757AttributeList
1758AttributeList::removeAttributeAtIndex(LLVMContext &C, unsigned Index,
1759 Attribute::AttrKind Kind) const {
1760 AttributeSet Attrs = getAttributes(Index);
1761 AttributeSet NewAttrs = Attrs.removeAttribute(C, Kind);
1762 if (Attrs == NewAttrs)
1763 return *this;
1764 return setAttributesAtIndex(C, Index, Attrs: NewAttrs);
1765}
1766
1767AttributeList AttributeList::removeAttributeAtIndex(LLVMContext &C,
1768 unsigned Index,
1769 StringRef Kind) const {
1770 AttributeSet Attrs = getAttributes(Index);
1771 AttributeSet NewAttrs = Attrs.removeAttribute(C, Kind);
1772 if (Attrs == NewAttrs)
1773 return *this;
1774 return setAttributesAtIndex(C, Index, Attrs: NewAttrs);
1775}
1776
1777AttributeList AttributeList::removeAttributesAtIndex(
1778 LLVMContext &C, unsigned Index, const AttributeMask &AttrsToRemove) const {
1779 AttributeSet Attrs = getAttributes(Index);
1780 AttributeSet NewAttrs = Attrs.removeAttributes(C, Attrs: AttrsToRemove);
1781 // If nothing was removed, return the original list.
1782 if (Attrs == NewAttrs)
1783 return *this;
1784 return setAttributesAtIndex(C, Index, Attrs: NewAttrs);
1785}
1786
1787AttributeList
1788AttributeList::removeAttributesAtIndex(LLVMContext &C,
1789 unsigned WithoutIndex) const {
1790 if (!pImpl)
1791 return {};
1792 if (attrIdxToArrayIdx(Index: WithoutIndex) >= getNumAttrSets())
1793 return *this;
1794 return setAttributesAtIndex(C, Index: WithoutIndex, Attrs: AttributeSet());
1795}
1796
1797AttributeList AttributeList::addDereferenceableRetAttr(LLVMContext &C,
1798 uint64_t Bytes) const {
1799 AttrBuilder B(C);
1800 B.addDereferenceableAttr(Bytes);
1801 return addRetAttributes(C, B);
1802}
1803
1804AttributeList AttributeList::addDereferenceableParamAttr(LLVMContext &C,
1805 unsigned Index,
1806 uint64_t Bytes) const {
1807 AttrBuilder B(C);
1808 B.addDereferenceableAttr(Bytes);
1809 return addParamAttributes(C, ArgNo: Index, B);
1810}
1811
1812AttributeList
1813AttributeList::addDereferenceableOrNullParamAttr(LLVMContext &C, unsigned Index,
1814 uint64_t Bytes) const {
1815 AttrBuilder B(C);
1816 B.addDereferenceableOrNullAttr(Bytes);
1817 return addParamAttributes(C, ArgNo: Index, B);
1818}
1819
1820AttributeList AttributeList::addRangeRetAttr(LLVMContext &C,
1821 const ConstantRange &CR) const {
1822 AttrBuilder B(C);
1823 B.addRangeAttr(CR);
1824 return addRetAttributes(C, B);
1825}
1826
1827AttributeList AttributeList::addAllocSizeParamAttr(
1828 LLVMContext &C, unsigned Index, unsigned ElemSizeArg,
1829 const std::optional<unsigned> &NumElemsArg) const {
1830 AttrBuilder B(C);
1831 B.addAllocSizeAttr(ElemSizeArg, NumElemsArg);
1832 return addParamAttributes(C, ArgNo: Index, B);
1833}
1834
1835std::optional<AttributeList>
1836AttributeList::intersectWith(LLVMContext &C, AttributeList Other) const {
1837 // Trivial case, the two lists are equal.
1838 if (*this == Other)
1839 return *this;
1840
1841 SmallVector<std::pair<unsigned, AttributeSet>> IntersectedAttrs;
1842 auto IndexIt =
1843 index_iterator(std::max(a: getNumAttrSets(), b: Other.getNumAttrSets()));
1844 for (unsigned Idx : IndexIt) {
1845 auto IntersectedAS =
1846 getAttributes(Index: Idx).intersectWith(C, Other: Other.getAttributes(Index: Idx));
1847 // If any index fails to intersect, fail.
1848 if (!IntersectedAS)
1849 return std::nullopt;
1850 if (!IntersectedAS->hasAttributes())
1851 continue;
1852 IntersectedAttrs.push_back(Elt: std::make_pair(x&: Idx, y&: *IntersectedAS));
1853 }
1854
1855 llvm::sort(C&: IntersectedAttrs, Comp: llvm::less_first());
1856 return AttributeList::get(C, Attrs: IntersectedAttrs);
1857}
1858
1859//===----------------------------------------------------------------------===//
1860// AttributeList Accessor Methods
1861//===----------------------------------------------------------------------===//
1862
1863AttributeSet AttributeList::getParamAttrs(unsigned ArgNo) const {
1864 return getAttributes(Index: ArgNo + FirstArgIndex);
1865}
1866
1867AttributeSet AttributeList::getRetAttrs() const {
1868 return getAttributes(Index: ReturnIndex);
1869}
1870
1871AttributeSet AttributeList::getFnAttrs() const {
1872 return getAttributes(Index: FunctionIndex);
1873}
1874
1875bool AttributeList::hasAttributeAtIndex(unsigned Index,
1876 Attribute::AttrKind Kind) const {
1877 return getAttributes(Index).hasAttribute(Kind);
1878}
1879
1880bool AttributeList::hasAttributeAtIndex(unsigned Index, StringRef Kind) const {
1881 return getAttributes(Index).hasAttribute(Kind);
1882}
1883
1884bool AttributeList::hasAttributesAtIndex(unsigned Index) const {
1885 return getAttributes(Index).hasAttributes();
1886}
1887
1888bool AttributeList::hasFnAttr(Attribute::AttrKind Kind) const {
1889 return pImpl && pImpl->hasFnAttribute(Kind);
1890}
1891
1892bool AttributeList::hasFnAttr(StringRef Kind) const {
1893 return hasAttributeAtIndex(Index: AttributeList::FunctionIndex, Kind);
1894}
1895
1896bool AttributeList::hasAttrSomewhere(Attribute::AttrKind Attr,
1897 unsigned *Index) const {
1898 return pImpl && pImpl->hasAttrSomewhere(Kind: Attr, Index);
1899}
1900
1901Attribute AttributeList::getAttributeAtIndex(unsigned Index,
1902 Attribute::AttrKind Kind) const {
1903 return getAttributes(Index).getAttribute(Kind);
1904}
1905
1906Attribute AttributeList::getAttributeAtIndex(unsigned Index,
1907 StringRef Kind) const {
1908 return getAttributes(Index).getAttribute(Kind);
1909}
1910
1911MaybeAlign AttributeList::getRetAlignment() const {
1912 return getAttributes(Index: ReturnIndex).getAlignment();
1913}
1914
1915MaybeAlign AttributeList::getParamAlignment(unsigned ArgNo) const {
1916 return getAttributes(Index: ArgNo + FirstArgIndex).getAlignment();
1917}
1918
1919MaybeAlign AttributeList::getParamStackAlignment(unsigned ArgNo) const {
1920 return getAttributes(Index: ArgNo + FirstArgIndex).getStackAlignment();
1921}
1922
1923Type *AttributeList::getParamByValType(unsigned Index) const {
1924 return getAttributes(Index: Index+FirstArgIndex).getByValType();
1925}
1926
1927Type *AttributeList::getParamStructRetType(unsigned Index) const {
1928 return getAttributes(Index: Index + FirstArgIndex).getStructRetType();
1929}
1930
1931Type *AttributeList::getParamByRefType(unsigned Index) const {
1932 return getAttributes(Index: Index + FirstArgIndex).getByRefType();
1933}
1934
1935Type *AttributeList::getParamPreallocatedType(unsigned Index) const {
1936 return getAttributes(Index: Index + FirstArgIndex).getPreallocatedType();
1937}
1938
1939Type *AttributeList::getParamInAllocaType(unsigned Index) const {
1940 return getAttributes(Index: Index + FirstArgIndex).getInAllocaType();
1941}
1942
1943Type *AttributeList::getParamElementType(unsigned Index) const {
1944 return getAttributes(Index: Index + FirstArgIndex).getElementType();
1945}
1946
1947MaybeAlign AttributeList::getFnStackAlignment() const {
1948 return getFnAttrs().getStackAlignment();
1949}
1950
1951MaybeAlign AttributeList::getRetStackAlignment() const {
1952 return getRetAttrs().getStackAlignment();
1953}
1954
1955uint64_t AttributeList::getRetDereferenceableBytes() const {
1956 return getRetAttrs().getDereferenceableBytes();
1957}
1958
1959uint64_t AttributeList::getParamDereferenceableBytes(unsigned Index) const {
1960 return getParamAttrs(ArgNo: Index).getDereferenceableBytes();
1961}
1962
1963uint64_t AttributeList::getRetDereferenceableOrNullBytes() const {
1964 return getRetAttrs().getDereferenceableOrNullBytes();
1965}
1966
1967uint64_t
1968AttributeList::getParamDereferenceableOrNullBytes(unsigned Index) const {
1969 return getParamAttrs(ArgNo: Index).getDereferenceableOrNullBytes();
1970}
1971
1972std::optional<ConstantRange>
1973AttributeList::getParamRange(unsigned ArgNo) const {
1974 auto RangeAttr = getParamAttrs(ArgNo).getAttribute(Kind: Attribute::Range);
1975 if (RangeAttr.isValid())
1976 return RangeAttr.getRange();
1977 return std::nullopt;
1978}
1979
1980FPClassTest AttributeList::getRetNoFPClass() const {
1981 return getRetAttrs().getNoFPClass();
1982}
1983
1984FPClassTest AttributeList::getParamNoFPClass(unsigned Index) const {
1985 return getParamAttrs(ArgNo: Index).getNoFPClass();
1986}
1987
1988UWTableKind AttributeList::getUWTableKind() const {
1989 return getFnAttrs().getUWTableKind();
1990}
1991
1992AllocFnKind AttributeList::getAllocKind() const {
1993 return getFnAttrs().getAllocKind();
1994}
1995
1996MemoryEffects AttributeList::getMemoryEffects() const {
1997 return getFnAttrs().getMemoryEffects();
1998}
1999
2000std::string AttributeList::getAsString(unsigned Index, bool InAttrGrp) const {
2001 return getAttributes(Index).getAsString(InAttrGrp);
2002}
2003
2004AttributeSet AttributeList::getAttributes(unsigned Index) const {
2005 Index = attrIdxToArrayIdx(Index);
2006 if (!pImpl || Index >= getNumAttrSets())
2007 return {};
2008 return pImpl->begin()[Index];
2009}
2010
2011bool AttributeList::hasParentContext(LLVMContext &C) const {
2012 assert(!isEmpty() && "an empty attribute list has no parent context");
2013 FoldingSetNodeID ID;
2014 pImpl->Profile(ID);
2015 void *Unused;
2016 return C.pImpl->AttrsLists.FindNodeOrInsertPos(ID, InsertPos&: Unused) == pImpl;
2017}
2018
2019AttributeList::iterator AttributeList::begin() const {
2020 return pImpl ? pImpl->begin() : nullptr;
2021}
2022
2023AttributeList::iterator AttributeList::end() const {
2024 return pImpl ? pImpl->end() : nullptr;
2025}
2026
2027//===----------------------------------------------------------------------===//
2028// AttributeList Introspection Methods
2029//===----------------------------------------------------------------------===//
2030
2031unsigned AttributeList::getNumAttrSets() const {
2032 return pImpl ? pImpl->NumAttrSets : 0;
2033}
2034
2035void AttributeList::print(raw_ostream &O) const {
2036 O << "AttributeList[\n";
2037
2038 for (unsigned i : indexes()) {
2039 if (!getAttributes(Index: i).hasAttributes())
2040 continue;
2041 O << " { ";
2042 switch (i) {
2043 case AttrIndex::ReturnIndex:
2044 O << "return";
2045 break;
2046 case AttrIndex::FunctionIndex:
2047 O << "function";
2048 break;
2049 default:
2050 O << "arg(" << i - AttrIndex::FirstArgIndex << ")";
2051 }
2052 O << " => " << getAsString(Index: i) << " }\n";
2053 }
2054
2055 O << "]\n";
2056}
2057
2058#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
2059LLVM_DUMP_METHOD void AttributeList::dump() const { print(dbgs()); }
2060#endif
2061
2062//===----------------------------------------------------------------------===//
2063// AttrBuilder Method Implementations
2064//===----------------------------------------------------------------------===//
2065
2066AttrBuilder::AttrBuilder(LLVMContext &Ctx, AttributeSet AS) : Ctx(Ctx) {
2067 append_range(C&: Attrs, R&: AS);
2068 assert(is_sorted(Attrs) && "AttributeSet should be sorted");
2069}
2070
2071void AttrBuilder::clear() { Attrs.clear(); }
2072
2073/// Attribute comparator that only compares attribute keys. Enum attributes are
2074/// sorted before string attributes.
2075struct AttributeComparator {
2076 bool operator()(Attribute A0, Attribute A1) const {
2077 bool A0IsString = A0.isStringAttribute();
2078 bool A1IsString = A1.isStringAttribute();
2079 if (A0IsString) {
2080 if (A1IsString)
2081 return A0.getKindAsString() < A1.getKindAsString();
2082 else
2083 return false;
2084 }
2085 if (A1IsString)
2086 return true;
2087 return A0.getKindAsEnum() < A1.getKindAsEnum();
2088 }
2089 bool operator()(Attribute A0, Attribute::AttrKind Kind) const {
2090 if (A0.isStringAttribute())
2091 return false;
2092 return A0.getKindAsEnum() < Kind;
2093 }
2094 bool operator()(Attribute A0, StringRef Kind) const {
2095 if (A0.isStringAttribute())
2096 return A0.getKindAsString() < Kind;
2097 return true;
2098 }
2099};
2100
2101template <typename K>
2102static void addAttributeImpl(SmallVectorImpl<Attribute> &Attrs, K Kind,
2103 Attribute Attr) {
2104 auto It = lower_bound(Attrs, Kind, AttributeComparator());
2105 if (It != Attrs.end() && It->hasAttribute(Kind))
2106 std::swap(*It, Attr);
2107 else
2108 Attrs.insert(It, Attr);
2109}
2110
2111AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) {
2112 if (Attr.isStringAttribute())
2113 addAttributeImpl(Attrs, Kind: Attr.getKindAsString(), Attr);
2114 else
2115 addAttributeImpl(Attrs, Kind: Attr.getKindAsEnum(), Attr);
2116 return *this;
2117}
2118
2119AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Kind) {
2120 addAttributeImpl(Attrs, Kind, Attr: Attribute::get(Context&: Ctx, Kind));
2121 return *this;
2122}
2123
2124AttrBuilder &AttrBuilder::addAttribute(StringRef A, StringRef V) {
2125 addAttributeImpl(Attrs, Kind: A, Attr: Attribute::get(Context&: Ctx, Kind: A, Val: V));
2126 return *this;
2127}
2128
2129AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) {
2130 assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!");
2131 auto It = lower_bound(Range&: Attrs, Value&: Val, C: AttributeComparator());
2132 if (It != Attrs.end() && It->hasAttribute(Kind: Val))
2133 Attrs.erase(CI: It);
2134 return *this;
2135}
2136
2137AttrBuilder &AttrBuilder::removeAttribute(StringRef A) {
2138 auto It = lower_bound(Range&: Attrs, Value&: A, C: AttributeComparator());
2139 if (It != Attrs.end() && It->hasAttribute(Kind: A))
2140 Attrs.erase(CI: It);
2141 return *this;
2142}
2143
2144std::optional<uint64_t>
2145AttrBuilder::getRawIntAttr(Attribute::AttrKind Kind) const {
2146 assert(Attribute::isIntAttrKind(Kind) && "Not an int attribute");
2147 Attribute A = getAttribute(Kind);
2148 if (A.isValid())
2149 return A.getValueAsInt();
2150 return std::nullopt;
2151}
2152
2153AttrBuilder &AttrBuilder::addRawIntAttr(Attribute::AttrKind Kind,
2154 uint64_t Value) {
2155 return addAttribute(Attr: Attribute::get(Context&: Ctx, Kind, Val: Value));
2156}
2157
2158std::optional<std::pair<unsigned, std::optional<unsigned>>>
2159AttrBuilder::getAllocSizeArgs() const {
2160 Attribute A = getAttribute(Kind: Attribute::AllocSize);
2161 if (A.isValid())
2162 return A.getAllocSizeArgs();
2163 return std::nullopt;
2164}
2165
2166AttrBuilder &AttrBuilder::addAlignmentAttr(MaybeAlign Align) {
2167 if (!Align)
2168 return *this;
2169
2170 assert(*Align <= llvm::Value::MaximumAlignment && "Alignment too large.");
2171 return addRawIntAttr(Kind: Attribute::Alignment, Value: Align->value());
2172}
2173
2174AttrBuilder &AttrBuilder::addStackAlignmentAttr(MaybeAlign Align) {
2175 // Default alignment, allow the target to define how to align it.
2176 if (!Align)
2177 return *this;
2178
2179 assert(*Align <= 0x100 && "Alignment too large.");
2180 return addRawIntAttr(Kind: Attribute::StackAlignment, Value: Align->value());
2181}
2182
2183AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) {
2184 if (Bytes == 0) return *this;
2185
2186 return addRawIntAttr(Kind: Attribute::Dereferenceable, Value: Bytes);
2187}
2188
2189AttrBuilder &AttrBuilder::addDereferenceableOrNullAttr(uint64_t Bytes) {
2190 if (Bytes == 0)
2191 return *this;
2192
2193 return addRawIntAttr(Kind: Attribute::DereferenceableOrNull, Value: Bytes);
2194}
2195
2196AttrBuilder &
2197AttrBuilder::addAllocSizeAttr(unsigned ElemSize,
2198 const std::optional<unsigned> &NumElems) {
2199 return addAllocSizeAttrFromRawRepr(RawAllocSizeRepr: packAllocSizeArgs(ElemSizeArg: ElemSize, NumElemsArg: NumElems));
2200}
2201
2202AttrBuilder &AttrBuilder::addAllocSizeAttrFromRawRepr(uint64_t RawArgs) {
2203 // (0, 0) is our "not present" value, so we need to check for it here.
2204 assert(RawArgs && "Invalid allocsize arguments -- given allocsize(0, 0)");
2205 return addRawIntAttr(Kind: Attribute::AllocSize, Value: RawArgs);
2206}
2207
2208AttrBuilder &AttrBuilder::addVScaleRangeAttr(unsigned MinValue,
2209 std::optional<unsigned> MaxValue) {
2210 return addVScaleRangeAttrFromRawRepr(RawVScaleRangeRepr: packVScaleRangeArgs(MinValue, MaxValue));
2211}
2212
2213AttrBuilder &AttrBuilder::addVScaleRangeAttrFromRawRepr(uint64_t RawArgs) {
2214 // (0, 0) is not present hence ignore this case
2215 if (RawArgs == 0)
2216 return *this;
2217
2218 return addRawIntAttr(Kind: Attribute::VScaleRange, Value: RawArgs);
2219}
2220
2221AttrBuilder &AttrBuilder::addUWTableAttr(UWTableKind Kind) {
2222 if (Kind == UWTableKind::None)
2223 return *this;
2224 return addRawIntAttr(Kind: Attribute::UWTable, Value: uint64_t(Kind));
2225}
2226
2227AttrBuilder &AttrBuilder::addMemoryAttr(MemoryEffects ME) {
2228 return addRawIntAttr(Kind: Attribute::Memory, Value: ME.toIntValue());
2229}
2230
2231AttrBuilder &AttrBuilder::addCapturesAttr(CaptureInfo CI) {
2232 return addRawIntAttr(Kind: Attribute::Captures, Value: CI.toIntValue());
2233}
2234
2235AttrBuilder &AttrBuilder::addNoFPClassAttr(FPClassTest Mask) {
2236 if (Mask == fcNone)
2237 return *this;
2238
2239 return addRawIntAttr(Kind: Attribute::NoFPClass, Value: Mask);
2240}
2241
2242AttrBuilder &AttrBuilder::addAllocKindAttr(AllocFnKind Kind) {
2243 return addRawIntAttr(Kind: Attribute::AllocKind, Value: static_cast<uint64_t>(Kind));
2244}
2245
2246Type *AttrBuilder::getTypeAttr(Attribute::AttrKind Kind) const {
2247 assert(Attribute::isTypeAttrKind(Kind) && "Not a type attribute");
2248 Attribute A = getAttribute(Kind);
2249 return A.isValid() ? A.getValueAsType() : nullptr;
2250}
2251
2252AttrBuilder &AttrBuilder::addTypeAttr(Attribute::AttrKind Kind, Type *Ty) {
2253 return addAttribute(Attr: Attribute::get(Context&: Ctx, Kind, Ty));
2254}
2255
2256AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) {
2257 return addTypeAttr(Kind: Attribute::ByVal, Ty);
2258}
2259
2260AttrBuilder &AttrBuilder::addStructRetAttr(Type *Ty) {
2261 return addTypeAttr(Kind: Attribute::StructRet, Ty);
2262}
2263
2264AttrBuilder &AttrBuilder::addByRefAttr(Type *Ty) {
2265 return addTypeAttr(Kind: Attribute::ByRef, Ty);
2266}
2267
2268AttrBuilder &AttrBuilder::addPreallocatedAttr(Type *Ty) {
2269 return addTypeAttr(Kind: Attribute::Preallocated, Ty);
2270}
2271
2272AttrBuilder &AttrBuilder::addInAllocaAttr(Type *Ty) {
2273 return addTypeAttr(Kind: Attribute::InAlloca, Ty);
2274}
2275
2276AttrBuilder &AttrBuilder::addConstantRangeAttr(Attribute::AttrKind Kind,
2277 const ConstantRange &CR) {
2278 if (CR.isFullSet())
2279 return *this;
2280
2281 return addAttribute(Attr: Attribute::get(Context&: Ctx, Kind, CR));
2282}
2283
2284AttrBuilder &AttrBuilder::addRangeAttr(const ConstantRange &CR) {
2285 return addConstantRangeAttr(Kind: Attribute::Range, CR);
2286}
2287
2288AttrBuilder &
2289AttrBuilder::addConstantRangeListAttr(Attribute::AttrKind Kind,
2290 ArrayRef<ConstantRange> Val) {
2291 return addAttribute(Attr: Attribute::get(Context&: Ctx, Kind, Val));
2292}
2293
2294AttrBuilder &AttrBuilder::addInitializesAttr(const ConstantRangeList &CRL) {
2295 return addConstantRangeListAttr(Kind: Attribute::Initializes, Val: CRL.rangesRef());
2296}
2297
2298AttrBuilder &AttrBuilder::addFromEquivalentMetadata(const Instruction &I) {
2299 if (I.hasMetadata(KindID: LLVMContext::MD_nonnull))
2300 addAttribute(Kind: Attribute::NonNull);
2301
2302 if (I.hasMetadata(KindID: LLVMContext::MD_noundef))
2303 addAttribute(Kind: Attribute::NoUndef);
2304
2305 if (const MDNode *Align = I.getMetadata(KindID: LLVMContext::MD_align)) {
2306 ConstantInt *CI = mdconst::extract<ConstantInt>(MD: Align->getOperand(I: 0));
2307 addAlignmentAttr(Align: CI->getZExtValue());
2308 }
2309
2310 if (const MDNode *Dereferenceable =
2311 I.getMetadata(KindID: LLVMContext::MD_dereferenceable)) {
2312 ConstantInt *CI =
2313 mdconst::extract<ConstantInt>(MD: Dereferenceable->getOperand(I: 0));
2314 addDereferenceableAttr(Bytes: CI->getZExtValue());
2315 }
2316
2317 if (const MDNode *DereferenceableOrNull =
2318 I.getMetadata(KindID: LLVMContext::MD_dereferenceable_or_null)) {
2319 ConstantInt *CI =
2320 mdconst::extract<ConstantInt>(MD: DereferenceableOrNull->getOperand(I: 0));
2321 addDereferenceableAttr(Bytes: CI->getZExtValue());
2322 }
2323
2324 if (const MDNode *Range = I.getMetadata(KindID: LLVMContext::MD_range))
2325 addRangeAttr(CR: getConstantRangeFromMetadata(RangeMD: *Range));
2326
2327 return *this;
2328}
2329
2330AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
2331 // TODO: Could make this O(n) as we're merging two sorted lists.
2332 for (const auto &I : B.attrs())
2333 addAttribute(Attr: I);
2334
2335 return *this;
2336}
2337
2338AttrBuilder &AttrBuilder::remove(const AttributeMask &AM) {
2339 erase_if(C&: Attrs, P: [&](Attribute A) { return AM.contains(A); });
2340 return *this;
2341}
2342
2343bool AttrBuilder::overlaps(const AttributeMask &AM) const {
2344 return any_of(Range: Attrs, P: [&](Attribute A) { return AM.contains(A); });
2345}
2346
2347Attribute AttrBuilder::getAttribute(Attribute::AttrKind A) const {
2348 assert((unsigned)A < Attribute::EndAttrKinds && "Attribute out of range!");
2349 auto It = lower_bound(Range: Attrs, Value&: A, C: AttributeComparator());
2350 if (It != Attrs.end() && It->hasAttribute(Kind: A))
2351 return *It;
2352 return {};
2353}
2354
2355Attribute AttrBuilder::getAttribute(StringRef A) const {
2356 auto It = lower_bound(Range: Attrs, Value&: A, C: AttributeComparator());
2357 if (It != Attrs.end() && It->hasAttribute(Kind: A))
2358 return *It;
2359 return {};
2360}
2361
2362std::optional<ConstantRange> AttrBuilder::getRange() const {
2363 const Attribute RangeAttr = getAttribute(A: Attribute::Range);
2364 if (RangeAttr.isValid())
2365 return RangeAttr.getRange();
2366 return std::nullopt;
2367}
2368
2369bool AttrBuilder::contains(Attribute::AttrKind A) const {
2370 return getAttribute(A).isValid();
2371}
2372
2373bool AttrBuilder::contains(StringRef A) const {
2374 return getAttribute(A).isValid();
2375}
2376
2377bool AttrBuilder::operator==(const AttrBuilder &B) const {
2378 return Attrs == B.Attrs;
2379}
2380
2381//===----------------------------------------------------------------------===//
2382// AttributeFuncs Function Defintions
2383//===----------------------------------------------------------------------===//
2384
2385/// Returns true if this is a type legal for the 'nofpclass' attribute. This
2386/// follows the same type rules as FPMathOperator.
2387bool AttributeFuncs::isNoFPClassCompatibleType(Type *Ty) {
2388 return FPMathOperator::isSupportedFloatingPointType(Ty);
2389}
2390
2391/// Which attributes cannot be applied to a type.
2392AttributeMask AttributeFuncs::typeIncompatible(Type *Ty, AttributeSet AS,
2393 AttributeSafetyKind ASK) {
2394 AttributeMask Incompatible;
2395
2396 if (!Ty->isIntegerTy()) {
2397 // Attributes that only apply to integers.
2398 if (ASK & ASK_SAFE_TO_DROP)
2399 Incompatible.addAttribute(Val: Attribute::AllocAlign);
2400 if (ASK & ASK_UNSAFE_TO_DROP)
2401 Incompatible.addAttribute(Val: Attribute::SExt).addAttribute(Val: Attribute::ZExt);
2402 }
2403
2404 if (!Ty->isIntOrIntVectorTy()) {
2405 // Attributes that only apply to integers or vector of integers.
2406 if (ASK & ASK_SAFE_TO_DROP)
2407 Incompatible.addAttribute(Val: Attribute::Range);
2408 } else {
2409 Attribute RangeAttr = AS.getAttribute(Kind: Attribute::Range);
2410 if (RangeAttr.isValid() &&
2411 RangeAttr.getRange().getBitWidth() != Ty->getScalarSizeInBits())
2412 Incompatible.addAttribute(Val: Attribute::Range);
2413 }
2414
2415 if (!Ty->isPointerTy()) {
2416 // Attributes that only apply to pointers.
2417 if (ASK & ASK_SAFE_TO_DROP)
2418 Incompatible.addAttribute(Val: Attribute::NoAlias)
2419 .addAttribute(Val: Attribute::NonNull)
2420 .addAttribute(Val: Attribute::ReadNone)
2421 .addAttribute(Val: Attribute::ReadOnly)
2422 .addAttribute(Val: Attribute::Dereferenceable)
2423 .addAttribute(Val: Attribute::DereferenceableOrNull)
2424 .addAttribute(Val: Attribute::Writable)
2425 .addAttribute(Val: Attribute::DeadOnUnwind)
2426 .addAttribute(Val: Attribute::Initializes)
2427 .addAttribute(Val: Attribute::Captures)
2428 .addAttribute(Val: Attribute::DeadOnReturn);
2429 if (ASK & ASK_UNSAFE_TO_DROP)
2430 Incompatible.addAttribute(Val: Attribute::Nest)
2431 .addAttribute(Val: Attribute::SwiftError)
2432 .addAttribute(Val: Attribute::Preallocated)
2433 .addAttribute(Val: Attribute::InAlloca)
2434 .addAttribute(Val: Attribute::ByVal)
2435 .addAttribute(Val: Attribute::StructRet)
2436 .addAttribute(Val: Attribute::ByRef)
2437 .addAttribute(Val: Attribute::ElementType)
2438 .addAttribute(Val: Attribute::AllocatedPointer);
2439 }
2440
2441 // Attributes that only apply to pointers or vectors of pointers.
2442 if (!Ty->isPtrOrPtrVectorTy()) {
2443 if (ASK & ASK_SAFE_TO_DROP)
2444 Incompatible.addAttribute(Val: Attribute::Alignment);
2445 }
2446
2447 if (ASK & ASK_SAFE_TO_DROP) {
2448 if (!isNoFPClassCompatibleType(Ty))
2449 Incompatible.addAttribute(Val: Attribute::NoFPClass);
2450 }
2451
2452 // Some attributes can apply to all "values" but there are no `void` values.
2453 if (Ty->isVoidTy()) {
2454 if (ASK & ASK_SAFE_TO_DROP)
2455 Incompatible.addAttribute(Val: Attribute::NoUndef);
2456 }
2457
2458 return Incompatible;
2459}
2460
2461AttributeMask AttributeFuncs::getUBImplyingAttributes() {
2462 AttributeMask AM;
2463 AM.addAttribute(Val: Attribute::NoUndef);
2464 AM.addAttribute(Val: Attribute::Dereferenceable);
2465 AM.addAttribute(Val: Attribute::DereferenceableOrNull);
2466 return AM;
2467}
2468
2469/// Callees with dynamic denormal modes are compatible with any caller mode.
2470static bool denormModeCompatible(DenormalMode CallerMode,
2471 DenormalMode CalleeMode) {
2472 if (CallerMode == CalleeMode || CalleeMode == DenormalMode::getDynamic())
2473 return true;
2474
2475 // If they don't exactly match, it's OK if the mismatched component is
2476 // dynamic.
2477 if (CalleeMode.Input == CallerMode.Input &&
2478 CalleeMode.Output == DenormalMode::Dynamic)
2479 return true;
2480
2481 if (CalleeMode.Output == CallerMode.Output &&
2482 CalleeMode.Input == DenormalMode::Dynamic)
2483 return true;
2484 return false;
2485}
2486
2487static bool checkDenormMode(const Function &Caller, const Function &Callee) {
2488 DenormalMode CallerMode = Caller.getDenormalModeRaw();
2489 DenormalMode CalleeMode = Callee.getDenormalModeRaw();
2490
2491 if (denormModeCompatible(CallerMode, CalleeMode)) {
2492 DenormalMode CallerModeF32 = Caller.getDenormalModeF32Raw();
2493 DenormalMode CalleeModeF32 = Callee.getDenormalModeF32Raw();
2494 if (CallerModeF32 == DenormalMode::getInvalid())
2495 CallerModeF32 = CallerMode;
2496 if (CalleeModeF32 == DenormalMode::getInvalid())
2497 CalleeModeF32 = CalleeMode;
2498 return denormModeCompatible(CallerMode: CallerModeF32, CalleeMode: CalleeModeF32);
2499 }
2500
2501 return false;
2502}
2503
2504static bool checkStrictFP(const Function &Caller, const Function &Callee) {
2505 // Do not inline strictfp function into non-strictfp one. It would require
2506 // conversion of all FP operations in host function to constrained intrinsics.
2507 return !Callee.getAttributes().hasFnAttr(Kind: Attribute::StrictFP) ||
2508 Caller.getAttributes().hasFnAttr(Kind: Attribute::StrictFP);
2509}
2510
2511template<typename AttrClass>
2512static bool isEqual(const Function &Caller, const Function &Callee) {
2513 return Caller.getFnAttribute(AttrClass::getKind()) ==
2514 Callee.getFnAttribute(AttrClass::getKind());
2515}
2516
2517static bool isEqual(const Function &Caller, const Function &Callee,
2518 const StringRef &AttrName) {
2519 return Caller.getFnAttribute(Kind: AttrName) == Callee.getFnAttribute(Kind: AttrName);
2520}
2521
2522/// Compute the logical AND of the attributes of the caller and the
2523/// callee.
2524///
2525/// This function sets the caller's attribute to false if the callee's attribute
2526/// is false.
2527template<typename AttrClass>
2528static void setAND(Function &Caller, const Function &Callee) {
2529 if (AttrClass::isSet(Caller, AttrClass::getKind()) &&
2530 !AttrClass::isSet(Callee, AttrClass::getKind()))
2531 AttrClass::set(Caller, AttrClass::getKind(), false);
2532}
2533
2534/// Compute the logical OR of the attributes of the caller and the
2535/// callee.
2536///
2537/// This function sets the caller's attribute to true if the callee's attribute
2538/// is true.
2539template<typename AttrClass>
2540static void setOR(Function &Caller, const Function &Callee) {
2541 if (!AttrClass::isSet(Caller, AttrClass::getKind()) &&
2542 AttrClass::isSet(Callee, AttrClass::getKind()))
2543 AttrClass::set(Caller, AttrClass::getKind(), true);
2544}
2545
2546/// If the inlined function had a higher stack protection level than the
2547/// calling function, then bump up the caller's stack protection level.
2548static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) {
2549 // If the calling function has *no* stack protection level (e.g. it was built
2550 // with Clang's -fno-stack-protector or no_stack_protector attribute), don't
2551 // change it as that could change the program's semantics.
2552 if (!Caller.hasStackProtectorFnAttr())
2553 return;
2554
2555 // If upgrading the SSP attribute, clear out the old SSP Attributes first.
2556 // Having multiple SSP attributes doesn't actually hurt, but it adds useless
2557 // clutter to the IR.
2558 AttributeMask OldSSPAttr;
2559 OldSSPAttr.addAttribute(Val: Attribute::StackProtect)
2560 .addAttribute(Val: Attribute::StackProtectStrong)
2561 .addAttribute(Val: Attribute::StackProtectReq);
2562
2563 if (Callee.hasFnAttribute(Kind: Attribute::StackProtectReq)) {
2564 Caller.removeFnAttrs(Attrs: OldSSPAttr);
2565 Caller.addFnAttr(Kind: Attribute::StackProtectReq);
2566 } else if (Callee.hasFnAttribute(Kind: Attribute::StackProtectStrong) &&
2567 !Caller.hasFnAttribute(Kind: Attribute::StackProtectReq)) {
2568 Caller.removeFnAttrs(Attrs: OldSSPAttr);
2569 Caller.addFnAttr(Kind: Attribute::StackProtectStrong);
2570 } else if (Callee.hasFnAttribute(Kind: Attribute::StackProtect) &&
2571 !Caller.hasFnAttribute(Kind: Attribute::StackProtectReq) &&
2572 !Caller.hasFnAttribute(Kind: Attribute::StackProtectStrong))
2573 Caller.addFnAttr(Kind: Attribute::StackProtect);
2574}
2575
2576/// If the inlined function required stack probes, then ensure that
2577/// the calling function has those too.
2578static void adjustCallerStackProbes(Function &Caller, const Function &Callee) {
2579 if (!Caller.hasFnAttribute(Kind: "probe-stack") &&
2580 Callee.hasFnAttribute(Kind: "probe-stack")) {
2581 Caller.addFnAttr(Attr: Callee.getFnAttribute(Kind: "probe-stack"));
2582 }
2583}
2584
2585/// If the inlined function defines the size of guard region
2586/// on the stack, then ensure that the calling function defines a guard region
2587/// that is no larger.
2588static void
2589adjustCallerStackProbeSize(Function &Caller, const Function &Callee) {
2590 Attribute CalleeAttr = Callee.getFnAttribute(Kind: "stack-probe-size");
2591 if (CalleeAttr.isValid()) {
2592 Attribute CallerAttr = Caller.getFnAttribute(Kind: "stack-probe-size");
2593 if (CallerAttr.isValid()) {
2594 uint64_t CallerStackProbeSize, CalleeStackProbeSize;
2595 CallerAttr.getValueAsString().getAsInteger(Radix: 0, Result&: CallerStackProbeSize);
2596 CalleeAttr.getValueAsString().getAsInteger(Radix: 0, Result&: CalleeStackProbeSize);
2597
2598 if (CallerStackProbeSize > CalleeStackProbeSize) {
2599 Caller.addFnAttr(Attr: CalleeAttr);
2600 }
2601 } else {
2602 Caller.addFnAttr(Attr: CalleeAttr);
2603 }
2604 }
2605}
2606
2607/// If the inlined function defines a min legal vector width, then ensure
2608/// the calling function has the same or larger min legal vector width. If the
2609/// caller has the attribute, but the callee doesn't, we need to remove the
2610/// attribute from the caller since we can't make any guarantees about the
2611/// caller's requirements.
2612/// This function is called after the inlining decision has been made so we have
2613/// to merge the attribute this way. Heuristics that would use
2614/// min-legal-vector-width to determine inline compatibility would need to be
2615/// handled as part of inline cost analysis.
2616static void
2617adjustMinLegalVectorWidth(Function &Caller, const Function &Callee) {
2618 Attribute CallerAttr = Caller.getFnAttribute(Kind: "min-legal-vector-width");
2619 if (CallerAttr.isValid()) {
2620 Attribute CalleeAttr = Callee.getFnAttribute(Kind: "min-legal-vector-width");
2621 if (CalleeAttr.isValid()) {
2622 uint64_t CallerVectorWidth, CalleeVectorWidth;
2623 CallerAttr.getValueAsString().getAsInteger(Radix: 0, Result&: CallerVectorWidth);
2624 CalleeAttr.getValueAsString().getAsInteger(Radix: 0, Result&: CalleeVectorWidth);
2625 if (CallerVectorWidth < CalleeVectorWidth)
2626 Caller.addFnAttr(Attr: CalleeAttr);
2627 } else {
2628 // If the callee doesn't have the attribute then we don't know anything
2629 // and must drop the attribute from the caller.
2630 Caller.removeFnAttr(Kind: "min-legal-vector-width");
2631 }
2632 }
2633}
2634
2635/// If the inlined function has null_pointer_is_valid attribute,
2636/// set this attribute in the caller post inlining.
2637static void
2638adjustNullPointerValidAttr(Function &Caller, const Function &Callee) {
2639 if (Callee.nullPointerIsDefined() && !Caller.nullPointerIsDefined()) {
2640 Caller.addFnAttr(Kind: Attribute::NullPointerIsValid);
2641 }
2642}
2643
2644struct EnumAttr {
2645 static bool isSet(const Function &Fn,
2646 Attribute::AttrKind Kind) {
2647 return Fn.hasFnAttribute(Kind);
2648 }
2649
2650 static void set(Function &Fn,
2651 Attribute::AttrKind Kind, bool Val) {
2652 if (Val)
2653 Fn.addFnAttr(Kind);
2654 else
2655 Fn.removeFnAttr(Kind);
2656 }
2657};
2658
2659struct StrBoolAttr {
2660 static bool isSet(const Function &Fn,
2661 StringRef Kind) {
2662 auto A = Fn.getFnAttribute(Kind);
2663 return A.getValueAsString() == "true";
2664 }
2665
2666 static void set(Function &Fn,
2667 StringRef Kind, bool Val) {
2668 Fn.addFnAttr(Kind, Val: Val ? "true" : "false");
2669 }
2670};
2671
2672#define GET_ATTR_NAMES
2673#define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) \
2674 struct ENUM_NAME##Attr : EnumAttr { \
2675 static enum Attribute::AttrKind getKind() { \
2676 return llvm::Attribute::ENUM_NAME; \
2677 } \
2678 };
2679#define ATTRIBUTE_STRBOOL(ENUM_NAME, DISPLAY_NAME) \
2680 struct ENUM_NAME##Attr : StrBoolAttr { \
2681 static StringRef getKind() { return #DISPLAY_NAME; } \
2682 };
2683#include "llvm/IR/Attributes.inc"
2684
2685#define GET_ATTR_COMPAT_FUNC
2686#include "llvm/IR/Attributes.inc"
2687
2688bool AttributeFuncs::areInlineCompatible(const Function &Caller,
2689 const Function &Callee) {
2690 return hasCompatibleFnAttrs(Caller, Callee);
2691}
2692
2693bool AttributeFuncs::areOutlineCompatible(const Function &A,
2694 const Function &B) {
2695 return hasCompatibleFnAttrs(Caller: A, Callee: B);
2696}
2697
2698void AttributeFuncs::mergeAttributesForInlining(Function &Caller,
2699 const Function &Callee) {
2700 mergeFnAttrs(Caller, Callee);
2701}
2702
2703void AttributeFuncs::mergeAttributesForOutlining(Function &Base,
2704 const Function &ToMerge) {
2705
2706 // We merge functions so that they meet the most general case.
2707 // For example, if the NoNansFPMathAttr is set in one function, but not in
2708 // the other, in the merged function we can say that the NoNansFPMathAttr
2709 // is not set.
2710 // However if we have the SpeculativeLoadHardeningAttr set true in one
2711 // function, but not the other, we make sure that the function retains
2712 // that aspect in the merged function.
2713 mergeFnAttrs(Caller&: Base, Callee: ToMerge);
2714}
2715
2716void AttributeFuncs::updateMinLegalVectorWidthAttr(Function &Fn,
2717 uint64_t Width) {
2718 Attribute Attr = Fn.getFnAttribute(Kind: "min-legal-vector-width");
2719 if (Attr.isValid()) {
2720 uint64_t OldWidth;
2721 Attr.getValueAsString().getAsInteger(Radix: 0, Result&: OldWidth);
2722 if (Width > OldWidth)
2723 Fn.addFnAttr(Kind: "min-legal-vector-width", Val: llvm::utostr(X: Width));
2724 }
2725}
2726