Skip to content

Commit 6cdf596

Browse files
authored
[InstCombine] If inst in unreachable refers to an inst change it to poison (#78444)
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 a return instruction in an unreachable basic block to poison if it refers to the instruction, allowing the instruction to be properly processed. Fixes #65107.
1 parent 9f45c5e commit 6cdf596

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+
/// are returned in \p 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
@@ -3241,9 +3241,12 @@ void InstCombinerImpl::handleUnreachableFrom(
32413241
MadeIRChange = true;
32423242
}
32433243

3244-
// RemoveDIs: to match behaviour in dbg.value mode, drop debug-info on
3245-
// terminator too.
3246-
BB->getTerminator()->dropDbgValues();
3244+
SmallVector<Value *> Changed;
3245+
if (handleUnreachableTerminator(BB->getTerminator(), Changed)) {
3246+
MadeIRChange = true;
3247+
for (Value *V : Changed)
3248+
addToWorklist(cast<Instruction>(V));
3249+
}
32473250

32483251
// Handle potentially dead successors.
32493252
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 *> 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)