Skip to content

Commit 73ffeea

Browse files
authored
[SandboxIR] Implement SelectInst (#99996)
This patch implements sandboxir::SelectInst which mirrors llvm::SelectInst.
1 parent 1eec594 commit 73ffeea

File tree

4 files changed

+190
-0
lines changed

4 files changed

+190
-0
lines changed

llvm/include/llvm/SandboxIR/SandboxIR.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class BasicBlock;
7575
class Context;
7676
class Function;
7777
class Instruction;
78+
class SelectInst;
7879
class LoadInst;
7980
class ReturnInst;
8081
class StoreInst;
@@ -177,6 +178,7 @@ class Value {
177178
friend class Context; // For getting `Val`.
178179
friend class User; // For getting `Val`.
179180
friend class Use; // For getting `Val`.
181+
friend class SelectInst; // For getting `Val`.
180182
friend class LoadInst; // For getting `Val`.
181183
friend class StoreInst; // For getting `Val`.
182184
friend class ReturnInst; // For getting `Val`.
@@ -411,6 +413,8 @@ class Constant : public sandboxir::User {
411413
}
412414

413415
public:
416+
static Constant *createInt(Type *Ty, uint64_t V, Context &Ctx,
417+
bool IsSigned = false);
414418
/// For isa/dyn_cast.
415419
static bool classof(const sandboxir::Value *From) {
416420
return From->getSubclassID() == ClassID::Constant ||
@@ -499,6 +503,7 @@ class Instruction : public sandboxir::User {
499503
/// A SandboxIR Instruction may map to multiple LLVM IR Instruction. This
500504
/// returns its topmost LLVM IR instruction.
501505
llvm::Instruction *getTopmostLLVMInstruction() const;
506+
friend class SelectInst; // For getTopmostLLVMInstruction().
502507
friend class LoadInst; // For getTopmostLLVMInstruction().
503508
friend class StoreInst; // For getTopmostLLVMInstruction().
504509
friend class ReturnInst; // For getTopmostLLVMInstruction().
@@ -566,6 +571,52 @@ class Instruction : public sandboxir::User {
566571
#endif
567572
};
568573

574+
class SelectInst : public Instruction {
575+
/// Use Context::createSelectInst(). Don't call the
576+
/// constructor directly.
577+
SelectInst(llvm::SelectInst *CI, Context &Ctx)
578+
: Instruction(ClassID::Select, Opcode::Select, CI, Ctx) {}
579+
friend Context; // for SelectInst()
580+
Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final {
581+
return getOperandUseDefault(OpIdx, Verify);
582+
}
583+
SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const final {
584+
return {cast<llvm::Instruction>(Val)};
585+
}
586+
static Value *createCommon(Value *Cond, Value *True, Value *False,
587+
const Twine &Name, IRBuilder<> &Builder,
588+
Context &Ctx);
589+
590+
public:
591+
unsigned getUseOperandNo(const Use &Use) const final {
592+
return getUseOperandNoDefault(Use);
593+
}
594+
unsigned getNumOfIRInstrs() const final { return 1u; }
595+
static Value *create(Value *Cond, Value *True, Value *False,
596+
Instruction *InsertBefore, Context &Ctx,
597+
const Twine &Name = "");
598+
static Value *create(Value *Cond, Value *True, Value *False,
599+
BasicBlock *InsertAtEnd, Context &Ctx,
600+
const Twine &Name = "");
601+
Value *getCondition() { return getOperand(0); }
602+
Value *getTrueValue() { return getOperand(1); }
603+
Value *getFalseValue() { return getOperand(2); }
604+
605+
void setCondition(Value *New) { setOperand(0, New); }
606+
void setTrueValue(Value *New) { setOperand(1, New); }
607+
void setFalseValue(Value *New) { setOperand(2, New); }
608+
void swapValues() { cast<llvm::SelectInst>(Val)->swapValues(); }
609+
/// For isa/dyn_cast.
610+
static bool classof(const Value *From);
611+
#ifndef NDEBUG
612+
void verify() const final {
613+
assert(isa<llvm::SelectInst>(Val) && "Expected SelectInst!");
614+
}
615+
void dump(raw_ostream &OS) const override;
616+
LLVM_DUMP_METHOD void dump() const override;
617+
#endif
618+
};
619+
569620
class LoadInst final : public Instruction {
570621
/// Use LoadInst::create() instead of calling the constructor.
571622
LoadInst(llvm::LoadInst *LI, Context &Ctx)
@@ -803,6 +854,11 @@ class Context {
803854
Value *getOrCreateValue(llvm::Value *LLVMV) {
804855
return getOrCreateValueInternal(LLVMV, 0);
805856
}
857+
/// Get or create a sandboxir::Constant from an existing LLVM IR \p LLVMC.
858+
Constant *getOrCreateConstant(llvm::Constant *LLVMC) {
859+
return cast<Constant>(getOrCreateValueInternal(LLVMC, 0));
860+
}
861+
friend class Constant; // For getOrCreateConstant().
806862
/// Create a sandboxir::BasicBlock for an existing LLVM IR \p BB. This will
807863
/// also create all contents of the block.
808864
BasicBlock *createBasicBlock(llvm::BasicBlock *BB);
@@ -812,6 +868,8 @@ class Context {
812868
IRBuilder<ConstantFolder> LLVMIRBuilder;
813869
auto &getLLVMIRBuilder() { return LLVMIRBuilder; }
814870

871+
SelectInst *createSelectInst(llvm::SelectInst *SI);
872+
friend SelectInst; // For createSelectInst()
815873
LoadInst *createLoadInst(llvm::LoadInst *LI);
816874
friend LoadInst; // For createLoadInst()
817875
StoreInst *createStoreInst(llvm::StoreInst *SI);

llvm/include/llvm/SandboxIR/SandboxIRValues.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ DEF_USER(Constant, Constant)
2525
#endif
2626
// ClassID, Opcode(s), Class
2727
DEF_INSTR(Opaque, OP(Opaque), OpaqueInst)
28+
DEF_INSTR(Select, OP(Select), SelectInst)
2829
DEF_INSTR(Load, OP(Load), LoadInst)
2930
DEF_INSTR(Store, OP(Store), StoreInst)
3031
DEF_INSTR(Ret, OP(Ret), ReturnInst)

llvm/lib/SandboxIR/SandboxIR.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,51 @@ void Instruction::dump() const {
455455
}
456456
#endif // NDEBUG
457457

458+
Value *SelectInst::createCommon(Value *Cond, Value *True, Value *False,
459+
const Twine &Name, IRBuilder<> &Builder,
460+
Context &Ctx) {
461+
llvm::Value *NewV =
462+
Builder.CreateSelect(Cond->Val, True->Val, False->Val, Name);
463+
if (auto *NewSI = dyn_cast<llvm::SelectInst>(NewV))
464+
return Ctx.createSelectInst(NewSI);
465+
assert(isa<llvm::Constant>(NewV) && "Expected constant");
466+
return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
467+
}
468+
469+
Value *SelectInst::create(Value *Cond, Value *True, Value *False,
470+
Instruction *InsertBefore, Context &Ctx,
471+
const Twine &Name) {
472+
llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();
473+
auto &Builder = Ctx.getLLVMIRBuilder();
474+
Builder.SetInsertPoint(BeforeIR);
475+
return createCommon(Cond, True, False, Name, Builder, Ctx);
476+
}
477+
478+
Value *SelectInst::create(Value *Cond, Value *True, Value *False,
479+
BasicBlock *InsertAtEnd, Context &Ctx,
480+
const Twine &Name) {
481+
auto *IRInsertAtEnd = cast<llvm::BasicBlock>(InsertAtEnd->Val);
482+
auto &Builder = Ctx.getLLVMIRBuilder();
483+
Builder.SetInsertPoint(IRInsertAtEnd);
484+
return createCommon(Cond, True, False, Name, Builder, Ctx);
485+
}
486+
487+
bool SelectInst::classof(const Value *From) {
488+
return From->getSubclassID() == ClassID::Select;
489+
}
490+
491+
#ifndef NDEBUG
492+
void SelectInst::dump(raw_ostream &OS) const {
493+
dumpCommonPrefix(OS);
494+
dumpCommonSuffix(OS);
495+
}
496+
497+
void SelectInst::dump() const {
498+
dump(dbgs());
499+
dbgs() << "\n";
500+
}
501+
#endif // NDEBUG
502+
458503
LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,
459504
Instruction *InsertBefore, Context &Ctx,
460505
const Twine &Name) {
@@ -592,7 +637,15 @@ void OpaqueInst::dump() const {
592637
dump(dbgs());
593638
dbgs() << "\n";
594639
}
640+
#endif // NDEBUG
641+
642+
Constant *Constant::createInt(Type *Ty, uint64_t V, Context &Ctx,
643+
bool IsSigned) {
644+
llvm::Constant *LLVMC = llvm::ConstantInt::get(Ty, V, IsSigned);
645+
return Ctx.getOrCreateConstant(LLVMC);
646+
}
595647

648+
#ifndef NDEBUG
596649
void Constant::dump(raw_ostream &OS) const {
597650
dumpCommonPrefix(OS);
598651
dumpCommonSuffix(OS);
@@ -700,6 +753,11 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
700753
assert(isa<llvm::Instruction>(LLVMV) && "Expected Instruction");
701754

702755
switch (cast<llvm::Instruction>(LLVMV)->getOpcode()) {
756+
case llvm::Instruction::Select: {
757+
auto *LLVMSel = cast<llvm::SelectInst>(LLVMV);
758+
It->second = std::unique_ptr<SelectInst>(new SelectInst(LLVMSel, *this));
759+
return It->second.get();
760+
}
703761
case llvm::Instruction::Load: {
704762
auto *LLVMLd = cast<llvm::LoadInst>(LLVMV);
705763
It->second = std::unique_ptr<LoadInst>(new LoadInst(LLVMLd, *this));
@@ -733,6 +791,11 @@ BasicBlock *Context::createBasicBlock(llvm::BasicBlock *LLVMBB) {
733791
return BB;
734792
}
735793

794+
SelectInst *Context::createSelectInst(llvm::SelectInst *SI) {
795+
auto NewPtr = std::unique_ptr<SelectInst>(new SelectInst(SI, *this));
796+
return cast<SelectInst>(registerValue(std::move(NewPtr)));
797+
}
798+
736799
LoadInst *Context::createLoadInst(llvm::LoadInst *LI) {
737800
auto NewPtr = std::unique_ptr<LoadInst>(new LoadInst(LI, *this));
738801
return cast<LoadInst>(registerValue(std::move(NewPtr)));

llvm/unittests/SandboxIR/SandboxIRTest.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,74 @@ define void @foo(i8 %v1) {
561561
EXPECT_EQ(I0->getNextNode(), Ret);
562562
}
563563

564+
TEST_F(SandboxIRTest, SelectInst) {
565+
parseIR(C, R"IR(
566+
define void @foo(i1 %c0, i8 %v0, i8 %v1, i1 %c1) {
567+
%sel = select i1 %c0, i8 %v0, i8 %v1
568+
ret void
569+
}
570+
)IR");
571+
llvm::Function *LLVMF = &*M->getFunction("foo");
572+
sandboxir::Context Ctx(C);
573+
sandboxir::Function *F = Ctx.createFunction(LLVMF);
574+
auto *Cond0 = F->getArg(0);
575+
auto *V0 = F->getArg(1);
576+
auto *V1 = F->getArg(2);
577+
auto *Cond1 = F->getArg(3);
578+
auto *BB = &*F->begin();
579+
auto It = BB->begin();
580+
auto *Select = cast<sandboxir::SelectInst>(&*It++);
581+
auto *Ret = &*It++;
582+
583+
// Check getCondition().
584+
EXPECT_EQ(Select->getCondition(), Cond0);
585+
// Check getTrueValue().
586+
EXPECT_EQ(Select->getTrueValue(), V0);
587+
// Check getFalseValue().
588+
EXPECT_EQ(Select->getFalseValue(), V1);
589+
// Check setCondition().
590+
Select->setCondition(Cond1);
591+
EXPECT_EQ(Select->getCondition(), Cond1);
592+
// Check setTrueValue().
593+
Select->setTrueValue(V1);
594+
EXPECT_EQ(Select->getTrueValue(), V1);
595+
// Check setFalseValue().
596+
Select->setFalseValue(V0);
597+
EXPECT_EQ(Select->getFalseValue(), V0);
598+
599+
{
600+
// Check SelectInst::create() InsertBefore.
601+
auto *NewSel = cast<sandboxir::SelectInst>(sandboxir::SelectInst::create(
602+
Cond0, V0, V1, /*InsertBefore=*/Ret, Ctx));
603+
EXPECT_EQ(NewSel->getCondition(), Cond0);
604+
EXPECT_EQ(NewSel->getTrueValue(), V0);
605+
EXPECT_EQ(NewSel->getFalseValue(), V1);
606+
EXPECT_EQ(NewSel->getNextNode(), Ret);
607+
}
608+
{
609+
// Check SelectInst::create() InsertAtEnd.
610+
auto *NewSel = cast<sandboxir::SelectInst>(
611+
sandboxir::SelectInst::create(Cond0, V0, V1, /*InsertAtEnd=*/BB, Ctx));
612+
EXPECT_EQ(NewSel->getCondition(), Cond0);
613+
EXPECT_EQ(NewSel->getTrueValue(), V0);
614+
EXPECT_EQ(NewSel->getFalseValue(), V1);
615+
EXPECT_EQ(NewSel->getPrevNode(), Ret);
616+
}
617+
{
618+
// Check SelectInst::create() Folded.
619+
auto *False =
620+
sandboxir::Constant::createInt(llvm::Type::getInt1Ty(C), 0, Ctx,
621+
/*IsSigned=*/false);
622+
auto *FortyTwo =
623+
sandboxir::Constant::createInt(llvm::Type::getInt1Ty(C), 42, Ctx,
624+
/*IsSigned=*/false);
625+
auto *NewSel =
626+
sandboxir::SelectInst::create(False, FortyTwo, FortyTwo, Ret, Ctx);
627+
EXPECT_TRUE(isa<sandboxir::Constant>(NewSel));
628+
EXPECT_EQ(NewSel, FortyTwo);
629+
}
630+
}
631+
564632
TEST_F(SandboxIRTest, LoadInst) {
565633
parseIR(C, R"IR(
566634
define void @foo(ptr %arg0, ptr %arg1) {

0 commit comments

Comments
 (0)