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