diff options
author | Ömer Sinan Ağacan <omeragacan@gmail.com> | 2016-05-27 05:18:47 -0400 |
---|---|---|
committer | Ömer Sinan Ağacan <omeragacan@gmail.com> | 2016-05-27 05:19:06 -0400 |
commit | cd50d236a4b29a9932ce4e12972db1fdd69f31be (patch) | |
tree | 9d80dcf6324c10aaecfaf806cc40fdb33df0ca39 /compiler | |
parent | 5b145c98900470c09ed6555e481b19cb27ec8b14 (diff) | |
download | haskell-cd50d236a4b29a9932ce4e12972db1fdd69f31be.tar.gz |
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
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/codeGen/StgCmmCon.hs | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/compiler/codeGen/StgCmmCon.hs b/compiler/codeGen/StgCmmCon.hs index 745dd720eb..04257dd991 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 [] - |