mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 19:23:23 +01:00
ef448d0349
This patch contains a pass that transforms CBZ/CBNZ/TBZ/TBNZ instructions into a conditional branch (Bcc), when the NZCV flags can be set for "free". This is preferred on targets that have more flexibility when scheduling Bcc instructions as compared to CBZ/CBNZ/TBZ/TBNZ (assuming all other variables are equal). This can reduce register pressure and is also the default behavior for GCC. A few examples: add w8, w0, w1 -> cmn w0, w1 ; CMN is an alias of ADDS. cbz w8, .LBB_2 -> b.eq .LBB0_2 ; single def/use of w8 removed. add w8, w0, w1 -> adds w8, w0, w1 ; w8 has multiple uses. cbz w8, .LBB1_2 -> b.eq .LBB1_2 sub w8, w0, w1 -> subs w8, w0, w1 ; w8 has multiple uses. tbz w8, #31, .LBB6_2 -> b.ge .LBB6_2 In looking at all current sub-target machine descriptions, this transformation appears to be either positive or neutral. Differential Revision: https://reviews.llvm.org/D34220. llvm-svn: 306144
424 lines
9.8 KiB
LLVM
424 lines
9.8 KiB
LLVM
; RUN: llc < %s -stress-early-ifcvt -aarch64-enable-atomic-cfg-tidy=0 | FileCheck %s
|
|
target triple = "arm64-apple-macosx"
|
|
|
|
; CHECK: mm2
|
|
define i32 @mm2(i32* nocapture %p, i32 %n) nounwind uwtable readonly ssp {
|
|
entry:
|
|
br label %do.body
|
|
|
|
; CHECK: do.body
|
|
; Loop body has no branches before the backedge.
|
|
; CHECK-NOT: LBB
|
|
do.body:
|
|
%max.0 = phi i32 [ 0, %entry ], [ %max.1, %do.cond ]
|
|
%min.0 = phi i32 [ 0, %entry ], [ %min.1, %do.cond ]
|
|
%n.addr.0 = phi i32 [ %n, %entry ], [ %dec, %do.cond ]
|
|
%p.addr.0 = phi i32* [ %p, %entry ], [ %incdec.ptr, %do.cond ]
|
|
%incdec.ptr = getelementptr inbounds i32, i32* %p.addr.0, i64 1
|
|
%0 = load i32, i32* %p.addr.0, align 4
|
|
%cmp = icmp sgt i32 %0, %max.0
|
|
br i1 %cmp, label %do.cond, label %if.else
|
|
|
|
if.else:
|
|
%cmp1 = icmp slt i32 %0, %min.0
|
|
%.min.0 = select i1 %cmp1, i32 %0, i32 %min.0
|
|
br label %do.cond
|
|
|
|
do.cond:
|
|
%max.1 = phi i32 [ %0, %do.body ], [ %max.0, %if.else ]
|
|
%min.1 = phi i32 [ %min.0, %do.body ], [ %.min.0, %if.else ]
|
|
; CHECK: b.ne
|
|
%dec = add i32 %n.addr.0, -1
|
|
%tobool = icmp eq i32 %dec, 0
|
|
br i1 %tobool, label %do.end, label %do.body
|
|
|
|
do.end:
|
|
%sub = sub nsw i32 %max.1, %min.1
|
|
ret i32 %sub
|
|
}
|
|
|
|
; CHECK-LABEL: fold_inc_true_32:
|
|
; CHECK: {{subs.*wzr,|cmp}} w2, #1
|
|
; CHECK-NEXT: csinc w0, w1, w0, eq
|
|
; CHECK-NEXT: ret
|
|
define i32 @fold_inc_true_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp eq i32 %c, 1
|
|
%inc = add nsw i32 %x, 1
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i32 [ %y, %eq_bb ], [ %inc, %entry ]
|
|
ret i32 %cond
|
|
}
|
|
|
|
; CHECK-LABEL: fold_inc_true_64:
|
|
; CHECK: {{subs.*xzr,|cmp}} x2, #1
|
|
; CHECK-NEXT: csinc x0, x1, x0, eq
|
|
; CHECK-NEXT: ret
|
|
define i64 @fold_inc_true_64(i64 %x, i64 %y, i64 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp eq i64 %c, 1
|
|
%inc = add nsw i64 %x, 1
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i64 [ %y, %eq_bb ], [ %inc, %entry ]
|
|
ret i64 %cond
|
|
}
|
|
|
|
; CHECK-LABEL: fold_inc_false_32:
|
|
; CHECK: {{subs.*wzr,|cmp}} w2, #1
|
|
; CHECK-NEXT: csinc w0, w1, w0, ne
|
|
; CHECK-NEXT: ret
|
|
define i32 @fold_inc_false_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp eq i32 %c, 1
|
|
%inc = add nsw i32 %x, 1
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i32 [ %inc, %eq_bb ], [ %y, %entry ]
|
|
ret i32 %cond
|
|
}
|
|
|
|
; CHECK-LABEL: fold_inc_false_64:
|
|
; CHECK: {{subs.*xzr,|cmp}} x2, #1
|
|
; CHECK-NEXT: csinc x0, x1, x0, ne
|
|
; CHECK-NEXT: ret
|
|
define i64 @fold_inc_false_64(i64 %x, i64 %y, i64 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp eq i64 %c, 1
|
|
%inc = add nsw i64 %x, 1
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i64 [ %inc, %eq_bb ], [ %y, %entry ]
|
|
ret i64 %cond
|
|
}
|
|
|
|
; CHECK-LABEL: fold_inv_true_32:
|
|
; CHECK: {{subs.*wzr,|cmp}} w2, #1
|
|
; CHECK-NEXT: csinv w0, w1, w0, eq
|
|
; CHECK-NEXT: ret
|
|
define i32 @fold_inv_true_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp eq i32 %c, 1
|
|
%inv = xor i32 %x, -1
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i32 [ %y, %eq_bb ], [ %inv, %entry ]
|
|
ret i32 %cond
|
|
}
|
|
|
|
; CHECK-LABEL: fold_inv_true_64:
|
|
; CHECK: {{subs.*xzr,|cmp}} x2, #1
|
|
; CHECK-NEXT: csinv x0, x1, x0, eq
|
|
; CHECK-NEXT: ret
|
|
define i64 @fold_inv_true_64(i64 %x, i64 %y, i64 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp eq i64 %c, 1
|
|
%inv = xor i64 %x, -1
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i64 [ %y, %eq_bb ], [ %inv, %entry ]
|
|
ret i64 %cond
|
|
}
|
|
|
|
; CHECK-LABEL: fold_inv_false_32:
|
|
; CHECK: {{subs.*wzr,|cmp}} w2, #1
|
|
; CHECK-NEXT: csinv w0, w1, w0, ne
|
|
; CHECK-NEXT: ret
|
|
define i32 @fold_inv_false_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp eq i32 %c, 1
|
|
%inv = xor i32 %x, -1
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i32 [ %inv, %eq_bb ], [ %y, %entry ]
|
|
ret i32 %cond
|
|
}
|
|
|
|
; CHECK-LABEL: fold_inv_false_64:
|
|
; CHECK: {{subs.*xzr,|cmp}} x2, #1
|
|
; CHECK-NEXT: csinv x0, x1, x0, ne
|
|
; CHECK-NEXT: ret
|
|
define i64 @fold_inv_false_64(i64 %x, i64 %y, i64 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp eq i64 %c, 1
|
|
%inv = xor i64 %x, -1
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i64 [ %inv, %eq_bb ], [ %y, %entry ]
|
|
ret i64 %cond
|
|
}
|
|
|
|
; CHECK-LABEL: fold_neg_true_32:
|
|
; CHECK: {{subs.*wzr,|cmp}} w2, #1
|
|
; CHECK-NEXT: csneg w0, w1, w0, eq
|
|
; CHECK-NEXT: ret
|
|
define i32 @fold_neg_true_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp eq i32 %c, 1
|
|
%neg = sub nsw i32 0, %x
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i32 [ %y, %eq_bb ], [ %neg, %entry ]
|
|
ret i32 %cond
|
|
}
|
|
|
|
; CHECK-LABEL: fold_neg_true_64:
|
|
; CHECK: {{subs.*xzr,|cmp}} x2, #1
|
|
; CHECK-NEXT: csneg x0, x1, x0, eq
|
|
; CHECK-NEXT: ret
|
|
define i64 @fold_neg_true_64(i64 %x, i64 %y, i64 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp eq i64 %c, 1
|
|
%neg = sub nsw i64 0, %x
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i64 [ %y, %eq_bb ], [ %neg, %entry ]
|
|
ret i64 %cond
|
|
}
|
|
|
|
; CHECK-LABEL: fold_neg_false_32:
|
|
; CHECK: {{subs.*wzr,|cmp}} w2, #1
|
|
; CHECK-NEXT: csneg w0, w1, w0, ne
|
|
; CHECK-NEXT: ret
|
|
define i32 @fold_neg_false_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp eq i32 %c, 1
|
|
%neg = sub nsw i32 0, %x
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i32 [ %neg, %eq_bb ], [ %y, %entry ]
|
|
ret i32 %cond
|
|
}
|
|
|
|
; CHECK-LABEL: fold_neg_false_64:
|
|
; CHECK: {{subs.*xzr,|cmp}} x2, #1
|
|
; CHECK-NEXT: csneg x0, x1, x0, ne
|
|
; CHECK-NEXT: ret
|
|
define i64 @fold_neg_false_64(i64 %x, i64 %y, i64 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp eq i64 %c, 1
|
|
%neg = sub nsw i64 0, %x
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i64 [ %neg, %eq_bb ], [ %y, %entry ]
|
|
ret i64 %cond
|
|
}
|
|
|
|
; CHECK: cbnz_32
|
|
; CHECK: {{subs.*wzr,|cmp}} w2, #0
|
|
; CHECK-NEXT: csel w0, w1, w0, ne
|
|
; CHECK-NEXT: ret
|
|
define i32 @cbnz_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp eq i32 %c, 0
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i32 [ %x, %eq_bb ], [ %y, %entry ]
|
|
ret i32 %cond
|
|
}
|
|
|
|
; CHECK: cbnz_64
|
|
; CHECK: {{subs.*xzr,|cmp}} x2, #0
|
|
; CHECK-NEXT: csel x0, x1, x0, ne
|
|
; CHECK-NEXT: ret
|
|
define i64 @cbnz_64(i64 %x, i64 %y, i64 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp eq i64 %c, 0
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i64 [ %x, %eq_bb ], [ %y, %entry ]
|
|
ret i64 %cond
|
|
}
|
|
|
|
; CHECK: cbz_32
|
|
; CHECK: {{subs.*wzr,|cmp}} w2, #0
|
|
; CHECK-NEXT: csel w0, w1, w0, eq
|
|
; CHECK-NEXT: ret
|
|
define i32 @cbz_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp ne i32 %c, 0
|
|
br i1 %tobool, label %ne_bb, label %done
|
|
|
|
ne_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i32 [ %x, %ne_bb ], [ %y, %entry ]
|
|
ret i32 %cond
|
|
}
|
|
|
|
; CHECK: cbz_64
|
|
; CHECK: {{subs.*xzr,|cmp}} x2, #0
|
|
; CHECK-NEXT: csel x0, x1, x0, eq
|
|
; CHECK-NEXT: ret
|
|
define i64 @cbz_64(i64 %x, i64 %y, i64 %c) nounwind ssp {
|
|
entry:
|
|
%tobool = icmp ne i64 %c, 0
|
|
br i1 %tobool, label %ne_bb, label %done
|
|
|
|
ne_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i64 [ %x, %ne_bb ], [ %y, %entry ]
|
|
ret i64 %cond
|
|
}
|
|
|
|
; CHECK: tbnz_32
|
|
; CHECK: {{ands.*xzr,|tst}} w2, #0x80
|
|
; CHECK-NEXT: csel w0, w1, w0, ne
|
|
; CHECK-NEXT: ret
|
|
define i32 @tbnz_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
|
|
entry:
|
|
%mask = and i32 %c, 128
|
|
%tobool = icmp eq i32 %mask, 0
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i32 [ %x, %eq_bb ], [ %y, %entry ]
|
|
ret i32 %cond
|
|
}
|
|
|
|
; CHECK: tbnz_64
|
|
; CHECK: {{ands.*xzr,|tst}} x2, #0x8000000000000000
|
|
; CHECK-NEXT: csel x0, x1, x0, ne
|
|
; CHECK-NEXT: ret
|
|
define i64 @tbnz_64(i64 %x, i64 %y, i64 %c) nounwind ssp {
|
|
entry:
|
|
%mask = and i64 %c, 9223372036854775808
|
|
%tobool = icmp eq i64 %mask, 0
|
|
br i1 %tobool, label %eq_bb, label %done
|
|
|
|
eq_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i64 [ %x, %eq_bb ], [ %y, %entry ]
|
|
ret i64 %cond
|
|
}
|
|
|
|
; CHECK: tbz_32
|
|
; CHECK: {{ands.*xzr,|tst}} w2, #0x80
|
|
; CHECK-NEXT: csel w0, w1, w0, eq
|
|
; CHECK-NEXT: ret
|
|
define i32 @tbz_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
|
|
entry:
|
|
%mask = and i32 %c, 128
|
|
%tobool = icmp ne i32 %mask, 0
|
|
br i1 %tobool, label %ne_bb, label %done
|
|
|
|
ne_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i32 [ %x, %ne_bb ], [ %y, %entry ]
|
|
ret i32 %cond
|
|
}
|
|
|
|
; CHECK: tbz_64
|
|
; CHECK: {{ands.*xzr,|tst}} x2, #0x8000000000000000
|
|
; CHECK-NEXT: csel x0, x1, x0, eq
|
|
; CHECK-NEXT: ret
|
|
define i64 @tbz_64(i64 %x, i64 %y, i64 %c) nounwind ssp {
|
|
entry:
|
|
%mask = and i64 %c, 9223372036854775808
|
|
%tobool = icmp ne i64 %mask, 0
|
|
br i1 %tobool, label %ne_bb, label %done
|
|
|
|
ne_bb:
|
|
br label %done
|
|
|
|
done:
|
|
%cond = phi i64 [ %x, %ne_bb ], [ %y, %entry ]
|
|
ret i64 %cond
|
|
}
|
|
|
|
; This function from 175.vpr folds an ADDWri into a CSINC.
|
|
; Remember to clear the kill flag on the ADDWri.
|
|
define i32 @get_ytrack_to_xtracks() nounwind ssp {
|
|
entry:
|
|
br label %for.body
|
|
|
|
for.body:
|
|
%x0 = load i32, i32* undef, align 4
|
|
br i1 undef, label %if.then.i146, label %is_sbox.exit155
|
|
|
|
if.then.i146:
|
|
%add8.i143 = add nsw i32 0, %x0
|
|
%rem.i144 = srem i32 %add8.i143, %x0
|
|
%add9.i145 = add i32 %rem.i144, 1
|
|
br label %is_sbox.exit155
|
|
|
|
is_sbox.exit155: ; preds = %if.then.i146, %for.body
|
|
%seg_offset.0.i151 = phi i32 [ %add9.i145, %if.then.i146 ], [ undef, %for.body ]
|
|
%idxprom15.i152 = sext i32 %seg_offset.0.i151 to i64
|
|
%arrayidx18.i154 = getelementptr inbounds i32, i32* null, i64 %idxprom15.i152
|
|
%x1 = load i32, i32* %arrayidx18.i154, align 4
|
|
br i1 undef, label %for.body51, label %for.body
|
|
|
|
for.body51: ; preds = %is_sbox.exit155
|
|
call fastcc void @get_switch_type(i32 %x1, i32 undef, i16 signext undef, i16 signext undef, i16* undef)
|
|
unreachable
|
|
}
|
|
declare fastcc void @get_switch_type(i32, i32, i16 signext, i16 signext, i16* nocapture) nounwind ssp
|