
#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