[llvm] 57e7cee - [IRBuilder] Add FMFSource overloads for CreateCall (#208171)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 8 18:23:07 PDT 2026


Author: Kito Cheng
Date: 2026-07-09T09:23:03+08:00
New Revision: 57e7ceed3398ed1ddf28afdf78ba81cc2638c665

URL: https://github.com/llvm/llvm-project/commit/57e7ceed3398ed1ddf28afdf78ba81cc2638c665
DIFF: https://github.com/llvm/llvm-project/commit/57e7ceed3398ed1ddf28afdf78ba81cc2638c665.diff

LOG: [IRBuilder] Add FMFSource overloads for CreateCall (#208171)

CreateCall had no way to set fast-math-flags at creation time, so
callers had to build the call and copy the flags in a second step:

  CallInst *C = B.CreateCall(Fn, Args);
  C->copyFastMathFlags(Src);

Add FMFSource overloads (mirroring CreateIntrinsic) so the flags can be
copied from a source instruction or FastMathFlags in one call:

  CallInst *C = B.CreateCall(Fn, Args, /*FMFSource=*/Src);

The FMFSource parameter has no default, so existing CreateCall callers
are unaffected and overload resolution stays unambiguous.

Assisted-by: Opus 4.8

Added: 
    

Modified: 
    llvm/include/llvm/IR/IRBuilder.h
    llvm/lib/CodeGen/ReplaceWithVeclib.cpp
    llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
    llvm/unittests/Analysis/ValueTrackingTest.cpp
    llvm/unittests/IR/IRBuilderTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index c935bf16e71b2..f2621bbe298df 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -2562,6 +2562,13 @@ class IRBuilderBase {
     return Insert(CI, Name);
   }
 
+  CallInst *CreateCall(FunctionType *FTy, Value *Callee, ArrayRef<Value *> Args,
+                       FMFSource FMFSource, const Twine &Name = "",
+                       MDNode *FPMathTag = nullptr) {
+    return CreateCall(FTy, Callee, Args, DefaultOperandBundles, FMFSource, Name,
+                      FPMathTag);
+  }
+
   CallInst *CreateCall(FunctionType *FTy, Value *Callee, ArrayRef<Value *> Args,
                        ArrayRef<OperandBundleDef> OpBundles,
                        const Twine &Name = "", MDNode *FPMathTag = nullptr) {
@@ -2573,12 +2580,31 @@ class IRBuilderBase {
     return Insert(CI, Name);
   }
 
+  CallInst *CreateCall(FunctionType *FTy, Value *Callee, ArrayRef<Value *> Args,
+                       ArrayRef<OperandBundleDef> OpBundles,
+                       FMFSource FMFSource, const Twine &Name = "",
+                       MDNode *FPMathTag = nullptr) {
+    CallInst *CI = CallInst::Create(FTy, Callee, Args, OpBundles);
+    if (IsFPConstrained)
+      setConstrainedFPCallAttr(CI);
+    if (isa<FPMathOperator>(CI))
+      setFPAttrs(CI, FPMathTag, FMFSource.get(FMF));
+    return Insert(CI, Name);
+  }
+
   CallInst *CreateCall(FunctionCallee Callee, ArrayRef<Value *> Args = {},
                        const Twine &Name = "", MDNode *FPMathTag = nullptr) {
     return CreateCall(Callee.getFunctionType(), Callee.getCallee(), Args, Name,
                       FPMathTag);
   }
 
+  CallInst *CreateCall(FunctionCallee Callee, ArrayRef<Value *> Args,
+                       FMFSource FMFSource, const Twine &Name = "",
+                       MDNode *FPMathTag = nullptr) {
+    return CreateCall(Callee.getFunctionType(), Callee.getCallee(), Args,
+                      FMFSource, Name, FPMathTag);
+  }
+
   CallInst *CreateCall(FunctionCallee Callee, ArrayRef<Value *> Args,
                        ArrayRef<OperandBundleDef> OpBundles,
                        const Twine &Name = "", MDNode *FPMathTag = nullptr) {
@@ -2586,6 +2612,14 @@ class IRBuilderBase {
                       OpBundles, Name, FPMathTag);
   }
 
+  CallInst *CreateCall(FunctionCallee Callee, ArrayRef<Value *> Args,
+                       ArrayRef<OperandBundleDef> OpBundles,
+                       FMFSource FMFSource, const Twine &Name = "",
+                       MDNode *FPMathTag = nullptr) {
+    return CreateCall(Callee.getFunctionType(), Callee.getCallee(), Args,
+                      OpBundles, FMFSource, Name, FPMathTag);
+  }
+
   LLVM_ABI CallInst *CreateConstrainedFPCall(
       Function *Callee, ArrayRef<Value *> Args, const Twine &Name = "",
       std::optional<RoundingMode> Rounding = std::nullopt,

diff  --git a/llvm/lib/CodeGen/ReplaceWithVeclib.cpp b/llvm/lib/CodeGen/ReplaceWithVeclib.cpp
index 587bed5f9bc00..600b8d84e3926 100644
--- a/llvm/lib/CodeGen/ReplaceWithVeclib.cpp
+++ b/llvm/lib/CodeGen/ReplaceWithVeclib.cpp
@@ -90,11 +90,11 @@ static void replaceWithTLIFunction(IntrinsicInst *II, VFInfo &Info,
   SmallVector<OperandBundleDef, 1> OpBundles;
   II->getOperandBundlesAsDefs(OpBundles);
 
-  auto *Replacement = IRBuilder.CreateCall(TLIVecFunc, Args, OpBundles);
+  // Preserve fast math flags for FP math (getFastMathFlagsOrNone keeps this
+  // safe for non-FP intrinsics, whose flags are simply empty).
+  auto *Replacement = IRBuilder.CreateCall(
+      TLIVecFunc, Args, OpBundles, /*FMFSource=*/II->getFastMathFlagsOrNone());
   II->replaceAllUsesWith(Replacement);
-  // Preserve fast math flags for FP math.
-  if (isa<FPMathOperator>(Replacement))
-    Replacement->copyFastMathFlags(II);
   Replacement->setCallingConv(TLIVecFunc->getCallingConv());
 }
 

diff  --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index 8d15cb5217031..b524c9dd83f4e 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -2999,8 +2999,7 @@ static Value *optimizeSymmetricCall(CallInst *CI, bool IsEven,
   Value *Src = CI->getArgOperand(0);
 
   if (match(Src, m_OneUse(m_FNeg(m_Value(X))))) {
-    auto *Call = B.CreateCall(CI->getCalledFunction(), {X});
-    Call->copyFastMathFlags(CI);
+    auto *Call = B.CreateCall(CI->getCalledFunction(), {X}, /*FMFSource=*/CI);
     auto *CallInst = copyFlags(*CI, Call);
     if (IsEven) {
       // Even function: f(-x) = f(x)
@@ -3013,8 +3012,7 @@ static Value *optimizeSymmetricCall(CallInst *CI, bool IsEven,
   // Even function: f(abs(x)) = f(x), f(copysign(x, y)) = f(x)
   if (IsEven && (match(Src, m_FAbs(m_Value(X))) ||
                  match(Src, m_CopySign(m_Value(X), m_Value())))) {
-    auto *Call = B.CreateCall(CI->getCalledFunction(), {X});
-    Call->copyFastMathFlags(CI);
+    auto *Call = B.CreateCall(CI->getCalledFunction(), {X}, /*FMFSource=*/CI);
     return copyFlags(*CI, Call);
   }
 

diff  --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index d40022d640290..382cf0f2b57ed 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -2879,7 +2879,7 @@ TEST_F(ComputeKnownBitsTest, ComputeKnownBitsUnknownVScale) {
   IRBuilder<> Builder(Context);
   Function *TheFn = Intrinsic::getOrInsertDeclaration(&M, Intrinsic::vscale,
                                                       {Builder.getInt32Ty()});
-  CallInst *CI = Builder.CreateCall(TheFn, {}, {}, "");
+  CallInst *CI = Builder.CreateCall(TheFn, {});
 
   KnownBits Known = computeKnownBits(CI, M.getDataLayout());
   // There is no parent function so we cannot look up the vscale_range

diff  --git a/llvm/unittests/IR/IRBuilderTest.cpp b/llvm/unittests/IR/IRBuilderTest.cpp
index 813b1d6e07a3a..6befc403c6f30 100644
--- a/llvm/unittests/IR/IRBuilderTest.cpp
+++ b/llvm/unittests/IR/IRBuilderTest.cpp
@@ -800,6 +800,26 @@ TEST_F(IRBuilderTest, FastMathFlags) {
 
   Builder.clearFastMathFlags();
 
+  // The FMFSource overload copies flags from the source, ignoring the builder's
+  // (here empty) flags.
+  FastMathFlags CallFMF;
+  CallFMF.setAllowContract();
+  FCall = Builder.CreateCall(Callee, {}, /*FMFSource=*/CallFMF);
+  EXPECT_FALSE(Builder.getFastMathFlags().any());
+  EXPECT_FALSE(FCall->hasNoNaNs());
+  EXPECT_TRUE(FCall->hasAllowContract());
+
+  // A source instruction forwards its flags too.
+  Instruction *FCall2 = Builder.CreateCall(V, {}, /*FMFSource=*/FCall);
+  EXPECT_TRUE(FCall2->hasAllowContract());
+
+  // The OpBundles + FMFSource overload behaves the same.
+  Instruction *FCall3 = Builder.CreateCall(
+      Callee, {}, ArrayRef<OperandBundleDef>{}, /*FMFSource=*/CallFMF);
+  EXPECT_TRUE(FCall3->hasAllowContract());
+
+  Builder.clearFastMathFlags();
+
   // To test a copy, make sure that a '0' and a '1' change state.
   F = Builder.CreateFDiv(F, F);
   ASSERT_TRUE(isa<Instruction>(F));


        


More information about the llvm-commits mailing list