From ca1e636a9c4d8947a680c36167683616d09f4625 Mon Sep 17 00:00:00 2001 From: Rodrigo Mesquita <rodrigo.m.mesquita@gmail.com> Date: Fri, 14 Jul 2023 16:58:55 +0100 Subject: [PATCH] Improve Note [Binder-swap during float-out] --- compiler/GHC/Core/Opt/SetLevels.hs | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/compiler/GHC/Core/Opt/SetLevels.hs b/compiler/GHC/Core/Opt/SetLevels.hs index bcd01bec04ab..ffa66b30288b 100644 --- a/compiler/GHC/Core/Opt/SetLevels.hs +++ b/compiler/GHC/Core/Opt/SetLevels.hs @@ -44,13 +44,33 @@ case x of wild { p -> ...wild... } we substitute x for wild in the RHS of the case alternatives: case x of wild { p -> ...x... } - This means that a sub-expression involving x is not "trapped" inside the RHS. + This means that a sub-expression involving x is not "trapped" inside the RHS + (i.e. it can now be floated out, whereas if it mentioned wild it could not). And it's not inconvenient because we already have a substitution. - Note that this is EXACTLY BACKWARDS from the what the simplifier does. - The simplifier tries to get rid of occurrences of x, in favour of wild, - in the hope that there will only be one remaining occurrence of x, namely - the scrutinee of the case, and we can inline it. + For example, consider: + + f x = letrec go y = case x of z { (a,b) -> ...(expensive z)... } + in ... + + If we do the reverse binder-swap we get + + f x = letrec go y = case x of z { (a,b) -> ...(expensive x)... } + in ... + + and now we can float out: + + f x = let t = expensive x + in letrec go y = case x of z { (a,b) -> ...(t)... } + in ... + + Now (expensive x) is computed once, rather than once each time around the 'go' loop. + + Note that this is EXACTLY BACKWARDS from the what the simplifier does. + The simplifier tries to get rid of occurrences of x, in favour of wild, + in the hope that there will only be one remaining occurrence of x, namely + the scrutinee of the case, and we can inline it. + -} module GHC.Core.Opt.SetLevels ( -- GitLab