1 //===--------- VectorBuilderTest.cpp - VectorBuilder unit tests -----------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/IR/VectorBuilder.h"
10 #include "llvm/IR/Constants.h"
11 #include "llvm/IR/IRBuilder.h"
12 #include "llvm/IR/IntrinsicInst.h"
13 #include "llvm/IR/LLVMContext.h"
14 #include "llvm/IR/Module.h"
15 #include "gtest/gtest.h"
21 static unsigned VectorNumElements
= 8;
23 class VectorBuilderTest
: public testing::Test
{
27 VectorBuilderTest() : Context() {}
29 std::unique_ptr
<Module
> createBuilderModule(Function
*&Func
, BasicBlock
*&BB
,
30 Value
*&Mask
, Value
*&EVL
) {
31 auto Mod
= std::make_unique
<Module
>("TestModule", Context
);
32 auto *Int32Ty
= Type::getInt32Ty(Context
);
34 FixedVectorType::get(Type::getInt1Ty(Context
), VectorNumElements
);
36 FunctionType::get(Type::getVoidTy(Context
), {Mask8Ty
, Int32Ty
}, false);
38 Function::Create(VoidFuncTy
, GlobalValue::ExternalLinkage
, "bla", *Mod
);
39 Mask
= Func
->getArg(0);
40 EVL
= Func
->getArg(1);
41 BB
= BasicBlock::Create(Context
, "entry", Func
);
47 /// Check that creating binary arithmetic VP intrinsics works.
48 TEST_F(VectorBuilderTest
, TestCreateBinaryInstructions
) {
52 auto Mod
= createBuilderModule(F
, BB
, Mask
, EVL
);
54 IRBuilder
<> Builder(BB
);
55 VectorBuilder
VBuild(Builder
);
56 VBuild
.setMask(Mask
).setEVL(EVL
);
59 FixedVectorType::get(Type::getFloatTy(Context
), VectorNumElements
);
61 FixedVectorType::get(Type::getInt32Ty(Context
), VectorNumElements
);
63 #define HANDLE_BINARY_INST(NUM, OPCODE, INSTCLASS) \
65 auto VPID = VPIntrinsic::getForOpcode(Instruction::OPCODE); \
66 bool IsFP = (#INSTCLASS)[0] == 'F'; \
67 auto *ValueTy = IsFP ? FloatVecTy : IntVecTy; \
68 Value *Op = PoisonValue::get(ValueTy); \
69 auto *I = VBuild.createVectorInstruction(Instruction::OPCODE, ValueTy, \
71 ASSERT_TRUE(isa<VPIntrinsic>(I)); \
72 auto *VPIntrin = cast<VPIntrinsic>(I); \
73 ASSERT_EQ(VPIntrin->getIntrinsicID(), VPID); \
74 ASSERT_EQ(VPIntrin->getMaskParam(), Mask); \
75 ASSERT_EQ(VPIntrin->getVectorLengthParam(), EVL); \
77 #include "llvm/IR/Instruction.def"
80 static bool isAllTrueMask(Value
*Val
, unsigned NumElements
) {
81 auto *ConstMask
= dyn_cast
<Constant
>(Val
);
86 if (!ConstMask
->isAllOnesValue())
90 auto *MaskVecTy
= cast
<FixedVectorType
>(ConstMask
->getType());
91 if (MaskVecTy
->getNumElements() != NumElements
)
94 return MaskVecTy
->getElementType()->isIntegerTy(1);
97 /// Check that creating binary arithmetic VP intrinsics works.
98 TEST_F(VectorBuilderTest
, TestCreateBinaryInstructions_FixedVector_NoMask
) {
102 auto Mod
= createBuilderModule(F
, BB
, Mask
, EVL
);
104 IRBuilder
<> Builder(BB
);
105 VectorBuilder
VBuild(Builder
);
106 VBuild
.setEVL(EVL
).setStaticVL(VectorNumElements
);
109 FixedVectorType::get(Type::getFloatTy(Context
), VectorNumElements
);
111 FixedVectorType::get(Type::getInt32Ty(Context
), VectorNumElements
);
113 #define HANDLE_BINARY_INST(NUM, OPCODE, INSTCLASS) \
115 auto VPID = VPIntrinsic::getForOpcode(Instruction::OPCODE); \
116 bool IsFP = (#INSTCLASS)[0] == 'F'; \
117 Type *ValueTy = IsFP ? FloatVecTy : IntVecTy; \
118 Value *Op = PoisonValue::get(ValueTy); \
119 auto *I = VBuild.createVectorInstruction(Instruction::OPCODE, ValueTy, \
121 ASSERT_TRUE(isa<VPIntrinsic>(I)); \
122 auto *VPIntrin = cast<VPIntrinsic>(I); \
123 ASSERT_EQ(VPIntrin->getIntrinsicID(), VPID); \
124 ASSERT_TRUE(isAllTrueMask(VPIntrin->getMaskParam(), VectorNumElements)); \
125 ASSERT_EQ(VPIntrin->getVectorLengthParam(), EVL); \
127 #include "llvm/IR/Instruction.def"
130 static bool isLegalConstEVL(Value
*Val
, unsigned ExpectedEVL
) {
131 auto *ConstEVL
= dyn_cast
<ConstantInt
>(Val
);
136 if (ConstEVL
->getZExtValue() != ExpectedEVL
)
140 return ConstEVL
->getType()->isIntegerTy(32);
143 /// Check that creating binary arithmetic VP intrinsics works.
144 TEST_F(VectorBuilderTest
, TestCreateBinaryInstructions_FixedVector_NoEVL
) {
148 auto Mod
= createBuilderModule(F
, BB
, Mask
, EVL
);
150 IRBuilder
<> Builder(BB
);
151 VectorBuilder
VBuild(Builder
);
152 VBuild
.setMask(Mask
).setStaticVL(VectorNumElements
);
155 FixedVectorType::get(Type::getFloatTy(Context
), VectorNumElements
);
157 FixedVectorType::get(Type::getInt32Ty(Context
), VectorNumElements
);
159 #define HANDLE_BINARY_INST(NUM, OPCODE, INSTCLASS) \
161 auto VPID = VPIntrinsic::getForOpcode(Instruction::OPCODE); \
162 bool IsFP = (#INSTCLASS)[0] == 'F'; \
163 Type *ValueTy = IsFP ? FloatVecTy : IntVecTy; \
164 Value *Op = PoisonValue::get(ValueTy); \
165 auto *I = VBuild.createVectorInstruction(Instruction::OPCODE, ValueTy, \
167 ASSERT_TRUE(isa<VPIntrinsic>(I)); \
168 auto *VPIntrin = cast<VPIntrinsic>(I); \
169 ASSERT_EQ(VPIntrin->getIntrinsicID(), VPID); \
170 ASSERT_EQ(VPIntrin->getMaskParam(), Mask); \
172 isLegalConstEVL(VPIntrin->getVectorLengthParam(), VectorNumElements)); \
174 #include "llvm/IR/Instruction.def"
177 /// Check that creating binary arithmetic VP intrinsics works.
178 TEST_F(VectorBuilderTest
,
179 TestCreateBinaryInstructions_FixedVector_NoMask_NoEVL
) {
183 auto Mod
= createBuilderModule(F
, BB
, Mask
, EVL
);
185 IRBuilder
<> Builder(BB
);
186 VectorBuilder
VBuild(Builder
);
187 VBuild
.setStaticVL(VectorNumElements
);
190 FixedVectorType::get(Type::getFloatTy(Context
), VectorNumElements
);
192 FixedVectorType::get(Type::getInt32Ty(Context
), VectorNumElements
);
194 #define HANDLE_BINARY_INST(NUM, OPCODE, INSTCLASS) \
196 auto VPID = VPIntrinsic::getForOpcode(Instruction::OPCODE); \
197 bool IsFP = (#INSTCLASS)[0] == 'F'; \
198 Type *ValueTy = IsFP ? FloatVecTy : IntVecTy; \
199 Value *Op = PoisonValue::get(ValueTy); \
200 auto *I = VBuild.createVectorInstruction(Instruction::OPCODE, ValueTy, \
202 ASSERT_TRUE(isa<VPIntrinsic>(I)); \
203 auto *VPIntrin = cast<VPIntrinsic>(I); \
204 ASSERT_EQ(VPIntrin->getIntrinsicID(), VPID); \
205 ASSERT_TRUE(isAllTrueMask(VPIntrin->getMaskParam(), VectorNumElements)); \
207 isLegalConstEVL(VPIntrin->getVectorLengthParam(), VectorNumElements)); \
209 #include "llvm/IR/Instruction.def"
211 /// Check that creating vp.load/vp.store works.
212 TEST_F(VectorBuilderTest
, TestCreateLoadStore
) {
216 auto Mod
= createBuilderModule(F
, BB
, Mask
, EVL
);
218 IRBuilder
<> Builder(BB
);
219 VectorBuilder
VBuild(Builder
);
220 VBuild
.setMask(Mask
).setEVL(EVL
);
223 FixedVectorType::get(Type::getFloatTy(Context
), VectorNumElements
);
225 Value
*FloatVecPtr
= PoisonValue::get(Builder
.getPtrTy(0));
226 Value
*FloatVec
= PoisonValue::get(FloatVecTy
);
229 auto LoadVPID
= VPIntrinsic::getForOpcode(Instruction::Load
);
230 auto *LoadIntrin
= VBuild
.createVectorInstruction(Instruction::Load
,
231 FloatVecTy
, {FloatVecPtr
});
232 ASSERT_TRUE(isa
<VPIntrinsic
>(LoadIntrin
));
233 auto *VPLoad
= cast
<VPIntrinsic
>(LoadIntrin
);
234 ASSERT_EQ(VPLoad
->getIntrinsicID(), LoadVPID
);
235 ASSERT_EQ(VPLoad
->getMemoryPointerParam(), FloatVecPtr
);
238 auto *VoidTy
= Builder
.getVoidTy();
239 auto StoreVPID
= VPIntrinsic::getForOpcode(Instruction::Store
);
240 auto *StoreIntrin
= VBuild
.createVectorInstruction(Instruction::Store
, VoidTy
,
241 {FloatVec
, FloatVecPtr
});
242 ASSERT_TRUE(isa
<VPIntrinsic
>(LoadIntrin
));
243 auto *VPStore
= cast
<VPIntrinsic
>(StoreIntrin
);
244 ASSERT_EQ(VPStore
->getIntrinsicID(), StoreVPID
);
245 ASSERT_EQ(VPStore
->getMemoryPointerParam(), FloatVecPtr
);
246 ASSERT_EQ(VPStore
->getMemoryDataParam(), FloatVec
);
249 /// Check that the SilentlyReturnNone error handling mode works.
250 TEST_F(VectorBuilderTest
, TestFail_SilentlyReturnNone
) {
254 auto Mod
= createBuilderModule(F
, BB
, Mask
, EVL
);
256 IRBuilder
<> Builder(BB
);
257 auto *VoidTy
= Builder
.getVoidTy();
258 VectorBuilder
VBuild(Builder
, VectorBuilder::Behavior::SilentlyReturnNone
);
259 VBuild
.setMask(Mask
).setEVL(EVL
);
260 auto *Val
= VBuild
.createVectorInstruction(Instruction::Br
, VoidTy
, {});
261 ASSERT_EQ(Val
, nullptr);
264 /// Check that the ReportAndFail error handling mode aborts as advertised.
265 TEST_F(VectorBuilderTest
, TestFail_ReportAndAbort
) {
269 auto Mod
= createBuilderModule(F
, BB
, Mask
, EVL
);
271 IRBuilder
<> Builder(BB
);
272 auto *VoidTy
= Builder
.getVoidTy();
273 VectorBuilder
VBuild(Builder
, VectorBuilder::Behavior::ReportAndAbort
);
274 VBuild
.setMask(Mask
).setEVL(EVL
);
275 ASSERT_DEATH({ VBuild
.createVectorInstruction(Instruction::Br
, VoidTy
, {}); },
276 "No VPIntrinsic for this opcode");
279 } // end anonymous namespace