Fix test failures introduced by PR #113697 (#116941)
[llvm-project.git] / llvm / unittests / IR / AttributesTest.cpp
blobf73f2b20e9fea54db0157f75fd926894ea23423c
1 //===- llvm/unittest/IR/AttributesTest.cpp - Attributes unit tests --------===//
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 //===----------------------------------------------------------------------===//
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"
21 using namespace llvm;
23 namespace {
25 TEST(Attributes, Uniquing) {
26 LLVMContext C;
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) {
41 LLVMContext C;
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);
63 AttributeList SetB =
64 SetA.removeParamAttributes(C, 0, ASs[1].getParamAttrs(0));
65 EXPECT_NE(SetA, SetB);
68 TEST(Attributes, AddAttributes) {
69 LLVMContext C;
70 AttributeList AL;
71 AttrBuilder B(C);
72 B.addAttribute(Attribute::NoReturn);
73 AL = AL.addFnAttributes(C, AttrBuilder(C, AttributeSet::get(C, B)));
74 EXPECT_TRUE(AL.hasFnAttr(Attribute::NoReturn));
75 B.clear();
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) {
83 LLVMContext C;
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));
109 AttributeList AL;
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));
134 AttributeList AL2;
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) {
153 LLVMContext C;
154 AttributeList AL;
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));
160 AttrBuilder B(C);
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) {
170 LLVMContext C;
171 AttributeList EmptyLists[] = {AttributeList(), AttributeList()};
172 AttributeList AL = AttributeList::get(C, EmptyLists);
173 EXPECT_TRUE(AL.isEmpty());
176 TEST(Attributes, OverflowGet) {
177 LLVMContext C;
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) {
186 LLVMContext C;
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) {
198 LLVMContext C1, C2;
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) {
231 LLVMContext C;
234 std::string S;
235 raw_string_ostream OS(S);
236 AttributeList AL;
237 AL.addFnAttribute(C, Attribute::AlwaysInline).print(OS);
238 EXPECT_EQ(S, "AttributeList[\n"
239 " { function => alwaysinline }\n"
240 "]\n");
244 std::string S;
245 raw_string_ostream OS(S);
246 AttributeList AL;
247 AL.addRetAttribute(C, Attribute::SExt).print(OS);
248 EXPECT_EQ(S, "AttributeList[\n"
249 " { return => signext }\n"
250 "]\n");
254 std::string S;
255 raw_string_ostream OS(S);
256 AttributeList AL;
257 AL.addParamAttribute(C, 5, Attribute::ZExt).print(OS);
258 EXPECT_EQ(S, "AttributeList[\n"
259 " { arg(5) => zeroext }\n"
260 "]\n");
264 TEST(Attributes, MismatchedABIAttrs) {
265 const char *IRString = R"IR(
266 declare void @f1(i32* byval(i32))
267 define void @g() {
268 call void @f1(i32* null)
269 ret void
271 declare void @f2(i32* preallocated(i32))
272 define void @h() {
273 call void @f2(i32* null)
274 ret void
276 declare void @f3(i32* inalloca(i32))
277 define void @i() {
278 call void @f3(i32* null)
279 ret void
281 )IR";
283 SMDiagnostic Err;
284 LLVMContext Context;
285 std::unique_ptr<Module> M = parseAssemblyString(IRString, Err, Context);
286 ASSERT_TRUE(M);
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) {
305 LLVMContext C;
306 AttributeList AL;
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) {
318 LLVMContext C;
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)
354 ret void
356 define void @g2(i32 %i) {
357 call void @f2(i32 %i)
358 ret void
360 define void @g3(i32 %i) {
361 call void @f1(i32 range(i32 3, 4) %i)
362 ret void
364 define void @g4(i32 %i) {
365 call void @f2(i32 range(i32 3, 4) %i)
366 ret void
368 )IR";
370 SMDiagnostic Err;
371 LLVMContext Context;
372 std::unique_ptr<Module> M = parseAssemblyString(IRString, Err, Context);
373 ASSERT_TRUE(M);
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) {
394 LLVMContext C0, C1;
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);
409 std::abort();
411 for (unsigned i = Attribute::AttrKind::None + 1,
412 e = Attribute::AttrKind::EndAttrKinds;
413 i < e; ++i) {
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;
419 AttrBuilder AB0(C0);
420 AttrBuilder AB1(C1);
421 uint64_t V0, V1;
422 V0 = 0;
423 V1 = 0;
424 if (Attribute::intersectWithCustom(Kind)) {
425 switch (Kind) {
426 case Attribute::Alignment:
427 V0 = 2;
428 V1 = 4;
429 break;
430 case Attribute::Memory:
431 V0 = MemoryEffects::readOnly().toIntValue();
432 V1 = MemoryEffects::none().toIntValue();
433 break;
434 case Attribute::NoFPClass:
435 V0 = FPClassTest::fcNan | FPClassTest::fcInf;
436 V1 = FPClassTest::fcNan;
437 break;
438 case Attribute::Range:
439 break;
440 default:
441 ASSERT_FALSE(true);
443 } else {
444 V0 = (i & 2) + 1;
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);
471 if (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);
481 if (!CanDrop) {
482 ASSERT_FALSE(Res.has_value());
483 continue;
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));
505 switch (Kind) {
506 case Attribute::Alignment:
507 ASSERT_EQ(Res->getAlignment().valueOrOne(), MaybeAlign(2).valueOrOne());
508 break;
509 case Attribute::Memory:
510 ASSERT_EQ(Res->getMemoryEffects(), MemoryEffects::readOnly());
511 break;
512 case Attribute::NoFPClass:
513 ASSERT_EQ(Res->getNoFPClass(), FPClassTest::fcNan);
514 break;
515 case Attribute::Range:
516 ASSERT_EQ(Res->getAttribute(Kind).getRange(),
517 ConstantRange(APInt(32, 0), APInt(32, 20)));
518 break;
519 default:
520 ASSERT_FALSE(true);
523 AS0 = AS0.addAttribute(C0, Attribute::AlwaysInline);
524 ASSERT_FALSE(AS0.intersectWith(C0, AS1).has_value());
528 TEST(Attributes, SetIntersectByValAlign) {
529 LLVMContext C;
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) {
600 LLVMContext C;
601 std::optional<AttributeList> Res;
603 AttributeList AL0;
604 AttributeList AL1;
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());
613 AttributeList AL0;
614 AttributeList AL1;
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) {
632 LLVMContext C;
633 AttributeList AL0;
634 AttributeList AL1;
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