xref: /llvm-project/llvm/unittests/IR/AttributesTest.cpp (revision 22e9024c9f374c0c740647829050c289673dbb11)
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 //===----------------------------------------------------------------------===//
8 
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;
22 
23 namespace {
24 
25 TEST(Attributes, Uniquing) {
26   LLVMContext C;
27 
28   Attribute AttrA = Attribute::get(C, Attribute::AlwaysInline);
29   Attribute AttrB = Attribute::get(C, Attribute::AlwaysInline);
30   EXPECT_EQ(AttrA, AttrB);
31 
32   AttributeList ASs[] = {AttributeList::get(C, 1, Attribute::ZExt),
33                          AttributeList::get(C, 2, Attribute::SExt)};
34 
35   AttributeList SetA = AttributeList::get(C, ASs);
36   AttributeList SetB = AttributeList::get(C, ASs);
37   EXPECT_EQ(SetA, SetB);
38 }
39 
40 TEST(Attributes, Ordering) {
41   LLVMContext C;
42 
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);
53 
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);
58 
59   AttributeList ASs[] = {AttributeList::get(C, 2, Attribute::ZExt),
60                          AttributeList::get(C, 1, Attribute::SExt)};
61 
62   AttributeList SetA = AttributeList::get(C, ASs);
63   AttributeList SetB =
64       SetA.removeParamAttributes(C, 0, ASs[1].getParamAttrs(0));
65   EXPECT_NE(SetA, SetB);
66 }
67 
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));
80 }
81 
82 TEST(Attributes, RemoveAlign) {
83   LLVMContext C;
84 
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);
97 
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));
108 
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));
120 
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));
127 
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));
133 
134   AttributeList AL2;
135   AL2 = AL2.addParamAttributes(C, 0, B_align_readonly);
136   AL2 = AL2.addRetAttributes(C, B_stackalign_optnone);
137 
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));
144 
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));
150 }
151 
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));
159 
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));
167 }
168 
169 TEST(Attributes, EmptyGet) {
170   LLVMContext C;
171   AttributeList EmptyLists[] = {AttributeList(), AttributeList()};
172   AttributeList AL = AttributeList::get(C, EmptyLists);
173   EXPECT_TRUE(AL.isEmpty());
174 }
175 
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());
183 }
184 
185 TEST(Attributes, StringRepresentation) {
186   LLVMContext C;
187   StructType *Ty = StructType::create(Type::getInt32Ty(C), "mystruct");
188 
189   // Insufficiently careful printing can result in byval(%mystruct = { i32 })
190   Attribute A = Attribute::getWithByValType(C, Ty);
191   EXPECT_EQ(A.getAsString(), "byval(%mystruct)");
192 
193   A = Attribute::getWithByValType(C, Type::getInt32Ty(C));
194   EXPECT_EQ(A.getAsString(), "byval(i32)");
195 }
196 
197 TEST(Attributes, HasParentContext) {
198   LLVMContext C1, C2;
199 
200   {
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));
207   }
208 
209   {
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));
218   }
219 
220   {
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));
227   }
228 }
229 
230 TEST(Attributes, AttributeListPrinting) {
231   LLVMContext C;
232 
233   {
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");
241   }
242 
243   {
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");
251   }
252 
253   {
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");
261   }
262 }
263 
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
270     }
271     declare void @f2(i32* preallocated(i32))
272     define void @h() {
273       call void @f2(i32* null)
274       ret void
275     }
276     declare void @f3(i32* inalloca(i32))
277     define void @i() {
278       call void @f3(i32* null)
279       ret void
280     }
281   )IR";
282 
283   SMDiagnostic Err;
284   LLVMContext Context;
285   std::unique_ptr<Module> M = parseAssemblyString(IRString, Err, Context);
286   ASSERT_TRUE(M);
287 
288   {
289     auto *I = cast<CallBase>(&M->getFunction("g")->getEntryBlock().front());
290     ASSERT_TRUE(I->isByValArgument(0));
291     ASSERT_TRUE(I->getParamByValType(0));
292   }
293   {
294     auto *I = cast<CallBase>(&M->getFunction("h")->getEntryBlock().front());
295     ASSERT_TRUE(I->getParamPreallocatedType(0));
296   }
297   {
298     auto *I = cast<CallBase>(&M->getFunction("i")->getEntryBlock().front());
299     ASSERT_TRUE(I->isInAllocaArgument(0));
300     ASSERT_TRUE(I->getParamInAllocaType(0));
301   }
302 }
303 
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);
315 }
316 
317 TEST(Attributes, ConstantRangeAttributeCAPI) {
318   LLVMContext C;
319   {
320     const unsigned NumBits = 8;
321     const uint64_t LowerWords[] = {0};
322     const uint64_t UpperWords[] = {42};
323 
324     ConstantRange Range(APInt(NumBits, ArrayRef(LowerWords)),
325                         APInt(NumBits, ArrayRef(UpperWords)));
326 
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);
331   }
332   {
333     const unsigned NumBits = 128;
334     const uint64_t LowerWords[] = {1, 1};
335     const uint64_t UpperWords[] = {42, 42};
336 
337     ConstantRange Range(APInt(NumBits, ArrayRef(LowerWords)),
338                         APInt(NumBits, ArrayRef(UpperWords)));
339 
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);
344   }
345 }
346 
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)
351 
352     define void @g1(i32 %i) {
353       call void @f1(i32 %i)
354       ret void
355     }
356     define void @g2(i32 %i) {
357       call void @f2(i32 %i)
358       ret void
359     }
360     define void @g3(i32 %i) {
361       call void @f1(i32 range(i32 3, 4) %i)
362       ret void
363     }
364     define void @g4(i32 %i) {
365       call void @f2(i32 range(i32 3, 4) %i)
366       ret void
367     }
368   )IR";
369 
370   SMDiagnostic Err;
371   LLVMContext Context;
372   std::unique_ptr<Module> M = parseAssemblyString(IRString, Err, Context);
373   ASSERT_TRUE(M);
374 
375   {
376     auto *I = cast<CallBase>(&M->getFunction("g1")->getEntryBlock().front());
377     ASSERT_FALSE(I->getParamAttr(0, Attribute::Range).isValid());
378   }
379   {
380     auto *I = cast<CallBase>(&M->getFunction("g2")->getEntryBlock().front());
381     ASSERT_TRUE(I->getParamAttr(0, Attribute::Range).isValid());
382   }
383   {
384     auto *I = cast<CallBase>(&M->getFunction("g3")->getEntryBlock().front());
385     ASSERT_TRUE(I->getParamAttr(0, Attribute::Range).isValid());
386   }
387   {
388     auto *I = cast<CallBase>(&M->getFunction("g4")->getEntryBlock().front());
389     ASSERT_TRUE(I->getParamAttr(0, Attribute::Range).isValid());
390   }
391 }
392 
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();
410   };
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);
415 
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       case Attribute::Captures:
441         V0 = CaptureInfo(CaptureComponents::AddressIsNull,
442                          CaptureComponents::None)
443                  .toIntValue();
444         V1 = CaptureInfo(CaptureComponents::None,
445                          CaptureComponents::ReadProvenance)
446                  .toIntValue();
447         break;
448       default:
449         ASSERT_FALSE(true);
450       }
451     } else {
452       V0 = (i & 2) + 1;
453       V1 = (2 - (i & 2)) + 1;
454     }
455 
456     ConstantRange CR0(APInt(32, 0), APInt(32, 10));
457     ConstantRange CR1(APInt(32, 15), APInt(32, 20));
458     ConstantRange CRL0[] = {CR0};
459     ConstantRange CRL1[] = {CR0, CR1};
460     Type *T0 = Type::getInt32Ty(C0);
461     Type *T1 = Type::getInt64Ty(C0);
462     Attribute Attr0 = BuildAttr(C0, Kind, V0, T0, CR0, CRL0);
463     Attribute Attr1 = BuildAttr(
464         C1, Attribute::isEnumAttrKind(Kind) ? Other : Kind, V1, T1, CR1, CRL1);
465     bool CanDrop = Attribute::intersectWithAnd(Kind) ||
466                    Attribute::intersectWithMin(Kind) ||
467                    Attribute::intersectWithCustom(Kind);
468 
469     AB0.addAttribute(Attr0);
470     AB1.addAttribute(Attr1);
471 
472     Res = AS0.intersectWith(C0, AS1);
473     ASSERT_TRUE(Res.has_value());
474     ASSERT_EQ(AS0, *Res);
475 
476     AS0 = AttributeSet::get(C0, AB0);
477     Res = AS0.intersectWith(C0, AS1);
478     ASSERT_EQ(Res.has_value(), CanDrop);
479     if (CanDrop)
480       ASSERT_FALSE(Res->hasAttributes());
481 
482     AS1 = AttributeSet::get(C1, AB0);
483     Res = AS0.intersectWith(C0, AS1);
484     ASSERT_TRUE(Res.has_value());
485     ASSERT_EQ(AS0, *Res);
486 
487     AS1 = AttributeSet::get(C1, AB1);
488     Res = AS0.intersectWith(C0, AS1);
489     if (!CanDrop) {
490       ASSERT_FALSE(Res.has_value());
491       continue;
492     }
493     if (Attribute::intersectWithAnd(Kind)) {
494       ASSERT_TRUE(Res.has_value());
495       ASSERT_FALSE(Res->hasAttributes());
496 
497       AS1 = AS1.addAttribute(C1, Kind);
498       Res = AS0.intersectWith(C0, AS1);
499       ASSERT_TRUE(Res.has_value());
500       ASSERT_TRUE(Res->hasAttributes());
501       ASSERT_TRUE(Res->hasAttribute(Kind));
502       ASSERT_FALSE(Res->hasAttribute(Other));
503     } else if (Attribute::intersectWithMin(Kind)) {
504       ASSERT_TRUE(Res.has_value());
505       ASSERT_TRUE(Res->hasAttributes());
506       ASSERT_TRUE(Res->hasAttribute(Kind));
507       ASSERT_EQ(Res->getAttribute(Kind).getValueAsInt(), std::min(V0, V1));
508     } else if (Attribute::intersectWithCustom(Kind)) {
509       ASSERT_TRUE(Res.has_value());
510       ASSERT_TRUE(Res->hasAttributes());
511       ASSERT_TRUE(Res->hasAttribute(Kind));
512 
513       switch (Kind) {
514       case Attribute::Alignment:
515         ASSERT_EQ(Res->getAlignment().valueOrOne(), MaybeAlign(2).valueOrOne());
516         break;
517       case Attribute::Memory:
518         ASSERT_EQ(Res->getMemoryEffects(), MemoryEffects::readOnly());
519         break;
520       case Attribute::NoFPClass:
521         ASSERT_EQ(Res->getNoFPClass(), FPClassTest::fcNan);
522         break;
523       case Attribute::Range:
524         ASSERT_EQ(Res->getAttribute(Kind).getRange(),
525                   ConstantRange(APInt(32, 0), APInt(32, 20)));
526         break;
527       case Attribute::Captures:
528         ASSERT_EQ(Res->getCaptureInfo(),
529                   CaptureInfo(CaptureComponents::AddressIsNull,
530                               CaptureComponents::ReadProvenance));
531         break;
532       default:
533         ASSERT_FALSE(true);
534       }
535     }
536     AS0 = AS0.addAttribute(C0, Attribute::AlwaysInline);
537     ASSERT_FALSE(AS0.intersectWith(C0, AS1).has_value());
538   }
539 }
540 
541 TEST(Attributes, SetIntersectByValAlign) {
542   LLVMContext C;
543   AttributeSet AS0, AS1;
544 
545   Attribute ByVal = Attribute::get(C, Attribute::ByVal, Type::getInt32Ty(C));
546   Attribute Align0 = Attribute::get(C, Attribute::Alignment, 4);
547   Attribute Align1 = Attribute::get(C, Attribute::Alignment, 8);
548 
549   {
550     AttrBuilder AB0(C), AB1(C);
551     AB0.addAttribute(Align0);
552     AB1.addAttribute(Align1);
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_TRUE(Res.has_value());
558     ASSERT_TRUE(Res->hasAttribute(Attribute::Alignment));
559   }
560   {
561     AttrBuilder AB0(C), AB1(C);
562     AB0.addAttribute(Align0);
563     AB0.addAttribute(ByVal);
564     AB1.addAttribute(Align1);
565     AB1.addAttribute(ByVal);
566     AB0.addAttribute(Attribute::NoUndef);
567     AS0 = AttributeSet::get(C, AB0);
568     AS1 = AttributeSet::get(C, AB1);
569     auto Res = AS0.intersectWith(C, AS1);
570     ASSERT_FALSE(Res.has_value());
571   }
572   {
573     AttrBuilder AB0(C), AB1(C);
574     AB0.addAttribute(Align0);
575     AB0.addAttribute(ByVal);
576     AB1.addAttribute(ByVal);
577     AB0.addAttribute(Attribute::NoUndef);
578     AS0 = AttributeSet::get(C, AB0);
579     AS1 = AttributeSet::get(C, AB1);
580     ASSERT_FALSE(AS0.intersectWith(C, AS1).has_value());
581     ASSERT_FALSE(AS1.intersectWith(C, AS0).has_value());
582   }
583   {
584     AttrBuilder AB0(C), AB1(C);
585     AB0.addAttribute(ByVal);
586     AB1.addAttribute(ByVal);
587     AB0.addAttribute(Attribute::NoUndef);
588     AS0 = AttributeSet::get(C, AB0);
589     AS1 = AttributeSet::get(C, AB1);
590 
591     auto Res = AS0.intersectWith(C, AS1);
592     ASSERT_TRUE(Res.has_value());
593     ASSERT_TRUE(Res->hasAttribute(Attribute::ByVal));
594   }
595   {
596     AttrBuilder AB0(C), AB1(C);
597     AB0.addAttribute(ByVal);
598     AB0.addAttribute(Align0);
599     AB1.addAttribute(ByVal);
600     AB1.addAttribute(Align0);
601     AB0.addAttribute(Attribute::NoUndef);
602     AS0 = AttributeSet::get(C, AB0);
603     AS1 = AttributeSet::get(C, AB1);
604 
605     auto Res = AS0.intersectWith(C, AS1);
606     ASSERT_TRUE(Res.has_value());
607     ASSERT_TRUE(Res->hasAttribute(Attribute::ByVal));
608     ASSERT_TRUE(Res->hasAttribute(Attribute::Alignment));
609   }
610 }
611 
612 TEST(Attributes, ListIntersectDifferingMustPreserve) {
613   LLVMContext C;
614   std::optional<AttributeList> Res;
615   {
616     AttributeList AL0;
617     AttributeList AL1;
618     AL1 = AL1.addFnAttribute(C, Attribute::ReadOnly);
619     AL0 = AL0.addParamAttribute(C, 0, Attribute::SExt);
620     Res = AL0.intersectWith(C, AL1);
621     ASSERT_FALSE(Res.has_value());
622     Res = AL1.intersectWith(C, AL0);
623     ASSERT_FALSE(Res.has_value());
624   }
625   {
626     AttributeList AL0;
627     AttributeList AL1;
628     AL1 = AL1.addFnAttribute(C, Attribute::AlwaysInline);
629     AL0 = AL0.addParamAttribute(C, 0, Attribute::ReadOnly);
630     Res = AL0.intersectWith(C, AL1);
631     ASSERT_FALSE(Res.has_value());
632     Res = AL1.intersectWith(C, AL0);
633     ASSERT_FALSE(Res.has_value());
634 
635     AL0 = AL0.addFnAttribute(C, Attribute::AlwaysInline);
636     AL1 = AL1.addParamAttribute(C, 1, Attribute::SExt);
637     Res = AL0.intersectWith(C, AL1);
638     ASSERT_FALSE(Res.has_value());
639     Res = AL1.intersectWith(C, AL0);
640     ASSERT_FALSE(Res.has_value());
641   }
642 }
643 
644 TEST(Attributes, ListIntersect) {
645   LLVMContext C;
646   AttributeList AL0;
647   AttributeList AL1;
648   std::optional<AttributeList> Res;
649   AL0 = AL0.addRetAttribute(C, Attribute::NoUndef);
650   AL1 = AL1.addRetAttribute(C, Attribute::NoUndef);
651 
652   Res = AL0.intersectWith(C, AL1);
653   ASSERT_TRUE(Res.has_value());
654   ASSERT_EQ(AL0, *Res);
655 
656   AL0 = AL0.addParamAttribute(C, 1, Attribute::NoUndef);
657   Res = AL0.intersectWith(C, AL1);
658   ASSERT_TRUE(Res.has_value());
659   ASSERT_TRUE(Res->hasRetAttr(Attribute::NoUndef));
660   ASSERT_FALSE(Res->hasParamAttr(1, Attribute::NoUndef));
661 
662   AL1 = AL1.addParamAttribute(C, 2, Attribute::NoUndef);
663   Res = AL0.intersectWith(C, AL1);
664   ASSERT_TRUE(Res.has_value());
665   ASSERT_TRUE(Res->hasRetAttr(Attribute::NoUndef));
666   ASSERT_FALSE(Res->hasParamAttr(1, Attribute::NoUndef));
667   ASSERT_FALSE(Res->hasParamAttr(2, Attribute::NoUndef));
668 
669   AL0 = AL0.addParamAttribute(C, 2, Attribute::NoUndef);
670   AL1 = AL1.addParamAttribute(C, 1, Attribute::NoUndef);
671   Res = AL0.intersectWith(C, AL1);
672   ASSERT_TRUE(Res.has_value());
673   ASSERT_EQ(AL0, *Res);
674 
675   AL0 = AL0.addParamAttribute(C, 2, Attribute::NonNull);
676   Res = AL0.intersectWith(C, AL1);
677   ASSERT_TRUE(Res.has_value());
678   ASSERT_NE(AL0, *Res);
679   ASSERT_TRUE(Res->hasRetAttr(Attribute::NoUndef));
680   ASSERT_TRUE(Res->hasParamAttr(1, Attribute::NoUndef));
681   ASSERT_TRUE(Res->hasParamAttr(2, Attribute::NoUndef));
682   ASSERT_FALSE(Res->hasParamAttr(2, Attribute::NonNull));
683 
684   AL0 = AL0.addRetAttribute(C, Attribute::NonNull);
685   Res = AL0.intersectWith(C, AL1);
686   ASSERT_TRUE(Res.has_value());
687   ASSERT_NE(AL0, *Res);
688   ASSERT_TRUE(Res->hasRetAttr(Attribute::NoUndef));
689   ASSERT_FALSE(Res->hasRetAttr(Attribute::NonNull));
690   ASSERT_TRUE(Res->hasParamAttr(1, Attribute::NoUndef));
691   ASSERT_TRUE(Res->hasParamAttr(2, Attribute::NoUndef));
692   ASSERT_FALSE(Res->hasParamAttr(2, Attribute::NonNull));
693 
694   AL0 = AL0.addFnAttribute(C, Attribute::ReadOnly);
695   Res = AL0.intersectWith(C, AL1);
696   ASSERT_TRUE(Res.has_value());
697   ASSERT_NE(AL0, *Res);
698   ASSERT_FALSE(Res->hasFnAttr(Attribute::ReadOnly));
699   ASSERT_TRUE(Res->hasRetAttr(Attribute::NoUndef));
700   ASSERT_FALSE(Res->hasRetAttr(Attribute::NonNull));
701   ASSERT_TRUE(Res->hasParamAttr(1, Attribute::NoUndef));
702   ASSERT_TRUE(Res->hasParamAttr(2, Attribute::NoUndef));
703   ASSERT_FALSE(Res->hasParamAttr(2, Attribute::NonNull));
704 
705   AL1 = AL1.addFnAttribute(C, Attribute::ReadOnly);
706   Res = AL0.intersectWith(C, AL1);
707   ASSERT_TRUE(Res.has_value());
708   ASSERT_NE(AL0, *Res);
709   ASSERT_TRUE(Res->hasFnAttr(Attribute::ReadOnly));
710   ASSERT_TRUE(Res->hasRetAttr(Attribute::NoUndef));
711   ASSERT_FALSE(Res->hasRetAttr(Attribute::NonNull));
712   ASSERT_TRUE(Res->hasParamAttr(1, Attribute::NoUndef));
713   ASSERT_TRUE(Res->hasParamAttr(2, Attribute::NoUndef));
714   ASSERT_FALSE(Res->hasParamAttr(2, Attribute::NonNull));
715 
716   AL1 = AL1.addFnAttribute(C, Attribute::AlwaysInline);
717   Res = AL0.intersectWith(C, AL1);
718   ASSERT_FALSE(Res.has_value());
719 
720   AL0 = AL0.addFnAttribute(C, Attribute::AlwaysInline);
721   Res = AL0.intersectWith(C, AL1);
722   ASSERT_TRUE(Res.has_value());
723   ASSERT_TRUE(Res->hasFnAttr(Attribute::AlwaysInline));
724   ASSERT_TRUE(Res->hasFnAttr(Attribute::ReadOnly));
725   ASSERT_TRUE(Res->hasRetAttr(Attribute::NoUndef));
726   ASSERT_FALSE(Res->hasRetAttr(Attribute::NonNull));
727   ASSERT_TRUE(Res->hasParamAttr(1, Attribute::NoUndef));
728   ASSERT_TRUE(Res->hasParamAttr(2, Attribute::NoUndef));
729   ASSERT_FALSE(Res->hasParamAttr(2, Attribute::NonNull));
730 
731   AL1 = AL1.addParamAttribute(C, 2, Attribute::ReadNone);
732   Res = AL0.intersectWith(C, AL1);
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 
743   AL1 = AL1.addParamAttribute(C, 3, Attribute::ReadNone);
744   Res = AL0.intersectWith(C, AL1);
745   ASSERT_TRUE(Res.has_value());
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_FALSE(Res->hasParamAttr(3, Attribute::ReadNone));
756 
757   AL0 = AL0.addParamAttribute(C, 3, Attribute::ReadNone);
758   Res = AL0.intersectWith(C, AL1);
759   ASSERT_TRUE(Res.has_value());
760   ASSERT_TRUE(Res->hasFnAttr(Attribute::AlwaysInline));
761   ASSERT_TRUE(Res->hasFnAttr(Attribute::ReadOnly));
762   ASSERT_TRUE(Res->hasRetAttr(Attribute::NoUndef));
763   ASSERT_FALSE(Res->hasRetAttr(Attribute::NonNull));
764   ASSERT_TRUE(Res->hasParamAttr(1, Attribute::NoUndef));
765   ASSERT_TRUE(Res->hasParamAttr(2, Attribute::NoUndef));
766   ASSERT_FALSE(Res->hasParamAttr(2, Attribute::NonNull));
767   ASSERT_FALSE(Res->hasParamAttr(2, Attribute::ReadNone));
768   ASSERT_TRUE(Res->hasParamAttr(3, Attribute::ReadNone));
769 
770   AL0 = AL0.addParamAttribute(
771       C, {3}, Attribute::get(C, Attribute::ByVal, Type::getInt32Ty(C)));
772   Res = AL0.intersectWith(C, AL1);
773   ASSERT_FALSE(Res.has_value());
774 
775   AL1 = AL1.addParamAttribute(
776       C, {3}, Attribute::get(C, Attribute::ByVal, Type::getInt32Ty(C)));
777   Res = AL0.intersectWith(C, AL1);
778   ASSERT_TRUE(Res.has_value());
779   ASSERT_TRUE(Res->hasFnAttr(Attribute::AlwaysInline));
780   ASSERT_TRUE(Res->hasFnAttr(Attribute::ReadOnly));
781   ASSERT_TRUE(Res->hasRetAttr(Attribute::NoUndef));
782   ASSERT_FALSE(Res->hasRetAttr(Attribute::NonNull));
783   ASSERT_TRUE(Res->hasParamAttr(1, Attribute::NoUndef));
784   ASSERT_TRUE(Res->hasParamAttr(2, Attribute::NoUndef));
785   ASSERT_FALSE(Res->hasParamAttr(2, Attribute::NonNull));
786   ASSERT_FALSE(Res->hasParamAttr(2, Attribute::ReadNone));
787   ASSERT_TRUE(Res->hasParamAttr(3, Attribute::ReadNone));
788   ASSERT_TRUE(Res->hasParamAttr(3, Attribute::ByVal));
789 }
790 
791 } // end anonymous namespace
792