blob: 6b84b45ef4772beab5f16fdf47e2a3480d5c0edd [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --scrub-attributes --version 2
; RUN: opt < %s -passes='pgo-force-function-attrs,function(loop-mssa(simple-loop-unswitch<nontrivial>))' -pgo-kind=pgo-instr-use-pipeline -pgo-cold-func-opt=optsize -S | FileCheck %s
; RUN: opt < %s -passes='pgo-force-function-attrs,function(loop-mssa(simple-loop-unswitch<nontrivial>))' -pgo-kind=pgo-instr-use-pipeline -pgo-cold-func-opt=minsize -S | FileCheck %s
;; Check that genuinely non-trivial loop unswitching - where the optimizer
;; would have to duplicate the entire loop body - is suppressed for cold
;; (optsize/minsize) functions.
;;
;; The branch on %cond in the loop header is loop-invariant, but both of its
;; successors (if.then, if.else) stay inside the loop, so unswitching it
;; requires producing two full copies of the loop. That code-size increase
;; must be blocked when the function is cold.
;;
;; Contrast with unswitch-cold-func.ll, where the invariant condition can be
;; hoisted via a latch-bypass rewrite that introduces no code duplication and
;; is therefore allowed even for cold functions.
;;
;; Source:
;; void function(bool cond, int N, int *A, int *B) {
;; for (int i = 0; i < N; i++) {
;; if (cond) A[i]++;
;; else B[i]++;
;; }
;; }
;; profiled when called with N=0 (cold).
define void @function(i1 %cond, i32 %N, ptr %A, ptr %B) !prof !16 {
; CHECK-LABEL: define void @function
; CHECK-SAME: (i1 [[COND:%.*]], i32 [[N:%.*]], ptr [[A:%.*]], ptr [[B:%.*]]) #[[ATTR0:[0-9]+]] {{.*}}{
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp sle i32 [[N]], 0
; CHECK-NEXT: br i1 [[CMP_NOT]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]], !prof [[PROF17:![0-9]+]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
; CHECK: loop.header:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ], [ [[I_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr inbounds i32, ptr [[A]], i32 [[I]]
; CHECK-NEXT: [[VAL_A:%.*]] = load i32, ptr [[GEP_A]], align 4
; CHECK-NEXT: [[INC_A:%.*]] = add i32 [[VAL_A]], 1
; CHECK-NEXT: store i32 [[INC_A]], ptr [[GEP_A]], align 4
; CHECK-NEXT: br label [[LOOP_LATCH]]
; CHECK: if.else:
; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr inbounds i32, ptr [[B]], i32 [[I]]
; CHECK-NEXT: [[VAL_B:%.*]] = load i32, ptr [[GEP_B]], align 4
; CHECK-NEXT: [[INC_B:%.*]] = add i32 [[VAL_B]], 1
; CHECK-NEXT: store i32 [[INC_B]], ptr [[GEP_B]], align 4
; CHECK-NEXT: br label [[LOOP_LATCH]]
; CHECK: loop.latch:
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[I_NEXT]], [[N]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_HEADER]], !prof [[PROF17]]
; CHECK: exit.loopexit:
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp.not = icmp sle i32 %N, 0
br i1 %cmp.not, label %exit, label %loop.preheader, !prof !17
loop.preheader:
br label %loop.header
loop.header:
%i = phi i32 [ 0, %loop.preheader ], [ %i.next, %loop.latch ]
br i1 %cond, label %if.then, label %if.else
if.then:
%gep.a = getelementptr inbounds i32, ptr %A, i32 %i
%val.a = load i32, ptr %gep.a, align 4
%inc.a = add i32 %val.a, 1
store i32 %inc.a, ptr %gep.a, align 4
br label %loop.latch
if.else:
%gep.b = getelementptr inbounds i32, ptr %B, i32 %i
%val.b = load i32, ptr %gep.b, align 4
%inc.b = add i32 %val.b, 1
store i32 %inc.b, ptr %gep.b, align 4
br label %loop.latch
loop.latch:
%i.next = add nuw i32 %i, 1
%exitcond.not = icmp eq i32 %i.next, %N
br i1 %exitcond.not, label %exit, label %loop.header, !prof !17
exit:
ret void
}
!llvm.module.flags = !{!0}
!0 = !{i32 1, !"ProfileSummary", !1}
!1 = !{!2, !3, !4, !5, !6, !7, !8, !9, !10, !11}
!2 = !{!"ProfileFormat", !"InstrProf"}
!3 = !{!"TotalCount", i64 1002}
!4 = !{!"MaxCount", i64 1000}
!5 = !{!"MaxInternalCount", i64 1000}
!6 = !{!"MaxFunctionCount", i64 1}
!7 = !{!"NumCounts", i64 6}
!8 = !{!"NumFunctions", i64 3}
!9 = !{!"IsPartialProfile", i64 0}
!10 = !{!"PartialProfileRatio", double 0.000000e+00}
!11 = !{!"DetailedSummary", !12}
!12 = !{!13, !14, !15}
!13 = !{i32 10000, i64 1000, i32 1}
!14 = !{i32 999000, i64 1000, i32 1}
!15 = !{i32 999999, i64 1, i32 3}
!16 = !{!"function_entry_count", i64 1}
!17 = !{!"branch_weights", i32 1, i32 0}