1 //===- llvm/unittest/IR/AttributesTest.cpp - Attributes unit tests --------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/IR/Attributes.h"
10 #include "llvm-c/Core.h"
11 #include "llvm/ADT/FloatingPointMode.h"
12 #include "llvm/AsmParser/Parser.h"
13 #include "llvm/IR/AttributeMask.h"
14 #include "llvm/IR/ConstantRange.h"
15 #include "llvm/IR/DerivedTypes.h"
16 #include "llvm/IR/InstrTypes.h"
17 #include "llvm/IR/LLVMContext.h"
18 #include "llvm/IR/Module.h"
19 #include "llvm/Support/SourceMgr.h"
20 #include "gtest/gtest.h"
25 TEST(Attributes
, Uniquing
) {
28 Attribute AttrA
= Attribute::get(C
, Attribute::AlwaysInline
);
29 Attribute AttrB
= Attribute::get(C
, Attribute::AlwaysInline
);
30 EXPECT_EQ(AttrA
, AttrB
);
32 AttributeList ASs
[] = {AttributeList::get(C
, 1, Attribute::ZExt
),
33 AttributeList::get(C
, 2, Attribute::SExt
)};
35 AttributeList SetA
= AttributeList::get(C
, ASs
);
36 AttributeList SetB
= AttributeList::get(C
, ASs
);
37 EXPECT_EQ(SetA
, SetB
);
40 TEST(Attributes
, Ordering
) {
43 Attribute Align4
= Attribute::get(C
, Attribute::Alignment
, 4);
44 Attribute Align5
= Attribute::get(C
, Attribute::Alignment
, 5);
45 Attribute Deref4
= Attribute::get(C
, Attribute::Dereferenceable
, 4);
46 Attribute Deref5
= Attribute::get(C
, Attribute::Dereferenceable
, 5);
47 EXPECT_TRUE(Align4
< Align5
);
48 EXPECT_TRUE(Align4
< Deref4
);
49 EXPECT_TRUE(Align4
< Deref5
);
50 EXPECT_TRUE(Align5
< Deref4
);
51 EXPECT_EQ(Deref5
.cmpKind(Deref4
), 0);
52 EXPECT_EQ(Align4
.cmpKind(Align5
), 0);
54 Attribute ByVal
= Attribute::get(C
, Attribute::ByVal
, Type::getInt32Ty(C
));
55 EXPECT_FALSE(ByVal
< Attribute::get(C
, Attribute::ZExt
));
56 EXPECT_TRUE(ByVal
< Align4
);
57 EXPECT_FALSE(ByVal
< ByVal
);
59 AttributeList ASs
[] = {AttributeList::get(C
, 2, Attribute::ZExt
),
60 AttributeList::get(C
, 1, Attribute::SExt
)};
62 AttributeList SetA
= AttributeList::get(C
, ASs
);
64 SetA
.removeParamAttributes(C
, 0, ASs
[1].getParamAttrs(0));
65 EXPECT_NE(SetA
, SetB
);
68 TEST(Attributes
, AddAttributes
) {
72 B
.addAttribute(Attribute::NoReturn
);
73 AL
= AL
.addFnAttributes(C
, AttrBuilder(C
, AttributeSet::get(C
, B
)));
74 EXPECT_TRUE(AL
.hasFnAttr(Attribute::NoReturn
));
76 B
.addAttribute(Attribute::SExt
);
77 AL
= AL
.addRetAttributes(C
, B
);
78 EXPECT_TRUE(AL
.hasRetAttr(Attribute::SExt
));
79 EXPECT_TRUE(AL
.hasFnAttr(Attribute::NoReturn
));
82 TEST(Attributes
, RemoveAlign
) {
85 Attribute AlignAttr
= Attribute::getWithAlignment(C
, Align(8));
86 Attribute StackAlignAttr
= Attribute::getWithStackAlignment(C
, Align(32));
87 AttrBuilder
B_align_readonly(C
);
88 B_align_readonly
.addAttribute(AlignAttr
);
89 B_align_readonly
.addAttribute(Attribute::ReadOnly
);
90 AttributeMask B_align
;
91 B_align
.addAttribute(AlignAttr
);
92 AttrBuilder
B_stackalign_optnone(C
);
93 B_stackalign_optnone
.addAttribute(StackAlignAttr
);
94 B_stackalign_optnone
.addAttribute(Attribute::OptimizeNone
);
95 AttributeMask B_stackalign
;
96 B_stackalign
.addAttribute(StackAlignAttr
);
98 AttributeSet AS
= AttributeSet::get(C
, B_align_readonly
);
99 EXPECT_TRUE(AS
.getAlignment() == MaybeAlign(8));
100 EXPECT_TRUE(AS
.hasAttribute(Attribute::ReadOnly
));
101 AS
= AS
.removeAttribute(C
, Attribute::Alignment
);
102 EXPECT_FALSE(AS
.hasAttribute(Attribute::Alignment
));
103 EXPECT_TRUE(AS
.hasAttribute(Attribute::ReadOnly
));
104 AS
= AttributeSet::get(C
, B_align_readonly
);
105 AS
= AS
.removeAttributes(C
, B_align
);
106 EXPECT_TRUE(AS
.getAlignment() == std::nullopt
);
107 EXPECT_TRUE(AS
.hasAttribute(Attribute::ReadOnly
));
110 AL
= AL
.addParamAttributes(C
, 0, B_align_readonly
);
111 AL
= AL
.addRetAttributes(C
, B_stackalign_optnone
);
112 EXPECT_TRUE(AL
.hasRetAttrs());
113 EXPECT_TRUE(AL
.hasRetAttr(Attribute::StackAlignment
));
114 EXPECT_TRUE(AL
.hasRetAttr(Attribute::OptimizeNone
));
115 EXPECT_TRUE(AL
.getRetStackAlignment() == MaybeAlign(32));
116 EXPECT_TRUE(AL
.hasParamAttrs(0));
117 EXPECT_TRUE(AL
.hasParamAttr(0, Attribute::Alignment
));
118 EXPECT_TRUE(AL
.hasParamAttr(0, Attribute::ReadOnly
));
119 EXPECT_TRUE(AL
.getParamAlignment(0) == MaybeAlign(8));
121 AL
= AL
.removeParamAttribute(C
, 0, Attribute::Alignment
);
122 EXPECT_FALSE(AL
.hasParamAttr(0, Attribute::Alignment
));
123 EXPECT_TRUE(AL
.hasParamAttr(0, Attribute::ReadOnly
));
124 EXPECT_TRUE(AL
.hasRetAttr(Attribute::StackAlignment
));
125 EXPECT_TRUE(AL
.hasRetAttr(Attribute::OptimizeNone
));
126 EXPECT_TRUE(AL
.getRetStackAlignment() == MaybeAlign(32));
128 AL
= AL
.removeRetAttribute(C
, Attribute::StackAlignment
);
129 EXPECT_FALSE(AL
.hasParamAttr(0, Attribute::Alignment
));
130 EXPECT_TRUE(AL
.hasParamAttr(0, Attribute::ReadOnly
));
131 EXPECT_FALSE(AL
.hasRetAttr(Attribute::StackAlignment
));
132 EXPECT_TRUE(AL
.hasRetAttr(Attribute::OptimizeNone
));
135 AL2
= AL2
.addParamAttributes(C
, 0, B_align_readonly
);
136 AL2
= AL2
.addRetAttributes(C
, B_stackalign_optnone
);
138 AL2
= AL2
.removeParamAttributes(C
, 0, B_align
);
139 EXPECT_FALSE(AL2
.hasParamAttr(0, Attribute::Alignment
));
140 EXPECT_TRUE(AL2
.hasParamAttr(0, Attribute::ReadOnly
));
141 EXPECT_TRUE(AL2
.hasRetAttr(Attribute::StackAlignment
));
142 EXPECT_TRUE(AL2
.hasRetAttr(Attribute::OptimizeNone
));
143 EXPECT_TRUE(AL2
.getRetStackAlignment() == MaybeAlign(32));
145 AL2
= AL2
.removeRetAttributes(C
, B_stackalign
);
146 EXPECT_FALSE(AL2
.hasParamAttr(0, Attribute::Alignment
));
147 EXPECT_TRUE(AL2
.hasParamAttr(0, Attribute::ReadOnly
));
148 EXPECT_FALSE(AL2
.hasRetAttr(Attribute::StackAlignment
));
149 EXPECT_TRUE(AL2
.hasRetAttr(Attribute::OptimizeNone
));
152 TEST(Attributes
, AddMatchingAlignAttr
) {
155 AL
= AL
.addParamAttribute(C
, 0, Attribute::getWithAlignment(C
, Align(8)));
156 AL
= AL
.addParamAttribute(C
, 1, Attribute::getWithAlignment(C
, Align(32)));
157 EXPECT_EQ(Align(8), AL
.getParamAlignment(0));
158 EXPECT_EQ(Align(32), AL
.getParamAlignment(1));
161 B
.addAttribute(Attribute::NonNull
);
162 B
.addAlignmentAttr(8);
163 AL
= AL
.addParamAttributes(C
, 0, B
);
164 EXPECT_EQ(Align(8), AL
.getParamAlignment(0));
165 EXPECT_EQ(Align(32), AL
.getParamAlignment(1));
166 EXPECT_TRUE(AL
.hasParamAttr(0, Attribute::NonNull
));
169 TEST(Attributes
, EmptyGet
) {
171 AttributeList EmptyLists
[] = {AttributeList(), AttributeList()};
172 AttributeList AL
= AttributeList::get(C
, EmptyLists
);
173 EXPECT_TRUE(AL
.isEmpty());
176 TEST(Attributes
, OverflowGet
) {
178 std::pair
<unsigned, Attribute
> Attrs
[] = {
179 {AttributeList::ReturnIndex
, Attribute::get(C
, Attribute::SExt
)},
180 {AttributeList::FunctionIndex
, Attribute::get(C
, Attribute::ReadOnly
)}};
181 AttributeList AL
= AttributeList::get(C
, Attrs
);
182 EXPECT_EQ(2U, AL
.getNumAttrSets());
185 TEST(Attributes
, StringRepresentation
) {
187 StructType
*Ty
= StructType::create(Type::getInt32Ty(C
), "mystruct");
189 // Insufficiently careful printing can result in byval(%mystruct = { i32 })
190 Attribute A
= Attribute::getWithByValType(C
, Ty
);
191 EXPECT_EQ(A
.getAsString(), "byval(%mystruct)");
193 A
= Attribute::getWithByValType(C
, Type::getInt32Ty(C
));
194 EXPECT_EQ(A
.getAsString(), "byval(i32)");
197 TEST(Attributes
, HasParentContext
) {
201 Attribute Attr1
= Attribute::get(C1
, Attribute::AlwaysInline
);
202 Attribute Attr2
= Attribute::get(C2
, Attribute::AlwaysInline
);
203 EXPECT_TRUE(Attr1
.hasParentContext(C1
));
204 EXPECT_FALSE(Attr1
.hasParentContext(C2
));
205 EXPECT_FALSE(Attr2
.hasParentContext(C1
));
206 EXPECT_TRUE(Attr2
.hasParentContext(C2
));
210 AttributeSet AS1
= AttributeSet::get(
211 C1
, ArrayRef(Attribute::get(C1
, Attribute::NoReturn
)));
212 AttributeSet AS2
= AttributeSet::get(
213 C2
, ArrayRef(Attribute::get(C2
, Attribute::NoReturn
)));
214 EXPECT_TRUE(AS1
.hasParentContext(C1
));
215 EXPECT_FALSE(AS1
.hasParentContext(C2
));
216 EXPECT_FALSE(AS2
.hasParentContext(C1
));
217 EXPECT_TRUE(AS2
.hasParentContext(C2
));
221 AttributeList AL1
= AttributeList::get(C1
, 1, Attribute::ZExt
);
222 AttributeList AL2
= AttributeList::get(C2
, 1, Attribute::ZExt
);
223 EXPECT_TRUE(AL1
.hasParentContext(C1
));
224 EXPECT_FALSE(AL1
.hasParentContext(C2
));
225 EXPECT_FALSE(AL2
.hasParentContext(C1
));
226 EXPECT_TRUE(AL2
.hasParentContext(C2
));
230 TEST(Attributes
, AttributeListPrinting
) {
235 raw_string_ostream
OS(S
);
237 AL
.addFnAttribute(C
, Attribute::AlwaysInline
).print(OS
);
238 EXPECT_EQ(S
, "AttributeList[\n"
239 " { function => alwaysinline }\n"
245 raw_string_ostream
OS(S
);
247 AL
.addRetAttribute(C
, Attribute::SExt
).print(OS
);
248 EXPECT_EQ(S
, "AttributeList[\n"
249 " { return => signext }\n"
255 raw_string_ostream
OS(S
);
257 AL
.addParamAttribute(C
, 5, Attribute::ZExt
).print(OS
);
258 EXPECT_EQ(S
, "AttributeList[\n"
259 " { arg(5) => zeroext }\n"
264 TEST(Attributes
, MismatchedABIAttrs
) {
265 const char *IRString
= R
"IR(
266 declare void @f1(i32* byval(i32))
268 call void @f1(i32* null)
271 declare void @f2(i32* preallocated(i32))
273 call void @f2(i32* null)
276 declare void @f3(i32* inalloca(i32))
278 call void @f3(i32* null)
285 std::unique_ptr
<Module
> M
= parseAssemblyString(IRString
, Err
, Context
);
289 auto *I
= cast
<CallBase
>(&M
->getFunction("g")->getEntryBlock().front());
290 ASSERT_TRUE(I
->isByValArgument(0));
291 ASSERT_TRUE(I
->getParamByValType(0));
294 auto *I
= cast
<CallBase
>(&M
->getFunction("h")->getEntryBlock().front());
295 ASSERT_TRUE(I
->getParamPreallocatedType(0));
298 auto *I
= cast
<CallBase
>(&M
->getFunction("i")->getEntryBlock().front());
299 ASSERT_TRUE(I
->isInAllocaArgument(0));
300 ASSERT_TRUE(I
->getParamInAllocaType(0));
304 TEST(Attributes
, RemoveParamAttributes
) {
307 AL
= AL
.addParamAttribute(C
, 1, Attribute::NoUndef
);
308 EXPECT_EQ(AL
.getNumAttrSets(), 4U);
309 AL
= AL
.addParamAttribute(C
, 3, Attribute::NonNull
);
310 EXPECT_EQ(AL
.getNumAttrSets(), 6U);
311 AL
= AL
.removeParamAttributes(C
, 3);
312 EXPECT_EQ(AL
.getNumAttrSets(), 4U);
313 AL
= AL
.removeParamAttribute(C
, 1, Attribute::NoUndef
);
314 EXPECT_EQ(AL
.getNumAttrSets(), 0U);
317 TEST(Attributes
, ConstantRangeAttributeCAPI
) {
320 const unsigned NumBits
= 8;
321 const uint64_t LowerWords
[] = {0};
322 const uint64_t UpperWords
[] = {42};
324 ConstantRange
Range(APInt(NumBits
, ArrayRef(LowerWords
)),
325 APInt(NumBits
, ArrayRef(UpperWords
)));
327 Attribute RangeAttr
= Attribute::get(C
, Attribute::Range
, Range
);
328 auto OutAttr
= unwrap(LLVMCreateConstantRangeAttribute(
329 wrap(&C
), Attribute::Range
, NumBits
, LowerWords
, UpperWords
));
330 EXPECT_EQ(OutAttr
, RangeAttr
);
333 const unsigned NumBits
= 128;
334 const uint64_t LowerWords
[] = {1, 1};
335 const uint64_t UpperWords
[] = {42, 42};
337 ConstantRange
Range(APInt(NumBits
, ArrayRef(LowerWords
)),
338 APInt(NumBits
, ArrayRef(UpperWords
)));
340 Attribute RangeAttr
= Attribute::get(C
, Attribute::Range
, Range
);
341 auto OutAttr
= unwrap(LLVMCreateConstantRangeAttribute(
342 wrap(&C
), Attribute::Range
, NumBits
, LowerWords
, UpperWords
));
343 EXPECT_EQ(OutAttr
, RangeAttr
);
347 TEST(Attributes
, CalleeAttributes
) {
348 const char *IRString
= R
"IR(
349 declare void @f1(i32 %i)
350 declare void @f2(i32 range(i32 1, 2) %i)
352 define void @g1(i32 %i) {
353 call void @f1(i32 %i)
356 define void @g2(i32 %i) {
357 call void @f2(i32 %i)
360 define void @g3(i32 %i) {
361 call void @f1(i32 range(i32 3, 4) %i)
364 define void @g4(i32 %i) {
365 call void @f2(i32 range(i32 3, 4) %i)
372 std::unique_ptr
<Module
> M
= parseAssemblyString(IRString
, Err
, Context
);
376 auto *I
= cast
<CallBase
>(&M
->getFunction("g1")->getEntryBlock().front());
377 ASSERT_FALSE(I
->getParamAttr(0, Attribute::Range
).isValid());
380 auto *I
= cast
<CallBase
>(&M
->getFunction("g2")->getEntryBlock().front());
381 ASSERT_TRUE(I
->getParamAttr(0, Attribute::Range
).isValid());
384 auto *I
= cast
<CallBase
>(&M
->getFunction("g3")->getEntryBlock().front());
385 ASSERT_TRUE(I
->getParamAttr(0, Attribute::Range
).isValid());
388 auto *I
= cast
<CallBase
>(&M
->getFunction("g4")->getEntryBlock().front());
389 ASSERT_TRUE(I
->getParamAttr(0, Attribute::Range
).isValid());
393 TEST(Attributes
, SetIntersect
) {
395 std::optional
<AttributeSet
> Res
;
396 auto BuildAttr
= [&](LLVMContext
&C
, Attribute::AttrKind Kind
, uint64_t Int
,
397 Type
*Ty
, ConstantRange
&CR
,
398 ArrayRef
<ConstantRange
> CRList
) {
399 if (Attribute::isEnumAttrKind(Kind
))
400 return Attribute::get(C
, Kind
);
401 if (Attribute::isTypeAttrKind(Kind
))
402 return Attribute::get(C
, Kind
, Ty
);
403 if (Attribute::isIntAttrKind(Kind
))
404 return Attribute::get(C
, Kind
, Int
);
405 if (Attribute::isConstantRangeAttrKind(Kind
))
406 return Attribute::get(C
, Kind
, CR
);
407 if (Attribute::isConstantRangeListAttrKind(Kind
))
408 return Attribute::get(C
, Kind
, CRList
);
411 for (unsigned i
= Attribute::AttrKind::None
+ 1,
412 e
= Attribute::AttrKind::EndAttrKinds
;
414 Attribute::AttrKind Kind
= static_cast<Attribute::AttrKind
>(i
);
416 Attribute::AttrKind Other
=
417 Kind
== Attribute::NoUndef
? Attribute::NonNull
: Attribute::NoUndef
;
418 AttributeSet AS0
, AS1
;
424 if (Attribute::intersectWithCustom(Kind
)) {
426 case Attribute::Alignment
:
430 case Attribute::Memory
:
431 V0
= MemoryEffects::readOnly().toIntValue();
432 V1
= MemoryEffects::none().toIntValue();
434 case Attribute::NoFPClass
:
435 V0
= FPClassTest::fcNan
| FPClassTest::fcInf
;
436 V1
= FPClassTest::fcNan
;
438 case Attribute::Range
:
445 V1
= (2 - (i
& 2)) + 1;
448 ConstantRange
CR0(APInt(32, 0), APInt(32, 10));
449 ConstantRange
CR1(APInt(32, 15), APInt(32, 20));
450 ConstantRange CRL0
[] = {CR0
};
451 ConstantRange CRL1
[] = {CR0
, CR1
};
452 Type
*T0
= Type::getInt32Ty(C0
);
453 Type
*T1
= Type::getInt64Ty(C0
);
454 Attribute Attr0
= BuildAttr(C0
, Kind
, V0
, T0
, CR0
, CRL0
);
455 Attribute Attr1
= BuildAttr(
456 C1
, Attribute::isEnumAttrKind(Kind
) ? Other
: Kind
, V1
, T1
, CR1
, CRL1
);
457 bool CanDrop
= Attribute::intersectWithAnd(Kind
) ||
458 Attribute::intersectWithMin(Kind
) ||
459 Attribute::intersectWithCustom(Kind
);
461 AB0
.addAttribute(Attr0
);
462 AB1
.addAttribute(Attr1
);
464 Res
= AS0
.intersectWith(C0
, AS1
);
465 ASSERT_TRUE(Res
.has_value());
466 ASSERT_EQ(AS0
, *Res
);
468 AS0
= AttributeSet::get(C0
, AB0
);
469 Res
= AS0
.intersectWith(C0
, AS1
);
470 ASSERT_EQ(Res
.has_value(), CanDrop
);
472 ASSERT_FALSE(Res
->hasAttributes());
474 AS1
= AttributeSet::get(C1
, AB0
);
475 Res
= AS0
.intersectWith(C0
, AS1
);
476 ASSERT_TRUE(Res
.has_value());
477 ASSERT_EQ(AS0
, *Res
);
479 AS1
= AttributeSet::get(C1
, AB1
);
480 Res
= AS0
.intersectWith(C0
, AS1
);
482 ASSERT_FALSE(Res
.has_value());
485 if (Attribute::intersectWithAnd(Kind
)) {
486 ASSERT_TRUE(Res
.has_value());
487 ASSERT_FALSE(Res
->hasAttributes());
489 AS1
= AS1
.addAttribute(C1
, Kind
);
490 Res
= AS0
.intersectWith(C0
, AS1
);
491 ASSERT_TRUE(Res
.has_value());
492 ASSERT_TRUE(Res
->hasAttributes());
493 ASSERT_TRUE(Res
->hasAttribute(Kind
));
494 ASSERT_FALSE(Res
->hasAttribute(Other
));
495 } else if (Attribute::intersectWithMin(Kind
)) {
496 ASSERT_TRUE(Res
.has_value());
497 ASSERT_TRUE(Res
->hasAttributes());
498 ASSERT_TRUE(Res
->hasAttribute(Kind
));
499 ASSERT_EQ(Res
->getAttribute(Kind
).getValueAsInt(), std::min(V0
, V1
));
500 } else if (Attribute::intersectWithCustom(Kind
)) {
501 ASSERT_TRUE(Res
.has_value());
502 ASSERT_TRUE(Res
->hasAttributes());
503 ASSERT_TRUE(Res
->hasAttribute(Kind
));
506 case Attribute::Alignment
:
507 ASSERT_EQ(Res
->getAlignment().valueOrOne(), MaybeAlign(2).valueOrOne());
509 case Attribute::Memory
:
510 ASSERT_EQ(Res
->getMemoryEffects(), MemoryEffects::readOnly());
512 case Attribute::NoFPClass
:
513 ASSERT_EQ(Res
->getNoFPClass(), FPClassTest::fcNan
);
515 case Attribute::Range
:
516 ASSERT_EQ(Res
->getAttribute(Kind
).getRange(),
517 ConstantRange(APInt(32, 0), APInt(32, 20)));
523 AS0
= AS0
.addAttribute(C0
, Attribute::AlwaysInline
);
524 ASSERT_FALSE(AS0
.intersectWith(C0
, AS1
).has_value());
528 TEST(Attributes
, SetIntersectByValAlign
) {
530 AttributeSet AS0
, AS1
;
532 Attribute ByVal
= Attribute::get(C
, Attribute::ByVal
, Type::getInt32Ty(C
));
533 Attribute Align0
= Attribute::get(C
, Attribute::Alignment
, 4);
534 Attribute Align1
= Attribute::get(C
, Attribute::Alignment
, 8);
537 AttrBuilder
AB0(C
), AB1(C
);
538 AB0
.addAttribute(Align0
);
539 AB1
.addAttribute(Align1
);
540 AB0
.addAttribute(Attribute::NoUndef
);
541 AS0
= AttributeSet::get(C
, AB0
);
542 AS1
= AttributeSet::get(C
, AB1
);
543 auto Res
= AS0
.intersectWith(C
, AS1
);
544 ASSERT_TRUE(Res
.has_value());
545 ASSERT_TRUE(Res
->hasAttribute(Attribute::Alignment
));
548 AttrBuilder
AB0(C
), AB1(C
);
549 AB0
.addAttribute(Align0
);
550 AB0
.addAttribute(ByVal
);
551 AB1
.addAttribute(Align1
);
552 AB1
.addAttribute(ByVal
);
553 AB0
.addAttribute(Attribute::NoUndef
);
554 AS0
= AttributeSet::get(C
, AB0
);
555 AS1
= AttributeSet::get(C
, AB1
);
556 auto Res
= AS0
.intersectWith(C
, AS1
);
557 ASSERT_FALSE(Res
.has_value());
560 AttrBuilder
AB0(C
), AB1(C
);
561 AB0
.addAttribute(Align0
);
562 AB0
.addAttribute(ByVal
);
563 AB1
.addAttribute(ByVal
);
564 AB0
.addAttribute(Attribute::NoUndef
);
565 AS0
= AttributeSet::get(C
, AB0
);
566 AS1
= AttributeSet::get(C
, AB1
);
567 ASSERT_FALSE(AS0
.intersectWith(C
, AS1
).has_value());
568 ASSERT_FALSE(AS1
.intersectWith(C
, AS0
).has_value());
571 AttrBuilder
AB0(C
), AB1(C
);
572 AB0
.addAttribute(ByVal
);
573 AB1
.addAttribute(ByVal
);
574 AB0
.addAttribute(Attribute::NoUndef
);
575 AS0
= AttributeSet::get(C
, AB0
);
576 AS1
= AttributeSet::get(C
, AB1
);
578 auto Res
= AS0
.intersectWith(C
, AS1
);
579 ASSERT_TRUE(Res
.has_value());
580 ASSERT_TRUE(Res
->hasAttribute(Attribute::ByVal
));
583 AttrBuilder
AB0(C
), AB1(C
);
584 AB0
.addAttribute(ByVal
);
585 AB0
.addAttribute(Align0
);
586 AB1
.addAttribute(ByVal
);
587 AB1
.addAttribute(Align0
);
588 AB0
.addAttribute(Attribute::NoUndef
);
589 AS0
= AttributeSet::get(C
, AB0
);
590 AS1
= AttributeSet::get(C
, AB1
);
592 auto Res
= AS0
.intersectWith(C
, AS1
);
593 ASSERT_TRUE(Res
.has_value());
594 ASSERT_TRUE(Res
->hasAttribute(Attribute::ByVal
));
595 ASSERT_TRUE(Res
->hasAttribute(Attribute::Alignment
));
599 TEST(Attributes
, ListIntersectDifferingMustPreserve
) {
601 std::optional
<AttributeList
> Res
;
605 AL1
= AL1
.addFnAttribute(C
, Attribute::ReadOnly
);
606 AL0
= AL0
.addParamAttribute(C
, 0, Attribute::SExt
);
607 Res
= AL0
.intersectWith(C
, AL1
);
608 ASSERT_FALSE(Res
.has_value());
609 Res
= AL1
.intersectWith(C
, AL0
);
610 ASSERT_FALSE(Res
.has_value());
615 AL1
= AL1
.addFnAttribute(C
, Attribute::AlwaysInline
);
616 AL0
= AL0
.addParamAttribute(C
, 0, Attribute::ReadOnly
);
617 Res
= AL0
.intersectWith(C
, AL1
);
618 ASSERT_FALSE(Res
.has_value());
619 Res
= AL1
.intersectWith(C
, AL0
);
620 ASSERT_FALSE(Res
.has_value());
622 AL0
= AL0
.addFnAttribute(C
, Attribute::AlwaysInline
);
623 AL1
= AL1
.addParamAttribute(C
, 1, Attribute::SExt
);
624 Res
= AL0
.intersectWith(C
, AL1
);
625 ASSERT_FALSE(Res
.has_value());
626 Res
= AL1
.intersectWith(C
, AL0
);
627 ASSERT_FALSE(Res
.has_value());
631 TEST(Attributes
, ListIntersect
) {
635 std::optional
<AttributeList
> Res
;
636 AL0
= AL0
.addRetAttribute(C
, Attribute::NoUndef
);
637 AL1
= AL1
.addRetAttribute(C
, Attribute::NoUndef
);
639 Res
= AL0
.intersectWith(C
, AL1
);
640 ASSERT_TRUE(Res
.has_value());
641 ASSERT_EQ(AL0
, *Res
);
643 AL0
= AL0
.addParamAttribute(C
, 1, Attribute::NoUndef
);
644 Res
= AL0
.intersectWith(C
, AL1
);
645 ASSERT_TRUE(Res
.has_value());
646 ASSERT_TRUE(Res
->hasRetAttr(Attribute::NoUndef
));
647 ASSERT_FALSE(Res
->hasParamAttr(1, Attribute::NoUndef
));
649 AL1
= AL1
.addParamAttribute(C
, 2, Attribute::NoUndef
);
650 Res
= AL0
.intersectWith(C
, AL1
);
651 ASSERT_TRUE(Res
.has_value());
652 ASSERT_TRUE(Res
->hasRetAttr(Attribute::NoUndef
));
653 ASSERT_FALSE(Res
->hasParamAttr(1, Attribute::NoUndef
));
654 ASSERT_FALSE(Res
->hasParamAttr(2, Attribute::NoUndef
));
656 AL0
= AL0
.addParamAttribute(C
, 2, Attribute::NoUndef
);
657 AL1
= AL1
.addParamAttribute(C
, 1, Attribute::NoUndef
);
658 Res
= AL0
.intersectWith(C
, AL1
);
659 ASSERT_TRUE(Res
.has_value());
660 ASSERT_EQ(AL0
, *Res
);
662 AL0
= AL0
.addParamAttribute(C
, 2, Attribute::NonNull
);
663 Res
= AL0
.intersectWith(C
, AL1
);
664 ASSERT_TRUE(Res
.has_value());
665 ASSERT_NE(AL0
, *Res
);
666 ASSERT_TRUE(Res
->hasRetAttr(Attribute::NoUndef
));
667 ASSERT_TRUE(Res
->hasParamAttr(1, Attribute::NoUndef
));
668 ASSERT_TRUE(Res
->hasParamAttr(2, Attribute::NoUndef
));
669 ASSERT_FALSE(Res
->hasParamAttr(2, Attribute::NonNull
));
671 AL0
= AL0
.addRetAttribute(C
, Attribute::NonNull
);
672 Res
= AL0
.intersectWith(C
, AL1
);
673 ASSERT_TRUE(Res
.has_value());
674 ASSERT_NE(AL0
, *Res
);
675 ASSERT_TRUE(Res
->hasRetAttr(Attribute::NoUndef
));
676 ASSERT_FALSE(Res
->hasRetAttr(Attribute::NonNull
));
677 ASSERT_TRUE(Res
->hasParamAttr(1, Attribute::NoUndef
));
678 ASSERT_TRUE(Res
->hasParamAttr(2, Attribute::NoUndef
));
679 ASSERT_FALSE(Res
->hasParamAttr(2, Attribute::NonNull
));
681 AL0
= AL0
.addFnAttribute(C
, Attribute::ReadOnly
);
682 Res
= AL0
.intersectWith(C
, AL1
);
683 ASSERT_TRUE(Res
.has_value());
684 ASSERT_NE(AL0
, *Res
);
685 ASSERT_FALSE(Res
->hasFnAttr(Attribute::ReadOnly
));
686 ASSERT_TRUE(Res
->hasRetAttr(Attribute::NoUndef
));
687 ASSERT_FALSE(Res
->hasRetAttr(Attribute::NonNull
));
688 ASSERT_TRUE(Res
->hasParamAttr(1, Attribute::NoUndef
));
689 ASSERT_TRUE(Res
->hasParamAttr(2, Attribute::NoUndef
));
690 ASSERT_FALSE(Res
->hasParamAttr(2, Attribute::NonNull
));
692 AL1
= AL1
.addFnAttribute(C
, Attribute::ReadOnly
);
693 Res
= AL0
.intersectWith(C
, AL1
);
694 ASSERT_TRUE(Res
.has_value());
695 ASSERT_NE(AL0
, *Res
);
696 ASSERT_TRUE(Res
->hasFnAttr(Attribute::ReadOnly
));
697 ASSERT_TRUE(Res
->hasRetAttr(Attribute::NoUndef
));
698 ASSERT_FALSE(Res
->hasRetAttr(Attribute::NonNull
));
699 ASSERT_TRUE(Res
->hasParamAttr(1, Attribute::NoUndef
));
700 ASSERT_TRUE(Res
->hasParamAttr(2, Attribute::NoUndef
));
701 ASSERT_FALSE(Res
->hasParamAttr(2, Attribute::NonNull
));
703 AL1
= AL1
.addFnAttribute(C
, Attribute::AlwaysInline
);
704 Res
= AL0
.intersectWith(C
, AL1
);
705 ASSERT_FALSE(Res
.has_value());
707 AL0
= AL0
.addFnAttribute(C
, Attribute::AlwaysInline
);
708 Res
= AL0
.intersectWith(C
, AL1
);
709 ASSERT_TRUE(Res
.has_value());
710 ASSERT_TRUE(Res
->hasFnAttr(Attribute::AlwaysInline
));
711 ASSERT_TRUE(Res
->hasFnAttr(Attribute::ReadOnly
));
712 ASSERT_TRUE(Res
->hasRetAttr(Attribute::NoUndef
));
713 ASSERT_FALSE(Res
->hasRetAttr(Attribute::NonNull
));
714 ASSERT_TRUE(Res
->hasParamAttr(1, Attribute::NoUndef
));
715 ASSERT_TRUE(Res
->hasParamAttr(2, Attribute::NoUndef
));
716 ASSERT_FALSE(Res
->hasParamAttr(2, Attribute::NonNull
));
718 AL1
= AL1
.addParamAttribute(C
, 2, Attribute::ReadNone
);
719 Res
= AL0
.intersectWith(C
, AL1
);
720 ASSERT_TRUE(Res
.has_value());
721 ASSERT_TRUE(Res
->hasFnAttr(Attribute::AlwaysInline
));
722 ASSERT_TRUE(Res
->hasFnAttr(Attribute::ReadOnly
));
723 ASSERT_TRUE(Res
->hasRetAttr(Attribute::NoUndef
));
724 ASSERT_FALSE(Res
->hasRetAttr(Attribute::NonNull
));
725 ASSERT_TRUE(Res
->hasParamAttr(1, Attribute::NoUndef
));
726 ASSERT_TRUE(Res
->hasParamAttr(2, Attribute::NoUndef
));
727 ASSERT_FALSE(Res
->hasParamAttr(2, Attribute::NonNull
));
728 ASSERT_FALSE(Res
->hasParamAttr(2, Attribute::ReadNone
));
730 AL1
= AL1
.addParamAttribute(C
, 3, Attribute::ReadNone
);
731 Res
= AL0
.intersectWith(C
, AL1
);
732 ASSERT_TRUE(Res
.has_value());
733 ASSERT_TRUE(Res
.has_value());
734 ASSERT_TRUE(Res
->hasFnAttr(Attribute::AlwaysInline
));
735 ASSERT_TRUE(Res
->hasFnAttr(Attribute::ReadOnly
));
736 ASSERT_TRUE(Res
->hasRetAttr(Attribute::NoUndef
));
737 ASSERT_FALSE(Res
->hasRetAttr(Attribute::NonNull
));
738 ASSERT_TRUE(Res
->hasParamAttr(1, Attribute::NoUndef
));
739 ASSERT_TRUE(Res
->hasParamAttr(2, Attribute::NoUndef
));
740 ASSERT_FALSE(Res
->hasParamAttr(2, Attribute::NonNull
));
741 ASSERT_FALSE(Res
->hasParamAttr(2, Attribute::ReadNone
));
742 ASSERT_FALSE(Res
->hasParamAttr(3, Attribute::ReadNone
));
744 AL0
= AL0
.addParamAttribute(C
, 3, Attribute::ReadNone
);
745 Res
= AL0
.intersectWith(C
, AL1
);
746 ASSERT_TRUE(Res
.has_value());
747 ASSERT_TRUE(Res
->hasFnAttr(Attribute::AlwaysInline
));
748 ASSERT_TRUE(Res
->hasFnAttr(Attribute::ReadOnly
));
749 ASSERT_TRUE(Res
->hasRetAttr(Attribute::NoUndef
));
750 ASSERT_FALSE(Res
->hasRetAttr(Attribute::NonNull
));
751 ASSERT_TRUE(Res
->hasParamAttr(1, Attribute::NoUndef
));
752 ASSERT_TRUE(Res
->hasParamAttr(2, Attribute::NoUndef
));
753 ASSERT_FALSE(Res
->hasParamAttr(2, Attribute::NonNull
));
754 ASSERT_FALSE(Res
->hasParamAttr(2, Attribute::ReadNone
));
755 ASSERT_TRUE(Res
->hasParamAttr(3, Attribute::ReadNone
));
757 AL0
= AL0
.addParamAttribute(
758 C
, {3}, Attribute::get(C
, Attribute::ByVal
, Type::getInt32Ty(C
)));
759 Res
= AL0
.intersectWith(C
, AL1
);
760 ASSERT_FALSE(Res
.has_value());
762 AL1
= AL1
.addParamAttribute(
763 C
, {3}, Attribute::get(C
, Attribute::ByVal
, Type::getInt32Ty(C
)));
764 Res
= AL0
.intersectWith(C
, AL1
);
765 ASSERT_TRUE(Res
.has_value());
766 ASSERT_TRUE(Res
->hasFnAttr(Attribute::AlwaysInline
));
767 ASSERT_TRUE(Res
->hasFnAttr(Attribute::ReadOnly
));
768 ASSERT_TRUE(Res
->hasRetAttr(Attribute::NoUndef
));
769 ASSERT_FALSE(Res
->hasRetAttr(Attribute::NonNull
));
770 ASSERT_TRUE(Res
->hasParamAttr(1, Attribute::NoUndef
));
771 ASSERT_TRUE(Res
->hasParamAttr(2, Attribute::NoUndef
));
772 ASSERT_FALSE(Res
->hasParamAttr(2, Attribute::NonNull
));
773 ASSERT_FALSE(Res
->hasParamAttr(2, Attribute::ReadNone
));
774 ASSERT_TRUE(Res
->hasParamAttr(3, Attribute::ReadNone
));
775 ASSERT_TRUE(Res
->hasParamAttr(3, Attribute::ByVal
));
778 } // end anonymous namespace