1 | //===- llvm/unittest/IR/IRBuilderTest.cpp - IRBuilder 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/Analysis/InstSimplifyFolder.h" |
10 | #include "llvm/IR/IRBuilder.h" |
11 | #include "llvm/IR/BasicBlock.h" |
12 | #include "llvm/IR/DIBuilder.h" |
13 | #include "llvm/IR/DataLayout.h" |
14 | #include "llvm/IR/Function.h" |
15 | #include "llvm/IR/IntrinsicInst.h" |
16 | #include "llvm/IR/IntrinsicsAArch64.h" |
17 | #include "llvm/IR/LLVMContext.h" |
18 | #include "llvm/IR/MDBuilder.h" |
19 | #include "llvm/IR/Module.h" |
20 | #include "llvm/IR/NoFolder.h" |
21 | #include "llvm/IR/Verifier.h" |
22 | #include "gmock/gmock.h" |
23 | #include "gtest/gtest.h" |
24 | |
25 | #include <type_traits> |
26 | |
27 | using namespace llvm; |
28 | using ::testing::UnorderedElementsAre; |
29 | |
30 | namespace { |
31 | |
32 | class IRBuilderTest : public testing::Test { |
33 | protected: |
34 | void SetUp() override { |
35 | M.reset(p: new Module("MyModule" , Ctx)); |
36 | FunctionType *FTy = FunctionType::get(Result: Type::getVoidTy(C&: Ctx), |
37 | /*isVarArg=*/false); |
38 | F = Function::Create(Ty: FTy, Linkage: Function::ExternalLinkage, N: "" , M: M.get()); |
39 | BB = BasicBlock::Create(Context&: Ctx, Name: "" , Parent: F); |
40 | GV = new GlobalVariable(*M, Type::getFloatTy(C&: Ctx), true, |
41 | GlobalValue::ExternalLinkage, nullptr); |
42 | } |
43 | |
44 | void TearDown() override { |
45 | BB = nullptr; |
46 | M.reset(); |
47 | } |
48 | |
49 | LLVMContext Ctx; |
50 | std::unique_ptr<Module> M; |
51 | Function *F; |
52 | BasicBlock *BB; |
53 | GlobalVariable *GV; |
54 | }; |
55 | |
56 | TEST_F(IRBuilderTest, Intrinsics) { |
57 | IRBuilder<> Builder(BB); |
58 | Value *V; |
59 | Instruction *I; |
60 | Value *Result; |
61 | IntrinsicInst *II; |
62 | |
63 | V = Builder.CreateLoad(Ty: GV->getValueType(), Ptr: GV); |
64 | I = cast<Instruction>(Val: Builder.CreateFAdd(L: V, R: V)); |
65 | I->setHasNoInfs(true); |
66 | I->setHasNoNaNs(false); |
67 | |
68 | Result = Builder.CreateMinNum(LHS: V, RHS: V); |
69 | II = cast<IntrinsicInst>(Val: Result); |
70 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::minnum); |
71 | |
72 | Result = Builder.CreateMaxNum(LHS: V, RHS: V); |
73 | II = cast<IntrinsicInst>(Val: Result); |
74 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::maxnum); |
75 | |
76 | Result = Builder.CreateMinimum(LHS: V, RHS: V); |
77 | II = cast<IntrinsicInst>(Val: Result); |
78 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::minimum); |
79 | |
80 | Result = Builder.CreateMaximum(LHS: V, RHS: V); |
81 | II = cast<IntrinsicInst>(Val: Result); |
82 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::maximum); |
83 | |
84 | Result = Builder.CreateIntrinsic(Intrinsic::readcyclecounter, {}, {}); |
85 | II = cast<IntrinsicInst>(Val: Result); |
86 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::readcyclecounter); |
87 | |
88 | Result = Builder.CreateUnaryIntrinsic(Intrinsic::ID: fabs, V); |
89 | II = cast<IntrinsicInst>(Val: Result); |
90 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fabs); |
91 | EXPECT_FALSE(II->hasNoInfs()); |
92 | EXPECT_FALSE(II->hasNoNaNs()); |
93 | |
94 | Result = Builder.CreateUnaryIntrinsic(Intrinsic::ID: fabs, V, FMFSource: I); |
95 | II = cast<IntrinsicInst>(Val: Result); |
96 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fabs); |
97 | EXPECT_TRUE(II->hasNoInfs()); |
98 | EXPECT_FALSE(II->hasNoNaNs()); |
99 | |
100 | Result = Builder.CreateBinaryIntrinsic(Intrinsic::ID: pow, LHS: V, RHS: V); |
101 | II = cast<IntrinsicInst>(Val: Result); |
102 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::pow); |
103 | EXPECT_FALSE(II->hasNoInfs()); |
104 | EXPECT_FALSE(II->hasNoNaNs()); |
105 | |
106 | Result = Builder.CreateBinaryIntrinsic(Intrinsic::ID: pow, LHS: V, RHS: V, FMFSource: I); |
107 | II = cast<IntrinsicInst>(Val: Result); |
108 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::pow); |
109 | EXPECT_TRUE(II->hasNoInfs()); |
110 | EXPECT_FALSE(II->hasNoNaNs()); |
111 | |
112 | Result = Builder.CreateIntrinsic(Intrinsic::fma, {V->getType()}, {V, V, V}); |
113 | II = cast<IntrinsicInst>(Val: Result); |
114 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fma); |
115 | EXPECT_FALSE(II->hasNoInfs()); |
116 | EXPECT_FALSE(II->hasNoNaNs()); |
117 | |
118 | Result = |
119 | Builder.CreateIntrinsic(Intrinsic::fma, {V->getType()}, {V, V, V}, I); |
120 | II = cast<IntrinsicInst>(Val: Result); |
121 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fma); |
122 | EXPECT_TRUE(II->hasNoInfs()); |
123 | EXPECT_FALSE(II->hasNoNaNs()); |
124 | |
125 | Result = |
126 | Builder.CreateIntrinsic(Intrinsic::fma, {V->getType()}, {V, V, V}, I); |
127 | II = cast<IntrinsicInst>(Val: Result); |
128 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fma); |
129 | EXPECT_TRUE(II->hasNoInfs()); |
130 | EXPECT_FALSE(II->hasNoNaNs()); |
131 | |
132 | Result = Builder.CreateUnaryIntrinsic(Intrinsic::ID: roundeven, V); |
133 | II = cast<IntrinsicInst>(Val: Result); |
134 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::roundeven); |
135 | EXPECT_FALSE(II->hasNoInfs()); |
136 | EXPECT_FALSE(II->hasNoNaNs()); |
137 | |
138 | Result = Builder.CreateIntrinsic( |
139 | Intrinsic::set_rounding, {}, |
140 | {Builder.getInt32(C: static_cast<uint32_t>(RoundingMode::TowardZero))}); |
141 | II = cast<IntrinsicInst>(Val: Result); |
142 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::set_rounding); |
143 | } |
144 | |
145 | TEST_F(IRBuilderTest, IntrinsicMangling) { |
146 | IRBuilder<> Builder(BB); |
147 | Type *VoidTy = Builder.getVoidTy(); |
148 | Type *Int64Ty = Builder.getInt64Ty(); |
149 | Value *Int64Val = Builder.getInt64(C: 0); |
150 | Value *DoubleVal = PoisonValue::get(T: Builder.getDoubleTy()); |
151 | CallInst *Call; |
152 | |
153 | // Mangled return type, no arguments. |
154 | Call = Builder.CreateIntrinsic(Int64Ty, Intrinsic::coro_size, {}); |
155 | EXPECT_EQ(Call->getCalledFunction()->getName(), "llvm.coro.size.i64" ); |
156 | |
157 | // Void return type, mangled argument type. |
158 | Call = |
159 | Builder.CreateIntrinsic(VoidTy, Intrinsic::set_loop_iterations, Int64Val); |
160 | EXPECT_EQ(Call->getCalledFunction()->getName(), |
161 | "llvm.set.loop.iterations.i64" ); |
162 | |
163 | // Mangled return type and argument type. |
164 | Call = Builder.CreateIntrinsic(Int64Ty, Intrinsic::lround, DoubleVal); |
165 | EXPECT_EQ(Call->getCalledFunction()->getName(), "llvm.lround.i64.f64" ); |
166 | } |
167 | |
168 | TEST_F(IRBuilderTest, IntrinsicsWithScalableVectors) { |
169 | IRBuilder<> Builder(BB); |
170 | CallInst *Call; |
171 | FunctionType *FTy; |
172 | |
173 | // Test scalable flag isn't dropped for intrinsic that is explicitly defined |
174 | // with scalable vectors, e.g. LLVMType<nxv4i32>. |
175 | Type *SrcVecTy = VectorType::get(ElementType: Builder.getHalfTy(), NumElements: 8, Scalable: true); |
176 | Type *DstVecTy = VectorType::get(ElementType: Builder.getInt32Ty(), NumElements: 4, Scalable: true); |
177 | Type *PredTy = VectorType::get(ElementType: Builder.getInt1Ty(), NumElements: 4, Scalable: true); |
178 | |
179 | SmallVector<Value*, 3> ArgTys; |
180 | ArgTys.push_back(Elt: UndefValue::get(T: DstVecTy)); |
181 | ArgTys.push_back(Elt: UndefValue::get(T: PredTy)); |
182 | ArgTys.push_back(Elt: UndefValue::get(T: SrcVecTy)); |
183 | |
184 | Call = Builder.CreateIntrinsic(Intrinsic::aarch64_sve_fcvtzs_i32f16, {}, |
185 | ArgTys, nullptr, "aarch64.sve.fcvtzs.i32f16" ); |
186 | FTy = Call->getFunctionType(); |
187 | EXPECT_EQ(FTy->getReturnType(), DstVecTy); |
188 | for (unsigned i = 0; i != ArgTys.size(); ++i) |
189 | EXPECT_EQ(FTy->getParamType(i), ArgTys[i]->getType()); |
190 | |
191 | // Test scalable flag isn't dropped for intrinsic defined with |
192 | // LLVMScalarOrSameVectorWidth. |
193 | |
194 | Type *VecTy = VectorType::get(ElementType: Builder.getInt32Ty(), NumElements: 4, Scalable: true); |
195 | Type *PtrToVecTy = Builder.getPtrTy(); |
196 | PredTy = VectorType::get(ElementType: Builder.getInt1Ty(), NumElements: 4, Scalable: true); |
197 | |
198 | ArgTys.clear(); |
199 | ArgTys.push_back(Elt: UndefValue::get(T: PtrToVecTy)); |
200 | ArgTys.push_back(Elt: UndefValue::get(T: Builder.getInt32Ty())); |
201 | ArgTys.push_back(Elt: UndefValue::get(T: PredTy)); |
202 | ArgTys.push_back(Elt: UndefValue::get(T: VecTy)); |
203 | |
204 | Call = Builder.CreateIntrinsic(Intrinsic::masked_load, |
205 | {VecTy, PtrToVecTy}, ArgTys, |
206 | nullptr, "masked.load" ); |
207 | FTy = Call->getFunctionType(); |
208 | EXPECT_EQ(FTy->getReturnType(), VecTy); |
209 | for (unsigned i = 0; i != ArgTys.size(); ++i) |
210 | EXPECT_EQ(FTy->getParamType(i), ArgTys[i]->getType()); |
211 | } |
212 | |
213 | TEST_F(IRBuilderTest, CreateVScale) { |
214 | IRBuilder<> Builder(BB); |
215 | |
216 | Constant *Zero = Builder.getInt32(C: 0); |
217 | Value *VScale = Builder.CreateVScale(Scaling: Zero); |
218 | EXPECT_TRUE(isa<ConstantInt>(VScale) && cast<ConstantInt>(VScale)->isZero()); |
219 | } |
220 | |
221 | TEST_F(IRBuilderTest, CreateStepVector) { |
222 | IRBuilder<> Builder(BB); |
223 | |
224 | // Fixed width vectors |
225 | Type *DstVecTy = VectorType::get(ElementType: Builder.getInt32Ty(), NumElements: 4, Scalable: false); |
226 | Value *StepVec = Builder.CreateStepVector(DstType: DstVecTy); |
227 | EXPECT_TRUE(isa<Constant>(StepVec)); |
228 | EXPECT_EQ(StepVec->getType(), DstVecTy); |
229 | |
230 | const auto *VectorValue = cast<Constant>(Val: StepVec); |
231 | for (unsigned i = 0; i < 4; i++) { |
232 | EXPECT_TRUE(isa<ConstantInt>(VectorValue->getAggregateElement(i))); |
233 | ConstantInt *El = cast<ConstantInt>(Val: VectorValue->getAggregateElement(Elt: i)); |
234 | EXPECT_EQ(El->getValue(), i); |
235 | } |
236 | |
237 | // Scalable vectors |
238 | DstVecTy = VectorType::get(ElementType: Builder.getInt32Ty(), NumElements: 4, Scalable: true); |
239 | StepVec = Builder.CreateStepVector(DstType: DstVecTy); |
240 | EXPECT_TRUE(isa<CallInst>(StepVec)); |
241 | CallInst *Call = cast<CallInst>(Val: StepVec); |
242 | FunctionType *FTy = Call->getFunctionType(); |
243 | EXPECT_EQ(FTy->getReturnType(), DstVecTy); |
244 | EXPECT_EQ(Call->getIntrinsicID(), Intrinsic::experimental_stepvector); |
245 | } |
246 | |
247 | TEST_F(IRBuilderTest, CreateStepVectorI3) { |
248 | IRBuilder<> Builder(BB); |
249 | |
250 | // Scalable vectors |
251 | Type *DstVecTy = VectorType::get(ElementType: IntegerType::get(C&: Ctx, NumBits: 3), NumElements: 2, Scalable: true); |
252 | Type *VecI8Ty = VectorType::get(ElementType: Builder.getInt8Ty(), NumElements: 2, Scalable: true); |
253 | Value *StepVec = Builder.CreateStepVector(DstType: DstVecTy); |
254 | EXPECT_TRUE(isa<TruncInst>(StepVec)); |
255 | TruncInst *Trunc = cast<TruncInst>(Val: StepVec); |
256 | EXPECT_EQ(Trunc->getDestTy(), DstVecTy); |
257 | EXPECT_EQ(Trunc->getSrcTy(), VecI8Ty); |
258 | EXPECT_TRUE(isa<CallInst>(Trunc->getOperand(0))); |
259 | |
260 | CallInst *Call = cast<CallInst>(Val: Trunc->getOperand(i_nocapture: 0)); |
261 | FunctionType *FTy = Call->getFunctionType(); |
262 | EXPECT_EQ(FTy->getReturnType(), VecI8Ty); |
263 | EXPECT_EQ(Call->getIntrinsicID(), Intrinsic::experimental_stepvector); |
264 | } |
265 | |
266 | TEST_F(IRBuilderTest, ConstrainedFP) { |
267 | IRBuilder<> Builder(BB); |
268 | Value *V; |
269 | Value *VDouble; |
270 | Value *VInt; |
271 | CallInst *Call; |
272 | IntrinsicInst *II; |
273 | GlobalVariable *GVDouble = new GlobalVariable(*M, Type::getDoubleTy(C&: Ctx), |
274 | true, GlobalValue::ExternalLinkage, nullptr); |
275 | |
276 | V = Builder.CreateLoad(Ty: GV->getValueType(), Ptr: GV); |
277 | VDouble = Builder.CreateLoad(Ty: GVDouble->getValueType(), Ptr: GVDouble); |
278 | |
279 | // See if we get constrained intrinsics instead of non-constrained |
280 | // instructions. |
281 | Builder.setIsFPConstrained(true); |
282 | auto Parent = BB->getParent(); |
283 | Parent->addFnAttr(Attribute::StrictFP); |
284 | |
285 | V = Builder.CreateFAdd(L: V, R: V); |
286 | ASSERT_TRUE(isa<IntrinsicInst>(V)); |
287 | II = cast<IntrinsicInst>(Val: V); |
288 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fadd); |
289 | |
290 | V = Builder.CreateFSub(L: V, R: V); |
291 | ASSERT_TRUE(isa<IntrinsicInst>(V)); |
292 | II = cast<IntrinsicInst>(Val: V); |
293 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fsub); |
294 | |
295 | V = Builder.CreateFMul(L: V, R: V); |
296 | ASSERT_TRUE(isa<IntrinsicInst>(V)); |
297 | II = cast<IntrinsicInst>(Val: V); |
298 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fmul); |
299 | |
300 | V = Builder.CreateFDiv(L: V, R: V); |
301 | ASSERT_TRUE(isa<IntrinsicInst>(V)); |
302 | II = cast<IntrinsicInst>(Val: V); |
303 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fdiv); |
304 | |
305 | V = Builder.CreateFRem(L: V, R: V); |
306 | ASSERT_TRUE(isa<IntrinsicInst>(V)); |
307 | II = cast<IntrinsicInst>(Val: V); |
308 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_frem); |
309 | |
310 | VInt = Builder.CreateFPToUI(V: VDouble, DestTy: Builder.getInt32Ty()); |
311 | ASSERT_TRUE(isa<IntrinsicInst>(VInt)); |
312 | II = cast<IntrinsicInst>(Val: VInt); |
313 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fptoui); |
314 | |
315 | VInt = Builder.CreateFPToSI(V: VDouble, DestTy: Builder.getInt32Ty()); |
316 | ASSERT_TRUE(isa<IntrinsicInst>(VInt)); |
317 | II = cast<IntrinsicInst>(Val: VInt); |
318 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fptosi); |
319 | |
320 | VDouble = Builder.CreateUIToFP(V: VInt, DestTy: Builder.getDoubleTy()); |
321 | ASSERT_TRUE(isa<IntrinsicInst>(VDouble)); |
322 | II = cast<IntrinsicInst>(Val: VDouble); |
323 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_uitofp); |
324 | |
325 | VDouble = Builder.CreateSIToFP(V: VInt, DestTy: Builder.getDoubleTy()); |
326 | ASSERT_TRUE(isa<IntrinsicInst>(VDouble)); |
327 | II = cast<IntrinsicInst>(Val: VDouble); |
328 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_sitofp); |
329 | |
330 | V = Builder.CreateFPTrunc(V: VDouble, DestTy: Type::getFloatTy(C&: Ctx)); |
331 | ASSERT_TRUE(isa<IntrinsicInst>(V)); |
332 | II = cast<IntrinsicInst>(Val: V); |
333 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fptrunc); |
334 | |
335 | VDouble = Builder.CreateFPExt(V, DestTy: Type::getDoubleTy(C&: Ctx)); |
336 | ASSERT_TRUE(isa<IntrinsicInst>(VDouble)); |
337 | II = cast<IntrinsicInst>(Val: VDouble); |
338 | EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fpext); |
339 | |
340 | // Verify attributes on the call are created automatically. |
341 | AttributeSet CallAttrs = II->getAttributes().getFnAttrs(); |
342 | EXPECT_EQ(CallAttrs.hasAttribute(Attribute::StrictFP), true); |
343 | |
344 | // Verify attributes on the containing function are created when requested. |
345 | Builder.setConstrainedFPFunctionAttr(); |
346 | AttributeList Attrs = BB->getParent()->getAttributes(); |
347 | AttributeSet FnAttrs = Attrs.getFnAttrs(); |
348 | EXPECT_EQ(FnAttrs.hasAttribute(Attribute::StrictFP), true); |
349 | |
350 | // Verify the codepaths for setting and overriding the default metadata. |
351 | V = Builder.CreateFAdd(L: V, R: V); |
352 | ASSERT_TRUE(isa<ConstrainedFPIntrinsic>(V)); |
353 | auto *CII = cast<ConstrainedFPIntrinsic>(Val: V); |
354 | EXPECT_EQ(fp::ebStrict, CII->getExceptionBehavior()); |
355 | EXPECT_EQ(RoundingMode::Dynamic, CII->getRoundingMode()); |
356 | |
357 | Builder.setDefaultConstrainedExcept(fp::ebIgnore); |
358 | Builder.setDefaultConstrainedRounding(RoundingMode::TowardPositive); |
359 | V = Builder.CreateFAdd(L: V, R: V); |
360 | CII = cast<ConstrainedFPIntrinsic>(Val: V); |
361 | EXPECT_EQ(fp::ebIgnore, CII->getExceptionBehavior()); |
362 | EXPECT_EQ(CII->getRoundingMode(), RoundingMode::TowardPositive); |
363 | |
364 | Builder.setDefaultConstrainedExcept(fp::ebIgnore); |
365 | Builder.setDefaultConstrainedRounding(RoundingMode::NearestTiesToEven); |
366 | V = Builder.CreateFAdd(L: V, R: V); |
367 | CII = cast<ConstrainedFPIntrinsic>(Val: V); |
368 | EXPECT_EQ(fp::ebIgnore, CII->getExceptionBehavior()); |
369 | EXPECT_EQ(RoundingMode::NearestTiesToEven, CII->getRoundingMode()); |
370 | |
371 | Builder.setDefaultConstrainedExcept(fp::ebMayTrap); |
372 | Builder.setDefaultConstrainedRounding(RoundingMode::TowardNegative); |
373 | V = Builder.CreateFAdd(L: V, R: V); |
374 | CII = cast<ConstrainedFPIntrinsic>(Val: V); |
375 | EXPECT_EQ(fp::ebMayTrap, CII->getExceptionBehavior()); |
376 | EXPECT_EQ(RoundingMode::TowardNegative, CII->getRoundingMode()); |
377 | |
378 | Builder.setDefaultConstrainedExcept(fp::ebStrict); |
379 | Builder.setDefaultConstrainedRounding(RoundingMode::TowardZero); |
380 | V = Builder.CreateFAdd(L: V, R: V); |
381 | CII = cast<ConstrainedFPIntrinsic>(Val: V); |
382 | EXPECT_EQ(fp::ebStrict, CII->getExceptionBehavior()); |
383 | EXPECT_EQ(RoundingMode::TowardZero, CII->getRoundingMode()); |
384 | |
385 | Builder.setDefaultConstrainedExcept(fp::ebIgnore); |
386 | Builder.setDefaultConstrainedRounding(RoundingMode::Dynamic); |
387 | V = Builder.CreateFAdd(L: V, R: V); |
388 | CII = cast<ConstrainedFPIntrinsic>(Val: V); |
389 | EXPECT_EQ(fp::ebIgnore, CII->getExceptionBehavior()); |
390 | EXPECT_EQ(RoundingMode::Dynamic, CII->getRoundingMode()); |
391 | |
392 | // Now override the defaults. |
393 | Call = Builder.CreateConstrainedFPBinOp( |
394 | Intrinsic::ID: experimental_constrained_fadd, L: V, R: V, FMFSource: nullptr, Name: "" , FPMathTag: nullptr, |
395 | Rounding: RoundingMode::TowardNegative, Except: fp::ebMayTrap); |
396 | CII = cast<ConstrainedFPIntrinsic>(Val: Call); |
397 | EXPECT_EQ(CII->getIntrinsicID(), Intrinsic::experimental_constrained_fadd); |
398 | EXPECT_EQ(fp::ebMayTrap, CII->getExceptionBehavior()); |
399 | EXPECT_EQ(RoundingMode::TowardNegative, CII->getRoundingMode()); |
400 | |
401 | Builder.CreateRetVoid(); |
402 | EXPECT_FALSE(verifyModule(*M)); |
403 | } |
404 | |
405 | TEST_F(IRBuilderTest, ConstrainedFPIntrinsics) { |
406 | IRBuilder<> Builder(BB); |
407 | Value *V; |
408 | Value *VDouble; |
409 | ConstrainedFPIntrinsic *CII; |
410 | GlobalVariable *GVDouble = new GlobalVariable( |
411 | *M, Type::getDoubleTy(C&: Ctx), true, GlobalValue::ExternalLinkage, nullptr); |
412 | VDouble = Builder.CreateLoad(Ty: GVDouble->getValueType(), Ptr: GVDouble); |
413 | |
414 | Builder.setDefaultConstrainedExcept(fp::ebStrict); |
415 | Builder.setDefaultConstrainedRounding(RoundingMode::TowardZero); |
416 | Function *Fn = Intrinsic::getDeclaration(M: M.get(), |
417 | Intrinsic::id: experimental_constrained_roundeven, Tys: { Type::getDoubleTy(C&: Ctx) }); |
418 | V = Builder.CreateConstrainedFPCall(Callee: Fn, Args: { VDouble }); |
419 | CII = cast<ConstrainedFPIntrinsic>(Val: V); |
420 | EXPECT_EQ(Intrinsic::experimental_constrained_roundeven, CII->getIntrinsicID()); |
421 | EXPECT_EQ(fp::ebStrict, CII->getExceptionBehavior()); |
422 | } |
423 | |
424 | TEST_F(IRBuilderTest, ConstrainedFPFunctionCall) { |
425 | IRBuilder<> Builder(BB); |
426 | |
427 | // Create an empty constrained FP function. |
428 | FunctionType *FTy = FunctionType::get(Result: Type::getVoidTy(C&: Ctx), |
429 | /*isVarArg=*/false); |
430 | Function *Callee = |
431 | Function::Create(Ty: FTy, Linkage: Function::ExternalLinkage, N: "" , M: M.get()); |
432 | BasicBlock *CalleeBB = BasicBlock::Create(Context&: Ctx, Name: "" , Parent: Callee); |
433 | IRBuilder<> CalleeBuilder(CalleeBB); |
434 | CalleeBuilder.setIsFPConstrained(true); |
435 | CalleeBuilder.setConstrainedFPFunctionAttr(); |
436 | CalleeBuilder.CreateRetVoid(); |
437 | |
438 | // Now call the empty constrained FP function. |
439 | Builder.setIsFPConstrained(true); |
440 | Builder.setConstrainedFPFunctionAttr(); |
441 | CallInst *FCall = Builder.CreateCall(Callee, Args: std::nullopt); |
442 | |
443 | // Check the attributes to verify the strictfp attribute is on the call. |
444 | EXPECT_TRUE( |
445 | FCall->getAttributes().getFnAttrs().hasAttribute(Attribute::StrictFP)); |
446 | |
447 | Builder.CreateRetVoid(); |
448 | EXPECT_FALSE(verifyModule(*M)); |
449 | } |
450 | |
451 | TEST_F(IRBuilderTest, Lifetime) { |
452 | IRBuilder<> Builder(BB); |
453 | AllocaInst *Var1 = Builder.CreateAlloca(Ty: Builder.getInt8Ty()); |
454 | AllocaInst *Var2 = Builder.CreateAlloca(Ty: Builder.getInt32Ty()); |
455 | AllocaInst *Var3 = Builder.CreateAlloca(Ty: Builder.getInt8Ty(), |
456 | ArraySize: Builder.getInt32(C: 123)); |
457 | |
458 | CallInst *Start1 = Builder.CreateLifetimeStart(Ptr: Var1); |
459 | CallInst *Start2 = Builder.CreateLifetimeStart(Ptr: Var2); |
460 | CallInst *Start3 = Builder.CreateLifetimeStart(Ptr: Var3, Size: Builder.getInt64(C: 100)); |
461 | |
462 | EXPECT_EQ(Start1->getArgOperand(0), Builder.getInt64(-1)); |
463 | EXPECT_EQ(Start2->getArgOperand(0), Builder.getInt64(-1)); |
464 | EXPECT_EQ(Start3->getArgOperand(0), Builder.getInt64(100)); |
465 | |
466 | EXPECT_EQ(Start1->getArgOperand(1), Var1); |
467 | EXPECT_EQ(Start2->getArgOperand(1)->stripPointerCasts(), Var2); |
468 | EXPECT_EQ(Start3->getArgOperand(1), Var3); |
469 | |
470 | Value *End1 = Builder.CreateLifetimeEnd(Ptr: Var1); |
471 | Builder.CreateLifetimeEnd(Ptr: Var2); |
472 | Builder.CreateLifetimeEnd(Ptr: Var3); |
473 | |
474 | IntrinsicInst *II_Start1 = dyn_cast<IntrinsicInst>(Val: Start1); |
475 | IntrinsicInst *II_End1 = dyn_cast<IntrinsicInst>(Val: End1); |
476 | ASSERT_TRUE(II_Start1 != nullptr); |
477 | EXPECT_EQ(II_Start1->getIntrinsicID(), Intrinsic::lifetime_start); |
478 | ASSERT_TRUE(II_End1 != nullptr); |
479 | EXPECT_EQ(II_End1->getIntrinsicID(), Intrinsic::lifetime_end); |
480 | } |
481 | |
482 | TEST_F(IRBuilderTest, CreateCondBr) { |
483 | IRBuilder<> Builder(BB); |
484 | BasicBlock *TBB = BasicBlock::Create(Context&: Ctx, Name: "" , Parent: F); |
485 | BasicBlock *FBB = BasicBlock::Create(Context&: Ctx, Name: "" , Parent: F); |
486 | |
487 | BranchInst *BI = Builder.CreateCondBr(Cond: Builder.getTrue(), True: TBB, False: FBB); |
488 | Instruction *TI = BB->getTerminator(); |
489 | EXPECT_EQ(BI, TI); |
490 | EXPECT_EQ(2u, TI->getNumSuccessors()); |
491 | EXPECT_EQ(TBB, TI->getSuccessor(0)); |
492 | EXPECT_EQ(FBB, TI->getSuccessor(1)); |
493 | |
494 | BI->eraseFromParent(); |
495 | MDNode *Weights = MDBuilder(Ctx).createBranchWeights(TrueWeight: 42, FalseWeight: 13); |
496 | BI = Builder.CreateCondBr(Cond: Builder.getTrue(), True: TBB, False: FBB, BranchWeights: Weights); |
497 | TI = BB->getTerminator(); |
498 | EXPECT_EQ(BI, TI); |
499 | EXPECT_EQ(2u, TI->getNumSuccessors()); |
500 | EXPECT_EQ(TBB, TI->getSuccessor(0)); |
501 | EXPECT_EQ(FBB, TI->getSuccessor(1)); |
502 | EXPECT_EQ(Weights, TI->getMetadata(LLVMContext::MD_prof)); |
503 | } |
504 | |
505 | TEST_F(IRBuilderTest, LandingPadName) { |
506 | IRBuilder<> Builder(BB); |
507 | LandingPadInst *LP = Builder.CreateLandingPad(Ty: Builder.getInt32Ty(), NumClauses: 0, Name: "LP" ); |
508 | EXPECT_EQ(LP->getName(), "LP" ); |
509 | } |
510 | |
511 | TEST_F(IRBuilderTest, DataLayout) { |
512 | std::unique_ptr<Module> M(new Module("test" , Ctx)); |
513 | M->setDataLayout("e-n32" ); |
514 | EXPECT_TRUE(M->getDataLayout().isLegalInteger(32)); |
515 | M->setDataLayout("e" ); |
516 | EXPECT_FALSE(M->getDataLayout().isLegalInteger(32)); |
517 | } |
518 | |
519 | TEST_F(IRBuilderTest, GetIntTy) { |
520 | IRBuilder<> Builder(BB); |
521 | IntegerType *Ty1 = Builder.getInt1Ty(); |
522 | EXPECT_EQ(Ty1, IntegerType::get(Ctx, 1)); |
523 | |
524 | DataLayout* DL = new DataLayout(M.get()); |
525 | IntegerType *IntPtrTy = Builder.getIntPtrTy(DL: *DL); |
526 | unsigned IntPtrBitSize = DL->getPointerSizeInBits(AS: 0); |
527 | EXPECT_EQ(IntPtrTy, IntegerType::get(Ctx, IntPtrBitSize)); |
528 | delete DL; |
529 | } |
530 | |
531 | TEST_F(IRBuilderTest, UnaryOperators) { |
532 | IRBuilder<NoFolder> Builder(BB); |
533 | Value *V = Builder.CreateLoad(Ty: GV->getValueType(), Ptr: GV); |
534 | |
535 | // Test CreateUnOp(X) |
536 | Value *U = Builder.CreateUnOp(Opc: Instruction::FNeg, V); |
537 | ASSERT_TRUE(isa<Instruction>(U)); |
538 | ASSERT_TRUE(isa<FPMathOperator>(U)); |
539 | ASSERT_TRUE(isa<UnaryOperator>(U)); |
540 | ASSERT_FALSE(isa<BinaryOperator>(U)); |
541 | |
542 | // Test CreateFNegFMF(X) |
543 | Instruction *I = cast<Instruction>(Val: U); |
544 | I->setHasNoSignedZeros(true); |
545 | I->setHasNoNaNs(true); |
546 | Value *VFMF = Builder.CreateFNegFMF(V, FMFSource: I); |
547 | Instruction *IFMF = cast<Instruction>(Val: VFMF); |
548 | EXPECT_TRUE(IFMF->hasNoSignedZeros()); |
549 | EXPECT_TRUE(IFMF->hasNoNaNs()); |
550 | EXPECT_FALSE(IFMF->hasAllowReassoc()); |
551 | } |
552 | |
553 | TEST_F(IRBuilderTest, FastMathFlags) { |
554 | IRBuilder<> Builder(BB); |
555 | Value *F, *FC; |
556 | Instruction *FDiv, *FAdd, *FCmp, *FCall, *FNeg, *FSub, *FMul, *FRem; |
557 | |
558 | F = Builder.CreateLoad(Ty: GV->getValueType(), Ptr: GV); |
559 | F = Builder.CreateFAdd(L: F, R: F); |
560 | |
561 | EXPECT_FALSE(Builder.getFastMathFlags().any()); |
562 | ASSERT_TRUE(isa<Instruction>(F)); |
563 | FAdd = cast<Instruction>(Val: F); |
564 | EXPECT_FALSE(FAdd->hasNoNaNs()); |
565 | |
566 | FastMathFlags FMF; |
567 | Builder.setFastMathFlags(FMF); |
568 | |
569 | // By default, no flags are set. |
570 | F = Builder.CreateFAdd(L: F, R: F); |
571 | EXPECT_FALSE(Builder.getFastMathFlags().any()); |
572 | ASSERT_TRUE(isa<Instruction>(F)); |
573 | FAdd = cast<Instruction>(Val: F); |
574 | EXPECT_FALSE(FAdd->hasNoNaNs()); |
575 | EXPECT_FALSE(FAdd->hasNoInfs()); |
576 | EXPECT_FALSE(FAdd->hasNoSignedZeros()); |
577 | EXPECT_FALSE(FAdd->hasAllowReciprocal()); |
578 | EXPECT_FALSE(FAdd->hasAllowContract()); |
579 | EXPECT_FALSE(FAdd->hasAllowReassoc()); |
580 | EXPECT_FALSE(FAdd->hasApproxFunc()); |
581 | |
582 | // Set all flags in the instruction. |
583 | FAdd->setFast(true); |
584 | EXPECT_TRUE(FAdd->hasNoNaNs()); |
585 | EXPECT_TRUE(FAdd->hasNoInfs()); |
586 | EXPECT_TRUE(FAdd->hasNoSignedZeros()); |
587 | EXPECT_TRUE(FAdd->hasAllowReciprocal()); |
588 | EXPECT_TRUE(FAdd->hasAllowContract()); |
589 | EXPECT_TRUE(FAdd->hasAllowReassoc()); |
590 | EXPECT_TRUE(FAdd->hasApproxFunc()); |
591 | |
592 | // All flags are set in the builder. |
593 | FMF.setFast(); |
594 | Builder.setFastMathFlags(FMF); |
595 | |
596 | F = Builder.CreateFAdd(L: F, R: F); |
597 | EXPECT_TRUE(Builder.getFastMathFlags().any()); |
598 | EXPECT_TRUE(Builder.getFastMathFlags().all()); |
599 | ASSERT_TRUE(isa<Instruction>(F)); |
600 | FAdd = cast<Instruction>(Val: F); |
601 | EXPECT_TRUE(FAdd->hasNoNaNs()); |
602 | EXPECT_TRUE(FAdd->isFast()); |
603 | |
604 | // Now, try it with CreateBinOp |
605 | F = Builder.CreateBinOp(Opc: Instruction::FAdd, LHS: F, RHS: F); |
606 | EXPECT_TRUE(Builder.getFastMathFlags().any()); |
607 | ASSERT_TRUE(isa<Instruction>(F)); |
608 | FAdd = cast<Instruction>(Val: F); |
609 | EXPECT_TRUE(FAdd->hasNoNaNs()); |
610 | EXPECT_TRUE(FAdd->isFast()); |
611 | |
612 | F = Builder.CreateFDiv(L: F, R: F); |
613 | EXPECT_TRUE(Builder.getFastMathFlags().all()); |
614 | ASSERT_TRUE(isa<Instruction>(F)); |
615 | FDiv = cast<Instruction>(Val: F); |
616 | EXPECT_TRUE(FDiv->hasAllowReciprocal()); |
617 | |
618 | // Clear all FMF in the builder. |
619 | Builder.clearFastMathFlags(); |
620 | |
621 | F = Builder.CreateFDiv(L: F, R: F); |
622 | ASSERT_TRUE(isa<Instruction>(F)); |
623 | FDiv = cast<Instruction>(Val: F); |
624 | EXPECT_FALSE(FDiv->hasAllowReciprocal()); |
625 | |
626 | // Try individual flags. |
627 | FMF.clear(); |
628 | FMF.setAllowReciprocal(); |
629 | Builder.setFastMathFlags(FMF); |
630 | |
631 | F = Builder.CreateFDiv(L: F, R: F); |
632 | EXPECT_TRUE(Builder.getFastMathFlags().any()); |
633 | EXPECT_TRUE(Builder.getFastMathFlags().AllowReciprocal); |
634 | ASSERT_TRUE(isa<Instruction>(F)); |
635 | FDiv = cast<Instruction>(Val: F); |
636 | EXPECT_TRUE(FDiv->hasAllowReciprocal()); |
637 | |
638 | Builder.clearFastMathFlags(); |
639 | |
640 | FC = Builder.CreateFCmpOEQ(LHS: F, RHS: F); |
641 | ASSERT_TRUE(isa<Instruction>(FC)); |
642 | FCmp = cast<Instruction>(Val: FC); |
643 | EXPECT_FALSE(FCmp->hasAllowReciprocal()); |
644 | |
645 | FMF.clear(); |
646 | FMF.setAllowReciprocal(); |
647 | Builder.setFastMathFlags(FMF); |
648 | |
649 | FC = Builder.CreateFCmpOEQ(LHS: F, RHS: F); |
650 | EXPECT_TRUE(Builder.getFastMathFlags().any()); |
651 | EXPECT_TRUE(Builder.getFastMathFlags().AllowReciprocal); |
652 | ASSERT_TRUE(isa<Instruction>(FC)); |
653 | FCmp = cast<Instruction>(Val: FC); |
654 | EXPECT_TRUE(FCmp->hasAllowReciprocal()); |
655 | |
656 | Builder.clearFastMathFlags(); |
657 | |
658 | // Test FP-contract |
659 | FC = Builder.CreateFAdd(L: F, R: F); |
660 | ASSERT_TRUE(isa<Instruction>(FC)); |
661 | FAdd = cast<Instruction>(Val: FC); |
662 | EXPECT_FALSE(FAdd->hasAllowContract()); |
663 | |
664 | FMF.clear(); |
665 | FMF.setAllowContract(true); |
666 | Builder.setFastMathFlags(FMF); |
667 | |
668 | FC = Builder.CreateFAdd(L: F, R: F); |
669 | EXPECT_TRUE(Builder.getFastMathFlags().any()); |
670 | EXPECT_TRUE(Builder.getFastMathFlags().AllowContract); |
671 | ASSERT_TRUE(isa<Instruction>(FC)); |
672 | FAdd = cast<Instruction>(Val: FC); |
673 | EXPECT_TRUE(FAdd->hasAllowContract()); |
674 | |
675 | FMF.setApproxFunc(); |
676 | Builder.clearFastMathFlags(); |
677 | Builder.setFastMathFlags(FMF); |
678 | // Now 'aml' and 'contract' are set. |
679 | F = Builder.CreateFMul(L: F, R: F); |
680 | FAdd = cast<Instruction>(Val: F); |
681 | EXPECT_TRUE(FAdd->hasApproxFunc()); |
682 | EXPECT_TRUE(FAdd->hasAllowContract()); |
683 | EXPECT_FALSE(FAdd->hasAllowReassoc()); |
684 | |
685 | FMF.setAllowReassoc(); |
686 | Builder.clearFastMathFlags(); |
687 | Builder.setFastMathFlags(FMF); |
688 | // Now 'aml' and 'contract' and 'reassoc' are set. |
689 | F = Builder.CreateFMul(L: F, R: F); |
690 | FAdd = cast<Instruction>(Val: F); |
691 | EXPECT_TRUE(FAdd->hasApproxFunc()); |
692 | EXPECT_TRUE(FAdd->hasAllowContract()); |
693 | EXPECT_TRUE(FAdd->hasAllowReassoc()); |
694 | |
695 | // Test a call with FMF. |
696 | auto CalleeTy = FunctionType::get(Result: Type::getFloatTy(C&: Ctx), |
697 | /*isVarArg=*/false); |
698 | auto Callee = |
699 | Function::Create(Ty: CalleeTy, Linkage: Function::ExternalLinkage, N: "" , M: M.get()); |
700 | |
701 | FCall = Builder.CreateCall(Callee, Args: std::nullopt); |
702 | EXPECT_FALSE(FCall->hasNoNaNs()); |
703 | |
704 | Function *V = |
705 | Function::Create(Ty: CalleeTy, Linkage: Function::ExternalLinkage, N: "" , M: M.get()); |
706 | FCall = Builder.CreateCall(Callee: V, Args: std::nullopt); |
707 | EXPECT_FALSE(FCall->hasNoNaNs()); |
708 | |
709 | FMF.clear(); |
710 | FMF.setNoNaNs(); |
711 | Builder.setFastMathFlags(FMF); |
712 | |
713 | FCall = Builder.CreateCall(Callee, Args: std::nullopt); |
714 | EXPECT_TRUE(Builder.getFastMathFlags().any()); |
715 | EXPECT_TRUE(Builder.getFastMathFlags().NoNaNs); |
716 | EXPECT_TRUE(FCall->hasNoNaNs()); |
717 | |
718 | FCall = Builder.CreateCall(Callee: V, Args: std::nullopt); |
719 | EXPECT_TRUE(Builder.getFastMathFlags().any()); |
720 | EXPECT_TRUE(Builder.getFastMathFlags().NoNaNs); |
721 | EXPECT_TRUE(FCall->hasNoNaNs()); |
722 | |
723 | Builder.clearFastMathFlags(); |
724 | |
725 | // To test a copy, make sure that a '0' and a '1' change state. |
726 | F = Builder.CreateFDiv(L: F, R: F); |
727 | ASSERT_TRUE(isa<Instruction>(F)); |
728 | FDiv = cast<Instruction>(Val: F); |
729 | EXPECT_FALSE(FDiv->getFastMathFlags().any()); |
730 | FDiv->setHasAllowReciprocal(true); |
731 | FAdd->setHasAllowReciprocal(false); |
732 | FAdd->setHasNoNaNs(true); |
733 | FDiv->copyFastMathFlags(I: FAdd); |
734 | EXPECT_TRUE(FDiv->hasNoNaNs()); |
735 | EXPECT_FALSE(FDiv->hasAllowReciprocal()); |
736 | |
737 | // Test that CreateF*FMF functions copy flags from the source instruction |
738 | // instead of using the builder default. |
739 | Instruction *const FMFSource = FAdd; |
740 | EXPECT_FALSE(Builder.getFastMathFlags().noNaNs()); |
741 | EXPECT_TRUE(FMFSource->hasNoNaNs()); |
742 | |
743 | F = Builder.CreateFNegFMF(V: F, FMFSource); |
744 | ASSERT_TRUE(isa<Instruction>(F)); |
745 | FNeg = cast<Instruction>(Val: F); |
746 | EXPECT_TRUE(FNeg->hasNoNaNs()); |
747 | F = Builder.CreateFAddFMF(L: F, R: F, FMFSource); |
748 | ASSERT_TRUE(isa<Instruction>(F)); |
749 | FAdd = cast<Instruction>(Val: F); |
750 | EXPECT_TRUE(FAdd->hasNoNaNs()); |
751 | F = Builder.CreateFSubFMF(L: F, R: F, FMFSource); |
752 | ASSERT_TRUE(isa<Instruction>(F)); |
753 | FSub = cast<Instruction>(Val: F); |
754 | EXPECT_TRUE(FSub->hasNoNaNs()); |
755 | F = Builder.CreateFMulFMF(L: F, R: F, FMFSource); |
756 | ASSERT_TRUE(isa<Instruction>(F)); |
757 | FMul = cast<Instruction>(Val: F); |
758 | EXPECT_TRUE(FMul->hasNoNaNs()); |
759 | F = Builder.CreateFDivFMF(L: F, R: F, FMFSource); |
760 | ASSERT_TRUE(isa<Instruction>(F)); |
761 | FDiv = cast<Instruction>(Val: F); |
762 | EXPECT_TRUE(FDiv->hasNoNaNs()); |
763 | F = Builder.CreateFRemFMF(L: F, R: F, FMFSource); |
764 | ASSERT_TRUE(isa<Instruction>(F)); |
765 | FRem = cast<Instruction>(Val: F); |
766 | EXPECT_TRUE(FRem->hasNoNaNs()); |
767 | } |
768 | |
769 | TEST_F(IRBuilderTest, WrapFlags) { |
770 | IRBuilder<NoFolder> Builder(BB); |
771 | |
772 | // Test instructions. |
773 | GlobalVariable *G = new GlobalVariable(*M, Builder.getInt32Ty(), true, |
774 | GlobalValue::ExternalLinkage, nullptr); |
775 | Value *V = Builder.CreateLoad(Ty: G->getValueType(), Ptr: G); |
776 | EXPECT_TRUE( |
777 | cast<BinaryOperator>(Builder.CreateNSWAdd(V, V))->hasNoSignedWrap()); |
778 | EXPECT_TRUE( |
779 | cast<BinaryOperator>(Builder.CreateNSWMul(V, V))->hasNoSignedWrap()); |
780 | EXPECT_TRUE( |
781 | cast<BinaryOperator>(Builder.CreateNSWSub(V, V))->hasNoSignedWrap()); |
782 | EXPECT_TRUE(cast<BinaryOperator>( |
783 | Builder.CreateShl(V, V, "" , /* NUW */ false, /* NSW */ true)) |
784 | ->hasNoSignedWrap()); |
785 | |
786 | EXPECT_TRUE( |
787 | cast<BinaryOperator>(Builder.CreateNUWAdd(V, V))->hasNoUnsignedWrap()); |
788 | EXPECT_TRUE( |
789 | cast<BinaryOperator>(Builder.CreateNUWMul(V, V))->hasNoUnsignedWrap()); |
790 | EXPECT_TRUE( |
791 | cast<BinaryOperator>(Builder.CreateNUWSub(V, V))->hasNoUnsignedWrap()); |
792 | EXPECT_TRUE(cast<BinaryOperator>( |
793 | Builder.CreateShl(V, V, "" , /* NUW */ true, /* NSW */ false)) |
794 | ->hasNoUnsignedWrap()); |
795 | |
796 | // Test operators created with constants. |
797 | Constant *C = Builder.getInt32(C: 42); |
798 | EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNSWAdd(C, C)) |
799 | ->hasNoSignedWrap()); |
800 | EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNSWSub(C, C)) |
801 | ->hasNoSignedWrap()); |
802 | EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNSWMul(C, C)) |
803 | ->hasNoSignedWrap()); |
804 | EXPECT_TRUE(cast<OverflowingBinaryOperator>( |
805 | Builder.CreateShl(C, C, "" , /* NUW */ false, /* NSW */ true)) |
806 | ->hasNoSignedWrap()); |
807 | |
808 | EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNUWAdd(C, C)) |
809 | ->hasNoUnsignedWrap()); |
810 | EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNUWSub(C, C)) |
811 | ->hasNoUnsignedWrap()); |
812 | EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNUWMul(C, C)) |
813 | ->hasNoUnsignedWrap()); |
814 | EXPECT_TRUE(cast<OverflowingBinaryOperator>( |
815 | Builder.CreateShl(C, C, "" , /* NUW */ true, /* NSW */ false)) |
816 | ->hasNoUnsignedWrap()); |
817 | } |
818 | |
819 | TEST_F(IRBuilderTest, RAIIHelpersTest) { |
820 | IRBuilder<> Builder(BB); |
821 | EXPECT_FALSE(Builder.getFastMathFlags().allowReciprocal()); |
822 | MDBuilder MDB(M->getContext()); |
823 | |
824 | MDNode *FPMathA = MDB.createFPMath(Accuracy: 0.01f); |
825 | MDNode *FPMathB = MDB.createFPMath(Accuracy: 0.1f); |
826 | |
827 | Builder.setDefaultFPMathTag(FPMathA); |
828 | |
829 | { |
830 | IRBuilder<>::FastMathFlagGuard Guard(Builder); |
831 | FastMathFlags FMF; |
832 | FMF.setAllowReciprocal(); |
833 | Builder.setFastMathFlags(FMF); |
834 | Builder.setDefaultFPMathTag(FPMathB); |
835 | EXPECT_TRUE(Builder.getFastMathFlags().allowReciprocal()); |
836 | EXPECT_EQ(FPMathB, Builder.getDefaultFPMathTag()); |
837 | } |
838 | |
839 | EXPECT_FALSE(Builder.getFastMathFlags().allowReciprocal()); |
840 | EXPECT_EQ(FPMathA, Builder.getDefaultFPMathTag()); |
841 | |
842 | Value *F = Builder.CreateLoad(Ty: GV->getValueType(), Ptr: GV); |
843 | |
844 | { |
845 | IRBuilder<>::InsertPointGuard Guard(Builder); |
846 | Builder.SetInsertPoint(cast<Instruction>(Val: F)); |
847 | EXPECT_EQ(F, &*Builder.GetInsertPoint()); |
848 | } |
849 | |
850 | EXPECT_EQ(BB->end(), Builder.GetInsertPoint()); |
851 | EXPECT_EQ(BB, Builder.GetInsertBlock()); |
852 | } |
853 | |
854 | TEST_F(IRBuilderTest, createFunction) { |
855 | IRBuilder<> Builder(BB); |
856 | DIBuilder DIB(*M); |
857 | auto File = DIB.createFile(Filename: "error.swift" , Directory: "/" ); |
858 | auto CU = |
859 | DIB.createCompileUnit(Lang: dwarf::DW_LANG_Swift, File, Producer: "swiftc" , isOptimized: true, Flags: "" , RV: 0); |
860 | auto Type = DIB.createSubroutineType(ParameterTypes: DIB.getOrCreateTypeArray(Elements: std::nullopt)); |
861 | auto NoErr = DIB.createFunction( |
862 | Scope: CU, Name: "noerr" , LinkageName: "" , File, LineNo: 1, Ty: Type, ScopeLine: 1, Flags: DINode::FlagZero, |
863 | SPFlags: DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized); |
864 | EXPECT_TRUE(!NoErr->getThrownTypes()); |
865 | auto Int = DIB.createBasicType(Name: "Int" , SizeInBits: 64, Encoding: dwarf::DW_ATE_signed); |
866 | auto Error = DIB.getOrCreateArray(Elements: {Int}); |
867 | auto Err = DIB.createFunction( |
868 | Scope: CU, Name: "err" , LinkageName: "" , File, LineNo: 1, Ty: Type, ScopeLine: 1, Flags: DINode::FlagZero, |
869 | SPFlags: DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized, TParams: nullptr, |
870 | Decl: nullptr, ThrownTypes: Error.get()); |
871 | EXPECT_TRUE(Err->getThrownTypes().get() == Error.get()); |
872 | DIB.finalize(); |
873 | } |
874 | |
875 | TEST_F(IRBuilderTest, DIBuilder) { |
876 | auto GetLastDbgRecord = [](const Instruction *I) -> DbgRecord * { |
877 | if (I->getDbgRecordRange().empty()) |
878 | return nullptr; |
879 | return &*std::prev(x: I->getDbgRecordRange().end()); |
880 | }; |
881 | |
882 | auto ExpectOrder = [&](DbgInstPtr First, BasicBlock::iterator Second) { |
883 | if (M->IsNewDbgInfoFormat) { |
884 | EXPECT_TRUE(First.is<DbgRecord *>()); |
885 | EXPECT_FALSE(Second->getDbgRecordRange().empty()); |
886 | EXPECT_EQ(GetLastDbgRecord(&*Second), First.get<DbgRecord *>()); |
887 | } else { |
888 | EXPECT_TRUE(First.is<Instruction *>()); |
889 | EXPECT_EQ(&*std::prev(Second), First.get<Instruction *>()); |
890 | } |
891 | }; |
892 | |
893 | auto RunTest = [&]() { |
894 | IRBuilder<> Builder(BB); |
895 | DIBuilder DIB(*M); |
896 | auto File = DIB.createFile(Filename: "F.CBL" , Directory: "/" ); |
897 | auto CU = DIB.createCompileUnit(Lang: dwarf::DW_LANG_Cobol74, |
898 | File: DIB.createFile(Filename: "F.CBL" , Directory: "/" ), |
899 | Producer: "llvm-cobol74" , isOptimized: true, Flags: "" , RV: 0); |
900 | auto Type = |
901 | DIB.createSubroutineType(ParameterTypes: DIB.getOrCreateTypeArray(Elements: std::nullopt)); |
902 | auto SP = DIB.createFunction( |
903 | Scope: CU, Name: "foo" , LinkageName: "" , File, LineNo: 1, Ty: Type, ScopeLine: 1, Flags: DINode::FlagZero, |
904 | SPFlags: DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized); |
905 | F->setSubprogram(SP); |
906 | AllocaInst *I = Builder.CreateAlloca(Ty: Builder.getInt8Ty()); |
907 | auto BarSP = DIB.createFunction( |
908 | Scope: CU, Name: "bar" , LinkageName: "" , File, LineNo: 1, Ty: Type, ScopeLine: 1, Flags: DINode::FlagZero, |
909 | SPFlags: DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized); |
910 | auto BarScope = DIB.createLexicalBlockFile(Scope: BarSP, File, Discriminator: 0); |
911 | I->setDebugLoc(DILocation::get(Context&: Ctx, Line: 2, Column: 0, Scope: BarScope)); |
912 | |
913 | // Create another instruction so that there's one before the alloca we're |
914 | // inserting debug intrinsics before, to make end-checking easier. |
915 | I = Builder.CreateAlloca(Ty: Builder.getInt1Ty()); |
916 | |
917 | // Label metadata and records |
918 | // -------------------------- |
919 | DILocation *LabelLoc = DILocation::get(Context&: Ctx, Line: 1, Column: 0, Scope: BarScope); |
920 | DILabel *AlwaysPreserveLabel = DIB.createLabel( |
921 | Scope: BarScope, Name: "meles_meles" , File, LineNo: 1, /*AlwaysPreserve*/ true); |
922 | DILabel *Label = |
923 | DIB.createLabel(Scope: BarScope, Name: "badger" , File, LineNo: 1, /*AlwaysPreserve*/ false); |
924 | |
925 | { /* dbg.label | DbgLabelRecord */ |
926 | // Insert before I and check order. |
927 | ExpectOrder(DIB.insertLabel(LabelInfo: Label, DL: LabelLoc, InsertBefore: I), I->getIterator()); |
928 | |
929 | // We should be able to insert at the end of the block, even if there's |
930 | // no terminator yet. Note that in RemoveDIs mode this record won't get |
931 | // inserted into the block untill another instruction is added. |
932 | DbgInstPtr LabelRecord = DIB.insertLabel(LabelInfo: Label, DL: LabelLoc, InsertAtEnd: BB); |
933 | // Specifically do not insert a terminator, to check this works. `I` |
934 | // should have absorbed the DbgLabelRecord in the new debug info mode. |
935 | I = Builder.CreateAlloca(Ty: Builder.getInt32Ty()); |
936 | ExpectOrder(LabelRecord, I->getIterator()); |
937 | } |
938 | |
939 | // Variable metadata and records |
940 | // ----------------------------- |
941 | DILocation *VarLoc = DILocation::get(Context&: Ctx, Line: 2, Column: 0, Scope: BarScope); |
942 | auto *IntType = DIB.createBasicType(Name: "int" , SizeInBits: 32, Encoding: dwarf::DW_ATE_signed); |
943 | DILocalVariable *VarX = |
944 | DIB.createAutoVariable(Scope: BarSP, Name: "X" , File, LineNo: 2, Ty: IntType, AlwaysPreserve: true); |
945 | DILocalVariable *VarY = |
946 | DIB.createAutoVariable(Scope: BarSP, Name: "Y" , File, LineNo: 2, Ty: IntType, AlwaysPreserve: true); |
947 | { /* dbg.value | DbgVariableRecord::Value */ |
948 | ExpectOrder(DIB.insertDbgValueIntrinsic(Val: I, VarInfo: VarX, Expr: DIB.createExpression(), |
949 | DL: VarLoc, InsertBefore: I), |
950 | I->getIterator()); |
951 | // Check inserting at end of the block works as with labels. |
952 | DbgInstPtr VarXValue = DIB.insertDbgValueIntrinsic( |
953 | Val: I, VarInfo: VarX, Expr: DIB.createExpression(), DL: VarLoc, InsertAtEnd: BB); |
954 | I = Builder.CreateAlloca(Ty: Builder.getInt32Ty()); |
955 | ExpectOrder(VarXValue, I->getIterator()); |
956 | EXPECT_EQ(BB->getTrailingDbgRecords(), nullptr); |
957 | } |
958 | { /* dbg.declare | DbgVariableRecord::Declare */ |
959 | ExpectOrder(DIB.insertDeclare(Storage: I, VarInfo: VarY, Expr: DIB.createExpression(), DL: VarLoc, InsertBefore: I), |
960 | I->getIterator()); |
961 | // Check inserting at end of the block works as with labels. |
962 | DbgInstPtr VarYDeclare = |
963 | DIB.insertDeclare(Storage: I, VarInfo: VarY, Expr: DIB.createExpression(), DL: VarLoc, InsertAtEnd: BB); |
964 | I = Builder.CreateAlloca(Ty: Builder.getInt32Ty()); |
965 | ExpectOrder(VarYDeclare, I->getIterator()); |
966 | EXPECT_EQ(BB->getTrailingDbgRecords(), nullptr); |
967 | } |
968 | { /* dbg.assign | DbgVariableRecord::Assign */ |
969 | I = Builder.CreateAlloca(Ty: Builder.getInt32Ty()); |
970 | I->setMetadata(KindID: LLVMContext::MD_DIAssignID, Node: DIAssignID::getDistinct(Context&: Ctx)); |
971 | // DbgAssign interface is slightly different - it always inserts after the |
972 | // linked instr. Check we can do this with no instruction to insert |
973 | // before. |
974 | DbgInstPtr VarXAssign = |
975 | DIB.insertDbgAssign(LinkedInstr: I, Val: I, SrcVar: VarX, ValExpr: DIB.createExpression(), Addr: I, |
976 | AddrExpr: DIB.createExpression(), DL: VarLoc); |
977 | I = Builder.CreateAlloca(Ty: Builder.getInt32Ty()); |
978 | ExpectOrder(VarXAssign, I->getIterator()); |
979 | EXPECT_EQ(BB->getTrailingDbgRecords(), nullptr); |
980 | } |
981 | |
982 | Builder.CreateRet(V: nullptr); |
983 | DIB.finalize(); |
984 | // Check the labels are not/are added to Bar's retainedNodes array |
985 | // (AlwaysPreserve). |
986 | EXPECT_EQ(find(BarSP->getRetainedNodes(), Label), |
987 | BarSP->getRetainedNodes().end()); |
988 | EXPECT_NE(find(BarSP->getRetainedNodes(), AlwaysPreserveLabel), |
989 | BarSP->getRetainedNodes().end()); |
990 | EXPECT_NE(find(BarSP->getRetainedNodes(), VarX), |
991 | BarSP->getRetainedNodes().end()); |
992 | EXPECT_NE(find(BarSP->getRetainedNodes(), VarY), |
993 | BarSP->getRetainedNodes().end()); |
994 | EXPECT_TRUE(verifyModule(*M)); |
995 | }; |
996 | |
997 | // Test in old-debug mode. |
998 | EXPECT_FALSE(M->IsNewDbgInfoFormat); |
999 | RunTest(); |
1000 | |
1001 | // Test in new-debug mode. |
1002 | // Reset the test then call convertToNewDbgValues to flip the flag |
1003 | // on the test's Module, Function and BasicBlock. |
1004 | TearDown(); |
1005 | SetUp(); |
1006 | M->convertToNewDbgValues(); |
1007 | EXPECT_TRUE(M->IsNewDbgInfoFormat); |
1008 | RunTest(); |
1009 | } |
1010 | |
1011 | TEST_F(IRBuilderTest, createArtificialSubprogram) { |
1012 | IRBuilder<> Builder(BB); |
1013 | DIBuilder DIB(*M); |
1014 | auto File = DIB.createFile(Filename: "main.c" , Directory: "/" ); |
1015 | auto CU = DIB.createCompileUnit(Lang: dwarf::DW_LANG_C, File, Producer: "clang" , |
1016 | /*isOptimized=*/true, /*Flags=*/"" , |
1017 | /*Runtime Version=*/RV: 0); |
1018 | auto Type = DIB.createSubroutineType(ParameterTypes: DIB.getOrCreateTypeArray(Elements: std::nullopt)); |
1019 | auto SP = DIB.createFunction( |
1020 | Scope: CU, Name: "foo" , /*LinkageName=*/"" , File, |
1021 | /*LineNo=*/1, Ty: Type, /*ScopeLine=*/2, Flags: DINode::FlagZero, |
1022 | SPFlags: DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized); |
1023 | EXPECT_TRUE(SP->isDistinct()); |
1024 | |
1025 | F->setSubprogram(SP); |
1026 | AllocaInst *I = Builder.CreateAlloca(Ty: Builder.getInt8Ty()); |
1027 | ReturnInst *R = Builder.CreateRetVoid(); |
1028 | I->setDebugLoc(DILocation::get(Context&: Ctx, Line: 3, Column: 2, Scope: SP)); |
1029 | R->setDebugLoc(DILocation::get(Context&: Ctx, Line: 4, Column: 2, Scope: SP)); |
1030 | DIB.finalize(); |
1031 | EXPECT_FALSE(verifyModule(*M)); |
1032 | |
1033 | Function *G = Function::Create(Ty: F->getFunctionType(), |
1034 | Linkage: Function::ExternalLinkage, N: "" , M: M.get()); |
1035 | BasicBlock *GBB = BasicBlock::Create(Context&: Ctx, Name: "" , Parent: G); |
1036 | Builder.SetInsertPoint(GBB); |
1037 | I->removeFromParent(); |
1038 | Builder.Insert(I); |
1039 | Builder.CreateRetVoid(); |
1040 | EXPECT_FALSE(verifyModule(*M)); |
1041 | |
1042 | DISubprogram *GSP = DIBuilder::createArtificialSubprogram(SP: F->getSubprogram()); |
1043 | EXPECT_EQ(SP->getFile(), GSP->getFile()); |
1044 | EXPECT_EQ(SP->getType(), GSP->getType()); |
1045 | EXPECT_EQ(SP->getLine(), GSP->getLine()); |
1046 | EXPECT_EQ(SP->getScopeLine(), GSP->getScopeLine()); |
1047 | EXPECT_TRUE(GSP->isDistinct()); |
1048 | |
1049 | G->setSubprogram(GSP); |
1050 | EXPECT_TRUE(verifyModule(*M)); |
1051 | |
1052 | auto *InlinedAtNode = |
1053 | DILocation::getDistinct(Context&: Ctx, Line: GSP->getScopeLine(), Column: 0, Scope: GSP); |
1054 | DebugLoc DL = I->getDebugLoc(); |
1055 | DenseMap<const MDNode *, MDNode *> IANodes; |
1056 | auto IA = DebugLoc::appendInlinedAt(DL, InlinedAt: InlinedAtNode, Ctx, Cache&: IANodes); |
1057 | auto NewDL = |
1058 | DILocation::get(Context&: Ctx, Line: DL.getLine(), Column: DL.getCol(), Scope: DL.getScope(), InlinedAt: IA); |
1059 | I->setDebugLoc(NewDL); |
1060 | EXPECT_FALSE(verifyModule(*M)); |
1061 | |
1062 | EXPECT_EQ("foo" , SP->getName()); |
1063 | EXPECT_EQ("foo" , GSP->getName()); |
1064 | EXPECT_FALSE(SP->isArtificial()); |
1065 | EXPECT_TRUE(GSP->isArtificial()); |
1066 | } |
1067 | |
1068 | // Check that we can add debug info to an existing DICompileUnit. |
1069 | TEST_F(IRBuilderTest, appendDebugInfo) { |
1070 | IRBuilder<> Builder(BB); |
1071 | Builder.CreateRetVoid(); |
1072 | EXPECT_FALSE(verifyModule(*M)); |
1073 | |
1074 | auto GetNames = [](DICompileUnit *CU) { |
1075 | SmallVector<StringRef> Names; |
1076 | for (auto *ET : CU->getEnumTypes()) |
1077 | Names.push_back(Elt: ET->getName()); |
1078 | for (auto *RT : CU->getRetainedTypes()) |
1079 | Names.push_back(Elt: RT->getName()); |
1080 | for (auto *GV : CU->getGlobalVariables()) |
1081 | Names.push_back(Elt: GV->getVariable()->getName()); |
1082 | for (auto *IE : CU->getImportedEntities()) |
1083 | Names.push_back(Elt: IE->getName()); |
1084 | for (auto *Node : CU->getMacros()) |
1085 | if (auto *MN = dyn_cast_or_null<DIMacro>(Val: Node)) |
1086 | Names.push_back(Elt: MN->getName()); |
1087 | return Names; |
1088 | }; |
1089 | |
1090 | DICompileUnit *CU; |
1091 | { |
1092 | DIBuilder DIB(*M); |
1093 | auto *File = DIB.createFile(Filename: "main.c" , Directory: "/" ); |
1094 | CU = DIB.createCompileUnit(Lang: dwarf::DW_LANG_C, File, Producer: "clang" , |
1095 | /*isOptimized=*/true, /*Flags=*/"" , |
1096 | /*Runtime Version=*/RV: 0); |
1097 | auto *ByteTy = DIB.createBasicType(Name: "byte0" , SizeInBits: 8, Encoding: dwarf::DW_ATE_signed); |
1098 | DIB.createEnumerationType(Scope: CU, Name: "ET0" , File, /*LineNo=*/LineNumber: 0, /*SizeInBits=*/8, |
1099 | /*AlignInBits=*/8, /*Elements=*/{}, UnderlyingType: ByteTy); |
1100 | DIB.retainType(T: ByteTy); |
1101 | DIB.createGlobalVariableExpression(Context: CU, Name: "GV0" , /*LinkageName=*/"" , File, |
1102 | /*LineNo=*/1, Ty: ByteTy, |
1103 | /*IsLocalToUnit=*/true); |
1104 | DIB.createImportedDeclaration(Context: CU, Decl: nullptr, File, /*LineNo=*/Line: 2, Name: "IM0" ); |
1105 | DIB.createMacro(Parent: nullptr, /*LineNo=*/Line: 0, MacroType: dwarf::DW_MACINFO_define, Name: "M0" ); |
1106 | DIB.finalize(); |
1107 | } |
1108 | EXPECT_FALSE(verifyModule(*M)); |
1109 | EXPECT_THAT(GetNames(CU), |
1110 | UnorderedElementsAre("ET0" , "byte0" , "GV0" , "IM0" , "M0" )); |
1111 | |
1112 | { |
1113 | DIBuilder DIB(*M, true, CU); |
1114 | auto *File = CU->getFile(); |
1115 | auto *ByteTy = DIB.createBasicType(Name: "byte1" , SizeInBits: 8, Encoding: dwarf::DW_ATE_signed); |
1116 | DIB.createEnumerationType(Scope: CU, Name: "ET1" , File, /*LineNo=*/LineNumber: 0, |
1117 | /*SizeInBits=*/8, /*AlignInBits=*/8, |
1118 | /*Elements=*/{}, UnderlyingType: ByteTy); |
1119 | DIB.retainType(T: ByteTy); |
1120 | DIB.createGlobalVariableExpression(Context: CU, Name: "GV1" , /*LinkageName=*/"" , File, |
1121 | /*LineNo=*/1, Ty: ByteTy, |
1122 | /*IsLocalToUnit=*/true); |
1123 | DIB.createImportedDeclaration(Context: CU, Decl: nullptr, File, /*LineNo=*/Line: 2, Name: "IM1" ); |
1124 | DIB.createMacro(Parent: nullptr, /*LineNo=*/Line: 0, MacroType: dwarf::DW_MACINFO_define, Name: "M1" ); |
1125 | DIB.finalize(); |
1126 | } |
1127 | EXPECT_FALSE(verifyModule(*M)); |
1128 | EXPECT_THAT(GetNames(CU), |
1129 | UnorderedElementsAre("ET0" , "byte0" , "GV0" , "IM0" , "M0" , "ET1" , |
1130 | "byte1" , "GV1" , "IM1" , "M1" )); |
1131 | } |
1132 | |
1133 | TEST_F(IRBuilderTest, InsertExtractElement) { |
1134 | IRBuilder<> Builder(BB); |
1135 | |
1136 | auto VecTy = FixedVectorType::get(ElementType: Builder.getInt64Ty(), NumElts: 4); |
1137 | auto Elt1 = Builder.getInt64(C: -1); |
1138 | auto Elt2 = Builder.getInt64(C: -2); |
1139 | Value *Vec = Builder.CreateInsertElement(VecTy, NewElt: Elt1, Idx: Builder.getInt8(C: 1)); |
1140 | Vec = Builder.CreateInsertElement(Vec, NewElt: Elt2, Idx: 2); |
1141 | auto X1 = Builder.CreateExtractElement(Vec, Idx: 1); |
1142 | auto X2 = Builder.CreateExtractElement(Vec, Idx: Builder.getInt32(C: 2)); |
1143 | EXPECT_EQ(Elt1, X1); |
1144 | EXPECT_EQ(Elt2, X2); |
1145 | } |
1146 | |
1147 | TEST_F(IRBuilderTest, CreateGlobalStringPtr) { |
1148 | IRBuilder<> Builder(BB); |
1149 | |
1150 | auto String1a = Builder.CreateGlobalStringPtr(Str: "TestString" , Name: "String1a" ); |
1151 | auto String1b = Builder.CreateGlobalStringPtr(Str: "TestString" , Name: "String1b" , AddressSpace: 0); |
1152 | auto String2 = Builder.CreateGlobalStringPtr(Str: "TestString" , Name: "String2" , AddressSpace: 1); |
1153 | auto String3 = Builder.CreateGlobalString(Str: "TestString" , Name: "String3" , AddressSpace: 2); |
1154 | |
1155 | EXPECT_TRUE(String1a->getType()->getPointerAddressSpace() == 0); |
1156 | EXPECT_TRUE(String1b->getType()->getPointerAddressSpace() == 0); |
1157 | EXPECT_TRUE(String2->getType()->getPointerAddressSpace() == 1); |
1158 | EXPECT_TRUE(String3->getType()->getPointerAddressSpace() == 2); |
1159 | } |
1160 | |
1161 | TEST_F(IRBuilderTest, DebugLoc) { |
1162 | auto CalleeTy = FunctionType::get(Result: Type::getVoidTy(C&: Ctx), |
1163 | /*isVarArg=*/false); |
1164 | auto Callee = |
1165 | Function::Create(Ty: CalleeTy, Linkage: Function::ExternalLinkage, N: "" , M: M.get()); |
1166 | |
1167 | DIBuilder DIB(*M); |
1168 | auto File = DIB.createFile(Filename: "tmp.cpp" , Directory: "/" ); |
1169 | auto CU = DIB.createCompileUnit(Lang: dwarf::DW_LANG_C_plus_plus_11, |
1170 | File: DIB.createFile(Filename: "tmp.cpp" , Directory: "/" ), Producer: "" , isOptimized: true, Flags: "" , |
1171 | RV: 0); |
1172 | auto SPType = |
1173 | DIB.createSubroutineType(ParameterTypes: DIB.getOrCreateTypeArray(Elements: std::nullopt)); |
1174 | auto SP = |
1175 | DIB.createFunction(Scope: CU, Name: "foo" , LinkageName: "foo" , File, LineNo: 1, Ty: SPType, ScopeLine: 1, Flags: DINode::FlagZero, |
1176 | SPFlags: DISubprogram::SPFlagDefinition); |
1177 | DebugLoc DL1 = DILocation::get(Context&: Ctx, Line: 2, Column: 0, Scope: SP); |
1178 | DebugLoc DL2 = DILocation::get(Context&: Ctx, Line: 3, Column: 0, Scope: SP); |
1179 | |
1180 | auto BB2 = BasicBlock::Create(Context&: Ctx, Name: "bb2" , Parent: F); |
1181 | auto Br = BranchInst::Create(IfTrue: BB2, InsertAtEnd: BB); |
1182 | Br->setDebugLoc(DL1); |
1183 | |
1184 | IRBuilder<> Builder(Ctx); |
1185 | Builder.SetInsertPoint(Br); |
1186 | EXPECT_EQ(DL1, Builder.getCurrentDebugLocation()); |
1187 | auto Call1 = Builder.CreateCall(Callee, Args: std::nullopt); |
1188 | EXPECT_EQ(DL1, Call1->getDebugLoc()); |
1189 | |
1190 | Call1->setDebugLoc(DL2); |
1191 | Builder.SetInsertPoint(TheBB: Call1->getParent(), IP: Call1->getIterator()); |
1192 | EXPECT_EQ(DL2, Builder.getCurrentDebugLocation()); |
1193 | auto Call2 = Builder.CreateCall(Callee, Args: std::nullopt); |
1194 | EXPECT_EQ(DL2, Call2->getDebugLoc()); |
1195 | |
1196 | DIB.finalize(); |
1197 | } |
1198 | |
1199 | TEST_F(IRBuilderTest, DIImportedEntity) { |
1200 | IRBuilder<> Builder(BB); |
1201 | DIBuilder DIB(*M); |
1202 | auto F = DIB.createFile(Filename: "F.CBL" , Directory: "/" ); |
1203 | auto CU = DIB.createCompileUnit(Lang: dwarf::DW_LANG_Cobol74, |
1204 | File: F, Producer: "llvm-cobol74" , |
1205 | isOptimized: true, Flags: "" , RV: 0); |
1206 | MDTuple *Elements = MDTuple::getDistinct(Context&: Ctx, MDs: std::nullopt); |
1207 | |
1208 | DIB.createImportedDeclaration(Context: CU, Decl: nullptr, File: F, Line: 1); |
1209 | DIB.createImportedDeclaration(Context: CU, Decl: nullptr, File: F, Line: 1); |
1210 | DIB.createImportedModule(Context: CU, NS: (DIImportedEntity *)nullptr, File: F, Line: 2); |
1211 | DIB.createImportedModule(Context: CU, NS: (DIImportedEntity *)nullptr, File: F, Line: 2); |
1212 | DIB.createImportedModule(Context: CU, NS: (DIImportedEntity *)nullptr, File: F, Line: 2, Elements); |
1213 | DIB.createImportedModule(Context: CU, NS: (DIImportedEntity *)nullptr, File: F, Line: 2, Elements); |
1214 | DIB.finalize(); |
1215 | EXPECT_TRUE(verifyModule(*M)); |
1216 | EXPECT_TRUE(CU->getImportedEntities().size() == 3); |
1217 | } |
1218 | |
1219 | // 0: #define M0 V0 <-- command line definition |
1220 | // 0: main.c <-- main file |
1221 | // 3: #define M1 V1 <-- M1 definition in main.c |
1222 | // 5: #include "file.h" <-- inclusion of file.h from main.c |
1223 | // 1: #define M2 <-- M2 definition in file.h with no value |
1224 | // 7: #undef M1 V1 <-- M1 un-definition in main.c |
1225 | TEST_F(IRBuilderTest, DIBuilderMacro) { |
1226 | IRBuilder<> Builder(BB); |
1227 | DIBuilder DIB(*M); |
1228 | auto File1 = DIB.createFile(Filename: "main.c" , Directory: "/" ); |
1229 | auto File2 = DIB.createFile(Filename: "file.h" , Directory: "/" ); |
1230 | auto CU = DIB.createCompileUnit( |
1231 | Lang: dwarf::DW_LANG_C, File: DIB.createFile(Filename: "main.c" , Directory: "/" ), Producer: "llvm-c" , isOptimized: true, Flags: "" , RV: 0); |
1232 | auto MDef0 = |
1233 | DIB.createMacro(Parent: nullptr, Line: 0, MacroType: dwarf::DW_MACINFO_define, Name: "M0" , Value: "V0" ); |
1234 | auto TMF1 = DIB.createTempMacroFile(Parent: nullptr, Line: 0, File: File1); |
1235 | auto MDef1 = DIB.createMacro(Parent: TMF1, Line: 3, MacroType: dwarf::DW_MACINFO_define, Name: "M1" , Value: "V1" ); |
1236 | auto TMF2 = DIB.createTempMacroFile(Parent: TMF1, Line: 5, File: File2); |
1237 | auto MDef2 = DIB.createMacro(Parent: TMF2, Line: 1, MacroType: dwarf::DW_MACINFO_define, Name: "M2" ); |
1238 | auto MUndef1 = DIB.createMacro(Parent: TMF1, Line: 7, MacroType: dwarf::DW_MACINFO_undef, Name: "M1" ); |
1239 | |
1240 | EXPECT_EQ(dwarf::DW_MACINFO_define, MDef1->getMacinfoType()); |
1241 | EXPECT_EQ(3u, MDef1->getLine()); |
1242 | EXPECT_EQ("M1" , MDef1->getName()); |
1243 | EXPECT_EQ("V1" , MDef1->getValue()); |
1244 | |
1245 | EXPECT_EQ(dwarf::DW_MACINFO_undef, MUndef1->getMacinfoType()); |
1246 | EXPECT_EQ(7u, MUndef1->getLine()); |
1247 | EXPECT_EQ("M1" , MUndef1->getName()); |
1248 | EXPECT_EQ("" , MUndef1->getValue()); |
1249 | |
1250 | EXPECT_EQ(dwarf::DW_MACINFO_start_file, TMF2->getMacinfoType()); |
1251 | EXPECT_EQ(5u, TMF2->getLine()); |
1252 | EXPECT_EQ(File2, TMF2->getFile()); |
1253 | |
1254 | DIB.finalize(); |
1255 | |
1256 | SmallVector<Metadata *, 4> Elements; |
1257 | Elements.push_back(Elt: MDef2); |
1258 | auto MF2 = DIMacroFile::get(Context&: Ctx, MIType: dwarf::DW_MACINFO_start_file, Line: 5, File: File2, |
1259 | Elements: DIB.getOrCreateMacroArray(Elements)); |
1260 | |
1261 | Elements.clear(); |
1262 | Elements.push_back(Elt: MDef1); |
1263 | Elements.push_back(Elt: MF2); |
1264 | Elements.push_back(Elt: MUndef1); |
1265 | auto MF1 = DIMacroFile::get(Context&: Ctx, MIType: dwarf::DW_MACINFO_start_file, Line: 0, File: File1, |
1266 | Elements: DIB.getOrCreateMacroArray(Elements)); |
1267 | |
1268 | Elements.clear(); |
1269 | Elements.push_back(Elt: MDef0); |
1270 | Elements.push_back(Elt: MF1); |
1271 | auto MN0 = MDTuple::get(Context&: Ctx, MDs: Elements); |
1272 | EXPECT_EQ(MN0, CU->getRawMacros()); |
1273 | |
1274 | Elements.clear(); |
1275 | Elements.push_back(Elt: MDef1); |
1276 | Elements.push_back(Elt: MF2); |
1277 | Elements.push_back(Elt: MUndef1); |
1278 | auto MN1 = MDTuple::get(Context&: Ctx, MDs: Elements); |
1279 | EXPECT_EQ(MN1, MF1->getRawElements()); |
1280 | |
1281 | Elements.clear(); |
1282 | Elements.push_back(Elt: MDef2); |
1283 | auto MN2 = MDTuple::get(Context&: Ctx, MDs: Elements); |
1284 | EXPECT_EQ(MN2, MF2->getRawElements()); |
1285 | EXPECT_TRUE(verifyModule(*M)); |
1286 | } |
1287 | |
1288 | TEST_F(IRBuilderTest, NoFolderNames) { |
1289 | IRBuilder<NoFolder> Builder(BB); |
1290 | auto *Add = |
1291 | Builder.CreateAdd(LHS: Builder.getInt32(C: 1), RHS: Builder.getInt32(C: 2), Name: "add" ); |
1292 | EXPECT_EQ(Add->getName(), "add" ); |
1293 | } |
1294 | |
1295 | TEST_F(IRBuilderTest, CTAD) { |
1296 | struct TestInserter : public IRBuilderDefaultInserter { |
1297 | TestInserter() = default; |
1298 | }; |
1299 | InstSimplifyFolder Folder(M->getDataLayout()); |
1300 | |
1301 | IRBuilder Builder1(Ctx, Folder, TestInserter()); |
1302 | static_assert(std::is_same_v<decltype(Builder1), |
1303 | IRBuilder<InstSimplifyFolder, TestInserter>>); |
1304 | IRBuilder Builder2(Ctx); |
1305 | static_assert(std::is_same_v<decltype(Builder2), IRBuilder<>>); |
1306 | IRBuilder Builder3(BB, Folder); |
1307 | static_assert( |
1308 | std::is_same_v<decltype(Builder3), IRBuilder<InstSimplifyFolder>>); |
1309 | IRBuilder Builder4(BB); |
1310 | static_assert(std::is_same_v<decltype(Builder4), IRBuilder<>>); |
1311 | // The block BB is empty, so don't test this one. |
1312 | // IRBuilder Builder5(BB->getTerminator()); |
1313 | // static_assert(std::is_same_v<decltype(Builder5), IRBuilder<>>); |
1314 | IRBuilder Builder6(BB, BB->end(), Folder); |
1315 | static_assert( |
1316 | std::is_same_v<decltype(Builder6), IRBuilder<InstSimplifyFolder>>); |
1317 | IRBuilder Builder7(BB, BB->end()); |
1318 | static_assert(std::is_same_v<decltype(Builder7), IRBuilder<>>); |
1319 | } |
1320 | } |
1321 | |