[docs] Fix build-docs.sh
[llvm-project.git] / llvm / unittests / IR / VectorBuilderTest.cpp
blob82ce045ab4b05328a7f620fe74b45aad5333e362
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 //===----------------------------------------------------------------------===//
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"
17 using namespace llvm;
19 namespace {
21 static unsigned VectorNumElements = 8;
23 class VectorBuilderTest : public testing::Test {
24 protected:
25 LLVMContext Context;
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);
33 auto *Mask8Ty =
34 FixedVectorType::get(Type::getInt1Ty(Context), VectorNumElements);
35 auto *VoidFuncTy =
36 FunctionType::get(Type::getVoidTy(Context), {Mask8Ty, Int32Ty}, false);
37 Func =
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);
43 return Mod;
47 /// Check that creating binary arithmetic VP intrinsics works.
48 TEST_F(VectorBuilderTest, TestCreateBinaryInstructions) {
49 Function *F;
50 BasicBlock *BB;
51 Value *Mask, *EVL;
52 auto Mod = createBuilderModule(F, BB, Mask, EVL);
54 IRBuilder<> Builder(BB);
55 VectorBuilder VBuild(Builder);
56 VBuild.setMask(Mask).setEVL(EVL);
58 auto *FloatVecTy =
59 FixedVectorType::get(Type::getFloatTy(Context), VectorNumElements);
60 auto *IntVecTy =
61 FixedVectorType::get(Type::getInt32Ty(Context), VectorNumElements);
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); \
77 #include "llvm/IR/Instruction.def"
80 static bool isAllTrueMask(Value *Val, unsigned NumElements) {
81 auto *ConstMask = dyn_cast<Constant>(Val);
82 if (!ConstMask)
83 return false;
85 // Structure check.
86 if (!ConstMask->isAllOnesValue())
87 return false;
89 // Type check.
90 auto *MaskVecTy = cast<FixedVectorType>(ConstMask->getType());
91 if (MaskVecTy->getNumElements() != NumElements)
92 return false;
94 return MaskVecTy->getElementType()->isIntegerTy(1);
97 /// Check that creating binary arithmetic VP intrinsics works.
98 TEST_F(VectorBuilderTest, TestCreateBinaryInstructions_FixedVector_NoMask) {
99 Function *F;
100 BasicBlock *BB;
101 Value *Mask, *EVL;
102 auto Mod = createBuilderModule(F, BB, Mask, EVL);
104 IRBuilder<> Builder(BB);
105 VectorBuilder VBuild(Builder);
106 VBuild.setEVL(EVL).setStaticVL(VectorNumElements);
108 auto *FloatVecTy =
109 FixedVectorType::get(Type::getFloatTy(Context), VectorNumElements);
110 auto *IntVecTy =
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 = 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); \
127 #include "llvm/IR/Instruction.def"
130 static bool isLegalConstEVL(Value *Val, unsigned ExpectedEVL) {
131 auto *ConstEVL = dyn_cast<ConstantInt>(Val);
132 if (!ConstEVL)
133 return false;
135 // Value check.
136 if (ConstEVL->getZExtValue() != ExpectedEVL)
137 return false;
139 // Type check.
140 return ConstEVL->getType()->isIntegerTy(32);
143 /// Check that creating binary arithmetic VP intrinsics works.
144 TEST_F(VectorBuilderTest, TestCreateBinaryInstructions_FixedVector_NoEVL) {
145 Function *F;
146 BasicBlock *BB;
147 Value *Mask, *EVL;
148 auto Mod = createBuilderModule(F, BB, Mask, EVL);
150 IRBuilder<> Builder(BB);
151 VectorBuilder VBuild(Builder);
152 VBuild.setMask(Mask).setStaticVL(VectorNumElements);
154 auto *FloatVecTy =
155 FixedVectorType::get(Type::getFloatTy(Context), VectorNumElements);
156 auto *IntVecTy =
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 = 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)); \
174 #include "llvm/IR/Instruction.def"
177 /// Check that creating binary arithmetic VP intrinsics works.
178 TEST_F(VectorBuilderTest,
179 TestCreateBinaryInstructions_FixedVector_NoMask_NoEVL) {
180 Function *F;
181 BasicBlock *BB;
182 Value *Mask, *EVL;
183 auto Mod = createBuilderModule(F, BB, Mask, EVL);
185 IRBuilder<> Builder(BB);
186 VectorBuilder VBuild(Builder);
187 VBuild.setStaticVL(VectorNumElements);
189 auto *FloatVecTy =
190 FixedVectorType::get(Type::getFloatTy(Context), VectorNumElements);
191 auto *IntVecTy =
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 = 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)); \
209 #include "llvm/IR/Instruction.def"
211 /// Check that creating vp.load/vp.store works.
212 TEST_F(VectorBuilderTest, TestCreateLoadStore) {
213 Function *F;
214 BasicBlock *BB;
215 Value *Mask, *EVL;
216 auto Mod = createBuilderModule(F, BB, Mask, EVL);
218 IRBuilder<> Builder(BB);
219 VectorBuilder VBuild(Builder);
220 VBuild.setMask(Mask).setEVL(EVL);
222 auto *FloatVecTy =
223 FixedVectorType::get(Type::getFloatTy(Context), VectorNumElements);
224 auto *FloatVecPtrTy = FloatVecTy->getPointerTo();
226 Value *FloatVecPtr = UndefValue::get(FloatVecPtrTy);
227 Value *FloatVec = UndefValue::get(FloatVecTy);
229 // vp.load
230 auto LoadVPID = VPIntrinsic::getForOpcode(Instruction::Load);
231 auto *LoadIntrin = VBuild.createVectorInstruction(Instruction::Load,
232 FloatVecTy, {FloatVecPtr});
233 ASSERT_TRUE(isa<VPIntrinsic>(LoadIntrin));
234 auto *VPLoad = cast<VPIntrinsic>(LoadIntrin);
235 ASSERT_EQ(VPLoad->getIntrinsicID(), LoadVPID);
236 ASSERT_EQ(VPLoad->getMemoryPointerParam(), FloatVecPtr);
238 // vp.store
239 auto *VoidTy = Builder.getVoidTy();
240 auto StoreVPID = VPIntrinsic::getForOpcode(Instruction::Store);
241 auto *StoreIntrin = VBuild.createVectorInstruction(Instruction::Store, VoidTy,
242 {FloatVec, FloatVecPtr});
243 ASSERT_TRUE(isa<VPIntrinsic>(LoadIntrin));
244 auto *VPStore = cast<VPIntrinsic>(StoreIntrin);
245 ASSERT_EQ(VPStore->getIntrinsicID(), StoreVPID);
246 ASSERT_EQ(VPStore->getMemoryPointerParam(), FloatVecPtr);
247 ASSERT_EQ(VPStore->getMemoryDataParam(), FloatVec);
250 /// Check that the SilentlyReturnNone error handling mode works.
251 TEST_F(VectorBuilderTest, TestFail_SilentlyReturnNone) {
252 Function *F;
253 BasicBlock *BB;
254 Value *Mask, *EVL;
255 auto Mod = createBuilderModule(F, BB, Mask, EVL);
257 IRBuilder<> Builder(BB);
258 auto *VoidTy = Builder.getVoidTy();
259 VectorBuilder VBuild(Builder, VectorBuilder::Behavior::SilentlyReturnNone);
260 VBuild.setMask(Mask).setEVL(EVL);
261 auto *Val = VBuild.createVectorInstruction(Instruction::Br, VoidTy, {});
262 ASSERT_EQ(Val, nullptr);
265 /// Check that the ReportAndFail error handling mode aborts as advertised.
266 TEST_F(VectorBuilderTest, TestFail_ReportAndAbort) {
267 Function *F;
268 BasicBlock *BB;
269 Value *Mask, *EVL;
270 auto Mod = createBuilderModule(F, BB, Mask, EVL);
272 IRBuilder<> Builder(BB);
273 auto *VoidTy = Builder.getVoidTy();
274 VectorBuilder VBuild(Builder, VectorBuilder::Behavior::ReportAndAbort);
275 VBuild.setMask(Mask).setEVL(EVL);
276 ASSERT_DEATH({ VBuild.createVectorInstruction(Instruction::Br, VoidTy, {}); },
277 "No VPIntrinsic for this opcode");
280 } // end anonymous namespace