Skip to content

Commit

Permalink
[SandboxIR] Implement UndefValue (llvm#107628)
Browse files Browse the repository at this point in the history
This patch implements sandboxir::UndefValue mirroring llvm::UndefValue.
  • Loading branch information
vporpo authored Sep 9, 2024
1 parent 33c1325 commit ae02211
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 6 deletions.
61 changes: 55 additions & 6 deletions llvm/include/llvm/SandboxIR/SandboxIR.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ class Value {
friend class ConstantStruct; // For `Val`.
friend class ConstantAggregateZero; // For `Val`.
friend class ConstantPointerNull; // For `Val`.
friend class UndefValue; // For `Val`.
friend class PoisonValue; // For `Val`.

/// All values point to the context.
Expand Down Expand Up @@ -1020,10 +1021,61 @@ class ConstantPointerNull final : public Constant {
#endif
};

// TODO: Inherit from UndefValue.
class PoisonValue final : public Constant {
// TODO: Inherit from ConstantData.
class UndefValue : public Constant {
protected:
UndefValue(llvm::UndefValue *C, Context &Ctx)
: Constant(ClassID::UndefValue, C, Ctx) {}
UndefValue(ClassID ID, llvm::Constant *C, Context &Ctx)
: Constant(ID, C, Ctx) {}
friend class Context; // For constructor.

public:
/// Static factory methods - Return an 'undef' object of the specified type.
static UndefValue *get(Type *T);

/// If this Undef has array or vector type, return a undef with the right
/// element type.
UndefValue *getSequentialElement() const;

/// If this undef has struct type, return a undef with the right element type
/// for the specified element.
UndefValue *getStructElement(unsigned Elt) const;

/// Return an undef of the right value for the specified GEP index if we can,
/// otherwise return null (e.g. if C is a ConstantExpr).
UndefValue *getElementValue(Constant *C) const;

/// Return an undef of the right value for the specified GEP index.
UndefValue *getElementValue(unsigned Idx) const;

/// Return the number of elements in the array, vector, or struct.
unsigned getNumElements() const {
return cast<llvm::UndefValue>(Val)->getNumElements();
}

/// For isa/dyn_cast.
static bool classof(const sandboxir::Value *From) {
return From->getSubclassID() == ClassID::UndefValue ||
From->getSubclassID() == ClassID::PoisonValue;
}
unsigned getUseOperandNo(const Use &Use) const final {
llvm_unreachable("UndefValue has no operands!");
}
#ifndef NDEBUG
void verify() const override {
assert(isa<llvm::UndefValue>(Val) && "Expected an UndefValue!");
}
void dumpOS(raw_ostream &OS) const override {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
#endif
};

class PoisonValue final : public UndefValue {
PoisonValue(llvm::PoisonValue *C, Context &Ctx)
: Constant(ClassID::PoisonValue, C, Ctx) {}
: UndefValue(ClassID::PoisonValue, C, Ctx) {}
friend class Context; // For constructor.

public:
Expand All @@ -1049,9 +1101,6 @@ class PoisonValue final : public Constant {
static bool classof(const sandboxir::Value *From) {
return From->getSubclassID() == ClassID::PoisonValue;
}
unsigned getUseOperandNo(const Use &Use) const final {
llvm_unreachable("PoisonValue has no operands!");
}
#ifndef NDEBUG
void verify() const override {
assert(isa<llvm::PoisonValue>(Val) && "Expected a PoisonValue!");
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/SandboxIR/SandboxIRValues.def
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ DEF_CONST(ConstantStruct, ConstantStruct)
DEF_CONST(ConstantVector, ConstantVector)
DEF_CONST(ConstantAggregateZero, ConstantAggregateZero)
DEF_CONST(ConstantPointerNull, ConstantPointerNull)
DEF_CONST(UndefValue, UndefValue)
DEF_CONST(PoisonValue, PoisonValue)

#ifndef DEF_INSTR
Expand Down
30 changes: 30 additions & 0 deletions llvm/lib/SandboxIR/SandboxIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2437,6 +2437,32 @@ PointerType *ConstantPointerNull::getType() const {
Ctx.getType(cast<llvm::ConstantPointerNull>(Val)->getType()));
}

UndefValue *UndefValue::get(Type *T) {
auto *LLVMC = llvm::UndefValue::get(T->LLVMTy);
return cast<UndefValue>(T->getContext().getOrCreateConstant(LLVMC));
}

UndefValue *UndefValue::getSequentialElement() const {
return cast<UndefValue>(Ctx.getOrCreateConstant(
cast<llvm::UndefValue>(Val)->getSequentialElement()));
}

UndefValue *UndefValue::getStructElement(unsigned Elt) const {
return cast<UndefValue>(Ctx.getOrCreateConstant(
cast<llvm::UndefValue>(Val)->getStructElement(Elt)));
}

UndefValue *UndefValue::getElementValue(Constant *C) const {
return cast<UndefValue>(
Ctx.getOrCreateConstant(cast<llvm::UndefValue>(Val)->getElementValue(
cast<llvm::Constant>(C->Val))));
}

UndefValue *UndefValue::getElementValue(unsigned Idx) const {
return cast<UndefValue>(Ctx.getOrCreateConstant(
cast<llvm::UndefValue>(Val)->getElementValue(Idx)));
}

PoisonValue *PoisonValue::get(Type *T) {
auto *LLVMC = llvm::PoisonValue::get(T->LLVMTy);
return cast<PoisonValue>(T->getContext().getOrCreateConstant(LLVMC));
Expand Down Expand Up @@ -2580,6 +2606,10 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
It->second = std::unique_ptr<PoisonValue>(
new PoisonValue(cast<llvm::PoisonValue>(C), *this));
return It->second.get();
case llvm::Value::UndefValueVal:
It->second = std::unique_ptr<UndefValue>(
new UndefValue(cast<llvm::UndefValue>(C), *this));
return It->second.get();
case llvm::Value::ConstantArrayVal:
It->second = std::unique_ptr<ConstantArray>(
new ConstantArray(cast<llvm::ConstantArray>(C), *this));
Expand Down
59 changes: 59 additions & 0 deletions llvm/unittests/SandboxIR/SandboxIRTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ define void @foo() {
// Check classof() and creation.
auto *Poison = cast<sandboxir::PoisonValue>(I0->getOperand(0));
EXPECT_EQ(Poison->getType(), Int32Ty);
EXPECT_TRUE(isa<sandboxir::UndefValue>(Poison)); // Poison is Undef
// Check get().
auto *NewPoison = sandboxir::PoisonValue::get(Int32Ty);
EXPECT_EQ(NewPoison, Poison);
Expand Down Expand Up @@ -670,6 +671,64 @@ define void @foo() {
sandboxir::PoisonValue::get(Int8Ty));
}

TEST_F(SandboxIRTest, UndefValue) {
parseIR(C, R"IR(
define void @foo() {
%i0 = add i32 undef, undef
%i1 = add <2 x i32> undef, undef
%i2 = extractvalue {i32, i8} undef, 0
ret void
}
)IR");
Function &LLVMF = *M->getFunction("foo");
sandboxir::Context Ctx(C);

auto &F = *Ctx.createFunction(&LLVMF);
auto &BB = *F.begin();
auto It = BB.begin();
auto *I0 = &*It++;
auto *I1 = &*It++;
auto *I2 = &*It++;
auto *Int32Ty = sandboxir::Type::getInt32Ty(Ctx);
auto *Int8Ty = sandboxir::Type::getInt8Ty(Ctx);
auto *Zero32 = sandboxir::ConstantInt::get(Int32Ty, 0u);
auto *One32 = sandboxir::ConstantInt::get(Int32Ty, 1u);

// Check classof() and creation.
auto *Undef = cast<sandboxir::UndefValue>(I0->getOperand(0));
EXPECT_EQ(Undef->getType(), Int32Ty);
EXPECT_FALSE(isa<sandboxir::PoisonValue>(Undef)); // Undef is not Poison
// Check get().
auto *NewUndef = sandboxir::UndefValue::get(Int32Ty);
EXPECT_EQ(NewUndef, Undef);
auto *NewUndef2 =
sandboxir::UndefValue::get(sandboxir::PointerType::get(Ctx, 0u));
EXPECT_NE(NewUndef2, Undef);
// Check getSequentialElement().
auto *UndefVector = cast<sandboxir::UndefValue>(I1->getOperand(0));
auto *SeqElm = UndefVector->getSequentialElement();
EXPECT_EQ(SeqElm->getType(), Int32Ty);
// Check getStructElement().
auto *UndefStruct = cast<sandboxir::UndefValue>(I2->getOperand(0));
auto *StrElm0 = UndefStruct->getStructElement(0);
auto *StrElm1 = UndefStruct->getStructElement(1);
EXPECT_EQ(StrElm0->getType(), Int32Ty);
EXPECT_EQ(StrElm1->getType(), Int8Ty);
// Check getElementValue(Constant)
EXPECT_EQ(UndefStruct->getElementValue(Zero32),
sandboxir::UndefValue::get(Int32Ty));
EXPECT_EQ(UndefStruct->getElementValue(One32),
sandboxir::UndefValue::get(Int8Ty));
// Check getElementValue(unsigned)
EXPECT_EQ(UndefStruct->getElementValue(0u),
sandboxir::UndefValue::get(Int32Ty));
EXPECT_EQ(UndefStruct->getElementValue(1u),
sandboxir::UndefValue::get(Int8Ty));
// Check getNumElements().
EXPECT_EQ(UndefVector->getNumElements(), 2u);
EXPECT_EQ(UndefStruct->getNumElements(), 2u);
}

TEST_F(SandboxIRTest, Use) {
parseIR(C, R"IR(
define i32 @foo(i32 %v0, i32 %v1) {
Expand Down

0 comments on commit ae02211

Please sign in to comment.