diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp index 8534a0ad886ec..c2f6f5e131603 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.cpp +++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -192,6 +192,7 @@ const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const { case MipsISD::Ret: return "MipsISD::Ret"; case MipsISD::ERet: return "MipsISD::ERet"; case MipsISD::EH_RETURN: return "MipsISD::EH_RETURN"; + case MipsISD::FAbs: return "MipsISD::FAbs"; case MipsISD::FMS: return "MipsISD::FMS"; case MipsISD::FPBrcond: return "MipsISD::FPBrcond"; case MipsISD::FPCmp: return "MipsISD::FPCmp"; @@ -353,15 +354,12 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM, setOperationAction(ISD::SETCC, MVT::f32, Custom); setOperationAction(ISD::SETCC, MVT::f64, Custom); setOperationAction(ISD::BRCOND, MVT::Other, Custom); + setOperationAction(ISD::FABS, MVT::f32, Custom); + setOperationAction(ISD::FABS, MVT::f64, Custom); setOperationAction(ISD::FCOPYSIGN, MVT::f32, Custom); setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom); setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); - if (!(TM.Options.NoNaNsFPMath || Subtarget.inAbs2008Mode())) { - setOperationAction(ISD::FABS, MVT::f32, Custom); - setOperationAction(ISD::FABS, MVT::f64, Custom); - } - if (Subtarget.isGP64bit()) { setOperationAction(ISD::GlobalAddress, MVT::i64, Custom); setOperationAction(ISD::BlockAddress, MVT::i64, Custom); @@ -2421,11 +2419,14 @@ MipsTargetLowering::lowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const { return lowerFCOPYSIGN32(Op, DAG, Subtarget.hasExtractInsert()); } -static SDValue lowerFABS32(SDValue Op, SelectionDAG &DAG, - bool HasExtractInsert) { +SDValue MipsTargetLowering::lowerFABS32(SDValue Op, SelectionDAG &DAG, + bool HasExtractInsert) const { SDLoc DL(Op); SDValue Res, Const1 = DAG.getConstant(1, DL, MVT::i32); + if (DAG.getTarget().Options.NoNaNsFPMath || Subtarget.inAbs2008Mode()) + return DAG.getNode(MipsISD::FAbs, DL, Op.getValueType(), Op.getOperand(0)); + // If operand is of type f64, extract the upper 32-bit. Otherwise, bitcast it // to i32. SDValue X = (Op.getValueType() == MVT::f32) @@ -2458,11 +2459,14 @@ static SDValue lowerFABS32(SDValue Op, SelectionDAG &DAG, return DAG.getNode(MipsISD::BuildPairF64, DL, MVT::f64, LowX, Res); } -static SDValue lowerFABS64(SDValue Op, SelectionDAG &DAG, - bool HasExtractInsert) { +SDValue MipsTargetLowering::lowerFABS64(SDValue Op, SelectionDAG &DAG, + bool HasExtractInsert) const { SDLoc DL(Op); SDValue Res, Const1 = DAG.getConstant(1, DL, MVT::i32); + if (DAG.getTarget().Options.NoNaNsFPMath || Subtarget.inAbs2008Mode()) + return DAG.getNode(MipsISD::FAbs, DL, Op.getValueType(), Op.getOperand(0)); + // Bitcast to integer node. SDValue X = DAG.getNode(ISD::BITCAST, DL, MVT::i64, Op.getOperand(0)); diff --git a/llvm/lib/Target/Mips/MipsISelLowering.h b/llvm/lib/Target/Mips/MipsISelLowering.h index 3905a18895ded..66207193c8b3a 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.h +++ b/llvm/lib/Target/Mips/MipsISelLowering.h @@ -99,6 +99,9 @@ class TargetRegisterClass; // Floating Point Compare FPCmp, + // Floating point Abs + FAbs, + // Floating point select FSELECT, @@ -540,6 +543,10 @@ class TargetRegisterClass; SDValue lowerVAARG(SDValue Op, SelectionDAG &DAG) const; SDValue lowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const; SDValue lowerFABS(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerFABS32(SDValue Op, SelectionDAG &DAG, + bool HasExtractInsert) const; + SDValue lowerFABS64(SDValue Op, SelectionDAG &DAG, + bool HasExtractInsert) const; SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; SDValue lowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp b/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp index 03a545605fe16..ae92604d47bac 100644 --- a/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp +++ b/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp @@ -956,6 +956,38 @@ bool MipsSEDAGToDAGISel::trySelect(SDNode *Node) { break; } + case MipsISD::FAbs: { + MVT ResTy = Node->getSimpleValueType(0); + assert((ResTy == MVT::f64 || ResTy == MVT::f32) && + "Unsupported float type!"); + unsigned Opc = 0; + if (ResTy == MVT::f64) + Opc = (Subtarget->isFP64bit() ? Mips::FABS_D64 : Mips::FABS_D32); + else + Opc = Mips::FABS_S; + + if (Subtarget->inMicroMipsMode()) { + switch (Opc) { + case Mips::FABS_D64: + Opc = Mips::FABS_D64_MM; + break; + case Mips::FABS_D32: + Opc = Mips::FABS_D32_MM; + break; + case Mips::FABS_S: + Opc = Mips::FABS_S_MM; + break; + default: + llvm_unreachable("Unknown opcode for MIPS floating point abs!"); + } + } + + ReplaceNode(Node, + CurDAG->getMachineNode(Opc, DL, ResTy, Node->getOperand(0))); + + return true; + } + // Manually match MipsISD::Ins nodes to get the correct instruction. It has // to be done in this fashion so that we respect the differences between // dins and dinsm, as the difference is that the size operand has the range diff --git a/llvm/test/CodeGen/Mips/llvm-ir/nan-fp-attr.ll b/llvm/test/CodeGen/Mips/llvm-ir/nan-fp-attr.ll new file mode 100644 index 0000000000000..918cda6b38c26 --- /dev/null +++ b/llvm/test/CodeGen/Mips/llvm-ir/nan-fp-attr.ll @@ -0,0 +1,327 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -march=mips -mcpu=mips32 | FileCheck %s --check-prefix=MIPS32R1 +; RUN: llc < %s -march=mips -mcpu=mips32r2 | FileCheck %s --check-prefix=MIPS32R2 +; RUN: llc < %s -march=mips -mcpu=mips32r2 -mattr=+abs2008 | FileCheck %s --check-prefix=MIPS32R2-ABS2K8 +; RUN: llc < %s -march=mips -mcpu=mips32r2 -mattr=+abs2008,+fp64 | FileCheck %s --check-prefix=MIPS32R2-ABS2K8 +; RUN: llc < %s -march=mips -mcpu=mips32r2 -mattr=+fp64 | FileCheck %s --check-prefix=MIPS32R2 +; RUN: llc < %s -march=mips -mcpu=mips32r6 | FileCheck %s --check-prefix=MIPS32R6 +; RUN: llc < %s -march=mips64 -mcpu=mips64 | FileCheck %s --check-prefix=MIPS64R1 +; RUN: llc < %s -march=mips64 -mcpu=mips64r2 | FileCheck %s --check-prefix=MIPS64R2 +; RUN: llc < %s -march=mips64 -mcpu=mips64r2 -mattr=+abs2008 | FileCheck %s --check-prefix=MIPS64R2-ABS2K8 +; RUN: llc < %s -march=mips64 -mcpu=mips64r6 | FileCheck %s --check-prefix=MIPS64R6 +; RUN: llc < %s -march=mips64 -mcpu=mips64r6 -mattr=+abs2008 | FileCheck %s --check-prefix=MIPS64R6-ABS2K8 +; RUN: llc < %s -march=mips -mcpu=mips32r2 -mattr=+micromips | FileCheck %s --check-prefix=MM +; RUN: llc < %s -march=mips -mcpu=mips32r2 -mattr=+micromips,+abs2008 | FileCheck %s --check-prefix=MM-ABS2K8 +; RUN: llc < %s -march=mips -mcpu=mips32r2 -mattr=+micromips,+abs2008,+fp64 | FileCheck %s --check-prefix=MM-ABS2K8 +; RUN: llc < %s -march=mips -mcpu=mips32r2 -mattr=+micromips,+fp64 | FileCheck %s --check-prefix=MM +; RUN: llc < %s -march=mips -mcpu=mips32r6 -mattr=+micromips | FileCheck %s --check-prefix=MMR6 + +; Test that the instruction selection for the case of `abs.s` and `abs.d` +; matches the expected behaviour. In the default case with NaNs and no "abs2008" +; mode MIPS treats abs.s and abs.d as arithmetic fp instructions triggering +; a fp exception on execution if the input is a NaN. This results in no abs.[sd] +; instructions. + +; In the case where no NaNs are present is asserted or in "abs2008" mode, +; abs.[sd] instructions are selected. + +declare double @llvm.fabs.f64(double) +declare float @llvm.fabs.f32(float) + +define dso_local double @foo(double %a) #0 { +; MIPS32R1-LABEL: foo: +; MIPS32R1: # %bb.0: # %entry +; MIPS32R1-NEXT: jr $ra +; MIPS32R1-NEXT: abs.d $f0, $f12 +; +; MIPS32R2-LABEL: foo: +; MIPS32R2: # %bb.0: # %entry +; MIPS32R2-NEXT: jr $ra +; MIPS32R2-NEXT: abs.d $f0, $f12 +; +; MIPS32R2-ABS2K8-LABEL: foo: +; MIPS32R2-ABS2K8: # %bb.0: # %entry +; MIPS32R2-ABS2K8-NEXT: jr $ra +; MIPS32R2-ABS2K8-NEXT: abs.d $f0, $f12 +; +; MIPS32R6-LABEL: foo: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: jr $ra +; MIPS32R6-NEXT: abs.d $f0, $f12 +; +; MIPS64R1-LABEL: foo: +; MIPS64R1: # %bb.0: # %entry +; MIPS64R1-NEXT: jr $ra +; MIPS64R1-NEXT: abs.d $f0, $f12 +; +; MIPS64R2-LABEL: foo: +; MIPS64R2: # %bb.0: # %entry +; MIPS64R2-NEXT: jr $ra +; MIPS64R2-NEXT: abs.d $f0, $f12 +; +; MIPS64R2-ABS2K8-LABEL: foo: +; MIPS64R2-ABS2K8: # %bb.0: # %entry +; MIPS64R2-ABS2K8-NEXT: jr $ra +; MIPS64R2-ABS2K8-NEXT: abs.d $f0, $f12 +; +; MIPS64R6-LABEL: foo: +; MIPS64R6: # %bb.0: # %entry +; MIPS64R6-NEXT: jr $ra +; MIPS64R6-NEXT: abs.d $f0, $f12 +; +; MIPS64R6-ABS2K8-LABEL: foo: +; MIPS64R6-ABS2K8: # %bb.0: # %entry +; MIPS64R6-ABS2K8-NEXT: jr $ra +; MIPS64R6-ABS2K8-NEXT: abs.d $f0, $f12 +; +; MM-LABEL: foo: +; MM: # %bb.0: # %entry +; MM-NEXT: jr $ra +; MM-NEXT: abs.d $f0, $f12 +; +; MM-ABS2K8-LABEL: foo: +; MM-ABS2K8: # %bb.0: # %entry +; MM-ABS2K8-NEXT: jr $ra +; MM-ABS2K8-NEXT: abs.d $f0, $f12 +; +; MMR6-LABEL: foo: +; MMR6: # %bb.0: # %entry +; MMR6-NEXT: abs.d $f0, $f12 +; MMR6-NEXT: jrc $ra +entry: + %0 = tail call fast double @llvm.fabs.f64(double %a) + ret double %0 +} + +define dso_local double @bar(double %a) { +; MIPS32R1-LABEL: bar: +; MIPS32R1: # %bb.0: # %entry +; MIPS32R1-NEXT: lui $1, 32767 +; MIPS32R1-NEXT: ori $1, $1, 65535 +; MIPS32R1-NEXT: mfc1 $2, $f13 +; MIPS32R1-NEXT: and $1, $2, $1 +; MIPS32R1-NEXT: mfc1 $2, $f12 +; MIPS32R1-NEXT: mtc1 $2, $f0 +; MIPS32R1-NEXT: jr $ra +; MIPS32R1-NEXT: mtc1 $1, $f1 +; +; MIPS32R2-LABEL: bar: +; MIPS32R2: # %bb.0: # %entry +; MIPS32R2-NEXT: mfc1 $1, $f12 +; MIPS32R2-NEXT: mfhc1 $2, $f12 +; MIPS32R2-NEXT: ins $2, $zero, 31, 1 +; MIPS32R2-NEXT: mtc1 $1, $f0 +; MIPS32R2-NEXT: mthc1 $2, $f0 +; MIPS32R2-NEXT: jr $ra +; MIPS32R2-NEXT: nop +; +; MIPS32R2-ABS2K8-LABEL: bar: +; MIPS32R2-ABS2K8: # %bb.0: # %entry +; MIPS32R2-ABS2K8-NEXT: jr $ra +; MIPS32R2-ABS2K8-NEXT: abs.d $f0, $f12 +; +; MIPS32R6-LABEL: bar: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: jr $ra +; MIPS32R6-NEXT: abs.d $f0, $f12 +; +; MIPS64R1-LABEL: bar: +; MIPS64R1: # %bb.0: # %entry +; MIPS64R1-NEXT: dmfc1 $1, $f12 +; MIPS64R1-NEXT: daddiu $2, $zero, 1 +; MIPS64R1-NEXT: dsll $2, $2, 63 +; MIPS64R1-NEXT: daddiu $2, $2, -1 +; MIPS64R1-NEXT: and $1, $1, $2 +; MIPS64R1-NEXT: jr $ra +; MIPS64R1-NEXT: dmtc1 $1, $f0 +; +; MIPS64R2-LABEL: bar: +; MIPS64R2: # %bb.0: # %entry +; MIPS64R2-NEXT: dmfc1 $1, $f12 +; MIPS64R2-NEXT: dinsu $1, $zero, 63, 1 +; MIPS64R2-NEXT: jr $ra +; MIPS64R2-NEXT: dmtc1 $1, $f0 +; +; MIPS64R2-ABS2K8-LABEL: bar: +; MIPS64R2-ABS2K8: # %bb.0: # %entry +; MIPS64R2-ABS2K8-NEXT: jr $ra +; MIPS64R2-ABS2K8-NEXT: abs.d $f0, $f12 +; +; MIPS64R6-LABEL: bar: +; MIPS64R6: # %bb.0: # %entry +; MIPS64R6-NEXT: jr $ra +; MIPS64R6-NEXT: abs.d $f0, $f12 +; +; MIPS64R6-ABS2K8-LABEL: bar: +; MIPS64R6-ABS2K8: # %bb.0: # %entry +; MIPS64R6-ABS2K8-NEXT: jr $ra +; MIPS64R6-ABS2K8-NEXT: abs.d $f0, $f12 +; +; MM-LABEL: bar: +; MM: # %bb.0: # %entry +; MM-NEXT: mfc1 $1, $f12 +; MM-NEXT: mfhc1 $2, $f12 +; MM-NEXT: ins $2, $zero, 31, 1 +; MM-NEXT: mtc1 $1, $f0 +; MM-NEXT: mthc1 $2, $f0 +; MM-NEXT: jrc $ra +; +; MM-ABS2K8-LABEL: bar: +; MM-ABS2K8: # %bb.0: # %entry +; MM-ABS2K8-NEXT: jr $ra +; MM-ABS2K8-NEXT: abs.d $f0, $f12 +; +; MMR6-LABEL: bar: +; MMR6: # %bb.0: # %entry +; MMR6-NEXT: abs.d $f0, $f12 +; MMR6-NEXT: jrc $ra +entry: + %0 = tail call fast double @llvm.fabs.f64(double %a) + ret double %0 +} + +define dso_local float @foo_2(float %a) #0 { +; MIPS32R1-LABEL: foo_2: +; MIPS32R1: # %bb.0: # %entry +; MIPS32R1-NEXT: jr $ra +; MIPS32R1-NEXT: abs.s $f0, $f12 +; +; MIPS32R2-LABEL: foo_2: +; MIPS32R2: # %bb.0: # %entry +; MIPS32R2-NEXT: jr $ra +; MIPS32R2-NEXT: abs.s $f0, $f12 +; +; MIPS32R2-ABS2K8-LABEL: foo_2: +; MIPS32R2-ABS2K8: # %bb.0: # %entry +; MIPS32R2-ABS2K8-NEXT: jr $ra +; MIPS32R2-ABS2K8-NEXT: abs.s $f0, $f12 +; +; MIPS32R6-LABEL: foo_2: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: jr $ra +; MIPS32R6-NEXT: abs.s $f0, $f12 +; +; MIPS64R1-LABEL: foo_2: +; MIPS64R1: # %bb.0: # %entry +; MIPS64R1-NEXT: jr $ra +; MIPS64R1-NEXT: abs.s $f0, $f12 +; +; MIPS64R2-LABEL: foo_2: +; MIPS64R2: # %bb.0: # %entry +; MIPS64R2-NEXT: jr $ra +; MIPS64R2-NEXT: abs.s $f0, $f12 +; +; MIPS64R2-ABS2K8-LABEL: foo_2: +; MIPS64R2-ABS2K8: # %bb.0: # %entry +; MIPS64R2-ABS2K8-NEXT: jr $ra +; MIPS64R2-ABS2K8-NEXT: abs.s $f0, $f12 +; +; MIPS64R6-LABEL: foo_2: +; MIPS64R6: # %bb.0: # %entry +; MIPS64R6-NEXT: jr $ra +; MIPS64R6-NEXT: abs.s $f0, $f12 +; +; MIPS64R6-ABS2K8-LABEL: foo_2: +; MIPS64R6-ABS2K8: # %bb.0: # %entry +; MIPS64R6-ABS2K8-NEXT: jr $ra +; MIPS64R6-ABS2K8-NEXT: abs.s $f0, $f12 +; +; MM-LABEL: foo_2: +; MM: # %bb.0: # %entry +; MM-NEXT: jr $ra +; MM-NEXT: abs.s $f0, $f12 +; +; MM-ABS2K8-LABEL: foo_2: +; MM-ABS2K8: # %bb.0: # %entry +; MM-ABS2K8-NEXT: jr $ra +; MM-ABS2K8-NEXT: abs.s $f0, $f12 +; +; MMR6-LABEL: foo_2: +; MMR6: # %bb.0: # %entry +; MMR6-NEXT: abs.s $f0, $f12 +; MMR6-NEXT: jrc $ra +entry: + %0 = tail call fast float @llvm.fabs.f32(float %a) + ret float %0 +} + +define dso_local float @bar_2(float %a) { +; MIPS32R1-LABEL: bar_2: +; MIPS32R1: # %bb.0: # %entry +; MIPS32R1-NEXT: lui $1, 32767 +; MIPS32R1-NEXT: ori $1, $1, 65535 +; MIPS32R1-NEXT: mfc1 $2, $f12 +; MIPS32R1-NEXT: and $1, $2, $1 +; MIPS32R1-NEXT: jr $ra +; MIPS32R1-NEXT: mtc1 $1, $f0 +; +; MIPS32R2-LABEL: bar_2: +; MIPS32R2: # %bb.0: # %entry +; MIPS32R2-NEXT: mfc1 $1, $f12 +; MIPS32R2-NEXT: ins $1, $zero, 31, 1 +; MIPS32R2-NEXT: jr $ra +; MIPS32R2-NEXT: mtc1 $1, $f0 +; +; MIPS32R2-ABS2K8-LABEL: bar_2: +; MIPS32R2-ABS2K8: # %bb.0: # %entry +; MIPS32R2-ABS2K8-NEXT: jr $ra +; MIPS32R2-ABS2K8-NEXT: abs.s $f0, $f12 +; +; MIPS32R6-LABEL: bar_2: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: jr $ra +; MIPS32R6-NEXT: abs.s $f0, $f12 +; +; MIPS64R1-LABEL: bar_2: +; MIPS64R1: # %bb.0: # %entry +; MIPS64R1-NEXT: lui $1, 32767 +; MIPS64R1-NEXT: ori $1, $1, 65535 +; MIPS64R1-NEXT: mfc1 $2, $f12 +; MIPS64R1-NEXT: and $1, $2, $1 +; MIPS64R1-NEXT: jr $ra +; MIPS64R1-NEXT: mtc1 $1, $f0 +; +; MIPS64R2-LABEL: bar_2: +; MIPS64R2: # %bb.0: # %entry +; MIPS64R2-NEXT: mfc1 $1, $f12 +; MIPS64R2-NEXT: ins $1, $zero, 31, 1 +; MIPS64R2-NEXT: jr $ra +; MIPS64R2-NEXT: mtc1 $1, $f0 +; +; MIPS64R2-ABS2K8-LABEL: bar_2: +; MIPS64R2-ABS2K8: # %bb.0: # %entry +; MIPS64R2-ABS2K8-NEXT: jr $ra +; MIPS64R2-ABS2K8-NEXT: abs.s $f0, $f12 +; +; MIPS64R6-LABEL: bar_2: +; MIPS64R6: # %bb.0: # %entry +; MIPS64R6-NEXT: jr $ra +; MIPS64R6-NEXT: abs.s $f0, $f12 +; +; MIPS64R6-ABS2K8-LABEL: bar_2: +; MIPS64R6-ABS2K8: # %bb.0: # %entry +; MIPS64R6-ABS2K8-NEXT: jr $ra +; MIPS64R6-ABS2K8-NEXT: abs.s $f0, $f12 +; +; MM-LABEL: bar_2: +; MM: # %bb.0: # %entry +; MM-NEXT: mfc1 $1, $f12 +; MM-NEXT: ins $1, $zero, 31, 1 +; MM-NEXT: jr $ra +; MM-NEXT: mtc1 $1, $f0 +; +; MM-ABS2K8-LABEL: bar_2: +; MM-ABS2K8: # %bb.0: # %entry +; MM-ABS2K8-NEXT: jr $ra +; MM-ABS2K8-NEXT: abs.s $f0, $f12 +; +; MMR6-LABEL: bar_2: +; MMR6: # %bb.0: # %entry +; MMR6-NEXT: abs.s $f0, $f12 +; MMR6-NEXT: jrc $ra +entry: + %0 = tail call fast float @llvm.fabs.f32(float %a) + ret float %0 +} + +attributes #0 = { nounwind "no-nans-fp-math"="true" }