| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 |
| ; RUN: opt < %s -S -passes=loop-unroll -enable-peeling-for-iv | FileCheck %s |
| ; RUN: opt < %s -S -passes=loop-unroll-full -enable-peeling-for-iv | FileCheck %s |
| |
| ; Check that unnecessary peeling doesn't occur if for a comparison instruction |
| ; between two instructions. The original code is as below. Both i and j are |
| ; inductions, but the comparison i < j is not an induction. |
| ; |
| ; val = 42; |
| ; for (i=0,j=100; i<10000; i+=2,j+=1) { |
| ; a[i] = val; |
| ; val = i < j; |
| ; } |
| ; |
| define void @dont_peel_cmp_ind_ind(ptr %a) { |
| ; CHECK-LABEL: define void @dont_peel_cmp_ind_ind( |
| ; CHECK-SAME: ptr [[A:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NEXT: br label %[[FOR_BODY:.*]] |
| ; CHECK: [[FOR_BODY]]: |
| ; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[FOR_BODY]] ] |
| ; CHECK-NEXT: [[J:%.*]] = phi i32 [ 100, %[[ENTRY]] ], [ [[J_NEXT:%.*]], %[[FOR_BODY]] ] |
| ; CHECK-NEXT: [[VAL:%.*]] = phi i32 [ 42, %[[ENTRY]] ], [ [[VAL_NEXT:%.*]], %[[FOR_BODY]] ] |
| ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i32, ptr [[A]], i32 [[I]] |
| ; CHECK-NEXT: store i32 10, ptr [[ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[VAL_NEXT_CMP:%.*]] = icmp slt i32 [[I]], [[J]] |
| ; CHECK-NEXT: [[VAL_NEXT]] = zext i1 [[VAL_NEXT_CMP]] to i32 |
| ; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 2 |
| ; CHECK-NEXT: [[J_NEXT]] = add i32 [[J]], 1 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[I_NEXT]], 10000 |
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp slt i32 [[I_NEXT]], 10000 |
| ; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[EXIT:.*]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %for.body |
| |
| for.body: |
| %i = phi i32 [ 0, %entry ], [ %i.next, %for.body ] |
| %j = phi i32 [ 100, %entry ] , [ %j.next, %for.body ] |
| %val = phi i32 [ 42, %entry ], [ %val.next, %for.body ] |
| %arrayidx = getelementptr inbounds nuw i32, ptr %a, i32 %i |
| store i32 10, ptr %arrayidx, align 4 |
| %val.next.cmp = icmp slt i32 %i, %j |
| %val.next = zext i1 %val.next.cmp to i32 |
| %i.next = add i32 %i, 2 |
| %j.next = add i32 %j, 1 |
| %cmp = icmp ne i32 %i.next, 10000 |
| %exitcond = icmp slt i32 %i.next, 10000 |
| br i1 %exitcond, label %for.body, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| |
| ; Check that unnecessary peeling doesn't occur if for a bitwise instructions |
| ; between IVs. The original code is as below. The variable i is an induction, |
| ; but vals (val0 through val4) are not. |
| ; |
| ; val0 = 42; |
| ; val1 = 42; |
| ; val2 = 42; |
| ; val3 = 42; |
| ; val4 = 42; |
| ; for (i=0,j=100; i<10000; i+=2,j+=1) { |
| ; a[i] = val0; |
| ; b[i] = val1; |
| ; c[i] = val2; |
| ; d[i] = val3; |
| ; e[i] = val4; |
| ; val0 = i & j; |
| ; val1 = i | j; |
| ; val2 = i ^ j; |
| ; val3 = i >> j; |
| ; val4 = i << j; |
| ; } |
| ; |
| define void @dont_peel_bitwise_op_iv_iv(ptr %a, ptr %b, ptr %c, ptr %d, ptr %e) { |
| ; CHECK-LABEL: define void @dont_peel_bitwise_op_iv_iv( |
| ; CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]], ptr [[C:%.*]], ptr [[D:%.*]], ptr [[E:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NEXT: br label %[[FOR_BODY:.*]] |
| ; CHECK: [[FOR_BODY]]: |
| ; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[FOR_BODY]] ] |
| ; CHECK-NEXT: [[J:%.*]] = phi i32 [ 100, %[[ENTRY]] ], [ [[J_NEXT:%.*]], %[[FOR_BODY]] ] |
| ; CHECK-NEXT: [[VAL0:%.*]] = phi i32 [ 42, %[[ENTRY]] ], [ [[VAL0_NEXT:%.*]], %[[FOR_BODY]] ] |
| ; CHECK-NEXT: [[VAL1:%.*]] = phi i32 [ 42, %[[ENTRY]] ], [ [[VAL1_NEXT:%.*]], %[[FOR_BODY]] ] |
| ; CHECK-NEXT: [[VAL2:%.*]] = phi i32 [ 42, %[[ENTRY]] ], [ [[VAL2_NEXT:%.*]], %[[FOR_BODY]] ] |
| ; CHECK-NEXT: [[VAL3:%.*]] = phi i32 [ 42, %[[ENTRY]] ], [ [[VAL3_NEXT:%.*]], %[[FOR_BODY]] ] |
| ; CHECK-NEXT: [[VAL4:%.*]] = phi i32 [ 42, %[[ENTRY]] ], [ [[VAL4_NEXT:%.*]], %[[FOR_BODY]] ] |
| ; CHECK-NEXT: [[IDX_0:%.*]] = getelementptr inbounds nuw i32, ptr [[A]], i32 [[I]] |
| ; CHECK-NEXT: [[IDX_1:%.*]] = getelementptr inbounds nuw i32, ptr [[B]], i32 [[I]] |
| ; CHECK-NEXT: [[IDX_2:%.*]] = getelementptr inbounds nuw i32, ptr [[C]], i32 [[I]] |
| ; CHECK-NEXT: [[IDX_3:%.*]] = getelementptr inbounds nuw i32, ptr [[D]], i32 [[I]] |
| ; CHECK-NEXT: [[IDX_4:%.*]] = getelementptr inbounds nuw i32, ptr [[E]], i32 [[I]] |
| ; CHECK-NEXT: store i32 [[VAL0]], ptr [[IDX_0]], align 4 |
| ; CHECK-NEXT: store i32 [[VAL1]], ptr [[IDX_1]], align 4 |
| ; CHECK-NEXT: store i32 [[VAL2]], ptr [[IDX_2]], align 4 |
| ; CHECK-NEXT: store i32 [[VAL3]], ptr [[IDX_3]], align 4 |
| ; CHECK-NEXT: store i32 [[VAL4]], ptr [[IDX_4]], align 4 |
| ; CHECK-NEXT: [[VAL0_NEXT]] = and i32 [[I]], [[J]] |
| ; CHECK-NEXT: [[VAL1_NEXT]] = or i32 [[I]], [[J]] |
| ; CHECK-NEXT: [[VAL2_NEXT]] = xor i32 [[I]], [[J]] |
| ; CHECK-NEXT: [[VAL3_NEXT]] = shl i32 [[I]], [[J]] |
| ; CHECK-NEXT: [[VAL4_NEXT]] = lshr i32 [[I]], [[J]] |
| ; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 2 |
| ; CHECK-NEXT: [[J_NEXT]] = add i32 [[J]], 1 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[I_NEXT]], 10000 |
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp slt i32 [[I_NEXT]], 10000 |
| ; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[EXIT:.*]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %for.body |
| |
| for.body: |
| %i = phi i32 [ 0, %entry ], [ %i.next, %for.body ] |
| %j = phi i32 [ 100, %entry ] , [ %j.next, %for.body ] |
| %val0 = phi i32 [ 42, %entry ], [ %val0.next, %for.body ] |
| %val1 = phi i32 [ 42, %entry ], [ %val1.next, %for.body ] |
| %val2 = phi i32 [ 42, %entry ], [ %val2.next, %for.body ] |
| %val3 = phi i32 [ 42, %entry ], [ %val3.next, %for.body ] |
| %val4 = phi i32 [ 42, %entry ], [ %val4.next, %for.body ] |
| %idx.0 = getelementptr inbounds nuw i32, ptr %a, i32 %i |
| %idx.1 = getelementptr inbounds nuw i32, ptr %b, i32 %i |
| %idx.2 = getelementptr inbounds nuw i32, ptr %c, i32 %i |
| %idx.3 = getelementptr inbounds nuw i32, ptr %d, i32 %i |
| %idx.4 = getelementptr inbounds nuw i32, ptr %e, i32 %i |
| store i32 %val0, ptr %idx.0, align 4 |
| store i32 %val1, ptr %idx.1, align 4 |
| store i32 %val2, ptr %idx.2, align 4 |
| store i32 %val3, ptr %idx.3, align 4 |
| store i32 %val4, ptr %idx.4, align 4 |
| %val0.next = and i32 %i, %j |
| %val1.next = or i32 %i, %j |
| %val2.next = xor i32 %i, %j |
| %val3.next = shl i32 %i, %j |
| %val4.next = lshr i32 %i, %j |
| %i.next = add i32 %i, 2 |
| %j.next = add i32 %j, 1 |
| %cmp = icmp ne i32 %i.next, 10000 |
| %exitcond = icmp slt i32 %i.next, 10000 |
| br i1 %exitcond, label %for.body, label %exit |
| |
| exit: |
| ret void |
| } |