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 
TEST(Attributes,Uniquing)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 
TEST(Attributes,Ordering)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 
TEST(Attributes,AddAttributes)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 
TEST(Attributes,RemoveAlign)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 
TEST(Attributes,AddMatchingAlignAttr)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 
TEST(Attributes,EmptyGet)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 
TEST(Attributes,OverflowGet)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 
TEST(Attributes,StringRepresentation)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 
TEST(Attributes,HasParentContext)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 
TEST(Attributes,AttributeListPrinting)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 
TEST(Attributes,MismatchedABIAttrs)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