Skip to content

Commit 8baa5bf

Browse files
authored
[DFAJumpThreading] Try harder to avoid cycles in paths. (#169151)
If a threading path has cycles within it then the transformation is not correct. This patch fixes a couple of cases that create such cycles. Fixes #166868
1 parent c2d659b commit 8baa5bf

File tree

3 files changed

+223
-1
lines changed

3 files changed

+223
-1
lines changed

llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,8 +625,12 @@ struct AllSwitchPaths {
625625
NewPath.setDeterminator(PhiBB);
626626
NewPath.setExitValue(C);
627627
// Don't add SwitchBlock at the start, this is handled later.
628-
if (IncomingBB != SwitchBlock)
628+
if (IncomingBB != SwitchBlock) {
629+
// Don't add a cycle to the path.
630+
if (VB.contains(IncomingBB))
631+
continue;
629632
NewPath.push_back(IncomingBB);
633+
}
630634
NewPath.push_back(PhiBB);
631635
Res.push_back(NewPath);
632636
continue;
@@ -815,7 +819,12 @@ struct AllSwitchPaths {
815819

816820
std::vector<ThreadingPath> TempList;
817821
for (const ThreadingPath &Path : PathsToPhiDef) {
822+
SmallPtrSet<BasicBlock *, 32> PathSet(Path.getPath().begin(),
823+
Path.getPath().end());
818824
for (const PathType &PathToSw : PathsToSwitchBB) {
825+
if (any_of(llvm::drop_begin(PathToSw),
826+
[&](const BasicBlock *BB) { return PathSet.contains(BB); }))
827+
continue;
819828
ThreadingPath PathCopy(Path);
820829
PathCopy.appendExcludingFirst(PathToSw);
821830
TempList.push_back(PathCopy);

llvm/test/Transforms/DFAJumpThreading/dfa-jump-threading-analysis.ll

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,5 +246,82 @@ exit:
246246
ret i32 0
247247
}
248248

249+
define i8 @cyclesInPaths1(i1 %call12, i1 %cmp18) {
250+
; CHECK-LABEL: DFA Jump threading: cyclesInPaths1
251+
; CHECK-NOT: <{{.*}}> [{{.*}}]
252+
253+
entry:
254+
br label %switchPhiDef.for.body
255+
256+
switchPhiDef.for.body: ; preds = %detBB2, %entry
257+
%switchPhi.curState = phi i32 [ %curState.1, %detBB2 ], [ 0, %entry ]
258+
br i1 %call12, label %detBB1, label %if.else
259+
260+
if.else: ; preds = %switchPhiDef.for.body
261+
br label %detBB1
262+
263+
detBB1: ; preds = %if.else, %switchPhiDef.for.body
264+
%newState.02 = phi i32 [ 2, %switchPhiDef.for.body ], [ 4, %if.else ]
265+
br i1 %cmp18, label %detBB2, label %if.end20
266+
267+
if.end20: ; preds = %detBB1
268+
br i1 %call12, label %if.end23, label %switchBB
269+
270+
switchBB: ; preds = %if.end20
271+
switch i32 %switchPhi.curState, label %if.end23 [
272+
i32 4, label %ret1
273+
i32 0, label %ret2
274+
]
275+
276+
ret1: ; preds = %switchBB
277+
ret i8 1
278+
279+
ret2: ; preds = %switchBB
280+
ret i8 2
281+
282+
if.end23: ; preds = %switchBB, %if.end20
283+
br label %detBB2
284+
285+
detBB2: ; preds = %if.end23, %detBB1
286+
%curState.1 = phi i32 [ %newState.02, %if.end23 ], [ 0, %detBB1 ]
287+
br label %switchPhiDef.for.body
288+
}
289+
290+
define void @cyclesInPaths2(i1 %tobool5.not.i) {
291+
; CHECK-LABEL: DFA Jump threading: cyclesInPaths2
292+
; CHECK: < sw.bb.i, bb.exit, if.end5, if.end.i > [ 1, bb.exit ]
293+
; CHECK-NEXT: < bb.exit, if.end5, if.end.i > [ 0, bb.exit ]
294+
295+
entry:
296+
br label %if.end5
297+
298+
if.end5: ; preds = %bb.exit, %entry
299+
%P.sroa.8.051 = phi i16 [ %retval.sroa.6.0.i, %bb.exit ], [ 0, %entry ]
300+
call void @foo3()
301+
br i1 %tobool5.not.i, label %if.end.i, label %bb.exit
302+
303+
if.end.i: ; preds = %if.end5
304+
switch i16 %P.sroa.8.051, label %sw.default.i [
305+
i16 1, label %sw.bb.i
306+
i16 0, label %bb.exit
307+
]
308+
309+
sw.bb.i: ; preds = %if.end.i
310+
call void @foo1()
311+
br label %bb.exit
312+
313+
sw.default.i: ; preds = %if.end.i
314+
unreachable
315+
316+
bb.exit: ; preds = %sw.bb.i, %if.end.i, %if.end5
317+
%retval.sroa.6.0.i = phi i16 [ 1, %sw.bb.i ], [ 0, %if.end5 ], [ 0, %if.end.i ]
318+
call void @foo2()
319+
br label %if.end5
320+
}
321+
322+
declare void @foo1()
323+
declare void @foo2()
324+
declare void @foo3()
325+
249326
!0 = !{!"function_entry_count", i32 10}
250327
!1 = !{!"branch_weights", i32 3, i32 5}

llvm/test/Transforms/DFAJumpThreading/dfa-jump-threading-transform.ll

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,142 @@ cleanup: ; preds = %for.inc, %switchblock,
499499
ret i16 0
500500
}
501501

502+
define i8 @cyclesInPaths1(i1 %call12, i1 %cmp18) {
503+
; CHECK-LABEL: @cyclesInPaths1(
504+
; CHECK-NEXT: entry:
505+
; CHECK-NEXT: br label [[SWITCHPHIDEF_FOR_BODY:%.*]]
506+
; CHECK: switchPhiDef.for.body:
507+
; CHECK-NEXT: [[SWITCHPHI_CURSTATE:%.*]] = phi i32 [ [[CURSTATE_1:%.*]], [[DETBB2:%.*]] ], [ 0, [[ENTRY:%.*]] ]
508+
; CHECK-NEXT: br i1 [[CALL12:%.*]], label [[DETBB1:%.*]], label [[IF_ELSE:%.*]]
509+
; CHECK: if.else:
510+
; CHECK-NEXT: br label [[DETBB1]]
511+
; CHECK: detBB1:
512+
; CHECK-NEXT: [[NEWSTATE_02:%.*]] = phi i32 [ 2, [[SWITCHPHIDEF_FOR_BODY]] ], [ 4, [[IF_ELSE]] ]
513+
; CHECK-NEXT: br i1 [[CMP18:%.*]], label [[DETBB2]], label [[IF_END20:%.*]]
514+
; CHECK: if.end20:
515+
; CHECK-NEXT: br i1 [[CALL12]], label [[IF_END23:%.*]], label [[SWITCHBB:%.*]]
516+
; CHECK: switchBB:
517+
; CHECK-NEXT: switch i32 [[SWITCHPHI_CURSTATE]], label [[IF_END23]] [
518+
; CHECK-NEXT: i32 4, label [[RET1:%.*]]
519+
; CHECK-NEXT: i32 0, label [[RET2:%.*]]
520+
; CHECK-NEXT: ]
521+
; CHECK: ret1:
522+
; CHECK-NEXT: ret i8 1
523+
; CHECK: ret2:
524+
; CHECK-NEXT: ret i8 2
525+
; CHECK: if.end23:
526+
; CHECK-NEXT: br label [[DETBB2]]
527+
; CHECK: detBB2:
528+
; CHECK-NEXT: [[CURSTATE_1]] = phi i32 [ [[NEWSTATE_02]], [[IF_END23]] ], [ 0, [[DETBB1]] ]
529+
; CHECK-NEXT: br label [[SWITCHPHIDEF_FOR_BODY]]
530+
;
531+
entry:
532+
br label %switchPhiDef.for.body
533+
534+
switchPhiDef.for.body: ; preds = %detBB2, %entry
535+
%switchPhi.curState = phi i32 [ %curState.1, %detBB2 ], [ 0, %entry ]
536+
br i1 %call12, label %detBB1, label %if.else
537+
538+
if.else: ; preds = %switchPhiDef.for.body
539+
br label %detBB1
540+
541+
detBB1: ; preds = %if.else, %switchPhiDef.for.body
542+
%newState.02 = phi i32 [ 2, %switchPhiDef.for.body ], [ 4, %if.else ]
543+
br i1 %cmp18, label %detBB2, label %if.end20
544+
545+
if.end20: ; preds = %detBB1
546+
br i1 %call12, label %if.end23, label %switchBB
547+
548+
switchBB: ; preds = %if.end20
549+
switch i32 %switchPhi.curState, label %if.end23 [
550+
i32 4, label %ret1
551+
i32 0, label %ret2
552+
]
553+
554+
ret1: ; preds = %switchBB
555+
ret i8 1
556+
557+
ret2: ; preds = %switchBB
558+
ret i8 2
559+
560+
if.end23: ; preds = %switchBB, %if.end20
561+
br label %detBB2
562+
563+
detBB2: ; preds = %if.end23, %detBB1
564+
%curState.1 = phi i32 [ %newState.02, %if.end23 ], [ 0, %detBB1 ]
565+
br label %switchPhiDef.for.body
566+
}
567+
568+
define void @cyclesInPaths2(i1 %tobool) {
569+
; CHECK-LABEL: @cyclesInPaths2(
570+
; CHECK-NEXT: entry:
571+
; CHECK-NEXT: br label [[IF_END5:%.*]]
572+
; CHECK: if.end5:
573+
; CHECK-NEXT: [[P_SROA_8_051:%.*]] = phi i16 [ [[RETVAL_SROA_6_0_I:%.*]], [[BB_EXIT:%.*]] ], [ 0, [[ENTRY:%.*]] ]
574+
; CHECK-NEXT: call void (...) @llvm.fake.use(i32 3)
575+
; CHECK-NEXT: br i1 [[TOBOOL:%.*]], label [[IF_END_I:%.*]], label [[BB_EXIT]]
576+
; CHECK: if.end5.jt0:
577+
; CHECK-NEXT: [[P_SROA_8_051_JT0:%.*]] = phi i16 [ [[RETVAL_SROA_6_0_I_JT0:%.*]], [[BB_EXIT_JT0:%.*]] ]
578+
; CHECK-NEXT: call void (...) @llvm.fake.use(i32 3)
579+
; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_END_I_JT0:%.*]], label [[BB_EXIT]]
580+
; CHECK: if.end5.jt1:
581+
; CHECK-NEXT: [[P_SROA_8_051_JT1:%.*]] = phi i16 [ [[RETVAL_SROA_6_0_I_JT1:%.*]], [[BB_EXIT_JT1:%.*]] ]
582+
; CHECK-NEXT: call void (...) @llvm.fake.use(i32 3)
583+
; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_END_I_JT1:%.*]], label [[BB_EXIT]]
584+
; CHECK: if.end.i:
585+
; CHECK-NEXT: switch i16 [[P_SROA_8_051]], label [[SW_DEFAULT_I:%.*]] [
586+
; CHECK-NEXT: i16 1, label [[SW_BB_I:%.*]]
587+
; CHECK-NEXT: i16 0, label [[BB_EXIT_JT0]]
588+
; CHECK-NEXT: ]
589+
; CHECK: if.end.i.jt0:
590+
; CHECK-NEXT: br label [[BB_EXIT_JT0]]
591+
; CHECK: if.end.i.jt1:
592+
; CHECK-NEXT: br label [[SW_BB_I]]
593+
; CHECK: sw.bb.i:
594+
; CHECK-NEXT: call void (...) @llvm.fake.use(i32 1)
595+
; CHECK-NEXT: br label [[BB_EXIT_JT1]]
596+
; CHECK: sw.default.i:
597+
; CHECK-NEXT: unreachable
598+
; CHECK: bb.exit:
599+
; CHECK-NEXT: [[RETVAL_SROA_6_0_I]] = phi i16 [ 0, [[IF_END5]] ], [ 0, [[IF_END5_JT1:%.*]] ], [ 0, [[IF_END5_JT0:%.*]] ]
600+
; CHECK-NEXT: call void (...) @llvm.fake.use(i32 2)
601+
; CHECK-NEXT: br label [[IF_END5]]
602+
; CHECK: bb.exit.jt0:
603+
; CHECK-NEXT: [[RETVAL_SROA_6_0_I_JT0]] = phi i16 [ 0, [[IF_END_I]] ], [ 0, [[IF_END_I_JT0]] ]
604+
; CHECK-NEXT: call void (...) @llvm.fake.use(i32 2)
605+
; CHECK-NEXT: br label [[IF_END5_JT0]]
606+
; CHECK: bb.exit.jt1:
607+
; CHECK-NEXT: [[RETVAL_SROA_6_0_I_JT1]] = phi i16 [ 1, [[SW_BB_I]] ]
608+
; CHECK-NEXT: call void (...) @llvm.fake.use(i32 2)
609+
; CHECK-NEXT: br label [[IF_END5_JT1]]
610+
;
611+
entry:
612+
br label %if.end5
613+
614+
if.end5: ; preds = %bb.exit, %entry
615+
%P.sroa.8.051 = phi i16 [ %retval.sroa.6.0.i, %bb.exit ], [ 0, %entry ]
616+
call void (...) @llvm.fake.use(i32 3)
617+
br i1 %tobool, label %if.end.i, label %bb.exit
618+
619+
if.end.i: ; preds = %if.end5
620+
switch i16 %P.sroa.8.051, label %sw.default.i [
621+
i16 1, label %sw.bb.i
622+
i16 0, label %bb.exit
623+
]
624+
625+
sw.bb.i: ; preds = %if.end.i
626+
call void (...) @llvm.fake.use(i32 1)
627+
br label %bb.exit
628+
629+
sw.default.i: ; preds = %if.end.i
630+
unreachable
631+
632+
bb.exit: ; preds = %sw.bb.i, %if.end.i, %if.end5
633+
%retval.sroa.6.0.i = phi i16 [ 1, %sw.bb.i ], [ 0, %if.end5 ], [ 0, %if.end.i ]
634+
call void (...) @llvm.fake.use(i32 2)
635+
br label %if.end5
636+
}
637+
502638
declare void @llvm.fake.use(...)
503639

504640
!0 = !{!"function_entry_count", i32 10}

0 commit comments

Comments
 (0)