Index: lib/Target/Mips/MicroMipsInstrFPU.td =================================================================== --- lib/Target/Mips/MicroMipsInstrFPU.td +++ lib/Target/Mips/MicroMipsInstrFPU.td @@ -123,7 +123,7 @@ defm FSQRT : ABSS_MMM<"sqrt.d", II_SQRT_D, fsqrt>, ROUND_W_FM_MM<1, 0x28>; defm FABS : ABSS_MMM<"abs.d", II_SQRT_D, fabs>, ABS_FM_MM<1, 0xd>; -let DecoderNamespace = "MicroMips" in { +let DecoderNamespace = "MicroMips", AdditionalPredicates = [UseAbs] in { def FABS_S_MM : MMRel, ABSS_FT<"abs.s", FGR32Opnd, FGR32Opnd, II_ABS, fabs>, ABS_FM_MM<0, 0xd>, ISA_MICROMIPS; } Index: lib/Target/Mips/Mips.td =================================================================== --- lib/Target/Mips/Mips.td +++ lib/Target/Mips/Mips.td @@ -82,6 +82,8 @@ "Support for FPXX">; def FeatureNaN2008 : SubtargetFeature<"nan2008", "IsNaN2008bit", "true", "IEEE 754-2008 NaN encoding">; +def FeatureAbs2008 : SubtargetFeature<"abs2008", "Abs2008", "true", + "Disable IEEE 754-2008 abs.fmt mode">; def FeatureSingleFloat : SubtargetFeature<"single-float", "IsSingleFloat", "true", "Only supports single precision float">; def FeatureSoftFloat : SubtargetFeature<"soft-float", "IsSoftFloat", "true", @@ -141,7 +143,7 @@ "Mips32r6", "Mips32r6 ISA Support [experimental]", [FeatureMips32r5, FeatureFP64Bit, - FeatureNaN2008]>; + FeatureNaN2008, FeatureAbs2008]>; def FeatureMips64 : SubtargetFeature<"mips64", "MipsArchVersion", "Mips64", "Mips64 ISA Support", [FeatureMips5, FeatureMips32]>; @@ -158,7 +160,7 @@ "Mips64r6", "Mips64r6 ISA Support [experimental]", [FeatureMips32r6, FeatureMips64r5, - FeatureNaN2008]>; + FeatureNaN2008, FeatureAbs2008]>; def FeatureSym32 : SubtargetFeature<"sym32", "HasSym32", "true", "Symbols are 32 bit on Mips64">; Index: lib/Target/Mips/MipsISelLowering.cpp =================================================================== --- lib/Target/Mips/MipsISelLowering.cpp +++ lib/Target/Mips/MipsISelLowering.cpp @@ -364,6 +364,11 @@ 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); @@ -1218,6 +1223,7 @@ case ISD::VASTART: return lowerVASTART(Op, DAG); case ISD::VAARG: return lowerVAARG(Op, DAG); case ISD::FCOPYSIGN: return lowerFCOPYSIGN(Op, DAG); + case ISD::FABS: return lowerFABS(Op, DAG); case ISD::FRAMEADDR: return lowerFRAMEADDR(Op, DAG); case ISD::RETURNADDR: return lowerRETURNADDR(Op, DAG); case ISD::EH_RETURN: return lowerEH_RETURN(Op, DAG); @@ -2295,6 +2301,71 @@ return lowerFCOPYSIGN32(Op, DAG, Subtarget.hasExtractInsert()); } +static SDValue lowerFABS32(SDValue Op, SelectionDAG &DAG, + bool HasExtractInsert) { + SDLoc DL(Op); + SDValue Res, Const1 = DAG.getConstant(1, DL, MVT::i32); + + // If operand is of type f64, extract the upper 32-bit. Otherwise, bitcast it + // to i32. + SDValue X = (Op.getValueType() == MVT::f32) + ? DAG.getNode(ISD::BITCAST, DL, MVT::i32, Op.getOperand(0)) + : DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, + Op.getOperand(0), Const1); + + // Clear MSB. + if (HasExtractInsert) + Res = DAG.getNode(MipsISD::Ins, DL, MVT::i32, + DAG.getRegister(Mips::ZERO, MVT::i32), + DAG.getConstant(31, DL, MVT::i32), Const1, X); + else { + // TODO: Provide DAG patterns which transform (and x, cst) + // back to a (shl (srl x (clz cst)) (clz cst)) sequence. + SDValue SllX = DAG.getNode(ISD::SHL, DL, MVT::i32, X, Const1); + Res = DAG.getNode(ISD::SRL, DL, MVT::i32, SllX, Const1); + } + + if (Op.getValueType() == MVT::f32) + return DAG.getNode(ISD::BITCAST, DL, MVT::f32, Res); + + // FIXME: For mips32r2, the sequence of (BuildPairF64 (ins (ExtractElementF64 + // Op 1), $zero, 31 1) (ExtractElementF64 Op 0)) and the Op has one use, we + // should be able to drop the usage of mfc1/mtc1 and rewrite the register in + // place. + SDValue LowX = + DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, Op.getOperand(0), + DAG.getConstant(0, DL, MVT::i32)); + return DAG.getNode(MipsISD::BuildPairF64, DL, MVT::f64, LowX, Res); +} + +static SDValue lowerFABS64(SDValue Op, SelectionDAG &DAG, + bool HasExtractInsert) { + SDLoc DL(Op); + SDValue Res, Const1 = DAG.getConstant(1, DL, MVT::i32); + + // Bitcast to integer node. + SDValue X = DAG.getNode(ISD::BITCAST, DL, MVT::i64, Op.getOperand(0)); + + // Clear MSB. + if (HasExtractInsert) + Res = DAG.getNode(MipsISD::Ins, DL, MVT::i64, + DAG.getRegister(Mips::ZERO_64, MVT::i64), + DAG.getConstant(63, DL, MVT::i32), Const1, X); + else { + SDValue SllX = DAG.getNode(ISD::SHL, DL, MVT::i64, X, Const1); + Res = DAG.getNode(ISD::SRL, DL, MVT::i64, SllX, Const1); + } + + return DAG.getNode(ISD::BITCAST, DL, MVT::f64, Res); +} + +SDValue MipsTargetLowering::lowerFABS(SDValue Op, SelectionDAG &DAG) const { + if ((ABI.IsN32() || ABI.IsN64()) && (Op.getValueType() == MVT::f64)) + return lowerFABS64(Op, DAG, Subtarget.hasExtractInsert()); + + return lowerFABS32(Op, DAG, Subtarget.hasExtractInsert()); +} + SDValue MipsTargetLowering:: lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { // check the depth Index: lib/Target/Mips/MipsInstrFPU.td =================================================================== --- lib/Target/Mips/MipsInstrFPU.td +++ lib/Target/Mips/MipsInstrFPU.td @@ -486,7 +486,7 @@ def PseudoCVT_D64_L : ABSS_FT<"", FGR64Opnd, GPR64Opnd, II_CVT>; } -let AdditionalPredicates = [NotInMicroMips] in { +let AdditionalPredicates = [NotInMicroMips, UseAbs] in { def FABS_S : MMRel, ABSS_FT<"abs.s", FGR32Opnd, FGR32Opnd, II_ABS, fabs>, ABSS_FM<0x5, 16>, ISA_MIPS1; defm FABS : ABSS_M<"abs.d", II_ABS, fabs>, ABSS_FM<0x5, 17>, ISA_MIPS1; Index: lib/Target/Mips/MipsInstrInfo.td =================================================================== --- lib/Target/Mips/MipsInstrInfo.td +++ lib/Target/Mips/MipsInstrInfo.td @@ -220,6 +220,8 @@ def RelocNotPIC : Predicate<"!TM.isPositionIndependent()">; def RelocPIC : Predicate<"TM.isPositionIndependent()">; def NoNaNsFPMath : Predicate<"TM.Options.NoNaNsFPMath">; +def UseAbs : Predicate<"Subtarget->inAbs2008Mode() ||" + "TM.Options.NoNaNsFPMath">; def HasStdEnc : Predicate<"Subtarget->hasStandardEncoding()">, AssemblerPredicate<"!FeatureMips16">; def NotDSP : Predicate<"!Subtarget->hasDSP()">; Index: lib/Target/Mips/MipsSubtarget.h =================================================================== --- lib/Target/Mips/MipsSubtarget.h +++ lib/Target/Mips/MipsSubtarget.h @@ -86,6 +86,9 @@ // NoABICalls - Disable SVR4-style position-independent code. bool NoABICalls; + // Abs2008 - Use IEEE 754-2008 abs.fmt instruction. + bool Abs2008; + // IsFP64bit - The target processor has 64-bit floating point registers. bool IsFP64bit; @@ -272,6 +275,7 @@ bool useOddSPReg() const { return UseOddSPReg; } bool noOddSPReg() const { return !UseOddSPReg; } bool isNaN2008() const { return IsNaN2008bit; } + bool inAbs2008Mode() const { return Abs2008; } bool isGP64bit() const { return IsGP64bit; } bool isGP32bit() const { return !IsGP64bit; } unsigned getGPRSizeInBytes() const { return isGP64bit() ? 8 : 4; } Index: lib/Target/Mips/MipsSubtarget.cpp =================================================================== --- lib/Target/Mips/MipsSubtarget.cpp +++ lib/Target/Mips/MipsSubtarget.cpp @@ -72,7 +72,7 @@ unsigned StackAlignOverride) : MipsGenSubtargetInfo(TT, CPU, FS), MipsArchVersion(MipsDefault), IsLittle(little), IsSoftFloat(false), IsSingleFloat(false), IsFPXX(false), - NoABICalls(false), IsFP64bit(false), UseOddSPReg(true), + NoABICalls(false), Abs2008(false), IsFP64bit(false), UseOddSPReg(true), IsNaN2008bit(false), IsGP64bit(false), HasVFPU(false), HasCnMips(false), HasMips3_32(false), HasMips3_32r2(false), HasMips4_32(false), HasMips4_32r2(false), HasMips5_32r2(false), InMips16Mode(false), @@ -128,11 +128,18 @@ report_fatal_error( "indirect jumps with hazard barriers requires MIPS32R2 or later"); } + if (inAbs2008Mode() && hasMips32() && !hasMips32r2()) { + report_fatal_error("IEEE 754-2008 abs.fmt is not supported for the given " + "architecture.", + false); + } + if (hasMips32r6()) { StringRef ISA = hasMips64r6() ? "MIPS64r6" : "MIPS32r6"; assert(isFP64bit()); assert(isNaN2008()); + assert(inAbs2008Mode()); if (hasDSP()) report_fatal_error(ISA + " is not compatible with the DSP ASE", false); } Index: test/CodeGen/Mips/fabs.ll =================================================================== --- test/CodeGen/Mips/fabs.ll +++ test/CodeGen/Mips/fabs.ll @@ -1,23 +1,84 @@ -; Check that abs.[ds] is selected and does not depend on -enable-no-nans-fp-math -; They obey the Has2008 and ABS2008 configuration bits which govern the -; conformance to IEEE 754 (1985) and IEEE 754 (2008). When these bits are not -; present, they confirm to 1985. +; Check that abs.[ds] is only selected for mips32r6 or mips64r6 when no +; additional options are passed. For revisions prior mips32r6 and mips64r6, +; abs.[ds] does not generate the correct result when working with NaNs, and +; should be explicitly enabled with -enable-no-nans-fp-math or +abs2008 options. + ; In 1985 mode, abs.[ds] are arithmetic (i.e. they raise invalid operation ; exceptions when given NaN's). In 2008 mode, they are non-arithmetic (i.e. ; they are copies and don't raise any exceptions). -; RUN: llc < %s -mtriple=mipsel-linux-gnu -mcpu=mips32 | FileCheck %s -; RUN: llc < %s -mtriple=mipsel-linux-gnu -mcpu=mips32r2 | FileCheck %s -; RUN: llc < %s -mtriple=mipsel-linux-gnu -mcpu=mips32 -enable-no-nans-fp-math | FileCheck %s +; Testing default values +; RUN: llc < %s -mtriple=mipsel-linux-gnu -mcpu=mips32 | FileCheck %s \ +; RUN: -check-prefix=CHECK-ABSLEGACY +; RUN: llc < %s -mtriple=mips64el-linux-gnu -mcpu=mips64 | FileCheck %s \ +; RUN: -check-prefix=CHECK-ABSLEGACY +; RUN: llc < %s -mtriple=mipsel-linux-gnu -mcpu=mips32r2 | FileCheck %s \ +; RUN: -check-prefix=CHECK-ABSLEGACY +; RUN: llc < %s -mtriple=mips64el-linux-gnu -mcpu=mips64r2 | FileCheck %s \ +; RUN: -check-prefix=CHECK-ABSLEGACY +; RUN: llc < %s -mtriple=mipsel-linux-gnu -mcpu=mips32r6 | FileCheck %s \ +; RUN: -check-prefix=CHECK-ABS2008 +; RUN: llc < %s -mtriple=mips64el-linux-gnu -mcpu=mips64r6 | FileCheck %s \ +; RUN: -check-prefix=CHECK-ABS2008 +; RUN: llc < %s -mtriple=mips-linux-gnu -mcpu=mips32 | FileCheck %s \ +; RUN: -check-prefix=CHECK-ABSLEGACY +; RUN: llc < %s -mtriple=mips64-linux-gnu -mcpu=mips64 | FileCheck %s \ +; RUN: -check-prefix=CHECK-ABSLEGACY +; RUN: llc < %s -mtriple=mips-linux-gnu -mcpu=mips32r2 | FileCheck %s \ +; RUN: -check-prefix=CHECK-ABSLEGACY +; RUN: llc < %s -mtriple=mips64-linux-gnu -mcpu=mips64r2 | FileCheck %s \ +; RUN: -check-prefix=CHECK-ABSLEGACY +; RUN: llc < %s -mtriple=mips-linux-gnu -mcpu=mips32r6 | FileCheck %s \ +; RUN: -check-prefix=CHECK-ABS2008 +; RUN: llc < %s -mtriple=mips64-linux-gnu -mcpu=mips64r6 | FileCheck %s \ +; RUN: -check-prefix=CHECK-ABS2008 +; Testing non-default values +; RUN: llc < %s -mtriple=mipsel-linux-gnu -mcpu=mips32r2 -mattr=+abs2008 \ +; RUN: | FileCheck %s -check-prefix=CHECK-ABS2008 +; RUN: llc < %s -mtriple=mips64el-linux-gnu -mcpu=mips64r2 -mattr=+abs2008 \ +; RUN: | FileCheck %s -check-prefix=CHECK-ABS2008 +; RUN: llc < %s -mtriple=mips-linux-gnu -mcpu=mips32r2 -mattr=+abs2008 \ +; RUN: | FileCheck %s -check-prefix=CHECK-ABS2008 +; RUN: llc < %s -mtriple=mips64-linux-gnu -mcpu=mips64r2 -mattr=+abs2008 \ +; RUN: | FileCheck %s -check-prefix=CHECK-ABS2008 +; Testing -enable-no-nans-fp-math +; RUN: llc < %s -mtriple=mipsel-linux-gnu -mcpu=mips32 \ +; RUN: -enable-no-nans-fp-math | FileCheck %s -check-prefix=CHECK-ABS2008 +; RUN: llc < %s -mtriple=mips64el-linux-gnu -mcpu=mips64 \ +; RUN: -enable-no-nans-fp-math | FileCheck %s -check-prefix=CHECK-ABS2008 +; RUN: llc < %s -mtriple=mips-linux-gnu -mcpu=mips32 \ +; RUN: -enable-no-nans-fp-math | FileCheck %s -check-prefix=CHECK-ABS2008 +; RUN: llc < %s -mtriple=mips64-linux-gnu -mcpu=mips64 \ +; RUN: -enable-no-nans-fp-math | FileCheck %s -check-prefix=CHECK-ABS2008 -; RUN: llc < %s -mtriple=mips64el-linux-gnu -mcpu=mips64 | FileCheck %s -; RUN: llc < %s -mtriple=mips64el-linux-gnu -mcpu=mips64 -enable-no-nans-fp-math | FileCheck %s +; microMIPS +; Testing default values +; RUN: llc < %s -mtriple=mipsel-linux-gnu -mcpu=mips32 -mattr=+micromips \ +; RUN: | FileCheck %s -check-prefix=CHECK-ABSLEGACY +; RUN: llc < %s -mtriple=mipsel-linux-gnu -mcpu=mips32r2 -mattr=+micromips \ +; RUN: | FileCheck %s -check-prefix=CHECK-ABSLEGACY +; RUN: llc < %s -mtriple=mips-linux-gnu -mcpu=mips32 -mattr=+micromips \ +; RUN: | FileCheck %s -check-prefix=CHECK-ABSLEGACY +; RUN: llc < %s -mtriple=mips-linux-gnu -mcpu=mips32r2 -mattr=+micromips \ +; RUN: | FileCheck %s -check-prefix=CHECK-ABSLEGACY +; Testing non-default values +; RUN: llc < %s -mtriple=mipsel-linux-gnu -mcpu=mips32r2 \ +; RUN: -mattr=+abs2008,+micromips | FileCheck %s -check-prefix=CHECK-ABS2008 +; RUN: llc < %s -mtriple=mips-linux-gnu -mcpu=mips32r2 \ +; RUN: -mattr=+abs2008,+micromips | FileCheck %s -check-prefix=CHECK-ABS2008 +; Testing -enable-no-nans-fp-math +; RUN: llc < %s -mtriple=mipsel-linux-gnu -mcpu=mips32 -mattr=+micromips \ +; RUN: -enable-no-nans-fp-math | FileCheck %s -check-prefix=CHECK-ABS2008 +; RUN: llc < %s -mtriple=mips-linux-gnu -mcpu=mips32 -mattr=+micromips \ +; RUN: -enable-no-nans-fp-math | FileCheck %s -check-prefix=CHECK-ABS2008 define float @foo0(float %a) nounwind readnone { entry: ; CHECK-LABEL: foo0 -; CHECK: abs.s +; CHECK-ABS2008: abs.s +; CHECK-ABSLEGACY: {{(ori|ins)}} +; CHECK-ABSLEGACY-NOT: abs.s %call = tail call float @fabsf(float %a) nounwind readnone ret float %call @@ -29,7 +90,9 @@ entry: ; CHECK-LABEL: foo1: -; CHECK: abs.d +; CHECK-ABS2008: abs.d +; CHECK-ABSLEGACY: {{(ori|ins|dsll)}} +; CHECK-ABSLEGACY-NOT: abs.d %call = tail call double @fabs(double %a) nounwind readnone ret double %call Index: test/CodeGen/Mips/llvm-ir/abs.ll =================================================================== --- test/CodeGen/Mips/llvm-ir/abs.ll +++ test/CodeGen/Mips/llvm-ir/abs.ll @@ -1,11 +1,12 @@ -; RUN: llc -march=mips -mcpu=mips32 -asm-show-inst < %s | FileCheck %s --check-prefix=MIPS32 -; RUN: llc -march=mips -mcpu=mips32r2 -mattr=+fp64 -asm-show-inst < %s | FileCheck %s --check-prefix=MIPS32FP64 -; RUN: llc -march=mips -mcpu=mips32r3 -mattr=+micromips -asm-show-inst < %s | FileCheck %s --check-prefix=MM -; RUN: llc -march=mips -mcpu=mips32r3 -mattr=+micromips,+fp64 -asm-show-inst < %s | FileCheck %s --check-prefix=MMFP64 -; RUN: llc -march=mips -mcpu=mips32r6 -mattr=+micromips -asm-show-inst < %s | FileCheck %s --check-prefix=MMR6 +; RUN: llc -march=mips -mcpu=mips32 -asm-show-inst < %s | FileCheck %s --check-prefix=MIPS32 +; RUN: llc -march=mips -mcpu=mips32r2 -mattr=+abs2008,+fp64 -asm-show-inst < %s | FileCheck %s --check-prefix=MIPS32FP64 +; RUN: llc -march=mips -mcpu=mips32r3 -mattr=+abs2008,+micromips -asm-show-inst < %s | FileCheck %s --check-prefix=MM +; RUN: llc -march=mips -mcpu=mips32r3 -mattr=+abs2008,+micromips,+fp64 -asm-show-inst < %s | FileCheck %s --check-prefix=MMFP64 +; RUN: llc -march=mips -mcpu=mips32r6 -mattr=+micromips -asm-show-inst < %s | FileCheck %s --check-prefix=MMR6 define float @abs_s(float %a) { -; MIPS32: abs.s {{.*}} #