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