diff --git a/llvm/include/llvm/SandboxIR/Instruction.h b/llvm/include/llvm/SandboxIR/Instruction.h index c17188ce90c7d..ccbcae6cec744 100644 --- a/llvm/include/llvm/SandboxIR/Instruction.h +++ b/llvm/include/llvm/SandboxIR/Instruction.h @@ -18,6 +18,9 @@ namespace llvm::sandboxir { +// Forward declaration for MSVC. +class IntrinsicInst; + /// A sandboxir::User with operands, opcode and linked with previous/next /// instructions in an instruction list. class Instruction : public User { @@ -1422,13 +1425,13 @@ class CallBase : public SingleLLVMInstructionImpl { bool isInlineAsm() const { return cast(Val)->isInlineAsm(); } }; -class CallInst final : public CallBase { +class CallInst : public CallBase { /// Use Context::createCallInst(). Don't call the /// constructor directly. CallInst(llvm::Instruction *I, Context &Ctx) : CallBase(ClassID::Call, Opcode::Call, I, Ctx) {} - friend class Context; // For accessing the constructor in - // create*() + friend class Context; // For accessing the constructor in create*() + friend class IntrinsicInst; // For constructor public: static CallInst *create(FunctionType *FTy, Value *Func, diff --git a/llvm/include/llvm/SandboxIR/IntrinsicInst.h b/llvm/include/llvm/SandboxIR/IntrinsicInst.h new file mode 100644 index 0000000000000..33d3746f15119 --- /dev/null +++ b/llvm/include/llvm/SandboxIR/IntrinsicInst.h @@ -0,0 +1,44 @@ +//===- IntrinsicInst.h ------------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SANDBOXIR_INTRINSICINST_H +#define LLVM_SANDBOXIR_INTRINSICINST_H + +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/SandboxIR/Instruction.h" + +namespace llvm::sandboxir { + +class IntrinsicInst : public CallInst { + IntrinsicInst(llvm::IntrinsicInst *I, Context &Ctx) : CallInst(I, Ctx) {} + +public: + Intrinsic::ID getIntrinsicID() const { + return cast(Val)->getIntrinsicID(); + } + bool isAssociative() const { + return cast(Val)->isAssociative(); + } + bool isCommutative() const { + return cast(Val)->isCommutative(); + } + bool isAssumeLikeIntrinsic() const { + return cast(Val)->isAssumeLikeIntrinsic(); + } + static bool mayLowerToFunctionCall(Intrinsic::ID IID) { + return llvm::IntrinsicInst::mayLowerToFunctionCall(IID); + } + static bool classof(const Value *V) { + auto *LLVMV = V->Val; + return isa(LLVMV); + } +}; + +} // namespace llvm::sandboxir + +#endif // LLVM_SANDBOXIR_INTRINSICINST_H diff --git a/llvm/include/llvm/SandboxIR/Value.h b/llvm/include/llvm/SandboxIR/Value.h index b28f0e664f80b..3509f2a8d8365 100644 --- a/llvm/include/llvm/SandboxIR/Value.h +++ b/llvm/include/llvm/SandboxIR/Value.h @@ -27,6 +27,7 @@ class GlobalObject; class Module; class UnaryInstruction; class CmpInst; +class IntrinsicInst; /// Iterator for the `Use` edges of a Value's users. /// \Returns a `Use` when dereferenced. @@ -156,6 +157,7 @@ class Value { friend class ConstantExpr; // For `Val`. friend class Utils; // For `Val`. friend class Module; // For `Val`. + friend class IntrinsicInst; // For `Val`. // Region needs to manipulate metadata in the underlying LLVM Value, we don't // expose metadata in sandboxir. friend class Region; diff --git a/llvm/unittests/SandboxIR/CMakeLists.txt b/llvm/unittests/SandboxIR/CMakeLists.txt index 622496ada567f..1e83bda7a1f6d 100644 --- a/llvm/unittests/SandboxIR/CMakeLists.txt +++ b/llvm/unittests/SandboxIR/CMakeLists.txt @@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS ) add_llvm_unittest(SandboxIRTests + IntrinsicInstTest.cpp PassTest.cpp RegionTest.cpp SandboxIRTest.cpp diff --git a/llvm/unittests/SandboxIR/IntrinsicInstTest.cpp b/llvm/unittests/SandboxIR/IntrinsicInstTest.cpp new file mode 100644 index 0000000000000..2272cfc114616 --- /dev/null +++ b/llvm/unittests/SandboxIR/IntrinsicInstTest.cpp @@ -0,0 +1,88 @@ +//===- IntrinsicInstTest.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/SandboxIR/IntrinsicInst.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Value.h" +#include "llvm/SandboxIR/Context.h" +#include "llvm/SandboxIR/Function.h" +#include "llvm/Support/SourceMgr.h" +#include "gtest/gtest.h" + +using namespace llvm; + +struct IntrinsicInstTest : public testing::Test { + LLVMContext C; + std::unique_ptr M; + + void parseIR(LLVMContext &C, const char *IR) { + SMDiagnostic Err; + M = parseAssemblyString(IR, Err, C); + if (!M) + Err.print("SandboxIRTest", errs()); + } + BasicBlock *getBasicBlockByName(Function &F, StringRef Name) { + for (BasicBlock &BB : F) + if (BB.getName() == Name) + return &BB; + llvm_unreachable("Expected to find basic block!"); + } +}; + +TEST_F(IntrinsicInstTest, Basic) { + parseIR(C, R"IR( +declare void @llvm.sideeffect() +declare void @llvm.assume(i1) +declare i8 @llvm.uadd.sat.i8(i8, i8) +declare i8 @llvm.smax.i8(i8, i8) + +define void @foo(i8 %v1, i1 %cond) { + call void @llvm.sideeffect() + call void @llvm.assume(i1 %cond) + call i8 @llvm.uadd.sat.i8(i8 %v1, i8 %v1) + call i8 @llvm.smax.i8(i8 %v1, i8 %v1) + ret void +} +)IR"); + + llvm::Function *LLVMF = &*M->getFunction("foo"); + auto *LLVMBB = &*LLVMF->begin(); + auto LLVMIt = LLVMBB->begin(); + + sandboxir::Context Ctx(C); + sandboxir::Function *F = Ctx.createFunction(LLVMF); + auto *BB = &*F->begin(); + auto It = BB->begin(); + auto ItE = BB->getTerminator()->getIterator(); + for (; It != ItE; ++It, ++LLVMIt) { + auto *I = &*It; + auto *LLVMI = &*LLVMIt; + // Check classof(). + EXPECT_TRUE(isa(I)); + // Check getIntrinsicID(). + EXPECT_EQ(cast(I)->getIntrinsicID(), + cast(LLVMI)->getIntrinsicID()); + // Check isAssociative(). + EXPECT_EQ(cast(I)->isAssociative(), + cast(LLVMI)->isAssociative()); + // Check isCommutative(). + EXPECT_EQ(cast(I)->isCommutative(), + cast(LLVMI)->isCommutative()); + // Check isAssumeLikeIntrinsic(). + EXPECT_EQ(cast(I)->isAssumeLikeIntrinsic(), + cast(LLVMI)->isAssumeLikeIntrinsic()); + // Check mayLowerToFunctionCall(). + auto ID = cast(I)->getIntrinsicID(); + EXPECT_EQ(sandboxir::IntrinsicInst::mayLowerToFunctionCall(ID), + llvm::IntrinsicInst::mayLowerToFunctionCall(ID)); + } +}