diff --git a/llvm/unittests/IR/VPIntrinsicTest.cpp b/llvm/unittests/IR/VPIntrinsicTest.cpp --- a/llvm/unittests/IR/VPIntrinsicTest.cpp +++ b/llvm/unittests/IR/VPIntrinsicTest.cpp @@ -8,6 +8,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/AsmParser/Parser.h" +#include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/IR/Constants.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/IntrinsicInst.h" @@ -16,6 +17,7 @@ #include "llvm/IR/Verifier.h" #include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" +#include using namespace llvm; @@ -31,24 +33,65 @@ SMDiagnostic Err; std::unique_ptr CreateVPDeclarationModule() { - return parseAssemblyString( -" declare <8 x i32> @llvm.vp.add.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) " -" declare <8 x i32> @llvm.vp.sub.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) " -" declare <8 x i32> @llvm.vp.mul.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) " -" declare <8 x i32> @llvm.vp.sdiv.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) " -" declare <8 x i32> @llvm.vp.srem.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) " -" declare <8 x i32> @llvm.vp.udiv.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) " -" declare <8 x i32> @llvm.vp.urem.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) " -" declare <8 x i32> @llvm.vp.and.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) " -" declare <8 x i32> @llvm.vp.xor.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) " -" declare <8 x i32> @llvm.vp.or.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) " -" declare <8 x i32> @llvm.vp.ashr.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) " -" declare <8 x i32> @llvm.vp.lshr.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) " -" declare <8 x i32> @llvm.vp.shl.v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) ", - Err, C); + const char *BinaryIntOpcodes[] = {"add", "sub", "mul", "sdiv", "srem", + "udiv", "urem", "and", "xor", "or", + "ashr", "lshr", "shl"}; + std::stringstream Str; + for (const char *BinaryIntOpcode : BinaryIntOpcodes) + Str << " declare <8 x i32> @llvm.vp." << BinaryIntOpcode + << ".v8i32(<8 x i32>, <8 x i32>, <8 x i1>, i32) "; + + return parseAssemblyString(Str.str(), Err, C); } }; +/// Check that the property scopes include/llvm/IR/VPIntrinsics.def are closed. +TEST_F(VPIntrinsicTest, VPIntrinsicsDefScopes) { + Optional ScopeVPID; +#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) \ + ASSERT_FALSE(ScopeVPID.hasValue()); \ + ScopeVPID = Intrinsic::VPID; +#define END_REGISTER_VP_INTRINSIC(VPID) \ + ASSERT_TRUE(ScopeVPID.hasValue()); \ + ASSERT_EQ(ScopeVPID.getValue(), Intrinsic::VPID); \ + ScopeVPID = None; + + Optional ScopeOPC; +#define BEGIN_REGISTER_VP_SDNODE(SDOPC, ...) \ + ASSERT_FALSE(ScopeOPC.hasValue()); \ + ScopeOPC = ISD::SDOPC; +#define END_REGISTER_VP_SDNODE(SDOPC) \ + ASSERT_TRUE(ScopeOPC.hasValue()); \ + ASSERT_EQ(ScopeOPC.getValue(), ISD::SDOPC); \ + ScopeOPC = None; +#include "llvm/IR/VPIntrinsics.def" + + ASSERT_FALSE(ScopeVPID.hasValue()); + ASSERT_FALSE(ScopeOPC.hasValue()); +} + +/// Check that every VP intrinsic in the test module is recognized as a VP +/// intrinsic. +TEST_F(VPIntrinsicTest, VPModuleComplete) { + std::unique_ptr M = CreateVPDeclarationModule(); + assert(M); + + // Check that all @llvm.vp.* functions in the module are recognized vp + // intrinsics. + std::set SeenIDs; + for (const auto &VPDecl : *M) { + ASSERT_TRUE(VPDecl.isIntrinsic()); + ASSERT_TRUE(VPIntrinsic::IsVPIntrinsic(VPDecl.getIntrinsicID())); + SeenIDs.insert(VPDecl.getIntrinsicID()); + } + + // Check that every registered VP intrinsic has an instance in the test + // module. +#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) \ + ASSERT_TRUE(SeenIDs.count(Intrinsic::VPID)); +#include "llvm/IR/VPIntrinsics.def" +} + /// Check that VPIntrinsic:canIgnoreVectorLengthParam() returns true /// if the vector length parameter does not mask off any lanes. TEST_F(VPIntrinsicTest, CanIgnoreVectorLength) { @@ -155,4 +198,27 @@ ASSERT_NE(FullTripCounts, 0u); } +/// Check that going from VP intrinsic to Opcode and back results in the same +/// intrinsic id. +TEST_F(VPIntrinsicTest, IntrinsicIDRoundTrip) { + std::unique_ptr M = CreateVPDeclarationModule(); + assert(M); + + unsigned FullTripCounts = 0; + for (const auto &VPDecl : *M) { + auto VPID = VPDecl.getIntrinsicID(); + unsigned OC = VPIntrinsic::GetFunctionalOpcodeForVP(VPID); + + // no equivalent Opcode available + if (OC == Instruction::Call) + continue; + + Intrinsic::ID RoundTripVPID = VPIntrinsic::GetForOpcode(OC); + + ASSERT_EQ(RoundTripVPID, VPID); + ++FullTripCounts; + } + ASSERT_NE(FullTripCounts, 0u); +} + } // end anonymous namespace