summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Dardis <simon.dardis@gmail.com>2022-04-29 00:55:31 +0100
committerTom Stellard <tstellar@redhat.com>2022-06-07 18:51:48 -0700
commit198626ad43fd1e5425fcd57c764057b1979431c6 (patch)
treef87a78afe212c83c967611efed82166bc5fbecda
parentb75bf750fdc287821fca697d103053f62a4b1d77 (diff)
downloadllvm-198626ad43fd1e5425fcd57c764057b1979431c6.tar.gz
[MIPS] Address instruction selection failure for abs.[sd]
Previously, the choice between the instruction selection of ISD::FABS was decided at the point of setting the MIPS target lowering operation choice either `Custom` lowering or `Legal`. This lead to instruction selection failures as functions could be marked as having no NaNs. Changing the lowering to always be `Custom` and directly handling the the cases where MIPS selects the instructions for ISD::FABS resolves this crash. Thanks to kray for reporting the issue and to Simon Atanasyan for producing the reduced test case. This resolves PR/53722. Differential Revision: https://reviews.llvm.org/D124651 (cherry picked from commit 938ed8ae99f92c19cfb92b76a7e20a72409df84a)
-rw-r--r--llvm/lib/Target/Mips/MipsISelLowering.cpp22
-rw-r--r--llvm/lib/Target/Mips/MipsISelLowering.h7
-rw-r--r--llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp32
-rw-r--r--llvm/test/CodeGen/Mips/llvm-ir/nan-fp-attr.ll327
4 files changed, 379 insertions, 9 deletions
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index 8534a0ad886e..c2f6f5e13160 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 3905a18895de..66207193c8b3 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 03a545605fe1..ae92604d47ba 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 000000000000..918cda6b38c2
--- /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" }