diff --git a/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td --- a/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td @@ -142,6 +142,7 @@ def : PatFprFpr; def : PatFprFpr; def : PatFprFpr; +def : PatFprFpr; def : PatFpr; def : PatFpr; def : PatFpr; diff --git a/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td --- a/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td @@ -148,12 +148,18 @@ def : PatFprFpr; def : PatFprFpr; def : PatFprFpr; +def : PatFprFpr; def : PatFpr; def : PatFpr; def : PatFpr; def : Pat<(fdiv fpimm1, (fsqrt FPR64:$fj)), (FRSQRT_D FPR64:$fj)>; +def : Pat<(fcopysign FPR64:$fj, FPR32:$fk), + (FCOPYSIGN_D FPR64:$fj, (FCVT_D_S FPR32:$fk))>; +def : Pat<(fcopysign FPR32:$fj, FPR64:$fk), + (FCOPYSIGN_S FPR32:$fj, (FCVT_S_D FPR64:$fk))>; + /// Setcc // Match non-signaling comparison diff --git a/llvm/test/CodeGen/LoongArch/fcopysign.ll b/llvm/test/CodeGen/LoongArch/fcopysign.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/fcopysign.ll @@ -0,0 +1,123 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc --mtriple=loongarch32 --mattr=+f,-d < %s | FileCheck %s --check-prefix=LA32F +; RUN: llc --mtriple=loongarch32 --mattr=+d < %s | FileCheck %s --check-prefix=LA32D +; RUN: llc --mtriple=loongarch64 --mattr=+f,-d < %s | FileCheck %s --check-prefix=LA64F +; RUN: llc --mtriple=loongarch64 --mattr=+d < %s | FileCheck %s --check-prefix=LA64D + +declare float @llvm.copysign.f32(float, float) +declare double @llvm.copysign.f64(double, double) + +define float @fcopysign_s(float %a, float %b) nounwind { +; LA32F-LABEL: fcopysign_s: +; LA32F: # %bb.0: +; LA32F-NEXT: fcopysign.s $fa0, $fa0, $fa1 +; LA32F-NEXT: ret +; +; LA32D-LABEL: fcopysign_s: +; LA32D: # %bb.0: +; LA32D-NEXT: fcopysign.s $fa0, $fa0, $fa1 +; LA32D-NEXT: ret +; +; LA64F-LABEL: fcopysign_s: +; LA64F: # %bb.0: +; LA64F-NEXT: fcopysign.s $fa0, $fa0, $fa1 +; LA64F-NEXT: ret +; +; LA64D-LABEL: fcopysign_s: +; LA64D: # %bb.0: +; LA64D-NEXT: fcopysign.s $fa0, $fa0, $fa1 +; LA64D-NEXT: ret + %1 = call float @llvm.copysign.f32(float %a, float %b) + ret float %1 +} + +define double @fcopysign_d(double %a, double %b) nounwind { +; LA32F-LABEL: fcopysign_d: +; LA32F: # %bb.0: +; LA32F-NEXT: srli.w $a2, $a3, 31 +; LA32F-NEXT: bstrins.w $a1, $a2, 31, 31 +; LA32F-NEXT: ret +; +; LA32D-LABEL: fcopysign_d: +; LA32D: # %bb.0: +; LA32D-NEXT: fcopysign.d $fa0, $fa0, $fa1 +; LA32D-NEXT: ret +; +; LA64F-LABEL: fcopysign_d: +; LA64F: # %bb.0: +; LA64F-NEXT: srli.d $a1, $a1, 63 +; LA64F-NEXT: bstrins.d $a0, $a1, 63, 63 +; LA64F-NEXT: ret +; +; LA64D-LABEL: fcopysign_d: +; LA64D: # %bb.0: +; LA64D-NEXT: fcopysign.d $fa0, $fa0, $fa1 +; LA64D-NEXT: ret + %1 = call double @llvm.copysign.f64(double %a, double %b) + ret double %1 +} + +define double @fold_promote_d_s(double %a, float %b) nounwind { +; LA32F-LABEL: fold_promote_d_s: +; LA32F: # %bb.0: +; LA32F-NEXT: movfr2gr.s $a2, $fa0 +; LA32F-NEXT: srli.w $a2, $a2, 31 +; LA32F-NEXT: bstrins.w $a1, $a2, 31, 31 +; LA32F-NEXT: ret +; +; LA32D-LABEL: fold_promote_d_s: +; LA32D: # %bb.0: +; LA32D-NEXT: fcvt.d.s $fa1, $fa1 +; LA32D-NEXT: fcopysign.d $fa0, $fa0, $fa1 +; LA32D-NEXT: ret +; +; LA64F-LABEL: fold_promote_d_s: +; LA64F: # %bb.0: +; LA64F-NEXT: lu12i.w $a1, -524288 +; LA64F-NEXT: lu32i.d $a1, 0 +; LA64F-NEXT: movfr2gr.s $a2, $fa0 +; LA64F-NEXT: and $a1, $a2, $a1 +; LA64F-NEXT: slli.d $a1, $a1, 32 +; LA64F-NEXT: bstrins.d $a1, $a0, 62, 0 +; LA64F-NEXT: move $a0, $a1 +; LA64F-NEXT: ret +; +; LA64D-LABEL: fold_promote_d_s: +; LA64D: # %bb.0: +; LA64D-NEXT: fcvt.d.s $fa1, $fa1 +; LA64D-NEXT: fcopysign.d $fa0, $fa0, $fa1 +; LA64D-NEXT: ret + %c = fpext float %b to double + %t = call double @llvm.copysign.f64(double %a, double %c) + ret double %t +} + +define float @fold_demote_s_d(float %a, double %b) nounwind { +; LA32F-LABEL: fold_demote_s_d: +; LA32F: # %bb.0: +; LA32F-NEXT: movgr2fr.w $fa1, $a1 +; LA32F-NEXT: fcopysign.s $fa0, $fa0, $fa1 +; LA32F-NEXT: ret +; +; LA32D-LABEL: fold_demote_s_d: +; LA32D: # %bb.0: +; LA32D-NEXT: fcvt.s.d $fa1, $fa1 +; LA32D-NEXT: fcopysign.s $fa0, $fa0, $fa1 +; LA32D-NEXT: ret +; +; LA64F-LABEL: fold_demote_s_d: +; LA64F: # %bb.0: +; LA64F-NEXT: srli.d $a0, $a0, 32 +; LA64F-NEXT: movgr2fr.w $fa1, $a0 +; LA64F-NEXT: fcopysign.s $fa0, $fa0, $fa1 +; LA64F-NEXT: ret +; +; LA64D-LABEL: fold_demote_s_d: +; LA64D: # %bb.0: +; LA64D-NEXT: fcvt.s.d $fa1, $fa1 +; LA64D-NEXT: fcopysign.s $fa0, $fa0, $fa1 +; LA64D-NEXT: ret + %c = fptrunc double %b to float + %t = call float @llvm.copysign.f32(float %a, float %c) + ret float %t +}