| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: opt -passes=loop-interchange -loop-interchange-profitabilities=ignore -S %s | FileCheck %s |
| |
| ; choice = freeze(poison); |
| ; sum = 0.0; |
| ; for (i = 0; i < 4; i++) |
| ; for (j = 0; j < 4; j++) |
| ; sum += choice ? A[j][i] : 0.0; |
| ; Interchange is allowed because the outer preheader keeps its loop depth and |
| ; execution count. |
| define void @outer_preheader_freeze(ptr noalias %A, ptr noalias %R) { |
| ; CHECK-LABEL: define void @outer_preheader_freeze( |
| ; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br label %[[INNER_HEADER_PREHEADER:.*]] |
| ; CHECK: [[OUTER_PREHEADER:.*]]: |
| ; CHECK-NEXT: br label %[[OUTER_HEADER:.*]] |
| ; CHECK: [[OUTER_HEADER]]: |
| ; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[OUTER_PREHEADER]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ] |
| ; CHECK-NEXT: [[SUM_J:%.*]] = phi double [ [[SUM_NEXT_J:%.*]], %[[OUTER_LATCH]] ], [ [[SUM_I:%.*]], %[[OUTER_PREHEADER]] ] |
| ; CHECK-NEXT: br label %[[INNER_HEADER_SPLIT1:.*]] |
| ; CHECK: [[INNER_HEADER_PREHEADER]]: |
| ; CHECK-NEXT: [[CHOICE:%.*]] = freeze i1 poison |
| ; CHECK-NEXT: br label %[[INNER_HEADER:.*]] |
| ; CHECK: [[INNER_HEADER]]: |
| ; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[TMP0:%.*]], %[[INNER_HEADER_SPLIT:.*]] ], [ 0, %[[INNER_HEADER_PREHEADER]] ] |
| ; CHECK-NEXT: [[SUM_I]] = phi double [ 0.000000e+00, %[[INNER_HEADER_PREHEADER]] ], [ [[SUM_NEXT:%.*]], %[[INNER_HEADER_SPLIT]] ] |
| ; CHECK-NEXT: br label %[[OUTER_PREHEADER]] |
| ; CHECK: [[INNER_HEADER_SPLIT1]]: |
| ; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]] |
| ; CHECK-NEXT: [[VALUE:%.*]] = load double, ptr [[IDX]], align 8 |
| ; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[CHOICE]], double [[VALUE]], double 0.000000e+00 |
| ; CHECK-NEXT: [[SUM_NEXT_J]] = fadd reassoc double [[SUM_J]], [[SELECTED]] |
| ; CHECK-NEXT: [[J_NEXT:%.*]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4 |
| ; CHECK-NEXT: br label %[[OUTER_LATCH]] |
| ; CHECK: [[INNER_HEADER_SPLIT]]: |
| ; CHECK-NEXT: [[SUM_NEXT]] = phi double [ [[SUM_NEXT_J]], %[[OUTER_LATCH]] ] |
| ; CHECK-NEXT: [[TMP0]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], 4 |
| ; CHECK-NEXT: br i1 [[TMP1]], label %[[EXIT:.*]], label %[[INNER_HEADER]] |
| ; CHECK: [[OUTER_LATCH]]: |
| ; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1 |
| ; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[I_EC]], label %[[INNER_HEADER_SPLIT]], label %[[OUTER_HEADER]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[SUM_RESULT:%.*]] = phi double [ [[SUM_NEXT]], %[[INNER_HEADER_SPLIT]] ] |
| ; CHECK-NEXT: store double [[SUM_RESULT]], ptr [[R]], align 8 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %outer.preheader |
| |
| outer.preheader: |
| %choice = freeze i1 poison |
| br label %outer.header |
| |
| outer.header: |
| %i = phi i64 [ 0, %outer.preheader ], [ %i.next, %outer.latch ] |
| %sum.i = phi double [ 0.000000e+00, %outer.preheader ], [ %sum.next, %outer.latch ] |
| br label %inner.header |
| |
| inner.header: |
| %j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ] |
| %sum.j = phi double [ %sum.i, %outer.header ], [ %sum.next.j, %inner.header ] |
| %idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i |
| %value = load double, ptr %idx, align 8 |
| %selected = select i1 %choice, double %value, double 0.000000e+00 |
| %sum.next.j = fadd reassoc double %sum.j, %selected |
| %j.next = add i64 %j, 1 |
| %j.ec = icmp eq i64 %j.next, 4 |
| br i1 %j.ec, label %outer.latch, label %inner.header |
| |
| outer.latch: |
| %sum.next = phi double [ %sum.next.j, %inner.header ] |
| %i.next = add i64 %i, 1 |
| %i.ec = icmp eq i64 %i.next, 4 |
| br i1 %i.ec, label %exit, label %outer.header |
| |
| exit: |
| %sum.result = phi double [ %sum.next, %outer.latch ] |
| store double %sum.result, ptr %R, align 8 |
| ret void |
| } |
| |
| ; sum = 0.0; |
| ; for (i = 0; i < 4; i++) |
| ; for (j = 0; j < 4; j++) { |
| ; choice = freeze(poison); |
| ; sum += choice ? A[j][i] : 0.0; |
| ; } |
| ; Interchange is allowed because the freeze in the inner-loop body keeps its |
| ; loop depth and is not cloned. |
| define void @inner_body_freeze(ptr noalias %A, ptr noalias %R) { |
| ; CHECK-LABEL: define void @inner_body_freeze( |
| ; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br label %[[INNER_HEADER_PREHEADER:.*]] |
| ; CHECK: [[OUTER_HEADER_PREHEADER:.*]]: |
| ; CHECK-NEXT: br label %[[OUTER_HEADER:.*]] |
| ; CHECK: [[OUTER_HEADER]]: |
| ; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ], [ 0, %[[OUTER_HEADER_PREHEADER]] ] |
| ; CHECK-NEXT: [[SUM_J:%.*]] = phi double [ [[SUM_NEXT_J:%.*]], %[[OUTER_LATCH]] ], [ [[SUM_I:%.*]], %[[OUTER_HEADER_PREHEADER]] ] |
| ; CHECK-NEXT: br label %[[INNER_HEADER_SPLIT1:.*]] |
| ; CHECK: [[INNER_HEADER_PREHEADER]]: |
| ; CHECK-NEXT: br label %[[INNER_HEADER:.*]] |
| ; CHECK: [[INNER_HEADER]]: |
| ; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[TMP0:%.*]], %[[INNER_HEADER_SPLIT:.*]] ], [ 0, %[[INNER_HEADER_PREHEADER]] ] |
| ; CHECK-NEXT: [[SUM_I]] = phi double [ [[SUM_NEXT:%.*]], %[[INNER_HEADER_SPLIT]] ], [ 0.000000e+00, %[[INNER_HEADER_PREHEADER]] ] |
| ; CHECK-NEXT: br label %[[OUTER_HEADER_PREHEADER]] |
| ; CHECK: [[INNER_HEADER_SPLIT1]]: |
| ; CHECK-NEXT: [[CHOICE:%.*]] = freeze i1 poison |
| ; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]] |
| ; CHECK-NEXT: [[VALUE:%.*]] = load double, ptr [[IDX]], align 8 |
| ; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[CHOICE]], double [[VALUE]], double 0.000000e+00 |
| ; CHECK-NEXT: [[SUM_NEXT_J]] = fadd reassoc double [[SUM_J]], [[SELECTED]] |
| ; CHECK-NEXT: [[J_NEXT:%.*]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4 |
| ; CHECK-NEXT: br label %[[OUTER_LATCH]] |
| ; CHECK: [[INNER_HEADER_SPLIT]]: |
| ; CHECK-NEXT: [[SUM_NEXT]] = phi double [ [[SUM_NEXT_J]], %[[OUTER_LATCH]] ] |
| ; CHECK-NEXT: [[TMP0]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], 4 |
| ; CHECK-NEXT: br i1 [[TMP1]], label %[[EXIT:.*]], label %[[INNER_HEADER]] |
| ; CHECK: [[OUTER_LATCH]]: |
| ; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1 |
| ; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[I_EC]], label %[[INNER_HEADER_SPLIT]], label %[[OUTER_HEADER]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[SUM_RESULT:%.*]] = phi double [ [[SUM_NEXT]], %[[INNER_HEADER_SPLIT]] ] |
| ; CHECK-NEXT: store double [[SUM_RESULT]], ptr [[R]], align 8 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %outer.header |
| |
| outer.header: |
| %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ] |
| %sum.i = phi double [ 0.000000e+00, %entry ], [ %sum.next, %outer.latch ] |
| br label %inner.header |
| |
| inner.header: |
| %j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ] |
| %sum.j = phi double [ %sum.i, %outer.header ], [ %sum.next.j, %inner.header ] |
| %choice = freeze i1 poison |
| %idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i |
| %value = load double, ptr %idx, align 8 |
| %selected = select i1 %choice, double %value, double 0.000000e+00 |
| %sum.next.j = fadd reassoc double %sum.j, %selected |
| %j.next = add i64 %j, 1 |
| %j.ec = icmp eq i64 %j.next, 4 |
| br i1 %j.ec, label %outer.latch, label %inner.header |
| |
| outer.latch: |
| %sum.next = phi double [ %sum.next.j, %inner.header ] |
| %i.next = add i64 %i, 1 |
| %i.ec = icmp eq i64 %i.next, 4 |
| br i1 %i.ec, label %exit, label %outer.header |
| |
| exit: |
| %sum.result = phi double [ %sum.next, %outer.latch ] |
| store double %sum.result, ptr %R, align 8 |
| ret void |
| } |
| |
| ; Interchange is allowed because the distinct outer-header and inner-preheader |
| ; blocks contain no freeze. |
| define void @header_preheader_control(ptr noalias %A, i1 %choice) { |
| ; CHECK-LABEL: define void @header_preheader_control( |
| ; CHECK-SAME: ptr noalias [[A:%.*]], i1 [[CHOICE:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br label %[[INNER_PREHEADER:.*]] |
| ; CHECK: [[OUTER_HEADER_PREHEADER:.*]]: |
| ; CHECK-NEXT: br label %[[OUTER_HEADER:.*]] |
| ; CHECK: [[OUTER_HEADER]]: |
| ; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ], [ 0, %[[OUTER_HEADER_PREHEADER]] ] |
| ; CHECK-NEXT: [[HEADER_BIT:%.*]] = xor i1 [[CHOICE]], true |
| ; CHECK-NEXT: [[PREHEADER_BIT:%.*]] = xor i1 [[CHOICE]], false |
| ; CHECK-NEXT: [[SELECTED_BIT:%.*]] = and i1 [[HEADER_BIT]], [[PREHEADER_BIT]] |
| ; CHECK-NEXT: br label %[[INNER_HEADER_SPLIT1:.*]] |
| ; CHECK: [[INNER_PREHEADER]]: |
| ; CHECK-NEXT: br label %[[INNER_HEADER:.*]] |
| ; CHECK: [[INNER_HEADER]]: |
| ; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, %[[INNER_PREHEADER]] ], [ [[TMP0:%.*]], %[[INNER_HEADER_SPLIT:.*]] ] |
| ; CHECK-NEXT: br label %[[OUTER_HEADER_PREHEADER]] |
| ; CHECK: [[INNER_HEADER_SPLIT1]]: |
| ; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[SELECTED_BIT]], double 1.000000e+00, double 0.000000e+00 |
| ; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]] |
| ; CHECK-NEXT: store double [[SELECTED]], ptr [[IDX]], align 8 |
| ; CHECK-NEXT: [[J_NEXT:%.*]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4 |
| ; CHECK-NEXT: br label %[[OUTER_LATCH]] |
| ; CHECK: [[INNER_HEADER_SPLIT]]: |
| ; CHECK-NEXT: [[TMP0]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], 4 |
| ; CHECK-NEXT: br i1 [[TMP1]], label %[[EXIT:.*]], label %[[INNER_HEADER]] |
| ; CHECK: [[OUTER_LATCH]]: |
| ; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1 |
| ; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[I_EC]], label %[[INNER_HEADER_SPLIT]], label %[[OUTER_HEADER]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %outer.header |
| |
| outer.header: |
| %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ] |
| %header.bit = xor i1 %choice, true |
| br label %inner.preheader |
| |
| inner.preheader: |
| %preheader.bit = xor i1 %choice, false |
| %selected.bit = and i1 %header.bit, %preheader.bit |
| br label %inner.header |
| |
| inner.header: |
| %j = phi i64 [ 0, %inner.preheader ], [ %j.next, %inner.header ] |
| %selected = select i1 %selected.bit, double 1.000000e+00, double 0.000000e+00 |
| %idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i |
| store double %selected, ptr %idx, align 8 |
| %j.next = add i64 %j, 1 |
| %j.ec = icmp eq i64 %j.next, 4 |
| br i1 %j.ec, label %outer.latch, label %inner.header |
| |
| outer.latch: |
| %i.next = add i64 %i, 1 |
| %i.ec = icmp eq i64 %i.next, 4 |
| br i1 %i.ec, label %exit, label %outer.header |
| |
| exit: |
| ret void |
| } |
| |
| ; choice = freeze(poison) in the outer header, before a distinct inner |
| ; preheader. |
| ; Interchange is rejected because the freeze in the outer header would move to |
| ; a different loop depth. |
| define void @outer_header_freeze(ptr noalias %A, i1 %choice) { |
| ; CHECK-LABEL: define void @outer_header_freeze( |
| ; CHECK-SAME: ptr noalias [[A:%.*]], i1 [[CHOICE:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NEXT: br label %[[OUTER_HEADER:.*]] |
| ; CHECK: [[OUTER_HEADER]]: |
| ; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ] |
| ; CHECK-NEXT: [[HEADER_BIT:%.*]] = freeze i1 poison |
| ; CHECK-NEXT: br label %[[INNER_PREHEADER:.*]] |
| ; CHECK: [[INNER_PREHEADER]]: |
| ; CHECK-NEXT: [[PREHEADER_BIT:%.*]] = xor i1 [[CHOICE]], false |
| ; CHECK-NEXT: [[SELECTED_BIT:%.*]] = and i1 [[HEADER_BIT]], [[PREHEADER_BIT]] |
| ; CHECK-NEXT: br label %[[INNER_HEADER:.*]] |
| ; CHECK: [[INNER_HEADER]]: |
| ; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, %[[INNER_PREHEADER]] ], [ [[J_NEXT:%.*]], %[[INNER_HEADER]] ] |
| ; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[SELECTED_BIT]], double 1.000000e+00, double 0.000000e+00 |
| ; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]] |
| ; CHECK-NEXT: store double [[SELECTED]], ptr [[IDX]], align 8 |
| ; CHECK-NEXT: [[J_NEXT]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[J_EC]], label %[[OUTER_LATCH]], label %[[INNER_HEADER]] |
| ; CHECK: [[OUTER_LATCH]]: |
| ; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1 |
| ; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[I_EC]], label %[[EXIT:.*]], label %[[OUTER_HEADER]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %outer.header |
| |
| outer.header: |
| %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ] |
| %header.bit = freeze i1 poison |
| br label %inner.preheader |
| |
| inner.preheader: |
| %preheader.bit = xor i1 %choice, false |
| %selected.bit = and i1 %header.bit, %preheader.bit |
| br label %inner.header |
| |
| inner.header: |
| %j = phi i64 [ 0, %inner.preheader ], [ %j.next, %inner.header ] |
| %selected = select i1 %selected.bit, double 1.000000e+00, double 0.000000e+00 |
| %idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i |
| store double %selected, ptr %idx, align 8 |
| %j.next = add i64 %j, 1 |
| %j.ec = icmp eq i64 %j.next, 4 |
| br i1 %j.ec, label %outer.latch, label %inner.header |
| |
| outer.latch: |
| %i.next = add i64 %i, 1 |
| %i.ec = icmp eq i64 %i.next, 4 |
| br i1 %i.ec, label %exit, label %outer.header |
| |
| exit: |
| ret void |
| } |
| |
| ; choice = freeze(poison) in the inner preheader, after a distinct outer |
| ; header. |
| ; Interchange is rejected because the freeze in the inner preheader would move |
| ; to a different loop depth. |
| define void @inner_preheader_freeze(ptr noalias %A, i1 %choice) { |
| ; CHECK-LABEL: define void @inner_preheader_freeze( |
| ; CHECK-SAME: ptr noalias [[A:%.*]], i1 [[CHOICE:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NEXT: br label %[[OUTER_HEADER:.*]] |
| ; CHECK: [[OUTER_HEADER]]: |
| ; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ] |
| ; CHECK-NEXT: [[HEADER_BIT:%.*]] = xor i1 [[CHOICE]], true |
| ; CHECK-NEXT: br label %[[INNER_PREHEADER:.*]] |
| ; CHECK: [[INNER_PREHEADER]]: |
| ; CHECK-NEXT: [[PREHEADER_BIT:%.*]] = freeze i1 poison |
| ; CHECK-NEXT: [[SELECTED_BIT:%.*]] = and i1 [[HEADER_BIT]], [[PREHEADER_BIT]] |
| ; CHECK-NEXT: br label %[[INNER_HEADER:.*]] |
| ; CHECK: [[INNER_HEADER]]: |
| ; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, %[[INNER_PREHEADER]] ], [ [[J_NEXT:%.*]], %[[INNER_HEADER]] ] |
| ; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[SELECTED_BIT]], double 1.000000e+00, double 0.000000e+00 |
| ; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]] |
| ; CHECK-NEXT: store double [[SELECTED]], ptr [[IDX]], align 8 |
| ; CHECK-NEXT: [[J_NEXT]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[J_EC]], label %[[OUTER_LATCH]], label %[[INNER_HEADER]] |
| ; CHECK: [[OUTER_LATCH]]: |
| ; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1 |
| ; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[I_EC]], label %[[EXIT:.*]], label %[[OUTER_HEADER]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %outer.header |
| |
| outer.header: |
| %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ] |
| %header.bit = xor i1 %choice, true |
| br label %inner.preheader |
| |
| inner.preheader: |
| %preheader.bit = freeze i1 poison |
| %selected.bit = and i1 %header.bit, %preheader.bit |
| br label %inner.header |
| |
| inner.header: |
| %j = phi i64 [ 0, %inner.preheader ], [ %j.next, %inner.header ] |
| %selected = select i1 %selected.bit, double 1.000000e+00, double 0.000000e+00 |
| %idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i |
| store double %selected, ptr %idx, align 8 |
| %j.next = add i64 %j, 1 |
| %j.ec = icmp eq i64 %j.next, 4 |
| br i1 %j.ec, label %outer.latch, label %inner.header |
| |
| outer.latch: |
| %i.next = add i64 %i, 1 |
| %i.ec = icmp eq i64 %i.next, 4 |
| br i1 %i.ec, label %exit, label %outer.header |
| |
| exit: |
| ret void |
| } |
| |
| ; Interchange is allowed because the distinct inner-exit and outer-latch blocks |
| ; contain no freeze. |
| define void @exit_latch_control(ptr noalias %A, ptr noalias %R, i1 %choice) { |
| ; CHECK-LABEL: define void @exit_latch_control( |
| ; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]], i1 [[CHOICE:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br label %[[OUTER_HEADER:.*]] |
| ; CHECK: [[OUTER_HEADER_PREHEADER:.*]]: |
| ; CHECK-NEXT: br label %[[INNER_HEADER:.*]] |
| ; CHECK: [[INNER_HEADER]]: |
| ; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ], [ 0, %[[OUTER_HEADER_PREHEADER]] ] |
| ; CHECK-NEXT: br label %[[INNER_HEADER_SPLIT1:.*]] |
| ; CHECK: [[OUTER_HEADER]]: |
| ; CHECK-NEXT: br label %[[INNER_HEADER1:.*]] |
| ; CHECK: [[INNER_HEADER1]]: |
| ; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[TMP2:%.*]], %[[INNER_HEADER_SPLIT:.*]] ], [ 0, %[[OUTER_HEADER]] ] |
| ; CHECK-NEXT: br label %[[OUTER_HEADER_PREHEADER]] |
| ; CHECK: [[INNER_HEADER_SPLIT1]]: |
| ; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]] |
| ; CHECK-NEXT: store double 1.000000e+00, ptr [[IDX]], align 8 |
| ; CHECK-NEXT: [[J_NEXT:%.*]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4 |
| ; CHECK-NEXT: br label %[[INNER_EXIT:.*]] |
| ; CHECK: [[INNER_HEADER_SPLIT]]: |
| ; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ [[EXIT_BIT:%.*]], %[[OUTER_LATCH]] ] |
| ; CHECK-NEXT: [[TMP1:%.*]] = phi i1 [ [[LATCH_BIT:%.*]], %[[OUTER_LATCH]] ] |
| ; CHECK-NEXT: [[TMP2]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], 4 |
| ; CHECK-NEXT: br i1 [[TMP3]], label %[[EXIT:.*]], label %[[INNER_HEADER1]] |
| ; CHECK: [[INNER_EXIT]]: |
| ; CHECK-NEXT: [[EXIT_BIT]] = xor i1 [[CHOICE]], true |
| ; CHECK-NEXT: br label %[[OUTER_LATCH]] |
| ; CHECK: [[OUTER_LATCH]]: |
| ; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1 |
| ; CHECK-NEXT: [[LATCH_BIT]] = xor i1 [[CHOICE]], false |
| ; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[I_EC]], label %[[INNER_HEADER_SPLIT]], label %[[INNER_HEADER]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[EXIT_OUT:%.*]] = phi i1 [ [[TMP0]], %[[INNER_HEADER_SPLIT]] ] |
| ; CHECK-NEXT: [[LATCH_OUT:%.*]] = phi i1 [ [[TMP1]], %[[INNER_HEADER_SPLIT]] ] |
| ; CHECK-NEXT: [[SELECTED_OUT:%.*]] = and i1 [[EXIT_OUT]], [[LATCH_OUT]] |
| ; CHECK-NEXT: [[VALUE:%.*]] = select i1 [[SELECTED_OUT]], double 1.000000e+00, double 0.000000e+00 |
| ; CHECK-NEXT: store double [[VALUE]], ptr [[R]], align 8 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %outer.header |
| |
| outer.header: |
| %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ] |
| br label %inner.header |
| |
| inner.header: |
| %j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ] |
| %idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i |
| store double 1.000000e+00, ptr %idx, align 8 |
| %j.next = add i64 %j, 1 |
| %j.ec = icmp eq i64 %j.next, 4 |
| br i1 %j.ec, label %inner.exit, label %inner.header |
| |
| inner.exit: |
| %exit.bit = xor i1 %choice, true |
| br label %outer.latch |
| |
| outer.latch: |
| %exit.bit.lcssa = phi i1 [ %exit.bit, %inner.exit ] |
| %i.next = add i64 %i, 1 |
| %latch.bit = xor i1 %choice, false |
| %i.ec = icmp eq i64 %i.next, 4 |
| br i1 %i.ec, label %exit, label %outer.header |
| |
| exit: |
| %exit.out = phi i1 [ %exit.bit.lcssa, %outer.latch ] |
| %latch.out = phi i1 [ %latch.bit, %outer.latch ] |
| %selected.out = and i1 %exit.out, %latch.out |
| %value = select i1 %selected.out, double 1.000000e+00, double 0.000000e+00 |
| store double %value, ptr %R, align 8 |
| ret void |
| } |
| |
| ; choice = freeze(poison) in the inner exit, before a distinct outer latch. |
| ; Interchange is rejected because the freeze in the inner exit would move to a |
| ; different loop depth. |
| define void @inner_exit_freeze(ptr noalias %A, ptr noalias %R, i1 %choice) { |
| ; CHECK-LABEL: define void @inner_exit_freeze( |
| ; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]], i1 [[CHOICE:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NEXT: br label %[[OUTER_HEADER:.*]] |
| ; CHECK: [[OUTER_HEADER]]: |
| ; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ] |
| ; CHECK-NEXT: br label %[[INNER_HEADER:.*]] |
| ; CHECK: [[INNER_HEADER]]: |
| ; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, %[[OUTER_HEADER]] ], [ [[J_NEXT:%.*]], %[[INNER_HEADER]] ] |
| ; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]] |
| ; CHECK-NEXT: store double 1.000000e+00, ptr [[IDX]], align 8 |
| ; CHECK-NEXT: [[J_NEXT]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[J_EC]], label %[[INNER_EXIT:.*]], label %[[INNER_HEADER]] |
| ; CHECK: [[INNER_EXIT]]: |
| ; CHECK-NEXT: [[EXIT_BIT:%.*]] = freeze i1 poison |
| ; CHECK-NEXT: br label %[[OUTER_LATCH]] |
| ; CHECK: [[OUTER_LATCH]]: |
| ; CHECK-NEXT: [[EXIT_BIT_LCSSA:%.*]] = phi i1 [ [[EXIT_BIT]], %[[INNER_EXIT]] ] |
| ; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1 |
| ; CHECK-NEXT: [[LATCH_BIT:%.*]] = xor i1 [[CHOICE]], false |
| ; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[I_EC]], label %[[EXIT:.*]], label %[[OUTER_HEADER]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[EXIT_OUT:%.*]] = phi i1 [ [[EXIT_BIT_LCSSA]], %[[OUTER_LATCH]] ] |
| ; CHECK-NEXT: [[LATCH_OUT:%.*]] = phi i1 [ [[LATCH_BIT]], %[[OUTER_LATCH]] ] |
| ; CHECK-NEXT: [[SELECTED_OUT:%.*]] = and i1 [[EXIT_OUT]], [[LATCH_OUT]] |
| ; CHECK-NEXT: [[VALUE:%.*]] = select i1 [[SELECTED_OUT]], double 1.000000e+00, double 0.000000e+00 |
| ; CHECK-NEXT: store double [[VALUE]], ptr [[R]], align 8 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %outer.header |
| |
| outer.header: |
| %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ] |
| br label %inner.header |
| |
| inner.header: |
| %j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ] |
| %idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i |
| store double 1.000000e+00, ptr %idx, align 8 |
| %j.next = add i64 %j, 1 |
| %j.ec = icmp eq i64 %j.next, 4 |
| br i1 %j.ec, label %inner.exit, label %inner.header |
| |
| inner.exit: |
| %exit.bit = freeze i1 poison |
| br label %outer.latch |
| |
| outer.latch: |
| %exit.bit.lcssa = phi i1 [ %exit.bit, %inner.exit ] |
| %i.next = add i64 %i, 1 |
| %latch.bit = xor i1 %choice, false |
| %i.ec = icmp eq i64 %i.next, 4 |
| br i1 %i.ec, label %exit, label %outer.header |
| |
| exit: |
| %exit.out = phi i1 [ %exit.bit.lcssa, %outer.latch ] |
| %latch.out = phi i1 [ %latch.bit, %outer.latch ] |
| %selected.out = and i1 %exit.out, %latch.out |
| %value = select i1 %selected.out, double 1.000000e+00, double 0.000000e+00 |
| store double %value, ptr %R, align 8 |
| ret void |
| } |
| |
| ; choice = freeze(poison) in the outer latch, after a distinct inner exit. |
| ; Interchange is rejected because the freeze in the outer latch would move to a |
| ; different loop depth. |
| define void @outer_latch_freeze(ptr noalias %A, ptr noalias %R, i1 %choice) { |
| ; CHECK-LABEL: define void @outer_latch_freeze( |
| ; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]], i1 [[CHOICE:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NEXT: br label %[[OUTER_HEADER:.*]] |
| ; CHECK: [[OUTER_HEADER]]: |
| ; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ] |
| ; CHECK-NEXT: br label %[[INNER_HEADER:.*]] |
| ; CHECK: [[INNER_HEADER]]: |
| ; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, %[[OUTER_HEADER]] ], [ [[J_NEXT:%.*]], %[[INNER_HEADER]] ] |
| ; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]] |
| ; CHECK-NEXT: store double 1.000000e+00, ptr [[IDX]], align 8 |
| ; CHECK-NEXT: [[J_NEXT]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[J_EC]], label %[[INNER_EXIT:.*]], label %[[INNER_HEADER]] |
| ; CHECK: [[INNER_EXIT]]: |
| ; CHECK-NEXT: [[EXIT_BIT:%.*]] = xor i1 [[CHOICE]], true |
| ; CHECK-NEXT: br label %[[OUTER_LATCH]] |
| ; CHECK: [[OUTER_LATCH]]: |
| ; CHECK-NEXT: [[EXIT_BIT_LCSSA:%.*]] = phi i1 [ [[EXIT_BIT]], %[[INNER_EXIT]] ] |
| ; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1 |
| ; CHECK-NEXT: [[LATCH_BIT:%.*]] = freeze i1 poison |
| ; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[I_EC]], label %[[EXIT:.*]], label %[[OUTER_HEADER]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[EXIT_OUT:%.*]] = phi i1 [ [[EXIT_BIT_LCSSA]], %[[OUTER_LATCH]] ] |
| ; CHECK-NEXT: [[LATCH_OUT:%.*]] = phi i1 [ [[LATCH_BIT]], %[[OUTER_LATCH]] ] |
| ; CHECK-NEXT: [[SELECTED_OUT:%.*]] = and i1 [[EXIT_OUT]], [[LATCH_OUT]] |
| ; CHECK-NEXT: [[VALUE:%.*]] = select i1 [[SELECTED_OUT]], double 1.000000e+00, double 0.000000e+00 |
| ; CHECK-NEXT: store double [[VALUE]], ptr [[R]], align 8 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %outer.header |
| |
| outer.header: |
| %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ] |
| br label %inner.header |
| |
| inner.header: |
| %j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ] |
| %idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i |
| store double 1.000000e+00, ptr %idx, align 8 |
| %j.next = add i64 %j, 1 |
| %j.ec = icmp eq i64 %j.next, 4 |
| br i1 %j.ec, label %inner.exit, label %inner.header |
| |
| inner.exit: |
| %exit.bit = xor i1 %choice, true |
| br label %outer.latch |
| |
| outer.latch: |
| %exit.bit.lcssa = phi i1 [ %exit.bit, %inner.exit ] |
| %i.next = add i64 %i, 1 |
| %latch.bit = freeze i1 poison |
| %i.ec = icmp eq i64 %i.next, 4 |
| br i1 %i.ec, label %exit, label %outer.header |
| |
| exit: |
| %exit.out = phi i1 [ %exit.bit.lcssa, %outer.latch ] |
| %latch.out = phi i1 [ %latch.bit, %outer.latch ] |
| %selected.out = and i1 %exit.out, %latch.out |
| %value = select i1 %selected.out, double 1.000000e+00, double 0.000000e+00 |
| store double %value, ptr %R, align 8 |
| ret void |
| } |
| |
| ; Interchange is allowed because neither cloned operand set contains a freeze. |
| define void @inner_latch_clone_control(ptr noalias %A, ptr noalias %R, |
| ; CHECK-LABEL: define void @inner_latch_clone_control( |
| ; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]], i1 [[CONDITION_ARG:%.*]], i1 [[STEP_ARG:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br label %[[INNER_HEADER_PREHEADER:.*]] |
| ; CHECK: [[OUTER_HEADER_PREHEADER:.*]]: |
| ; CHECK-NEXT: br label %[[OUTER_HEADER:.*]] |
| ; CHECK: [[OUTER_HEADER]]: |
| ; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ], [ 0, %[[OUTER_HEADER_PREHEADER]] ] |
| ; CHECK-NEXT: br label %[[INNER_HEADER_SPLIT1:.*]] |
| ; CHECK: [[INNER_HEADER_PREHEADER]]: |
| ; CHECK-NEXT: br label %[[INNER_HEADER:.*]] |
| ; CHECK: [[INNER_HEADER]]: |
| ; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[TMP9:%.*]], %[[INNER_HEADER_SPLIT:.*]] ], [ 0, %[[INNER_HEADER_PREHEADER]] ] |
| ; CHECK-NEXT: [[K:%.*]] = phi i64 [ [[TMP4:%.*]], %[[INNER_HEADER_SPLIT]] ], [ 0, %[[INNER_HEADER_PREHEADER]] ] |
| ; CHECK-NEXT: br label %[[OUTER_HEADER_PREHEADER]] |
| ; CHECK: [[INNER_HEADER_SPLIT1]]: |
| ; CHECK-NEXT: [[CONDITION_CHOICE:%.*]] = xor i1 [[CONDITION_ARG]], true |
| ; CHECK-NEXT: [[STEP_CHOICE:%.*]] = xor i1 [[STEP_ARG]], true |
| ; CHECK-NEXT: [[CONDITION_EXT:%.*]] = zext i1 [[CONDITION_CHOICE]] to i64 |
| ; CHECK-NEXT: [[CONDITION_ZERO:%.*]] = mul i64 [[CONDITION_EXT]], 0 |
| ; CHECK-NEXT: [[BOUND:%.*]] = add i64 4, [[CONDITION_ZERO]] |
| ; CHECK-NEXT: [[STEP_EXT:%.*]] = zext i1 [[STEP_CHOICE]] to i64 |
| ; CHECK-NEXT: [[STEP_ZERO:%.*]] = mul i64 [[STEP_EXT]], 0 |
| ; CHECK-NEXT: [[STEP:%.*]] = add i64 1, [[STEP_ZERO]] |
| ; CHECK-NEXT: [[K_NEXT:%.*]] = add i64 [[K]], [[STEP]] |
| ; CHECK-NEXT: [[K_FP:%.*]] = sitofp i64 [[K]] to double |
| ; CHECK-NEXT: [[SELECTED_BIT:%.*]] = and i1 [[CONDITION_CHOICE]], [[STEP_CHOICE]] |
| ; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[SELECTED_BIT]], double 1.000000e+00, double 0.000000e+00 |
| ; CHECK-NEXT: [[VALUE:%.*]] = fadd double [[SELECTED]], [[K_FP]] |
| ; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]] |
| ; CHECK-NEXT: store double [[VALUE]], ptr [[IDX]], align 8 |
| ; CHECK-NEXT: [[J_NEXT:%.*]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], [[BOUND]] |
| ; CHECK-NEXT: br label %[[OUTER_LATCH]] |
| ; CHECK: [[INNER_HEADER_SPLIT]]: |
| ; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[STEP_ARG]], true |
| ; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[TMP0]] to i64 |
| ; CHECK-NEXT: [[TMP2:%.*]] = mul i64 [[TMP1]], 0 |
| ; CHECK-NEXT: [[TMP3:%.*]] = add i64 1, [[TMP2]] |
| ; CHECK-NEXT: [[TMP4]] = add i64 [[K]], [[TMP3]] |
| ; CHECK-NEXT: [[TMP5:%.*]] = xor i1 [[CONDITION_ARG]], true |
| ; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i64 |
| ; CHECK-NEXT: [[TMP7:%.*]] = mul i64 [[TMP6]], 0 |
| ; CHECK-NEXT: [[TMP8:%.*]] = add i64 4, [[TMP7]] |
| ; CHECK-NEXT: [[TMP9]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], [[TMP8]] |
| ; CHECK-NEXT: br i1 [[TMP10]], label %[[EXIT:.*]], label %[[INNER_HEADER]] |
| ; CHECK: [[OUTER_LATCH]]: |
| ; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1 |
| ; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[I_EC]], label %[[INNER_HEADER_SPLIT]], label %[[OUTER_HEADER]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[CONDITION_OUT:%.*]] = phi i1 [ [[TMP5]], %[[INNER_HEADER_SPLIT]] ] |
| ; CHECK-NEXT: [[STEP_OUT:%.*]] = phi i1 [ [[TMP0]], %[[INNER_HEADER_SPLIT]] ] |
| ; CHECK-NEXT: [[SELECTED_OUT:%.*]] = and i1 [[CONDITION_OUT]], [[STEP_OUT]] |
| ; CHECK-NEXT: [[RESULT:%.*]] = select i1 [[SELECTED_OUT]], double 2.000000e+00, double 3.000000e+00 |
| ; CHECK-NEXT: store double [[RESULT]], ptr [[R]], align 8 |
| ; CHECK-NEXT: ret void |
| ; |
| i1 %condition.arg, i1 %step.arg) { |
| entry: |
| br label %outer.header |
| |
| outer.header: |
| %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ] |
| br label %inner.header |
| |
| inner.header: |
| %j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ] |
| %k = phi i64 [ 0, %outer.header ], [ %k.next, %inner.header ] |
| %condition.choice = xor i1 %condition.arg, true |
| %step.choice = xor i1 %step.arg, true |
| %condition.ext = zext i1 %condition.choice to i64 |
| %condition.zero = mul i64 %condition.ext, 0 |
| %bound = add i64 4, %condition.zero |
| %step.ext = zext i1 %step.choice to i64 |
| %step.zero = mul i64 %step.ext, 0 |
| %step = add i64 1, %step.zero |
| %k.next = add i64 %k, %step |
| %k.fp = sitofp i64 %k to double |
| %selected.bit = and i1 %condition.choice, %step.choice |
| %selected = select i1 %selected.bit, double 1.000000e+00, double 0.000000e+00 |
| %value = fadd double %selected, %k.fp |
| %idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i |
| store double %value, ptr %idx, align 8 |
| %j.next = add i64 %j, 1 |
| %j.ec = icmp eq i64 %j.next, %bound |
| br i1 %j.ec, label %outer.latch, label %inner.header |
| |
| outer.latch: |
| %condition.lcssa = phi i1 [ %condition.choice, %inner.header ] |
| %step.lcssa = phi i1 [ %step.choice, %inner.header ] |
| %i.next = add i64 %i, 1 |
| %i.ec = icmp eq i64 %i.next, 4 |
| br i1 %i.ec, label %exit, label %outer.header |
| |
| exit: |
| %condition.out = phi i1 [ %condition.lcssa, %outer.latch ] |
| %step.out = phi i1 [ %step.lcssa, %outer.latch ] |
| %selected.out = and i1 %condition.out, %step.out |
| %result = select i1 %selected.out, double 2.000000e+00, double 3.000000e+00 |
| store double %result, ptr %R, align 8 |
| ret void |
| } |
| |
| ; Interchange is rejected because the latch-condition computation would clone |
| ; the freeze. |
| define void @inner_latch_condition_freeze(ptr noalias %A, ptr noalias %R, |
| ; CHECK-LABEL: define void @inner_latch_condition_freeze( |
| ; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]], i1 [[STEP_ARG:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NEXT: br label %[[OUTER_HEADER:.*]] |
| ; CHECK: [[OUTER_HEADER]]: |
| ; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ] |
| ; CHECK-NEXT: br label %[[INNER_HEADER:.*]] |
| ; CHECK: [[INNER_HEADER]]: |
| ; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, %[[OUTER_HEADER]] ], [ [[J_NEXT:%.*]], %[[INNER_HEADER]] ] |
| ; CHECK-NEXT: [[K:%.*]] = phi i64 [ 0, %[[OUTER_HEADER]] ], [ [[K_NEXT:%.*]], %[[INNER_HEADER]] ] |
| ; CHECK-NEXT: [[CONDITION_CHOICE:%.*]] = freeze i1 poison |
| ; CHECK-NEXT: [[STEP_CHOICE:%.*]] = xor i1 [[STEP_ARG]], true |
| ; CHECK-NEXT: [[CONDITION_EXT:%.*]] = zext i1 [[CONDITION_CHOICE]] to i64 |
| ; CHECK-NEXT: [[CONDITION_ZERO:%.*]] = mul i64 [[CONDITION_EXT]], 0 |
| ; CHECK-NEXT: [[BOUND:%.*]] = add i64 4, [[CONDITION_ZERO]] |
| ; CHECK-NEXT: [[STEP_EXT:%.*]] = zext i1 [[STEP_CHOICE]] to i64 |
| ; CHECK-NEXT: [[STEP_ZERO:%.*]] = mul i64 [[STEP_EXT]], 0 |
| ; CHECK-NEXT: [[STEP:%.*]] = add i64 1, [[STEP_ZERO]] |
| ; CHECK-NEXT: [[K_NEXT]] = add i64 [[K]], [[STEP]] |
| ; CHECK-NEXT: [[K_FP:%.*]] = sitofp i64 [[K]] to double |
| ; CHECK-NEXT: [[SELECTED_BIT:%.*]] = and i1 [[CONDITION_CHOICE]], [[STEP_CHOICE]] |
| ; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[SELECTED_BIT]], double 1.000000e+00, double 0.000000e+00 |
| ; CHECK-NEXT: [[VALUE:%.*]] = fadd double [[SELECTED]], [[K_FP]] |
| ; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]] |
| ; CHECK-NEXT: store double [[VALUE]], ptr [[IDX]], align 8 |
| ; CHECK-NEXT: [[J_NEXT]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], [[BOUND]] |
| ; CHECK-NEXT: br i1 [[J_EC]], label %[[OUTER_LATCH]], label %[[INNER_HEADER]] |
| ; CHECK: [[OUTER_LATCH]]: |
| ; CHECK-NEXT: [[CONDITION_LCSSA:%.*]] = phi i1 [ [[CONDITION_CHOICE]], %[[INNER_HEADER]] ] |
| ; CHECK-NEXT: [[STEP_LCSSA:%.*]] = phi i1 [ [[STEP_CHOICE]], %[[INNER_HEADER]] ] |
| ; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1 |
| ; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[I_EC]], label %[[EXIT:.*]], label %[[OUTER_HEADER]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[CONDITION_OUT:%.*]] = phi i1 [ [[CONDITION_LCSSA]], %[[OUTER_LATCH]] ] |
| ; CHECK-NEXT: [[STEP_OUT:%.*]] = phi i1 [ [[STEP_LCSSA]], %[[OUTER_LATCH]] ] |
| ; CHECK-NEXT: [[SELECTED_OUT:%.*]] = and i1 [[CONDITION_OUT]], [[STEP_OUT]] |
| ; CHECK-NEXT: [[RESULT:%.*]] = select i1 [[SELECTED_OUT]], double 2.000000e+00, double 3.000000e+00 |
| ; CHECK-NEXT: store double [[RESULT]], ptr [[R]], align 8 |
| ; CHECK-NEXT: ret void |
| ; |
| i1 %step.arg) { |
| entry: |
| br label %outer.header |
| |
| outer.header: |
| %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ] |
| br label %inner.header |
| |
| inner.header: |
| %j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ] |
| %k = phi i64 [ 0, %outer.header ], [ %k.next, %inner.header ] |
| %condition.choice = freeze i1 poison |
| %step.choice = xor i1 %step.arg, true |
| %condition.ext = zext i1 %condition.choice to i64 |
| %condition.zero = mul i64 %condition.ext, 0 |
| %bound = add i64 4, %condition.zero |
| %step.ext = zext i1 %step.choice to i64 |
| %step.zero = mul i64 %step.ext, 0 |
| %step = add i64 1, %step.zero |
| %k.next = add i64 %k, %step |
| %k.fp = sitofp i64 %k to double |
| %selected.bit = and i1 %condition.choice, %step.choice |
| %selected = select i1 %selected.bit, double 1.000000e+00, double 0.000000e+00 |
| %value = fadd double %selected, %k.fp |
| %idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i |
| store double %value, ptr %idx, align 8 |
| %j.next = add i64 %j, 1 |
| %j.ec = icmp eq i64 %j.next, %bound |
| br i1 %j.ec, label %outer.latch, label %inner.header |
| |
| outer.latch: |
| %condition.lcssa = phi i1 [ %condition.choice, %inner.header ] |
| %step.lcssa = phi i1 [ %step.choice, %inner.header ] |
| %i.next = add i64 %i, 1 |
| %i.ec = icmp eq i64 %i.next, 4 |
| br i1 %i.ec, label %exit, label %outer.header |
| |
| exit: |
| %condition.out = phi i1 [ %condition.lcssa, %outer.latch ] |
| %step.out = phi i1 [ %step.lcssa, %outer.latch ] |
| %selected.out = and i1 %condition.out, %step.out |
| %result = select i1 %selected.out, double 2.000000e+00, double 3.000000e+00 |
| store double %result, ptr %R, align 8 |
| ret void |
| } |
| |
| ; Interchange is rejected because the second induction update would clone the |
| ; freeze. |
| define void @inner_latch_induction_freeze(ptr noalias %A, ptr noalias %R, |
| ; CHECK-LABEL: define void @inner_latch_induction_freeze( |
| ; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]], i1 [[CONDITION_ARG:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NEXT: br label %[[OUTER_HEADER:.*]] |
| ; CHECK: [[OUTER_HEADER]]: |
| ; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ] |
| ; CHECK-NEXT: br label %[[INNER_HEADER:.*]] |
| ; CHECK: [[INNER_HEADER]]: |
| ; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, %[[OUTER_HEADER]] ], [ [[J_NEXT:%.*]], %[[INNER_HEADER]] ] |
| ; CHECK-NEXT: [[K:%.*]] = phi i64 [ 0, %[[OUTER_HEADER]] ], [ [[K_NEXT:%.*]], %[[INNER_HEADER]] ] |
| ; CHECK-NEXT: [[CONDITION_CHOICE:%.*]] = xor i1 [[CONDITION_ARG]], true |
| ; CHECK-NEXT: [[STEP_CHOICE:%.*]] = freeze i1 poison |
| ; CHECK-NEXT: [[CONDITION_EXT:%.*]] = zext i1 [[CONDITION_CHOICE]] to i64 |
| ; CHECK-NEXT: [[CONDITION_ZERO:%.*]] = mul i64 [[CONDITION_EXT]], 0 |
| ; CHECK-NEXT: [[BOUND:%.*]] = add i64 4, [[CONDITION_ZERO]] |
| ; CHECK-NEXT: [[STEP_EXT:%.*]] = zext i1 [[STEP_CHOICE]] to i64 |
| ; CHECK-NEXT: [[STEP_ZERO:%.*]] = mul i64 [[STEP_EXT]], 0 |
| ; CHECK-NEXT: [[STEP:%.*]] = add i64 1, [[STEP_ZERO]] |
| ; CHECK-NEXT: [[K_NEXT]] = add i64 [[K]], [[STEP]] |
| ; CHECK-NEXT: [[K_FP:%.*]] = sitofp i64 [[K]] to double |
| ; CHECK-NEXT: [[SELECTED_BIT:%.*]] = and i1 [[CONDITION_CHOICE]], [[STEP_CHOICE]] |
| ; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[SELECTED_BIT]], double 1.000000e+00, double 0.000000e+00 |
| ; CHECK-NEXT: [[VALUE:%.*]] = fadd double [[SELECTED]], [[K_FP]] |
| ; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]] |
| ; CHECK-NEXT: store double [[VALUE]], ptr [[IDX]], align 8 |
| ; CHECK-NEXT: [[J_NEXT]] = add i64 [[J]], 1 |
| ; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], [[BOUND]] |
| ; CHECK-NEXT: br i1 [[J_EC]], label %[[OUTER_LATCH]], label %[[INNER_HEADER]] |
| ; CHECK: [[OUTER_LATCH]]: |
| ; CHECK-NEXT: [[CONDITION_LCSSA:%.*]] = phi i1 [ [[CONDITION_CHOICE]], %[[INNER_HEADER]] ] |
| ; CHECK-NEXT: [[STEP_LCSSA:%.*]] = phi i1 [ [[STEP_CHOICE]], %[[INNER_HEADER]] ] |
| ; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1 |
| ; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4 |
| ; CHECK-NEXT: br i1 [[I_EC]], label %[[EXIT:.*]], label %[[OUTER_HEADER]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[CONDITION_OUT:%.*]] = phi i1 [ [[CONDITION_LCSSA]], %[[OUTER_LATCH]] ] |
| ; CHECK-NEXT: [[STEP_OUT:%.*]] = phi i1 [ [[STEP_LCSSA]], %[[OUTER_LATCH]] ] |
| ; CHECK-NEXT: [[SELECTED_OUT:%.*]] = and i1 [[CONDITION_OUT]], [[STEP_OUT]] |
| ; CHECK-NEXT: [[RESULT:%.*]] = select i1 [[SELECTED_OUT]], double 2.000000e+00, double 3.000000e+00 |
| ; CHECK-NEXT: store double [[RESULT]], ptr [[R]], align 8 |
| ; CHECK-NEXT: ret void |
| ; |
| i1 %condition.arg) { |
| entry: |
| br label %outer.header |
| |
| outer.header: |
| %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ] |
| br label %inner.header |
| |
| inner.header: |
| %j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ] |
| %k = phi i64 [ 0, %outer.header ], [ %k.next, %inner.header ] |
| %condition.choice = xor i1 %condition.arg, true |
| %step.choice = freeze i1 poison |
| %condition.ext = zext i1 %condition.choice to i64 |
| %condition.zero = mul i64 %condition.ext, 0 |
| %bound = add i64 4, %condition.zero |
| %step.ext = zext i1 %step.choice to i64 |
| %step.zero = mul i64 %step.ext, 0 |
| %step = add i64 1, %step.zero |
| %k.next = add i64 %k, %step |
| %k.fp = sitofp i64 %k to double |
| %selected.bit = and i1 %condition.choice, %step.choice |
| %selected = select i1 %selected.bit, double 1.000000e+00, double 0.000000e+00 |
| %value = fadd double %selected, %k.fp |
| %idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i |
| store double %value, ptr %idx, align 8 |
| %j.next = add i64 %j, 1 |
| %j.ec = icmp eq i64 %j.next, %bound |
| br i1 %j.ec, label %outer.latch, label %inner.header |
| |
| outer.latch: |
| %condition.lcssa = phi i1 [ %condition.choice, %inner.header ] |
| %step.lcssa = phi i1 [ %step.choice, %inner.header ] |
| %i.next = add i64 %i, 1 |
| %i.ec = icmp eq i64 %i.next, 4 |
| br i1 %i.ec, label %exit, label %outer.header |
| |
| exit: |
| %condition.out = phi i1 [ %condition.lcssa, %outer.latch ] |
| %step.out = phi i1 [ %step.lcssa, %outer.latch ] |
| %selected.out = and i1 %condition.out, %step.out |
| %result = select i1 %selected.out, double 2.000000e+00, double 3.000000e+00 |
| store double %result, ptr %R, align 8 |
| ret void |
| } |