[clang] [llvm] [WIP][llvm] Flag to forcibly outline fixed point mul/div intrinsics (PR #144612)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 17 15:07:12 PDT 2025
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 <leonardchan at 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));
More information about the llvm-commits
mailing list