Index: lib/CodeGen/SelectionDAG/LegalizeDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -3945,11 +3945,31 @@ RTLIB::ROUND_PPCF128)); break; case ISD::FPOWI: - case ISD::STRICT_FPOWI: + case ISD::STRICT_FPOWI: { + RTLIB::Libcall LC; + switch (Node->getSimpleValueType(0).SimpleTy) { + default: llvm_unreachable("Unexpected request for libcall!"); + case MVT::f32: LC = RTLIB::POWI_F32; break; + case MVT::f64: LC = RTLIB::POWI_F64; break; + case MVT::f80: LC = RTLIB::POWI_F80; break; + case MVT::f128: LC = RTLIB::POWI_F128; break; + case MVT::ppcf128: LC = RTLIB::POWI_PPCF128; break; + } + if (!TLI.getLibcallName(LC)) { + // Some targets don't have a powi libcall; use pow instead. + SDValue Exponent = DAG.getNode(ISD::SINT_TO_FP, SDLoc(Node), + Node->getValueType(0), + Node->getOperand(1)); + Results.push_back(DAG.getNode(ISD::FPOW, SDLoc(Node), + Node->getValueType(0), Node->getOperand(0), + Exponent)); + break; + } Results.push_back(ExpandFPLibCall(Node, RTLIB::POWI_F32, RTLIB::POWI_F64, RTLIB::POWI_F80, RTLIB::POWI_F128, RTLIB::POWI_PPCF128)); break; + } case ISD::FPOW: case ISD::STRICT_FPOW: if (CanUseFiniteLibCall && DAG.getLibInfo().has(LibFunc_pow_finite)) Index: lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp @@ -571,19 +571,24 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FPOWI(SDNode *N) { assert(N->getOperand(1).getValueType() == MVT::i32 && "Unsupported power type!"); + RTLIB::Libcall LC = GetFPLibCall(N->getValueType(0), + RTLIB::POWI_F32, + RTLIB::POWI_F64, + RTLIB::POWI_F80, + RTLIB::POWI_F128, + RTLIB::POWI_PPCF128); + if (!TLI.getLibcallName(LC)) { + // Some targets don't have a powi libcall; use pow instead. + report_fatal_error("Don't know how to soften fpowi to fpow"); + } + EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue Ops[2] = { GetSoftenedFloat(N->getOperand(0)), N->getOperand(1) }; TargetLowering::MakeLibCallOptions CallOptions; EVT OpsVT[2] = { N->getOperand(0).getValueType(), N->getOperand(1).getValueType() }; CallOptions.setTypeListBeforeSoften(OpsVT, N->getValueType(0), true); - return TLI.makeLibCall(DAG, GetFPLibCall(N->getValueType(0), - RTLIB::POWI_F32, - RTLIB::POWI_F64, - RTLIB::POWI_F80, - RTLIB::POWI_F128, - RTLIB::POWI_PPCF128), - NVT, Ops, CallOptions, SDLoc(N)).first; + return TLI.makeLibCall(DAG, LC, NVT, Ops, CallOptions, SDLoc(N)).first; } SDValue DAGTypeLegalizer::SoftenFloatRes_FREM(SDNode *N) { Index: lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.cpp +++ lib/Target/AArch64/AArch64ISelLowering.cpp @@ -525,6 +525,12 @@ setOperationAction(ISD::FSINCOS, MVT::f32, Expand); } + if (Subtarget->getTargetTriple().isOSMSVCRT()) { + // MSVCRT doesn't have powi; fall back to pow + setLibcallName(RTLIB::POWI_F32, nullptr); + setLibcallName(RTLIB::POWI_F64, nullptr); + } + // Make floating-point constants legal for the large code model, so they don't // become loads from the constant pool. if (Subtarget->isTargetMachO() && TM.getCodeModel() == CodeModel::Large) { Index: lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- lib/Target/ARM/ARMISelLowering.cpp +++ lib/Target/ARM/ARMISelLowering.cpp @@ -1160,9 +1160,11 @@ setOperationAction(ISD::UDIVREM, MVT::i32, Expand); } - if (Subtarget->isTargetWindows() && Subtarget->getTargetTriple().isOSMSVCRT()) - for (auto &VT : {MVT::f32, MVT::f64}) - setOperationAction(ISD::FPOWI, VT, Custom); + if (Subtarget->getTargetTriple().isOSMSVCRT()) { + // MSVCRT doesn't have powi; fall back to pow + setLibcallName(RTLIB::POWI_F32, nullptr); + setLibcallName(RTLIB::POWI_F64, nullptr); + } setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); setOperationAction(ISD::ConstantPool, MVT::i32, Custom); @@ -8959,58 +8961,6 @@ Results.push_back(SDValue(CmpSwap, 2)); } -static SDValue LowerFPOWI(SDValue Op, const ARMSubtarget &Subtarget, - SelectionDAG &DAG) { - const auto &TLI = DAG.getTargetLoweringInfo(); - - assert(Subtarget.getTargetTriple().isOSMSVCRT() && - "Custom lowering is MSVCRT specific!"); - - SDLoc dl(Op); - SDValue Val = Op.getOperand(0); - MVT Ty = Val->getSimpleValueType(0); - SDValue Exponent = DAG.getNode(ISD::SINT_TO_FP, dl, Ty, Op.getOperand(1)); - SDValue Callee = DAG.getExternalSymbol(Ty == MVT::f32 ? "powf" : "pow", - TLI.getPointerTy(DAG.getDataLayout())); - - TargetLowering::ArgListTy Args; - TargetLowering::ArgListEntry Entry; - - Entry.Node = Val; - Entry.Ty = Val.getValueType().getTypeForEVT(*DAG.getContext()); - Entry.IsZExt = true; - Args.push_back(Entry); - - Entry.Node = Exponent; - Entry.Ty = Exponent.getValueType().getTypeForEVT(*DAG.getContext()); - Entry.IsZExt = true; - Args.push_back(Entry); - - Type *LCRTy = Val.getValueType().getTypeForEVT(*DAG.getContext()); - - // In the in-chain to the call is the entry node If we are emitting a - // tailcall, the chain will be mutated if the node has a non-entry input - // chain. - SDValue InChain = DAG.getEntryNode(); - SDValue TCChain = InChain; - - const Function &F = DAG.getMachineFunction().getFunction(); - bool IsTC = TLI.isInTailCallPosition(DAG, Op.getNode(), TCChain) && - F.getReturnType() == LCRTy; - if (IsTC) - InChain = TCChain; - - TargetLowering::CallLoweringInfo CLI(DAG); - CLI.setDebugLoc(dl) - .setChain(InChain) - .setCallee(CallingConv::ARM_AAPCS_VFP, LCRTy, Callee, std::move(Args)) - .setTailCall(IsTC); - std::pair CI = TLI.LowerCallTo(CLI); - - // Return the chain (the DAG root) if it is a tail call - return !CI.second.getNode() ? DAG.getRoot() : CI.first; -} - SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { LLVM_DEBUG(dbgs() << "Lowering node: "; Op.dump()); switch (Op.getOpcode()) { @@ -9097,7 +9047,6 @@ llvm_unreachable("Don't know how to custom lower this!"); case ISD::FP_ROUND: return LowerFP_ROUND(Op, DAG); case ISD::FP_EXTEND: return LowerFP_EXTEND(Op, DAG); - case ISD::FPOWI: return LowerFPOWI(Op, *Subtarget, DAG); case ARMISD::WIN__DBZCHK: return SDValue(); } } Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -154,6 +154,12 @@ setLibcallCallingConv(RTLIB::MUL_I64, CallingConv::X86_StdCall); } + if (Subtarget.getTargetTriple().isOSMSVCRT()) { + // MSVCRT doesn't have powi; fall back to pow + setLibcallName(RTLIB::POWI_F32, nullptr); + setLibcallName(RTLIB::POWI_F64, nullptr); + } + if (Subtarget.isTargetDarwin()) { // Darwin should use _setjmp/_longjmp instead of setjmp/longjmp. setUseUnderscoreSetJmp(false); Index: test/CodeGen/AArch64/powi-windows.ll =================================================================== --- /dev/null +++ test/CodeGen/AArch64/powi-windows.ll @@ -0,0 +1,46 @@ +; RUN: llc -mtriple aarch64-windows < %s | FileCheck %s + +declare double @llvm.powi.f64(double, i32) +declare float @llvm.powi.f32(float, i32) + +define double @d(double %d, i32 %i) { +entry: + %0 = tail call double @llvm.powi.f64(double %d, i32 %i) + ret double %0 +} + +; CHECK-LABEL: d: +; CHECK: scvtf d1, w0 +; CHECK-NEXT: b pow + +define float @f(float %f, i32 %i) { +entry: + %0 = tail call float @llvm.powi.f32(float %f, i32 %i) + ret float %0 +} + +; CHECK-LABEL: f: +; CHECK: scvtf s1, w0 +; CHECK-NEXT: b powf + +define float @g(double %d, i32 %i) { +entry: + %0 = tail call double @llvm.powi.f64(double %d, i32 %i) + %conv = fptrunc double %0 to float + ret float %conv +} + +; CHECK-LABEL: g: +; CHECK: scvtf d1, w0 +; CHECK-NEXT: bl pow + +define double @h(float %f, i32 %i) { +entry: + %0 = tail call float @llvm.powi.f32(float %f, i32 %i) + %conv = fpext float %0 to double + ret double %conv +} + +; CHECK-LABEL: h: +; CHECK: scvtf s1, w0 +; CHECK-NEXT: bl powf Index: test/CodeGen/X86/powi-windows.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/powi-windows.ll @@ -0,0 +1,46 @@ +; RUN: llc -mtriple x86_64-windows < %s | FileCheck %s + +declare double @llvm.powi.f64(double, i32) +declare float @llvm.powi.f32(float, i32) + +define double @d(double %d, i32 %i) { +entry: + %0 = tail call double @llvm.powi.f64(double %d, i32 %i) + ret double %0 +} + +; CHECK-LABEL: d: +; CHECK: cvtsi2sd %edx, %xmm1 +; CHECK-NEXT: jmp pow + +define float @f(float %f, i32 %i) { +entry: + %0 = tail call float @llvm.powi.f32(float %f, i32 %i) + ret float %0 +} + +; CHECK-LABEL: f: +; CHECK: cvtsi2ss %edx, %xmm1 +; CHECK-NEXT: jmp powf + +define float @g(double %d, i32 %i) { +entry: + %0 = tail call double @llvm.powi.f64(double %d, i32 %i) + %conv = fptrunc double %0 to float + ret float %conv +} + +; CHECK-LABEL: g: +; CHECK: cvtsi2sd %edx, %xmm1 +; CHECK-NEXT: callq pow + +define double @h(float %f, i32 %i) { +entry: + %0 = tail call float @llvm.powi.f32(float %f, i32 %i) + %conv = fpext float %0 to double + ret double %conv +} + +; CHECK-LABEL: h: +; CHECK: cvtsi2ss %edx, %xmm1 +; CHECK-NEXT: callq powf