https://github.com/PiJoules created 
https://github.com/llvm/llvm-project/pull/144612

This saves about 3kB on embedded project.

>From 9f179e644ddadba15f51d45479b20744b66f6291 Mon Sep 17 00:00:00 2001
From: Leonard Chan <leonardc...@google.com>
Date: Tue, 17 Jun 2025 15:06:10 -0700
Subject: [PATCH] [WIP][llvm] Flag to forcibly outline fixed point mul/div
 intrinsics

This saves about 3kB on embedded project.
---
 clang/include/clang/Basic/CodeGenOptions.def |  3 +
 clang/include/clang/Driver/Options.td        |  9 +++
 clang/lib/CodeGen/CGExprScalar.cpp           |  8 +-
 clang/lib/Driver/ToolChains/Clang.cpp        |  3 +
 llvm/include/llvm/IR/FixedPointBuilder.h     | 78 +++++++++++++++++---
 5 files changed, 89 insertions(+), 12 deletions(-)

diff --git a/clang/include/clang/Basic/CodeGenOptions.def 
b/clang/include/clang/Basic/CodeGenOptions.def
index e5566a540dc65..6cf06196bd2d5 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -483,6 +483,9 @@ CODEGENOPT(StaticClosure, 1, 0)
 /// Assume that UAVs/SRVs may alias
 CODEGENOPT(ResMayAlias, 1, 0)
 
+/// Outline fixed point multiplication and division intrinsics.
+CODEGENOPT(OutlineFixedPointMulDiv, 1, 0)
+
 /// Controls how unwind v2 (epilog) information should be generated for x64
 /// Windows.
 ENUM_CODEGENOPT(WinX64EHUnwindV2, llvm::WinX64EHUnwindV2Mode,
diff --git a/clang/include/clang/Driver/Options.td 
b/clang/include/clang/Driver/Options.td
index 72d564e1ba0be..899b563f97bba 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2741,6 +2741,15 @@ defm strict_float_cast_overflow : 
BoolFOption<"strict-float-cast-overflow",
             " of the target's native float-to-int conversion instructions">,
   PosFlag<SetTrue, [], [ClangOption], "Assume that overflowing float-to-int 
casts are undefined (default)">>;
 
+defm outline_fixed_point_mul_div_intrinsics
+    : BoolFOption<
+          "outline-fixed-point-mul-div-intrinsics",
+          CodeGenOpts<"OutlineFixedPointMulDiv">, DefaultFalse,
+          NegFlag<SetFalse, [], [ClangOption, CC1Option], "Do not outline ">,
+          PosFlag<SetTrue, [], [ClangOption, CC1Option], "Outline ">,
+          BothFlags<[], [ClangOption, CC1Option],
+                    "the fixed point multiplication and division intrinsics">>;
+
 defm protect_parens : BoolFOption<"protect-parens",
   LangOpts<"ProtectParens">, DefaultFalse,
   PosFlag<SetTrue, [], [ClangOption, CLOption, CC1Option],
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index 193710bef2d16..e8de96dedc90a 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -4543,11 +4543,15 @@ Value *ScalarExprEmitter::EmitFixedPointBinOp(const 
BinOpInfo &op) {
     break;
   case BO_MulAssign:
   case BO_Mul:
-    Result = FPBuilder.CreateMul(LHS, LHSFixedSema, RHS, RHSFixedSema);
+    Result =
+        FPBuilder.CreateMul(LHS, LHSFixedSema, RHS, RHSFixedSema,
+                            CGF.CGM.getCodeGenOpts().OutlineFixedPointMulDiv);
     break;
   case BO_DivAssign:
   case BO_Div:
-    Result = FPBuilder.CreateDiv(LHS, LHSFixedSema, RHS, RHSFixedSema);
+    Result =
+        FPBuilder.CreateDiv(LHS, LHSFixedSema, RHS, RHSFixedSema,
+                            CGF.CGM.getCodeGenOpts().OutlineFixedPointMulDiv);
     break;
   case BO_ShlAssign:
   case BO_Shl:
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 7dfed3a3356bb..e18feae4e2059 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6369,6 +6369,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
   Args.AddLastArg(CmdArgs, options::OPT_fexperimental_omit_vtable_rtti,
                   options::OPT_fno_experimental_omit_vtable_rtti);
 
+  Args.AddLastArg(CmdArgs, 
options::OPT_foutline_fixed_point_mul_div_intrinsics,
+                  options::OPT_fno_outline_fixed_point_mul_div_intrinsics);
+
   if (Arg *A = Args.getLastArg(options::OPT_ffuchsia_api_level_EQ))
     A->render(Args, CmdArgs);
 
diff --git a/llvm/include/llvm/IR/FixedPointBuilder.h 
b/llvm/include/llvm/IR/FixedPointBuilder.h
index 1a22dd6b60936..ec983c96ab7b8 100644
--- a/llvm/include/llvm/IR/FixedPointBuilder.h
+++ b/llvm/include/llvm/IR/FixedPointBuilder.h
@@ -132,6 +132,44 @@ template <class IRBuilderTy> class FixedPointBuilder {
     return Type::getFloatingPointTy(Ty->getContext(), *FloatSema);
   }
 
+  static SmallString<16> GetOutlinedFuncName(StringRef OpName, bool Saturated,
+                                             unsigned Scale) {
+    SmallString<16> OutlinedFuncName("__outlined_");
+    OutlinedFuncName += OpName;
+    OutlinedFuncName += "_fix";
+    if (Saturated)
+      OutlinedFuncName += "_sat";
+    OutlinedFuncName += "_";
+    OutlinedFuncName += std::to_string(Scale);
+    return OutlinedFuncName;
+  }
+
+  Value *CallFixedPointIntrinsicWrapper(Intrinsic::ID IID,
+                                        StringRef OutlinedFuncName,
+                                        Value *WideLHS, Value *WideRHS,
+                                        unsigned Scale) {
+    Module *M = B.GetInsertBlock()->getParent()->getParent();
+    FunctionCallee Callee =
+        M->getOrInsertFunction(OutlinedFuncName, WideLHS->getType(),
+                               WideLHS->getType(), WideRHS->getType());
+    Function *OutlinedFunc = cast<Function>(Callee.getCallee());
+    if (OutlinedFunc->empty()) {
+      BasicBlock *BB =
+          BasicBlock::Create(M->getContext(), "entry", OutlinedFunc);
+      IRBuilder<> Builder(BB);
+      Value *V = Builder.CreateIntrinsic(IID, {WideLHS->getType()},
+                                         {OutlinedFunc->getArg(0),
+                                          OutlinedFunc->getArg(1),
+                                          Builder.getInt32(Scale)});
+      Builder.CreateRet(V);
+
+      Comdat *C = M->getOrInsertComdat(OutlinedFuncName);
+      OutlinedFunc->setComdat(C);
+      OutlinedFunc->addFnAttr(Attribute::NoInline);
+    }
+    return B.CreateCall(Callee, {WideLHS, WideRHS});
+  }
+
 public:
   FixedPointBuilder(IRBuilderTy &Builder) : B(Builder) {}
 
@@ -285,8 +323,8 @@ template <class IRBuilderTy> class FixedPointBuilder {
   /// \p LHSSema - The semantic of the left hand side
   /// \p RHS     - The right hand side
   /// \p RHSSema - The semantic of the right hand side
-  Value *CreateMul(Value *LHS, const FixedPointSemantics &LHSSema,
-                   Value *RHS, const FixedPointSemantics &RHSSema) {
+  Value *CreateMul(Value *LHS, const FixedPointSemantics &LHSSema, Value *RHS,
+                   const FixedPointSemantics &RHSSema, bool Outlined = false) {
     auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
     bool UseSigned = CommonSema.isSigned() || CommonSema.hasUnsignedPadding();
 
@@ -299,9 +337,19 @@ template <class IRBuilderTy> class FixedPointBuilder {
     } else {
       IID = UseSigned ? Intrinsic::smul_fix : Intrinsic::umul_fix;
     }
-    Value *Result = B.CreateIntrinsic(
-        IID, {WideLHS->getType()},
-        {WideLHS, WideRHS, B.getInt32(CommonSema.getScale())});
+
+    Value *Result;
+    if (!Outlined) {
+      Result = B.CreateIntrinsic(
+          IID, {WideLHS->getType()},
+          {WideLHS, WideRHS, B.getInt32(CommonSema.getScale())});
+    } else {
+      auto OutlinedFuncName =
+          GetOutlinedFuncName(UseSigned ? "smul" : "umul",
+                              CommonSema.isSaturated(), CommonSema.getScale());
+      Result = CallFixedPointIntrinsicWrapper(IID, OutlinedFuncName, WideLHS,
+                                              WideRHS, CommonSema.getScale());
+    }
 
     return CreateFixedToFixed(Result, CommonSema,
                               LHSSema.getCommonSemantics(RHSSema));
@@ -313,8 +361,8 @@ template <class IRBuilderTy> class FixedPointBuilder {
   /// \p LHSSema - The semantic of the left hand side
   /// \p RHS     - The right hand side
   /// \p RHSSema - The semantic of the right hand side
-  Value *CreateDiv(Value *LHS, const FixedPointSemantics &LHSSema,
-                   Value *RHS, const FixedPointSemantics &RHSSema) {
+  Value *CreateDiv(Value *LHS, const FixedPointSemantics &LHSSema, Value *RHS,
+                   const FixedPointSemantics &RHSSema, bool Outlined = false) {
     auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
     bool UseSigned = CommonSema.isSigned() || CommonSema.hasUnsignedPadding();
 
@@ -327,9 +375,19 @@ template <class IRBuilderTy> class FixedPointBuilder {
     } else {
       IID = UseSigned ? Intrinsic::sdiv_fix : Intrinsic::udiv_fix;
     }
-    Value *Result = B.CreateIntrinsic(
-        IID, {WideLHS->getType()},
-        {WideLHS, WideRHS, B.getInt32(CommonSema.getScale())});
+
+    Value *Result;
+    if (!Outlined) {
+      Result = B.CreateIntrinsic(
+          IID, {WideLHS->getType()},
+          {WideLHS, WideRHS, B.getInt32(CommonSema.getScale())});
+    } else {
+      auto OutlinedFuncName =
+          GetOutlinedFuncName(UseSigned ? "sdiv" : "udiv",
+                              CommonSema.isSaturated(), CommonSema.getScale());
+      Result = CallFixedPointIntrinsicWrapper(IID, OutlinedFuncName, WideLHS,
+                                              WideRHS, CommonSema.getScale());
+    }
 
     return CreateFixedToFixed(Result, CommonSema,
                               LHSSema.getCommonSemantics(RHSSema));

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to