|  | //===- llvm/unittest/IR/IntrinsicsTest.cpp - ------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/IR/Intrinsics.h" | 
|  | #include "llvm/ADT/SmallVector.h" | 
|  | #include "llvm/IR/Constant.h" | 
|  | #include "llvm/IR/IRBuilder.h" | 
|  | #include "llvm/IR/IntrinsicInst.h" | 
|  | #include "llvm/IR/IntrinsicsAArch64.h" | 
|  | #include "llvm/IR/IntrinsicsAMDGPU.h" | 
|  | #include "llvm/IR/IntrinsicsARM.h" | 
|  | #include "llvm/IR/IntrinsicsBPF.h" | 
|  | #include "llvm/IR/IntrinsicsDirectX.h" | 
|  | #include "llvm/IR/IntrinsicsHexagon.h" | 
|  | #include "llvm/IR/IntrinsicsLoongArch.h" | 
|  | #include "llvm/IR/IntrinsicsMips.h" | 
|  | #include "llvm/IR/IntrinsicsNVPTX.h" | 
|  | #include "llvm/IR/IntrinsicsPowerPC.h" | 
|  | #include "llvm/IR/IntrinsicsRISCV.h" | 
|  | #include "llvm/IR/IntrinsicsS390.h" | 
|  | #include "llvm/IR/IntrinsicsX86.h" | 
|  | #include "llvm/IR/Module.h" | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class IntrinsicsTest : public ::testing::Test { | 
|  | LLVMContext Context; | 
|  | std::unique_ptr<Module> M; | 
|  | BasicBlock *BB = nullptr; | 
|  |  | 
|  | void TearDown() override { M.reset(); } | 
|  |  | 
|  | void SetUp() override { | 
|  | M = std::make_unique<Module>("Test", Context); | 
|  | auto F = M->getOrInsertFunction( | 
|  | "test", FunctionType::get(Type::getVoidTy(Context), false)); | 
|  | BB = BasicBlock::Create(Context, "", cast<Function>(F.getCallee())); | 
|  | EXPECT_NE(BB, nullptr); | 
|  | } | 
|  |  | 
|  | public: | 
|  | Instruction *makeIntrinsic(Intrinsic::ID ID) const { | 
|  | IRBuilder<> Builder(BB); | 
|  | SmallVector<Value *, 4> ProcessedArgs; | 
|  | auto *Decl = Intrinsic::getOrInsertDeclaration(M.get(), ID); | 
|  | for (auto *Ty : Decl->getFunctionType()->params()) { | 
|  | auto *Val = Constant::getNullValue(Ty); | 
|  | ProcessedArgs.push_back(Val); | 
|  | } | 
|  | return Builder.CreateCall(Decl, ProcessedArgs); | 
|  | } | 
|  | template <typename T> void checkIsa(const Instruction &I) { | 
|  | EXPECT_TRUE(isa<T>(I)); | 
|  | } | 
|  | }; | 
|  |  | 
|  | TEST(IntrinsicNameLookup, Basic) { | 
|  | using namespace Intrinsic; | 
|  | EXPECT_EQ(Intrinsic::memcpy, lookupIntrinsicID("llvm.memcpy")); | 
|  |  | 
|  | // Partial, either between dots or not the last dot are not intrinsics. | 
|  | EXPECT_EQ(not_intrinsic, lookupIntrinsicID("llvm.mem")); | 
|  | EXPECT_EQ(not_intrinsic, lookupIntrinsicID("llvm.gc")); | 
|  |  | 
|  | // Look through intrinsic names with internal dots. | 
|  | EXPECT_EQ(memcpy_inline, lookupIntrinsicID("llvm.memcpy.inline")); | 
|  |  | 
|  | // Check that overloaded names are mapped to the underlying ID. | 
|  | EXPECT_EQ(memcpy_inline, lookupIntrinsicID("llvm.memcpy.inline.p0.p0.i8")); | 
|  | EXPECT_EQ(memcpy_inline, lookupIntrinsicID("llvm.memcpy.inline.p0.p0.i32")); | 
|  | EXPECT_EQ(memcpy_inline, lookupIntrinsicID("llvm.memcpy.inline.p0.p0.i64")); | 
|  | EXPECT_EQ(memcpy_inline, lookupIntrinsicID("llvm.memcpy.inline.p0.p0.i1024")); | 
|  | } | 
|  |  | 
|  | // Tests to verify getIntrinsicForClangBuiltin. | 
|  | TEST(IntrinsicNameLookup, ClangBuiltinLookup) { | 
|  | using namespace Intrinsic; | 
|  | static constexpr std::tuple<StringRef, StringRef, ID> ClangTests[] = { | 
|  | {"__builtin_adjust_trampoline", "", adjust_trampoline}, | 
|  | {"__builtin_trap", "", trap}, | 
|  | {"__builtin_arm_chkfeat", "aarch64", aarch64_chkfeat}, | 
|  | {"__builtin_amdgcn_alignbyte", "amdgcn", amdgcn_alignbyte}, | 
|  | {"__builtin_amdgcn_workgroup_id_z", "amdgcn", amdgcn_workgroup_id_z}, | 
|  | {"__builtin_arm_cdp", "arm", arm_cdp}, | 
|  | {"__builtin_bpf_preserve_type_info", "bpf", bpf_preserve_type_info}, | 
|  | {"__builtin_HEXAGON_A2_tfr", "hexagon", hexagon_A2_tfr}, | 
|  | {"__builtin_lasx_xbz_w", "loongarch", loongarch_lasx_xbz_w}, | 
|  | {"__builtin_mips_bitrev", "mips", mips_bitrev}, | 
|  | {"__nvvm_add_rn_d", "nvvm", nvvm_add_rn_d}, | 
|  | {"__builtin_altivec_dss", "ppc", ppc_altivec_dss}, | 
|  | {"__builtin_riscv_sha512sum1r", "riscv", riscv_sha512sum1r}, | 
|  | {"__builtin_tend", "s390", s390_tend}, | 
|  | {"__builtin_ia32_pause", "x86", x86_sse2_pause}, | 
|  |  | 
|  | {"__does_not_exist", "", not_intrinsic}, | 
|  | {"__does_not_exist", "arm", not_intrinsic}, | 
|  | {"__builtin_arm_cdp", "", not_intrinsic}, | 
|  | {"__builtin_arm_cdp", "x86", not_intrinsic}, | 
|  | }; | 
|  |  | 
|  | for (const auto &[Builtin, Target, ID] : ClangTests) | 
|  | EXPECT_EQ(ID, getIntrinsicForClangBuiltin(Target, Builtin)); | 
|  | } | 
|  |  | 
|  | // Tests to verify getIntrinsicForMSBuiltin. | 
|  | TEST(IntrinsicNameLookup, MSBuiltinLookup) { | 
|  | using namespace Intrinsic; | 
|  | static constexpr std::tuple<StringRef, StringRef, ID> MSTests[] = { | 
|  | {"__dmb", "aarch64", aarch64_dmb}, | 
|  | {"__dmb", "arm", arm_dmb}, | 
|  | {"__dmb", "", not_intrinsic}, | 
|  | {"__does_not_exist", "", not_intrinsic}, | 
|  | {"__does_not_exist", "arm", not_intrinsic}, | 
|  | }; | 
|  | for (const auto &[Builtin, Target, ID] : MSTests) | 
|  | EXPECT_EQ(ID, getIntrinsicForMSBuiltin(Target, Builtin)); | 
|  | } | 
|  |  | 
|  | TEST_F(IntrinsicsTest, InstrProfInheritance) { | 
|  | auto isInstrProfInstBase = [](const Instruction &I) { | 
|  | return isa<InstrProfInstBase>(I); | 
|  | }; | 
|  | #define __ISA(TYPE, PARENT)                                                    \ | 
|  | auto is##TYPE = [&](const Instruction &I) -> bool {                          \ | 
|  | return isa<TYPE>(I) && is##PARENT(I);                                      \ | 
|  | } | 
|  | __ISA(InstrProfCntrInstBase, InstrProfInstBase); | 
|  | __ISA(InstrProfCoverInst, InstrProfCntrInstBase); | 
|  | __ISA(InstrProfIncrementInst, InstrProfCntrInstBase); | 
|  | __ISA(InstrProfIncrementInstStep, InstrProfIncrementInst); | 
|  | __ISA(InstrProfCallsite, InstrProfCntrInstBase); | 
|  | __ISA(InstrProfTimestampInst, InstrProfCntrInstBase); | 
|  | __ISA(InstrProfValueProfileInst, InstrProfCntrInstBase); | 
|  | __ISA(InstrProfMCDCBitmapInstBase, InstrProfInstBase); | 
|  | __ISA(InstrProfMCDCBitmapParameters, InstrProfMCDCBitmapInstBase); | 
|  | __ISA(InstrProfMCDCTVBitmapUpdate, InstrProfMCDCBitmapInstBase); | 
|  | #undef __ISA | 
|  |  | 
|  | std::vector< | 
|  | std::pair<Intrinsic::ID, std::function<bool(const Instruction &)>>> | 
|  | LeafIDs = { | 
|  | {Intrinsic::instrprof_cover, isInstrProfCoverInst}, | 
|  | {Intrinsic::instrprof_increment, isInstrProfIncrementInst}, | 
|  | {Intrinsic::instrprof_increment_step, isInstrProfIncrementInstStep}, | 
|  | {Intrinsic::instrprof_callsite, isInstrProfCallsite}, | 
|  | {Intrinsic::instrprof_mcdc_parameters, | 
|  | isInstrProfMCDCBitmapParameters}, | 
|  | {Intrinsic::instrprof_mcdc_tvbitmap_update, | 
|  | isInstrProfMCDCTVBitmapUpdate}, | 
|  | {Intrinsic::instrprof_timestamp, isInstrProfTimestampInst}, | 
|  | {Intrinsic::instrprof_value_profile, isInstrProfValueProfileInst}}; | 
|  | for (const auto &[ID, Checker] : LeafIDs) { | 
|  | auto *Intr = makeIntrinsic(ID); | 
|  | EXPECT_TRUE(Checker(*Intr)); | 
|  | } | 
|  | } | 
|  |  | 
|  | } // end namespace |