• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/ADT/SmallVector.h"
10 #include "llvm/AsmParser/Parser.h"
11 #include "llvm/IR/Constants.h"
12 #include "llvm/IR/IRBuilder.h"
13 #include "llvm/IR/IntrinsicInst.h"
14 #include "llvm/IR/LLVMContext.h"
15 #include "llvm/IR/Module.h"
16 #include "llvm/IR/Verifier.h"
17 #include "llvm/Support/SourceMgr.h"
18 #include "gtest/gtest.h"
19 
20 using namespace llvm;
21 
22 namespace {
23 
24 class VPIntrinsicTest : public testing::Test {
25 protected:
26   LLVMContext Context;
27 
VPIntrinsicTest()28   VPIntrinsicTest() : Context() {}
29 
30   LLVMContext C;
31   SMDiagnostic Err;
32 
CreateVPDeclarationModule()33   std::unique_ptr<Module> CreateVPDeclarationModule() {
34       return parseAssemblyString(
35 " declare <8 x i32> @llvm.vp.add.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) "
36 " declare <8 x i32> @llvm.vp.sub.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) "
37 " declare <8 x i32> @llvm.vp.mul.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) "
38 " declare <8 x i32> @llvm.vp.sdiv.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) "
39 " declare <8 x i32> @llvm.vp.srem.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) "
40 " declare <8 x i32> @llvm.vp.udiv.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) "
41 " declare <8 x i32> @llvm.vp.urem.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) "
42 " declare <8 x i32> @llvm.vp.and.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) "
43 " declare <8 x i32> @llvm.vp.xor.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) "
44 " declare <8 x i32> @llvm.vp.or.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) "
45 " declare <8 x i32> @llvm.vp.ashr.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32)  "
46 " declare <8 x i32> @llvm.vp.lshr.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32)  "
47 " declare <8 x i32> @llvm.vp.shl.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) ",
48           Err, C);
49   }
50 };
51 
52 /// Check that VPIntrinsic:canIgnoreVectorLengthParam() returns true
53 /// if the vector length parameter does not mask off any lanes.
TEST_F(VPIntrinsicTest,CanIgnoreVectorLength)54 TEST_F(VPIntrinsicTest, CanIgnoreVectorLength) {
55   LLVMContext C;
56   SMDiagnostic Err;
57 
58   std::unique_ptr<Module> M =
59       parseAssemblyString(
60 "declare <256 x i64> @llvm.vp.mul.v256i64(<256 x i64>, <256 x i64>, <256 x i1>, i32)"
61 "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)"
62 "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)"
63 "declare i32 @llvm.vscale.i32()"
64 "define void @test_static_vlen( "
65 "      <256 x i64> %i0, <vscale x 2 x i64> %si0x2, <vscale x 1 x i64> %si0x1,"
66 "      <256 x i64> %i1, <vscale x 2 x i64> %si1x2, <vscale x 1 x i64> %si1x1,"
67 "      <256 x i1> %m, <vscale x 2 x i1> %smx2, <vscale x 1 x i1> %smx1, i32 %vl) { "
68 "  %r0 = call <256 x i64> @llvm.vp.mul.v256i64(<256 x i64> %i0, <256 x i64> %i1, <256 x i1> %m, i32 %vl)"
69 "  %r1 = call <256 x i64> @llvm.vp.mul.v256i64(<256 x i64> %i0, <256 x i64> %i1, <256 x i1> %m, i32 256)"
70 "  %r2 = call <256 x i64> @llvm.vp.mul.v256i64(<256 x i64> %i0, <256 x i64> %i1, <256 x i1> %m, i32 0)"
71 "  %r3 = call <256 x i64> @llvm.vp.mul.v256i64(<256 x i64> %i0, <256 x i64> %i1, <256 x i1> %m, i32 7)"
72 "  %r4 = call <256 x i64> @llvm.vp.mul.v256i64(<256 x i64> %i0, <256 x i64> %i1, <256 x i1> %m, i32 123)"
73 "  %vs = call i32 @llvm.vscale.i32()"
74 "  %vs.x2 = mul i32 %vs, 2"
75 "  %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)"
76 "  %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)"
77 "  %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)"
78 "  %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)"
79 "  %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)"
80 "  %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)"
81 "  %vs.wat = add i32 %vs, 2"
82 "  %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)"
83 "  ret void "
84 "}",
85           Err, C);
86 
87   auto *F = M->getFunction("test_static_vlen");
88   assert(F);
89 
90   const int NumExpected = 12;
91   const bool Expected[] = {false, true, false, false, false, true, false, false, true, false, true, false};
92   int i = 0;
93   for (auto &I : F->getEntryBlock()) {
94     VPIntrinsic *VPI = dyn_cast<VPIntrinsic>(&I);
95     if (!VPI)
96       continue;
97 
98     ASSERT_LT(i, NumExpected);
99     ASSERT_EQ(Expected[i], VPI->canIgnoreVectorLengthParam());
100     ++i;
101   }
102 }
103 
104 /// Check that the argument returned by
105 /// VPIntrinsic::Get<X>ParamPos(Intrinsic::ID) has the expected type.
TEST_F(VPIntrinsicTest,GetParamPos)106 TEST_F(VPIntrinsicTest, GetParamPos) {
107   std::unique_ptr<Module> M = CreateVPDeclarationModule();
108   assert(M);
109 
110   for (Function &F : *M) {
111     ASSERT_TRUE(F.isIntrinsic());
112     Optional<int> MaskParamPos =
113         VPIntrinsic::GetMaskParamPos(F.getIntrinsicID());
114     if (MaskParamPos.hasValue()) {
115       Type *MaskParamType = F.getArg(MaskParamPos.getValue())->getType();
116       ASSERT_TRUE(MaskParamType->isVectorTy());
117       ASSERT_TRUE(cast<VectorType>(MaskParamType)->getElementType()->isIntegerTy(1));
118     }
119 
120     Optional<int> VecLenParamPos =
121         VPIntrinsic::GetVectorLengthParamPos(F.getIntrinsicID());
122     if (VecLenParamPos.hasValue()) {
123       Type *VecLenParamType = F.getArg(VecLenParamPos.getValue())->getType();
124       ASSERT_TRUE(VecLenParamType->isIntegerTy(32));
125     }
126   }
127 }
128 
129 /// Check that going from Opcode to VP intrinsic and back results in the same
130 /// Opcode.
TEST_F(VPIntrinsicTest,OpcodeRoundTrip)131 TEST_F(VPIntrinsicTest, OpcodeRoundTrip) {
132   std::vector<unsigned> Opcodes;
133   Opcodes.reserve(100);
134 
135   {
136 #define HANDLE_INST(OCNum, OCName, Class) Opcodes.push_back(OCNum);
137 #include "llvm/IR/Instruction.def"
138   }
139 
140   unsigned FullTripCounts = 0;
141   for (unsigned OC : Opcodes) {
142     Intrinsic::ID VPID = VPIntrinsic::GetForOpcode(OC);
143     // no equivalent VP intrinsic available
144     if (VPID == Intrinsic::not_intrinsic)
145       continue;
146 
147     unsigned RoundTripOC = VPIntrinsic::GetFunctionalOpcodeForVP(VPID);
148     // no equivalent Opcode available
149     if (RoundTripOC == Instruction::Call)
150       continue;
151 
152     ASSERT_EQ(RoundTripOC, OC);
153     ++FullTripCounts;
154   }
155   ASSERT_NE(FullTripCounts, 0u);
156 }
157 
158 } // end anonymous namespace
159