Index: CodeGen/Mips/fabs.ll =================================================================== --- CodeGen/Mips/fabs.ll +++ CodeGen/Mips/fabs.ll @@ -1,23 +1,37 @@ -; 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. -; 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 - -; 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 +; 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] is not generating correct result when working with NaNs, and +; should be explicitly enabed with -enable-no-nans-fp-math or +abs2008 options. + +; 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=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=mipsel-linux-gnu -mcpu=mips32r2 -mattr=+abs2008 \ +; RUN: | FileCheck %s -check-prefix=CHECK-ABS2008 +; RUN: llc < %s -mtriple=mipsel-linux-gnu -mcpu=mips32r2 -mattr=+abs2008 \ +; RUN: | FileCheck %s -check-prefix=CHECK-ABS2008 +; 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 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 +43,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: CodeGen/Mips/msa/f16-llvm-ir.ll =================================================================== --- CodeGen/Mips/msa/f16-llvm-ir.ll +++ CodeGen/Mips/msa/f16-llvm-ir.ll @@ -1,11 +1,11 @@ ; RUN: llc -relocation-model=pic -march=mipsel -mcpu=mips32r5 \ -; RUN: -mattr=+fp64,+msa -verify-machineinstrs < %s | FileCheck %s \ +; RUN: -mattr=+fp64,+msa,+abs2008 -verify-machineinstrs < %s | FileCheck %s \ ; RUN: --check-prefixes=ALL,MIPS32,MIPSR5,MIPS32-O32,MIPS32R5-O32 ; RUN: llc -relocation-model=pic -march=mips64el -mcpu=mips64r5 \ -; RUN: -mattr=+fp64,+msa -verify-machineinstrs -target-abi n32 < %s | FileCheck %s \ +; RUN: -mattr=+fp64,+msa,+abs2008 -verify-machineinstrs -target-abi n32 < %s | FileCheck %s \ ; RUN: --check-prefixes=ALL,MIPS64,MIPSR5,MIPS64-N32,MIPS64R5-N32 ; RUN: llc -relocation-model=pic -march=mips64el -mcpu=mips64r5 \ -; RUN: -mattr=+fp64,+msa -verify-machineinstrs -target-abi n64 < %s | FileCheck %s \ +; RUN: -mattr=+fp64,+msa,+abs2008 -verify-machineinstrs -target-abi n64 < %s | FileCheck %s \ ; RUN: --check-prefixes=ALL,MIPS64,MIPSR5,MIPS64-N64,MIPS64R5-N64 ; RUN: llc -relocation-model=pic -march=mipsel -mcpu=mips32r6 \ Index: Target/Mips/Mips.td =================================================================== --- Target/Mips/Mips.td +++ Target/Mips/Mips.td @@ -79,6 +79,8 @@ "Support for FPXX">; def FeatureNaN2008 : SubtargetFeature<"nan2008", "IsNaN2008bit", "true", "IEEE 754-2008 NaN encoding">; +def FeatureAbs2008 : SubtargetFeature<"abs2008", "Abs2008", "true", + "IEEE 754-2008 abs mode">; def FeatureSingleFloat : SubtargetFeature<"single-float", "IsSingleFloat", "true", "Only supports single precision float">; def FeatureSoftFloat : SubtargetFeature<"soft-float", "IsSoftFloat", "true", @@ -138,7 +140,7 @@ "Mips32r6", "Mips32r6 ISA Support [experimental]", [FeatureMips32r5, FeatureFP64Bit, - FeatureNaN2008]>; + FeatureNaN2008, FeatureAbs2008]>; def FeatureMips64 : SubtargetFeature<"mips64", "MipsArchVersion", "Mips64", "Mips64 ISA Support", [FeatureMips5, FeatureMips32]>; @@ -155,7 +157,7 @@ "Mips64r6", "Mips64r6 ISA Support [experimental]", [FeatureMips32r6, FeatureMips64r5, - FeatureNaN2008]>; + FeatureNaN2008, FeatureAbs2008]>; def FeatureSym32 : SubtargetFeature<"sym32", "HasSym32", "true", "Symbols are 32 bit on Mips64">; Index: Target/Mips/MipsISelLowering.cpp =================================================================== --- Target/Mips/MipsISelLowering.cpp +++ Target/Mips/MipsISelLowering.cpp @@ -332,6 +332,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); @@ -1234,6 +1239,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); @@ -2366,6 +2372,65 @@ 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 { + 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); + + 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 (Subtarget.hasMips64() && (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: Target/Mips/MipsInstrFPU.td =================================================================== --- Target/Mips/MipsInstrFPU.td +++ Target/Mips/MipsInstrFPU.td @@ -425,11 +425,14 @@ def PseudoCVT_D64_L : ABSS_FT<"", FGR64Opnd, GPR64Opnd, II_CVT>; } -def FABS_S : MMRel, ABSS_FT<"abs.s", FGR32Opnd, FGR32Opnd, II_ABS, fabs>, - ABSS_FM<0x5, 16>; +let AdditionalPredicates = [UseAbs] in { + def FABS_S : MMRel, ABSS_FT<"abs.s", FGR32Opnd, FGR32Opnd, II_ABS, fabs>, + ABSS_FM<0x5, 16>; + defm FABS : ABSS_M<"abs.d", II_ABS, fabs>, ABSS_FM<0x5, 17>; +} + def FNEG_S : MMRel, ABSS_FT<"neg.s", FGR32Opnd, FGR32Opnd, II_NEG, fneg>, ABSS_FM<0x7, 16>; -defm FABS : ABSS_M<"abs.d", II_ABS, fabs>, ABSS_FM<0x5, 17>; defm FNEG : ABSS_M<"neg.d", II_NEG, fneg>, ABSS_FM<0x7, 17>; def FSQRT_S : MMRel, StdMMR6Rel, ABSS_FT<"sqrt.s", FGR32Opnd, FGR32Opnd, Index: Target/Mips/MipsInstrInfo.td =================================================================== --- Target/Mips/MipsInstrInfo.td +++ Target/Mips/MipsInstrInfo.td @@ -223,6 +223,7 @@ 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: Target/Mips/MipsSubtarget.h =================================================================== --- Target/Mips/MipsSubtarget.h +++ Target/Mips/MipsSubtarget.h @@ -78,6 +78,9 @@ // IsNan2008 - IEEE 754-2008 NaN encoding. bool IsNaN2008bit; + // Abs2008 - Use IEEE 754-2008 Abs instruction. + bool Abs2008; + // IsGP64bit - General-purpose registers are 64 bits wide bool IsGP64bit; @@ -234,6 +237,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: Target/Mips/MipsSubtarget.cpp =================================================================== --- Target/Mips/MipsSubtarget.cpp +++ Target/Mips/MipsSubtarget.cpp @@ -64,14 +64,14 @@ : MipsGenSubtargetInfo(TT, CPU, FS), MipsArchVersion(MipsDefault), IsLittle(little), IsSoftFloat(false), IsSingleFloat(false), IsFPXX(false), NoABICalls(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), - InMips16HardFloat(Mips16HardFloat), InMicroMipsMode(false), HasDSP(false), - HasDSPR2(false), HasDSPR3(false), AllowMixed16_32(Mixed16_32 | Mips_Os16), - Os16(Mips_Os16), HasMSA(false), UseTCCInDIV(false), HasSym32(false), - HasEVA(false), DisableMadd4(false), HasMT(false), TM(TM), - TargetTriple(TT), TSInfo(), + IsNaN2008bit(false), Abs2008(false), IsGP64bit(false), HasVFPU(false), + HasCnMips(false), HasMips3_32(false), HasMips3_32r2(false), + HasMips4_32(false), HasMips4_32r2(false), HasMips5_32r2(false), + InMips16Mode(false), InMips16HardFloat(Mips16HardFloat), + InMicroMipsMode(false), HasDSP(false), HasDSPR2(false), HasDSPR3(false), + AllowMixed16_32(Mixed16_32 | Mips_Os16), Os16(Mips_Os16), HasMSA(false), + UseTCCInDIV(false), HasSym32(false), HasEVA(false), DisableMadd4(false), + HasMT(false), TM(TM), TargetTriple(TT), TSInfo(), InstrInfo( MipsInstrInfo::create(initializeSubtargetDependencies(CPU, FS, TM))), FrameLowering(MipsFrameLowering::create(*this)), @@ -103,11 +103,18 @@ if (IsFPXX && (isABI_N32() || isABI_N64())) report_fatal_error("FPXX is not permitted for the N32/N64 ABI's.", false); + if (inAbs2008Mode()) { + if (hasMips32() && !hasMips32r2()) { + report_fatal_error("IEEE 754-2008 Abs 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); }