Skip to content

Commit 3403b59

Browse files
[SandboxIR] Implement PHINodes (llvm#101111)
This patch implements sandboxir::PHINode which mirrors llvm::PHINode. Based almost entirely on work by vporpo.
1 parent 65d3c22 commit 3403b59

File tree

8 files changed

+587
-0
lines changed

8 files changed

+587
-0
lines changed

llvm/include/llvm/SandboxIR/SandboxIR.h

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ class Value {
226226
friend class CallBrInst; // For getting `Val`.
227227
friend class GetElementPtrInst; // For getting `Val`.
228228
friend class CastInst; // For getting `Val`.
229+
friend class PHINode; // For getting `Val`.
229230

230231
/// All values point to the context.
231232
Context &Ctx;
@@ -618,6 +619,7 @@ class Instruction : public sandboxir::User {
618619
friend class CallBrInst; // For getTopmostLLVMInstruction().
619620
friend class GetElementPtrInst; // For getTopmostLLVMInstruction().
620621
friend class CastInst; // For getTopmostLLVMInstruction().
622+
friend class PHINode; // For getTopmostLLVMInstruction().
621623

622624
/// \Returns the LLVM IR Instructions that this SandboxIR maps to in program
623625
/// order.
@@ -1515,6 +1517,100 @@ class IntToPtrInst final : public CastInst {
15151517
#endif // NDEBUG
15161518
};
15171519

1520+
class PHINode final : public Instruction {
1521+
/// Use Context::createPHINode(). Don't call the constructor directly.
1522+
PHINode(llvm::PHINode *PHI, Context &Ctx)
1523+
: Instruction(ClassID::PHI, Opcode::PHI, PHI, Ctx) {}
1524+
friend Context; // for PHINode()
1525+
Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final {
1526+
return getOperandUseDefault(OpIdx, Verify);
1527+
}
1528+
SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const final {
1529+
return {cast<llvm::Instruction>(Val)};
1530+
}
1531+
/// Helper for mapped_iterator.
1532+
struct LLVMBBToBB {
1533+
Context &Ctx;
1534+
LLVMBBToBB(Context &Ctx) : Ctx(Ctx) {}
1535+
BasicBlock *operator()(llvm::BasicBlock *LLVMBB) const;
1536+
};
1537+
1538+
public:
1539+
unsigned getUseOperandNo(const Use &Use) const final {
1540+
return getUseOperandNoDefault(Use);
1541+
}
1542+
unsigned getNumOfIRInstrs() const final { return 1u; }
1543+
static PHINode *create(Type *Ty, unsigned NumReservedValues,
1544+
Instruction *InsertBefore, Context &Ctx,
1545+
const Twine &Name = "");
1546+
/// For isa/dyn_cast.
1547+
static bool classof(const Value *From);
1548+
1549+
using const_block_iterator =
1550+
mapped_iterator<llvm::PHINode::const_block_iterator, LLVMBBToBB>;
1551+
1552+
const_block_iterator block_begin() const {
1553+
LLVMBBToBB BBGetter(Ctx);
1554+
return const_block_iterator(cast<llvm::PHINode>(Val)->block_begin(),
1555+
BBGetter);
1556+
}
1557+
const_block_iterator block_end() const {
1558+
LLVMBBToBB BBGetter(Ctx);
1559+
return const_block_iterator(cast<llvm::PHINode>(Val)->block_end(),
1560+
BBGetter);
1561+
}
1562+
iterator_range<const_block_iterator> blocks() const {
1563+
return make_range(block_begin(), block_end());
1564+
}
1565+
1566+
op_range incoming_values() { return operands(); }
1567+
1568+
const_op_range incoming_values() const { return operands(); }
1569+
1570+
unsigned getNumIncomingValues() const {
1571+
return cast<llvm::PHINode>(Val)->getNumIncomingValues();
1572+
}
1573+
Value *getIncomingValue(unsigned Idx) const;
1574+
void setIncomingValue(unsigned Idx, Value *V);
1575+
static unsigned getOperandNumForIncomingValue(unsigned Idx) {
1576+
return llvm::PHINode::getOperandNumForIncomingValue(Idx);
1577+
}
1578+
static unsigned getIncomingValueNumForOperand(unsigned Idx) {
1579+
return llvm::PHINode::getIncomingValueNumForOperand(Idx);
1580+
}
1581+
BasicBlock *getIncomingBlock(unsigned Idx) const;
1582+
BasicBlock *getIncomingBlock(const Use &U) const;
1583+
1584+
void setIncomingBlock(unsigned Idx, BasicBlock *BB);
1585+
1586+
void addIncoming(Value *V, BasicBlock *BB);
1587+
1588+
Value *removeIncomingValue(unsigned Idx);
1589+
Value *removeIncomingValue(BasicBlock *BB);
1590+
1591+
int getBasicBlockIndex(const BasicBlock *BB) const;
1592+
Value *getIncomingValueForBlock(const BasicBlock *BB) const;
1593+
1594+
Value *hasConstantValue() const;
1595+
1596+
bool hasConstantOrUndefValue() const {
1597+
return cast<llvm::PHINode>(Val)->hasConstantOrUndefValue();
1598+
}
1599+
bool isComplete() const { return cast<llvm::PHINode>(Val)->isComplete(); }
1600+
// TODO: Implement the below functions:
1601+
// void replaceIncomingBlockWith (const BasicBlock *Old, BasicBlock *New);
1602+
// void copyIncomingBlocks(iterator_range<const_block_iterator> BBRange,
1603+
// uint32_t ToIdx = 0)
1604+
// void removeIncomingValueIf(function_ref< bool(unsigned)> Predicate,
1605+
// bool DeletePHIIfEmpty=true)
1606+
#ifndef NDEBUG
1607+
void verify() const final {
1608+
assert(isa<llvm::PHINode>(Val) && "Expected PHINode!");
1609+
}
1610+
void dump(raw_ostream &OS) const override;
1611+
LLVM_DUMP_METHOD void dump() const override;
1612+
#endif
1613+
};
15181614
class PtrToIntInst final : public CastInst {
15191615
public:
15201616
static Value *create(Value *Src, Type *DestTy, BBIterator WhereIt,
@@ -1700,6 +1796,8 @@ class Context {
17001796
friend GetElementPtrInst; // For createGetElementPtrInst()
17011797
CastInst *createCastInst(llvm::CastInst *I);
17021798
friend CastInst; // For createCastInst()
1799+
PHINode *createPHINode(llvm::PHINode *I);
1800+
friend PHINode; // For createPHINode()
17031801

17041802
public:
17051803
Context(LLVMContext &LLVMCtx)

llvm/include/llvm/SandboxIR/SandboxIRValues.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ DEF_INSTR(Cast, OPCODES(\
5858
OP(BitCast) \
5959
OP(AddrSpaceCast) \
6060
), CastInst)
61+
DEF_INSTR(PHI, OP(PHI), PHINode)
62+
6163
// clang-format on
6264
#ifdef DEF_VALUE
6365
#undef DEF_VALUE

llvm/include/llvm/SandboxIR/Tracker.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,64 @@ class UseSet : public IRChangeBase {
102102
#endif
103103
};
104104

105+
class PHISetIncoming : public IRChangeBase {
106+
PHINode &PHI;
107+
unsigned Idx;
108+
PointerUnion<Value *, BasicBlock *> OrigValueOrBB;
109+
110+
public:
111+
enum class What {
112+
Value,
113+
Block,
114+
};
115+
PHISetIncoming(PHINode &PHI, unsigned Idx, What What, Tracker &Tracker);
116+
void revert() final;
117+
void accept() final {}
118+
#ifndef NDEBUG
119+
void dump(raw_ostream &OS) const final {
120+
dumpCommon(OS);
121+
OS << "PHISetIncoming";
122+
}
123+
LLVM_DUMP_METHOD void dump() const final;
124+
#endif
125+
};
126+
127+
class PHIRemoveIncoming : public IRChangeBase {
128+
PHINode &PHI;
129+
unsigned RemovedIdx;
130+
Value *RemovedV;
131+
BasicBlock *RemovedBB;
132+
133+
public:
134+
PHIRemoveIncoming(PHINode &PHI, unsigned RemovedIdx, Tracker &Tracker);
135+
void revert() final;
136+
void accept() final {}
137+
#ifndef NDEBUG
138+
void dump(raw_ostream &OS) const final {
139+
dumpCommon(OS);
140+
OS << "PHISetIncoming";
141+
}
142+
LLVM_DUMP_METHOD void dump() const final;
143+
#endif
144+
};
145+
146+
class PHIAddIncoming : public IRChangeBase {
147+
PHINode &PHI;
148+
unsigned Idx;
149+
150+
public:
151+
PHIAddIncoming(PHINode &PHI, Tracker &Tracker);
152+
void revert() final;
153+
void accept() final {}
154+
#ifndef NDEBUG
155+
void dump(raw_ostream &OS) const final {
156+
dumpCommon(OS);
157+
OS << "PHISetIncoming";
158+
}
159+
LLVM_DUMP_METHOD void dump() const final;
160+
#endif
161+
};
162+
105163
/// Tracks swapping a Use with another Use.
106164
class UseSwap : public IRChangeBase {
107165
Use ThisUse;

llvm/include/llvm/SandboxIR/Use.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class Context;
2222
class Value;
2323
class User;
2424
class CallBase;
25+
class PHINode;
2526

2627
/// Represents a Def-use/Use-def edge in SandboxIR.
2728
/// NOTE: Unlike llvm::Use, this is not an integral part of the use-def chains.
@@ -43,6 +44,7 @@ class Use {
4344
friend class UserUseIterator; // For accessing members
4445
friend class CallBase; // For LLVMUse
4546
friend class CallBrInst; // For constructor
47+
friend class PHINode; // For LLVMUse
4648

4749
public:
4850
operator Value *() const { return get(); }

llvm/lib/SandboxIR/SandboxIR.cpp

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,95 @@ void GetElementPtrInst::dump() const {
10621062
}
10631063
#endif // NDEBUG
10641064

1065+
BasicBlock *PHINode::LLVMBBToBB::operator()(llvm::BasicBlock *LLVMBB) const {
1066+
return cast<BasicBlock>(Ctx.getValue(LLVMBB));
1067+
}
1068+
1069+
PHINode *PHINode::create(Type *Ty, unsigned NumReservedValues,
1070+
Instruction *InsertBefore, Context &Ctx,
1071+
const Twine &Name) {
1072+
llvm::PHINode *NewPHI = llvm::PHINode::Create(
1073+
Ty, NumReservedValues, Name, InsertBefore->getTopmostLLVMInstruction());
1074+
return Ctx.createPHINode(NewPHI);
1075+
}
1076+
1077+
bool PHINode::classof(const Value *From) {
1078+
return From->getSubclassID() == ClassID::PHI;
1079+
}
1080+
1081+
Value *PHINode::getIncomingValue(unsigned Idx) const {
1082+
return Ctx.getValue(cast<llvm::PHINode>(Val)->getIncomingValue(Idx));
1083+
}
1084+
void PHINode::setIncomingValue(unsigned Idx, Value *V) {
1085+
auto &Tracker = Ctx.getTracker();
1086+
if (Tracker.isTracking())
1087+
Tracker.track(std::make_unique<PHISetIncoming>(
1088+
*this, Idx, PHISetIncoming::What::Value, Tracker));
1089+
1090+
cast<llvm::PHINode>(Val)->setIncomingValue(Idx, V->Val);
1091+
}
1092+
BasicBlock *PHINode::getIncomingBlock(unsigned Idx) const {
1093+
return cast<BasicBlock>(
1094+
Ctx.getValue(cast<llvm::PHINode>(Val)->getIncomingBlock(Idx)));
1095+
}
1096+
BasicBlock *PHINode::getIncomingBlock(const Use &U) const {
1097+
llvm::Use *LLVMUse = U.LLVMUse;
1098+
llvm::BasicBlock *BB = cast<llvm::PHINode>(Val)->getIncomingBlock(*LLVMUse);
1099+
return cast<BasicBlock>(Ctx.getValue(BB));
1100+
}
1101+
void PHINode::setIncomingBlock(unsigned Idx, BasicBlock *BB) {
1102+
auto &Tracker = Ctx.getTracker();
1103+
if (Tracker.isTracking())
1104+
Tracker.track(std::make_unique<PHISetIncoming>(
1105+
*this, Idx, PHISetIncoming::What::Block, Tracker));
1106+
cast<llvm::PHINode>(Val)->setIncomingBlock(Idx,
1107+
cast<llvm::BasicBlock>(BB->Val));
1108+
}
1109+
void PHINode::addIncoming(Value *V, BasicBlock *BB) {
1110+
auto &Tracker = Ctx.getTracker();
1111+
if (Tracker.isTracking())
1112+
Tracker.track(std::make_unique<PHIAddIncoming>(*this, Tracker));
1113+
1114+
cast<llvm::PHINode>(Val)->addIncoming(V->Val,
1115+
cast<llvm::BasicBlock>(BB->Val));
1116+
}
1117+
Value *PHINode::removeIncomingValue(unsigned Idx) {
1118+
auto &Tracker = Ctx.getTracker();
1119+
if (Tracker.isTracking())
1120+
Tracker.track(std::make_unique<PHIRemoveIncoming>(*this, Idx, Tracker));
1121+
1122+
llvm::Value *LLVMV =
1123+
cast<llvm::PHINode>(Val)->removeIncomingValue(Idx,
1124+
/*DeletePHIIfEmpty=*/false);
1125+
return Ctx.getValue(LLVMV);
1126+
}
1127+
Value *PHINode::removeIncomingValue(BasicBlock *BB) {
1128+
auto &Tracker = Ctx.getTracker();
1129+
if (Tracker.isTracking())
1130+
Tracker.track(std::make_unique<PHIRemoveIncoming>(
1131+
*this, getBasicBlockIndex(BB), Tracker));
1132+
1133+
auto *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
1134+
llvm::Value *LLVMV =
1135+
cast<llvm::PHINode>(Val)->removeIncomingValue(LLVMBB,
1136+
/*DeletePHIIfEmpty=*/false);
1137+
return Ctx.getValue(LLVMV);
1138+
}
1139+
int PHINode::getBasicBlockIndex(const BasicBlock *BB) const {
1140+
auto *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
1141+
return cast<llvm::PHINode>(Val)->getBasicBlockIndex(LLVMBB);
1142+
}
1143+
Value *PHINode::getIncomingValueForBlock(const BasicBlock *BB) const {
1144+
auto *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
1145+
llvm::Value *LLVMV =
1146+
cast<llvm::PHINode>(Val)->getIncomingValueForBlock(LLVMBB);
1147+
return Ctx.getValue(LLVMV);
1148+
}
1149+
Value *PHINode::hasConstantValue() const {
1150+
llvm::Value *LLVMV = cast<llvm::PHINode>(Val)->hasConstantValue();
1151+
return LLVMV != nullptr ? Ctx.getValue(LLVMV) : nullptr;
1152+
}
1153+
10651154
static llvm::Instruction::CastOps getLLVMCastOp(Instruction::Opcode Opc) {
10661155
switch (Opc) {
10671156
case Instruction::Opcode::ZExt:
@@ -1272,6 +1361,16 @@ Value *PtrToIntInst::create(Value *Src, Type *DestTy, BasicBlock *InsertAtEnd,
12721361
}
12731362

12741363
#ifndef NDEBUG
1364+
void PHINode::dump(raw_ostream &OS) const {
1365+
dumpCommonPrefix(OS);
1366+
dumpCommonSuffix(OS);
1367+
}
1368+
1369+
void PHINode::dump() const {
1370+
dump(dbgs());
1371+
dbgs() << "\n";
1372+
}
1373+
12751374
void PtrToIntInst::dump(raw_ostream &OS) const {
12761375
dumpCommonPrefix(OS);
12771376
dumpCommonSuffix(OS);
@@ -1537,6 +1636,11 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
15371636
It->second = std::unique_ptr<CastInst>(new CastInst(LLVMCast, *this));
15381637
return It->second.get();
15391638
}
1639+
case llvm::Instruction::PHI: {
1640+
auto *LLVMPhi = cast<llvm::PHINode>(LLVMV);
1641+
It->second = std::unique_ptr<PHINode>(new PHINode(LLVMPhi, *this));
1642+
return It->second.get();
1643+
}
15401644
default:
15411645
break;
15421646
}
@@ -1606,6 +1710,10 @@ CastInst *Context::createCastInst(llvm::CastInst *I) {
16061710
auto NewPtr = std::unique_ptr<CastInst>(new CastInst(I, *this));
16071711
return cast<CastInst>(registerValue(std::move(NewPtr)));
16081712
}
1713+
PHINode *Context::createPHINode(llvm::PHINode *I) {
1714+
auto NewPtr = std::unique_ptr<PHINode>(new PHINode(I, *this));
1715+
return cast<PHINode>(registerValue(std::move(NewPtr)));
1716+
}
16091717

16101718
Value *Context::getValue(llvm::Value *V) const {
16111719
auto It = LLVMValueToValueMap.find(V);

0 commit comments

Comments
 (0)