This code is directly ported from the X86 backend which applies the same rewrite (along with several others). Planning on looking more closely at the other branchless variants from x86 to see if any are worth porting in future changes. Motivation here is the coremark crc8 routine from https://github.com/eembc/coremark/blob/main/core_util.c#L165. This patch significantly reduces the number of unpredictable branches in the workload. Differential Revision: https://reviews.llvm.org/D134881
156 lines
4.1 KiB
LLVM
156 lines
4.1 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
|
; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s | FileCheck --check-prefixes=CHECK,RV32 %s
|
|
; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s | FileCheck --check-prefixes=CHECK,RV64 %s
|
|
|
|
define i16 @select_xor_1(i16 %A, i8 %cond) {
|
|
; RV32-LABEL: select_xor_1:
|
|
; RV32: # %bb.0: # %entry
|
|
; RV32-NEXT: andi a1, a1, 1
|
|
; RV32-NEXT: neg a1, a1
|
|
; RV32-NEXT: andi a1, a1, 43
|
|
; RV32-NEXT: xor a0, a1, a0
|
|
; RV32-NEXT: ret
|
|
;
|
|
; RV64-LABEL: select_xor_1:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: andi a1, a1, 1
|
|
; RV64-NEXT: negw a1, a1
|
|
; RV64-NEXT: andi a1, a1, 43
|
|
; RV64-NEXT: xor a0, a1, a0
|
|
; RV64-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) {
|
|
; RV32-LABEL: select_xor_1b:
|
|
; RV32: # %bb.0: # %entry
|
|
; RV32-NEXT: andi a1, a1, 1
|
|
; RV32-NEXT: neg a1, a1
|
|
; RV32-NEXT: andi a1, a1, 43
|
|
; RV32-NEXT: xor a0, a1, a0
|
|
; RV32-NEXT: ret
|
|
;
|
|
; RV64-LABEL: select_xor_1b:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: andi a1, a1, 1
|
|
; RV64-NEXT: negw a1, a1
|
|
; RV64-NEXT: andi a1, a1, 43
|
|
; RV64-NEXT: xor a0, a1, a0
|
|
; RV64-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) {
|
|
; CHECK-LABEL: select_xor_2:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: andi a2, a2, 1
|
|
; CHECK-NEXT: neg a2, a2
|
|
; CHECK-NEXT: and a1, a2, a1
|
|
; CHECK-NEXT: xor a0, a1, a0
|
|
; CHECK-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) {
|
|
; CHECK-LABEL: select_xor_2b:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: andi a2, a2, 1
|
|
; CHECK-NEXT: neg a2, a2
|
|
; CHECK-NEXT: and a1, a2, a1
|
|
; CHECK-NEXT: xor a0, a1, a0
|
|
; CHECK-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) {
|
|
; CHECK-LABEL: select_or:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: andi a2, a2, 1
|
|
; CHECK-NEXT: neg a2, a2
|
|
; CHECK-NEXT: and a1, a2, a1
|
|
; CHECK-NEXT: or a0, a1, a0
|
|
; CHECK-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) {
|
|
; CHECK-LABEL: select_or_b:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: andi a2, a2, 1
|
|
; CHECK-NEXT: neg a2, a2
|
|
; CHECK-NEXT: and a1, a2, a1
|
|
; CHECK-NEXT: or a0, a1, a0
|
|
; CHECK-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) {
|
|
; CHECK-LABEL: select_or_1:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: andi a2, a2, 1
|
|
; CHECK-NEXT: neg a2, a2
|
|
; CHECK-NEXT: and a1, a2, a1
|
|
; CHECK-NEXT: or a0, a1, a0
|
|
; CHECK-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) {
|
|
; CHECK-LABEL: select_or_1b:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: andi a2, a2, 1
|
|
; CHECK-NEXT: neg a2, a2
|
|
; CHECK-NEXT: and a1, a2, a1
|
|
; CHECK-NEXT: or a0, a1, a0
|
|
; CHECK-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
|
|
}
|