From 2e4e15edbba9099702b667652ffe8f5dae4055d8 Mon Sep 17 00:00:00 2001
From: Sylvain Henry <sylvain@haskus.fr>
Date: Fri, 14 Mar 2025 15:24:14 +0100
Subject: [PATCH] Document -fnum-constant-folding (#25862)

---
 compiler/GHC/Core/Opt/ConstantFold.hs         |  7 +++++
 compiler/GHC/Core/Rules/Config.hs             | 14 ++++++---
 compiler/GHC/Driver/Flags.hs                  |  2 +-
 .../expected-undocumented-flags.txt           |  1 -
 docs/users_guide/using-optimisation.rst       | 30 +++++++++++++++++++
 5 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/compiler/GHC/Core/Opt/ConstantFold.hs b/compiler/GHC/Core/Opt/ConstantFold.hs
index 71e22f8e9f6..b082dff1f7c 100644
--- a/compiler/GHC/Core/Opt/ConstantFold.hs
+++ b/compiler/GHC/Core/Opt/ConstantFold.hs
@@ -2635,6 +2635,13 @@ match_inline _ = Nothing
 --------------------------------------------------------
 -- Note [Constant folding through nested expressions]
 -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-- GHC has some support for constant folding through nested expressions (i.e.
+-- when constants are not only arguments of the considered App node but to one
+-- of its own argument (an App node too), see examples below).
+--
+-- For performance reason, this optimization is only enabled with -O1 and above.
+-- As with all optimizations, it can also be independently enabled with its own
+-- command-line flag too: -fnum-constant-folding (grep Opt_NumConstantFolding).
 --
 -- We use rewrites rules to perform constant folding. It means that we don't
 -- have a global view of the expression we are trying to optimise. As a
diff --git a/compiler/GHC/Core/Rules/Config.hs b/compiler/GHC/Core/Rules/Config.hs
index 2ae1e35a671..fa0ba4baeed 100644
--- a/compiler/GHC/Core/Rules/Config.hs
+++ b/compiler/GHC/Core/Rules/Config.hs
@@ -5,9 +5,15 @@ import GHC.Platform
 
 -- | Rule options
 data RuleOpts = RuleOpts
-   { roPlatform                :: !Platform -- ^ Target platform
-   , roNumConstantFolding      :: !Bool     -- ^ Enable more advanced numeric constant folding
-   , roExcessRationalPrecision :: !Bool     -- ^ Cut down precision of Rational values to that of Float/Double if disabled
-   , roBignumRules             :: !Bool     -- ^ Enable rules for bignums
+   { roPlatform                :: !Platform
+     -- ^ Target platform
+   , roNumConstantFolding      :: !Bool
+     -- ^ Enable constant folding through nested expressions.
+     --
+     -- See Note [Constant folding through nested expressions] in GHC.Core.Opt.ConstantFold
+   , roExcessRationalPrecision :: !Bool
+     -- ^ Cut down precision of Rational values to that of Float/Double if disabled
+   , roBignumRules             :: !Bool
+     -- ^ Enable rules for bignums
    }
 
diff --git a/compiler/GHC/Driver/Flags.hs b/compiler/GHC/Driver/Flags.hs
index a323ec56fe0..1096802f17e 100644
--- a/compiler/GHC/Driver/Flags.hs
+++ b/compiler/GHC/Driver/Flags.hs
@@ -678,7 +678,7 @@ data GeneralFlag
    | Opt_SolveConstantDicts
    | Opt_AlignmentSanitisation
    | Opt_CatchNonexhaustiveCases
-   | Opt_NumConstantFolding
+   | Opt_NumConstantFolding   -- ^ See Note [Constant folding through nested expressions] in GHC.Core.Opt.ConstantFold
    | Opt_CoreConstantFolding
    | Opt_FastPAPCalls                  -- #6084
    | Opt_SpecEval
diff --git a/docs/users_guide/expected-undocumented-flags.txt b/docs/users_guide/expected-undocumented-flags.txt
index 87aa92ae720..bc79591af94 100644
--- a/docs/users_guide/expected-undocumented-flags.txt
+++ b/docs/users_guide/expected-undocumented-flags.txt
@@ -57,7 +57,6 @@
 -fmax-errors
 -fmax-pmcheck-iterations
 -fmonomorphism-restriction
--fnum-constant-folding
 -fpre-inlining
 -fprint-bind-contents
 -freduction-depth
diff --git a/docs/users_guide/using-optimisation.rst b/docs/users_guide/using-optimisation.rst
index efaca3c3874..4dc43b30492 100644
--- a/docs/users_guide/using-optimisation.rst
+++ b/docs/users_guide/using-optimisation.rst
@@ -132,6 +132,36 @@ as such you shouldn't need to set any of them explicitly. A flag
     Enables Core-level constant folding, i.e. propagation of values
     that can be computed at compile time.
 
+.. ghc-flag:: -fnum-constant-folding
+    :shortdesc: Enable constant folding on nested numerical expressions. Implied by :ghc-flag:`-O`.
+    :type: dynamic
+    :reverse: -fno-num-constant-folding
+    :category:
+
+    :default: off but enabled by :ghc-flag:`-O`.
+
+    When enabled, the compiler uses associativity, commutativity, and
+    distributivity laws of numerical primops to perform constant folding on
+    nested numerical expressions.
+
+    Examples:
+
+        (10 + x) + 10
+        ===> 20 + x
+
+        5 + x + (y + (z + (t + 5)))
+        ===> 10 + (x + (y + (z + t)))
+
+        (5 + x) * 6
+        ===> 30 + 6*x
+
+        5 + x + (x + (x + (x + 5)))
+        ===> 10 + (4 * x)
+
+        (5 + 4*x) - (3*x + 2)
+        ===> 3 + x
+
+
 .. ghc-flag:: -fcase-merge
     :shortdesc: Enable case-merging. Implied by :ghc-flag:`-O`.
     :type: dynamic
-- 
GitLab