| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --filter "br i1|= select |!prof|!llvm.loop|^.*:" --version 6 | |
| ; RUN: opt -passes=loop-vectorize -force-vector-width=4 -force-vector-interleave=1 -S %s | FileCheck %s --check-prefix=VF4 | |
| ; RUN: opt -passes=loop-vectorize -force-vector-width=2 -force-vector-interleave=1 -S %s | FileCheck %s --check-prefix=VF2 | |
| ; The uncountable exit is taken with probability 1/4 per original iteration. | |
| define i64 @early_exit_taken_1_in_4(ptr dereferenceable(1024) %a) !prof !0 { | |
| ; VF4-LABEL: define i64 @early_exit_taken_1_in_4( | |
| ; VF4-SAME: ptr dereferenceable(1024) [[A:%.*]]) !prof [[PROF0:![0-9]+]] { | |
| ; VF4: [[ENTRY:.*:]] | |
| ; VF4: [[VECTOR_PH:.*:]] | |
| ; VF4: [[VECTOR_BODY:.*]]: | |
| ; VF4: br i1 [[TMP3:%.*]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM:.*]] | |
| ; VF4: [[VECTOR_BODY_INTERIM]]: | |
| ; VF4: br i1 [[TMP4:%.*]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP1:![0-9]+]] | |
| ; VF4: [[MIDDLE_BLOCK]]: | |
| ; VF4: [[VECTOR_EARLY_EXIT]]: | |
| ; VF4: [[FOUND:.*:]] | |
| ; VF4: [[EXIT:.*:]] | |
| ; | |
| ; VF2-LABEL: define i64 @early_exit_taken_1_in_4( | |
| ; VF2-SAME: ptr dereferenceable(1024) [[A:%.*]]) !prof [[PROF0:![0-9]+]] { | |
| ; VF2: [[ENTRY:.*:]] | |
| ; VF2: [[VECTOR_PH:.*:]] | |
| ; VF2: [[VECTOR_BODY:.*]]: | |
| ; VF2: br i1 [[TMP3:%.*]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM:.*]] | |
| ; VF2: [[VECTOR_BODY_INTERIM]]: | |
| ; VF2: br i1 [[TMP4:%.*]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP1:![0-9]+]] | |
| ; VF2: [[MIDDLE_BLOCK]]: | |
| ; VF2: [[VECTOR_EARLY_EXIT]]: | |
| ; VF2: [[FOUND:.*:]] | |
| ; VF2: [[EXIT:.*:]] | |
| ; | |
| entry: | |
| br label %loop.header | |
| loop.header: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ] | |
| %gep = getelementptr inbounds i8, ptr %a, i64 %iv | |
| %l = load i8, ptr %gep, align 1 | |
| %c = icmp eq i8 %l, 42 | |
| br i1 %c, label %found, label %loop.latch, !prof !1 | |
| loop.latch: | |
| %iv.next = add nuw i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop.header | |
| found: | |
| ret i64 %iv | |
| exit: | |
| ret i64 -1 | |
| } | |
| ; Same, with the early exit as the false successor, so the weights are reversed. | |
| define i64 @early_exit_negated(ptr dereferenceable(1024) %a) !prof !0 { | |
| ; VF4-LABEL: define i64 @early_exit_negated( | |
| ; VF4-SAME: ptr dereferenceable(1024) [[A:%.*]]) !prof [[PROF0]] { | |
| ; VF4: [[ENTRY:.*:]] | |
| ; VF4: [[VECTOR_PH:.*:]] | |
| ; VF4: [[VECTOR_BODY:.*]]: | |
| ; VF4: br i1 [[TMP3:%.*]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM:.*]] | |
| ; VF4: [[VECTOR_BODY_INTERIM]]: | |
| ; VF4: br i1 [[TMP4:%.*]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]] | |
| ; VF4: [[MIDDLE_BLOCK]]: | |
| ; VF4: [[VECTOR_EARLY_EXIT]]: | |
| ; VF4: [[FOUND:.*:]] | |
| ; VF4: [[EXIT:.*:]] | |
| ; | |
| ; VF2-LABEL: define i64 @early_exit_negated( | |
| ; VF2-SAME: ptr dereferenceable(1024) [[A:%.*]]) !prof [[PROF0]] { | |
| ; VF2: [[ENTRY:.*:]] | |
| ; VF2: [[VECTOR_PH:.*:]] | |
| ; VF2: [[VECTOR_BODY:.*]]: | |
| ; VF2: br i1 [[TMP3:%.*]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM:.*]] | |
| ; VF2: [[VECTOR_BODY_INTERIM]]: | |
| ; VF2: br i1 [[TMP4:%.*]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]] | |
| ; VF2: [[MIDDLE_BLOCK]]: | |
| ; VF2: [[VECTOR_EARLY_EXIT]]: | |
| ; VF2: [[FOUND:.*:]] | |
| ; VF2: [[EXIT:.*:]] | |
| ; | |
| entry: | |
| br label %loop.header | |
| loop.header: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ] | |
| %gep = getelementptr inbounds i8, ptr %a, i64 %iv | |
| %l = load i8, ptr %gep, align 1 | |
| %c = icmp ne i8 %l, 42 | |
| br i1 %c, label %loop.latch, label %found, !prof !2 | |
| loop.latch: | |
| %iv.next = add nuw i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop.header | |
| found: | |
| ret i64 %iv | |
| exit: | |
| ret i64 -1 | |
| } | |
| ; Without weights on the original exit condition there is nothing to derive. | |
| define i64 @early_exit_no_weights(ptr dereferenceable(1024) %a) !prof !0 { | |
| ; VF4-LABEL: define i64 @early_exit_no_weights( | |
| ; VF4-SAME: ptr dereferenceable(1024) [[A:%.*]]) !prof [[PROF0]] { | |
| ; VF4: [[ENTRY:.*:]] | |
| ; VF4: [[VECTOR_PH:.*:]] | |
| ; VF4: [[VECTOR_BODY:.*]]: | |
| ; VF4: br i1 [[TMP3:%.*]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM:.*]] | |
| ; VF4: [[VECTOR_BODY_INTERIM]]: | |
| ; VF4: br i1 [[TMP4:%.*]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP5:![0-9]+]] | |
| ; VF4: [[MIDDLE_BLOCK]]: | |
| ; VF4: [[VECTOR_EARLY_EXIT]]: | |
| ; VF4: [[FOUND:.*:]] | |
| ; VF4: [[EXIT:.*:]] | |
| ; | |
| ; VF2-LABEL: define i64 @early_exit_no_weights( | |
| ; VF2-SAME: ptr dereferenceable(1024) [[A:%.*]]) !prof [[PROF0]] { | |
| ; VF2: [[ENTRY:.*:]] | |
| ; VF2: [[VECTOR_PH:.*:]] | |
| ; VF2: [[VECTOR_BODY:.*]]: | |
| ; VF2: br i1 [[TMP3:%.*]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM:.*]] | |
| ; VF2: [[VECTOR_BODY_INTERIM]]: | |
| ; VF2: br i1 [[TMP4:%.*]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP5:![0-9]+]] | |
| ; VF2: [[MIDDLE_BLOCK]]: | |
| ; VF2: [[VECTOR_EARLY_EXIT]]: | |
| ; VF2: [[FOUND:.*:]] | |
| ; VF2: [[EXIT:.*:]] | |
| ; | |
| entry: | |
| br label %loop.header | |
| loop.header: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ] | |
| %gep = getelementptr inbounds i8, ptr %a, i64 %iv | |
| %l = load i8, ptr %gep, align 1 | |
| %c = icmp eq i8 %l, 42 | |
| br i1 %c, label %found, label %loop.latch | |
| loop.latch: | |
| %iv.next = add nuw i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop.header | |
| found: | |
| ret i64 %iv | |
| exit: | |
| ret i64 -1 | |
| } | |
| ; Which of several uncountable exits a vector iteration takes is not known. | |
| define i64 @three_early_exits(ptr dereferenceable(1024) %a, ptr dereferenceable(1024) %b) !prof !0 { | |
| ; VF4-LABEL: define i64 @three_early_exits( | |
| ; VF4-SAME: ptr dereferenceable(1024) [[A:%.*]], ptr dereferenceable(1024) [[B:%.*]]) !prof [[PROF0]] { | |
| ; VF4: [[ENTRY:.*:]] | |
| ; VF4: [[VECTOR_PH:.*:]] | |
| ; VF4: [[VECTOR_BODY:.*]]: | |
| ; VF4: [[TMP5:%.*]] = select <4 x i1> [[TMP2:%.*]], <4 x i1> splat (i1 true), <4 x i1> [[TMP3:%.*]] | |
| ; VF4: [[TMP6:%.*]] = select <4 x i1> [[TMP5]], <4 x i1> splat (i1 true), <4 x i1> [[TMP4:%.*]] | |
| ; VF4: br i1 [[TMP8:%.*]], label %[[VECTOR_EARLY_EXIT_CHECK:.*]], label %[[VECTOR_BODY_INTERIM:.*]] | |
| ; VF4: [[VECTOR_BODY_INTERIM]]: | |
| ; VF4: br i1 [[TMP9:%.*]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP6:![0-9]+]] | |
| ; VF4: [[MIDDLE_BLOCK]]: | |
| ; VF4: [[VECTOR_EARLY_EXIT_CHECK]]: | |
| ; VF4: br i1 [[TMP10:%.*]], label %[[VECTOR_EARLY_EXIT_0:.*]], label %[[VECTOR_EARLY_EXIT_CHECK_0:.*]] | |
| ; VF4: [[VECTOR_EARLY_EXIT_CHECK_0]]: | |
| ; VF4: br i1 [[TMP11:%.*]], label %[[VECTOR_EARLY_EXIT_1:.*]], label %[[VECTOR_EARLY_EXIT_2:.*]] | |
| ; VF4: [[VECTOR_EARLY_EXIT_2]]: | |
| ; VF4: [[VECTOR_EARLY_EXIT_1]]: | |
| ; VF4: [[VECTOR_EARLY_EXIT_0]]: | |
| ; VF4: [[EXIT_0:.*:]] | |
| ; VF4: [[EXIT_1:.*:]] | |
| ; VF4: [[EXIT_2:.*:]] | |
| ; VF4: [[EXIT:.*:]] | |
| ; | |
| ; VF2-LABEL: define i64 @three_early_exits( | |
| ; VF2-SAME: ptr dereferenceable(1024) [[A:%.*]], ptr dereferenceable(1024) [[B:%.*]]) !prof [[PROF0]] { | |
| ; VF2: [[ENTRY:.*:]] | |
| ; VF2: [[VECTOR_PH:.*:]] | |
| ; VF2: [[VECTOR_BODY:.*]]: | |
| ; VF2: [[TMP5:%.*]] = select <2 x i1> [[TMP2:%.*]], <2 x i1> splat (i1 true), <2 x i1> [[TMP3:%.*]] | |
| ; VF2: [[TMP6:%.*]] = select <2 x i1> [[TMP5]], <2 x i1> splat (i1 true), <2 x i1> [[TMP4:%.*]] | |
| ; VF2: br i1 [[TMP8:%.*]], label %[[VECTOR_EARLY_EXIT_CHECK:.*]], label %[[VECTOR_BODY_INTERIM:.*]] | |
| ; VF2: [[VECTOR_BODY_INTERIM]]: | |
| ; VF2: br i1 [[TMP9:%.*]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP6:![0-9]+]] | |
| ; VF2: [[MIDDLE_BLOCK]]: | |
| ; VF2: [[VECTOR_EARLY_EXIT_CHECK]]: | |
| ; VF2: br i1 [[TMP10:%.*]], label %[[VECTOR_EARLY_EXIT_0:.*]], label %[[VECTOR_EARLY_EXIT_CHECK_0:.*]] | |
| ; VF2: [[VECTOR_EARLY_EXIT_CHECK_0]]: | |
| ; VF2: br i1 [[TMP11:%.*]], label %[[VECTOR_EARLY_EXIT_1:.*]], label %[[VECTOR_EARLY_EXIT_2:.*]] | |
| ; VF2: [[VECTOR_EARLY_EXIT_2]]: | |
| ; VF2: [[VECTOR_EARLY_EXIT_1]]: | |
| ; VF2: [[VECTOR_EARLY_EXIT_0]]: | |
| ; VF2: [[EXIT_0:.*:]] | |
| ; VF2: [[EXIT_1:.*:]] | |
| ; VF2: [[EXIT_2:.*:]] | |
| ; VF2: [[EXIT:.*:]] | |
| ; | |
| entry: | |
| br label %loop.header | |
| loop.header: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ] | |
| %gep.a = getelementptr inbounds i8, ptr %a, i64 %iv | |
| %l.a = load i8, ptr %gep.a, align 1 | |
| %gep.b = getelementptr inbounds i8, ptr %b, i64 %iv | |
| %l.b = load i8, ptr %gep.b, align 1 | |
| %c.0 = icmp eq i8 %l.a, %l.b | |
| br i1 %c.0, label %exit.0, label %check.1 | |
| check.1: | |
| %c.1 = icmp ult i8 %l.a, 34 | |
| br i1 %c.1, label %exit.1, label %check.2 | |
| check.2: | |
| %c.2 = icmp ugt i8 %l.b, 100 | |
| br i1 %c.2, label %exit.2, label %loop.latch | |
| loop.latch: | |
| %iv.next = add nuw i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop.header | |
| exit.0: | |
| ret i64 %iv | |
| exit.1: | |
| ret i64 100 | |
| exit.2: | |
| ret i64 200 | |
| exit: | |
| ret i64 -1 | |
| } | |
| define i64 @early_exit_not_profiled(ptr dereferenceable(1024) %a) { | |
| ; VF4-LABEL: define i64 @early_exit_not_profiled( | |
| ; VF4-SAME: ptr dereferenceable(1024) [[A:%.*]]) { | |
| ; VF4: [[ENTRY:.*:]] | |
| ; VF4: [[VECTOR_PH:.*:]] | |
| ; VF4: [[VECTOR_BODY:.*]]: | |
| ; VF4: br i1 [[TMP3:%.*]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM:.*]] | |
| ; VF4: [[VECTOR_BODY_INTERIM]]: | |
| ; VF4: br i1 [[TMP4:%.*]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP7:![0-9]+]] | |
| ; VF4: [[MIDDLE_BLOCK]]: | |
| ; VF4: [[VECTOR_EARLY_EXIT]]: | |
| ; VF4: [[FOUND:.*:]] | |
| ; VF4: [[EXIT:.*:]] | |
| ; | |
| ; VF2-LABEL: define i64 @early_exit_not_profiled( | |
| ; VF2-SAME: ptr dereferenceable(1024) [[A:%.*]]) { | |
| ; VF2: [[ENTRY:.*:]] | |
| ; VF2: [[VECTOR_PH:.*:]] | |
| ; VF2: [[VECTOR_BODY:.*]]: | |
| ; VF2: br i1 [[TMP3:%.*]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM:.*]] | |
| ; VF2: [[VECTOR_BODY_INTERIM]]: | |
| ; VF2: br i1 [[TMP4:%.*]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP7:![0-9]+]] | |
| ; VF2: [[MIDDLE_BLOCK]]: | |
| ; VF2: [[VECTOR_EARLY_EXIT]]: | |
| ; VF2: [[FOUND:.*:]] | |
| ; VF2: [[EXIT:.*:]] | |
| ; | |
| entry: | |
| br label %loop.header | |
| loop.header: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ] | |
| %gep = getelementptr inbounds i8, ptr %a, i64 %iv | |
| %l = load i8, ptr %gep, align 1 | |
| %c = icmp eq i8 %l, 42 | |
| br i1 %c, label %found, label %loop.latch, !prof !1 | |
| loop.latch: | |
| %iv.next = add nuw i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop.header | |
| found: | |
| ret i64 %iv | |
| exit: | |
| ret i64 -1 | |
| } | |
| !0 = !{!"function_entry_count", i64 1000} | |
| !1 = !{!"branch_weights", i32 1, i32 3} | |
| !2 = !{!"branch_weights", i32 3, i32 1} | |
| ;. | |
| ; VF4: [[PROF0]] = !{!"function_entry_count", i64 1000} | |
| ; VF4: [[LOOP1]] = distinct !{[[LOOP1]], [[META2:![0-9]+]], [[META3:![0-9]+]]} | |
| ; VF4: [[META2]] = !{!"llvm.loop.isvectorized", i32 1} | |
| ; VF4: [[META3]] = !{!"llvm.loop.unroll.runtime.disable"} | |
| ; VF4: [[LOOP4]] = distinct !{[[LOOP4]], [[META2]], [[META3]]} | |
| ; VF4: [[LOOP5]] = distinct !{[[LOOP5]], [[META2]], [[META3]]} | |
| ; VF4: [[LOOP6]] = distinct !{[[LOOP6]], [[META2]], [[META3]]} | |
| ; VF4: [[LOOP7]] = distinct !{[[LOOP7]], [[META2]], [[META3]]} | |
| ;. | |
| ; VF2: [[PROF0]] = !{!"function_entry_count", i64 1000} | |
| ; VF2: [[LOOP1]] = distinct !{[[LOOP1]], [[META2:![0-9]+]], [[META3:![0-9]+]]} | |
| ; VF2: [[META2]] = !{!"llvm.loop.isvectorized", i32 1} | |
| ; VF2: [[META3]] = !{!"llvm.loop.unroll.runtime.disable"} | |
| ; VF2: [[LOOP4]] = distinct !{[[LOOP4]], [[META2]], [[META3]]} | |
| ; VF2: [[LOOP5]] = distinct !{[[LOOP5]], [[META2]], [[META3]]} | |
| ; VF2: [[LOOP6]] = distinct !{[[LOOP6]], [[META2]], [[META3]]} | |
| ; VF2: [[LOOP7]] = distinct !{[[LOOP7]], [[META2]], [[META3]]} | |
| ;. |