[commit: ghc] master: StgCmmCon: Do not generate moves from unused fields to local variables (cd50d23)

git at git.haskell.org git at git.haskell.org
Fri May 27 09:18:03 UTC 2016


Repository : ssh://git@git.haskell.org/ghc

On branch  : master
Link       : http://ghc.haskell.org/trac/ghc/changeset/cd50d236a4b29a9932ce4e12972db1fdd69f31be/ghc

>---------------------------------------------------------------

commit cd50d236a4b29a9932ce4e12972db1fdd69f31be
Author: Ömer Sinan Ağacan <omeragacan at gmail.com>
Date:   Fri May 27 05:18:47 2016 -0400

    StgCmmCon: Do not generate moves from unused fields to local variables
    
    Say we have a record like this:
    
        data Rec = Rec
          { f1 :: Int
          , f2 :: Int
          , f3 :: Int
          , f4 :: Int
          , f5 :: Int
          }
    
    Before this patch, the code generated for `f1` looked like this:
    
        f1_entry()
            {offset
               ...
               cJT:
                   _sI6::P64 = R1;
                   _sI7::P64 = P64[_sI6::P64 + 7];
                   _sI8::P64 = P64[_sI6::P64 + 15];
                   _sI9::P64 = P64[_sI6::P64 + 23];
                   _sIa::P64 = P64[_sI6::P64 + 31];
                   _sIb::P64 = P64[_sI6::P64 + 39];
                   R1 = _sI7::P64 & (-8);
                   Sp = Sp + 8;
                   call (I64[R1])(R1) args: 8, res: 0, upd: 8;
            }
    
    Note how all fields of the record are moved to local variables, even though
    they're never used. These moves make it to the final assembly:
    
        f1_info:
            ...
        _cJT:
            movq 7(%rbx),%rax
            movq 15(%rbx),%rcx
            movq 23(%rbx),%rcx
            movq 31(%rbx),%rcx
            movq 39(%rbx),%rbx
            movq %rax,%rbx
            andq $-8,%rbx
            addq $8,%rbp
            jmp *(%rbx)
    
    With this patch we stop generating these move instructions. Cmm becomes this:
    
        f1_entry()
            {offset
               ...
               cJT:
                   _sI6::P64 = R1;
                   _sI7::P64 = P64[_sI6::P64 + 7];
                   R1 = _sI7::P64 & (-8);
                   Sp = Sp + 8;
                   call (I64[R1])(R1) args: 8, res: 0, upd: 8;
            }
    
    Assembly becomes this:
    
        f1_info:
            ...
        _cJT:
            movq 7(%rbx),%rax
            movq %rax,%rbx
            andq $-8,%rbx
            addq $8,%rbp
            jmp *(%rbx)
    
    It turns out CmmSink already optimizes this, but it's better to generate
    better code in the first place.
    
    Reviewers: simonmar, simonpj, austin, bgamari
    
    Reviewed By: simonmar, simonpj
    
    Subscribers: rwbarton, thomie
    
    Differential Revision: https://phabricator.haskell.org/D2269


>---------------------------------------------------------------

cd50d236a4b29a9932ce4e12972db1fdd69f31be
 compiler/codeGen/StgCmmCon.hs | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/compiler/codeGen/StgCmmCon.hs b/compiler/codeGen/StgCmmCon.hs
index 745dd72..04257dd 100644
--- a/compiler/codeGen/StgCmmCon.hs
+++ b/compiler/codeGen/StgCmmCon.hs
@@ -43,6 +43,7 @@ import PrelInfo
 import Outputable
 import Platform
 import Util
+import MonadUtils (mapMaybeM)
 
 import Control.Monad
 import Data.Char
@@ -258,12 +259,18 @@ bindConArgs (DataAlt con) base args
 
            -- The binding below forces the masking out of the tag bits
            -- when accessing the constructor field.
-           bind_arg :: (NonVoid Id, VirtualHpOffset) -> FCode LocalReg
-           bind_arg (arg, offset)
-               = do emit $ mkTaggedObjectLoad dflags (idToReg dflags arg) base offset tag
-                    bindArgToReg arg
-       mapM bind_arg args_w_offsets
+           bind_arg :: (NonVoid Id, VirtualHpOffset) -> FCode (Maybe LocalReg)
+           bind_arg (arg@(NonVoid b), offset)
+             | isDeadBinder b =
+                 -- Do not load unused fields from objects to local variables.
+                 -- (CmmSink can optimize this, but it's cheap and common enough
+                 -- to handle here)
+                 return Nothing
+             | otherwise      = do
+                 emit $ mkTaggedObjectLoad dflags (idToReg dflags arg) base offset tag
+                 Just <$> bindArgToReg arg
+
+       mapMaybeM bind_arg args_w_offsets
 
 bindConArgs _other_con _base args
   = ASSERT( null args ) return []
-



More information about the ghc-commits mailing list