1//===--------- VectorBuilderTest.cpp - VectorBuilder 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/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"
16
17using namespace llvm;
18
19namespace {
20
21static unsigned VectorNumElements = 8;
22
23class VectorBuilderTest : public testing::Test {
24protected:
25 LLVMContext Context;
26
27 VectorBuilderTest() : Context() {}
28
29 std::unique_ptr<Module> createBuilderModule(Function *&Func, BasicBlock *&BB,
30 Value *&Mask, Value *&EVL) {
31 auto Mod = std::make_unique<Module>(args: "TestModule", args&: Context);
32 auto *Int32Ty = Type::getInt32Ty(C&: Context);
33 auto *Mask8Ty =
34 FixedVectorType::get(ElementType: Type::getInt1Ty(C&: Context), NumElts: VectorNumElements);
35 auto *VoidFuncTy =
36 FunctionType::get(Result: Type::getVoidTy(C&: Context), Params: {Mask8Ty, Int32Ty}, isVarArg: false);
37 Func =
38 Function::Create(Ty: VoidFuncTy, Linkage: GlobalValue::ExternalLinkage, N: "bla", M&: *Mod);
39 Mask = Func->getArg(i: 0);
40 EVL = Func->getArg(i: 1);
41 BB = BasicBlock::Create(Context, Name: "entry", Parent: Func);
42
43 return Mod;
44 }
45};
46
47/// Check that creating binary arithmetic VP intrinsics works.
48TEST_F(VectorBuilderTest, TestCreateBinaryInstructions) {
49 Function *F;
50 BasicBlock *BB;
51 Value *Mask, *EVL;
52 auto Mod = createBuilderModule(Func&: F, BB, Mask, EVL);
53
54 IRBuilder<> Builder(BB);
55 VectorBuilder VBuild(Builder);
56 VBuild.setMask(Mask).setEVL(EVL);
57
58 auto *FloatVecTy =
59 FixedVectorType::get(ElementType: Type::getFloatTy(C&: Context), NumElts: VectorNumElements);
60 auto *IntVecTy =
61 FixedVectorType::get(ElementType: Type::getInt32Ty(C&: Context), NumElts: VectorNumElements);
62
63#define HANDLE_BINARY_INST(NUM, OPCODE, INSTCLASS) \
64 { \
65 auto VPID = VPIntrinsic::getForOpcode(Instruction::OPCODE); \
66 bool IsFP = (#INSTCLASS)[0] == 'F'; \
67 auto *ValueTy = IsFP ? FloatVecTy : IntVecTy; \
68 Value *Op = UndefValue::get(ValueTy); \
69 auto *I = VBuild.createVectorInstruction(Instruction::OPCODE, ValueTy, \
70 {Op, Op}); \
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); \
76 }
77#include "llvm/IR/Instruction.def"
78}
79
80static bool isAllTrueMask(Value *Val, unsigned NumElements) {
81 auto *ConstMask = dyn_cast<Constant>(Val);
82 if (!ConstMask)
83 return false;
84
85 // Structure check.
86 if (!ConstMask->isAllOnesValue())
87 return false;
88
89 // Type check.
90 auto *MaskVecTy = cast<FixedVectorType>(Val: ConstMask->getType());
91 if (MaskVecTy->getNumElements() != NumElements)
92 return false;
93
94 return MaskVecTy->getElementType()->isIntegerTy(Bitwidth: 1);
95}
96
97/// Check that creating binary arithmetic VP intrinsics works.
98TEST_F(VectorBuilderTest, TestCreateBinaryInstructions_FixedVector_NoMask) {
99 Function *F;
100 BasicBlock *BB;
101 Value *Mask, *EVL;
102 auto Mod = createBuilderModule(Func&: F, BB, Mask, EVL);
103
104 IRBuilder<> Builder(BB);
105 VectorBuilder VBuild(Builder);
106 VBuild.setEVL(EVL).setStaticVL(VectorNumElements);
107
108 auto *FloatVecTy =
109 FixedVectorType::get(ElementType: Type::getFloatTy(C&: Context), NumElts: VectorNumElements);
110 auto *IntVecTy =
111 FixedVectorType::get(ElementType: Type::getInt32Ty(C&: Context), NumElts: VectorNumElements);
112
113#define HANDLE_BINARY_INST(NUM, OPCODE, INSTCLASS) \
114 { \
115 auto VPID = VPIntrinsic::getForOpcode(Instruction::OPCODE); \
116 bool IsFP = (#INSTCLASS)[0] == 'F'; \
117 Type *ValueTy = IsFP ? FloatVecTy : IntVecTy; \
118 Value *Op = UndefValue::get(ValueTy); \
119 auto *I = VBuild.createVectorInstruction(Instruction::OPCODE, ValueTy, \
120 {Op, Op}); \
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); \
126 }
127#include "llvm/IR/Instruction.def"
128}
129
130static bool isLegalConstEVL(Value *Val, unsigned ExpectedEVL) {
131 auto *ConstEVL = dyn_cast<ConstantInt>(Val);
132 if (!ConstEVL)
133 return false;
134
135 // Value check.
136 if (ConstEVL->getZExtValue() != ExpectedEVL)
137 return false;
138
139 // Type check.
140 return ConstEVL->getType()->isIntegerTy(Bitwidth: 32);
141}
142
143/// Check that creating binary arithmetic VP intrinsics works.
144TEST_F(VectorBuilderTest, TestCreateBinaryInstructions_FixedVector_NoEVL) {
145 Function *F;
146 BasicBlock *BB;
147 Value *Mask, *EVL;
148 auto Mod = createBuilderModule(Func&: F, BB, Mask, EVL);
149
150 IRBuilder<> Builder(BB);
151 VectorBuilder VBuild(Builder);
152 VBuild.setMask(Mask).setStaticVL(VectorNumElements);
153
154 auto *FloatVecTy =
155 FixedVectorType::get(ElementType: Type::getFloatTy(C&: Context), NumElts: VectorNumElements);
156 auto *IntVecTy =
157 FixedVectorType::get(ElementType: Type::getInt32Ty(C&: Context), NumElts: VectorNumElements);
158
159#define HANDLE_BINARY_INST(NUM, OPCODE, INSTCLASS) \
160 { \
161 auto VPID = VPIntrinsic::getForOpcode(Instruction::OPCODE); \
162 bool IsFP = (#INSTCLASS)[0] == 'F'; \
163 Type *ValueTy = IsFP ? FloatVecTy : IntVecTy; \
164 Value *Op = UndefValue::get(ValueTy); \
165 auto *I = VBuild.createVectorInstruction(Instruction::OPCODE, ValueTy, \
166 {Op, Op}); \
167 ASSERT_TRUE(isa<VPIntrinsic>(I)); \
168 auto *VPIntrin = cast<VPIntrinsic>(I); \
169 ASSERT_EQ(VPIntrin->getIntrinsicID(), VPID); \
170 ASSERT_EQ(VPIntrin->getMaskParam(), Mask); \
171 ASSERT_TRUE( \
172 isLegalConstEVL(VPIntrin->getVectorLengthParam(), VectorNumElements)); \
173 }
174#include "llvm/IR/Instruction.def"
175}
176
177/// Check that creating binary arithmetic VP intrinsics works.
178TEST_F(VectorBuilderTest,
179 TestCreateBinaryInstructions_FixedVector_NoMask_NoEVL) {
180 Function *F;
181 BasicBlock *BB;
182 Value *Mask, *EVL;
183 auto Mod = createBuilderModule(Func&: F, BB, Mask, EVL);
184
185 IRBuilder<> Builder(BB);
186 VectorBuilder VBuild(Builder);
187 VBuild.setStaticVL(VectorNumElements);
188
189 auto *FloatVecTy =
190 FixedVectorType::get(ElementType: Type::getFloatTy(C&: Context), NumElts: VectorNumElements);
191 auto *IntVecTy =
192 FixedVectorType::get(ElementType: Type::getInt32Ty(C&: Context), NumElts: VectorNumElements);
193
194#define HANDLE_BINARY_INST(NUM, OPCODE, INSTCLASS) \
195 { \
196 auto VPID = VPIntrinsic::getForOpcode(Instruction::OPCODE); \
197 bool IsFP = (#INSTCLASS)[0] == 'F'; \
198 Type *ValueTy = IsFP ? FloatVecTy : IntVecTy; \
199 Value *Op = UndefValue::get(ValueTy); \
200 auto *I = VBuild.createVectorInstruction(Instruction::OPCODE, ValueTy, \
201 {Op, Op}); \
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)); \
206 ASSERT_TRUE( \
207 isLegalConstEVL(VPIntrin->getVectorLengthParam(), VectorNumElements)); \
208 }
209#include "llvm/IR/Instruction.def"
210}
211/// Check that creating vp.load/vp.store works.
212TEST_F(VectorBuilderTest, TestCreateLoadStore) {
213 Function *F;
214 BasicBlock *BB;
215 Value *Mask, *EVL;
216 auto Mod = createBuilderModule(Func&: F, BB, Mask, EVL);
217
218 IRBuilder<> Builder(BB);
219 VectorBuilder VBuild(Builder);
220 VBuild.setMask(Mask).setEVL(EVL);
221
222 auto *FloatVecTy =
223 FixedVectorType::get(ElementType: Type::getFloatTy(C&: Context), NumElts: VectorNumElements);
224
225 Value *FloatVecPtr = UndefValue::get(T: Builder.getPtrTy(AddrSpace: 0));
226 Value *FloatVec = UndefValue::get(T: FloatVecTy);
227
228 // vp.load
229 auto LoadVPID = VPIntrinsic::getForOpcode(OC: Instruction::Load);
230 auto *LoadIntrin = VBuild.createVectorInstruction(Opcode: Instruction::Load,
231 ReturnTy: FloatVecTy, VecOpArray: {FloatVecPtr});
232 ASSERT_TRUE(isa<VPIntrinsic>(LoadIntrin));
233 auto *VPLoad = cast<VPIntrinsic>(Val: LoadIntrin);
234 ASSERT_EQ(VPLoad->getIntrinsicID(), LoadVPID);
235 ASSERT_EQ(VPLoad->getMemoryPointerParam(), FloatVecPtr);
236
237 // vp.store
238 auto *VoidTy = Builder.getVoidTy();
239 auto StoreVPID = VPIntrinsic::getForOpcode(OC: Instruction::Store);
240 auto *StoreIntrin = VBuild.createVectorInstruction(Opcode: Instruction::Store, ReturnTy: VoidTy,
241 VecOpArray: {FloatVec, FloatVecPtr});
242 ASSERT_TRUE(isa<VPIntrinsic>(LoadIntrin));
243 auto *VPStore = cast<VPIntrinsic>(Val: StoreIntrin);
244 ASSERT_EQ(VPStore->getIntrinsicID(), StoreVPID);
245 ASSERT_EQ(VPStore->getMemoryPointerParam(), FloatVecPtr);
246 ASSERT_EQ(VPStore->getMemoryDataParam(), FloatVec);
247}
248
249/// Check that the SilentlyReturnNone error handling mode works.
250TEST_F(VectorBuilderTest, TestFail_SilentlyReturnNone) {
251 Function *F;
252 BasicBlock *BB;
253 Value *Mask, *EVL;
254 auto Mod = createBuilderModule(Func&: F, BB, Mask, EVL);
255
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(Opcode: Instruction::Br, ReturnTy: VoidTy, VecOpArray: {});
261 ASSERT_EQ(Val, nullptr);
262}
263
264/// Check that the ReportAndFail error handling mode aborts as advertised.
265TEST_F(VectorBuilderTest, TestFail_ReportAndAbort) {
266 Function *F;
267 BasicBlock *BB;
268 Value *Mask, *EVL;
269 auto Mod = createBuilderModule(Func&: F, BB, Mask, EVL);
270
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");
277}
278
279} // end anonymous namespace
280

source code of llvm/unittests/IR/VectorBuilderTest.cpp