Commit cd50d236 authored by Ömer Sinan Ağacan's avatar Ömer Sinan Ağacan
Browse files

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
parent 5b145c98
......@@ -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 []
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment