diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index dd8a4f3851e9..5c3787e35f29 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -1775,7 +1775,48 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) { break; } break; - + + case ISD::FCOPYSIGN: // FCOPYSIGN does not require LHS/RHS to match type! + Tmp1 = LegalizeOp(Node->getOperand(0)); // LHS + switch (getTypeAction(Node->getOperand(1).getValueType())) { + case Expand: assert(0 && "Not possible"); + case Legal: + Tmp2 = LegalizeOp(Node->getOperand(1)); // Legalize the RHS. + break; + case Promote: + Tmp2 = PromoteOp(Node->getOperand(1)); // Promote the RHS. + break; + } + + Result = DAG.UpdateNodeOperands(Result, Tmp1, Tmp2); + + switch (TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0))) { + default: assert(0 && "Operation not supported"); + case TargetLowering::Custom: + Tmp1 = TLI.LowerOperation(Result, DAG); + if (Tmp1.Val) Result = Tmp1; + break; + case TargetLowering::Legal: break; + case TargetLowering::Expand: + // Floating point mod -> fmod libcall. + const char *FnName; + if (Node->getValueType(0) == MVT::f32) { + FnName = "copysignf"; + if (Tmp2.getValueType() != MVT::f32) // Force operands to match type. + Result = DAG.UpdateNodeOperands(Result, Tmp1, + DAG.getNode(ISD::FP_ROUND, MVT::f32, Tmp2)); + } else { + FnName = "copysign"; + if (Tmp2.getValueType() != MVT::f64) // Force operands to match type. + Result = DAG.UpdateNodeOperands(Result, Tmp1, + DAG.getNode(ISD::FP_EXTEND, MVT::f64, Tmp2)); + } + SDOperand Dummy; + Result = ExpandLibCall(FnName, Node, Dummy); + break; + } + break; + case ISD::ADDC: case ISD::SUBC: Tmp1 = LegalizeOp(Node->getOperand(0)); @@ -2604,13 +2645,14 @@ SDOperand SelectionDAGLegalize::PromoteOp(SDOperand Op) { break; case ISD::FDIV: case ISD::FREM: + case ISD::FCOPYSIGN: // These operators require that their input be fp extended. Tmp1 = PromoteOp(Node->getOperand(0)); Tmp2 = PromoteOp(Node->getOperand(1)); Result = DAG.getNode(Node->getOpcode(), NVT, Tmp1, Tmp2); // Perform FP_ROUND: this is probably overly pessimistic. - if (NoExcessFPPrecision) + if (NoExcessFPPrecision && Node->getOpcode() != ISD::FCOPYSIGN) Result = DAG.getNode(ISD::FP_ROUND_INREG, NVT, Result, DAG.getValueType(VT)); break; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 7312d66dd6be..534015ccf930 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -1152,7 +1152,12 @@ SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT, assert(N1.getValueType() == N2.getValueType() && N1.getValueType() == VT && "Binary operator types must match!"); break; - + case ISD::FCOPYSIGN: // N1 and result must match. N1/N2 need not match. + assert(N1.getValueType() == VT && + MVT::isFloatingPoint(N1.getValueType()) && + MVT::isFloatingPoint(N2.getValueType()) && + "Invalid FCOPYSIGN!"); + break; case ISD::SHL: case ISD::SRA: case ISD::SRL: @@ -2635,6 +2640,7 @@ const char *SDNode::getOperationName(const SelectionDAG *G) const { case ISD::FMUL: return "fmul"; case ISD::FDIV: return "fdiv"; case ISD::FREM: return "frem"; + case ISD::FCOPYSIGN: return "fcopysign"; case ISD::VADD: return "vadd"; case ISD::VSUB: return "vsub"; case ISD::VMUL: return "vmul"; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 3069465800cb..f011281fa971 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -1120,7 +1120,18 @@ void SelectionDAGLowering::visitCall(CallInst &I) { return; } else { // Not an LLVM intrinsic. const std::string &Name = F->getName(); - if (Name[0] == 'f' && (Name == "fabs" || Name == "fabsf")) { + if (Name[0] == 'c' && (Name == "copysign" || Name == "copysignf")) { + if (I.getNumOperands() == 3 && // Basic sanity checks. + I.getOperand(1)->getType()->isFloatingPoint() && + I.getType() == I.getOperand(1)->getType() && + I.getType() == I.getOperand(2)->getType()) { + SDOperand LHS = getValue(I.getOperand(1)); + SDOperand RHS = getValue(I.getOperand(2)); + setValue(&I, DAG.getNode(ISD::FCOPYSIGN, LHS.getValueType(), + LHS, RHS)); + return; + } + } else if (Name[0] == 'f' && (Name == "fabs" || Name == "fabsf")) { if (I.getNumOperands() == 2 && // Basic sanity checks. I.getOperand(1)->getType()->isFloatingPoint() && I.getType() == I.getOperand(1)->getType()) {