792 lines · cpp
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-exception6//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"21using namespace llvm;22 23namespace {24 25TEST(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 40TEST(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 68TEST(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 82TEST(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 152TEST(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 169TEST(Attributes, EmptyGet) {170 LLVMContext C;171 AttributeList EmptyLists[] = {AttributeList(), AttributeList()};172 AttributeList AL = AttributeList::get(C, EmptyLists);173 EXPECT_TRUE(AL.isEmpty());174}175 176TEST(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 185TEST(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 197TEST(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 230TEST(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 264TEST(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 void270 }271 declare void @f2(i32* preallocated(i32))272 define void @h() {273 call void @f2(i32* null)274 ret void275 }276 declare void @f3(i32* inalloca(i32))277 define void @i() {278 call void @f3(i32* null)279 ret void280 }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 304TEST(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 317TEST(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 347TEST(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 void355 }356 define void @g2(i32 %i) {357 call void @f2(i32 %i)358 ret void359 }360 define void @g3(i32 %i) {361 call void @f1(i32 range(i32 3, 4) %i)362 ret void363 }364 define void @g4(i32 %i) {365 call void @f2(i32 range(i32 3, 4) %i)366 ret void367 }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 393TEST(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 541TEST(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 612TEST(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 644TEST(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 namespace792