llvm-project/llvm/test/Transforms/SimpleLoopUnswitch/inject-invariant-conditions-exponential.ll
Nikita Popov 8362cae71b [SimpleLoopUnswitch] Fix exponential unswitch
When unswitching via invariant condition injection, we currently
mark the condition in the old loop, so that it does not get
unswitched again. However, if there are multiple branches for
which conditions can be injected, then we can do that for both
the old and new loop. This means that the number of unswitches
increases exponentially.

Change the handling to be more similar to partial unswitching,
where we instead mark the whole loop, rather than a single
condition. This means that we will only generate a linear number
of loops.

TBH I think even that is still highly undesirable, and we should
probably be unswitching all candidates at the same time, so that
we end up with only two loops. But at least this mitigates the
worst case.

The test case is a reduced variant that generates 1700 lines of IR
without this patch and 290 with it.

Fixes https://github.com/llvm/llvm-project/issues/66868.
2023-09-21 09:47:15 +02:00

261 lines
14 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
; RUN: opt -S -passes='simple-loop-unswitch<nontrivial>' < %s | FileCheck %s
; Make sure invariant condition injection does not result in exponential
; size increase.
; FIXME: It probably shouldn't result in linear size increase either.
define void @ham(i64 %arg) {
; CHECK-LABEL: define void @ham(
; CHECK-SAME: i64 [[ARG:%.*]]) {
; CHECK-NEXT: bb:
; CHECK-NEXT: [[INJECTED_COND:%.*]] = icmp ule i64 [[ARG]], [[ARG]]
; CHECK-NEXT: [[INJECTED_COND_FR:%.*]] = freeze i1 [[INJECTED_COND]]
; CHECK-NEXT: br i1 [[INJECTED_COND_FR]], label [[BB_SPLIT_US:%.*]], label [[BB_SPLIT:%.*]]
; CHECK: bb.split.us:
; CHECK-NEXT: [[INJECTED_COND1:%.*]] = icmp ule i64 [[ARG]], [[ARG]]
; CHECK-NEXT: [[INJECTED_COND1_FR:%.*]] = freeze i1 [[INJECTED_COND1]]
; CHECK-NEXT: br i1 [[INJECTED_COND1_FR]], label [[BB_SPLIT_US_SPLIT_US:%.*]], label [[BB_SPLIT_US_SPLIT:%.*]]
; CHECK: bb.split.us.split.us:
; CHECK-NEXT: [[INJECTED_COND2:%.*]] = icmp ule i64 [[ARG]], [[ARG]]
; CHECK-NEXT: [[INJECTED_COND2_FR:%.*]] = freeze i1 [[INJECTED_COND2]]
; CHECK-NEXT: br i1 [[INJECTED_COND2_FR]], label [[BB_SPLIT_US_SPLIT_US_SPLIT_US:%.*]], label [[BB_SPLIT_US_SPLIT_US_SPLIT:%.*]]
; CHECK: bb.split.us.split.us.split.us:
; CHECK-NEXT: [[INJECTED_COND3:%.*]] = icmp ule i64 [[ARG]], [[ARG]]
; CHECK-NEXT: [[INJECTED_COND3_FR:%.*]] = freeze i1 [[INJECTED_COND3]]
; CHECK-NEXT: br i1 [[INJECTED_COND3_FR]], label [[BB_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US:%.*]], label [[BB_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT:%.*]]
; CHECK: bb.split.us.split.us.split.us.split.us:
; CHECK-NEXT: [[INJECTED_COND4:%.*]] = icmp ule i64 [[ARG]], [[ARG]]
; CHECK-NEXT: [[INJECTED_COND4_FR:%.*]] = freeze i1 [[INJECTED_COND4]]
; CHECK-NEXT: br i1 [[INJECTED_COND4_FR]], label [[BB_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US:%.*]], label [[BB_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT:%.*]]
; CHECK: bb.split.us.split.us.split.us.split.us.split.us:
; CHECK-NEXT: br label [[BB1_US_US_US_US_US:%.*]]
; CHECK: bb1.us.us.us.us.us:
; CHECK-NEXT: [[PHI_US_US_US_US_US:%.*]] = phi i64 [ 0, [[BB_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US]] ], [ [[ADD_US_US_US_US_US:%.*]], [[BB20_US_US_US_US_US:%.*]] ]
; CHECK-NEXT: [[ADD_US_US_US_US_US]] = add nuw i64 [[PHI_US_US_US_US_US]], 1
; CHECK-NEXT: [[ICMP_US_US_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US_US_US]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP_US_US_US_US_US]], label [[BB2_US_US_US_US_US:%.*]], label [[BB21_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US:%.*]], !prof [[PROF0:![0-9]+]]
; CHECK: bb2.us.us.us.us.us:
; CHECK-NEXT: [[ICMP3_US_US_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB4_US_US_US_US_US:%.*]]
; CHECK: bb4.us.us.us.us.us:
; CHECK-NEXT: [[ICMP5_US_US_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB6_US_US_US_US_US:%.*]]
; CHECK: bb6.us.us.us.us.us:
; CHECK-NEXT: [[ICMP7_US_US_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB8_US_US_US_US_US:%.*]]
; CHECK: bb8.us.us.us.us.us:
; CHECK-NEXT: [[ICMP9_US_US_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB10_US_US_US_US_US:%.*]]
; CHECK: bb10.us.us.us.us.us:
; CHECK-NEXT: [[ICMP11_US_US_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB20_US_US_US_US_US]]
; CHECK: bb20.us.us.us.us.us:
; CHECK-NEXT: br label [[BB1_US_US_US_US_US]]
; CHECK: bb21.split.us.split.us.split.us.split.us.split.us:
; CHECK-NEXT: br label [[BB21_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US:%.*]]
; CHECK: bb.split.us.split.us.split.us.split.us.split:
; CHECK-NEXT: br label [[BB1_US_US_US_US:%.*]]
; CHECK: bb1.us.us.us.us:
; CHECK-NEXT: [[PHI_US_US_US_US:%.*]] = phi i64 [ 0, [[BB_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT]] ], [ [[ADD_US_US_US_US:%.*]], [[BB20_US_US_US_US:%.*]] ]
; CHECK-NEXT: [[ADD_US_US_US_US]] = add nuw i64 [[PHI_US_US_US_US]], 1
; CHECK-NEXT: [[ICMP_US_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US_US]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP_US_US_US_US]], label [[BB2_US_US_US_US:%.*]], label [[BB21_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT:%.*]], !prof [[PROF0]]
; CHECK: bb2.us.us.us.us:
; CHECK-NEXT: [[ICMP3_US_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB4_US_US_US_US:%.*]]
; CHECK: bb4.us.us.us.us:
; CHECK-NEXT: [[ICMP5_US_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB6_US_US_US_US:%.*]]
; CHECK: bb6.us.us.us.us:
; CHECK-NEXT: [[ICMP7_US_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB8_US_US_US_US:%.*]]
; CHECK: bb8.us.us.us.us:
; CHECK-NEXT: [[ICMP9_US_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB10_US_US_US_US:%.*]]
; CHECK: bb10.us.us.us.us:
; CHECK-NEXT: [[ICMP11_US_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB10_US_US_US_US_CHECK:%.*]]
; CHECK: bb10.us.us.us.us.check:
; CHECK-NEXT: br i1 [[ICMP11_US_US_US_US]], label [[BB20_US_US_US_US]], label [[BB21_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT]]
; CHECK: bb20.us.us.us.us:
; CHECK-NEXT: br label [[BB1_US_US_US_US]], !llvm.loop [[LOOP1:![0-9]+]]
; CHECK: bb21.split.us.split.us.split.us.split.us.split:
; CHECK-NEXT: br label [[BB21_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US]]
; CHECK: bb21.split.us.split.us.split.us.split.us:
; CHECK-NEXT: br label [[BB21_SPLIT_US_SPLIT_US_SPLIT_US:%.*]]
; CHECK: bb.split.us.split.us.split.us.split:
; CHECK-NEXT: br label [[BB1_US_US_US:%.*]]
; CHECK: bb1.us.us.us:
; CHECK-NEXT: [[PHI_US_US_US:%.*]] = phi i64 [ 0, [[BB_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT]] ], [ [[ADD_US_US_US:%.*]], [[BB20_US_US_US:%.*]] ]
; CHECK-NEXT: [[ADD_US_US_US]] = add nuw i64 [[PHI_US_US_US]], 1
; CHECK-NEXT: [[ICMP_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP_US_US_US]], label [[BB2_US_US_US:%.*]], label [[BB21_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT:%.*]], !prof [[PROF0]]
; CHECK: bb2.us.us.us:
; CHECK-NEXT: [[ICMP3_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB4_US_US_US:%.*]]
; CHECK: bb4.us.us.us:
; CHECK-NEXT: [[ICMP5_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB6_US_US_US:%.*]]
; CHECK: bb6.us.us.us:
; CHECK-NEXT: [[ICMP7_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB8_US_US_US:%.*]]
; CHECK: bb8.us.us.us:
; CHECK-NEXT: [[ICMP9_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB8_US_US_US_CHECK:%.*]]
; CHECK: bb8.us.us.us.check:
; CHECK-NEXT: br i1 [[ICMP9_US_US_US]], label [[BB10_US_US_US:%.*]], label [[BB21_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT]]
; CHECK: bb10.us.us.us:
; CHECK-NEXT: [[ICMP11_US_US_US:%.*]] = icmp ult i64 [[PHI_US_US_US]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP11_US_US_US]], label [[BB20_US_US_US]], label [[BB21_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT]], !prof [[PROF0]]
; CHECK: bb20.us.us.us:
; CHECK-NEXT: br label [[BB1_US_US_US]], !llvm.loop [[LOOP3:![0-9]+]]
; CHECK: bb21.split.us.split.us.split.us.split:
; CHECK-NEXT: br label [[BB21_SPLIT_US_SPLIT_US_SPLIT_US]]
; CHECK: bb21.split.us.split.us.split.us:
; CHECK-NEXT: br label [[BB21_SPLIT_US_SPLIT_US:%.*]]
; CHECK: bb.split.us.split.us.split:
; CHECK-NEXT: br label [[BB1_US_US:%.*]]
; CHECK: bb1.us.us:
; CHECK-NEXT: [[PHI_US_US:%.*]] = phi i64 [ 0, [[BB_SPLIT_US_SPLIT_US_SPLIT]] ], [ [[ADD_US_US:%.*]], [[BB20_US_US:%.*]] ]
; CHECK-NEXT: [[ADD_US_US]] = add nuw i64 [[PHI_US_US]], 1
; CHECK-NEXT: [[ICMP_US_US:%.*]] = icmp ult i64 [[PHI_US_US]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP_US_US]], label [[BB2_US_US:%.*]], label [[BB21_SPLIT_US_SPLIT_US_SPLIT:%.*]], !prof [[PROF0]]
; CHECK: bb2.us.us:
; CHECK-NEXT: [[ICMP3_US_US:%.*]] = icmp ult i64 [[PHI_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB4_US_US:%.*]]
; CHECK: bb4.us.us:
; CHECK-NEXT: [[ICMP5_US_US:%.*]] = icmp ult i64 [[PHI_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB6_US_US:%.*]]
; CHECK: bb6.us.us:
; CHECK-NEXT: [[ICMP7_US_US:%.*]] = icmp ult i64 [[PHI_US_US]], [[ARG]]
; CHECK-NEXT: br label [[BB6_US_US_CHECK:%.*]]
; CHECK: bb6.us.us.check:
; CHECK-NEXT: br i1 [[ICMP7_US_US]], label [[BB8_US_US:%.*]], label [[BB21_SPLIT_US_SPLIT_US_SPLIT]]
; CHECK: bb8.us.us:
; CHECK-NEXT: [[ICMP9_US_US:%.*]] = icmp ult i64 [[PHI_US_US]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP9_US_US]], label [[BB10_US_US:%.*]], label [[BB21_SPLIT_US_SPLIT_US_SPLIT]], !prof [[PROF0]]
; CHECK: bb10.us.us:
; CHECK-NEXT: [[ICMP11_US_US:%.*]] = icmp ult i64 [[PHI_US_US]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP11_US_US]], label [[BB20_US_US]], label [[BB21_SPLIT_US_SPLIT_US_SPLIT]], !prof [[PROF0]]
; CHECK: bb20.us.us:
; CHECK-NEXT: br label [[BB1_US_US]], !llvm.loop [[LOOP4:![0-9]+]]
; CHECK: bb21.split.us.split.us.split:
; CHECK-NEXT: br label [[BB21_SPLIT_US_SPLIT_US]]
; CHECK: bb21.split.us.split.us:
; CHECK-NEXT: br label [[BB21_SPLIT_US:%.*]]
; CHECK: bb.split.us.split:
; CHECK-NEXT: br label [[BB1_US:%.*]]
; CHECK: bb1.us:
; CHECK-NEXT: [[PHI_US:%.*]] = phi i64 [ 0, [[BB_SPLIT_US_SPLIT]] ], [ [[ADD_US:%.*]], [[BB20_US:%.*]] ]
; CHECK-NEXT: [[ADD_US]] = add nuw i64 [[PHI_US]], 1
; CHECK-NEXT: [[ICMP_US:%.*]] = icmp ult i64 [[PHI_US]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP_US]], label [[BB2_US:%.*]], label [[BB21_SPLIT_US_SPLIT:%.*]], !prof [[PROF0]]
; CHECK: bb2.us:
; CHECK-NEXT: [[ICMP3_US:%.*]] = icmp ult i64 [[PHI_US]], [[ARG]]
; CHECK-NEXT: br label [[BB4_US:%.*]]
; CHECK: bb4.us:
; CHECK-NEXT: [[ICMP5_US:%.*]] = icmp ult i64 [[PHI_US]], [[ARG]]
; CHECK-NEXT: br label [[BB4_US_CHECK:%.*]]
; CHECK: bb4.us.check:
; CHECK-NEXT: br i1 [[ICMP5_US]], label [[BB6_US:%.*]], label [[BB22_SPLIT_US:%.*]]
; CHECK: bb6.us:
; CHECK-NEXT: [[ICMP7_US:%.*]] = icmp ult i64 [[PHI_US]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP7_US]], label [[BB8_US:%.*]], label [[BB21_SPLIT_US_SPLIT]], !prof [[PROF0]]
; CHECK: bb8.us:
; CHECK-NEXT: [[ICMP9_US:%.*]] = icmp ult i64 [[PHI_US]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP9_US]], label [[BB10_US:%.*]], label [[BB21_SPLIT_US_SPLIT]], !prof [[PROF0]]
; CHECK: bb10.us:
; CHECK-NEXT: [[ICMP11_US:%.*]] = icmp ult i64 [[PHI_US]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP11_US]], label [[BB20_US]], label [[BB21_SPLIT_US_SPLIT]], !prof [[PROF0]]
; CHECK: bb20.us:
; CHECK-NEXT: br label [[BB1_US]], !llvm.loop [[LOOP5:![0-9]+]]
; CHECK: bb21.split.us.split:
; CHECK-NEXT: br label [[BB21_SPLIT_US]]
; CHECK: bb21.split.us:
; CHECK-NEXT: br label [[BB21:%.*]]
; CHECK: bb22.split.us:
; CHECK-NEXT: br label [[BB22:%.*]]
; CHECK: bb.split:
; CHECK-NEXT: br label [[BB1:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[PHI:%.*]] = phi i64 [ 0, [[BB_SPLIT]] ], [ [[ADD:%.*]], [[BB20:%.*]] ]
; CHECK-NEXT: [[ADD]] = add nuw i64 [[PHI]], 1
; CHECK-NEXT: [[ICMP:%.*]] = icmp ult i64 [[PHI]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP]], label [[BB2:%.*]], label [[BB21_SPLIT:%.*]], !prof [[PROF0]]
; CHECK: bb2:
; CHECK-NEXT: [[ICMP3:%.*]] = icmp ult i64 [[PHI]], [[ARG]]
; CHECK-NEXT: br label [[BB2_CHECK:%.*]]
; CHECK: bb2.check:
; CHECK-NEXT: br i1 [[ICMP3]], label [[BB4:%.*]], label [[BB21_SPLIT]]
; CHECK: bb4:
; CHECK-NEXT: [[ICMP5:%.*]] = icmp ult i64 [[PHI]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP5]], label [[BB6:%.*]], label [[BB22_SPLIT:%.*]], !prof [[PROF0]]
; CHECK: bb6:
; CHECK-NEXT: [[ICMP7:%.*]] = icmp ult i64 [[PHI]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP7]], label [[BB8:%.*]], label [[BB21_SPLIT]], !prof [[PROF0]]
; CHECK: bb8:
; CHECK-NEXT: [[ICMP9:%.*]] = icmp ult i64 [[PHI]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP9]], label [[BB10:%.*]], label [[BB21_SPLIT]], !prof [[PROF0]]
; CHECK: bb10:
; CHECK-NEXT: [[ICMP11:%.*]] = icmp ult i64 [[PHI]], [[ARG]]
; CHECK-NEXT: br i1 [[ICMP11]], label [[BB20]], label [[BB21_SPLIT]], !prof [[PROF0]]
; CHECK: bb20:
; CHECK-NEXT: br label [[BB1]], !llvm.loop [[LOOP6:![0-9]+]]
; CHECK: bb21.split:
; CHECK-NEXT: br label [[BB21]]
; CHECK: bb21:
; CHECK-NEXT: call void @zot()
; CHECK-NEXT: ret void
; CHECK: bb22.split:
; CHECK-NEXT: br label [[BB22]]
; CHECK: bb22:
; CHECK-NEXT: call void @zot()
; CHECK-NEXT: ret void
;
bb:
br label %bb1
bb1: ; preds = %bb20, %bb
%phi = phi i64 [ 0, %bb ], [ %add, %bb20 ]
%add = add nuw i64 %phi, 1
%icmp = icmp ult i64 %phi, %arg
br i1 %icmp, label %bb2, label %bb21, !prof !0
bb2: ; preds = %bb1
%icmp3 = icmp ult i64 %phi, %arg
br i1 %icmp3, label %bb4, label %bb21, !prof !0
bb4: ; preds = %bb2
%icmp5 = icmp ult i64 %phi, %arg
br i1 %icmp5, label %bb6, label %bb22, !prof !0
bb6: ; preds = %bb4
%icmp7 = icmp ult i64 %phi, %arg
br i1 %icmp7, label %bb8, label %bb21, !prof !0
bb8: ; preds = %bb6
%icmp9 = icmp ult i64 %phi, %arg
br i1 %icmp9, label %bb10, label %bb21, !prof !0
bb10: ; preds = %bb8
%icmp11 = icmp ult i64 %phi, %arg
br i1 %icmp11, label %bb20, label %bb21, !prof !0
bb20: ; preds = %bb18
br label %bb1
bb21: ; preds = %bb18, %bb16, %bb14, %bb12, %bb10, %bb8, %bb6, %bb2, %bb1
call void @zot()
ret void
bb22: ; preds = %bb4
call void @zot()
ret void
}
declare void @zot()
!0 = !{!"branch_weights", i32 2000, i32 1}