Middle end up optimizations can speculate away the short circuit behavior of C/C++ && and ||. Using i1 and/or or logical select instructions and a single branch. SelectionDAGBuilder can turn i1 and/or/select back into multiple branches, but this is disabled when jump is expensive. RISC-V can use slt(u)(i) to evaluate a condition into any GPR which makes us better than other targets that use a flag register. RISC-V also has single instruction compare and branch. So its not clear from a code size perspective that using compare+and/or is better. If the full condition is dependent on multiple loads, using a logic delays the branch resolution until all the loads are resolved even if there is a cheap condition that makes the loads unnecessary. PowerPC and Lanai are the only CPU targets that use setJumpIsExpensive. NVPTX and AMDGPU also use it but they are GPU targets. PowerPC appears to have a MachineIR pass that turns AND/OR of CR bits into multiple branches. I don't know anything about Lanai and their reason for using setJumpIsExpensive. I think the decision to use logic vs branches is much more nuanced than this big hammer. So I propose to make RISC-V match other CPU targets. Anyone who wants the old behavior can still pass -mllvm -jump-is-expensive=true.
91 lines
3.0 KiB
LLVM
91 lines
3.0 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
|
; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi=ilp32 -verify-machineinstrs < %s \
|
|
; RUN: | FileCheck -check-prefix=RV32IFD %s
|
|
; RUN: llc -mtriple=riscv32 -mattr=+zdinx -target-abi=ilp32 -verify-machineinstrs < %s \
|
|
; RUN: | FileCheck -check-prefix=RV32IZFINXZDINX %s
|
|
|
|
define double @test(double %a) nounwind {
|
|
; RV32IFD-LABEL: test:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV32IZFINXZDINX-LABEL: test:
|
|
; RV32IZFINXZDINX: # %bb.0:
|
|
; RV32IZFINXZDINX-NEXT: ret
|
|
ret double %a
|
|
}
|
|
|
|
; This previously failed complaining of multiple vreg defs due to an ABI
|
|
; lowering issue.
|
|
|
|
define i32 @main() nounwind {
|
|
; RV32IFD-LABEL: main:
|
|
; RV32IFD: # %bb.0: # %entry
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
|
|
; RV32IFD-NEXT: lui a1, 262144
|
|
; RV32IFD-NEXT: li a0, 0
|
|
; RV32IFD-NEXT: call test@plt
|
|
; RV32IFD-NEXT: sw a0, 0(sp)
|
|
; RV32IFD-NEXT: sw a1, 4(sp)
|
|
; RV32IFD-NEXT: fld fa5, 0(sp)
|
|
; RV32IFD-NEXT: lui a0, %hi(.LCPI1_0)
|
|
; RV32IFD-NEXT: fld fa4, %lo(.LCPI1_0)(a0)
|
|
; RV32IFD-NEXT: flt.d a0, fa5, fa4
|
|
; RV32IFD-NEXT: bnez a0, .LBB1_3
|
|
; RV32IFD-NEXT: # %bb.1: # %entry
|
|
; RV32IFD-NEXT: lui a0, %hi(.LCPI1_1)
|
|
; RV32IFD-NEXT: fld fa4, %lo(.LCPI1_1)(a0)
|
|
; RV32IFD-NEXT: flt.d a0, fa4, fa5
|
|
; RV32IFD-NEXT: bnez a0, .LBB1_3
|
|
; RV32IFD-NEXT: # %bb.2: # %if.end
|
|
; RV32IFD-NEXT: call exit@plt
|
|
; RV32IFD-NEXT: .LBB1_3: # %if.then
|
|
; RV32IFD-NEXT: call abort@plt
|
|
;
|
|
; RV32IZFINXZDINX-LABEL: main:
|
|
; RV32IZFINXZDINX: # %bb.0: # %entry
|
|
; RV32IZFINXZDINX-NEXT: addi sp, sp, -16
|
|
; RV32IZFINXZDINX-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
|
|
; RV32IZFINXZDINX-NEXT: lui a1, 262144
|
|
; RV32IZFINXZDINX-NEXT: li a0, 0
|
|
; RV32IZFINXZDINX-NEXT: call test@plt
|
|
; RV32IZFINXZDINX-NEXT: sw a0, 0(sp)
|
|
; RV32IZFINXZDINX-NEXT: sw a1, 4(sp)
|
|
; RV32IZFINXZDINX-NEXT: lw a0, 0(sp)
|
|
; RV32IZFINXZDINX-NEXT: lw a1, 4(sp)
|
|
; RV32IZFINXZDINX-NEXT: lui a2, %hi(.LCPI1_0)
|
|
; RV32IZFINXZDINX-NEXT: lw a3, %lo(.LCPI1_0+4)(a2)
|
|
; RV32IZFINXZDINX-NEXT: lw a2, %lo(.LCPI1_0)(a2)
|
|
; RV32IZFINXZDINX-NEXT: flt.d a2, a0, a2
|
|
; RV32IZFINXZDINX-NEXT: bnez a2, .LBB1_3
|
|
; RV32IZFINXZDINX-NEXT: # %bb.1: # %entry
|
|
; RV32IZFINXZDINX-NEXT: lui a2, %hi(.LCPI1_1)
|
|
; RV32IZFINXZDINX-NEXT: lw a3, %lo(.LCPI1_1+4)(a2)
|
|
; RV32IZFINXZDINX-NEXT: lw a2, %lo(.LCPI1_1)(a2)
|
|
; RV32IZFINXZDINX-NEXT: flt.d a0, a2, a0
|
|
; RV32IZFINXZDINX-NEXT: bnez a0, .LBB1_3
|
|
; RV32IZFINXZDINX-NEXT: # %bb.2: # %if.end
|
|
; RV32IZFINXZDINX-NEXT: call exit@plt
|
|
; RV32IZFINXZDINX-NEXT: .LBB1_3: # %if.then
|
|
; RV32IZFINXZDINX-NEXT: call abort@plt
|
|
entry:
|
|
%call = call double @test(double 2.000000e+00)
|
|
%cmp = fcmp olt double %call, 2.400000e-01
|
|
%cmp2 = fcmp ogt double %call, 2.600000e-01
|
|
%or.cond = or i1 %cmp, %cmp2
|
|
br i1 %or.cond, label %if.then, label %if.end
|
|
|
|
if.then:
|
|
call void @abort()
|
|
unreachable
|
|
|
|
if.end:
|
|
call void @exit(i32 0)
|
|
unreachable
|
|
}
|
|
|
|
declare void @abort()
|
|
|
|
declare void @exit(i32)
|