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