Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/IR/Attributes.cpp
35234 views
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
46
using 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."
58
static const unsigned AllocSizeNumElemsNotPresent = -1;
59
60
static 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(AllocSizeNumElemsNotPresent);
67
}
68
69
static std::pair<unsigned, std::optional<unsigned>>
70
unpackAllocSizeArgs(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(ElemSizeArg, NumElemsArg);
78
}
79
80
static uint64_t packVScaleRangeArgs(unsigned MinValue,
81
std::optional<unsigned> MaxValue) {
82
return uint64_t(MinValue) << 32 | MaxValue.value_or(0);
83
}
84
85
static std::pair<unsigned, std::optional<unsigned>>
86
unpackVScaleRangeArgs(uint64_t Value) {
87
unsigned MaxValue = Value & std::numeric_limits<unsigned>::max();
88
unsigned MinValue = Value >> 32;
89
90
return std::make_pair(MinValue,
91
MaxValue > 0 ? MaxValue : std::optional<unsigned>());
92
}
93
94
Attribute 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(Kind);
103
if (IsIntAttr)
104
ID.AddInteger(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, 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(PA, InsertPoint);
119
}
120
121
// Return the Attribute that we found or created.
122
return Attribute(PA);
123
}
124
125
Attribute Attribute::get(LLVMContext &Context, StringRef Kind, StringRef Val) {
126
LLVMContextImpl *pImpl = Context.pImpl;
127
FoldingSetNodeID ID;
128
ID.AddString(Kind);
129
if (!Val.empty()) ID.AddString(Val);
130
131
void *InsertPoint;
132
AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, 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(StringAttributeImpl::totalSizeToAlloc(Kind, Val),
139
alignof(StringAttributeImpl));
140
PA = new (Mem) StringAttributeImpl(Kind, Val);
141
pImpl->AttrsSet.InsertNode(PA, InsertPoint);
142
}
143
144
// Return the Attribute that we found or created.
145
return Attribute(PA);
146
}
147
148
Attribute 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(Kind);
154
ID.AddPointer(Ty);
155
156
void *InsertPoint;
157
AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, 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(PA, InsertPoint);
164
}
165
166
// Return the Attribute that we found or created.
167
return Attribute(PA);
168
}
169
170
Attribute 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(Kind);
177
CR.getLower().Profile(ID);
178
CR.getUpper().Profile(ID);
179
180
void *InsertPoint;
181
AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, 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(PA, InsertPoint);
189
}
190
191
// Return the Attribute that we found or created.
192
return Attribute(PA);
193
}
194
195
Attribute 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(Kind);
202
ID.AddInteger(Val.size());
203
for (auto &CR : Val) {
204
CR.getLower().Profile(ID);
205
CR.getUpper().Profile(ID);
206
}
207
208
void *InsertPoint;
209
AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, 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
ConstantRangeListAttributeImpl::totalSizeToAlloc(Val),
221
alignof(ConstantRangeListAttributeImpl));
222
PA = new (Mem) ConstantRangeListAttributeImpl(Kind, Val);
223
pImpl->AttrsSet.InsertNode(PA, InsertPoint);
224
pImpl->ConstantRangeListAttributes.push_back(
225
reinterpret_cast<ConstantRangeListAttributeImpl *>(PA));
226
}
227
228
// Return the Attribute that we found or created.
229
return Attribute(PA);
230
}
231
232
Attribute Attribute::getWithAlignment(LLVMContext &Context, Align A) {
233
assert(A <= llvm::Value::MaximumAlignment && "Alignment too large.");
234
return get(Context, Alignment, A.value());
235
}
236
237
Attribute Attribute::getWithStackAlignment(LLVMContext &Context, Align A) {
238
assert(A <= 0x100 && "Alignment too large.");
239
return get(Context, StackAlignment, A.value());
240
}
241
242
Attribute Attribute::getWithDereferenceableBytes(LLVMContext &Context,
243
uint64_t Bytes) {
244
assert(Bytes && "Bytes must be non-zero.");
245
return get(Context, Dereferenceable, Bytes);
246
}
247
248
Attribute Attribute::getWithDereferenceableOrNullBytes(LLVMContext &Context,
249
uint64_t Bytes) {
250
assert(Bytes && "Bytes must be non-zero.");
251
return get(Context, DereferenceableOrNull, Bytes);
252
}
253
254
Attribute Attribute::getWithByValType(LLVMContext &Context, Type *Ty) {
255
return get(Context, ByVal, Ty);
256
}
257
258
Attribute Attribute::getWithStructRetType(LLVMContext &Context, Type *Ty) {
259
return get(Context, StructRet, Ty);
260
}
261
262
Attribute Attribute::getWithByRefType(LLVMContext &Context, Type *Ty) {
263
return get(Context, ByRef, Ty);
264
}
265
266
Attribute Attribute::getWithPreallocatedType(LLVMContext &Context, Type *Ty) {
267
return get(Context, Preallocated, Ty);
268
}
269
270
Attribute Attribute::getWithInAllocaType(LLVMContext &Context, Type *Ty) {
271
return get(Context, InAlloca, Ty);
272
}
273
274
Attribute Attribute::getWithUWTableKind(LLVMContext &Context,
275
UWTableKind Kind) {
276
return get(Context, UWTable, uint64_t(Kind));
277
}
278
279
Attribute Attribute::getWithMemoryEffects(LLVMContext &Context,
280
MemoryEffects ME) {
281
return get(Context, Memory, ME.toIntValue());
282
}
283
284
Attribute Attribute::getWithNoFPClass(LLVMContext &Context,
285
FPClassTest ClassMask) {
286
return get(Context, NoFPClass, ClassMask);
287
}
288
289
Attribute
290
Attribute::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, AllocSize, packAllocSizeArgs(ElemSizeArg, NumElemsArg));
295
}
296
297
Attribute Attribute::getWithVScaleRangeArgs(LLVMContext &Context,
298
unsigned MinValue,
299
unsigned MaxValue) {
300
return get(Context, VScaleRange, packVScaleRangeArgs(MinValue, MaxValue));
301
}
302
303
Attribute::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(Attribute::None);
310
}
311
312
StringRef 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
326
bool 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(false);
332
}
333
334
//===----------------------------------------------------------------------===//
335
// Attribute Accessor Methods
336
//===----------------------------------------------------------------------===//
337
338
bool Attribute::isEnumAttribute() const {
339
return pImpl && pImpl->isEnumAttribute();
340
}
341
342
bool Attribute::isIntAttribute() const {
343
return pImpl && pImpl->isIntAttribute();
344
}
345
346
bool Attribute::isStringAttribute() const {
347
return pImpl && pImpl->isStringAttribute();
348
}
349
350
bool Attribute::isTypeAttribute() const {
351
return pImpl && pImpl->isTypeAttribute();
352
}
353
354
bool Attribute::isConstantRangeAttribute() const {
355
return pImpl && pImpl->isConstantRangeAttribute();
356
}
357
358
bool Attribute::isConstantRangeListAttribute() const {
359
return pImpl && pImpl->isConstantRangeListAttribute();
360
}
361
362
Attribute::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
370
uint64_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
377
bool 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
384
StringRef 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
391
StringRef 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
398
Type *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
405
const ConstantRange &Attribute::getValueAsConstantRange() const {
406
assert(isConstantRangeAttribute() &&
407
"Invalid attribute type to get the value as a ConstantRange!");
408
return pImpl->getValueAsConstantRange();
409
}
410
411
ArrayRef<ConstantRange> Attribute::getValueAsConstantRangeList() const {
412
assert(isConstantRangeListAttribute() &&
413
"Invalid attribute type to get the value as a ConstantRangeList!");
414
return pImpl->getValueAsConstantRangeList();
415
}
416
417
bool Attribute::hasAttribute(AttrKind Kind) const {
418
return (pImpl && pImpl->hasAttribute(Kind)) || (!pImpl && Kind == None);
419
}
420
421
bool Attribute::hasAttribute(StringRef Kind) const {
422
if (!isStringAttribute()) return false;
423
return pImpl && pImpl->hasAttribute(Kind);
424
}
425
426
MaybeAlign Attribute::getAlignment() const {
427
assert(hasAttribute(Attribute::Alignment) &&
428
"Trying to get alignment from non-alignment attribute!");
429
return MaybeAlign(pImpl->getValueAsInt());
430
}
431
432
MaybeAlign Attribute::getStackAlignment() const {
433
assert(hasAttribute(Attribute::StackAlignment) &&
434
"Trying to get alignment from non-alignment attribute!");
435
return MaybeAlign(pImpl->getValueAsInt());
436
}
437
438
uint64_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
445
uint64_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
452
std::pair<unsigned, std::optional<unsigned>>
453
Attribute::getAllocSizeArgs() const {
454
assert(hasAttribute(Attribute::AllocSize) &&
455
"Trying to get allocsize args from non-allocsize attribute");
456
return unpackAllocSizeArgs(pImpl->getValueAsInt());
457
}
458
459
unsigned Attribute::getVScaleRangeMin() const {
460
assert(hasAttribute(Attribute::VScaleRange) &&
461
"Trying to get vscale args from non-vscale attribute");
462
return unpackVScaleRangeArgs(pImpl->getValueAsInt()).first;
463
}
464
465
std::optional<unsigned> Attribute::getVScaleRangeMax() const {
466
assert(hasAttribute(Attribute::VScaleRange) &&
467
"Trying to get vscale args from non-vscale attribute");
468
return unpackVScaleRangeArgs(pImpl->getValueAsInt()).second;
469
}
470
471
UWTableKind 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
477
AllocFnKind 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
483
MemoryEffects Attribute::getMemoryEffects() const {
484
assert(hasAttribute(Attribute::Memory) &&
485
"Can only call getMemoryEffects() on memory attribute");
486
return MemoryEffects::createFromIntValue(pImpl->getValueAsInt());
487
}
488
489
FPClassTest 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
495
const 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
501
ArrayRef<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
507
static 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
521
std::string Attribute::getAsString(bool InAttrGrp) const {
522
if (!pImpl) return {};
523
524
if (isEnumAttribute())
525
return getNameFromAttrKind(getKindAsEnum()).str();
526
527
if (isTypeAttribute()) {
528
std::string Result = getNameFromAttrKind(getKindAsEnum()).str();
529
Result += '(';
530
raw_string_ostream OS(Result);
531
getValueAsType()->print(OS, false, 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(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(Attribute::StackAlignment))
554
return AttrWithBytesToString("alignstack");
555
556
if (hasAttribute(Attribute::Dereferenceable))
557
return AttrWithBytesToString("dereferenceable");
558
559
if (hasAttribute(Attribute::DereferenceableOrNull))
560
return AttrWithBytesToString("dereferenceable_or_null");
561
562
if (hasAttribute(Attribute::AllocSize)) {
563
unsigned ElemSize;
564
std::optional<unsigned> NumElems;
565
std::tie(ElemSize, NumElems) = getAllocSizeArgs();
566
567
return (NumElems
568
? "allocsize(" + Twine(ElemSize) + "," + Twine(*NumElems) + ")"
569
: "allocsize(" + Twine(ElemSize) + ")")
570
.str();
571
}
572
573
if (hasAttribute(Attribute::VScaleRange)) {
574
unsigned MinValue = getVScaleRangeMin();
575
std::optional<unsigned> MaxValue = getVScaleRangeMax();
576
return ("vscale_range(" + Twine(MinValue) + "," +
577
Twine(MaxValue.value_or(0)) + ")")
578
.str();
579
}
580
581
if (hasAttribute(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(Attribute::AllocKind)) {
588
AllocFnKind Kind = getAllocKind();
589
SmallVector<StringRef> parts;
590
if ((Kind & AllocFnKind::Alloc) != AllocFnKind::Unknown)
591
parts.push_back("alloc");
592
if ((Kind & AllocFnKind::Realloc) != AllocFnKind::Unknown)
593
parts.push_back("realloc");
594
if ((Kind & AllocFnKind::Free) != AllocFnKind::Unknown)
595
parts.push_back("free");
596
if ((Kind & AllocFnKind::Uninitialized) != AllocFnKind::Unknown)
597
parts.push_back("uninitialized");
598
if ((Kind & AllocFnKind::Zeroed) != AllocFnKind::Unknown)
599
parts.push_back("zeroed");
600
if ((Kind & AllocFnKind::Aligned) != AllocFnKind::Unknown)
601
parts.push_back("aligned");
602
return ("allockind(\"" +
603
Twine(llvm::join(parts.begin(), parts.end(), ",")) + "\")")
604
.str();
605
}
606
607
if (hasAttribute(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(IRMemLocation::Other);
618
if (OtherMR != ModRefInfo::NoModRef || ME.getModRef() == OtherMR) {
619
First = false;
620
OS << getModRefStr(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(Attribute::NoFPClass)) {
650
std::string Result = "nofpclass";
651
raw_string_ostream OS(Result);
652
OS << getNoFPClass();
653
return Result;
654
}
655
656
if (hasAttribute(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(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(AttrVal, OS);
697
OS << "\"";
698
}
699
}
700
return Result;
701
}
702
703
llvm_unreachable("Unknown attribute");
704
}
705
706
bool 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, Unused) == pImpl;
712
}
713
714
bool 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
721
void Attribute::Profile(FoldingSetNodeID &ID) const {
722
ID.AddPointer(pImpl);
723
}
724
725
enum 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
734
static 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
741
bool Attribute::canUseAsFnAttr(AttrKind Kind) {
742
return hasAttributeProperty(Kind, AttributeProperty::FnAttr);
743
}
744
745
bool Attribute::canUseAsParamAttr(AttrKind Kind) {
746
return hasAttributeProperty(Kind, AttributeProperty::ParamAttr);
747
}
748
749
bool Attribute::canUseAsRetAttr(AttrKind Kind) {
750
return hasAttributeProperty(Kind, AttributeProperty::RetAttr);
751
}
752
753
//===----------------------------------------------------------------------===//
754
// AttributeImpl Definition
755
//===----------------------------------------------------------------------===//
756
757
bool AttributeImpl::hasAttribute(Attribute::AttrKind A) const {
758
if (isStringAttribute()) return false;
759
return getKindAsEnum() == A;
760
}
761
762
bool AttributeImpl::hasAttribute(StringRef Kind) const {
763
if (!isStringAttribute()) return false;
764
return getKindAsString() == Kind;
765
}
766
767
Attribute::AttrKind AttributeImpl::getKindAsEnum() const {
768
assert(isEnumAttribute() || isIntAttribute() || isTypeAttribute() ||
769
isConstantRangeAttribute() || isConstantRangeListAttribute());
770
return static_cast<const EnumAttributeImpl *>(this)->getEnumKind();
771
}
772
773
uint64_t AttributeImpl::getValueAsInt() const {
774
assert(isIntAttribute());
775
return static_cast<const IntAttributeImpl *>(this)->getValue();
776
}
777
778
bool AttributeImpl::getValueAsBool() const {
779
assert(getValueAsString().empty() || getValueAsString() == "false" || getValueAsString() == "true");
780
return getValueAsString() == "true";
781
}
782
783
StringRef AttributeImpl::getKindAsString() const {
784
assert(isStringAttribute());
785
return static_cast<const StringAttributeImpl *>(this)->getStringKind();
786
}
787
788
StringRef AttributeImpl::getValueAsString() const {
789
assert(isStringAttribute());
790
return static_cast<const StringAttributeImpl *>(this)->getStringValue();
791
}
792
793
Type *AttributeImpl::getValueAsType() const {
794
assert(isTypeAttribute());
795
return static_cast<const TypeAttributeImpl *>(this)->getTypeValue();
796
}
797
798
const ConstantRange &AttributeImpl::getValueAsConstantRange() const {
799
assert(isConstantRangeAttribute());
800
return static_cast<const ConstantRangeAttributeImpl *>(this)
801
->getConstantRangeValue();
802
}
803
804
ArrayRef<ConstantRange> AttributeImpl::getValueAsConstantRangeList() const {
805
assert(isConstantRangeListAttribute());
806
return static_cast<const ConstantRangeListAttributeImpl *>(this)
807
->getConstantRangeListValue();
808
}
809
810
bool 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
842
AttributeSet AttributeSet::get(LLVMContext &C, const AttrBuilder &B) {
843
return AttributeSet(AttributeSetNode::get(C, B));
844
}
845
846
AttributeSet AttributeSet::get(LLVMContext &C, ArrayRef<Attribute> Attrs) {
847
return AttributeSet(AttributeSetNode::get(C, Attrs));
848
}
849
850
AttributeSet AttributeSet::addAttribute(LLVMContext &C,
851
Attribute::AttrKind Kind) const {
852
if (hasAttribute(Kind)) return *this;
853
AttrBuilder B(C);
854
B.addAttribute(Kind);
855
return addAttributes(C, AttributeSet::get(C, B));
856
}
857
858
AttributeSet AttributeSet::addAttribute(LLVMContext &C, StringRef Kind,
859
StringRef Value) const {
860
AttrBuilder B(C);
861
B.addAttribute(Kind, Value);
862
return addAttributes(C, AttributeSet::get(C, B));
863
}
864
865
AttributeSet 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(AttrBuilder(C, AS));
875
return get(C, B);
876
}
877
878
AttributeSet AttributeSet::removeAttribute(LLVMContext &C,
879
Attribute::AttrKind Kind) const {
880
if (!hasAttribute(Kind)) return *this;
881
AttrBuilder B(C, *this);
882
B.removeAttribute(Kind);
883
return get(C, B);
884
}
885
886
AttributeSet AttributeSet::removeAttribute(LLVMContext &C,
887
StringRef Kind) const {
888
if (!hasAttribute(Kind)) return *this;
889
AttrBuilder B(C, *this);
890
B.removeAttribute(Kind);
891
return get(C, B);
892
}
893
894
AttributeSet 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(Attrs))
899
return *this;
900
901
B.remove(Attrs);
902
return get(C, B);
903
}
904
905
unsigned AttributeSet::getNumAttributes() const {
906
return SetNode ? SetNode->getNumAttributes() : 0;
907
}
908
909
bool AttributeSet::hasAttribute(Attribute::AttrKind Kind) const {
910
return SetNode ? SetNode->hasAttribute(Kind) : false;
911
}
912
913
bool AttributeSet::hasAttribute(StringRef Kind) const {
914
return SetNode ? SetNode->hasAttribute(Kind) : false;
915
}
916
917
Attribute AttributeSet::getAttribute(Attribute::AttrKind Kind) const {
918
return SetNode ? SetNode->getAttribute(Kind) : Attribute();
919
}
920
921
Attribute AttributeSet::getAttribute(StringRef Kind) const {
922
return SetNode ? SetNode->getAttribute(Kind) : Attribute();
923
}
924
925
MaybeAlign AttributeSet::getAlignment() const {
926
return SetNode ? SetNode->getAlignment() : std::nullopt;
927
}
928
929
MaybeAlign AttributeSet::getStackAlignment() const {
930
return SetNode ? SetNode->getStackAlignment() : std::nullopt;
931
}
932
933
uint64_t AttributeSet::getDereferenceableBytes() const {
934
return SetNode ? SetNode->getDereferenceableBytes() : 0;
935
}
936
937
uint64_t AttributeSet::getDereferenceableOrNullBytes() const {
938
return SetNode ? SetNode->getDereferenceableOrNullBytes() : 0;
939
}
940
941
Type *AttributeSet::getByRefType() const {
942
return SetNode ? SetNode->getAttributeType(Attribute::ByRef) : nullptr;
943
}
944
945
Type *AttributeSet::getByValType() const {
946
return SetNode ? SetNode->getAttributeType(Attribute::ByVal) : nullptr;
947
}
948
949
Type *AttributeSet::getStructRetType() const {
950
return SetNode ? SetNode->getAttributeType(Attribute::StructRet) : nullptr;
951
}
952
953
Type *AttributeSet::getPreallocatedType() const {
954
return SetNode ? SetNode->getAttributeType(Attribute::Preallocated) : nullptr;
955
}
956
957
Type *AttributeSet::getInAllocaType() const {
958
return SetNode ? SetNode->getAttributeType(Attribute::InAlloca) : nullptr;
959
}
960
961
Type *AttributeSet::getElementType() const {
962
return SetNode ? SetNode->getAttributeType(Attribute::ElementType) : nullptr;
963
}
964
965
std::optional<std::pair<unsigned, std::optional<unsigned>>>
966
AttributeSet::getAllocSizeArgs() const {
967
if (SetNode)
968
return SetNode->getAllocSizeArgs();
969
return std::nullopt;
970
}
971
972
unsigned AttributeSet::getVScaleRangeMin() const {
973
return SetNode ? SetNode->getVScaleRangeMin() : 1;
974
}
975
976
std::optional<unsigned> AttributeSet::getVScaleRangeMax() const {
977
return SetNode ? SetNode->getVScaleRangeMax() : std::nullopt;
978
}
979
980
UWTableKind AttributeSet::getUWTableKind() const {
981
return SetNode ? SetNode->getUWTableKind() : UWTableKind::None;
982
}
983
984
AllocFnKind AttributeSet::getAllocKind() const {
985
return SetNode ? SetNode->getAllocKind() : AllocFnKind::Unknown;
986
}
987
988
MemoryEffects AttributeSet::getMemoryEffects() const {
989
return SetNode ? SetNode->getMemoryEffects() : MemoryEffects::unknown();
990
}
991
992
FPClassTest AttributeSet::getNoFPClass() const {
993
return SetNode ? SetNode->getNoFPClass() : fcNone;
994
}
995
996
std::string AttributeSet::getAsString(bool InAttrGrp) const {
997
return SetNode ? SetNode->getAsString(InAttrGrp) : "";
998
}
999
1000
bool 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, Unused) == SetNode;
1006
}
1007
1008
AttributeSet::iterator AttributeSet::begin() const {
1009
return SetNode ? SetNode->begin() : nullptr;
1010
}
1011
1012
AttributeSet::iterator AttributeSet::end() const {
1013
return SetNode ? SetNode->end() : nullptr;
1014
}
1015
1016
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1017
LLVM_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
1028
AttributeSetNode::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(Attrs, getTrailingObjects<Attribute>());
1032
1033
for (const auto &I : *this) {
1034
if (I.isStringAttribute())
1035
StringAttrs.insert({ I.getKindAsString(), I });
1036
else
1037
AvailableAttrs.addAttribute(I.getKindAsEnum());
1038
}
1039
}
1040
1041
AttributeSetNode *AttributeSetNode::get(LLVMContext &C,
1042
ArrayRef<Attribute> Attrs) {
1043
SmallVector<Attribute, 8> SortedAttrs(Attrs.begin(), Attrs.end());
1044
llvm::sort(SortedAttrs);
1045
return getSorted(C, SortedAttrs);
1046
}
1047
1048
AttributeSetNode *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, 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>(SortedAttrs.size()));
1070
PA = new (Mem) AttributeSetNode(SortedAttrs);
1071
pImpl->AttrsSetNodes.InsertNode(PA, InsertPoint);
1072
}
1073
1074
// Return the AttributeSetNode that we found or created.
1075
return PA;
1076
}
1077
1078
AttributeSetNode *AttributeSetNode::get(LLVMContext &C, const AttrBuilder &B) {
1079
return getSorted(C, B.attrs());
1080
}
1081
1082
bool AttributeSetNode::hasAttribute(StringRef Kind) const {
1083
return StringAttrs.count(Kind);
1084
}
1085
1086
std::optional<Attribute>
1087
AttributeSetNode::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(begin(), end() - StringAttrs.size(), Kind,
1096
[](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
1103
Attribute AttributeSetNode::getAttribute(Attribute::AttrKind Kind) const {
1104
if (auto A = findEnumAttribute(Kind))
1105
return *A;
1106
return {};
1107
}
1108
1109
Attribute AttributeSetNode::getAttribute(StringRef Kind) const {
1110
return StringAttrs.lookup(Kind);
1111
}
1112
1113
MaybeAlign AttributeSetNode::getAlignment() const {
1114
if (auto A = findEnumAttribute(Attribute::Alignment))
1115
return A->getAlignment();
1116
return std::nullopt;
1117
}
1118
1119
MaybeAlign AttributeSetNode::getStackAlignment() const {
1120
if (auto A = findEnumAttribute(Attribute::StackAlignment))
1121
return A->getStackAlignment();
1122
return std::nullopt;
1123
}
1124
1125
Type *AttributeSetNode::getAttributeType(Attribute::AttrKind Kind) const {
1126
if (auto A = findEnumAttribute(Kind))
1127
return A->getValueAsType();
1128
return nullptr;
1129
}
1130
1131
uint64_t AttributeSetNode::getDereferenceableBytes() const {
1132
if (auto A = findEnumAttribute(Attribute::Dereferenceable))
1133
return A->getDereferenceableBytes();
1134
return 0;
1135
}
1136
1137
uint64_t AttributeSetNode::getDereferenceableOrNullBytes() const {
1138
if (auto A = findEnumAttribute(Attribute::DereferenceableOrNull))
1139
return A->getDereferenceableOrNullBytes();
1140
return 0;
1141
}
1142
1143
std::optional<std::pair<unsigned, std::optional<unsigned>>>
1144
AttributeSetNode::getAllocSizeArgs() const {
1145
if (auto A = findEnumAttribute(Attribute::AllocSize))
1146
return A->getAllocSizeArgs();
1147
return std::nullopt;
1148
}
1149
1150
unsigned AttributeSetNode::getVScaleRangeMin() const {
1151
if (auto A = findEnumAttribute(Attribute::VScaleRange))
1152
return A->getVScaleRangeMin();
1153
return 1;
1154
}
1155
1156
std::optional<unsigned> AttributeSetNode::getVScaleRangeMax() const {
1157
if (auto A = findEnumAttribute(Attribute::VScaleRange))
1158
return A->getVScaleRangeMax();
1159
return std::nullopt;
1160
}
1161
1162
UWTableKind AttributeSetNode::getUWTableKind() const {
1163
if (auto A = findEnumAttribute(Attribute::UWTable))
1164
return A->getUWTableKind();
1165
return UWTableKind::None;
1166
}
1167
1168
AllocFnKind AttributeSetNode::getAllocKind() const {
1169
if (auto A = findEnumAttribute(Attribute::AllocKind))
1170
return A->getAllocKind();
1171
return AllocFnKind::Unknown;
1172
}
1173
1174
MemoryEffects AttributeSetNode::getMemoryEffects() const {
1175
if (auto A = findEnumAttribute(Attribute::Memory))
1176
return A->getMemoryEffects();
1177
return MemoryEffects::unknown();
1178
}
1179
1180
FPClassTest AttributeSetNode::getNoFPClass() const {
1181
if (auto A = findEnumAttribute(Attribute::NoFPClass))
1182
return A->getNoFPClass();
1183
return fcNone;
1184
}
1185
1186
std::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.
1202
static unsigned attrIdxToArrayIdx(unsigned Index) {
1203
return Index + 1;
1204
}
1205
1206
AttributeListImpl::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(Sets, getTrailingObjects<AttributeSet>());
1212
1213
// Initialize AvailableFunctionAttrs and AvailableSomewhereAttrs
1214
// summary bitsets.
1215
for (const auto &I : Sets[attrIdxToArrayIdx(AttributeList::FunctionIndex)])
1216
if (!I.isStringAttribute())
1217
AvailableFunctionAttrs.addAttribute(I.getKindAsEnum());
1218
1219
for (const auto &Set : Sets)
1220
for (const auto &I : Set)
1221
if (!I.isStringAttribute())
1222
AvailableSomewhereAttrs.addAttribute(I.getKindAsEnum());
1223
}
1224
1225
void AttributeListImpl::Profile(FoldingSetNodeID &ID) const {
1226
Profile(ID, ArrayRef(begin(), end()));
1227
}
1228
1229
void AttributeListImpl::Profile(FoldingSetNodeID &ID,
1230
ArrayRef<AttributeSet> Sets) {
1231
for (const auto &Set : Sets)
1232
ID.AddPointer(Set.SetNode);
1233
}
1234
1235
bool 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)
1254
LLVM_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
1263
AttributeList 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, AttrSets);
1270
1271
void *InsertPoint;
1272
AttributeListImpl *PA =
1273
pImpl->AttrsLists.FindNodeOrInsertPos(ID, 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
AttributeListImpl::totalSizeToAlloc<AttributeSet>(AttrSets.size()),
1281
alignof(AttributeListImpl));
1282
PA = new (Mem) AttributeListImpl(AttrSets);
1283
pImpl->AttrsLists.InsertNode(PA, InsertPoint);
1284
}
1285
1286
// Return the AttributesList that we found or created.
1287
return AttributeList(PA);
1288
}
1289
1290
AttributeList
1291
AttributeList::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(I->second);
1314
++I;
1315
}
1316
1317
AttrPairVec.emplace_back(Index, AttributeSet::get(C, AttrVec));
1318
}
1319
1320
return get(C, AttrPairVec);
1321
}
1322
1323
AttributeList
1324
AttributeList::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(MaxIndex) + 1);
1345
for (const auto &Pair : Attrs)
1346
AttrVec[attrIdxToArrayIdx(Pair.first)] = Pair.second;
1347
1348
return getImpl(C, AttrVec);
1349
}
1350
1351
AttributeList 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(NumSets);
1379
// If we have any attributes, we always have function attributes.
1380
AttrSets.push_back(FnAttrs);
1381
if (NumSets > 1)
1382
AttrSets.push_back(RetAttrs);
1383
if (NumSets > 2) {
1384
// Drop the empty argument attribute sets at the end.
1385
ArgAttrs = ArgAttrs.take_front(NumSets - 2);
1386
llvm::append_range(AttrSets, ArgAttrs);
1387
}
1388
1389
return getImpl(C, AttrSets);
1390
}
1391
1392
AttributeList 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
1402
AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
1403
const AttrBuilder &B) {
1404
return get(C, Index, AttributeSet::get(C, B));
1405
}
1406
1407
AttributeList 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(Index, Attribute::get(C, K));
1412
return get(C, Attrs);
1413
}
1414
1415
AttributeList 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(Index, Attribute::get(C, K, *VI++));
1423
return get(C, Attrs);
1424
}
1425
1426
AttributeList 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(Index, Attribute::get(C, K));
1431
return get(C, Attrs);
1432
}
1433
1434
AttributeList 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(MaxSize, 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(AttrBuilder(C, List.getAttributes(I - 1)));
1454
NewAttrSets[I] = AttributeSet::get(C, CurBuilder);
1455
}
1456
1457
return getImpl(C, NewAttrSets);
1458
}
1459
1460
AttributeList
1461
AttributeList::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(Attribute::get(C, Kind));
1469
return setAttributesAtIndex(C, Index, AttributeSet::get(C, NewAttrs));
1470
}
1471
1472
AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index,
1473
StringRef Kind,
1474
StringRef Value) const {
1475
AttrBuilder B(C);
1476
B.addAttribute(Kind, Value);
1477
return addAttributesAtIndex(C, Index, B);
1478
}
1479
1480
AttributeList 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
1487
AttributeList 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(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
1504
AttributeList 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, {{Index, AttributeSet::get(C, B)}});
1512
1513
AttrBuilder Merged(C, getAttributes(Index));
1514
Merged.merge(B);
1515
return setAttributesAtIndex(C, Index, AttributeSet::get(C, Merged));
1516
}
1517
1518
AttributeList 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(ArgNos.back() + FirstArgIndex);
1525
if (MaxIndex >= AttrSets.size())
1526
AttrSets.resize(MaxIndex + 1);
1527
1528
for (unsigned ArgNo : ArgNos) {
1529
unsigned Index = attrIdxToArrayIdx(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
1538
AttributeList
1539
AttributeList::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, NewAttrs);
1546
}
1547
1548
AttributeList 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, NewAttrs);
1556
}
1557
1558
AttributeList AttributeList::removeAttributesAtIndex(
1559
LLVMContext &C, unsigned Index, const AttributeMask &AttrsToRemove) const {
1560
AttributeSet Attrs = getAttributes(Index);
1561
AttributeSet NewAttrs = Attrs.removeAttributes(C, AttrsToRemove);
1562
// If nothing was removed, return the original list.
1563
if (Attrs == NewAttrs)
1564
return *this;
1565
return setAttributesAtIndex(C, Index, NewAttrs);
1566
}
1567
1568
AttributeList
1569
AttributeList::removeAttributesAtIndex(LLVMContext &C,
1570
unsigned WithoutIndex) const {
1571
if (!pImpl)
1572
return {};
1573
if (attrIdxToArrayIdx(WithoutIndex) >= getNumAttrSets())
1574
return *this;
1575
return setAttributesAtIndex(C, WithoutIndex, AttributeSet());
1576
}
1577
1578
AttributeList AttributeList::addDereferenceableRetAttr(LLVMContext &C,
1579
uint64_t Bytes) const {
1580
AttrBuilder B(C);
1581
B.addDereferenceableAttr(Bytes);
1582
return addRetAttributes(C, B);
1583
}
1584
1585
AttributeList AttributeList::addDereferenceableParamAttr(LLVMContext &C,
1586
unsigned Index,
1587
uint64_t Bytes) const {
1588
AttrBuilder B(C);
1589
B.addDereferenceableAttr(Bytes);
1590
return addParamAttributes(C, Index, B);
1591
}
1592
1593
AttributeList
1594
AttributeList::addDereferenceableOrNullParamAttr(LLVMContext &C, unsigned Index,
1595
uint64_t Bytes) const {
1596
AttrBuilder B(C);
1597
B.addDereferenceableOrNullAttr(Bytes);
1598
return addParamAttributes(C, Index, B);
1599
}
1600
1601
AttributeList AttributeList::addRangeRetAttr(LLVMContext &C,
1602
const ConstantRange &CR) const {
1603
AttrBuilder B(C);
1604
B.addRangeAttr(CR);
1605
return addRetAttributes(C, B);
1606
}
1607
1608
AttributeList 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, Index, B);
1614
}
1615
1616
//===----------------------------------------------------------------------===//
1617
// AttributeList Accessor Methods
1618
//===----------------------------------------------------------------------===//
1619
1620
AttributeSet AttributeList::getParamAttrs(unsigned ArgNo) const {
1621
return getAttributes(ArgNo + FirstArgIndex);
1622
}
1623
1624
AttributeSet AttributeList::getRetAttrs() const {
1625
return getAttributes(ReturnIndex);
1626
}
1627
1628
AttributeSet AttributeList::getFnAttrs() const {
1629
return getAttributes(FunctionIndex);
1630
}
1631
1632
bool AttributeList::hasAttributeAtIndex(unsigned Index,
1633
Attribute::AttrKind Kind) const {
1634
return getAttributes(Index).hasAttribute(Kind);
1635
}
1636
1637
bool AttributeList::hasAttributeAtIndex(unsigned Index, StringRef Kind) const {
1638
return getAttributes(Index).hasAttribute(Kind);
1639
}
1640
1641
bool AttributeList::hasAttributesAtIndex(unsigned Index) const {
1642
return getAttributes(Index).hasAttributes();
1643
}
1644
1645
bool AttributeList::hasFnAttr(Attribute::AttrKind Kind) const {
1646
return pImpl && pImpl->hasFnAttribute(Kind);
1647
}
1648
1649
bool AttributeList::hasFnAttr(StringRef Kind) const {
1650
return hasAttributeAtIndex(AttributeList::FunctionIndex, Kind);
1651
}
1652
1653
bool AttributeList::hasAttrSomewhere(Attribute::AttrKind Attr,
1654
unsigned *Index) const {
1655
return pImpl && pImpl->hasAttrSomewhere(Attr, Index);
1656
}
1657
1658
Attribute AttributeList::getAttributeAtIndex(unsigned Index,
1659
Attribute::AttrKind Kind) const {
1660
return getAttributes(Index).getAttribute(Kind);
1661
}
1662
1663
Attribute AttributeList::getAttributeAtIndex(unsigned Index,
1664
StringRef Kind) const {
1665
return getAttributes(Index).getAttribute(Kind);
1666
}
1667
1668
MaybeAlign AttributeList::getRetAlignment() const {
1669
return getAttributes(ReturnIndex).getAlignment();
1670
}
1671
1672
MaybeAlign AttributeList::getParamAlignment(unsigned ArgNo) const {
1673
return getAttributes(ArgNo + FirstArgIndex).getAlignment();
1674
}
1675
1676
MaybeAlign AttributeList::getParamStackAlignment(unsigned ArgNo) const {
1677
return getAttributes(ArgNo + FirstArgIndex).getStackAlignment();
1678
}
1679
1680
Type *AttributeList::getParamByValType(unsigned Index) const {
1681
return getAttributes(Index+FirstArgIndex).getByValType();
1682
}
1683
1684
Type *AttributeList::getParamStructRetType(unsigned Index) const {
1685
return getAttributes(Index + FirstArgIndex).getStructRetType();
1686
}
1687
1688
Type *AttributeList::getParamByRefType(unsigned Index) const {
1689
return getAttributes(Index + FirstArgIndex).getByRefType();
1690
}
1691
1692
Type *AttributeList::getParamPreallocatedType(unsigned Index) const {
1693
return getAttributes(Index + FirstArgIndex).getPreallocatedType();
1694
}
1695
1696
Type *AttributeList::getParamInAllocaType(unsigned Index) const {
1697
return getAttributes(Index + FirstArgIndex).getInAllocaType();
1698
}
1699
1700
Type *AttributeList::getParamElementType(unsigned Index) const {
1701
return getAttributes(Index + FirstArgIndex).getElementType();
1702
}
1703
1704
MaybeAlign AttributeList::getFnStackAlignment() const {
1705
return getFnAttrs().getStackAlignment();
1706
}
1707
1708
MaybeAlign AttributeList::getRetStackAlignment() const {
1709
return getRetAttrs().getStackAlignment();
1710
}
1711
1712
uint64_t AttributeList::getRetDereferenceableBytes() const {
1713
return getRetAttrs().getDereferenceableBytes();
1714
}
1715
1716
uint64_t AttributeList::getParamDereferenceableBytes(unsigned Index) const {
1717
return getParamAttrs(Index).getDereferenceableBytes();
1718
}
1719
1720
uint64_t AttributeList::getRetDereferenceableOrNullBytes() const {
1721
return getRetAttrs().getDereferenceableOrNullBytes();
1722
}
1723
1724
uint64_t
1725
AttributeList::getParamDereferenceableOrNullBytes(unsigned Index) const {
1726
return getParamAttrs(Index).getDereferenceableOrNullBytes();
1727
}
1728
1729
FPClassTest AttributeList::getRetNoFPClass() const {
1730
return getRetAttrs().getNoFPClass();
1731
}
1732
1733
FPClassTest AttributeList::getParamNoFPClass(unsigned Index) const {
1734
return getParamAttrs(Index).getNoFPClass();
1735
}
1736
1737
UWTableKind AttributeList::getUWTableKind() const {
1738
return getFnAttrs().getUWTableKind();
1739
}
1740
1741
AllocFnKind AttributeList::getAllocKind() const {
1742
return getFnAttrs().getAllocKind();
1743
}
1744
1745
MemoryEffects AttributeList::getMemoryEffects() const {
1746
return getFnAttrs().getMemoryEffects();
1747
}
1748
1749
std::string AttributeList::getAsString(unsigned Index, bool InAttrGrp) const {
1750
return getAttributes(Index).getAsString(InAttrGrp);
1751
}
1752
1753
AttributeSet AttributeList::getAttributes(unsigned Index) const {
1754
Index = attrIdxToArrayIdx(Index);
1755
if (!pImpl || Index >= getNumAttrSets())
1756
return {};
1757
return pImpl->begin()[Index];
1758
}
1759
1760
bool 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, Unused) == pImpl;
1766
}
1767
1768
AttributeList::iterator AttributeList::begin() const {
1769
return pImpl ? pImpl->begin() : nullptr;
1770
}
1771
1772
AttributeList::iterator AttributeList::end() const {
1773
return pImpl ? pImpl->end() : nullptr;
1774
}
1775
1776
//===----------------------------------------------------------------------===//
1777
// AttributeList Introspection Methods
1778
//===----------------------------------------------------------------------===//
1779
1780
unsigned AttributeList::getNumAttrSets() const {
1781
return pImpl ? pImpl->NumAttrSets : 0;
1782
}
1783
1784
void AttributeList::print(raw_ostream &O) const {
1785
O << "AttributeList[\n";
1786
1787
for (unsigned i : indexes()) {
1788
if (!getAttributes(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(i) << " }\n";
1802
}
1803
1804
O << "]\n";
1805
}
1806
1807
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1808
LLVM_DUMP_METHOD void AttributeList::dump() const { print(dbgs()); }
1809
#endif
1810
1811
//===----------------------------------------------------------------------===//
1812
// AttrBuilder Method Implementations
1813
//===----------------------------------------------------------------------===//
1814
1815
AttrBuilder::AttrBuilder(LLVMContext &Ctx, AttributeSet AS) : Ctx(Ctx) {
1816
append_range(Attrs, AS);
1817
assert(is_sorted(Attrs) && "AttributeSet should be sorted");
1818
}
1819
1820
void AttrBuilder::clear() { Attrs.clear(); }
1821
1822
/// Attribute comparator that only compares attribute keys. Enum attributes are
1823
/// sorted before string attributes.
1824
struct 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
1850
template <typename K>
1851
static 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
1860
AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) {
1861
if (Attr.isStringAttribute())
1862
addAttributeImpl(Attrs, Attr.getKindAsString(), Attr);
1863
else
1864
addAttributeImpl(Attrs, Attr.getKindAsEnum(), Attr);
1865
return *this;
1866
}
1867
1868
AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Kind) {
1869
addAttributeImpl(Attrs, Kind, Attribute::get(Ctx, Kind));
1870
return *this;
1871
}
1872
1873
AttrBuilder &AttrBuilder::addAttribute(StringRef A, StringRef V) {
1874
addAttributeImpl(Attrs, A, Attribute::get(Ctx, A, V));
1875
return *this;
1876
}
1877
1878
AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) {
1879
assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!");
1880
auto It = lower_bound(Attrs, Val, AttributeComparator());
1881
if (It != Attrs.end() && It->hasAttribute(Val))
1882
Attrs.erase(It);
1883
return *this;
1884
}
1885
1886
AttrBuilder &AttrBuilder::removeAttribute(StringRef A) {
1887
auto It = lower_bound(Attrs, A, AttributeComparator());
1888
if (It != Attrs.end() && It->hasAttribute(A))
1889
Attrs.erase(It);
1890
return *this;
1891
}
1892
1893
std::optional<uint64_t>
1894
AttrBuilder::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
1902
AttrBuilder &AttrBuilder::addRawIntAttr(Attribute::AttrKind Kind,
1903
uint64_t Value) {
1904
return addAttribute(Attribute::get(Ctx, Kind, Value));
1905
}
1906
1907
std::optional<std::pair<unsigned, std::optional<unsigned>>>
1908
AttrBuilder::getAllocSizeArgs() const {
1909
Attribute A = getAttribute(Attribute::AllocSize);
1910
if (A.isValid())
1911
return A.getAllocSizeArgs();
1912
return std::nullopt;
1913
}
1914
1915
AttrBuilder &AttrBuilder::addAlignmentAttr(MaybeAlign Align) {
1916
if (!Align)
1917
return *this;
1918
1919
assert(*Align <= llvm::Value::MaximumAlignment && "Alignment too large.");
1920
return addRawIntAttr(Attribute::Alignment, Align->value());
1921
}
1922
1923
AttrBuilder &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(Attribute::StackAlignment, Align->value());
1930
}
1931
1932
AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) {
1933
if (Bytes == 0) return *this;
1934
1935
return addRawIntAttr(Attribute::Dereferenceable, Bytes);
1936
}
1937
1938
AttrBuilder &AttrBuilder::addDereferenceableOrNullAttr(uint64_t Bytes) {
1939
if (Bytes == 0)
1940
return *this;
1941
1942
return addRawIntAttr(Attribute::DereferenceableOrNull, Bytes);
1943
}
1944
1945
AttrBuilder &
1946
AttrBuilder::addAllocSizeAttr(unsigned ElemSize,
1947
const std::optional<unsigned> &NumElems) {
1948
return addAllocSizeAttrFromRawRepr(packAllocSizeArgs(ElemSize, NumElems));
1949
}
1950
1951
AttrBuilder &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(Attribute::AllocSize, RawArgs);
1955
}
1956
1957
AttrBuilder &AttrBuilder::addVScaleRangeAttr(unsigned MinValue,
1958
std::optional<unsigned> MaxValue) {
1959
return addVScaleRangeAttrFromRawRepr(packVScaleRangeArgs(MinValue, MaxValue));
1960
}
1961
1962
AttrBuilder &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(Attribute::VScaleRange, RawArgs);
1968
}
1969
1970
AttrBuilder &AttrBuilder::addUWTableAttr(UWTableKind Kind) {
1971
if (Kind == UWTableKind::None)
1972
return *this;
1973
return addRawIntAttr(Attribute::UWTable, uint64_t(Kind));
1974
}
1975
1976
AttrBuilder &AttrBuilder::addMemoryAttr(MemoryEffects ME) {
1977
return addRawIntAttr(Attribute::Memory, ME.toIntValue());
1978
}
1979
1980
AttrBuilder &AttrBuilder::addNoFPClassAttr(FPClassTest Mask) {
1981
if (Mask == fcNone)
1982
return *this;
1983
1984
return addRawIntAttr(Attribute::NoFPClass, Mask);
1985
}
1986
1987
AttrBuilder &AttrBuilder::addAllocKindAttr(AllocFnKind Kind) {
1988
return addRawIntAttr(Attribute::AllocKind, static_cast<uint64_t>(Kind));
1989
}
1990
1991
Type *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
1997
AttrBuilder &AttrBuilder::addTypeAttr(Attribute::AttrKind Kind, Type *Ty) {
1998
return addAttribute(Attribute::get(Ctx, Kind, Ty));
1999
}
2000
2001
AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) {
2002
return addTypeAttr(Attribute::ByVal, Ty);
2003
}
2004
2005
AttrBuilder &AttrBuilder::addStructRetAttr(Type *Ty) {
2006
return addTypeAttr(Attribute::StructRet, Ty);
2007
}
2008
2009
AttrBuilder &AttrBuilder::addByRefAttr(Type *Ty) {
2010
return addTypeAttr(Attribute::ByRef, Ty);
2011
}
2012
2013
AttrBuilder &AttrBuilder::addPreallocatedAttr(Type *Ty) {
2014
return addTypeAttr(Attribute::Preallocated, Ty);
2015
}
2016
2017
AttrBuilder &AttrBuilder::addInAllocaAttr(Type *Ty) {
2018
return addTypeAttr(Attribute::InAlloca, Ty);
2019
}
2020
2021
AttrBuilder &AttrBuilder::addConstantRangeAttr(Attribute::AttrKind Kind,
2022
const ConstantRange &CR) {
2023
return addAttribute(Attribute::get(Ctx, Kind, CR));
2024
}
2025
2026
AttrBuilder &AttrBuilder::addRangeAttr(const ConstantRange &CR) {
2027
return addConstantRangeAttr(Attribute::Range, CR);
2028
}
2029
2030
AttrBuilder &
2031
AttrBuilder::addConstantRangeListAttr(Attribute::AttrKind Kind,
2032
ArrayRef<ConstantRange> Val) {
2033
return addAttribute(Attribute::get(Ctx, Kind, Val));
2034
}
2035
2036
AttrBuilder &AttrBuilder::addInitializesAttr(const ConstantRangeList &CRL) {
2037
return addConstantRangeListAttr(Attribute::Initializes, CRL.rangesRef());
2038
}
2039
2040
AttrBuilder &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(I);
2044
2045
return *this;
2046
}
2047
2048
AttrBuilder &AttrBuilder::remove(const AttributeMask &AM) {
2049
erase_if(Attrs, [&](Attribute A) { return AM.contains(A); });
2050
return *this;
2051
}
2052
2053
bool AttrBuilder::overlaps(const AttributeMask &AM) const {
2054
return any_of(Attrs, [&](Attribute A) { return AM.contains(A); });
2055
}
2056
2057
Attribute AttrBuilder::getAttribute(Attribute::AttrKind A) const {
2058
assert((unsigned)A < Attribute::EndAttrKinds && "Attribute out of range!");
2059
auto It = lower_bound(Attrs, A, AttributeComparator());
2060
if (It != Attrs.end() && It->hasAttribute(A))
2061
return *It;
2062
return {};
2063
}
2064
2065
Attribute AttrBuilder::getAttribute(StringRef A) const {
2066
auto It = lower_bound(Attrs, A, AttributeComparator());
2067
if (It != Attrs.end() && It->hasAttribute(A))
2068
return *It;
2069
return {};
2070
}
2071
2072
bool AttrBuilder::contains(Attribute::AttrKind A) const {
2073
return getAttribute(A).isValid();
2074
}
2075
2076
bool AttrBuilder::contains(StringRef A) const {
2077
return getAttribute(A).isValid();
2078
}
2079
2080
bool 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.
2092
bool AttributeFuncs::isNoFPClassCompatibleType(Type *Ty) {
2093
while (ArrayType *ArrTy = dyn_cast<ArrayType>(Ty))
2094
Ty = ArrTy->getElementType();
2095
return Ty->isFPOrFPVectorTy();
2096
}
2097
2098
/// Which attributes cannot be applied to a type.
2099
AttributeMask 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(Attribute::AllocAlign);
2107
if (ASK & ASK_UNSAFE_TO_DROP)
2108
Incompatible.addAttribute(Attribute::SExt).addAttribute(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(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(Attribute::NoAlias)
2121
.addAttribute(Attribute::NoCapture)
2122
.addAttribute(Attribute::NonNull)
2123
.addAttribute(Attribute::ReadNone)
2124
.addAttribute(Attribute::ReadOnly)
2125
.addAttribute(Attribute::Dereferenceable)
2126
.addAttribute(Attribute::DereferenceableOrNull)
2127
.addAttribute(Attribute::Writable)
2128
.addAttribute(Attribute::DeadOnUnwind)
2129
.addAttribute(Attribute::Initializes);
2130
if (ASK & ASK_UNSAFE_TO_DROP)
2131
Incompatible.addAttribute(Attribute::Nest)
2132
.addAttribute(Attribute::SwiftError)
2133
.addAttribute(Attribute::Preallocated)
2134
.addAttribute(Attribute::InAlloca)
2135
.addAttribute(Attribute::ByVal)
2136
.addAttribute(Attribute::StructRet)
2137
.addAttribute(Attribute::ByRef)
2138
.addAttribute(Attribute::ElementType)
2139
.addAttribute(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(Attribute::Alignment);
2146
}
2147
2148
if (ASK & ASK_SAFE_TO_DROP) {
2149
if (!isNoFPClassCompatibleType(Ty))
2150
Incompatible.addAttribute(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(Attribute::NoUndef);
2157
}
2158
2159
return Incompatible;
2160
}
2161
2162
AttributeMask AttributeFuncs::getUBImplyingAttributes() {
2163
AttributeMask AM;
2164
AM.addAttribute(Attribute::NoUndef);
2165
AM.addAttribute(Attribute::Dereferenceable);
2166
AM.addAttribute(Attribute::DereferenceableOrNull);
2167
return AM;
2168
}
2169
2170
/// Callees with dynamic denormal modes are compatible with any caller mode.
2171
static 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
2188
static 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(CallerModeF32, CalleeModeF32);
2200
}
2201
2202
return false;
2203
}
2204
2205
static 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(Attribute::StrictFP) ||
2209
Caller.getAttributes().hasFnAttr(Attribute::StrictFP);
2210
}
2211
2212
template<typename AttrClass>
2213
static bool isEqual(const Function &Caller, const Function &Callee) {
2214
return Caller.getFnAttribute(AttrClass::getKind()) ==
2215
Callee.getFnAttribute(AttrClass::getKind());
2216
}
2217
2218
static bool isEqual(const Function &Caller, const Function &Callee,
2219
const StringRef &AttrName) {
2220
return Caller.getFnAttribute(AttrName) == Callee.getFnAttribute(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.
2228
template<typename AttrClass>
2229
static 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.
2240
template<typename AttrClass>
2241
static 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.
2249
static 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(Attribute::StackProtect)
2261
.addAttribute(Attribute::StackProtectStrong)
2262
.addAttribute(Attribute::StackProtectReq);
2263
2264
if (Callee.hasFnAttribute(Attribute::StackProtectReq)) {
2265
Caller.removeFnAttrs(OldSSPAttr);
2266
Caller.addFnAttr(Attribute::StackProtectReq);
2267
} else if (Callee.hasFnAttribute(Attribute::StackProtectStrong) &&
2268
!Caller.hasFnAttribute(Attribute::StackProtectReq)) {
2269
Caller.removeFnAttrs(OldSSPAttr);
2270
Caller.addFnAttr(Attribute::StackProtectStrong);
2271
} else if (Callee.hasFnAttribute(Attribute::StackProtect) &&
2272
!Caller.hasFnAttribute(Attribute::StackProtectReq) &&
2273
!Caller.hasFnAttribute(Attribute::StackProtectStrong))
2274
Caller.addFnAttr(Attribute::StackProtect);
2275
}
2276
2277
/// If the inlined function required stack probes, then ensure that
2278
/// the calling function has those too.
2279
static void adjustCallerStackProbes(Function &Caller, const Function &Callee) {
2280
if (!Caller.hasFnAttribute("probe-stack") &&
2281
Callee.hasFnAttribute("probe-stack")) {
2282
Caller.addFnAttr(Callee.getFnAttribute("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.
2289
static void
2290
adjustCallerStackProbeSize(Function &Caller, const Function &Callee) {
2291
Attribute CalleeAttr = Callee.getFnAttribute("stack-probe-size");
2292
if (CalleeAttr.isValid()) {
2293
Attribute CallerAttr = Caller.getFnAttribute("stack-probe-size");
2294
if (CallerAttr.isValid()) {
2295
uint64_t CallerStackProbeSize, CalleeStackProbeSize;
2296
CallerAttr.getValueAsString().getAsInteger(0, CallerStackProbeSize);
2297
CalleeAttr.getValueAsString().getAsInteger(0, CalleeStackProbeSize);
2298
2299
if (CallerStackProbeSize > CalleeStackProbeSize) {
2300
Caller.addFnAttr(CalleeAttr);
2301
}
2302
} else {
2303
Caller.addFnAttr(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.
2317
static void
2318
adjustMinLegalVectorWidth(Function &Caller, const Function &Callee) {
2319
Attribute CallerAttr = Caller.getFnAttribute("min-legal-vector-width");
2320
if (CallerAttr.isValid()) {
2321
Attribute CalleeAttr = Callee.getFnAttribute("min-legal-vector-width");
2322
if (CalleeAttr.isValid()) {
2323
uint64_t CallerVectorWidth, CalleeVectorWidth;
2324
CallerAttr.getValueAsString().getAsInteger(0, CallerVectorWidth);
2325
CalleeAttr.getValueAsString().getAsInteger(0, CalleeVectorWidth);
2326
if (CallerVectorWidth < CalleeVectorWidth)
2327
Caller.addFnAttr(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("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.
2338
static void
2339
adjustNullPointerValidAttr(Function &Caller, const Function &Callee) {
2340
if (Callee.nullPointerIsDefined() && !Caller.nullPointerIsDefined()) {
2341
Caller.addFnAttr(Attribute::NullPointerIsValid);
2342
}
2343
}
2344
2345
struct 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
2360
struct 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 ? "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
2389
bool AttributeFuncs::areInlineCompatible(const Function &Caller,
2390
const Function &Callee) {
2391
return hasCompatibleFnAttrs(Caller, Callee);
2392
}
2393
2394
bool AttributeFuncs::areOutlineCompatible(const Function &A,
2395
const Function &B) {
2396
return hasCompatibleFnAttrs(A, B);
2397
}
2398
2399
void AttributeFuncs::mergeAttributesForInlining(Function &Caller,
2400
const Function &Callee) {
2401
mergeFnAttrs(Caller, Callee);
2402
}
2403
2404
void 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(Base, ToMerge);
2415
}
2416
2417
void AttributeFuncs::updateMinLegalVectorWidthAttr(Function &Fn,
2418
uint64_t Width) {
2419
Attribute Attr = Fn.getFnAttribute("min-legal-vector-width");
2420
if (Attr.isValid()) {
2421
uint64_t OldWidth;
2422
Attr.getValueAsString().getAsInteger(0, OldWidth);
2423
if (Width > OldWidth)
2424
Fn.addFnAttr("min-legal-vector-width", llvm::utostr(Width));
2425
}
2426
}
2427
2428