brintos

brintos / llvm-project-archived public Read only

0
0
Text · 26.8 KiB · f0e34aa Raw
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