| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py |
| ; RUN: llc -debugify-and-strip-all-safe < %s -mtriple=aarch64-linux-gnu | FileCheck %s |
| |
| ; marked as external to prevent possible optimizations |
| @a = external global i32 |
| @b = external global i32 |
| @c = external global i32 |
| @d = external global i32 |
| |
| ; (a > 10 && b == c) || (a >= 10 && b == d) |
| define i32 @combine_gt_ge_10() #0 { |
| ; CHECK-LABEL: combine_gt_ge_10: |
| ; CHECK: // %bb.0: // %entry |
| ; CHECK-NEXT: adrp x8, :got:a |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:a] |
| ; CHECK-NEXT: ldr w9, [x8] |
| ; CHECK-NEXT: adrp x8, :got:b |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:b] |
| ; CHECK-NEXT: cmp w9, #10 |
| ; CHECK-NEXT: b.le .LBB0_3 |
| ; CHECK-NEXT: // %bb.1: // %land.lhs.true |
| ; CHECK-NEXT: adrp x9, :got:c |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:c] |
| ; CHECK-NEXT: ldr w10, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w10, w9 |
| ; CHECK-NEXT: b.ne .LBB0_4 |
| ; CHECK-NEXT: // %bb.2: |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB0_3: // %lor.lhs.false |
| ; CHECK-NEXT: b.lt .LBB0_6 |
| ; CHECK-NEXT: .LBB0_4: // %land.lhs.true3 |
| ; CHECK-NEXT: adrp x9, :got:d |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:d] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w8, w9 |
| ; CHECK-NEXT: b.ne .LBB0_6 |
| ; CHECK-NEXT: // %bb.5: |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB0_6: // %if.end |
| ; CHECK-NEXT: mov w0, wzr |
| ; CHECK-NEXT: ret |
| entry: |
| %0 = load i32, i32* @a, align 4 |
| %cmp = icmp sgt i32 %0, 10 |
| br i1 %cmp, label %land.lhs.true, label %lor.lhs.false |
| |
| land.lhs.true: ; preds = %entry |
| %1 = load i32, i32* @b, align 4 |
| %2 = load i32, i32* @c, align 4 |
| %cmp1 = icmp eq i32 %1, %2 |
| br i1 %cmp1, label %return, label %land.lhs.true3 |
| |
| lor.lhs.false: ; preds = %entry |
| %cmp2 = icmp sgt i32 %0, 9 |
| br i1 %cmp2, label %land.lhs.true3, label %if.end |
| |
| land.lhs.true3: ; preds = %lor.lhs.false, %land.lhs.true |
| %3 = load i32, i32* @b, align 4 |
| %4 = load i32, i32* @d, align 4 |
| %cmp4 = icmp eq i32 %3, %4 |
| br i1 %cmp4, label %return, label %if.end |
| |
| if.end: ; preds = %land.lhs.true3, %lor.lhs.false |
| br label %return |
| |
| return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true |
| %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] |
| ret i32 %retval.0 |
| } |
| |
| ; (a > 5 && b == c) || (a < 5 && b == d) |
| define i32 @combine_gt_lt_5() #0 { |
| ; CHECK-LABEL: combine_gt_lt_5: |
| ; CHECK: // %bb.0: // %entry |
| ; CHECK-NEXT: adrp x8, :got:a |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:a] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: cmp w8, #5 |
| ; CHECK-NEXT: b.le .LBB1_3 |
| ; CHECK-NEXT: // %bb.1: // %land.lhs.true |
| ; CHECK-NEXT: adrp x8, :got:b |
| ; CHECK-NEXT: adrp x9, :got:c |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:b] |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:c] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w8, w9 |
| ; CHECK-NEXT: b.ne .LBB1_6 |
| ; CHECK-NEXT: // %bb.2: |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB1_3: // %lor.lhs.false |
| ; CHECK-NEXT: b.ge .LBB1_6 |
| ; CHECK-NEXT: // %bb.4: // %land.lhs.true3 |
| ; CHECK-NEXT: adrp x8, :got:b |
| ; CHECK-NEXT: adrp x9, :got:d |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:b] |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:d] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w8, w9 |
| ; CHECK-NEXT: b.ne .LBB1_6 |
| ; CHECK-NEXT: // %bb.5: |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB1_6: // %if.end |
| ; CHECK-NEXT: mov w0, wzr |
| ; CHECK-NEXT: ret |
| entry: |
| %0 = load i32, i32* @a, align 4 |
| %cmp = icmp sgt i32 %0, 5 |
| br i1 %cmp, label %land.lhs.true, label %lor.lhs.false |
| |
| land.lhs.true: ; preds = %entry |
| %1 = load i32, i32* @b, align 4 |
| %2 = load i32, i32* @c, align 4 |
| %cmp1 = icmp eq i32 %1, %2 |
| br i1 %cmp1, label %return, label %if.end |
| |
| lor.lhs.false: ; preds = %entry |
| %cmp2 = icmp slt i32 %0, 5 |
| br i1 %cmp2, label %land.lhs.true3, label %if.end |
| |
| land.lhs.true3: ; preds = %lor.lhs.false |
| %3 = load i32, i32* @b, align 4 |
| %4 = load i32, i32* @d, align 4 |
| %cmp4 = icmp eq i32 %3, %4 |
| br i1 %cmp4, label %return, label %if.end |
| |
| if.end: ; preds = %land.lhs.true3, %lor.lhs.false, %land.lhs.true |
| br label %return |
| |
| return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true |
| %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] |
| ret i32 %retval.0 |
| } |
| |
| ; (a < 5 && b == c) || (a <= 5 && b == d) |
| define i32 @combine_lt_ge_5() #0 { |
| ; CHECK-LABEL: combine_lt_ge_5: |
| ; CHECK: // %bb.0: // %entry |
| ; CHECK-NEXT: adrp x8, :got:a |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:a] |
| ; CHECK-NEXT: ldr w9, [x8] |
| ; CHECK-NEXT: adrp x8, :got:b |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:b] |
| ; CHECK-NEXT: cmp w9, #5 |
| ; CHECK-NEXT: b.ge .LBB2_3 |
| ; CHECK-NEXT: // %bb.1: // %land.lhs.true |
| ; CHECK-NEXT: adrp x9, :got:c |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:c] |
| ; CHECK-NEXT: ldr w10, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w10, w9 |
| ; CHECK-NEXT: b.ne .LBB2_4 |
| ; CHECK-NEXT: // %bb.2: |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB2_3: // %lor.lhs.false |
| ; CHECK-NEXT: b.gt .LBB2_6 |
| ; CHECK-NEXT: .LBB2_4: // %land.lhs.true3 |
| ; CHECK-NEXT: adrp x9, :got:d |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:d] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w8, w9 |
| ; CHECK-NEXT: b.ne .LBB2_6 |
| ; CHECK-NEXT: // %bb.5: |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB2_6: // %if.end |
| ; CHECK-NEXT: mov w0, wzr |
| ; CHECK-NEXT: ret |
| entry: |
| %0 = load i32, i32* @a, align 4 |
| %cmp = icmp slt i32 %0, 5 |
| br i1 %cmp, label %land.lhs.true, label %lor.lhs.false |
| |
| land.lhs.true: ; preds = %entry |
| %1 = load i32, i32* @b, align 4 |
| %2 = load i32, i32* @c, align 4 |
| %cmp1 = icmp eq i32 %1, %2 |
| br i1 %cmp1, label %return, label %land.lhs.true3 |
| |
| lor.lhs.false: ; preds = %entry |
| %cmp2 = icmp slt i32 %0, 6 |
| br i1 %cmp2, label %land.lhs.true3, label %if.end |
| |
| land.lhs.true3: ; preds = %lor.lhs.false, %land.lhs.true |
| %3 = load i32, i32* @b, align 4 |
| %4 = load i32, i32* @d, align 4 |
| %cmp4 = icmp eq i32 %3, %4 |
| br i1 %cmp4, label %return, label %if.end |
| |
| if.end: ; preds = %land.lhs.true3, %lor.lhs.false |
| br label %return |
| |
| return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true |
| %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] |
| ret i32 %retval.0 |
| } |
| |
| ; (a < 5 && b == c) || (a > 5 && b == d) |
| define i32 @combine_lt_gt_5() #0 { |
| ; CHECK-LABEL: combine_lt_gt_5: |
| ; CHECK: // %bb.0: // %entry |
| ; CHECK-NEXT: adrp x8, :got:a |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:a] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: cmp w8, #5 |
| ; CHECK-NEXT: b.ge .LBB3_3 |
| ; CHECK-NEXT: // %bb.1: // %land.lhs.true |
| ; CHECK-NEXT: adrp x8, :got:b |
| ; CHECK-NEXT: adrp x9, :got:c |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:b] |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:c] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w8, w9 |
| ; CHECK-NEXT: b.ne .LBB3_6 |
| ; CHECK-NEXT: // %bb.2: |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB3_3: // %lor.lhs.false |
| ; CHECK-NEXT: b.le .LBB3_6 |
| ; CHECK-NEXT: // %bb.4: // %land.lhs.true3 |
| ; CHECK-NEXT: adrp x8, :got:b |
| ; CHECK-NEXT: adrp x9, :got:d |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:b] |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:d] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w8, w9 |
| ; CHECK-NEXT: b.ne .LBB3_6 |
| ; CHECK-NEXT: // %bb.5: |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB3_6: // %if.end |
| ; CHECK-NEXT: mov w0, wzr |
| ; CHECK-NEXT: ret |
| entry: |
| %0 = load i32, i32* @a, align 4 |
| %cmp = icmp slt i32 %0, 5 |
| br i1 %cmp, label %land.lhs.true, label %lor.lhs.false |
| |
| land.lhs.true: ; preds = %entry |
| %1 = load i32, i32* @b, align 4 |
| %2 = load i32, i32* @c, align 4 |
| %cmp1 = icmp eq i32 %1, %2 |
| br i1 %cmp1, label %return, label %if.end |
| |
| lor.lhs.false: ; preds = %entry |
| %cmp2 = icmp sgt i32 %0, 5 |
| br i1 %cmp2, label %land.lhs.true3, label %if.end |
| |
| land.lhs.true3: ; preds = %lor.lhs.false |
| %3 = load i32, i32* @b, align 4 |
| %4 = load i32, i32* @d, align 4 |
| %cmp4 = icmp eq i32 %3, %4 |
| br i1 %cmp4, label %return, label %if.end |
| |
| if.end: ; preds = %land.lhs.true3, %lor.lhs.false, %land.lhs.true |
| br label %return |
| |
| return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true |
| %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] |
| ret i32 %retval.0 |
| } |
| |
| ; (a > -5 && b == c) || (a < -5 && b == d) |
| define i32 @combine_gt_lt_n5() #0 { |
| ; CHECK-LABEL: combine_gt_lt_n5: |
| ; CHECK: // %bb.0: // %entry |
| ; CHECK-NEXT: adrp x8, :got:a |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:a] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: cmn w8, #5 |
| ; CHECK-NEXT: b.le .LBB4_3 |
| ; CHECK-NEXT: // %bb.1: // %land.lhs.true |
| ; CHECK-NEXT: adrp x8, :got:b |
| ; CHECK-NEXT: adrp x9, :got:c |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:b] |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:c] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w8, w9 |
| ; CHECK-NEXT: b.ne .LBB4_6 |
| ; CHECK-NEXT: // %bb.2: |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB4_3: // %lor.lhs.false |
| ; CHECK-NEXT: b.ge .LBB4_6 |
| ; CHECK-NEXT: // %bb.4: // %land.lhs.true3 |
| ; CHECK-NEXT: adrp x8, :got:b |
| ; CHECK-NEXT: adrp x9, :got:d |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:b] |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:d] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w8, w9 |
| ; CHECK-NEXT: b.ne .LBB4_6 |
| ; CHECK-NEXT: // %bb.5: |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB4_6: // %if.end |
| ; CHECK-NEXT: mov w0, wzr |
| ; CHECK-NEXT: ret |
| entry: |
| %0 = load i32, i32* @a, align 4 |
| %cmp = icmp sgt i32 %0, -5 |
| br i1 %cmp, label %land.lhs.true, label %lor.lhs.false |
| |
| land.lhs.true: ; preds = %entry |
| %1 = load i32, i32* @b, align 4 |
| %2 = load i32, i32* @c, align 4 |
| %cmp1 = icmp eq i32 %1, %2 |
| br i1 %cmp1, label %return, label %if.end |
| |
| lor.lhs.false: ; preds = %entry |
| %cmp2 = icmp slt i32 %0, -5 |
| br i1 %cmp2, label %land.lhs.true3, label %if.end |
| |
| land.lhs.true3: ; preds = %lor.lhs.false |
| %3 = load i32, i32* @b, align 4 |
| %4 = load i32, i32* @d, align 4 |
| %cmp4 = icmp eq i32 %3, %4 |
| br i1 %cmp4, label %return, label %if.end |
| |
| if.end: ; preds = %land.lhs.true3, %lor.lhs.false, %land.lhs.true |
| br label %return |
| |
| return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true |
| %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] |
| ret i32 %retval.0 |
| } |
| |
| ; (a < -5 && b == c) || (a > -5 && b == d) |
| define i32 @combine_lt_gt_n5() #0 { |
| ; CHECK-LABEL: combine_lt_gt_n5: |
| ; CHECK: // %bb.0: // %entry |
| ; CHECK-NEXT: adrp x8, :got:a |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:a] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: cmn w8, #5 |
| ; CHECK-NEXT: b.ge .LBB5_3 |
| ; CHECK-NEXT: // %bb.1: // %land.lhs.true |
| ; CHECK-NEXT: adrp x8, :got:b |
| ; CHECK-NEXT: adrp x9, :got:c |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:b] |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:c] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w8, w9 |
| ; CHECK-NEXT: b.ne .LBB5_6 |
| ; CHECK-NEXT: // %bb.2: |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB5_3: // %lor.lhs.false |
| ; CHECK-NEXT: b.le .LBB5_6 |
| ; CHECK-NEXT: // %bb.4: // %land.lhs.true3 |
| ; CHECK-NEXT: adrp x8, :got:b |
| ; CHECK-NEXT: adrp x9, :got:d |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:b] |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:d] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w8, w9 |
| ; CHECK-NEXT: b.ne .LBB5_6 |
| ; CHECK-NEXT: // %bb.5: |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB5_6: // %if.end |
| ; CHECK-NEXT: mov w0, wzr |
| ; CHECK-NEXT: ret |
| entry: |
| %0 = load i32, i32* @a, align 4 |
| %cmp = icmp slt i32 %0, -5 |
| br i1 %cmp, label %land.lhs.true, label %lor.lhs.false |
| |
| land.lhs.true: ; preds = %entry |
| %1 = load i32, i32* @b, align 4 |
| %2 = load i32, i32* @c, align 4 |
| %cmp1 = icmp eq i32 %1, %2 |
| br i1 %cmp1, label %return, label %if.end |
| |
| lor.lhs.false: ; preds = %entry |
| %cmp2 = icmp sgt i32 %0, -5 |
| br i1 %cmp2, label %land.lhs.true3, label %if.end |
| |
| land.lhs.true3: ; preds = %lor.lhs.false |
| %3 = load i32, i32* @b, align 4 |
| %4 = load i32, i32* @d, align 4 |
| %cmp4 = icmp eq i32 %3, %4 |
| br i1 %cmp4, label %return, label %if.end |
| |
| if.end: ; preds = %land.lhs.true3, %lor.lhs.false, %land.lhs.true |
| br label %return |
| |
| return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true |
| %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] |
| ret i32 %retval.0 |
| } |
| |
| %struct.Struct = type { i64, i64 } |
| |
| @glob = internal unnamed_addr global %struct.Struct* null, align 8 |
| |
| declare %struct.Struct* @Update(%struct.Struct*) #1 |
| |
| ; no checks for this case, it just should be processed without errors |
| define void @combine_non_adjacent_cmp_br(%struct.Struct* nocapture readonly %hdCall) #0 { |
| ; CHECK-LABEL: combine_non_adjacent_cmp_br: |
| ; CHECK: // %bb.0: // %entry |
| ; CHECK-NEXT: str x30, [sp, #-48]! // 8-byte Folded Spill |
| ; CHECK-NEXT: stp x22, x21, [sp, #16] // 16-byte Folded Spill |
| ; CHECK-NEXT: stp x20, x19, [sp, #32] // 16-byte Folded Spill |
| ; CHECK-NEXT: .cfi_def_cfa_offset 48 |
| ; CHECK-NEXT: .cfi_offset w19, -8 |
| ; CHECK-NEXT: .cfi_offset w20, -16 |
| ; CHECK-NEXT: .cfi_offset w21, -24 |
| ; CHECK-NEXT: .cfi_offset w22, -32 |
| ; CHECK-NEXT: .cfi_offset w30, -48 |
| ; CHECK-NEXT: ldr x20, [x0] |
| ; CHECK-NEXT: mov w19, #24 |
| ; CHECK-NEXT: adrp x22, glob |
| ; CHECK-NEXT: add x21, x20, #2 |
| ; CHECK-NEXT: .LBB6_1: // %land.rhs |
| ; CHECK-NEXT: // =>This Inner Loop Header: Depth=1 |
| ; CHECK-NEXT: ldr x8, [x19] |
| ; CHECK-NEXT: cmp x8, #1 |
| ; CHECK-NEXT: b.lt .LBB6_3 |
| ; CHECK-NEXT: // %bb.2: // %while.body |
| ; CHECK-NEXT: // in Loop: Header=BB6_1 Depth=1 |
| ; CHECK-NEXT: ldr x0, [x22, :lo12:glob] |
| ; CHECK-NEXT: bl Update |
| ; CHECK-NEXT: sub x21, x21, #2 |
| ; CHECK-NEXT: cmp x20, x21 |
| ; CHECK-NEXT: b.lt .LBB6_1 |
| ; CHECK-NEXT: .LBB6_3: // %while.end |
| ; CHECK-NEXT: ldp x20, x19, [sp, #32] // 16-byte Folded Reload |
| ; CHECK-NEXT: ldp x22, x21, [sp, #16] // 16-byte Folded Reload |
| ; CHECK-NEXT: ldr x30, [sp], #48 // 8-byte Folded Reload |
| ; CHECK-NEXT: ret |
| entry: |
| %size = getelementptr inbounds %struct.Struct, %struct.Struct* %hdCall, i64 0, i32 0 |
| %0 = load i64, i64* %size, align 8 |
| br label %land.rhs |
| |
| land.rhs: |
| %rp.06 = phi i64 [ %0, %entry ], [ %sub, %while.body ] |
| %1 = load i64, i64* inttoptr (i64 24 to i64*), align 8 |
| %cmp2 = icmp sgt i64 %1, 0 |
| br i1 %cmp2, label %while.body, label %while.end |
| |
| while.body: |
| %2 = load %struct.Struct*, %struct.Struct** @glob, align 8 |
| %call = tail call %struct.Struct* @Update(%struct.Struct* %2) #2 |
| %sub = add nsw i64 %rp.06, -2 |
| %cmp = icmp slt i64 %0, %rp.06 |
| br i1 %cmp, label %land.rhs, label %while.end |
| |
| while.end: |
| ret void |
| } |
| |
| ; undefined external to prevent possible optimizations |
| declare void @do_something() #1 |
| |
| define i32 @do_nothing_if_resultant_opcodes_would_differ() #0 { |
| ; CHECK-LABEL: do_nothing_if_resultant_opcodes_would_differ: |
| ; CHECK: // %bb.0: // %entry |
| ; CHECK-NEXT: str x30, [sp, #-32]! // 8-byte Folded Spill |
| ; CHECK-NEXT: stp x20, x19, [sp, #16] // 16-byte Folded Spill |
| ; CHECK-NEXT: .cfi_def_cfa_offset 32 |
| ; CHECK-NEXT: .cfi_offset w19, -8 |
| ; CHECK-NEXT: .cfi_offset w20, -16 |
| ; CHECK-NEXT: .cfi_offset w30, -32 |
| ; CHECK-NEXT: adrp x19, :got:a |
| ; CHECK-NEXT: ldr x19, [x19, :got_lo12:a] |
| ; CHECK-NEXT: ldr w8, [x19] |
| ; CHECK-NEXT: cmn w8, #2 |
| ; CHECK-NEXT: b.gt .LBB7_4 |
| ; CHECK-NEXT: // %bb.1: // %while.body.preheader |
| ; CHECK-NEXT: sub w20, w8, #1 |
| ; CHECK-NEXT: .LBB7_2: // %while.body |
| ; CHECK-NEXT: // =>This Inner Loop Header: Depth=1 |
| ; CHECK-NEXT: bl do_something |
| ; CHECK-NEXT: adds w20, w20, #1 |
| ; CHECK-NEXT: b.mi .LBB7_2 |
| ; CHECK-NEXT: // %bb.3: // %while.cond.while.end_crit_edge |
| ; CHECK-NEXT: ldr w8, [x19] |
| ; CHECK-NEXT: .LBB7_4: // %while.end |
| ; CHECK-NEXT: cmp w8, #1 |
| ; CHECK-NEXT: b.gt .LBB7_7 |
| ; CHECK-NEXT: // %bb.5: // %land.lhs.true |
| ; CHECK-NEXT: adrp x8, :got:b |
| ; CHECK-NEXT: adrp x9, :got:d |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:b] |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:d] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w8, w9 |
| ; CHECK-NEXT: b.ne .LBB7_7 |
| ; CHECK-NEXT: // %bb.6: |
| ; CHECK-NEXT: mov w0, #123 |
| ; CHECK-NEXT: b .LBB7_8 |
| ; CHECK-NEXT: .LBB7_7: // %if.end |
| ; CHECK-NEXT: mov w0, wzr |
| ; CHECK-NEXT: .LBB7_8: // %return |
| ; CHECK-NEXT: ldp x20, x19, [sp, #16] // 16-byte Folded Reload |
| ; CHECK-NEXT: ldr x30, [sp], #32 // 8-byte Folded Reload |
| ; CHECK-NEXT: ret |
| entry: |
| %0 = load i32, i32* @a, align 4 |
| %cmp4 = icmp slt i32 %0, -1 |
| br i1 %cmp4, label %while.body.preheader, label %while.end |
| |
| while.body.preheader: ; preds = %entry |
| br label %while.body |
| |
| while.body: ; preds = %while.body, %while.body.preheader |
| %i.05 = phi i32 [ %inc, %while.body ], [ %0, %while.body.preheader ] |
| tail call void @do_something() #2 |
| %inc = add nsw i32 %i.05, 1 |
| %cmp = icmp slt i32 %i.05, 0 |
| br i1 %cmp, label %while.body, label %while.cond.while.end_crit_edge |
| |
| while.cond.while.end_crit_edge: ; preds = %while.body |
| %.pre = load i32, i32* @a, align 4 |
| br label %while.end |
| |
| while.end: ; preds = %while.cond.while.end_crit_edge, %entry |
| %1 = phi i32 [ %.pre, %while.cond.while.end_crit_edge ], [ %0, %entry ] |
| %cmp1 = icmp slt i32 %1, 2 |
| br i1 %cmp1, label %land.lhs.true, label %if.end |
| |
| land.lhs.true: ; preds = %while.end |
| %2 = load i32, i32* @b, align 4 |
| %3 = load i32, i32* @d, align 4 |
| %cmp2 = icmp eq i32 %2, %3 |
| br i1 %cmp2, label %return, label %if.end |
| |
| if.end: ; preds = %land.lhs.true, %while.end |
| br label %return |
| |
| return: ; preds = %if.end, %land.lhs.true |
| %retval.0 = phi i32 [ 0, %if.end ], [ 123, %land.lhs.true ] |
| ret i32 %retval.0 |
| } |
| |
| define i32 @do_nothing_if_compares_can_not_be_adjusted_to_each_other() #0 { |
| ; CHECK-LABEL: do_nothing_if_compares_can_not_be_adjusted_to_each_other: |
| ; CHECK: // %bb.0: // %entry |
| ; CHECK-NEXT: stp x30, x19, [sp, #-16]! // 16-byte Folded Spill |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: .cfi_offset w19, -8 |
| ; CHECK-NEXT: .cfi_offset w30, -16 |
| ; CHECK-NEXT: adrp x8, :got:a |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:a] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: cmp w8, #0 |
| ; CHECK-NEXT: b.gt .LBB8_3 |
| ; CHECK-NEXT: // %bb.1: // %while.body.preheader |
| ; CHECK-NEXT: sub w19, w8, #1 |
| ; CHECK-NEXT: .LBB8_2: // %while.body |
| ; CHECK-NEXT: // =>This Inner Loop Header: Depth=1 |
| ; CHECK-NEXT: bl do_something |
| ; CHECK-NEXT: adds w19, w19, #1 |
| ; CHECK-NEXT: b.mi .LBB8_2 |
| ; CHECK-NEXT: .LBB8_3: // %while.end |
| ; CHECK-NEXT: adrp x8, :got:c |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:c] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: cmn w8, #2 |
| ; CHECK-NEXT: b.lt .LBB8_6 |
| ; CHECK-NEXT: // %bb.4: // %land.lhs.true |
| ; CHECK-NEXT: adrp x8, :got:b |
| ; CHECK-NEXT: adrp x9, :got:d |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:b] |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:d] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w8, w9 |
| ; CHECK-NEXT: b.ne .LBB8_6 |
| ; CHECK-NEXT: // %bb.5: |
| ; CHECK-NEXT: mov w0, #123 |
| ; CHECK-NEXT: ldp x30, x19, [sp], #16 // 16-byte Folded Reload |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB8_6: // %if.end |
| ; CHECK-NEXT: mov w0, wzr |
| ; CHECK-NEXT: ldp x30, x19, [sp], #16 // 16-byte Folded Reload |
| ; CHECK-NEXT: ret |
| entry: |
| %0 = load i32, i32* @a, align 4 |
| %cmp4 = icmp slt i32 %0, 1 |
| br i1 %cmp4, label %while.body.preheader, label %while.end |
| |
| while.body.preheader: ; preds = %entry |
| br label %while.body |
| |
| while.body: ; preds = %while.body, %while.body.preheader |
| %i.05 = phi i32 [ %inc, %while.body ], [ %0, %while.body.preheader ] |
| tail call void @do_something() #2 |
| %inc = add nsw i32 %i.05, 1 |
| %cmp = icmp slt i32 %i.05, 0 |
| br i1 %cmp, label %while.body, label %while.end.loopexit |
| |
| while.end.loopexit: ; preds = %while.body |
| br label %while.end |
| |
| while.end: ; preds = %while.end.loopexit, %entry |
| %1 = load i32, i32* @c, align 4 |
| %cmp1 = icmp sgt i32 %1, -3 |
| br i1 %cmp1, label %land.lhs.true, label %if.end |
| |
| land.lhs.true: ; preds = %while.end |
| %2 = load i32, i32* @b, align 4 |
| %3 = load i32, i32* @d, align 4 |
| %cmp2 = icmp eq i32 %2, %3 |
| br i1 %cmp2, label %return, label %if.end |
| |
| if.end: ; preds = %land.lhs.true, %while.end |
| br label %return |
| |
| return: ; preds = %if.end, %land.lhs.true |
| %retval.0 = phi i32 [ 0, %if.end ], [ 123, %land.lhs.true ] |
| ret i32 %retval.0 |
| } |
| |
| ; Test in the following case, we don't hit 'cmp' and trigger a false positive |
| ; cmp w19, #0 |
| ; cinc w0, w19, gt |
| ; ... |
| ; fcmp d8, #0.0 |
| ; b.gt .LBB0_5 |
| |
| define i32 @fcmpri(i32 %argc, i8** nocapture readonly %argv) { |
| ; CHECK-LABEL: fcmpri: |
| ; CHECK: // %bb.0: // %entry |
| ; CHECK-NEXT: str d8, [sp, #-32]! // 8-byte Folded Spill |
| ; CHECK-NEXT: stp x30, x19, [sp, #16] // 16-byte Folded Spill |
| ; CHECK-NEXT: .cfi_def_cfa_offset 32 |
| ; CHECK-NEXT: .cfi_offset w19, -8 |
| ; CHECK-NEXT: .cfi_offset w30, -16 |
| ; CHECK-NEXT: .cfi_offset b8, -32 |
| ; CHECK-NEXT: cmp w0, #2 |
| ; CHECK-NEXT: b.lt .LBB9_3 |
| ; CHECK-NEXT: // %bb.1: // %land.lhs.true |
| ; CHECK-NEXT: ldr x8, [x1, #8] |
| ; CHECK-NEXT: cbz x8, .LBB9_3 |
| ; CHECK-NEXT: // %bb.2: |
| ; CHECK-NEXT: mov w0, #3 |
| ; CHECK-NEXT: b .LBB9_4 |
| ; CHECK-NEXT: .LBB9_3: // %if.end |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: bl zoo |
| ; CHECK-NEXT: mov w19, w0 |
| ; CHECK-NEXT: mov w0, #-1 |
| ; CHECK-NEXT: bl yoo |
| ; CHECK-NEXT: cmp w19, #0 |
| ; CHECK-NEXT: mov w1, #2 |
| ; CHECK-NEXT: cinc w0, w19, gt |
| ; CHECK-NEXT: fmov d8, d0 |
| ; CHECK-NEXT: bl xoo |
| ; CHECK-NEXT: fmov d0, #-1.00000000 |
| ; CHECK-NEXT: fcmp d8, #0.0 |
| ; CHECK-NEXT: fmov d1, #-2.00000000 |
| ; CHECK-NEXT: fadd d0, d8, d0 |
| ; CHECK-NEXT: fcsel d0, d8, d0, gt |
| ; CHECK-NEXT: bl woo |
| ; CHECK-NEXT: mov w0, #4 |
| ; CHECK-NEXT: .LBB9_4: // %return |
| ; CHECK-NEXT: ldp x30, x19, [sp, #16] // 16-byte Folded Reload |
| ; CHECK-NEXT: ldr d8, [sp], #32 // 8-byte Folded Reload |
| ; CHECK-NEXT: ret |
| |
| ; CHECK-LABEL-DAG: .LBB9_3 |
| |
| entry: |
| %cmp = icmp sgt i32 %argc, 1 |
| br i1 %cmp, label %land.lhs.true, label %if.end |
| |
| land.lhs.true: ; preds = %entry |
| %arrayidx = getelementptr inbounds i8*, i8** %argv, i64 1 |
| %0 = load i8*, i8** %arrayidx, align 8 |
| %cmp1 = icmp eq i8* %0, null |
| br i1 %cmp1, label %if.end, label %return |
| |
| if.end: ; preds = %land.lhs.true, %entry |
| %call = call i32 @zoo(i32 1) |
| %call2 = call double @yoo(i32 -1) |
| %cmp4 = icmp sgt i32 %call, 0 |
| %add = zext i1 %cmp4 to i32 |
| %cond = add nsw i32 %add, %call |
| %call7 = call i32 @xoo(i32 %cond, i32 2) |
| %cmp9 = fcmp ogt double %call2, 0.000000e+00 |
| br i1 %cmp9, label %cond.end14, label %cond.false12 |
| |
| cond.false12: ; preds = %if.end |
| %sub = fadd fast double %call2, -1.000000e+00 |
| br label %cond.end14 |
| |
| cond.end14: ; preds = %if.end, %cond.false12 |
| %cond15 = phi double [ %sub, %cond.false12 ], [ %call2, %if.end ] |
| %call16 = call i32 @woo(double %cond15, double -2.000000e+00) |
| br label %return |
| |
| return: ; preds = %land.lhs.true, %cond.end14 |
| %retval.0 = phi i32 [ 4, %cond.end14 ], [ 3, %land.lhs.true ] |
| ret i32 %retval.0 |
| } |
| |
| define void @cmp_shifted(i32 %in, i32 %lhs, i32 %rhs) { |
| ; CHECK-LABEL: cmp_shifted: |
| ; CHECK: // %bb.0: // %common.ret |
| ; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: .cfi_offset w30, -16 |
| ; CHECK-NEXT: mov w8, #42 |
| ; CHECK-NEXT: cmp w0, #0 |
| ; CHECK-NEXT: csinc w8, w8, wzr, gt |
| ; CHECK-NEXT: cmp w0, #2, lsl #12 // =8192 |
| ; CHECK-NEXT: mov w9, #128 |
| ; CHECK-NEXT: csel w0, w9, w8, ge |
| ; CHECK-NEXT: bl zoo |
| ; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload |
| ; CHECK-NEXT: ret |
| ; [...] |
| |
| %tst_low = icmp sgt i32 %in, 8191 |
| br i1 %tst_low, label %true, label %false |
| |
| true: |
| call i32 @zoo(i32 128) |
| ret void |
| |
| false: |
| %tst = icmp sgt i32 %in, 0 |
| br i1 %tst, label %truer, label %falser |
| |
| truer: |
| call i32 @zoo(i32 42) |
| ret void |
| |
| falser: |
| call i32 @zoo(i32 1) |
| ret void |
| } |
| |
| define i32 @combine_gt_ge_sel(i64 %v, i64* %p) #0 { |
| ; CHECK-LABEL: combine_gt_ge_sel: |
| ; CHECK: // %bb.0: // %entry |
| ; CHECK-NEXT: adrp x8, :got:a |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:a] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: cmp w8, #0 |
| ; CHECK-NEXT: csel x9, x0, xzr, gt |
| ; CHECK-NEXT: str x9, [x1] |
| ; CHECK-NEXT: b.le .LBB11_2 |
| ; CHECK-NEXT: // %bb.1: // %lor.lhs.false |
| ; CHECK-NEXT: cmp w8, #2 |
| ; CHECK-NEXT: b.ge .LBB11_4 |
| ; CHECK-NEXT: b .LBB11_6 |
| ; CHECK-NEXT: .LBB11_2: // %land.lhs.true |
| ; CHECK-NEXT: adrp x8, :got:b |
| ; CHECK-NEXT: adrp x9, :got:c |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:b] |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:c] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w8, w9 |
| ; CHECK-NEXT: b.ne .LBB11_4 |
| ; CHECK-NEXT: // %bb.3: |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB11_4: // %land.lhs.true3 |
| ; CHECK-NEXT: adrp x8, :got:b |
| ; CHECK-NEXT: adrp x9, :got:d |
| ; CHECK-NEXT: ldr x8, [x8, :got_lo12:b] |
| ; CHECK-NEXT: ldr x9, [x9, :got_lo12:d] |
| ; CHECK-NEXT: ldr w8, [x8] |
| ; CHECK-NEXT: ldr w9, [x9] |
| ; CHECK-NEXT: cmp w8, w9 |
| ; CHECK-NEXT: b.ne .LBB11_6 |
| ; CHECK-NEXT: // %bb.5: |
| ; CHECK-NEXT: mov w0, #1 |
| ; CHECK-NEXT: ret |
| ; CHECK-NEXT: .LBB11_6: // %if.end |
| ; CHECK-NEXT: mov w0, wzr |
| ; CHECK-NEXT: ret |
| entry: |
| %0 = load i32, i32* @a, align 4 |
| %cmp = icmp sgt i32 %0, 0 |
| %m = select i1 %cmp, i64 %v, i64 0 |
| store i64 %m, i64* %p |
| br i1 %cmp, label %lor.lhs.false, label %land.lhs.true |
| |
| land.lhs.true: ; preds = %entry |
| %1 = load i32, i32* @b, align 4 |
| %2 = load i32, i32* @c, align 4 |
| %cmp1 = icmp eq i32 %1, %2 |
| br i1 %cmp1, label %return, label %land.lhs.true3 |
| |
| lor.lhs.false: ; preds = %entry |
| %cmp2 = icmp sgt i32 %0, 1 |
| br i1 %cmp2, label %land.lhs.true3, label %if.end |
| |
| land.lhs.true3: ; preds = %lor.lhs.false, %land.lhs.true |
| %3 = load i32, i32* @b, align 4 |
| %4 = load i32, i32* @d, align 4 |
| %cmp4 = icmp eq i32 %3, %4 |
| br i1 %cmp4, label %return, label %if.end |
| |
| if.end: ; preds = %land.lhs.true3, %lor.lhs.false |
| br label %return |
| |
| return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true |
| %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] |
| ret i32 %retval.0 |
| } |
| |
| declare i32 @zoo(i32) |
| |
| declare double @yoo(i32) |
| |
| declare i32 @xoo(i32, i32) |
| |
| declare i32 @woo(double, double) |