201 lines · cpp
1//===- llvm/unittest/IR/IntrinsicsTest.cpp - ------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/IR/Intrinsics.h"10#include "llvm/ADT/SmallVector.h"11#include "llvm/IR/Constant.h"12#include "llvm/IR/IRBuilder.h"13#include "llvm/IR/IntrinsicInst.h"14#include "llvm/IR/IntrinsicsAArch64.h"15#include "llvm/IR/IntrinsicsAMDGPU.h"16#include "llvm/IR/IntrinsicsARM.h"17#include "llvm/IR/IntrinsicsBPF.h"18#include "llvm/IR/IntrinsicsDirectX.h"19#include "llvm/IR/IntrinsicsHexagon.h"20#include "llvm/IR/IntrinsicsLoongArch.h"21#include "llvm/IR/IntrinsicsMips.h"22#include "llvm/IR/IntrinsicsNVPTX.h"23#include "llvm/IR/IntrinsicsPowerPC.h"24#include "llvm/IR/IntrinsicsRISCV.h"25#include "llvm/IR/IntrinsicsS390.h"26#include "llvm/IR/IntrinsicsX86.h"27#include "llvm/IR/Module.h"28#include "gtest/gtest.h"29 30using namespace llvm;31 32namespace {33 34class IntrinsicsTest : public ::testing::Test {35 LLVMContext Context;36 std::unique_ptr<Module> M;37 BasicBlock *BB = nullptr;38 39 void TearDown() override { M.reset(); }40 41 void SetUp() override {42 M = std::make_unique<Module>("Test", Context);43 auto F = M->getOrInsertFunction(44 "test", FunctionType::get(Type::getVoidTy(Context), false));45 BB = BasicBlock::Create(Context, "", cast<Function>(F.getCallee()));46 EXPECT_NE(BB, nullptr);47 }48 49public:50 Instruction *makeIntrinsic(Intrinsic::ID ID) const {51 IRBuilder<> Builder(BB);52 SmallVector<Value *, 4> ProcessedArgs;53 auto *Decl = Intrinsic::getOrInsertDeclaration(M.get(), ID);54 for (auto *Ty : Decl->getFunctionType()->params()) {55 auto *Val = Constant::getNullValue(Ty);56 ProcessedArgs.push_back(Val);57 }58 return Builder.CreateCall(Decl, ProcessedArgs);59 }60 template <typename T> void checkIsa(const Instruction &I) {61 EXPECT_TRUE(isa<T>(I));62 }63};64 65TEST(IntrinsicNameLookup, Basic) {66 using namespace Intrinsic;67 EXPECT_EQ(Intrinsic::memcpy, lookupIntrinsicID("llvm.memcpy"));68 69 // Partial, either between dots or not the last dot are not intrinsics.70 EXPECT_EQ(not_intrinsic, lookupIntrinsicID("llvm.mem"));71 EXPECT_EQ(not_intrinsic, lookupIntrinsicID("llvm.gc"));72 73 // Look through intrinsic names with internal dots.74 EXPECT_EQ(memcpy_inline, lookupIntrinsicID("llvm.memcpy.inline"));75 76 // Check that overloaded names are mapped to the underlying ID.77 EXPECT_EQ(memcpy_inline, lookupIntrinsicID("llvm.memcpy.inline.p0.p0.i8"));78 EXPECT_EQ(memcpy_inline, lookupIntrinsicID("llvm.memcpy.inline.p0.p0.i32"));79 EXPECT_EQ(memcpy_inline, lookupIntrinsicID("llvm.memcpy.inline.p0.p0.i64"));80 EXPECT_EQ(memcpy_inline, lookupIntrinsicID("llvm.memcpy.inline.p0.p0.i1024"));81}82 83TEST(IntrinsicNameLookup, NonNullterminatedStringRef) {84 using namespace Intrinsic;85 // This reproduces an issue where lookupIntrinsicID() can access memory beyond86 // the bounds of the passed in StringRef. For ASAN to catch this as an error,87 // create a StringRef using heap allocated memory and make it not null88 // terminated.89 90 // ASAN will report a "AddressSanitizer: heap-buffer-overflow" error in91 // `lookupLLVMIntrinsicByName` when LLVM is built with these options:92 // -DCMAKE_BUILD_TYPE=Debug93 // -DLLVM_USE_SANITIZER=Address94 // -DLLVM_OPTIMIZE_SANITIZED_BUILDS=OFF95 96 // Make an intrinsic name "llvm.memcpy.inline" on the heap.97 std::string Name = "llvm.memcpy.inline";98 assert(Name.size() == 18);99 // Create a StringRef backed by heap allocated memory such that OOB access100 // in that StringRef can be flagged by asan. Here, the String `S` is of size101 // 18, and backed by a heap allocated buffer `Data`, so access to S[18] will102 // be flagged bby asan.103 auto Data = std::make_unique<char[]>(Name.size());104 std::strncpy(Data.get(), Name.data(), Name.size());105 StringRef S(Data.get(), Name.size());106 EXPECT_EQ(memcpy_inline, lookupIntrinsicID(S));107}108 109// Tests to verify getIntrinsicForClangBuiltin.110TEST(IntrinsicNameLookup, ClangBuiltinLookup) {111 using namespace Intrinsic;112 static constexpr std::tuple<StringRef, StringRef, ID> ClangTests[] = {113 {"__builtin_adjust_trampoline", "", adjust_trampoline},114 {"__builtin_trap", "", trap},115 {"__builtin_arm_chkfeat", "aarch64", aarch64_chkfeat},116 {"__builtin_amdgcn_alignbyte", "amdgcn", amdgcn_alignbyte},117 {"__builtin_amdgcn_workgroup_id_z", "amdgcn", amdgcn_workgroup_id_z},118 {"__builtin_arm_cdp", "arm", arm_cdp},119 {"__builtin_bpf_preserve_type_info", "bpf", bpf_preserve_type_info},120 {"__builtin_HEXAGON_A2_tfr", "hexagon", hexagon_A2_tfr},121 {"__builtin_lasx_xbz_w", "loongarch", loongarch_lasx_xbz_w},122 {"__builtin_mips_bitrev", "mips", mips_bitrev},123 {"__nvvm_add_rn_d", "nvvm", nvvm_add_rn_d},124 {"__builtin_altivec_dss", "ppc", ppc_altivec_dss},125 {"__builtin_riscv_sha512sum1r", "riscv", riscv_sha512sum1r},126 {"__builtin_tend", "s390", s390_tend},127 {"__builtin_ia32_pause", "x86", x86_sse2_pause},128 129 {"__does_not_exist", "", not_intrinsic},130 {"__does_not_exist", "arm", not_intrinsic},131 {"__builtin_arm_cdp", "", not_intrinsic},132 {"__builtin_arm_cdp", "x86", not_intrinsic},133 };134 135 for (const auto &[Builtin, Target, ID] : ClangTests)136 EXPECT_EQ(ID, getIntrinsicForClangBuiltin(Target, Builtin));137}138 139// Tests to verify getIntrinsicForMSBuiltin.140TEST(IntrinsicNameLookup, MSBuiltinLookup) {141 using namespace Intrinsic;142 static constexpr std::tuple<StringRef, StringRef, ID> MSTests[] = {143 {"__dmb", "aarch64", aarch64_dmb},144 {"__dmb", "arm", arm_dmb},145 {"__dmb", "", not_intrinsic},146 {"__does_not_exist", "", not_intrinsic},147 {"__does_not_exist", "arm", not_intrinsic},148 };149 for (const auto &[Builtin, Target, ID] : MSTests)150 EXPECT_EQ(ID, getIntrinsicForMSBuiltin(Target, Builtin));151}152 153TEST_F(IntrinsicsTest, InstrProfInheritance) {154 auto isInstrProfInstBase = [](const Instruction &I) {155 return isa<InstrProfInstBase>(I);156 };157#define __ISA(TYPE, PARENT) \158 auto is##TYPE = [&](const Instruction &I) -> bool { \159 return isa<TYPE>(I) && is##PARENT(I); \160 }161 __ISA(InstrProfCntrInstBase, InstrProfInstBase);162 __ISA(InstrProfCoverInst, InstrProfCntrInstBase);163 __ISA(InstrProfIncrementInst, InstrProfCntrInstBase);164 __ISA(InstrProfIncrementInstStep, InstrProfIncrementInst);165 __ISA(InstrProfCallsite, InstrProfCntrInstBase);166 __ISA(InstrProfTimestampInst, InstrProfCntrInstBase);167 __ISA(InstrProfValueProfileInst, InstrProfCntrInstBase);168 __ISA(InstrProfMCDCBitmapInstBase, InstrProfInstBase);169 __ISA(InstrProfMCDCBitmapParameters, InstrProfMCDCBitmapInstBase);170 __ISA(InstrProfMCDCTVBitmapUpdate, InstrProfMCDCBitmapInstBase);171#undef __ISA172 173 std::vector<174 std::pair<Intrinsic::ID, std::function<bool(const Instruction &)>>>175 LeafIDs = {176 {Intrinsic::instrprof_cover, isInstrProfCoverInst},177 {Intrinsic::instrprof_increment, isInstrProfIncrementInst},178 {Intrinsic::instrprof_increment_step, isInstrProfIncrementInstStep},179 {Intrinsic::instrprof_callsite, isInstrProfCallsite},180 {Intrinsic::instrprof_mcdc_parameters,181 isInstrProfMCDCBitmapParameters},182 {Intrinsic::instrprof_mcdc_tvbitmap_update,183 isInstrProfMCDCTVBitmapUpdate},184 {Intrinsic::instrprof_timestamp, isInstrProfTimestampInst},185 {Intrinsic::instrprof_value_profile, isInstrProfValueProfileInst}};186 for (const auto &[ID, Checker] : LeafIDs) {187 auto *Intr = makeIntrinsic(ID);188 EXPECT_TRUE(Checker(*Intr));189 }190}191 192// Check that getFnAttributes for intrinsics that do not have any function193// attributes correcty returns an empty set.194TEST(IntrinsicAttributes, TestGetFnAttributesBug) {195 using namespace Intrinsic;196 LLVMContext Context;197 AttributeSet AS = getFnAttributes(Context, experimental_guard);198 EXPECT_FALSE(AS.hasAttributes());199}200} // end namespace201