From 2edf253eb80abc1ef8dd782c1b44b5831110de25 Mon Sep 17 00:00:00 2001 From: Alex Bradbury Date: Fri, 25 Jan 2019 14:33:08 +0000 Subject: [PATCH] [RISCV] Add tests to demonstrate bitcasted fneg/fabs dagcombines This target-independent code won't trigger for cases such as RV32FD where custom SelectionDAG nodes are generated. These new tests demonstrate such cases. Additionally, float-arith.ll was updated so that fneg.s, fsgnjn.s, and fabs.s selection patterns are actually exercised. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@352199 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../RISCV/double-bitmanip-dagcombines.ll | 80 +++++++++++++++++++ test/CodeGen/RISCV/float-arith.ll | 58 ++++++++------ .../RISCV/float-bitmanip-dagcombines.ll | 49 ++++++++++++ 3 files changed, 162 insertions(+), 25 deletions(-) create mode 100644 test/CodeGen/RISCV/double-bitmanip-dagcombines.ll create mode 100644 test/CodeGen/RISCV/float-bitmanip-dagcombines.ll diff --git a/test/CodeGen/RISCV/double-bitmanip-dagcombines.ll b/test/CodeGen/RISCV/double-bitmanip-dagcombines.ll new file mode 100644 index 00000000000..7ad72cca60c --- /dev/null +++ b/test/CodeGen/RISCV/double-bitmanip-dagcombines.ll @@ -0,0 +1,80 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s +; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32IFD %s +; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64I %s +; +; This file tests cases where simple floating point operations can be +; profitably handled though bit manipulation if a soft-float ABI is being used +; (e.g. fneg implemented by XORing the sign bit). This is typically handled in +; DAGCombiner::visitBITCAST, but this target-independent code may not trigger +; in cases where we perform custom legalisation (e.g. RV32IFD). + +; TODO: Add an appropriate target-specific DAG combine that can handle +; RISCVISD::SplitF64/BuildPairF64 used for RV32IFD. + +define double @fneg(double %a) nounwind { +; RV32I-LABEL: fneg: +; RV32I: # %bb.0: +; RV32I-NEXT: lui a2, 524288 +; RV32I-NEXT: xor a1, a1, a2 +; RV32I-NEXT: ret +; +; RV32IFD-LABEL: fneg: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw a0, 8(sp) +; RV32IFD-NEXT: sw a1, 12(sp) +; RV32IFD-NEXT: fld ft0, 8(sp) +; RV32IFD-NEXT: fneg.d ft0, ft0 +; RV32IFD-NEXT: fsd ft0, 8(sp) +; RV32IFD-NEXT: lw a0, 8(sp) +; RV32IFD-NEXT: lw a1, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret +; +; RV64I-LABEL: fneg: +; RV64I: # %bb.0: +; RV64I-NEXT: addi a1, zero, -1 +; RV64I-NEXT: slli a1, a1, 63 +; RV64I-NEXT: xor a0, a0, a1 +; RV64I-NEXT: ret + %1 = fneg double %a + ret double %1 +} + +declare double @llvm.fabs.f64(double) + +define double @fabs(double %a) nounwind { +; RV32I-LABEL: fabs: +; RV32I: # %bb.0: +; RV32I-NEXT: lui a2, 524288 +; RV32I-NEXT: addi a2, a2, -1 +; RV32I-NEXT: and a1, a1, a2 +; RV32I-NEXT: ret +; +; RV32IFD-LABEL: fabs: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw a0, 8(sp) +; RV32IFD-NEXT: sw a1, 12(sp) +; RV32IFD-NEXT: fld ft0, 8(sp) +; RV32IFD-NEXT: fabs.d ft0, ft0 +; RV32IFD-NEXT: fsd ft0, 8(sp) +; RV32IFD-NEXT: lw a0, 8(sp) +; RV32IFD-NEXT: lw a1, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret +; +; RV64I-LABEL: fabs: +; RV64I: # %bb.0: +; RV64I-NEXT: addi a1, zero, -1 +; RV64I-NEXT: slli a1, a1, 63 +; RV64I-NEXT: addi a1, a1, -1 +; RV64I-NEXT: and a0, a0, a1 +; RV64I-NEXT: ret + %1 = call double @llvm.fabs.f64(double %a) + ret double %1 +} diff --git a/test/CodeGen/RISCV/float-arith.ll b/test/CodeGen/RISCV/float-arith.ll index ab874476541..25e09471fad 100644 --- a/test/CodeGen/RISCV/float-arith.ll +++ b/test/CodeGen/RISCV/float-arith.ll @@ -81,50 +81,58 @@ define float @fsgnj_s(float %a, float %b) nounwind { ret float %1 } -define float @fneg_s(float %a) nounwind { -; TODO: doesn't test the fneg selection pattern because -; DAGCombiner::visitBITCAST will generate a xor on the incoming integer -; argument +; This function performs extra work to ensure that +; DAGCombiner::visitBITCAST doesn't replace the fneg with an xor. +define i32 @fneg_s(float %a, float %b) nounwind { ; RV32IF-LABEL: fneg_s: ; RV32IF: # %bb.0: -; RV32IF-NEXT: lui a1, 524288 -; RV32IF-NEXT: xor a0, a0, a1 +; RV32IF-NEXT: fmv.w.x ft0, a0 +; RV32IF-NEXT: fadd.s ft0, ft0, ft0 +; RV32IF-NEXT: fneg.s ft1, ft0 +; RV32IF-NEXT: feq.s a0, ft0, ft1 ; RV32IF-NEXT: ret - %1 = fsub float -0.0, %a - ret float %1 + %1 = fadd float %a, %a + %2 = fneg float %1 + %3 = fcmp oeq float %1, %2 + %4 = zext i1 %3 to i32 + ret i32 %4 } +; This function performs extra work to ensure that +; DAGCombiner::visitBITCAST doesn't replace the fneg with an xor. define float @fsgnjn_s(float %a, float %b) nounwind { -; TODO: fsgnjn.s isn't selected because DAGCombiner::visitBITCAST will convert -; (bitconvert (fneg x)) to a xor ; RV32IF-LABEL: fsgnjn_s: ; RV32IF: # %bb.0: -; RV32IF-NEXT: lui a2, 524288 -; RV32IF-NEXT: xor a1, a1, a2 ; RV32IF-NEXT: fmv.w.x ft0, a1 ; RV32IF-NEXT: fmv.w.x ft1, a0 -; RV32IF-NEXT: fsgnj.s ft0, ft1, ft0 +; RV32IF-NEXT: fadd.s ft0, ft1, ft0 +; RV32IF-NEXT: fsgnjn.s ft0, ft1, ft0 ; RV32IF-NEXT: fmv.x.w a0, ft0 ; RV32IF-NEXT: ret - %1 = fsub float -0.0, %b - %2 = call float @llvm.copysign.f32(float %a, float %1) - ret float %2 + %1 = fadd float %a, %b + %2 = fneg float %1 + %3 = call float @llvm.copysign.f32(float %a, float %2) + ret float %3 } declare float @llvm.fabs.f32(float) -define float @fabs_s(float %a) nounwind { -; TODO: doesn't test the fabs selection pattern because -; DAGCombiner::visitBITCAST will generate an and on the incoming integer -; argument +; This function performs extra work to ensure that +; DAGCombiner::visitBITCAST doesn't replace the fabs with an and. +define float @fabs_s(float %a, float %b) nounwind { ; RV32IF-LABEL: fabs_s: ; RV32IF: # %bb.0: -; RV32IF-NEXT: lui a1, 524288 -; RV32IF-NEXT: addi a1, a1, -1 -; RV32IF-NEXT: and a0, a0, a1 +; RV32IF-NEXT: fmv.w.x ft0, a1 +; RV32IF-NEXT: fmv.w.x ft1, a0 +; RV32IF-NEXT: fadd.s ft0, ft1, ft0 +; RV32IF-NEXT: fabs.s ft1, ft0 +; RV32IF-NEXT: fadd.s ft0, ft1, ft0 +; RV32IF-NEXT: fmv.x.w a0, ft0 ; RV32IF-NEXT: ret - %1 = call float @llvm.fabs.f32(float %a) - ret float %1 + %1 = fadd float %a, %b + %2 = call float @llvm.fabs.f32(float %1) + %3 = fadd float %2, %1 + ret float %3 } declare float @llvm.minnum.f32(float, float) diff --git a/test/CodeGen/RISCV/float-bitmanip-dagcombines.ll b/test/CodeGen/RISCV/float-bitmanip-dagcombines.ll new file mode 100644 index 00000000000..0911481e5c8 --- /dev/null +++ b/test/CodeGen/RISCV/float-bitmanip-dagcombines.ll @@ -0,0 +1,49 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s +; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s +; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64I %s + +; This file tests cases where simple floating point operations can be +; profitably handled though bit manipulation if a soft-float ABI is being used +; (e.g. fneg implemented by XORing the sign bit). This is typically handled in +; DAGCombiner::visitBITCAST, but this target-independent code may not trigger +; in cases where we perform custom legalisation (e.g. RV64F). + +define float @fneg(float %a) nounwind { +; RV32I-LABEL: fneg: +; RV32I: # %bb.0: +; RV32I-NEXT: lui a1, 524288 +; RV32I-NEXT: xor a0, a0, a1 +; RV32I-NEXT: ret +; +; RV64I-LABEL: fneg: +; RV64I: # %bb.0: +; RV64I-NEXT: lui a1, 524288 +; RV64I-NEXT: xor a0, a0, a1 +; RV64I-NEXT: ret + %1 = fneg float %a + ret float %1 +} + +declare float @llvm.fabs.f32(float) + +define float @fabs(float %a) nounwind { +; RV32I-LABEL: fabs: +; RV32I: # %bb.0: +; RV32I-NEXT: lui a1, 524288 +; RV32I-NEXT: addi a1, a1, -1 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: ret +; +; RV64I-LABEL: fabs: +; RV64I: # %bb.0: +; RV64I-NEXT: lui a1, 524288 +; RV64I-NEXT: addiw a1, a1, -1 +; RV64I-NEXT: and a0, a0, a1 +; RV64I-NEXT: ret + %1 = call float @llvm.fabs.f32(float %a) + ret float %1 +} -- 2.50.1