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