Skip to content

Commit a092ee4

Browse files
committed
[InstCombine] If Inst in unreachable refers to Inst change it to poison (#65107)
Instructions in unreachable basic blocks are removed, but terminators are not. In this case, even instructions that are only referenced by a terminator, such as a return instruction, cannot be processed properly. This patch changes the operand of terminator instruction in an unreachable basic block to poison if it refers to the instruction, allowing the instruction to be properly processed.
1 parent a9f39ff commit a092ee4

File tree

6 files changed

+164
-8
lines changed

6 files changed

+164
-8
lines changed

llvm/include/llvm/Transforms/Utils/Local.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,10 @@ Value *salvageDebugInfoImpl(Instruction &I, uint64_t CurrentLocOps,
357357
bool replaceAllDbgUsesWith(Instruction &From, Value &To, Instruction &DomPoint,
358358
DominatorTree &DT);
359359

360+
/// if the terminator in an unreachable basic block refers to an instruction
361+
/// transform it to poison.
362+
void handleUnreachableTerminator(Instruction *I);
363+
360364
/// Remove all instructions from a basic block other than its terminator
361365
/// and any present EH pad instructions. Returns a pair where the first element
362366
/// is the number of instructions (excluding debug info intrinsics) that have

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3100,9 +3100,8 @@ void InstCombinerImpl::handleUnreachableFrom(
31003100
MadeIRChange = true;
31013101
}
31023102

3103-
// RemoveDIs: to match behaviour in dbg.value mode, drop debug-info on
3104-
// terminator too.
3105-
BB->getTerminator()->dropDbgValues();
3103+
// if terminator refer instruction, transform it into poison.
3104+
handleUnreachableTerminator(BB->getTerminator());
31063105

31073106
// Handle potentially dead successors.
31083107
for (BasicBlock *Succ : successors(BB))

llvm/lib/Transforms/Utils/Local.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2770,15 +2770,31 @@ bool llvm::replaceAllDbgUsesWith(Instruction &From, Value &To,
27702770
return false;
27712771
}
27722772

2773+
void llvm::handleUnreachableTerminator(Instruction *I) {
2774+
// RemoveDIs: erase debug-info on this instruction manually.
2775+
I->dropDbgValues();
2776+
unsigned Opcode = I->getOpcode();
2777+
if (Opcode >= Instruction::Ret && Opcode <= Instruction::Invoke &&
2778+
I->getNumOperands() > 0) {
2779+
unsigned OpNum = isa<InvokeInst>(I) ? I->getNumOperands() - 1 : 0;
2780+
Value *Op = I->getOperand(OpNum);
2781+
if (Op == nullptr || !isa<Instruction>(Op) || isa<Constant>(Op))
2782+
return;
2783+
I->setOperand(OpNum, PoisonValue::get(Op->getType()));
2784+
}
2785+
}
2786+
27732787
std::pair<unsigned, unsigned>
27742788
llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) {
27752789
unsigned NumDeadInst = 0;
27762790
unsigned NumDeadDbgInst = 0;
27772791
// Delete the instructions backwards, as it has a reduced likelihood of
27782792
// having to update as many def-use and use-def chains.
27792793
Instruction *EndInst = BB->getTerminator(); // Last not to be deleted.
2780-
// RemoveDIs: erasing debug-info must be done manually.
2781-
EndInst->dropDbgValues();
2794+
2795+
// if terminator refer instruction, transform it into poison.
2796+
handleUnreachableTerminator(EndInst);
2797+
27822798
while (EndInst != &BB->front()) {
27832799
// Delete the next to last instruction.
27842800
Instruction *Inst = &*--EndInst->getIterator();

llvm/test/Transforms/InstCombine/phi-select-constant.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,11 @@ end:
140140
define i16 @sink_to_unreachable_crash(i1 %a) {
141141
; CHECK-LABEL: @sink_to_unreachable_crash(
142142
; CHECK-NEXT: entry:
143-
; CHECK-NEXT: [[S:%.*]] = select i1 [[A:%.*]], i16 0, i16 5
144143
; CHECK-NEXT: br label [[INF_LOOP:%.*]]
145144
; CHECK: inf_loop:
146145
; CHECK-NEXT: br label [[INF_LOOP]]
147146
; CHECK: unreachable:
148-
; CHECK-NEXT: ret i16 [[S]]
147+
; CHECK-NEXT: ret i16 poison
149148
;
150149
entry:
151150
%s = select i1 %a, i16 0, i16 5

llvm/test/Transforms/InstCombine/pr63791.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ define void @y() {
1717
; CHECK: for.cond5.preheader.i:
1818
; CHECK-NEXT: br i1 false, label [[FOR_INC19_I:%.*]], label [[FOR_COND1_LOOPEXIT_I:%.*]]
1919
; CHECK: for.inc19.i:
20-
; CHECK-NEXT: br i1 false, label [[FOR_INC19_I]], label [[FOR_COND1_LOOPEXIT_I]]
20+
; CHECK-NEXT: br i1 poison, label [[FOR_INC19_I]], label [[FOR_COND1_LOOPEXIT_I]]
2121
;
2222
entry:
2323
br label %for.cond.i

llvm/test/Transforms/InstCombine/sink_to_unreachable.ll

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,141 @@ bb3:
157157
%p = phi i32 [0, %bb1], [%a, %bb2]
158158
ret i32 %p
159159
}
160+
161+
define i1 @sink_to_unreachable_ret(i16 %X) {
162+
; CHECK-LABEL: @sink_to_unreachable_ret(
163+
; CHECK-NEXT: entry:
164+
; CHECK-NEXT: br label [[LOOP:%.*]]
165+
; CHECK: loop:
166+
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
167+
; CHECK: unreach:
168+
; CHECK-NEXT: ret i1 poison
169+
;
170+
entry:
171+
br label %loop
172+
173+
loop:
174+
%p = icmp sgt i16 %X, 16
175+
br i1 true, label %loop, label %unreach
176+
177+
unreach:
178+
ret i1 %p
179+
}
180+
181+
define void @sink_to_unreachable_condbr(i16 %X) {
182+
; CHECK-LABEL: @sink_to_unreachable_condbr(
183+
; CHECK-NEXT: entry:
184+
; CHECK-NEXT: br label [[LOOP:%.*]]
185+
; CHECK: loop:
186+
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
187+
; CHECK: unreach:
188+
; CHECK-NEXT: br i1 poison, label [[DUMMY:%.*]], label [[LOOP]]
189+
; CHECK: dummy:
190+
; CHECK-NEXT: unreachable
191+
;
192+
entry:
193+
br label %loop
194+
195+
loop:
196+
%p = icmp sgt i16 %X, 16
197+
br i1 true, label %loop, label %unreach
198+
199+
unreach:
200+
br i1 %p, label %dummy, label %loop
201+
202+
dummy:
203+
unreachable
204+
}
205+
206+
define void @sink_to_unreachable_switch(i16 %X) {
207+
; CHECK-LABEL: @sink_to_unreachable_switch(
208+
; CHECK-NEXT: entry:
209+
; CHECK-NEXT: br label [[LOOP:%.*]]
210+
; CHECK: loop:
211+
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
212+
; CHECK: unreach:
213+
; CHECK-NEXT: switch i16 poison, label [[UNREACH_RET:%.*]] [
214+
; CHECK-NEXT: ]
215+
; CHECK: unreach.ret:
216+
; CHECK-NEXT: unreachable
217+
;
218+
entry:
219+
br label %loop
220+
221+
loop:
222+
%quantum = srem i16 %X, 32
223+
br i1 true, label %loop, label %unreach
224+
225+
unreach:
226+
switch i16 %quantum, label %unreach.ret []
227+
228+
unreach.ret:
229+
unreachable
230+
}
231+
232+
define void @sink_to_unreachable_indirectbr(ptr %Ptr) {
233+
; CHECK-LABEL: @sink_to_unreachable_indirectbr(
234+
; CHECK-NEXT: entry:
235+
; CHECK-NEXT: br label [[LOOP:%.*]]
236+
; CHECK: loop:
237+
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
238+
; CHECK: unreach:
239+
; CHECK-NEXT: indirectbr ptr poison, [label %loop]
240+
;
241+
entry:
242+
br label %loop
243+
244+
loop:
245+
%gep = getelementptr inbounds ptr, ptr %Ptr, i16 1
246+
br i1 true, label %loop, label %unreach
247+
248+
unreach:
249+
indirectbr ptr %gep, [label %loop]
250+
}
251+
252+
define void @sink_to_unreachable_invoke(ptr %Ptr) personality ptr @__CxxFrameHandler3 {
253+
; CHECK-LABEL: @sink_to_unreachable_invoke(
254+
; CHECK-NEXT: entry:
255+
; CHECK-NEXT: br label [[LOOP:%.*]]
256+
; CHECK: loop:
257+
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
258+
; CHECK: unreach:
259+
; CHECK-NEXT: invoke void poison(i1 false)
260+
; CHECK-NEXT: to label [[DUMMY:%.*]] unwind label [[ICATCH_DISPATCH:%.*]]
261+
; CHECK: icatch.dispatch:
262+
; CHECK-NEXT: [[TMP1:%.*]] = catchswitch within none [label %icatch] unwind to caller
263+
; CHECK: icatch:
264+
; CHECK-NEXT: [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null, i32 64, ptr null]
265+
; CHECK-NEXT: catchret from [[TMP2]] to label [[DUMMY2:%.*]]
266+
; CHECK: dummy:
267+
; CHECK-NEXT: ret void
268+
; CHECK: dummy2:
269+
; CHECK-NEXT: ret void
270+
;
271+
entry:
272+
br label %loop
273+
274+
loop:
275+
%gep = getelementptr inbounds ptr, ptr %Ptr, i16 1
276+
br i1 true, label %loop, label %unreach
277+
278+
unreach:
279+
invoke void %gep(i1 false)
280+
to label %dummy unwind label %icatch.dispatch
281+
282+
icatch.dispatch:
283+
%tmp1 = catchswitch within none [label %icatch] unwind to caller
284+
285+
icatch:
286+
%tmp2 = catchpad within %tmp1 [ptr null, i32 64, ptr null]
287+
catchret from %tmp2 to label %dummy2
288+
289+
dummy:
290+
ret void
291+
292+
dummy2:
293+
ret void
294+
}
295+
296+
declare void @may_throw()
297+
declare i32 @__CxxFrameHandler3(...)

0 commit comments

Comments
 (0)