[SandboxIR] OpaqueValue (#127699)

This patch implements a new subclass of the Value class used for Sandbox
IR Values that we don't support, like metadata or inline asm. The goal
is to never have null sandboxir::Value objects, because this is not the
expected behavior.
This commit is contained in:
vporpo 2025-02-19 11:54:44 -08:00 committed by GitHub
parent 4a411eb4ee
commit 1987f93d03
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 57 additions and 6 deletions

View File

@ -9,6 +9,7 @@
#ifndef LLVM_SANDBOXIR_VALUE_H
#define LLVM_SANDBOXIR_VALUE_H
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Value.h"
#include "llvm/SandboxIR/Use.h"
@ -282,6 +283,28 @@ public:
#endif
};
class OpaqueValue : public Value {
protected:
OpaqueValue(llvm::Value *V, Context &Ctx)
: Value(ClassID::OpaqueValue, V, Ctx) {}
friend class Context; // For constructor.
public:
static bool classof(const Value *From) {
return From->getSubclassID() == ClassID::OpaqueValue;
}
#ifndef NDEBUG
void verify() const override {
assert((isa<llvm::MetadataAsValue>(Val) || isa<llvm::InlineAsm>(Val)) &&
"Expected Metadata or InlineAssembly!");
}
void dumpOS(raw_ostream &OS) const override {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
#endif // NDEBUG
};
} // namespace llvm::sandboxir
#endif // LLVM_SANDBOXIR_VALUE_H

View File

@ -21,6 +21,7 @@
DEF_CONST(Function, Function)
DEF_VALUE(Argument, Argument)
DEF_VALUE(OpaqueValue, OpaqueValue)
DEF_USER(User, User)
DEF_VALUE(Block, BasicBlock)

View File

@ -67,12 +67,6 @@ void BasicBlock::buildBasicBlockFromLLVMIR(llvm::BasicBlock *LLVMBB) {
// Skip instruction's label operands
if (isa<llvm::BasicBlock>(Op))
continue;
// Skip metadata
if (isa<llvm::MetadataAsValue>(Op))
continue;
// Skip asm
if (isa<llvm::InlineAsm>(Op))
continue;
Ctx.getOrCreateValue(Op);
}
}

View File

@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/SandboxIR/Context.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/SandboxIR/Function.h"
#include "llvm/SandboxIR/Instruction.h"
#include "llvm/SandboxIR/Module.h"
@ -169,6 +170,15 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
return SBBB;
return nullptr;
}
// TODO: Move these checks after more common Values, like after Instruction.
if (auto *MD = dyn_cast<llvm::MetadataAsValue>(LLVMV)) {
It->second = std::unique_ptr<OpaqueValue>(new OpaqueValue(MD, *this));
return It->second.get();
}
if (auto *Asm = dyn_cast<llvm::InlineAsm>(LLVMV)) {
It->second = std::unique_ptr<OpaqueValue>(new OpaqueValue(Asm, *this));
return It->second.get();
}
assert(isa<llvm::Instruction>(LLVMV) && "Expected Instruction");
switch (cast<llvm::Instruction>(LLVMV)->getOpcode()) {

View File

@ -6166,3 +6166,26 @@ define void @bar() {
// This should not crash, even though there is already a value for LLVMBar.
Ctx.createFunction(&LLVMBar);
}
TEST_F(SandboxIRTest, OpaqueValue) {
parseIR(C, R"IR(
declare void @bar(metadata)
define void @foo() {
call void @bar(metadata !1)
call void asm "asm", ""()
ret void
}
!1 = !{}
)IR");
Function &LLVMFoo = *M->getFunction("foo");
sandboxir::Context Ctx(C);
auto *F = Ctx.createFunction(&LLVMFoo);
auto *BB = &*F->begin();
auto It = BB->begin();
auto *Call = cast<sandboxir::CallInst>(&*It++);
auto *Op0 = Call->getOperand(0);
EXPECT_TRUE(isa<sandboxir::OpaqueValue>(Op0));
auto *Asm = cast<sandboxir::CallInst>(&*It++);
auto *AsmOp0 = Asm->getOperand(0);
EXPECT_TRUE(isa<sandboxir::OpaqueValue>(AsmOp0));
}