
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.
668 lines
33 KiB
LLVM
668 lines
33 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
|
|
; RUN: opt < %s -S -simple-loop-unswitch-inject-invariant-conditions=true -passes="loop(simple-loop-unswitch<nontrivial>),simplifycfg" | FileCheck %s
|
|
; RUN: opt < %s -S -simple-loop-unswitch-inject-invariant-conditions=true -passes="loop-mssa(simple-loop-unswitch<nontrivial>),simplifycfg" -verify-memoryssa | FileCheck %s
|
|
|
|
define i32 @test_01(ptr noundef %p, i32 noundef %n, i32 noundef %limit, ptr noundef %arr, ptr noundef %x_p) {
|
|
; CHECK-LABEL: @test_01(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[X_P:%.*]], align 4, !noundef !0
|
|
; CHECK-NEXT: [[INJECTED_COND:%.*]] = icmp ule i32 [[LIMIT:%.*]], [[X]]
|
|
; CHECK-NEXT: br i1 [[INJECTED_COND]], label [[LOOP_US:%.*]], label [[LOOP:%.*]]
|
|
; CHECK: loop.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ [[IV_NEXT_US:%.*]], [[GUARDED_US:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[EL_PTR_US:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV_US]]
|
|
; CHECK-NEXT: [[EL_US:%.*]] = load i32, ptr [[EL_PTR_US]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK_US:%.*]] = icmp ult i32 [[EL_US]], [[LIMIT]]
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK_US]], label [[GUARDED_US]], label [[COMMON_RET:%.*]], !prof [[PROF1:![0-9]+]]
|
|
; CHECK: guarded.us:
|
|
; CHECK-NEXT: [[RANGE_CHECK_US:%.*]] = icmp ult i32 [[EL_US]], [[X]]
|
|
; CHECK-NEXT: [[ARR_PTR_US:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL_US]]
|
|
; CHECK-NEXT: store i32 [[IV_US]], ptr [[ARR_PTR_US]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: [[LOOP_COND_US:%.*]] = icmp slt i32 [[IV_NEXT_US]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND_US]], label [[LOOP_US]], label [[COMMON_RET]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[ENTRY]] ]
|
|
; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]]
|
|
; CHECK-NEXT: [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK:%.*]] = icmp ult i32 [[EL]], [[LIMIT]]
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[GUARDED:%.*]], label [[COMMON_RET]], !prof [[PROF1]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[EL]], [[X]]
|
|
; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[COMMON_RET]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[EL]]
|
|
; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[COMMON_RET]], !llvm.loop [[LOOP2:![0-9]+]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 0, [[BACKEDGE]] ], [ 0, [[GUARDED_US]] ], [ -1, [[LOOP]] ], [ -1, [[LOOP_US]] ], [ -2, [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
entry:
|
|
%x = load i32, ptr %x_p, align 4, !noundef !{}
|
|
br label %loop
|
|
|
|
loop: ; preds = %backedge, %entry
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%el.ptr = getelementptr i32, ptr %p, i32 %iv
|
|
%el = load i32, ptr %el.ptr, align 4
|
|
%bound_check = icmp ult i32 %el, %limit
|
|
br i1 %bound_check, label %guarded, label %bound_check_failed, !prof !{!"branch_weights", i32 100, i32 1}
|
|
|
|
guarded: ; preds = %loop
|
|
%range_check = icmp ult i32 %el, %x
|
|
br i1 %range_check, label %backedge, label %range_check_failed, !prof !{!"branch_weights", i32 100, i32 1}
|
|
|
|
backedge: ; preds = %guarded
|
|
%arr.ptr = getelementptr i32, ptr %arr, i32 %el
|
|
store i32 %iv, ptr %arr.ptr, align 4
|
|
%iv.next = add i32 %iv, 1
|
|
%loop_cond = icmp slt i32 %iv.next, %n
|
|
br i1 %loop_cond, label %loop, label %exit
|
|
|
|
exit: ; preds = %backedge
|
|
ret i32 0
|
|
|
|
bound_check_failed: ; preds = %loop
|
|
ret i32 -1
|
|
|
|
range_check_failed: ; preds = %guarded
|
|
ret i32 -2
|
|
}
|
|
|
|
; Should not optimize: profile metadata is missing.
|
|
define i32 @test_01_neg_void_profile(ptr noundef %p, i32 noundef %n, i32 noundef %limit, ptr noundef %arr, ptr noundef %x_p) {
|
|
; CHECK-LABEL: @test_01_neg_void_profile(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[X_P:%.*]], align 4, !noundef !0
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]]
|
|
; CHECK-NEXT: [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK:%.*]] = icmp ult i32 [[EL]], [[LIMIT:%.*]]
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[GUARDED:%.*]], label [[COMMON_RET:%.*]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[EL]], [[X]]
|
|
; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[COMMON_RET]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]]
|
|
; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[COMMON_RET]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 0, [[BACKEDGE]] ], [ -1, [[LOOP]] ], [ -2, [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
entry:
|
|
%x = load i32, ptr %x_p, align 4, !noundef !{}
|
|
br label %loop
|
|
|
|
loop: ; preds = %backedge, %entry
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%el.ptr = getelementptr i32, ptr %p, i32 %iv
|
|
%el = load i32, ptr %el.ptr, align 4
|
|
%bound_check = icmp ult i32 %el, %limit
|
|
br i1 %bound_check, label %guarded, label %bound_check_failed
|
|
|
|
guarded: ; preds = %loop
|
|
%range_check = icmp ult i32 %el, %x
|
|
br i1 %range_check, label %backedge, label %range_check_failed
|
|
|
|
backedge: ; preds = %guarded
|
|
%arr.ptr = getelementptr i32, ptr %arr, i32 %el
|
|
store i32 %iv, ptr %arr.ptr, align 4
|
|
%iv.next = add i32 %iv, 1
|
|
%loop_cond = icmp slt i32 %iv.next, %n
|
|
br i1 %loop_cond, label %loop, label %exit
|
|
|
|
exit: ; preds = %backedge
|
|
ret i32 0
|
|
|
|
bound_check_failed: ; preds = %loop
|
|
ret i32 -1
|
|
|
|
range_check_failed: ; preds = %guarded
|
|
ret i32 -2
|
|
}
|
|
|
|
; Same as test_01, but n and limit are constants.
|
|
define i32 @test_01_constants(ptr noundef %p, ptr noundef %arr, ptr noundef %x_p) {
|
|
; CHECK-LABEL: @test_01_constants(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[X_P:%.*]], align 4, !noundef !0
|
|
; CHECK-NEXT: [[INJECTED_COND:%.*]] = icmp ule i32 200, 300
|
|
; CHECK-NEXT: br i1 [[INJECTED_COND]], label [[LOOP_US:%.*]], label [[LOOP:%.*]]
|
|
; CHECK: loop.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ [[IV_NEXT_US:%.*]], [[GUARDED_US:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[EL_PTR_US:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV_US]]
|
|
; CHECK-NEXT: [[EL_US:%.*]] = load i32, ptr [[EL_PTR_US]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK_US:%.*]] = icmp ult i32 [[EL_US]], 200
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK_US]], label [[GUARDED_US]], label [[COMMON_RET:%.*]], !prof [[PROF1]]
|
|
; CHECK: guarded.us:
|
|
; CHECK-NEXT: [[RANGE_CHECK_US:%.*]] = icmp ult i32 [[EL_US]], 300
|
|
; CHECK-NEXT: [[ARR_PTR_US:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL_US]]
|
|
; CHECK-NEXT: store i32 [[IV_US]], ptr [[ARR_PTR_US]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: [[LOOP_COND_US:%.*]] = icmp slt i32 [[IV_NEXT_US]], 1000
|
|
; CHECK-NEXT: br i1 [[LOOP_COND_US]], label [[LOOP_US]], label [[COMMON_RET]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[ENTRY]] ]
|
|
; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]]
|
|
; CHECK-NEXT: [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK:%.*]] = icmp ult i32 [[EL]], 200
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[BACKEDGE]], label [[COMMON_RET]], !prof [[PROF1]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[EL]]
|
|
; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 1000
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[COMMON_RET]], !llvm.loop [[LOOP4:![0-9]+]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 0, [[BACKEDGE]] ], [ 0, [[GUARDED_US]] ], [ -1, [[LOOP]] ], [ -1, [[LOOP_US]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
entry:
|
|
%x = load i32, ptr %x_p, align 4, !noundef !{}
|
|
br label %loop
|
|
|
|
loop: ; preds = %backedge, %entry
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%el.ptr = getelementptr i32, ptr %p, i32 %iv
|
|
%el = load i32, ptr %el.ptr, align 4
|
|
%bound_check = icmp ult i32 %el, 200
|
|
br i1 %bound_check, label %guarded, label %bound_check_failed, !prof !{!"branch_weights", i32 100, i32 1}
|
|
|
|
guarded: ; preds = %loop
|
|
%range_check = icmp ult i32 %el, 300
|
|
br i1 %range_check, label %backedge, label %range_check_failed, !prof !{!"branch_weights", i32 100, i32 1}
|
|
|
|
backedge: ; preds = %guarded
|
|
%arr.ptr = getelementptr i32, ptr %arr, i32 %el
|
|
store i32 %iv, ptr %arr.ptr, align 4
|
|
%iv.next = add i32 %iv, 1
|
|
%loop_cond = icmp slt i32 %iv.next, 1000
|
|
br i1 %loop_cond, label %loop, label %exit
|
|
|
|
exit: ; preds = %backedge
|
|
ret i32 0
|
|
|
|
bound_check_failed: ; preds = %loop
|
|
ret i32 -1
|
|
|
|
range_check_failed: ; preds = %guarded
|
|
ret i32 -2
|
|
}
|
|
|
|
define i32 @test_01_neg_degenerate_profile(ptr noundef %p, i32 noundef %n, i32 noundef %limit, ptr noundef %arr, ptr noundef %x_p) {
|
|
; CHECK-LABEL: @test_01_neg_degenerate_profile(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[X_P:%.*]], align 4, !noundef !0
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]]
|
|
; CHECK-NEXT: [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK:%.*]] = icmp ult i32 [[EL]], [[LIMIT:%.*]]
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[GUARDED:%.*]], label [[COMMON_RET:%.*]], !prof [[PROF1]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[EL]], [[X]]
|
|
; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[COMMON_RET]], !prof [[PROF5:![0-9]+]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]]
|
|
; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[COMMON_RET]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 0, [[BACKEDGE]] ], [ -1, [[LOOP]] ], [ -2, [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
entry:
|
|
%x = load i32, ptr %x_p, align 4, !noundef !{}
|
|
br label %loop
|
|
|
|
loop: ; preds = %backedge, %entry
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%el.ptr = getelementptr i32, ptr %p, i32 %iv
|
|
%el = load i32, ptr %el.ptr, align 4
|
|
%bound_check = icmp ult i32 %el, %limit
|
|
br i1 %bound_check, label %guarded, label %bound_check_failed, !prof !{!"branch_weights", i32 100, i32 1}
|
|
|
|
guarded: ; preds = %loop
|
|
%range_check = icmp ult i32 %el, %x
|
|
br i1 %range_check, label %backedge, label %range_check_failed, !prof !{!"branch_weights", i32 0, i32 0}
|
|
|
|
backedge: ; preds = %guarded
|
|
%arr.ptr = getelementptr i32, ptr %arr, i32 %el
|
|
store i32 %iv, ptr %arr.ptr, align 4
|
|
%iv.next = add i32 %iv, 1
|
|
%loop_cond = icmp slt i32 %iv.next, %n
|
|
br i1 %loop_cond, label %loop, label %exit
|
|
|
|
exit: ; preds = %backedge
|
|
ret i32 0
|
|
|
|
bound_check_failed: ; preds = %loop
|
|
ret i32 -1
|
|
|
|
range_check_failed: ; preds = %guarded
|
|
ret i32 -2
|
|
}
|
|
|
|
; Should not optimize: cold branch.
|
|
define i32 @test_01_neg_cold(ptr noundef %p, i32 noundef %n, i32 noundef %limit, ptr noundef %arr, ptr noundef %x_p) {
|
|
; CHECK-LABEL: @test_01_neg_cold(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[X_P:%.*]], align 4, !noundef !0
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]]
|
|
; CHECK-NEXT: [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK:%.*]] = icmp ult i32 [[EL]], [[LIMIT:%.*]]
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[GUARDED:%.*]], label [[COMMON_RET:%.*]], !prof [[PROF1]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[EL]], [[X]]
|
|
; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[COMMON_RET]], !prof [[PROF6:![0-9]+]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]]
|
|
; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[COMMON_RET]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 0, [[BACKEDGE]] ], [ -1, [[LOOP]] ], [ -2, [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
entry:
|
|
%x = load i32, ptr %x_p, align 4, !noundef !{}
|
|
br label %loop
|
|
|
|
loop: ; preds = %backedge, %entry
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%el.ptr = getelementptr i32, ptr %p, i32 %iv
|
|
%el = load i32, ptr %el.ptr, align 4
|
|
%bound_check = icmp ult i32 %el, %limit
|
|
br i1 %bound_check, label %guarded, label %bound_check_failed, !prof !{!"branch_weights", i32 100, i32 1}
|
|
|
|
guarded: ; preds = %loop
|
|
%range_check = icmp ult i32 %el, %x
|
|
br i1 %range_check, label %backedge, label %range_check_failed, !prof !{!"branch_weights", i32 2, i32 3}
|
|
|
|
backedge: ; preds = %guarded
|
|
%arr.ptr = getelementptr i32, ptr %arr, i32 %el
|
|
store i32 %iv, ptr %arr.ptr, align 4
|
|
%iv.next = add i32 %iv, 1
|
|
%loop_cond = icmp slt i32 %iv.next, %n
|
|
br i1 %loop_cond, label %loop, label %exit
|
|
|
|
exit: ; preds = %backedge
|
|
ret i32 0
|
|
|
|
bound_check_failed: ; preds = %loop
|
|
ret i32 -1
|
|
|
|
range_check_failed: ; preds = %guarded
|
|
ret i32 -2
|
|
}
|
|
|
|
; Make sure we don't crash if probability overflows
|
|
define i32 @test_01_neg_overflowing_metadata(ptr noundef %p, i32 noundef %n, i32 noundef %limit, ptr noundef %arr, ptr noundef %x_p) {
|
|
; CHECK-LABEL: @test_01_neg_overflowing_metadata(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[X_P:%.*]], align 4, !noundef !0
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]]
|
|
; CHECK-NEXT: [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK:%.*]] = icmp ult i32 [[EL]], [[LIMIT:%.*]]
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[GUARDED:%.*]], label [[COMMON_RET:%.*]], !prof [[PROF7:![0-9]+]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[EL]], [[X]]
|
|
; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[COMMON_RET]], !prof [[PROF7]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]]
|
|
; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[COMMON_RET]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 0, [[BACKEDGE]] ], [ -1, [[LOOP]] ], [ -2, [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
entry:
|
|
%x = load i32, ptr %x_p, align 4, !noundef !{}
|
|
br label %loop
|
|
|
|
loop: ; preds = %backedge, %entry
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%el.ptr = getelementptr i32, ptr %p, i32 %iv
|
|
%el = load i32, ptr %el.ptr, align 4
|
|
%bound_check = icmp ult i32 %el, %limit
|
|
br i1 %bound_check, label %guarded, label %bound_check_failed, !prof !{!"branch_weights", i32 -1, i32 -1000}
|
|
|
|
guarded: ; preds = %loop
|
|
%range_check = icmp ult i32 %el, %x
|
|
br i1 %range_check, label %backedge, label %range_check_failed, !prof !{!"branch_weights", i32 -1, i32 -1000}
|
|
|
|
backedge: ; preds = %guarded
|
|
%arr.ptr = getelementptr i32, ptr %arr, i32 %el
|
|
store i32 %iv, ptr %arr.ptr, align 4
|
|
%iv.next = add i32 %iv, 1
|
|
%loop_cond = icmp slt i32 %iv.next, %n
|
|
br i1 %loop_cond, label %loop, label %exit
|
|
|
|
exit: ; preds = %backedge
|
|
ret i32 0
|
|
|
|
bound_check_failed: ; preds = %loop
|
|
ret i32 -1
|
|
|
|
range_check_failed: ; preds = %guarded
|
|
ret i32 -2
|
|
}
|
|
|
|
|
|
define i32 @test_02(ptr noundef %p, i32 noundef %n, i32 noundef %limit, ptr noundef %arr, ptr noundef %x_p) {
|
|
; CHECK-LABEL: @test_02(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[X_P:%.*]], align 4, !noundef !0
|
|
; CHECK-NEXT: [[INJECTED_COND:%.*]] = icmp ule i32 -2147483648, [[X]]
|
|
; CHECK-NEXT: br i1 [[INJECTED_COND]], label [[LOOP_US:%.*]], label [[LOOP:%.*]]
|
|
; CHECK: loop.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ [[IV_NEXT_US:%.*]], [[GUARDED_US:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[EL_PTR_US:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV_US]]
|
|
; CHECK-NEXT: [[EL_US:%.*]] = load i32, ptr [[EL_PTR_US]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK_US:%.*]] = icmp sge i32 [[EL_US]], 0
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK_US]], label [[GUARDED_US]], label [[COMMON_RET:%.*]], !prof [[PROF1]]
|
|
; CHECK: guarded.us:
|
|
; CHECK-NEXT: [[RANGE_CHECK_US:%.*]] = icmp ult i32 [[EL_US]], [[X]]
|
|
; CHECK-NEXT: [[ARR_PTR_US:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL_US]]
|
|
; CHECK-NEXT: store i32 [[IV_US]], ptr [[ARR_PTR_US]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: [[LOOP_COND_US:%.*]] = icmp slt i32 [[IV_NEXT_US]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND_US]], label [[LOOP_US]], label [[COMMON_RET]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[ENTRY]] ]
|
|
; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]]
|
|
; CHECK-NEXT: [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK:%.*]] = icmp sge i32 [[EL]], 0
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[GUARDED:%.*]], label [[COMMON_RET]], !prof [[PROF1]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[EL]], [[X]]
|
|
; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[COMMON_RET]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[EL]]
|
|
; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[COMMON_RET]], !llvm.loop [[LOOP8:![0-9]+]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 0, [[BACKEDGE]] ], [ 0, [[GUARDED_US]] ], [ -1, [[LOOP]] ], [ -1, [[LOOP_US]] ], [ -2, [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
entry:
|
|
%x = load i32, ptr %x_p, align 4, !noundef !{}
|
|
br label %loop
|
|
|
|
loop: ; preds = %backedge, %entry
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%el.ptr = getelementptr i32, ptr %p, i32 %iv
|
|
%el = load i32, ptr %el.ptr, align 4
|
|
%bound_check = icmp sge i32 %el, 0
|
|
br i1 %bound_check, label %guarded, label %bound_check_failed, !prof !{!"branch_weights", i32 100, i32 1}
|
|
|
|
guarded: ; preds = %loop
|
|
%range_check = icmp ult i32 %el, %x
|
|
br i1 %range_check, label %backedge, label %range_check_failed, !prof !{!"branch_weights", i32 100, i32 1}
|
|
|
|
backedge: ; preds = %guarded
|
|
%arr.ptr = getelementptr i32, ptr %arr, i32 %el
|
|
store i32 %iv, ptr %arr.ptr, align 4
|
|
%iv.next = add i32 %iv, 1
|
|
%loop_cond = icmp slt i32 %iv.next, %n
|
|
br i1 %loop_cond, label %loop, label %exit
|
|
|
|
exit: ; preds = %backedge
|
|
ret i32 0
|
|
|
|
bound_check_failed: ; preds = %loop
|
|
ret i32 -1
|
|
|
|
range_check_failed: ; preds = %guarded
|
|
ret i32 -2
|
|
}
|
|
|
|
define i32 @test_02_inverse(ptr noundef %p, i32 noundef %n, i32 noundef %limit, ptr noundef %arr, ptr noundef %x_p) {
|
|
; CHECK-LABEL: @test_02_inverse(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[X_P:%.*]], align 4, !noundef !0
|
|
; CHECK-NEXT: [[INJECTED_COND:%.*]] = icmp ule i32 -2147483648, [[X]]
|
|
; CHECK-NEXT: br i1 [[INJECTED_COND]], label [[LOOP_US:%.*]], label [[LOOP:%.*]]
|
|
; CHECK: loop.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ [[IV_NEXT_US:%.*]], [[GUARDED_US:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[EL_PTR_US:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV_US]]
|
|
; CHECK-NEXT: [[EL_US:%.*]] = load i32, ptr [[EL_PTR_US]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK_US:%.*]] = icmp sge i32 [[EL_US]], 0
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK_US]], label [[GUARDED_US]], label [[COMMON_RET:%.*]], !prof [[PROF1]]
|
|
; CHECK: guarded.us:
|
|
; CHECK-NEXT: [[RANGE_CHECK_US:%.*]] = icmp uge i32 [[EL_US]], [[X]]
|
|
; CHECK-NEXT: [[ARR_PTR_US:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL_US]]
|
|
; CHECK-NEXT: store i32 [[IV_US]], ptr [[ARR_PTR_US]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: [[LOOP_COND_US:%.*]] = icmp slt i32 [[IV_NEXT_US]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND_US]], label [[LOOP_US]], label [[COMMON_RET]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[ENTRY]] ]
|
|
; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]]
|
|
; CHECK-NEXT: [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK:%.*]] = icmp sge i32 [[EL]], 0
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[GUARDED:%.*]], label [[COMMON_RET]], !prof [[PROF1]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp uge i32 [[EL]], [[X]]
|
|
; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[COMMON_RET]], label [[BACKEDGE]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[EL]]
|
|
; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[COMMON_RET]], !llvm.loop [[LOOP9:![0-9]+]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 0, [[BACKEDGE]] ], [ 0, [[GUARDED_US]] ], [ -1, [[LOOP]] ], [ -1, [[LOOP_US]] ], [ -2, [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
entry:
|
|
%x = load i32, ptr %x_p, align 4, !noundef !{}
|
|
br label %loop
|
|
|
|
loop: ; preds = %backedge, %entry
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%el.ptr = getelementptr i32, ptr %p, i32 %iv
|
|
%el = load i32, ptr %el.ptr, align 4
|
|
%bound_check = icmp sge i32 %el, 0
|
|
br i1 %bound_check, label %guarded, label %bound_check_failed, !prof !{!"branch_weights", i32 100, i32 1}
|
|
|
|
guarded: ; preds = %loop
|
|
%range_check = icmp uge i32 %el, %x
|
|
br i1 %range_check, label %range_check_failed, label %backedge, !prof !{!"branch_weights", i32 1, i32 100}
|
|
|
|
backedge: ; preds = %guarded
|
|
%arr.ptr = getelementptr i32, ptr %arr, i32 %el
|
|
store i32 %iv, ptr %arr.ptr, align 4
|
|
%iv.next = add i32 %iv, 1
|
|
%loop_cond = icmp slt i32 %iv.next, %n
|
|
br i1 %loop_cond, label %loop, label %exit
|
|
|
|
exit: ; preds = %backedge
|
|
ret i32 0
|
|
|
|
bound_check_failed: ; preds = %loop
|
|
ret i32 -1
|
|
|
|
range_check_failed: ; preds = %guarded
|
|
ret i32 -2
|
|
}
|
|
|
|
define i32 @test_03(ptr noundef %p, i32 noundef %n, i32 noundef %limit, ptr noundef %arr, ptr noundef %x_p) {
|
|
; CHECK-LABEL: @test_03(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[X_P:%.*]], align 4, !noundef !0
|
|
; CHECK-NEXT: [[INJECTED_COND:%.*]] = icmp ule i32 -2147483648, [[X]]
|
|
; CHECK-NEXT: br i1 [[INJECTED_COND]], label [[LOOP_US:%.*]], label [[LOOP:%.*]]
|
|
; CHECK: loop.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ [[IV_NEXT_US:%.*]], [[GUARDED_US:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[EL_PTR_US:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV_US]]
|
|
; CHECK-NEXT: [[EL_US:%.*]] = load i32, ptr [[EL_PTR_US]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK_US:%.*]] = icmp slt i32 [[EL_US]], 0
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK_US]], label [[COMMON_RET:%.*]], label [[GUARDED_US]], !prof [[PROF10:![0-9]+]]
|
|
; CHECK: guarded.us:
|
|
; CHECK-NEXT: [[RANGE_CHECK_US:%.*]] = icmp ult i32 [[EL_US]], [[X]]
|
|
; CHECK-NEXT: [[ARR_PTR_US:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL_US]]
|
|
; CHECK-NEXT: store i32 [[IV_US]], ptr [[ARR_PTR_US]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: [[LOOP_COND_US:%.*]] = icmp slt i32 [[IV_NEXT_US]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND_US]], label [[LOOP_US]], label [[COMMON_RET]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[ENTRY]] ]
|
|
; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]]
|
|
; CHECK-NEXT: [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK:%.*]] = icmp slt i32 [[EL]], 0
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[COMMON_RET]], label [[GUARDED:%.*]], !prof [[PROF10]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[EL]], [[X]]
|
|
; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[COMMON_RET]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[EL]]
|
|
; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[COMMON_RET]], !llvm.loop [[LOOP11:![0-9]+]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 0, [[BACKEDGE]] ], [ 0, [[GUARDED_US]] ], [ -1, [[LOOP]] ], [ -1, [[LOOP_US]] ], [ -2, [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
entry:
|
|
%x = load i32, ptr %x_p, align 4, !noundef !{}
|
|
br label %loop
|
|
|
|
loop: ; preds = %backedge, %entry
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%el.ptr = getelementptr i32, ptr %p, i32 %iv
|
|
%el = load i32, ptr %el.ptr, align 4
|
|
%bound_check = icmp slt i32 %el, 0
|
|
br i1 %bound_check, label %bound_check_failed, label %guarded, !prof !{!"branch_weights", i32 1, i32 100}
|
|
|
|
guarded: ; preds = %loop
|
|
%range_check = icmp ult i32 %el, %x
|
|
br i1 %range_check, label %backedge, label %range_check_failed, !prof !{!"branch_weights", i32 100, i32 1}
|
|
|
|
backedge: ; preds = %guarded
|
|
%arr.ptr = getelementptr i32, ptr %arr, i32 %el
|
|
store i32 %iv, ptr %arr.ptr, align 4
|
|
%iv.next = add i32 %iv, 1
|
|
%loop_cond = icmp slt i32 %iv.next, %n
|
|
br i1 %loop_cond, label %loop, label %exit
|
|
|
|
exit: ; preds = %backedge
|
|
ret i32 0
|
|
|
|
bound_check_failed: ; preds = %loop
|
|
ret i32 -1
|
|
|
|
range_check_failed: ; preds = %guarded
|
|
ret i32 -2
|
|
}
|
|
|
|
define i32 @test_04(ptr noundef %p, i32 noundef %n, i32 noundef %limit, ptr noundef %arr, ptr noundef %x_p) {
|
|
; CHECK-LABEL: @test_04(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[X_P:%.*]], align 4, !noundef !0
|
|
; CHECK-NEXT: [[INJECTED_COND:%.*]] = icmp ule i32 128, [[X]]
|
|
; CHECK-NEXT: br i1 [[INJECTED_COND]], label [[LOOP_US:%.*]], label [[LOOP:%.*]]
|
|
; CHECK: loop.us:
|
|
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ [[IV_NEXT_US:%.*]], [[GUARDED_US:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[EL_PTR_US:%.*]] = getelementptr i8, ptr [[P:%.*]], i32 [[IV_US]]
|
|
; CHECK-NEXT: [[EL_US:%.*]] = load i8, ptr [[EL_PTR_US]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK_US:%.*]] = icmp slt i8 [[EL_US]], 0
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK_US]], label [[COMMON_RET:%.*]], label [[GUARDED_US]], !prof [[PROF10]]
|
|
; CHECK: guarded.us:
|
|
; CHECK-NEXT: [[EL_WIDE_US:%.*]] = zext i8 [[EL_US]] to i32
|
|
; CHECK-NEXT: [[RANGE_CHECK_US:%.*]] = icmp ult i32 [[EL_WIDE_US]], [[X]]
|
|
; CHECK-NEXT: [[ARR_PTR_US:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL_WIDE_US]]
|
|
; CHECK-NEXT: store i32 [[IV_US]], ptr [[ARR_PTR_US]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
|
|
; CHECK-NEXT: [[LOOP_COND_US:%.*]] = icmp slt i32 [[IV_NEXT_US]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND_US]], label [[LOOP_US]], label [[COMMON_RET]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[ENTRY]] ]
|
|
; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i8, ptr [[P]], i32 [[IV]]
|
|
; CHECK-NEXT: [[EL:%.*]] = load i8, ptr [[EL_PTR]], align 4
|
|
; CHECK-NEXT: [[BOUND_CHECK:%.*]] = icmp slt i8 [[EL]], 0
|
|
; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[COMMON_RET]], label [[GUARDED:%.*]], !prof [[PROF10]]
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[EL_WIDE:%.*]] = zext i8 [[EL]] to i32
|
|
; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[EL_WIDE]], [[X]]
|
|
; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[COMMON_RET]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[EL_WIDE]]
|
|
; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[COMMON_RET]], !llvm.loop [[LOOP12:![0-9]+]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 0, [[BACKEDGE]] ], [ 0, [[GUARDED_US]] ], [ -1, [[LOOP]] ], [ -1, [[LOOP_US]] ], [ -2, [[GUARDED]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
entry:
|
|
%x = load i32, ptr %x_p, align 4, !noundef !{}
|
|
br label %loop
|
|
|
|
loop: ; preds = %backedge, %entry
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%el.ptr = getelementptr i8, ptr %p, i32 %iv
|
|
%el = load i8, ptr %el.ptr, align 4
|
|
%bound_check = icmp slt i8 %el, 0
|
|
br i1 %bound_check, label %bound_check_failed, label %guarded, !prof !{!"branch_weights", i32 1, i32 100}
|
|
|
|
guarded: ; preds = %loop
|
|
%el.wide = zext i8 %el to i32
|
|
%range_check = icmp ult i32 %el.wide, %x
|
|
br i1 %range_check, label %backedge, label %range_check_failed, !prof !{!"branch_weights", i32 100, i32 1}
|
|
|
|
backedge: ; preds = %guarded
|
|
%arr.ptr = getelementptr i32, ptr %arr, i32 %el.wide
|
|
store i32 %iv, ptr %arr.ptr, align 4
|
|
%iv.next = add i32 %iv, 1
|
|
%loop_cond = icmp slt i32 %iv.next, %n
|
|
br i1 %loop_cond, label %loop, label %exit
|
|
|
|
exit: ; preds = %backedge
|
|
ret i32 0
|
|
|
|
bound_check_failed: ; preds = %loop
|
|
ret i32 -1
|
|
|
|
range_check_failed: ; preds = %guarded
|
|
ret i32 -2
|
|
}
|
|
;.
|
|
; CHECK: [[META0:![0-9]+]] = !{}
|
|
; CHECK: [[PROF1]] = !{!"branch_weights", i32 100, i32 1}
|
|
; CHECK: [[LOOP2]] = distinct !{!2, !3}
|
|
; CHECK: [[META3:![0-9]+]] = !{!"llvm.loop.unswitch.injection.disable"}
|
|
; CHECK: [[LOOP4]] = distinct !{!4, !3}
|
|
; CHECK: [[PROF5]] = !{!"branch_weights", i32 0, i32 0}
|
|
; CHECK: [[PROF6]] = !{!"branch_weights", i32 2, i32 3}
|
|
; CHECK: [[PROF7]] = !{!"branch_weights", i32 -1, i32 -1000}
|
|
; CHECK: [[LOOP8]] = distinct !{!8, !3}
|
|
; CHECK: [[LOOP9]] = distinct !{!9, !3}
|
|
; CHECK: [[PROF10]] = !{!"branch_weights", i32 1, i32 100}
|
|
; CHECK: [[LOOP11]] = distinct !{!11, !3}
|
|
; CHECK: [[LOOP12]] = distinct !{!12, !3}
|
|
;.
|