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