[libc] Deprecate LLVM_ENABLE_PROJECTS in favor of LLVM_ENABLE_RUNTIMES. (#117265)
[llvm-project.git] / llvm / unittests / IR / VectorBuilderTest.cpp
blobe01378a2755f03e582e2f76e3b03e756837ebceb
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 = PoisonValue::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 = PoisonValue::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 = PoisonValue::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 = PoisonValue::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);
225 Value *FloatVecPtr = PoisonValue::get(Builder.getPtrTy(0));
226 Value *FloatVec = PoisonValue::get(FloatVecTy);
228 // vp.load
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);
237 // vp.store
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) {
251 Function *F;
252 BasicBlock *BB;
253 Value *Mask, *EVL;
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) {
266 Function *F;
267 BasicBlock *BB;
268 Value *Mask, *EVL;
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