|  | ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | 
|  | ; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s | 
|  |  | 
|  | ; Here we can remove range check because: | 
|  | ; length >= min_length (from entry) | 
|  | ; idx < min_length (from in_bounds check) | 
|  | ; therefore, idx < length is trivially true. | 
|  |  | 
|  | define i32 @test_01(ptr %p, ptr %array, i32 %min_length) { | 
|  | ; CHECK-LABEL: @test_01( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    br label [[LOOP:%.*]] | 
|  | ; CHECK:       loop: | 
|  | ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] | 
|  | ; CHECK-NEXT:    [[ELEM_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]] | 
|  | ; CHECK-NEXT:    [[IDX:%.*]] = load i32, ptr [[ELEM_PTR]], align 4 | 
|  | ; CHECK-NEXT:    [[IN_BOUNDS:%.*]] = icmp ult i32 [[IDX]], [[MIN_LENGTH:%.*]] | 
|  | ; CHECK-NEXT:    br i1 [[IN_BOUNDS]], label [[RANGE_CHECK_BLOCK:%.*]], label [[OUT_OF_BOUNDS:%.*]] | 
|  | ; CHECK:       range_check_block: | 
|  | ; CHECK-NEXT:    br i1 true, label [[BACKEDGE]], label [[RANGE_CHECK_FAILED:%.*]] | 
|  | ; CHECK:       backedge: | 
|  | ; CHECK-NEXT:    [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARRAY:%.*]], i32 [[IDX]] | 
|  | ; CHECK-NEXT:    store i32 [[IV]], ptr [[ARR_PTR]], align 4 | 
|  | ; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1 | 
|  | ; CHECK-NEXT:    [[LOOP_COND:%.*]] = call i1 @cond() | 
|  | ; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] | 
|  | ; CHECK:       exit: | 
|  | ; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[BACKEDGE]] ] | 
|  | ; CHECK-NEXT:    ret i32 [[IV_LCSSA]] | 
|  | ; CHECK:       out_of_bounds: | 
|  | ; CHECK-NEXT:    ret i32 -1 | 
|  | ; CHECK:       range_check_failed: | 
|  | ; CHECK-NEXT:    [[IV_LCSSA_RC:%.*]] = phi i32 [ [[IV]], [[RANGE_CHECK_BLOCK]] ] | 
|  | ; CHECK-NEXT:    call void @failed_range_check(i32 [[IV_LCSSA_RC]]) | 
|  | ; CHECK-NEXT:    unreachable | 
|  | ; | 
|  | entry: | 
|  | br label %loop | 
|  |  | 
|  | loop:                                             ; preds = %backedge, %entry | 
|  | %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ] | 
|  | %elem_ptr = getelementptr i32, ptr %p, i32 %iv | 
|  | %idx = load i32, ptr %elem_ptr, align 4 | 
|  | %in_bounds = icmp ult i32 %idx, %min_length | 
|  | br i1 %in_bounds, label %range_check_block, label %out_of_bounds | 
|  |  | 
|  | range_check_block:                                ; preds = %loop | 
|  | %range_check = icmp ult i32 %idx, %min_length | 
|  | br i1 %range_check, label %backedge, label %range_check_failed | 
|  |  | 
|  | backedge:                                         ; preds = %range_check_block | 
|  | %arr_ptr = getelementptr i32, ptr %array, i32 %idx | 
|  | store i32 %iv, ptr %arr_ptr, align 4 | 
|  | %iv.next = add i32 %iv, 1 | 
|  | %loop_cond = call i1 @cond() | 
|  | br i1 %loop_cond, label %loop, label %exit | 
|  |  | 
|  | exit:                                             ; preds = %backedge | 
|  | %iv.lcssa = phi i32 [ %iv, %backedge ] | 
|  | ret i32 %iv.lcssa | 
|  |  | 
|  | out_of_bounds:                                    ; preds = %loop | 
|  | ret i32 -1 | 
|  |  | 
|  | range_check_failed:                               ; preds = %range_check_block | 
|  | %iv.lcssa.rc = phi i32 [ %iv, %range_check_block ] | 
|  | call void @failed_range_check(i32 %iv.lcssa.rc) | 
|  | unreachable | 
|  | } | 
|  |  | 
|  | define i32 @test_02(ptr %p, ptr %array, i32 %length, i32 %min_length) { | 
|  | ; CHECK-LABEL: @test_02( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[LENGTH_CHECK:%.*]] = icmp uge i32 [[LENGTH:%.*]], [[MIN_LENGTH:%.*]] | 
|  | ; CHECK-NEXT:    br i1 [[LENGTH_CHECK]], label [[LOOP:%.*]], label [[FAILED:%.*]] | 
|  | ; CHECK:       loop: | 
|  | ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] | 
|  | ; CHECK-NEXT:    [[ELEM_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]] | 
|  | ; CHECK-NEXT:    [[IDX:%.*]] = load i32, ptr [[ELEM_PTR]], align 4 | 
|  | ; CHECK-NEXT:    [[IN_BOUNDS:%.*]] = icmp ult i32 [[IDX]], [[MIN_LENGTH]] | 
|  | ; CHECK-NEXT:    br i1 [[IN_BOUNDS]], label [[RANGE_CHECK_BLOCK:%.*]], label [[OUT_OF_BOUNDS:%.*]] | 
|  | ; CHECK:       range_check_block: | 
|  | ; CHECK-NEXT:    br i1 true, label [[BACKEDGE]], label [[RANGE_CHECK_FAILED:%.*]] | 
|  | ; CHECK:       backedge: | 
|  | ; CHECK-NEXT:    [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARRAY:%.*]], i32 [[IDX]] | 
|  | ; CHECK-NEXT:    store i32 [[IV]], ptr [[ARR_PTR]], align 4 | 
|  | ; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1 | 
|  | ; CHECK-NEXT:    [[LOOP_COND:%.*]] = call i1 @cond() | 
|  | ; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] | 
|  | ; CHECK:       exit: | 
|  | ; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[BACKEDGE]] ] | 
|  | ; CHECK-NEXT:    ret i32 [[IV_LCSSA]] | 
|  | ; CHECK:       failed: | 
|  | ; CHECK-NEXT:    unreachable | 
|  | ; CHECK:       out_of_bounds: | 
|  | ; CHECK-NEXT:    ret i32 -1 | 
|  | ; CHECK:       range_check_failed: | 
|  | ; CHECK-NEXT:    [[IV_LCSSA_RC:%.*]] = phi i32 [ [[IV]], [[RANGE_CHECK_BLOCK]] ] | 
|  | ; CHECK-NEXT:    call void @failed_range_check(i32 [[IV_LCSSA_RC]]) | 
|  | ; CHECK-NEXT:    unreachable | 
|  | ; | 
|  | entry: | 
|  | %length_check = icmp uge i32 %length, %min_length | 
|  | br i1 %length_check, label %loop, label %failed | 
|  |  | 
|  | loop:                                             ; preds = %backedge, %entry | 
|  | %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ] | 
|  | %elem_ptr = getelementptr i32, ptr %p, i32 %iv | 
|  | %idx = load i32, ptr %elem_ptr, align 4 | 
|  | %in_bounds = icmp ult i32 %idx, %min_length | 
|  | br i1 %in_bounds, label %range_check_block, label %out_of_bounds | 
|  |  | 
|  | range_check_block:                                ; preds = %loop | 
|  | %range_check = icmp ult i32 %idx, %length | 
|  | br i1 %range_check, label %backedge, label %range_check_failed | 
|  |  | 
|  | backedge:                                         ; preds = %range_check_block | 
|  | %arr_ptr = getelementptr i32, ptr %array, i32 %idx | 
|  | store i32 %iv, ptr %arr_ptr, align 4 | 
|  | %iv.next = add i32 %iv, 1 | 
|  | %loop_cond = call i1 @cond() | 
|  | br i1 %loop_cond, label %loop, label %exit | 
|  |  | 
|  | exit:                                             ; preds = %backedge | 
|  | %iv.lcssa = phi i32 [ %iv, %backedge ] | 
|  | ret i32 %iv.lcssa | 
|  |  | 
|  | failed:                                           ; preds = %entry | 
|  | unreachable | 
|  |  | 
|  | out_of_bounds:                                    ; preds = %loop | 
|  | ret i32 -1 | 
|  |  | 
|  | range_check_failed:                               ; preds = %range_check_block | 
|  | %iv.lcssa.rc = phi i32 [ %iv, %range_check_block ] | 
|  | call void @failed_range_check(i32 %iv.lcssa.rc) | 
|  | unreachable | 
|  | } | 
|  |  | 
|  | declare i1 @cond() | 
|  |  | 
|  | declare void @failed_range_check(i32) |