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