Skip to content

Commit 98e272f

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 38c706e commit 98e272f

File tree

7 files changed

+246
-8
lines changed

7 files changed

+246
-8
lines changed

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

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

360+
/// If a terminator in an unreachable basic block has an operand of type
361+
/// Instruction, transform it into poison. Return true if any operands
362+
/// are changed to poison. Original Values prior to being changed to poison
363+
/// be returned to PoisonedValues.
364+
bool handleUnreachableTerminator(Instruction *I,
365+
SmallVectorImpl<Value *> &PoisonedValues);
366+
360367
/// Remove all instructions from a basic block other than its terminator
361368
/// and any present EH pad instructions. Returns a pair where the first element
362369
/// is the number of instructions (excluding debug info intrinsics) that have

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3231,9 +3231,12 @@ void InstCombinerImpl::handleUnreachableFrom(
32313231
MadeIRChange = true;
32323232
}
32333233

3234-
// RemoveDIs: to match behaviour in dbg.value mode, drop debug-info on
3235-
// terminator too.
3236-
BB->getTerminator()->dropDbgValues();
3234+
SmallVector<Value *, 4> Changed;
3235+
if (handleUnreachableTerminator(BB->getTerminator(), Changed)) {
3236+
MadeIRChange = true;
3237+
for (Value *V : Changed)
3238+
addToWorklist(cast<Instruction>(V));
3239+
}
32373240

32383241
// Handle potentially dead successors.
32393242
for (BasicBlock *Succ : successors(BB))

llvm/lib/Transforms/Utils/Local.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2762,15 +2762,33 @@ bool llvm::replaceAllDbgUsesWith(Instruction &From, Value &To,
27622762
return false;
27632763
}
27642764

2765+
bool llvm::handleUnreachableTerminator(
2766+
Instruction *I, SmallVectorImpl<Value *> &PoisonedValues) {
2767+
bool Changed = false;
2768+
// RemoveDIs: erase debug-info on this instruction manually.
2769+
I->dropDbgValues();
2770+
for (Use &U : I->operands()) {
2771+
Value *Op = U.get();
2772+
if (isa<Instruction>(Op) && !Op->getType()->isTokenTy()) {
2773+
U.set(PoisonValue::get(Op->getType()));
2774+
PoisonedValues.push_back(Op);
2775+
Changed = true;
2776+
}
2777+
}
2778+
2779+
return Changed;
2780+
}
2781+
27652782
std::pair<unsigned, unsigned>
27662783
llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) {
27672784
unsigned NumDeadInst = 0;
27682785
unsigned NumDeadDbgInst = 0;
27692786
// Delete the instructions backwards, as it has a reduced likelihood of
27702787
// having to update as many def-use and use-def chains.
27712788
Instruction *EndInst = BB->getTerminator(); // Last not to be deleted.
2772-
// RemoveDIs: erasing debug-info must be done manually.
2773-
EndInst->dropDbgValues();
2789+
SmallVector<Value *, 4> Uses;
2790+
handleUnreachableTerminator(EndInst, Uses);
2791+
27742792
while (EndInst != &BB->front()) {
27752793
// Delete the next to last instruction.
27762794
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: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,157 @@ 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: unreach2:
262+
; CHECK-NEXT: invoke void @__CxxFrameHandler3(ptr poison)
263+
; CHECK-NEXT: to label [[DUMMY]] unwind label [[ICATCH_DISPATCH]]
264+
; CHECK: unreach3:
265+
; CHECK-NEXT: [[CLEAN:%.*]] = cleanuppad within none []
266+
; CHECK-NEXT: invoke void @__CxxFrameHandler3(ptr poison) [ "funclet"(token [[CLEAN]]) ]
267+
; CHECK-NEXT: to label [[DUMMY]] unwind label [[ICATCH_DISPATCH]]
268+
; CHECK: icatch.dispatch:
269+
; CHECK-NEXT: [[TMP1:%.*]] = catchswitch within none [label %icatch] unwind to caller
270+
; CHECK: icatch:
271+
; CHECK-NEXT: [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null, i32 64, ptr null]
272+
; CHECK-NEXT: catchret from [[TMP2]] to label [[DUMMY2:%.*]]
273+
; CHECK: dummy:
274+
; CHECK-NEXT: ret void
275+
; CHECK: dummy2:
276+
; CHECK-NEXT: ret void
277+
;
278+
entry:
279+
br label %loop
280+
281+
loop:
282+
%gep = getelementptr inbounds ptr, ptr %Ptr, i16 1
283+
br i1 true, label %loop, label %unreach
284+
285+
unreach:
286+
invoke void %gep(i1 false)
287+
to label %dummy unwind label %icatch.dispatch
288+
289+
unreach2:
290+
invoke void @__CxxFrameHandler3(ptr %gep)
291+
to label %dummy unwind label %icatch.dispatch
292+
293+
unreach3:
294+
%clean = cleanuppad within none []
295+
invoke void @__CxxFrameHandler3(ptr %gep) [ "funclet"(token %clean) ]
296+
to label %dummy unwind label %icatch.dispatch
297+
298+
icatch.dispatch:
299+
%tmp1 = catchswitch within none [label %icatch] unwind to caller
300+
301+
icatch:
302+
%tmp2 = catchpad within %tmp1 [ptr null, i32 64, ptr null]
303+
catchret from %tmp2 to label %dummy2
304+
305+
dummy:
306+
ret void
307+
308+
dummy2:
309+
ret void
310+
}
311+
312+
declare void @may_throw()
313+
declare i32 @__CxxFrameHandler3(...)

llvm/test/Transforms/InstCombine/unreachable-code.ll

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,63 @@ bb2:
540540
br label %bb
541541
}
542542

543+
declare void @invoke(ptr)
544+
declare i32 @__gxx_personality_v0(...)
545+
define void @test(i1 %x) personality ptr @__gxx_personality_v0 {
546+
; CHECK-LABEL: define void @test
547+
; CHECK-SAME: (i1 [[X:%.*]]) personality ptr @__gxx_personality_v0 {
548+
; CHECK-NEXT: entry:
549+
; CHECK-NEXT: br i1 [[X]], label [[IF_ELSE:%.*]], label [[CLEAN1:%.*]]
550+
; CHECK: if.else:
551+
; CHECK-NEXT: store i32 1, ptr undef, align 4
552+
; CHECK-NEXT: invoke void @invoke(ptr poison)
553+
; CHECK-NEXT: to label [[CONT:%.*]] unwind label [[LPAD5:%.*]]
554+
; CHECK: cont:
555+
; CHECK-NEXT: invoke void @invoke(ptr poison)
556+
; CHECK-NEXT: to label [[CLEAN1]] unwind label [[LPAD6:%.*]]
557+
; CHECK: lpad5:
558+
; CHECK-NEXT: [[TMP0:%.*]] = landingpad { ptr, i32 }
559+
; CHECK-NEXT: cleanup
560+
; CHECK-NEXT: br label [[CLEAN1]]
561+
; CHECK: lpad6:
562+
; CHECK-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 }
563+
; CHECK-NEXT: cleanup
564+
; CHECK-NEXT: br label [[CLEAN2:%.*]]
565+
; CHECK: clean1:
566+
; CHECK-NEXT: ret void
567+
; CHECK: clean2:
568+
; CHECK-NEXT: ret void
569+
;
570+
entry:
571+
%ref = alloca ptr
572+
br i1 %x, label %if.else, label %clean1
573+
574+
if.else:
575+
store i32 1, ptr undef
576+
invoke void @invoke(ptr %ref)
577+
to label %cont unwind label %lpad5
578+
579+
cont:
580+
invoke void @invoke(ptr %ref)
581+
to label %clean1 unwind label %lpad6
582+
583+
lpad5:
584+
%13 = landingpad { ptr, i32 }
585+
cleanup
586+
br label %clean1
587+
588+
lpad6:
589+
%14 = landingpad { ptr, i32 }
590+
cleanup
591+
br label %clean2
592+
593+
clean1:
594+
ret void
595+
596+
clean2:
597+
ret void
598+
}
599+
543600
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
544601
; DEFAULT_ITER: {{.*}}
545602
; MAX1: {{.*}}

0 commit comments

Comments
 (0)