[GHC] #8905: Function arguments are always spilled/reloaded if scrutinee is already in WHNF
GHC
ghc-devs at haskell.org
Sun Mar 16 18:27:18 UTC 2014
#8905: Function arguments are always spilled/reloaded if scrutinee is already in
WHNF
------------------------------+--------------------------------------------
Reporter: tibbe | Owner:
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 7.9
Keywords: | Operating System: Unknown/Multiple
Architecture: | Type of failure: Runtime performance bug
Unknown/Multiple | Test Case:
Difficulty: Unknown | Blocking:
Blocked By: |
Related Tickets: |
------------------------------+--------------------------------------------
The code generator unnecessarily spills and reloads function arguments if
the scrutinee turns out to be already evaluated (i.e. has non-zero tag
bits).
Here's the beginning of a function body, taken from the `insert` function
at https://github.com/tibbe/unordered-
containers/blob/master/Data/HashMap/Base.hs#L303:
{{{
c2wQ: // stack check
if ((Sp + -72) < SpLim) goto c2wR; else goto c2wS;
c2wR: // stack check failure
R1 = PicBaseReg + $wpoly_go_closure;
I64[Sp - 40] = R2;
I64[Sp - 32] = R3;
P64[Sp - 24] = R4;
I64[Sp - 16] = R5;
P64[Sp - 8] = R6;
Sp = Sp - 40;
call (I64[BaseReg - 8])(R1) args: 48, res: 0, upd: 8;
c2wS: // stack check success
I64[Sp - 40] = PicBaseReg + block_c2my_info; // return addr for eval
R1 = R6; // t
I64[Sp - 32] = R2; // spill: s
I64[Sp - 24] = R3; // spill: x
P64[Sp - 16] = R4; // spill: k
I64[Sp - 8] = R5; // spill: h
Sp = Sp - 40;
if (R1 & 7 != 0) goto c2my; else goto c2mz; // eval check of t
c2mz: // eval check failed
call (I64[R1])(R1) returns to c2my, args: 8, res: 8, upd: 8; // eval
c2my: // eval check succeeded
_s2b1::I64 = I64[Sp + 8]; // reload: h
_s2b2::I64 = I64[Sp + 16]; // reload: k
_s2b3::P64 = P64[Sp + 24]; // reload: x
_s2b4::I64 = I64[Sp + 32]; // reload: s
switch [0 .. 4] (R1 & 7 - 1) {
case 0 : goto c2wK;
case 1 : goto c2wL;
case 2 : goto c2wM;
case 3 : goto c2wN;
case 4 : goto c2wO;
}
}}}
It seems to me that all the spills/reloads could be pushed into the `c2mz`
block.
The `c2my` block, in its current form, is reused for a heap check failure
case, so the heap check most likely will have to do its own
spilling/reloading. However, since the scrutinee not having tags bit or
the eval checking failing is not the common case, they should be out of
the common path.
If it matters the data type is spine strict so GHC should have enough
information to know that the common case (e.g. self-recursive calls)
already have an evaluated argument (although there might be an indirection
in some cases).
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8905>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list