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/AsmParser/Parser.h" 11 #include "llvm/IR/DerivedTypes.h" 12 #include "llvm/IR/InstrTypes.h" 13 #include "llvm/IR/LLVMContext.h" 14 #include "llvm/IR/Module.h" 15 #include "llvm/Support/SourceMgr.h" 16 #include "gtest/gtest.h" 17 using namespace llvm; 18 19 namespace { 20 21 TEST(Attributes, Uniquing) { 22 LLVMContext C; 23 24 Attribute AttrA = Attribute::get(C, Attribute::AlwaysInline); 25 Attribute AttrB = Attribute::get(C, Attribute::AlwaysInline); 26 EXPECT_EQ(AttrA, AttrB); 27 28 AttributeList ASs[] = {AttributeList::get(C, 1, Attribute::ZExt), 29 AttributeList::get(C, 2, Attribute::SExt)}; 30 31 AttributeList SetA = AttributeList::get(C, ASs); 32 AttributeList SetB = AttributeList::get(C, ASs); 33 EXPECT_EQ(SetA, SetB); 34 } 35 36 TEST(Attributes, Ordering) { 37 LLVMContext C; 38 39 Attribute Align4 = Attribute::get(C, Attribute::Alignment, 4); 40 Attribute Align5 = Attribute::get(C, Attribute::Alignment, 5); 41 Attribute Deref4 = Attribute::get(C, Attribute::Dereferenceable, 4); 42 Attribute Deref5 = Attribute::get(C, Attribute::Dereferenceable, 5); 43 EXPECT_TRUE(Align4 < Align5); 44 EXPECT_TRUE(Align4 < Deref4); 45 EXPECT_TRUE(Align4 < Deref5); 46 EXPECT_TRUE(Align5 < Deref4); 47 48 Attribute ByVal = Attribute::get(C, Attribute::ByVal, Type::getInt32Ty(C)); 49 EXPECT_FALSE(ByVal < Attribute::get(C, Attribute::ZExt)); 50 EXPECT_TRUE(ByVal < Align4); 51 EXPECT_FALSE(ByVal < ByVal); 52 53 AttributeList ASs[] = {AttributeList::get(C, 2, Attribute::ZExt), 54 AttributeList::get(C, 1, Attribute::SExt)}; 55 56 AttributeList SetA = AttributeList::get(C, ASs); 57 AttributeList SetB = SetA.removeAttributes(C, 1, ASs[1].getAttributes(1)); 58 EXPECT_NE(SetA, SetB); 59 } 60 61 TEST(Attributes, AddAttributes) { 62 LLVMContext C; 63 AttributeList AL; 64 AttrBuilder B; 65 B.addAttribute(Attribute::NoReturn); 66 AL = AL.addAttributes(C, AttributeList::FunctionIndex, AttributeSet::get(C, B)); 67 EXPECT_TRUE(AL.hasFnAttribute(Attribute::NoReturn)); 68 B.clear(); 69 B.addAttribute(Attribute::SExt); 70 AL = AL.addAttributes(C, AttributeList::ReturnIndex, B); 71 EXPECT_TRUE(AL.hasAttribute(AttributeList::ReturnIndex, Attribute::SExt)); 72 EXPECT_TRUE(AL.hasFnAttribute(Attribute::NoReturn)); 73 } 74 75 TEST(Attributes, RemoveAlign) { 76 LLVMContext C; 77 78 Attribute AlignAttr = Attribute::getWithAlignment(C, Align(8)); 79 Attribute StackAlignAttr = Attribute::getWithStackAlignment(C, Align(32)); 80 AttrBuilder B_align_readonly; 81 B_align_readonly.addAttribute(AlignAttr); 82 B_align_readonly.addAttribute(Attribute::ReadOnly); 83 AttrBuilder B_align; 84 B_align.addAttribute(AlignAttr); 85 AttrBuilder B_stackalign_optnone; 86 B_stackalign_optnone.addAttribute(StackAlignAttr); 87 B_stackalign_optnone.addAttribute(Attribute::OptimizeNone); 88 AttrBuilder B_stackalign; 89 B_stackalign.addAttribute(StackAlignAttr); 90 91 AttributeSet AS = AttributeSet::get(C, B_align_readonly); 92 EXPECT_TRUE(AS.getAlignment() == 8); 93 EXPECT_TRUE(AS.hasAttribute(Attribute::ReadOnly)); 94 AS = AS.removeAttribute(C, Attribute::Alignment); 95 EXPECT_FALSE(AS.hasAttribute(Attribute::Alignment)); 96 EXPECT_TRUE(AS.hasAttribute(Attribute::ReadOnly)); 97 AS = AttributeSet::get(C, B_align_readonly); 98 AS = AS.removeAttributes(C, B_align); 99 EXPECT_TRUE(AS.getAlignment() == 0); 100 EXPECT_TRUE(AS.hasAttribute(Attribute::ReadOnly)); 101 102 AttributeList AL; 103 AL = AL.addParamAttributes(C, 0, B_align_readonly); 104 AL = AL.addAttributes(C, 0, B_stackalign_optnone); 105 EXPECT_TRUE(AL.hasAttributes(0)); 106 EXPECT_TRUE(AL.hasAttribute(0, Attribute::StackAlignment)); 107 EXPECT_TRUE(AL.hasAttribute(0, Attribute::OptimizeNone)); 108 EXPECT_TRUE(AL.getStackAlignment(0) == 32); 109 EXPECT_TRUE(AL.hasParamAttrs(0)); 110 EXPECT_TRUE(AL.hasParamAttr(0, Attribute::Alignment)); 111 EXPECT_TRUE(AL.hasParamAttr(0, Attribute::ReadOnly)); 112 EXPECT_TRUE(AL.getParamAlignment(0) == 8); 113 114 AL = AL.removeParamAttribute(C, 0, Attribute::Alignment); 115 EXPECT_FALSE(AL.hasParamAttr(0, Attribute::Alignment)); 116 EXPECT_TRUE(AL.hasParamAttr(0, Attribute::ReadOnly)); 117 EXPECT_TRUE(AL.hasAttribute(0, Attribute::StackAlignment)); 118 EXPECT_TRUE(AL.hasAttribute(0, Attribute::OptimizeNone)); 119 EXPECT_TRUE(AL.getStackAlignment(0) == 32); 120 121 AL = AL.removeAttribute(C, 0, Attribute::StackAlignment); 122 EXPECT_FALSE(AL.hasParamAttr(0, Attribute::Alignment)); 123 EXPECT_TRUE(AL.hasParamAttr(0, Attribute::ReadOnly)); 124 EXPECT_FALSE(AL.hasAttribute(0, Attribute::StackAlignment)); 125 EXPECT_TRUE(AL.hasAttribute(0, Attribute::OptimizeNone)); 126 127 AttributeList AL2; 128 AL2 = AL2.addParamAttributes(C, 0, B_align_readonly); 129 AL2 = AL2.addAttributes(C, 0, B_stackalign_optnone); 130 131 AL2 = AL2.removeParamAttributes(C, 0, B_align); 132 EXPECT_FALSE(AL2.hasParamAttr(0, Attribute::Alignment)); 133 EXPECT_TRUE(AL2.hasParamAttr(0, Attribute::ReadOnly)); 134 EXPECT_TRUE(AL2.hasAttribute(0, Attribute::StackAlignment)); 135 EXPECT_TRUE(AL2.hasAttribute(0, Attribute::OptimizeNone)); 136 EXPECT_TRUE(AL2.getStackAlignment(0) == 32); 137 138 AL2 = AL2.removeAttributes(C, 0, B_stackalign); 139 EXPECT_FALSE(AL2.hasParamAttr(0, Attribute::Alignment)); 140 EXPECT_TRUE(AL2.hasParamAttr(0, Attribute::ReadOnly)); 141 EXPECT_FALSE(AL2.hasAttribute(0, Attribute::StackAlignment)); 142 EXPECT_TRUE(AL2.hasAttribute(0, Attribute::OptimizeNone)); 143 } 144 145 TEST(Attributes, AddMatchingAlignAttr) { 146 LLVMContext C; 147 AttributeList AL; 148 AL = AL.addAttribute(C, AttributeList::FirstArgIndex, 149 Attribute::getWithAlignment(C, Align(8))); 150 AL = AL.addAttribute(C, AttributeList::FirstArgIndex + 1, 151 Attribute::getWithAlignment(C, Align(32))); 152 EXPECT_EQ(Align(8), AL.getParamAlignment(0)); 153 EXPECT_EQ(Align(32), AL.getParamAlignment(1)); 154 155 AttrBuilder B; 156 B.addAttribute(Attribute::NonNull); 157 B.addAlignmentAttr(8); 158 AL = AL.addAttributes(C, AttributeList::FirstArgIndex, B); 159 EXPECT_EQ(Align(8), AL.getParamAlignment(0)); 160 EXPECT_EQ(Align(32), AL.getParamAlignment(1)); 161 EXPECT_TRUE(AL.hasParamAttribute(0, Attribute::NonNull)); 162 } 163 164 TEST(Attributes, EmptyGet) { 165 LLVMContext C; 166 AttributeList EmptyLists[] = {AttributeList(), AttributeList()}; 167 AttributeList AL = AttributeList::get(C, EmptyLists); 168 EXPECT_TRUE(AL.isEmpty()); 169 } 170 171 TEST(Attributes, OverflowGet) { 172 LLVMContext C; 173 std::pair<unsigned, Attribute> Attrs[] = { { AttributeList::ReturnIndex, Attribute::get(C, Attribute::SExt) }, 174 { AttributeList::FunctionIndex, Attribute::get(C, Attribute::ReadOnly) } }; 175 AttributeList AL = AttributeList::get(C, Attrs); 176 EXPECT_EQ(2U, AL.getNumAttrSets()); 177 } 178 179 TEST(Attributes, StringRepresentation) { 180 LLVMContext C; 181 StructType *Ty = StructType::create(Type::getInt32Ty(C), "mystruct"); 182 183 // Insufficiently careful printing can result in byval(%mystruct = { i32 }) 184 Attribute A = Attribute::getWithByValType(C, Ty); 185 EXPECT_EQ(A.getAsString(), "byval(%mystruct)"); 186 187 A = Attribute::getWithByValType(C, Type::getInt32Ty(C)); 188 EXPECT_EQ(A.getAsString(), "byval(i32)"); 189 } 190 191 TEST(Attributes, HasParentContext) { 192 LLVMContext C1, C2; 193 194 { 195 Attribute Attr1 = Attribute::get(C1, Attribute::AlwaysInline); 196 Attribute Attr2 = Attribute::get(C2, Attribute::AlwaysInline); 197 EXPECT_TRUE(Attr1.hasParentContext(C1)); 198 EXPECT_FALSE(Attr1.hasParentContext(C2)); 199 EXPECT_FALSE(Attr2.hasParentContext(C1)); 200 EXPECT_TRUE(Attr2.hasParentContext(C2)); 201 } 202 203 { 204 AttributeSet AS1 = AttributeSet::get( 205 C1, makeArrayRef(Attribute::get(C1, Attribute::NoReturn))); 206 AttributeSet AS2 = AttributeSet::get( 207 C2, makeArrayRef(Attribute::get(C2, Attribute::NoReturn))); 208 EXPECT_TRUE(AS1.hasParentContext(C1)); 209 EXPECT_FALSE(AS1.hasParentContext(C2)); 210 EXPECT_FALSE(AS2.hasParentContext(C1)); 211 EXPECT_TRUE(AS2.hasParentContext(C2)); 212 } 213 214 { 215 AttributeList AL1 = AttributeList::get(C1, 1, Attribute::ZExt); 216 AttributeList AL2 = AttributeList::get(C2, 1, Attribute::ZExt); 217 EXPECT_TRUE(AL1.hasParentContext(C1)); 218 EXPECT_FALSE(AL1.hasParentContext(C2)); 219 EXPECT_FALSE(AL2.hasParentContext(C1)); 220 EXPECT_TRUE(AL2.hasParentContext(C2)); 221 } 222 } 223 224 TEST(Attributes, AttributeListPrinting) { 225 LLVMContext C; 226 227 { 228 std::string S; 229 raw_string_ostream OS(S); 230 AttributeList AL; 231 AL.addAttribute(C, AttributeList::FunctionIndex, Attribute::AlwaysInline) 232 .print(OS); 233 EXPECT_EQ(S, "AttributeList[\n" 234 " { function => alwaysinline }\n" 235 "]\n"); 236 } 237 238 { 239 std::string S; 240 raw_string_ostream OS(S); 241 AttributeList AL; 242 AL.addAttribute(C, AttributeList::ReturnIndex, Attribute::SExt).print(OS); 243 EXPECT_EQ(S, "AttributeList[\n" 244 " { return => signext }\n" 245 "]\n"); 246 } 247 248 { 249 std::string S; 250 raw_string_ostream OS(S); 251 AttributeList AL; 252 AL.addParamAttribute(C, 5, Attribute::ZExt).print(OS); 253 EXPECT_EQ(S, "AttributeList[\n" 254 " { arg(5) => zeroext }\n" 255 "]\n"); 256 } 257 } 258 259 TEST(Attributes, MismatchedABIAttrs) { 260 const char *IRString = R"IR( 261 declare void @f1(i32* byval(i32)) 262 define void @g() { 263 call void @f1(i32* null) 264 ret void 265 } 266 declare void @f2(i32* preallocated(i32)) 267 define void @h() { 268 call void @f2(i32* null) 269 ret void 270 } 271 declare void @f3(i32* inalloca(i32)) 272 define void @i() { 273 call void @f3(i32* null) 274 ret void 275 } 276 )IR"; 277 278 SMDiagnostic Err; 279 LLVMContext Context; 280 std::unique_ptr<Module> M = parseAssemblyString(IRString, Err, Context); 281 ASSERT_TRUE(M); 282 283 { 284 auto *I = cast<CallBase>(&M->getFunction("g")->getEntryBlock().front()); 285 ASSERT_TRUE(I->isByValArgument(0)); 286 ASSERT_TRUE(I->getParamByValType(0)); 287 } 288 { 289 auto *I = cast<CallBase>(&M->getFunction("h")->getEntryBlock().front()); 290 ASSERT_TRUE(I->getParamPreallocatedType(0)); 291 } 292 { 293 auto *I = cast<CallBase>(&M->getFunction("i")->getEntryBlock().front()); 294 ASSERT_TRUE(I->isInAllocaArgument(0)); 295 ASSERT_TRUE(I->getParamInAllocaType(0)); 296 } 297 } 298 299 } // end anonymous namespace 300