From bfc9e35df0dcc5b724281d62b808b7b22eb15204 Mon Sep 17 00:00:00 2001 From: Alexey Bader Date: Fri, 14 Aug 2026 15:23:56 -0700 Subject: [PATCH] [FPBuiltinFnSelection] Fold fdiv-by-exact-reciprocal-constant to fmul llvm.fpbuiltin.fdiv hides the division from InstCombine's foldFDivConstantDivisor until this pass lowers it to a real fdiv late in the pipeline, so InstCombine never gets a second look. Replicate the exact-reciprocal case of that fold here so X / C becomes X * (1/C) whenever C has an exact FP inverse. --- .../Scalar/FPBuiltinFnSelection.cpp | 19 +++++++++-- .../fp-builtin-intrinsics-fdiv-const.ll | 34 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 llvm/test/Transforms/FPBuiltinFnSelection/Generic/fp-builtin-intrinsics-fdiv-const.ll diff --git a/llvm/lib/Transforms/Scalar/FPBuiltinFnSelection.cpp b/llvm/lib/Transforms/Scalar/FPBuiltinFnSelection.cpp index 123c2b2aafa4f..00cb4d2762e0d 100644 --- a/llvm/lib/Transforms/Scalar/FPBuiltinFnSelection.cpp +++ b/llvm/lib/Transforms/Scalar/FPBuiltinFnSelection.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Scalar/FPBuiltinFnSelection.h" +#include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/CodeGen/Passes.h" @@ -20,10 +21,12 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/IntrinsicsNVPTX.h" #include "llvm/IR/MDBuilder.h" +#include "llvm/IR/PatternMatch.h" #include "llvm/InitializePasses.h" #include "llvm/Support/FormatVariadic.h" using namespace llvm; +using namespace llvm::PatternMatch; #define DEBUG_TYPE "fpbuiltin-fn-selection" @@ -85,9 +88,21 @@ static bool replaceWithLLVMIR(FPBuiltinIntrinsic &BuiltinCall) { case Intrinsic::fpbuiltin_fmul: Replacement = IRBuilder.CreateFMul(Args[0], Args[1]); break; - case Intrinsic::fpbuiltin_fdiv: - Replacement = IRBuilder.CreateFDiv(Args[0], Args[1]); + case Intrinsic::fpbuiltin_fdiv: { + // X / C --> X * (1 / C) when C has an exact FP reciprocal. InstCombine + // already does this for plain fdiv, but by the time this pass lowers + // llvm.fpbuiltin.fdiv to a real fdiv, InstCombine has already run and + // won't see it again, so the fold is replicated here. + Constant *C; + Constant *RecipC = nullptr; + if (match(Args[1], m_Constant(C)) && C->hasExactInverseFP()) + RecipC = ConstantFoldBinaryOpOperands( + Instruction::FDiv, ConstantFP::get(BuiltinCall.getType(), 1.0), C, + BuiltinCall.getModule()->getDataLayout()); + Replacement = RecipC ? IRBuilder.CreateFMul(Args[0], RecipC) + : IRBuilder.CreateFDiv(Args[0], Args[1]); break; + } case Intrinsic::fpbuiltin_frem: Replacement = IRBuilder.CreateFRem(Args[0], Args[1]); break; diff --git a/llvm/test/Transforms/FPBuiltinFnSelection/Generic/fp-builtin-intrinsics-fdiv-const.ll b/llvm/test/Transforms/FPBuiltinFnSelection/Generic/fp-builtin-intrinsics-fdiv-const.ll new file mode 100644 index 0000000000000..7d507b811f8a2 --- /dev/null +++ b/llvm/test/Transforms/FPBuiltinFnSelection/Generic/fp-builtin-intrinsics-fdiv-const.ll @@ -0,0 +1,34 @@ +; RUN: opt -fpbuiltin-fn-selection -S < %s | FileCheck %s + +; llvm.fpbuiltin.fdiv by a constant divisor with an exact FP reciprocal +; should lower to a multiply by the reciprocal, matching what InstCombine +; would do for a plain fdiv (see CMPLRLLVM-77622). + +; CHECK-LABEL: @test_fdiv_exact_reciprocal +; CHECK: %{{.*}} = fmul float %x, 2.500000e-01 +; CHECK-NOT: fdiv +define float @test_fdiv_exact_reciprocal(float %x) { +entry: + %r = call float @llvm.fpbuiltin.fdiv.f32(float %x, float 4.0) #0 + ret float %r +} + +; CHECK-LABEL: @test_fdiv_inexact_reciprocal +; CHECK: %{{.*}} = fdiv float %x, 3.000000e+00 +define float @test_fdiv_inexact_reciprocal(float %x) { +entry: + %r = call float @llvm.fpbuiltin.fdiv.f32(float %x, float 3.0) #0 + ret float %r +} + +; CHECK-LABEL: @test_fdiv_nonconstant_divisor +; CHECK: %{{.*}} = fdiv float %x, %y +define float @test_fdiv_nonconstant_divisor(float %x, float %y) { +entry: + %r = call float @llvm.fpbuiltin.fdiv.f32(float %x, float %y) #0 + ret float %r +} + +declare float @llvm.fpbuiltin.fdiv.f32(float, float) + +attributes #0 = { "fpbuiltin-max-error"="2.5" }