From ae02211eaef305f957b419e5c39499aa472b956e Mon Sep 17 00:00:00 2001 From: vporpo Date: Mon, 9 Sep 2024 16:52:54 -0700 Subject: [PATCH] [SandboxIR] Implement UndefValue (#107628) This patch implements sandboxir::UndefValue mirroring llvm::UndefValue. --- llvm/include/llvm/SandboxIR/SandboxIR.h | 61 +++++++++++++++++-- .../llvm/SandboxIR/SandboxIRValues.def | 1 + llvm/lib/SandboxIR/SandboxIR.cpp | 30 +++++++++ llvm/unittests/SandboxIR/SandboxIRTest.cpp | 59 ++++++++++++++++++ 4 files changed, 145 insertions(+), 6 deletions(-) diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h index bede697670a281..8f025f7257b39f 100644 --- a/llvm/include/llvm/SandboxIR/SandboxIR.h +++ b/llvm/include/llvm/SandboxIR/SandboxIR.h @@ -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. @@ -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(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(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: @@ -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(Val) && "Expected a PoisonValue!"); diff --git a/llvm/include/llvm/SandboxIR/SandboxIRValues.def b/llvm/include/llvm/SandboxIR/SandboxIRValues.def index 5acf7bfe08f5ae..459226216703d9 100644 --- a/llvm/include/llvm/SandboxIR/SandboxIRValues.def +++ b/llvm/include/llvm/SandboxIR/SandboxIRValues.def @@ -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 diff --git a/llvm/lib/SandboxIR/SandboxIR.cpp b/llvm/lib/SandboxIR/SandboxIR.cpp index 4ba3ab7a0ce43b..07472d1bff47be 100644 --- a/llvm/lib/SandboxIR/SandboxIR.cpp +++ b/llvm/lib/SandboxIR/SandboxIR.cpp @@ -2437,6 +2437,32 @@ PointerType *ConstantPointerNull::getType() const { Ctx.getType(cast(Val)->getType())); } +UndefValue *UndefValue::get(Type *T) { + auto *LLVMC = llvm::UndefValue::get(T->LLVMTy); + return cast(T->getContext().getOrCreateConstant(LLVMC)); +} + +UndefValue *UndefValue::getSequentialElement() const { + return cast(Ctx.getOrCreateConstant( + cast(Val)->getSequentialElement())); +} + +UndefValue *UndefValue::getStructElement(unsigned Elt) const { + return cast(Ctx.getOrCreateConstant( + cast(Val)->getStructElement(Elt))); +} + +UndefValue *UndefValue::getElementValue(Constant *C) const { + return cast( + Ctx.getOrCreateConstant(cast(Val)->getElementValue( + cast(C->Val)))); +} + +UndefValue *UndefValue::getElementValue(unsigned Idx) const { + return cast(Ctx.getOrCreateConstant( + cast(Val)->getElementValue(Idx))); +} + PoisonValue *PoisonValue::get(Type *T) { auto *LLVMC = llvm::PoisonValue::get(T->LLVMTy); return cast(T->getContext().getOrCreateConstant(LLVMC)); @@ -2580,6 +2606,10 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) { It->second = std::unique_ptr( new PoisonValue(cast(C), *this)); return It->second.get(); + case llvm::Value::UndefValueVal: + It->second = std::unique_ptr( + new UndefValue(cast(C), *this)); + return It->second.get(); case llvm::Value::ConstantArrayVal: It->second = std::unique_ptr( new ConstantArray(cast(C), *this)); diff --git a/llvm/unittests/SandboxIR/SandboxIRTest.cpp b/llvm/unittests/SandboxIR/SandboxIRTest.cpp index 1c0b9f83ab629a..1b939b4d047aaf 100644 --- a/llvm/unittests/SandboxIR/SandboxIRTest.cpp +++ b/llvm/unittests/SandboxIR/SandboxIRTest.cpp @@ -642,6 +642,7 @@ define void @foo() { // Check classof() and creation. auto *Poison = cast(I0->getOperand(0)); EXPECT_EQ(Poison->getType(), Int32Ty); + EXPECT_TRUE(isa(Poison)); // Poison is Undef // Check get(). auto *NewPoison = sandboxir::PoisonValue::get(Int32Ty); EXPECT_EQ(NewPoison, Poison); @@ -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(I0->getOperand(0)); + EXPECT_EQ(Undef->getType(), Int32Ty); + EXPECT_FALSE(isa(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(I1->getOperand(0)); + auto *SeqElm = UndefVector->getSequentialElement(); + EXPECT_EQ(SeqElm->getType(), Int32Ty); + // Check getStructElement(). + auto *UndefStruct = cast(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) {