diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index e71bc78a611..42a35ad1b5a 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -128,8 +128,8 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand); setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand); - setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand); - setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand); + setOperationAction(ISD::FCOPYSIGN, MVT::f32, Custom); + setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom); setOperationAction(ISD::FSIN, MVT::f32, Expand); setOperationAction(ISD::FSIN, MVT::f64, Expand); setOperationAction(ISD::FCOS, MVT::f32, Expand); @@ -515,6 +515,7 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const case ISD::JumpTable: return LowerJumpTable(Op, DAG); case ISD::SELECT: return LowerSELECT(Op, DAG); case ISD::VASTART: return LowerVASTART(Op, DAG); + case ISD::FCOPYSIGN: return LowerFCOPYSIGN(Op, DAG); } return SDValue(); } @@ -943,6 +944,60 @@ SDValue MipsTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const { false, false, 0); } +static SDValue LowerFCOPYSIGN32(SDValue Op, SelectionDAG &DAG) { + // FIXME: Use ext/ins instructions if target architecture is Mips32r2. + DebugLoc dl = Op.getDebugLoc(); + SDValue Op0 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op.getOperand(0)); + SDValue Op1 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op.getOperand(1)); + SDValue And0 = DAG.getNode(ISD::AND, dl, MVT::i32, Op0, + DAG.getConstant(0x7fffffff, MVT::i32)); + SDValue And1 = DAG.getNode(ISD::AND, dl, MVT::i32, Op1, + DAG.getConstant(0x80000000, MVT::i32)); + SDValue Result = DAG.getNode(ISD::OR, dl, MVT::i32, And0, And1); + return DAG.getNode(ISD::BITCAST, dl, MVT::f32, Result); +} + +static SDValue LowerFCOPYSIGN64(SDValue Op, SelectionDAG &DAG, bool isLittle) { + // FIXME: + // Use ext/ins instructions if target architecture is Mips32r2. + // Eliminate redundant mfc1 and mtc1 instructions. + unsigned LoIdx = 0, HiIdx = 1; + + if (!isLittle) + std::swap(LoIdx, HiIdx); + + DebugLoc dl = Op.getDebugLoc(); + SDValue Word0 = DAG.getNode(MipsISD::ExtractElementF64, dl, MVT::i32, + Op.getOperand(0), + DAG.getConstant(LoIdx, MVT::i32)); + SDValue Hi0 = DAG.getNode(MipsISD::ExtractElementF64, dl, MVT::i32, + Op.getOperand(0), DAG.getConstant(HiIdx, MVT::i32)); + SDValue Hi1 = DAG.getNode(MipsISD::ExtractElementF64, dl, MVT::i32, + Op.getOperand(1), DAG.getConstant(HiIdx, MVT::i32)); + SDValue And0 = DAG.getNode(ISD::AND, dl, MVT::i32, Hi0, + DAG.getConstant(0x7fffffff, MVT::i32)); + SDValue And1 = DAG.getNode(ISD::AND, dl, MVT::i32, Hi1, + DAG.getConstant(0x80000000, MVT::i32)); + SDValue Word1 = DAG.getNode(ISD::OR, dl, MVT::i32, And0, And1); + + if (!isLittle) + std::swap(Word0, Word1); + + return DAG.getNode(MipsISD::BuildPairF64, dl, MVT::f64, Word0, Word1); +} + +SDValue MipsTargetLowering::LowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) + const { + EVT Ty = Op.getValueType(); + + assert(Ty == MVT::f32 || Ty == MVT::f64); + + if (Ty == MVT::f32) + return LowerFCOPYSIGN32(Op, DAG); + else + return LowerFCOPYSIGN64(Op, DAG, Subtarget->isLittle()); +} + //===----------------------------------------------------------------------===// // Calling Convention Implementation //===----------------------------------------------------------------------===// diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h index 1cb966572fd..010451f3867 100644 --- a/lib/Target/Mips/MipsISelLowering.h +++ b/lib/Target/Mips/MipsISelLowering.h @@ -113,6 +113,7 @@ namespace llvm { SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSELECT(SDValue Op, SelectionDAG &DAG) const; SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const; virtual SDValue LowerFormalArguments(SDValue Chain, diff --git a/test/CodeGen/Mips/2008-07-31-fcopysign.ll b/test/CodeGen/Mips/2008-07-31-fcopysign.ll index 47382f989ca..f152acc9a15 100644 --- a/test/CodeGen/Mips/2008-07-31-fcopysign.ll +++ b/test/CodeGen/Mips/2008-07-31-fcopysign.ll @@ -2,6 +2,10 @@ ; RUN: grep abs.s %t | count 1 ; RUN: grep neg.s %t | count 1 +; FIXME: Should not emit abs.s or neg.s since these instructions produce +; incorrect results if the operand is NaN. +; REQUIRES: disabled + target datalayout = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64" target triple = "mipsallegrexel-unknown-psp-elf" diff --git a/test/CodeGen/Mips/fcopysign.ll b/test/CodeGen/Mips/fcopysign.ll new file mode 100644 index 00000000000..14c6507cc95 --- /dev/null +++ b/test/CodeGen/Mips/fcopysign.ll @@ -0,0 +1,55 @@ +; RUN: llc < %s -march=mipsel -mcpu=4ke | FileCheck %s -check-prefix=CHECK-EL +; RUN: llc < %s -march=mips -mcpu=4ke | FileCheck %s -check-prefix=CHECK-EB + +define double @func0(double %d0, double %d1) nounwind readnone { +entry: +; CHECK-EL: func0: +; CHECK-EL: lui $[[T0:[0-9]+]], 32767 +; CHECK-EL: lui $[[T1:[0-9]+]], 32768 +; CHECK-EL: mfc1 $[[HI0:[0-9]+]], $f13 +; CHECK-EL: ori $[[MSK0:[0-9]+]], $[[T0]], 65535 +; CHECK-EL: mfc1 $[[HI1:[0-9]+]], $f15 +; CHECK-EL: ori $[[MSK1:[0-9]+]], $[[T1]], 0 +; CHECK-EL: and $[[AND0:[0-9]+]], $[[HI0]], $[[MSK0]] +; CHECK-EL: and $[[AND1:[0-9]+]], $[[HI1]], $[[MSK1]] +; CHECK-EL: mfc1 $[[LO0:[0-9]+]], $f12 +; CHECK-EL: or $[[OR:[0-9]+]], $[[AND0]], $[[AND1]] +; CHECK-EL: mtc1 $[[LO0]], $f0 +; CHECK-EL: mtc1 $[[OR]], $f1 +; +; CHECK-EB: lui $[[T0:[0-9]+]], 32767 +; CHECK-EB: lui $[[T1:[0-9]+]], 32768 +; CHECK-EB: mfc1 $[[HI0:[0-9]+]], $f12 +; CHECK-EB: ori $[[MSK0:[0-9]+]], $[[T0]], 65535 +; CHECK-EB: mfc1 $[[HI1:[0-9]+]], $f14 +; CHECK-EB: ori $[[MSK1:[0-9]+]], $[[T1]], 0 +; CHECK-EB: and $[[AND0:[0-9]+]], $[[HI0]], $[[MSK0]] +; CHECK-EB: and $[[AND1:[0-9]+]], $[[HI1]], $[[MSK1]] +; CHECK-EB: or $[[OR:[0-9]+]], $[[AND0]], $[[AND1]] +; CHECK-EB: mfc1 $[[LO0:[0-9]+]], $f13 +; CHECK-EB: mtc1 $[[OR]], $f0 +; CHECK-EB: mtc1 $[[LO0]], $f1 + %call = tail call double @copysign(double %d0, double %d1) nounwind readnone + ret double %call +} + +declare double @copysign(double, double) nounwind readnone + +define float @func1(float %f0, float %f1) nounwind readnone { +entry: +; CHECK-EL: func1: +; CHECK-EL: lui $[[T0:[0-9]+]], 32767 +; CHECK-EL: lui $[[T1:[0-9]+]], 32768 +; CHECK-EL: mfc1 $[[ARG0:[0-9]+]], $f12 +; CHECK-EL: ori $[[MSK0:[0-9]+]], $[[T0]], 65535 +; CHECK-EL: mfc1 $[[ARG1:[0-9]+]], $f14 +; CHECK-EL: ori $[[MSK1:[0-9]+]], $[[T1]], 0 +; CHECK-EL: and $[[T2:[0-9]+]], $[[ARG0]], $[[MSK0]] +; CHECK-EL: and $[[T3:[0-9]+]], $[[ARG1]], $[[MSK1]] +; CHECK-EL: or $[[T4:[0-9]+]], $[[T2]], $[[T3]] +; CHECK-EL: mtc1 $[[T4]], $f0 + %call = tail call float @copysignf(float %f0, float %f1) nounwind readnone + ret float %call +} + +declare float @copysignf(float, float) nounwind readnone