llvm/llvm/test/CodeGen/RISCV/cmov-branch-opt.ll

; 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
}