[llvm-shlib] Fix the version naming style of libLLVM for Windows (#85710)
[llvm-project.git] / llvm / unittests / IR / VPIntrinsicTest.cpp
blob7a9d91cc76b34a84219f4e8a9b8a9b6d17aa0107
1 //===- VPIntrinsicTest.cpp - VPIntrinsic 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/ADT/SmallVector.h"
10 #include "llvm/AsmParser/Parser.h"
11 #include "llvm/CodeGen/ISDOpcodes.h"
12 #include "llvm/IR/Constants.h"
13 #include "llvm/IR/IRBuilder.h"
14 #include "llvm/IR/IntrinsicInst.h"
15 #include "llvm/IR/LLVMContext.h"
16 #include "llvm/IR/Module.h"
17 #include "llvm/IR/Verifier.h"
18 #include "llvm/Support/SourceMgr.h"
19 #include "gtest/gtest.h"
20 #include <optional>
21 #include <sstream>
23 using namespace llvm;
25 namespace {
27 static const char *ReductionIntOpcodes[] = {
28 "add", "mul", "and", "or", "xor", "smin", "smax", "umin", "umax"};
30 static const char *ReductionFPOpcodes[] = {"fadd", "fmul", "fmin", "fmax"};
32 class VPIntrinsicTest : public testing::Test {
33 protected:
34 LLVMContext Context;
36 VPIntrinsicTest() : Context() {}
38 LLVMContext C;
39 SMDiagnostic Err;
41 std::unique_ptr<Module> createVPDeclarationModule() {
42 const char *BinaryIntOpcodes[] = {"add", "sub", "mul", "sdiv", "srem",
43 "udiv", "urem", "and", "xor", "or",
44 "ashr", "lshr", "shl", "smin", "smax",
45 "umin", "umax"};
46 std::stringstream Str;
47 for (const char *BinaryIntOpcode : BinaryIntOpcodes)
48 Str << " declare <8 x i32> @llvm.vp." << BinaryIntOpcode
49 << ".v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) ";
51 const char *BinaryFPOpcodes[] = {"fadd", "fsub", "fmul", "fdiv",
52 "frem", "minnum", "maxnum", "minimum",
53 "maximum", "copysign"};
54 for (const char *BinaryFPOpcode : BinaryFPOpcodes)
55 Str << " declare <8 x float> @llvm.vp." << BinaryFPOpcode
56 << ".v8f32(<8 x float>, <8 x float>, <8 x i1>, i32) ";
58 Str << " declare <8 x float> @llvm.vp.floor.v8f32(<8 x float>, <8 x i1>, "
59 "i32)";
60 Str << " declare <8 x float> @llvm.vp.round.v8f32(<8 x float>, <8 x i1>, "
61 "i32)";
62 Str << " declare <8 x float> @llvm.vp.roundeven.v8f32(<8 x float>, <8 x "
63 "i1>, "
64 "i32)";
65 Str << " declare <8 x float> @llvm.vp.roundtozero.v8f32(<8 x float>, <8 x "
66 "i1>, "
67 "i32)";
68 Str << " declare <8 x float> @llvm.vp.rint.v8f32(<8 x float>, <8 x i1>, "
69 "i32)";
70 Str << " declare <8 x float> @llvm.vp.nearbyint.v8f32(<8 x float>, <8 x "
71 "i1>, "
72 "i32)";
73 Str << " declare <8 x float> @llvm.vp.ceil.v8f32(<8 x float>, <8 x i1>, "
74 "i32)";
75 Str << " declare <8 x float> @llvm.vp.fneg.v8f32(<8 x float>, <8 x i1>, "
76 "i32)";
77 Str << " declare <8 x float> @llvm.vp.fabs.v8f32(<8 x float>, <8 x i1>, "
78 "i32)";
79 Str << " declare <8 x float> @llvm.vp.sqrt.v8f32(<8 x float>, <8 x i1>, "
80 "i32)";
81 Str << " declare <8 x float> @llvm.vp.fma.v8f32(<8 x float>, <8 x float>, "
82 "<8 x float>, <8 x i1>, i32) ";
83 Str << " declare <8 x float> @llvm.vp.fmuladd.v8f32(<8 x float>, "
84 "<8 x float>, <8 x float>, <8 x i1>, i32) ";
86 Str << " declare void @llvm.vp.store.v8i32.p0v8i32(<8 x i32>, <8 x i32>*, "
87 "<8 x i1>, i32) ";
88 Str << "declare void "
89 "@llvm.experimental.vp.strided.store.v8i32.i32(<8 x i32>, "
90 "i32*, i32, <8 x i1>, i32) ";
91 Str << "declare void "
92 "@llvm.experimental.vp.strided.store.v8i32.p1i32.i32(<8 x i32>, "
93 "i32 addrspace(1)*, i32, <8 x i1>, i32) ";
94 Str << " declare void @llvm.vp.scatter.v8i32.v8p0i32(<8 x i32>, <8 x "
95 "i32*>, <8 x i1>, i32) ";
96 Str << " declare <8 x i32> @llvm.vp.load.v8i32.p0v8i32(<8 x i32>*, <8 x "
97 "i1>, i32) ";
98 Str << "declare <8 x i32> "
99 "@llvm.experimental.vp.strided.load.v8i32.i32(i32*, i32, <8 "
100 "x i1>, i32) ";
101 Str << "declare <8 x i32> "
102 "@llvm.experimental.vp.strided.load.v8i32.p1i32.i32(i32 "
103 "addrspace(1)*, i32, <8 x i1>, i32) ";
104 Str << " declare <8 x i32> @llvm.vp.gather.v8i32.v8p0i32(<8 x i32*>, <8 x "
105 "i1>, i32) ";
107 for (const char *ReductionOpcode : ReductionIntOpcodes)
108 Str << " declare i32 @llvm.vp.reduce." << ReductionOpcode
109 << ".v8i32(i32, <8 x i32>, <8 x i1>, i32) ";
111 for (const char *ReductionOpcode : ReductionFPOpcodes)
112 Str << " declare float @llvm.vp.reduce." << ReductionOpcode
113 << ".v8f32(float, <8 x float>, <8 x i1>, i32) ";
115 Str << " declare <8 x i32> @llvm.vp.merge.v8i32(<8 x i1>, <8 x i32>, <8 x "
116 "i32>, i32)";
117 Str << " declare <8 x i32> @llvm.vp.select.v8i32(<8 x i1>, <8 x i32>, <8 x "
118 "i32>, i32)";
119 Str << " declare <8 x i1> @llvm.vp.is.fpclass.v8f32(<8 x float>, i32, <8 x "
120 "i1>, i32)";
121 Str << " declare <8 x i32> @llvm.experimental.vp.splice.v8i32(<8 x "
122 "i32>, <8 x i32>, i32, <8 x i1>, i32, i32) ";
124 Str << " declare <8 x i32> @llvm.vp.fptoui.v8i32"
125 << ".v8f32(<8 x float>, <8 x i1>, i32) ";
126 Str << " declare <8 x i32> @llvm.vp.fptosi.v8i32"
127 << ".v8f32(<8 x float>, <8 x i1>, i32) ";
128 Str << " declare <8 x float> @llvm.vp.uitofp.v8f32"
129 << ".v8i32(<8 x i32>, <8 x i1>, i32) ";
130 Str << " declare <8 x float> @llvm.vp.sitofp.v8f32"
131 << ".v8i32(<8 x i32>, <8 x i1>, i32) ";
132 Str << " declare <8 x float> @llvm.vp.fptrunc.v8f32"
133 << ".v8f64(<8 x double>, <8 x i1>, i32) ";
134 Str << " declare <8 x double> @llvm.vp.fpext.v8f64"
135 << ".v8f32(<8 x float>, <8 x i1>, i32) ";
136 Str << " declare <8 x i32> @llvm.vp.trunc.v8i32"
137 << ".v8i64(<8 x i64>, <8 x i1>, i32) ";
138 Str << " declare <8 x i64> @llvm.vp.zext.v8i64"
139 << ".v8i32(<8 x i32>, <8 x i1>, i32) ";
140 Str << " declare <8 x i64> @llvm.vp.sext.v8i64"
141 << ".v8i32(<8 x i32>, <8 x i1>, i32) ";
142 Str << " declare <8 x i32> @llvm.vp.ptrtoint.v8i32"
143 << ".v8p0i32(<8 x i32*>, <8 x i1>, i32) ";
144 Str << " declare <8 x i32*> @llvm.vp.inttoptr.v8p0i32"
145 << ".v8i32(<8 x i32>, <8 x i1>, i32) ";
147 Str << " declare <8 x i1> @llvm.vp.fcmp.v8f32"
148 << "(<8 x float>, <8 x float>, metadata, <8 x i1>, i32) ";
149 Str << " declare <8 x i1> @llvm.vp.icmp.v8i16"
150 << "(<8 x i16>, <8 x i16>, metadata, <8 x i1>, i32) ";
152 Str << " declare <8 x i32> @llvm.experimental.vp.reverse.v8i32(<8 x i32>, "
153 "<8 x i1>, i32) ";
154 Str << " declare <8 x i16> @llvm.vp.abs.v8i16"
155 << "(<8 x i16>, i1 immarg, <8 x i1>, i32) ";
156 Str << " declare <8 x i16> @llvm.vp.bitreverse.v8i16"
157 << "(<8 x i16>, <8 x i1>, i32) ";
158 Str << " declare <8 x i16> @llvm.vp.bswap.v8i16"
159 << "(<8 x i16>, <8 x i1>, i32) ";
160 Str << " declare <8 x i16> @llvm.vp.ctpop.v8i16"
161 << "(<8 x i16>, <8 x i1>, i32) ";
162 Str << " declare <8 x i16> @llvm.vp.ctlz.v8i16"
163 << "(<8 x i16>, i1 immarg, <8 x i1>, i32) ";
164 Str << " declare <8 x i16> @llvm.vp.cttz.v8i16"
165 << "(<8 x i16>, i1 immarg, <8 x i1>, i32) ";
166 Str << " declare <8 x i16> @llvm.vp.fshl.v8i16"
167 << "(<8 x i16>, <8 x i16>, <8 x i16>, <8 x i1>, i32) ";
168 Str << " declare <8 x i16> @llvm.vp.fshr.v8i16"
169 << "(<8 x i16>, <8 x i16>, <8 x i16>, <8 x i1>, i32) ";
171 return parseAssemblyString(Str.str(), Err, C);
175 /// Check that the property scopes include/llvm/IR/VPIntrinsics.def are closed.
176 TEST_F(VPIntrinsicTest, VPIntrinsicsDefScopes) {
177 std::optional<Intrinsic::ID> ScopeVPID;
178 #define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) \
179 ASSERT_FALSE(ScopeVPID.has_value()); \
180 ScopeVPID = Intrinsic::VPID;
181 #define END_REGISTER_VP_INTRINSIC(VPID) \
182 ASSERT_TRUE(ScopeVPID.has_value()); \
183 ASSERT_EQ(*ScopeVPID, Intrinsic::VPID); \
184 ScopeVPID = std::nullopt;
186 std::optional<ISD::NodeType> ScopeOPC;
187 #define BEGIN_REGISTER_VP_SDNODE(SDOPC, ...) \
188 ASSERT_FALSE(ScopeOPC.has_value()); \
189 ScopeOPC = ISD::SDOPC;
190 #define END_REGISTER_VP_SDNODE(SDOPC) \
191 ASSERT_TRUE(ScopeOPC.has_value()); \
192 ASSERT_EQ(*ScopeOPC, ISD::SDOPC); \
193 ScopeOPC = std::nullopt;
194 #include "llvm/IR/VPIntrinsics.def"
196 ASSERT_FALSE(ScopeVPID.has_value());
197 ASSERT_FALSE(ScopeOPC.has_value());
200 /// Check that every VP intrinsic in the test module is recognized as a VP
201 /// intrinsic.
202 TEST_F(VPIntrinsicTest, VPModuleComplete) {
203 std::unique_ptr<Module> M = createVPDeclarationModule();
204 assert(M);
206 // Check that all @llvm.vp.* functions in the module are recognized vp
207 // intrinsics.
208 std::set<Intrinsic::ID> SeenIDs;
209 for (const auto &VPDecl : *M) {
210 ASSERT_TRUE(VPDecl.isIntrinsic());
211 ASSERT_TRUE(VPIntrinsic::isVPIntrinsic(VPDecl.getIntrinsicID()));
212 SeenIDs.insert(VPDecl.getIntrinsicID());
215 // Check that every registered VP intrinsic has an instance in the test
216 // module.
217 #define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) \
218 ASSERT_TRUE(SeenIDs.count(Intrinsic::VPID));
219 #include "llvm/IR/VPIntrinsics.def"
222 /// Check that VPIntrinsic:canIgnoreVectorLengthParam() returns true
223 /// if the vector length parameter does not mask off any lanes.
224 TEST_F(VPIntrinsicTest, CanIgnoreVectorLength) {
225 LLVMContext C;
226 SMDiagnostic Err;
228 std::unique_ptr<Module> M =
229 parseAssemblyString(
230 "declare <256 x i64> @llvm.vp.mul.v256i64(<256 x i64>, <256 x i64>, <256 x i1>, i32)"
231 "declare <vscale x 2 x i64> @llvm.vp.mul.nxv2i64(<vscale x 2 x i64>, <vscale x 2 x i64>, <vscale x 2 x i1>, i32)"
232 "declare <vscale x 1 x i64> @llvm.vp.mul.nxv1i64(<vscale x 1 x i64>, <vscale x 1 x i64>, <vscale x 1 x i1>, i32)"
233 "declare i32 @llvm.vscale.i32()"
234 "define void @test_static_vlen( "
235 " <256 x i64> %i0, <vscale x 2 x i64> %si0x2, <vscale x 1 x i64> %si0x1,"
236 " <256 x i64> %i1, <vscale x 2 x i64> %si1x2, <vscale x 1 x i64> %si1x1,"
237 " <256 x i1> %m, <vscale x 2 x i1> %smx2, <vscale x 1 x i1> %smx1, i32 %vl) { "
238 " %r0 = call <256 x i64> @llvm.vp.mul.v256i64(<256 x i64> %i0, <256 x i64> %i1, <256 x i1> %m, i32 %vl)"
239 " %r1 = call <256 x i64> @llvm.vp.mul.v256i64(<256 x i64> %i0, <256 x i64> %i1, <256 x i1> %m, i32 256)"
240 " %r2 = call <256 x i64> @llvm.vp.mul.v256i64(<256 x i64> %i0, <256 x i64> %i1, <256 x i1> %m, i32 0)"
241 " %r3 = call <256 x i64> @llvm.vp.mul.v256i64(<256 x i64> %i0, <256 x i64> %i1, <256 x i1> %m, i32 7)"
242 " %r4 = call <256 x i64> @llvm.vp.mul.v256i64(<256 x i64> %i0, <256 x i64> %i1, <256 x i1> %m, i32 123)"
243 " %vs = call i32 @llvm.vscale.i32()"
244 " %vs.x2 = mul i32 %vs, 2"
245 " %r5 = call <vscale x 2 x i64> @llvm.vp.mul.nxv2i64(<vscale x 2 x i64> %si0x2, <vscale x 2 x i64> %si1x2, <vscale x 2 x i1> %smx2, i32 %vs.x2)"
246 " %r6 = call <vscale x 2 x i64> @llvm.vp.mul.nxv2i64(<vscale x 2 x i64> %si0x2, <vscale x 2 x i64> %si1x2, <vscale x 2 x i1> %smx2, i32 %vs)"
247 " %r7 = call <vscale x 2 x i64> @llvm.vp.mul.nxv2i64(<vscale x 2 x i64> %si0x2, <vscale x 2 x i64> %si1x2, <vscale x 2 x i1> %smx2, i32 99999)"
248 " %r8 = call <vscale x 1 x i64> @llvm.vp.mul.nxv1i64(<vscale x 1 x i64> %si0x1, <vscale x 1 x i64> %si1x1, <vscale x 1 x i1> %smx1, i32 %vs)"
249 " %r9 = call <vscale x 1 x i64> @llvm.vp.mul.nxv1i64(<vscale x 1 x i64> %si0x1, <vscale x 1 x i64> %si1x1, <vscale x 1 x i1> %smx1, i32 1)"
250 " %r10 = call <vscale x 1 x i64> @llvm.vp.mul.nxv1i64(<vscale x 1 x i64> %si0x1, <vscale x 1 x i64> %si1x1, <vscale x 1 x i1> %smx1, i32 %vs.x2)"
251 " %vs.wat = add i32 %vs, 2"
252 " %r11 = call <vscale x 2 x i64> @llvm.vp.mul.nxv2i64(<vscale x 2 x i64> %si0x2, <vscale x 2 x i64> %si1x2, <vscale x 2 x i1> %smx2, i32 %vs.wat)"
253 " ret void "
254 "}",
255 Err, C);
257 auto *F = M->getFunction("test_static_vlen");
258 assert(F);
260 const bool Expected[] = {false, true, false, false, false, true,
261 false, false, true, false, true, false};
262 const auto *ExpectedIt = std::begin(Expected);
263 for (auto &I : F->getEntryBlock()) {
264 VPIntrinsic *VPI = dyn_cast<VPIntrinsic>(&I);
265 if (!VPI)
266 continue;
268 ASSERT_NE(ExpectedIt, std::end(Expected));
269 ASSERT_EQ(*ExpectedIt, VPI->canIgnoreVectorLengthParam());
270 ++ExpectedIt;
274 /// Check that the argument returned by
275 /// VPIntrinsic::get<X>ParamPos(Intrinsic::ID) has the expected type.
276 TEST_F(VPIntrinsicTest, GetParamPos) {
277 std::unique_ptr<Module> M = createVPDeclarationModule();
278 assert(M);
280 for (Function &F : *M) {
281 ASSERT_TRUE(F.isIntrinsic());
282 std::optional<unsigned> MaskParamPos =
283 VPIntrinsic::getMaskParamPos(F.getIntrinsicID());
284 if (MaskParamPos) {
285 Type *MaskParamType = F.getArg(*MaskParamPos)->getType();
286 ASSERT_TRUE(MaskParamType->isVectorTy());
287 ASSERT_TRUE(
288 cast<VectorType>(MaskParamType)->getElementType()->isIntegerTy(1));
291 std::optional<unsigned> VecLenParamPos =
292 VPIntrinsic::getVectorLengthParamPos(F.getIntrinsicID());
293 if (VecLenParamPos) {
294 Type *VecLenParamType = F.getArg(*VecLenParamPos)->getType();
295 ASSERT_TRUE(VecLenParamType->isIntegerTy(32));
300 /// Check that going from Opcode to VP intrinsic and back results in the same
301 /// Opcode.
302 TEST_F(VPIntrinsicTest, OpcodeRoundTrip) {
303 std::vector<unsigned> Opcodes;
304 Opcodes.reserve(100);
307 #define HANDLE_INST(OCNum, OCName, Class) Opcodes.push_back(OCNum);
308 #include "llvm/IR/Instruction.def"
311 unsigned FullTripCounts = 0;
312 for (unsigned OC : Opcodes) {
313 Intrinsic::ID VPID = VPIntrinsic::getForOpcode(OC);
314 // No equivalent VP intrinsic available.
315 if (VPID == Intrinsic::not_intrinsic)
316 continue;
318 std::optional<unsigned> RoundTripOC =
319 VPIntrinsic::getFunctionalOpcodeForVP(VPID);
320 // No equivalent Opcode available.
321 if (!RoundTripOC)
322 continue;
324 ASSERT_EQ(*RoundTripOC, OC);
325 ++FullTripCounts;
327 ASSERT_NE(FullTripCounts, 0u);
330 /// Check that going from VP intrinsic to Opcode and back results in the same
331 /// intrinsic id.
332 TEST_F(VPIntrinsicTest, IntrinsicIDRoundTrip) {
333 std::unique_ptr<Module> M = createVPDeclarationModule();
334 assert(M);
336 unsigned FullTripCounts = 0;
337 for (const auto &VPDecl : *M) {
338 auto VPID = VPDecl.getIntrinsicID();
339 std::optional<unsigned> OC = VPIntrinsic::getFunctionalOpcodeForVP(VPID);
341 // no equivalent Opcode available
342 if (!OC)
343 continue;
345 Intrinsic::ID RoundTripVPID = VPIntrinsic::getForOpcode(*OC);
347 ASSERT_EQ(RoundTripVPID, VPID);
348 ++FullTripCounts;
350 ASSERT_NE(FullTripCounts, 0u);
353 /// Check that VPIntrinsic::getDeclarationForParams works.
354 TEST_F(VPIntrinsicTest, VPIntrinsicDeclarationForParams) {
355 std::unique_ptr<Module> M = createVPDeclarationModule();
356 assert(M);
358 auto OutM = std::make_unique<Module>("", M->getContext());
360 for (auto &F : *M) {
361 auto *FuncTy = F.getFunctionType();
363 // Declare intrinsic anew with explicit types.
364 std::vector<Value *> Values;
365 for (auto *ParamTy : FuncTy->params())
366 Values.push_back(UndefValue::get(ParamTy));
368 ASSERT_NE(F.getIntrinsicID(), Intrinsic::not_intrinsic);
369 auto *NewDecl = VPIntrinsic::getDeclarationForParams(
370 OutM.get(), F.getIntrinsicID(), FuncTy->getReturnType(), Values);
371 ASSERT_TRUE(NewDecl);
373 // Check that 'old decl' == 'new decl'.
374 ASSERT_EQ(F.getIntrinsicID(), NewDecl->getIntrinsicID());
375 FunctionType::param_iterator ItNewParams =
376 NewDecl->getFunctionType()->param_begin();
377 FunctionType::param_iterator EndItNewParams =
378 NewDecl->getFunctionType()->param_end();
379 for (auto *ParamTy : FuncTy->params()) {
380 ASSERT_NE(ItNewParams, EndItNewParams);
381 ASSERT_EQ(*ItNewParams, ParamTy);
382 ++ItNewParams;
387 /// Check that the HANDLE_VP_TO_CONSTRAINEDFP maps to an existing intrinsic with
388 /// the right amount of constrained-fp metadata args.
389 TEST_F(VPIntrinsicTest, HandleToConstrainedFP) {
390 #define VP_PROPERTY_CONSTRAINEDFP(HASROUND, HASEXCEPT, CFPID) \
392 SmallVector<Intrinsic::IITDescriptor, 5> T; \
393 Intrinsic::getIntrinsicInfoTableEntries(Intrinsic::CFPID, T); \
394 unsigned NumMetadataArgs = 0; \
395 for (auto TD : T) \
396 NumMetadataArgs += (TD.Kind == Intrinsic::IITDescriptor::Metadata); \
397 bool IsCmp = Intrinsic::CFPID == Intrinsic::experimental_constrained_fcmp; \
398 ASSERT_EQ(NumMetadataArgs, (unsigned)(IsCmp + HASROUND + HASEXCEPT)); \
400 #include "llvm/IR/VPIntrinsics.def"
403 } // end anonymous namespace
405 /// Check various properties of VPReductionIntrinsics
406 TEST_F(VPIntrinsicTest, VPReductions) {
407 LLVMContext C;
408 SMDiagnostic Err;
410 std::stringstream Str;
411 Str << "declare <8 x i32> @llvm.vp.mul.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, "
412 "i32)";
413 for (const char *ReductionOpcode : ReductionIntOpcodes)
414 Str << " declare i32 @llvm.vp.reduce." << ReductionOpcode
415 << ".v8i32(i32, <8 x i32>, <8 x i1>, i32) ";
417 for (const char *ReductionOpcode : ReductionFPOpcodes)
418 Str << " declare float @llvm.vp.reduce." << ReductionOpcode
419 << ".v8f32(float, <8 x float>, <8 x i1>, i32) ";
421 Str << "define void @test_reductions(i32 %start, <8 x i32> %val, float "
422 "%fpstart, <8 x float> %fpval, <8 x i1> %m, i32 %vl) {";
424 // Mix in a regular non-reduction intrinsic to check that the
425 // VPReductionIntrinsic subclass works as intended.
426 Str << " %r0 = call <8 x i32> @llvm.vp.mul.v8i32(<8 x i32> %val, <8 x i32> "
427 "%val, <8 x i1> %m, i32 %vl)";
429 unsigned Idx = 1;
430 for (const char *ReductionOpcode : ReductionIntOpcodes)
431 Str << " %r" << Idx++ << " = call i32 @llvm.vp.reduce." << ReductionOpcode
432 << ".v8i32(i32 %start, <8 x i32> %val, <8 x i1> %m, i32 %vl)";
433 for (const char *ReductionOpcode : ReductionFPOpcodes)
434 Str << " %r" << Idx++ << " = call float @llvm.vp.reduce."
435 << ReductionOpcode
436 << ".v8f32(float %fpstart, <8 x float> %fpval, <8 x i1> %m, i32 %vl)";
438 Str << " ret void"
439 "}";
441 std::unique_ptr<Module> M = parseAssemblyString(Str.str(), Err, C);
442 assert(M);
444 auto *F = M->getFunction("test_reductions");
445 assert(F);
447 for (const auto &I : F->getEntryBlock()) {
448 const VPIntrinsic *VPI = dyn_cast<VPIntrinsic>(&I);
449 if (!VPI)
450 continue;
452 Intrinsic::ID ID = VPI->getIntrinsicID();
453 const auto *VPRedI = dyn_cast<VPReductionIntrinsic>(&I);
455 if (!VPReductionIntrinsic::isVPReduction(ID)) {
456 EXPECT_EQ(VPRedI, nullptr);
457 EXPECT_EQ(VPReductionIntrinsic::getStartParamPos(ID).has_value(), false);
458 EXPECT_EQ(VPReductionIntrinsic::getVectorParamPos(ID).has_value(), false);
459 continue;
462 EXPECT_EQ(VPReductionIntrinsic::getStartParamPos(ID).has_value(), true);
463 EXPECT_EQ(VPReductionIntrinsic::getVectorParamPos(ID).has_value(), true);
464 ASSERT_NE(VPRedI, nullptr);
465 EXPECT_EQ(VPReductionIntrinsic::getStartParamPos(ID),
466 VPRedI->getStartParamPos());
467 EXPECT_EQ(VPReductionIntrinsic::getVectorParamPos(ID),
468 VPRedI->getVectorParamPos());
469 EXPECT_EQ(VPRedI->getStartParamPos(), 0u);
470 EXPECT_EQ(VPRedI->getVectorParamPos(), 1u);