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