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