Skip to content

Commit 4cdc9da

Browse files
committed
Renable r314928
Eliminate inttype phi with inttoptr/ptrtoint. This version fixed a bug in finding the matching phi -- the order of the incoming blocks may be different (triggered in self build on Windows). A new test case is added. llvm-svn: 315272
1 parent c04a91a commit 4cdc9da

File tree

9 files changed

+767
-0
lines changed

9 files changed

+767
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,10 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner
670670
Instruction *FoldPHIArgGEPIntoPHI(PHINode &PN);
671671
Instruction *FoldPHIArgLoadIntoPHI(PHINode &PN);
672672
Instruction *FoldPHIArgZextsIntoPHI(PHINode &PN);
673+
/// If an integer typed PHI has only one use which is an IntToPtr operation,
674+
/// replace the PHI with an existing pointer typed PHI if it exists. Otherwise
675+
/// insert a new pointer typed PHI and replace the original one.
676+
Instruction *FoldIntegerTypedPHI(PHINode &PN);
673677

674678
/// Helper function for FoldPHIArgXIntoPHI() to set debug location for the
675679
/// folded operation.

llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,238 @@ void InstCombiner::PHIArgMergedDebugLoc(Instruction *Inst, PHINode &PN) {
4040
}
4141
}
4242

43+
// Replace Integer typed PHI PN if the PHI's value is used as a pointer value.
44+
// If there is an existing pointer typed PHI that produces the same value as PN,
45+
// replace PN and the IntToPtr operation with it. Otherwise, synthesize a new
46+
// PHI node:
47+
//
48+
// Case-1:
49+
// bb1:
50+
// int_init = PtrToInt(ptr_init)
51+
// br label %bb2
52+
// bb2:
53+
// int_val = PHI([int_init, %bb1], [int_val_inc, %bb2]
54+
// ptr_val = PHI([ptr_init, %bb1], [ptr_val_inc, %bb2]
55+
// ptr_val2 = IntToPtr(int_val)
56+
// ...
57+
// use(ptr_val2)
58+
// ptr_val_inc = ...
59+
// inc_val_inc = PtrToInt(ptr_val_inc)
60+
//
61+
// ==>
62+
// bb1:
63+
// br label %bb2
64+
// bb2:
65+
// ptr_val = PHI([ptr_init, %bb1], [ptr_val_inc, %bb2]
66+
// ...
67+
// use(ptr_val)
68+
// ptr_val_inc = ...
69+
//
70+
// Case-2:
71+
// bb1:
72+
// int_ptr = BitCast(ptr_ptr)
73+
// int_init = Load(int_ptr)
74+
// br label %bb2
75+
// bb2:
76+
// int_val = PHI([int_init, %bb1], [int_val_inc, %bb2]
77+
// ptr_val2 = IntToPtr(int_val)
78+
// ...
79+
// use(ptr_val2)
80+
// ptr_val_inc = ...
81+
// inc_val_inc = PtrToInt(ptr_val_inc)
82+
// ==>
83+
// bb1:
84+
// ptr_init = Load(ptr_ptr)
85+
// br label %bb2
86+
// bb2:
87+
// ptr_val = PHI([ptr_init, %bb1], [ptr_val_inc, %bb2]
88+
// ...
89+
// use(ptr_val)
90+
// ptr_val_inc = ...
91+
// ...
92+
//
93+
Instruction *InstCombiner::FoldIntegerTypedPHI(PHINode &PN) {
94+
if (!PN.getType()->isIntegerTy())
95+
return nullptr;
96+
if (!PN.hasOneUse())
97+
return nullptr;
98+
99+
auto *IntToPtr = dyn_cast<IntToPtrInst>(PN.user_back());
100+
if (!IntToPtr)
101+
return nullptr;
102+
103+
// Check if the pointer is actually used as pointer:
104+
auto HasPointerUse = [](Instruction *IIP) {
105+
for (User *U : IIP->users()) {
106+
Value *Ptr = nullptr;
107+
if (LoadInst *LoadI = dyn_cast<LoadInst>(U)) {
108+
Ptr = LoadI->getPointerOperand();
109+
} else if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
110+
Ptr = SI->getPointerOperand();
111+
} else if (GetElementPtrInst *GI = dyn_cast<GetElementPtrInst>(U)) {
112+
Ptr = GI->getPointerOperand();
113+
}
114+
115+
if (Ptr && Ptr == IIP)
116+
return true;
117+
}
118+
return false;
119+
};
120+
121+
if (!HasPointerUse(IntToPtr))
122+
return nullptr;
123+
124+
if (DL.getPointerSizeInBits(IntToPtr->getAddressSpace()) !=
125+
DL.getTypeSizeInBits(IntToPtr->getOperand(0)->getType()))
126+
return nullptr;
127+
128+
SmallVector<Value *, 4> AvailablePtrVals;
129+
for (unsigned i = 0; i != PN.getNumIncomingValues(); ++i) {
130+
Value *Arg = PN.getIncomingValue(i);
131+
132+
// First look backward:
133+
if (auto *PI = dyn_cast<PtrToIntInst>(Arg)) {
134+
AvailablePtrVals.emplace_back(PI->getOperand(0));
135+
continue;
136+
}
137+
138+
// Next look forward:
139+
Value *ArgIntToPtr = nullptr;
140+
for (User *U : Arg->users()) {
141+
if (isa<IntToPtrInst>(U) && U->getType() == IntToPtr->getType() &&
142+
(DT.dominates(cast<Instruction>(U), PN.getIncomingBlock(i)) ||
143+
cast<Instruction>(U)->getParent() == PN.getIncomingBlock(i))) {
144+
ArgIntToPtr = U;
145+
break;
146+
}
147+
}
148+
149+
if (ArgIntToPtr) {
150+
AvailablePtrVals.emplace_back(ArgIntToPtr);
151+
continue;
152+
}
153+
154+
// If Arg is defined by a PHI, allow it. This will also create
155+
// more opportunities iteratively.
156+
if (isa<PHINode>(Arg)) {
157+
AvailablePtrVals.emplace_back(Arg);
158+
continue;
159+
}
160+
161+
// For a single use integer load:
162+
auto *LoadI = dyn_cast<LoadInst>(Arg);
163+
if (!LoadI)
164+
return nullptr;
165+
166+
if (!LoadI->hasOneUse())
167+
return nullptr;
168+
169+
// Push the integer typed Load instruction into the available
170+
// value set, and fix it up later when the pointer typed PHI
171+
// is synthesized.
172+
AvailablePtrVals.emplace_back(LoadI);
173+
}
174+
175+
// Now search for a matching PHI
176+
auto *BB = PN.getParent();
177+
assert(AvailablePtrVals.size() == PN.getNumIncomingValues() &&
178+
"Not enough available ptr typed incoming values");
179+
PHINode *MatchingPtrPHI = nullptr;
180+
for (auto II = BB->begin(), EI = BasicBlock::iterator(BB->getFirstNonPHI());
181+
II != EI; II++) {
182+
PHINode *PtrPHI = dyn_cast<PHINode>(II);
183+
if (!PtrPHI || PtrPHI == &PN || PtrPHI->getType() != IntToPtr->getType())
184+
continue;
185+
MatchingPtrPHI = PtrPHI;
186+
for (unsigned i = 0; i != PtrPHI->getNumIncomingValues(); ++i) {
187+
if (AvailablePtrVals[i] !=
188+
PtrPHI->getIncomingValueForBlock(PN.getIncomingBlock(i))) {
189+
MatchingPtrPHI = nullptr;
190+
break;
191+
}
192+
}
193+
194+
if (MatchingPtrPHI)
195+
break;
196+
}
197+
198+
if (MatchingPtrPHI) {
199+
assert(MatchingPtrPHI->getType() == IntToPtr->getType() &&
200+
"Phi's Type does not match with IntToPtr");
201+
// The PtrToCast + IntToPtr will be simplified later
202+
return CastInst::CreateBitOrPointerCast(MatchingPtrPHI,
203+
IntToPtr->getOperand(0)->getType());
204+
}
205+
206+
// If it requires a conversion for every PHI operand, do not do it.
207+
if (std::all_of(AvailablePtrVals.begin(), AvailablePtrVals.end(),
208+
[&](Value *V) {
209+
return (V->getType() != IntToPtr->getType()) ||
210+
isa<IntToPtrInst>(V);
211+
}))
212+
return nullptr;
213+
214+
// If any of the operand that requires casting is a terminator
215+
// instruction, do not do it.
216+
if (std::any_of(AvailablePtrVals.begin(), AvailablePtrVals.end(),
217+
[&](Value *V) {
218+
return (V->getType() != IntToPtr->getType()) &&
219+
isa<TerminatorInst>(V);
220+
}))
221+
return nullptr;
222+
223+
PHINode *NewPtrPHI = PHINode::Create(
224+
IntToPtr->getType(), PN.getNumIncomingValues(), PN.getName() + ".ptr");
225+
226+
InsertNewInstBefore(NewPtrPHI, PN);
227+
SmallDenseMap<Value *, Instruction *> Casts;
228+
for (unsigned i = 0; i != PN.getNumIncomingValues(); ++i) {
229+
auto *IncomingBB = PN.getIncomingBlock(i);
230+
auto *IncomingVal = AvailablePtrVals[i];
231+
232+
if (IncomingVal->getType() == IntToPtr->getType()) {
233+
NewPtrPHI->addIncoming(IncomingVal, IncomingBB);
234+
continue;
235+
}
236+
237+
#ifndef NDEBUG
238+
LoadInst *LoadI = dyn_cast<LoadInst>(IncomingVal);
239+
assert((isa<PHINode>(IncomingVal) ||
240+
IncomingVal->getType()->isPointerTy() ||
241+
(LoadI && LoadI->hasOneUse())) &&
242+
"Can not replace LoadInst with multiple uses");
243+
#endif
244+
// Need to insert a BitCast.
245+
// For an integer Load instruction with a single use, the load + IntToPtr
246+
// cast will be simplified into a pointer load:
247+
// %v = load i64, i64* %a.ip, align 8
248+
// %v.cast = inttoptr i64 %v to float **
249+
// ==>
250+
// %v.ptrp = bitcast i64 * %a.ip to float **
251+
// %v.cast = load float *, float ** %v.ptrp, align 8
252+
Instruction *&CI = Casts[IncomingVal];
253+
if (!CI) {
254+
CI = CastInst::CreateBitOrPointerCast(IncomingVal, IntToPtr->getType(),
255+
IncomingVal->getName() + ".ptr");
256+
if (auto *IncomingI = dyn_cast<Instruction>(IncomingVal)) {
257+
BasicBlock::iterator InsertPos(IncomingI);
258+
InsertPos++;
259+
if (isa<PHINode>(IncomingI))
260+
InsertPos = IncomingI->getParent()->getFirstInsertionPt();
261+
InsertNewInstBefore(CI, *InsertPos);
262+
} else {
263+
auto *InsertBB = &IncomingBB->getParent()->getEntryBlock();
264+
InsertNewInstBefore(CI, *InsertBB->getFirstInsertionPt());
265+
}
266+
}
267+
NewPtrPHI->addIncoming(CI, IncomingBB);
268+
}
269+
270+
// The PtrToCast + IntToPtr will be simplified later
271+
return CastInst::CreateBitOrPointerCast(NewPtrPHI,
272+
IntToPtr->getOperand(0)->getType());
273+
}
274+
43275
/// If we have something like phi [add (a,b), add(a,c)] and if a/b/c and the
44276
/// adds all have a single use, turn this into a phi and a single binop.
45277
Instruction *InstCombiner::FoldPHIArgBinOpIntoPHI(PHINode &PN) {
@@ -903,6 +1135,9 @@ Instruction *InstCombiner::visitPHINode(PHINode &PN) {
9031135
// this PHI only has a single use (a PHI), and if that PHI only has one use (a
9041136
// PHI)... break the cycle.
9051137
if (PN.hasOneUse()) {
1138+
if (Instruction *Result = FoldIntegerTypedPHI(PN))
1139+
return Result;
1140+
9061141
Instruction *PHIUser = cast<Instruction>(PN.user_back());
9071142
if (PHINode *PU = dyn_cast<PHINode>(PHIUser)) {
9081143
SmallPtrSet<PHINode*, 16> PotentiallyDeadPHIs;

0 commit comments

Comments
 (0)