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