; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv64 -mattr=+c -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=NOCMOV %s
; RUN: llc -mtriple=riscv64 -mattr=+conditional-cmv-fusion,+c -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefixes=CMOV,CMOV-NOZICOND %s
; RUN: llc -mtriple=riscv64 -mattr=+conditional-cmv-fusion,+c,+zicond -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefixes=CMOV,CMOV-ZICOND %s
; RUN: llc -mtriple=riscv64 -mattr=+short-forward-branch-opt -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefixes=SHORT_FORWARD,SFB-NOZICOND %s
; RUN: llc -mtriple=riscv64 -mattr=+short-forward-branch-opt,+c -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefixes=SHORT_FORWARD,SFB-NOZICOND %s
; RUN: llc -mtriple=riscv64 -mattr=+short-forward-branch-opt,+zicond -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefixes=SHORT_FORWARD,SFB-ZICOND %s
; The conditional move optimization in sifive-p450 requires that only a
; single c.mv instruction appears in the branch shadow.
; The sifive-7-series can predicate an xor.
define signext i32 @test1(i32 signext %x, i32 signext %y, i32 signext %z) {
; NOCMOV-LABEL: test1:
; NOCMOV: # %bb.0:
; NOCMOV-NEXT: snez a2, a2
; NOCMOV-NEXT: addi a2, a2, -1
; NOCMOV-NEXT: and a1, a1, a2
; NOCMOV-NEXT: xor a0, a0, a1
; NOCMOV-NEXT: ret
;
; CMOV-LABEL: test1:
; CMOV: # %bb.0:
; CMOV-NEXT: xor a1, a1, a0
; CMOV-NEXT: bnez a2, .LBB0_2
; CMOV-NEXT: # %bb.1:
; CMOV-NEXT: mv a0, a1
; CMOV-NEXT: .LBB0_2:
; CMOV-NEXT: ret
;
; SHORT_FORWARD-LABEL: test1:
; SHORT_FORWARD: # %bb.0:
; SHORT_FORWARD-NEXT: bnez a2, .LBB0_2
; SHORT_FORWARD-NEXT: # %bb.1:
; SHORT_FORWARD-NEXT: xor a0, a0, a1
; SHORT_FORWARD-NEXT: .LBB0_2:
; SHORT_FORWARD-NEXT: ret
%c = icmp eq i32 %z, 0
%a = xor i32 %x, %y
%b = select i1 %c, i32 %a, i32 %x
ret i32 %b
}
define signext i32 @test2(i32 signext %x, i32 signext %y, i32 signext %z) {
; NOCMOV-LABEL: test2:
; NOCMOV: # %bb.0:
; NOCMOV-NEXT: seqz a2, a2
; NOCMOV-NEXT: addi a2, a2, -1
; NOCMOV-NEXT: and a1, a1, a2
; NOCMOV-NEXT: xor a0, a0, a1
; NOCMOV-NEXT: ret
;
; CMOV-LABEL: test2:
; CMOV: # %bb.0:
; CMOV-NEXT: xor a1, a1, a0
; CMOV-NEXT: beqz a2, .LBB1_2
; CMOV-NEXT: # %bb.1:
; CMOV-NEXT: mv a0, a1
; CMOV-NEXT: .LBB1_2:
; CMOV-NEXT: ret
;
; SHORT_FORWARD-LABEL: test2:
; SHORT_FORWARD: # %bb.0:
; SHORT_FORWARD-NEXT: beqz a2, .LBB1_2
; SHORT_FORWARD-NEXT: # %bb.1:
; SHORT_FORWARD-NEXT: xor a0, a0, a1
; SHORT_FORWARD-NEXT: .LBB1_2:
; SHORT_FORWARD-NEXT: ret
%c = icmp eq i32 %z, 0
%a = xor i32 %x, %y
%b = select i1 %c, i32 %x, i32 %a
ret i32 %b
}
; Make sure we don't share the same basic block for two selects with the same
; condition.
define signext i32 @test3(i32 signext %v, i32 signext %w, i32 signext %x, i32 signext %y, i32 signext %z) {
; NOCMOV-LABEL: test3:
; NOCMOV: # %bb.0:
; NOCMOV-NEXT: seqz a4, a4
; NOCMOV-NEXT: addi a4, a4, -1
; NOCMOV-NEXT: and a1, a1, a4
; NOCMOV-NEXT: xor a0, a0, a1
; NOCMOV-NEXT: and a3, a3, a4
; NOCMOV-NEXT: xor a2, a2, a3
; NOCMOV-NEXT: addw a0, a0, a2
; NOCMOV-NEXT: ret
;
; CMOV-LABEL: test3:
; CMOV: # %bb.0:
; CMOV-NEXT: xor a1, a1, a0
; CMOV-NEXT: bnez a4, .LBB2_2
; CMOV-NEXT: # %bb.1:
; CMOV-NEXT: mv a1, a0
; CMOV-NEXT: .LBB2_2:
; CMOV-NEXT: xor a0, a2, a3
; CMOV-NEXT: bnez a4, .LBB2_4
; CMOV-NEXT: # %bb.3:
; CMOV-NEXT: mv a0, a2
; CMOV-NEXT: .LBB2_4:
; CMOV-NEXT: addw a0, a0, a1
; CMOV-NEXT: ret
;
; SHORT_FORWARD-LABEL: test3:
; SHORT_FORWARD: # %bb.0:
; SHORT_FORWARD-NEXT: beqz a4, .LBB2_2
; SHORT_FORWARD-NEXT: # %bb.1:
; SHORT_FORWARD-NEXT: xor a0, a0, a1
; SHORT_FORWARD-NEXT: .LBB2_2:
; SHORT_FORWARD-NEXT: beqz a4, .LBB2_4
; SHORT_FORWARD-NEXT: # %bb.3:
; SHORT_FORWARD-NEXT: xor a2, a2, a3
; SHORT_FORWARD-NEXT: .LBB2_4:
; SHORT_FORWARD-NEXT: addw a0, a0, a2
; SHORT_FORWARD-NEXT: ret
%c = icmp eq i32 %z, 0
%a = xor i32 %v, %w
%b = select i1 %c, i32 %v, i32 %a
%d = xor i32 %x, %y
%e = select i1 %c, i32 %x, i32 %d
%f = add i32 %b, %e
ret i32 %f
}
define signext i32 @test4(i32 signext %x, i32 signext %y, i32 signext %z) {
; NOCMOV-LABEL: test4:
; NOCMOV: # %bb.0:
; NOCMOV-NEXT: snez a0, a2
; NOCMOV-NEXT: addi a0, a0, -1
; NOCMOV-NEXT: andi a0, a0, 3
; NOCMOV-NEXT: ret
;
; CMOV-NOZICOND-LABEL: test4:
; CMOV-NOZICOND: # %bb.0:
; CMOV-NOZICOND-NEXT: li a1, 0
; CMOV-NOZICOND-NEXT: li a0, 3
; CMOV-NOZICOND-NEXT: beqz a2, .LBB3_2
; CMOV-NOZICOND-NEXT: # %bb.1:
; CMOV-NOZICOND-NEXT: mv a0, a1
; CMOV-NOZICOND-NEXT: .LBB3_2:
; CMOV-NOZICOND-NEXT: ret
;
; CMOV-ZICOND-LABEL: test4:
; CMOV-ZICOND: # %bb.0:
; CMOV-ZICOND-NEXT: li a0, 3
; CMOV-ZICOND-NEXT: czero.nez a0, a0, a2
; CMOV-ZICOND-NEXT: ret
;
; SFB-NOZICOND-LABEL: test4:
; SFB-NOZICOND: # %bb.0:
; SFB-NOZICOND-NEXT: li a0, 3
; SFB-NOZICOND-NEXT: beqz a2, .LBB3_2
; SFB-NOZICOND-NEXT: # %bb.1:
; SFB-NOZICOND-NEXT: li a0, 0
; SFB-NOZICOND-NEXT: .LBB3_2:
; SFB-NOZICOND-NEXT: ret
;
; SFB-ZICOND-LABEL: test4:
; SFB-ZICOND: # %bb.0:
; SFB-ZICOND-NEXT: li a0, 3
; SFB-ZICOND-NEXT: czero.nez a0, a0, a2
; SFB-ZICOND-NEXT: ret
%c = icmp eq i32 %z, 0
%a = select i1 %c, i32 3, i32 0
ret i32 %a
}
define i16 @select_xor_1(i16 %A, i8 %cond) {
; NOCMOV-LABEL: select_xor_1:
; NOCMOV: # %bb.0: # %entry
; NOCMOV-NEXT: slli a1, a1, 63
; NOCMOV-NEXT: srai a1, a1, 63
; NOCMOV-NEXT: andi a1, a1, 43
; NOCMOV-NEXT: xor a0, a0, a1
; NOCMOV-NEXT: ret
;
; CMOV-LABEL: select_xor_1:
; CMOV: # %bb.0: # %entry
; CMOV-NEXT: andi a1, a1, 1
; CMOV-NEXT: xori a2, a0, 43
; CMOV-NEXT: beqz a1, .LBB4_2
; CMOV-NEXT: # %bb.1: # %entry
; CMOV-NEXT: mv a0, a2
; CMOV-NEXT: .LBB4_2: # %entry
; CMOV-NEXT: ret
;
; SHORT_FORWARD-LABEL: select_xor_1:
; SHORT_FORWARD: # %bb.0: # %entry
; SHORT_FORWARD-NEXT: andi a1, a1, 1
; SHORT_FORWARD-NEXT: beqz a1, .LBB4_2
; SHORT_FORWARD-NEXT: # %bb.1: # %entry
; SHORT_FORWARD-NEXT: xori a0, a0, 43
; SHORT_FORWARD-NEXT: .LBB4_2: # %entry
; SHORT_FORWARD-NEXT: ret
entry:
%and = and i8 %cond, 1
%cmp10 = icmp eq i8 %and, 0
%0 = xor i16 %A, 43
%1 = select i1 %cmp10, i16 %A, i16 %0
ret i16 %1
}
; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of
; icmp eq (and %cond, 1), 0
define i16 @select_xor_1b(i16 %A, i8 %cond) {
; NOCMOV-LABEL: select_xor_1b:
; NOCMOV: # %bb.0: # %entry
; NOCMOV-NEXT: slli a1, a1, 63
; NOCMOV-NEXT: srai a1, a1, 63
; NOCMOV-NEXT: andi a1, a1, 43
; NOCMOV-NEXT: xor a0, a0, a1
; NOCMOV-NEXT: ret
;
; CMOV-LABEL: select_xor_1b:
; CMOV: # %bb.0: # %entry
; CMOV-NEXT: andi a1, a1, 1
; CMOV-NEXT: xori a2, a0, 43
; CMOV-NEXT: beqz a1, .LBB5_2
; CMOV-NEXT: # %bb.1: # %entry
; CMOV-NEXT: mv a0, a2
; CMOV-NEXT: .LBB5_2: # %entry
; CMOV-NEXT: ret
;
; SHORT_FORWARD-LABEL: select_xor_1b:
; SHORT_FORWARD: # %bb.0: # %entry
; SHORT_FORWARD-NEXT: andi a1, a1, 1
; SHORT_FORWARD-NEXT: beqz a1, .LBB5_2
; SHORT_FORWARD-NEXT: # %bb.1: # %entry
; SHORT_FORWARD-NEXT: xori a0, a0, 43
; SHORT_FORWARD-NEXT: .LBB5_2: # %entry
; SHORT_FORWARD-NEXT: ret
entry:
%and = and i8 %cond, 1
%cmp10 = icmp ne i8 %and, 1
%0 = xor i16 %A, 43
%1 = select i1 %cmp10, i16 %A, i16 %0
ret i16 %1
}
define i32 @select_xor_2(i32 %A, i32 %B, i8 %cond) {
; NOCMOV-LABEL: select_xor_2:
; NOCMOV: # %bb.0: # %entry
; NOCMOV-NEXT: slli a2, a2, 63
; NOCMOV-NEXT: srai a2, a2, 63
; NOCMOV-NEXT: and a1, a1, a2
; NOCMOV-NEXT: xor a0, a0, a1
; NOCMOV-NEXT: ret
;
; CMOV-LABEL: select_xor_2:
; CMOV: # %bb.0: # %entry
; CMOV-NEXT: andi a2, a2, 1
; CMOV-NEXT: xor a1, a1, a0
; CMOV-NEXT: beqz a2, .LBB6_2
; CMOV-NEXT: # %bb.1: # %entry
; CMOV-NEXT: mv a0, a1
; CMOV-NEXT: .LBB6_2: # %entry
; CMOV-NEXT: ret
;
; SFB-ZICOND-LABEL: select_xor_2:
; SFB-ZICOND: # %bb.0: # %entry
; SFB-ZICOND-NEXT: andi a2, a2, 1
; SFB-ZICOND-NEXT: beqz a2, .LBB6_2
; SFB-ZICOND-NEXT: # %bb.1: # %entry
; SFB-ZICOND-NEXT: xor a0, a1, a0
; SFB-ZICOND-NEXT: .LBB6_2: # %entry
; SFB-ZICOND-NEXT: ret
entry:
%and = and i8 %cond, 1
%cmp10 = icmp eq i8 %and, 0
%0 = xor i32 %B, %A
%1 = select i1 %cmp10, i32 %A, i32 %0
ret i32 %1
}
; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of
; icmp eq (and %cond, 1), 0
define i32 @select_xor_2b(i32 %A, i32 %B, i8 %cond) {
; NOCMOV-LABEL: select_xor_2b:
; NOCMOV: # %bb.0: # %entry
; NOCMOV-NEXT: slli a2, a2, 63
; NOCMOV-NEXT: srai a2, a2, 63
; NOCMOV-NEXT: and a1, a1, a2
; NOCMOV-NEXT: xor a0, a0, a1
; NOCMOV-NEXT: ret
;
; CMOV-LABEL: select_xor_2b:
; CMOV: # %bb.0: # %entry
; CMOV-NEXT: andi a2, a2, 1
; CMOV-NEXT: xor a1, a1, a0
; CMOV-NEXT: beqz a2, .LBB7_2
; CMOV-NEXT: # %bb.1: # %entry
; CMOV-NEXT: mv a0, a1
; CMOV-NEXT: .LBB7_2: # %entry
; CMOV-NEXT: ret
;
; SFB-ZICOND-LABEL: select_xor_2b:
; SFB-ZICOND: # %bb.0: # %entry
; SFB-ZICOND-NEXT: andi a2, a2, 1
; SFB-ZICOND-NEXT: beqz a2, .LBB7_2
; SFB-ZICOND-NEXT: # %bb.1: # %entry
; SFB-ZICOND-NEXT: xor a0, a1, a0
; SFB-ZICOND-NEXT: .LBB7_2: # %entry
; SFB-ZICOND-NEXT: ret
entry:
%and = and i8 %cond, 1
%cmp10 = icmp ne i8 %and, 1
%0 = xor i32 %B, %A
%1 = select i1 %cmp10, i32 %A, i32 %0
ret i32 %1
}
define i32 @select_or(i32 %A, i32 %B, i8 %cond) {
; NOCMOV-LABEL: select_or:
; NOCMOV: # %bb.0: # %entry
; NOCMOV-NEXT: slli a2, a2, 63
; NOCMOV-NEXT: srai a2, a2, 63
; NOCMOV-NEXT: and a1, a1, a2
; NOCMOV-NEXT: or a0, a0, a1
; NOCMOV-NEXT: ret
;
; CMOV-LABEL: select_or:
; CMOV: # %bb.0: # %entry
; CMOV-NEXT: andi a2, a2, 1
; CMOV-NEXT: or a1, a1, a0
; CMOV-NEXT: beqz a2, .LBB8_2
; CMOV-NEXT: # %bb.1: # %entry
; CMOV-NEXT: mv a0, a1
; CMOV-NEXT: .LBB8_2: # %entry
; CMOV-NEXT: ret
;
; SFB-ZICOND-LABEL: select_or:
; SFB-ZICOND: # %bb.0: # %entry
; SFB-ZICOND-NEXT: andi a2, a2, 1
; SFB-ZICOND-NEXT: beqz a2, .LBB8_2
; SFB-ZICOND-NEXT: # %bb.1: # %entry
; SFB-ZICOND-NEXT: or a0, a1, a0
; SFB-ZICOND-NEXT: .LBB8_2: # %entry
; SFB-ZICOND-NEXT: ret
entry:
%and = and i8 %cond, 1
%cmp10 = icmp eq i8 %and, 0
%0 = or i32 %B, %A
%1 = select i1 %cmp10, i32 %A, i32 %0
ret i32 %1
}
; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of
; icmp eq (and %cond, 1), 0
define i32 @select_or_b(i32 %A, i32 %B, i8 %cond) {
; NOCMOV-LABEL: select_or_b:
; NOCMOV: # %bb.0: # %entry
; NOCMOV-NEXT: slli a2, a2, 63
; NOCMOV-NEXT: srai a2, a2, 63
; NOCMOV-NEXT: and a1, a1, a2
; NOCMOV-NEXT: or a0, a0, a1
; NOCMOV-NEXT: ret
;
; CMOV-LABEL: select_or_b:
; CMOV: # %bb.0: # %entry
; CMOV-NEXT: andi a2, a2, 1
; CMOV-NEXT: or a1, a1, a0
; CMOV-NEXT: beqz a2, .LBB9_2
; CMOV-NEXT: # %bb.1: # %entry
; CMOV-NEXT: mv a0, a1
; CMOV-NEXT: .LBB9_2: # %entry
; CMOV-NEXT: ret
;
; SFB-ZICOND-LABEL: select_or_b:
; SFB-ZICOND: # %bb.0: # %entry
; SFB-ZICOND-NEXT: andi a2, a2, 1
; SFB-ZICOND-NEXT: beqz a2, .LBB9_2
; SFB-ZICOND-NEXT: # %bb.1: # %entry
; SFB-ZICOND-NEXT: or a0, a1, a0
; SFB-ZICOND-NEXT: .LBB9_2: # %entry
; SFB-ZICOND-NEXT: ret
entry:
%and = and i8 %cond, 1
%cmp10 = icmp ne i8 %and, 1
%0 = or i32 %B, %A
%1 = select i1 %cmp10, i32 %A, i32 %0
ret i32 %1
}
define i32 @select_or_1(i32 %A, i32 %B, i32 %cond) {
; NOCMOV-LABEL: select_or_1:
; NOCMOV: # %bb.0: # %entry
; NOCMOV-NEXT: slli a2, a2, 63
; NOCMOV-NEXT: srai a2, a2, 63
; NOCMOV-NEXT: and a1, a1, a2
; NOCMOV-NEXT: or a0, a0, a1
; NOCMOV-NEXT: ret
;
; CMOV-LABEL: select_or_1:
; CMOV: # %bb.0: # %entry
; CMOV-NEXT: andi a2, a2, 1
; CMOV-NEXT: or a1, a1, a0
; CMOV-NEXT: beqz a2, .LBB10_2
; CMOV-NEXT: # %bb.1: # %entry
; CMOV-NEXT: mv a0, a1
; CMOV-NEXT: .LBB10_2: # %entry
; CMOV-NEXT: ret
;
; SFB-ZICOND-LABEL: select_or_1:
; SFB-ZICOND: # %bb.0: # %entry
; SFB-ZICOND-NEXT: andi a2, a2, 1
; SFB-ZICOND-NEXT: beqz a2, .LBB10_2
; SFB-ZICOND-NEXT: # %bb.1: # %entry
; SFB-ZICOND-NEXT: or a0, a1, a0
; SFB-ZICOND-NEXT: .LBB10_2: # %entry
; SFB-ZICOND-NEXT: ret
entry:
%and = and i32 %cond, 1
%cmp10 = icmp eq i32 %and, 0
%0 = or i32 %B, %A
%1 = select i1 %cmp10, i32 %A, i32 %0
ret i32 %1
}
; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of
; icmp eq (and %cond, 1), 0
define i32 @select_or_1b(i32 %A, i32 %B, i32 %cond) {
; NOCMOV-LABEL: select_or_1b:
; NOCMOV: # %bb.0: # %entry
; NOCMOV-NEXT: slli a2, a2, 63
; NOCMOV-NEXT: srai a2, a2, 63
; NOCMOV-NEXT: and a1, a1, a2
; NOCMOV-NEXT: or a0, a0, a1
; NOCMOV-NEXT: ret
;
; CMOV-LABEL: select_or_1b:
; CMOV: # %bb.0: # %entry
; CMOV-NEXT: andi a2, a2, 1
; CMOV-NEXT: or a1, a1, a0
; CMOV-NEXT: beqz a2, .LBB11_2
; CMOV-NEXT: # %bb.1: # %entry
; CMOV-NEXT: mv a0, a1
; CMOV-NEXT: .LBB11_2: # %entry
; CMOV-NEXT: ret
;
; SFB-ZICOND-LABEL: select_or_1b:
; SFB-ZICOND: # %bb.0: # %entry
; SFB-ZICOND-NEXT: andi a2, a2, 1
; SFB-ZICOND-NEXT: beqz a2, .LBB11_2
; SFB-ZICOND-NEXT: # %bb.1: # %entry
; SFB-ZICOND-NEXT: or a0, a1, a0
; SFB-ZICOND-NEXT: .LBB11_2: # %entry
; SFB-ZICOND-NEXT: ret
entry:
%and = and i32 %cond, 1
%cmp10 = icmp ne i32 %and, 1
%0 = or i32 %B, %A
%1 = select i1 %cmp10, i32 %A, i32 %0
ret i32 %1
}