[SandboxIR] Implement Operator (#112805)

This patch implements sandboxir::Operator mirroring llvm::Operator.
This commit is contained in:
vporpo
2024-10-18 08:14:14 -07:00
committed by GitHub
parent 00d30bd61e
commit 54566ba523
4 changed files with 153 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
//===- Operator.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_OPERATOR_H
#define LLVM_SANDBOXIR_OPERATOR_H
#include "llvm/IR/Operator.h"
#include "llvm/SandboxIR/Instruction.h"
#include "llvm/SandboxIR/User.h"
namespace llvm::sandboxir {
class Operator : public User {
public:
// The Operator class is intended to be used as a utility, and is never itself
// instantiated.
Operator() = delete;
void *operator new(size_t s) = delete;
static bool classof(const Instruction *) { return true; }
static bool classof(const ConstantExpr *) { return true; }
static bool classof(const Value *From) {
return llvm::Operator::classof(From->Val);
}
bool hasPoisonGeneratingFlags() const {
return cast<llvm::Operator>(Val)->hasPoisonGeneratingFlags();
}
};
class OverflowingBinaryOperator : public Operator {
public:
bool hasNoUnsignedWrap() const {
return cast<llvm::OverflowingBinaryOperator>(Val)->hasNoUnsignedWrap();
}
bool hasNoSignedWrap() const {
return cast<llvm::OverflowingBinaryOperator>(Val)->hasNoSignedWrap();
}
unsigned getNoWrapKind() const {
return cast<llvm::OverflowingBinaryOperator>(Val)->getNoWrapKind();
}
static bool classof(const Instruction *From) {
return llvm::OverflowingBinaryOperator::classof(
cast<llvm::Instruction>(From->Val));
}
static bool classof(const ConstantExpr *From) {
return llvm::OverflowingBinaryOperator::classof(
cast<llvm::ConstantExpr>(From->Val));
}
static bool classof(const Value *From) {
return llvm::OverflowingBinaryOperator::classof(From->Val);
}
};
} // namespace llvm::sandboxir
#endif // LLVM_SANDBOXIR_OPERATOR_H

View File

@@ -28,6 +28,8 @@ class Module;
class UnaryInstruction;
class CmpInst;
class IntrinsicInst;
class Operator;
class OverflowingBinaryOperator;
/// Iterator for the `Use` edges of a Value's users.
/// \Returns a `Use` when dereferenced.
@@ -158,6 +160,8 @@ protected:
friend class Utils; // For `Val`.
friend class Module; // For `Val`.
friend class IntrinsicInst; // For `Val`.
friend class Operator; // For `Val`.
friend class OverflowingBinaryOperator; // For `Val`.
// Region needs to manipulate metadata in the underlying LLVM Value, we don't
// expose metadata in sandboxir.
friend class Region;

View File

@@ -9,6 +9,7 @@ add_llvm_unittest(SandboxIRTests
IntrinsicInstTest.cpp
PassTest.cpp
RegionTest.cpp
OperatorTest.cpp
SandboxIRTest.cpp
TrackerTest.cpp
TypesTest.cpp

View File

@@ -0,0 +1,88 @@
//===- OperatorTest.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/Operator.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/SandboxIR/Context.h"
#include "llvm/SandboxIR/Function.h"
#include "llvm/SandboxIR/Instruction.h"
#include "llvm/SandboxIR/Module.h"
#include "llvm/SandboxIR/Value.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"
using namespace llvm;
struct OperatorTest : public testing::Test {
LLVMContext C;
std::unique_ptr<Module> M;
void parseIR(LLVMContext &C, const char *IR) {
SMDiagnostic Err;
M = parseAssemblyString(IR, Err, C);
if (!M)
Err.print("OperatorTest", 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(OperatorTest, Operator) {
parseIR(C, R"IR(
define void @foo(i8 %v1) {
%add0 = add i8 %v1, 42
%add1 = add nuw i8 %v1, 42
ret void
}
)IR");
llvm::Function *LLVMF = &*M->getFunction("foo");
sandboxir::Context Ctx(C);
sandboxir::Function *F = Ctx.createFunction(LLVMF);
auto *BB = &*F->begin();
auto It = BB->begin();
auto *OperatorI0 = cast<sandboxir::Operator>(&*It++);
auto *OperatorI1 = cast<sandboxir::Operator>(&*It++);
EXPECT_FALSE(OperatorI0->hasPoisonGeneratingFlags());
EXPECT_TRUE(OperatorI1->hasPoisonGeneratingFlags());
}
TEST_F(OperatorTest, OverflowingBinaryOperator) {
parseIR(C, R"IR(
define void @foo(i8 %v1) {
%add = add i8 %v1, 42
%addNSW = add nsw i8 %v1, 42
%addNUW = add nuw i8 %v1, 42
ret void
}
)IR");
llvm::Function *LLVMF = &*M->getFunction("foo");
sandboxir::Context Ctx(C);
sandboxir::Function *F = Ctx.createFunction(LLVMF);
auto *BB = &*F->begin();
auto It = BB->begin();
auto *Add = cast<sandboxir::OverflowingBinaryOperator>(&*It++);
auto *AddNSW = cast<sandboxir::OverflowingBinaryOperator>(&*It++);
auto *AddNUW = cast<sandboxir::OverflowingBinaryOperator>(&*It++);
EXPECT_FALSE(Add->hasNoUnsignedWrap());
EXPECT_FALSE(Add->hasNoSignedWrap());
EXPECT_EQ(Add->getNoWrapKind(), llvm::OverflowingBinaryOperator::AnyWrap);
EXPECT_FALSE(AddNSW->hasNoUnsignedWrap());
EXPECT_TRUE(AddNSW->hasNoSignedWrap());
EXPECT_EQ(AddNSW->getNoWrapKind(),
llvm::OverflowingBinaryOperator::NoSignedWrap);
EXPECT_TRUE(AddNUW->hasNoUnsignedWrap());
EXPECT_FALSE(AddNUW->hasNoSignedWrap());
EXPECT_EQ(AddNUW->getNoWrapKind(),
llvm::OverflowingBinaryOperator::NoUnsignedWrap);
}