
#14791: Move stack checks out of code paths that don't use the stack. -------------------------------------+------------------------------------- Reporter: AndreasK | Owner: (none) Type: task | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.2.2 Keywords: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- Given the simple function: {{{ func :: Int -> Int func 11 = 11111 func 41 = 4444 }}} We produce this cmm code: {{{ [section ""data" . T.func_closure" { T.func_closure: const T.func_info; const 0; }, T.func_entry() // [R2] { info_tbl: [(c2lk, label: block_c2lk_info rep:StackRep []), (c2ln, label: T.func_info rep:HeapRep static { Fun {arity: 1 fun_type: ArgSpec 5} })] stack_info: arg_space: 8 updfr_space: Just 8 } {offset c2ln: // global if ((Sp + -8) < SpLim) (likely: False) goto c2lo; else goto c2lp; c2lo: // global R2 = R2; R1 = T.func_closure; call (stg_gc_fun)(R2, R1) args: 8, res: 0, upd: 8; c2lp: // global I64[Sp - 8] = c2lk; R1 = R2; Sp = Sp - 8; if (R1 & 7 != 0) goto c2lk; else goto c2ll; c2ll: // global call (I64[R1])(R1) returns to c2lk, args: 8, res: 8, upd: 8; c2lk: // global _s2kY::I64 = I64[R1 + 7]; if (_s2kY::I64 != 11) goto u2ly; else goto c2lw; u2ly: // global if (_s2kY::I64 == 41) (likely: False) goto c2lx; else goto c2lv; c2lx: // global R1 = T.func1_closure+1; Sp = Sp + 8; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; c2lv: // global R1 = T.func3_closure; Sp = Sp + 8; call (I64[R1])(R1) args: 8, res: 0, upd: 8; c2lw: // global R1 = T.func2_closure+1; Sp = Sp + 8; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } }] }}} However the code path if the argument is already evaluated never uses the stack: {{{ T.func_entry() // [R2] { info_tbl: [(c2lk, label: block_c2lk_info rep:StackRep []), (c2ln, label: T.func_info rep:HeapRep static { Fun {arity: 1 fun_type: ArgSpec 5} })] stack_info: arg_space: 8 updfr_space: Just 8 } {offset c2ln: // global if ((Sp + -8) < SpLim) (likely: False) goto c2lo; else goto c2lp; c2lp: // global I64[Sp - 8] = c2lk; R1 = R2; Sp = Sp - 8; if (R1 & 7 != 0) goto c2lk; else goto <..>; c2lk: // global _s2kY::I64 = I64[R1 + 7]; if (_s2kY::I64 != 11) goto u2ly; else goto c2lw; u2ly: // global if (_s2kY::I64 == 41) (likely: False) goto c2lx; else goto c2lv; c2lx: // global R1 = T.func1_closure+1; Sp = Sp + 8; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; c2lv: // global R1 = T.func3_closure; Sp = Sp + 8; call (I64[R1])(R1) args: 8, res: 0, upd: 8; c2lw: // global R1 = T.func2_closure+1; Sp = Sp + 8; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } }] }}} This means if we have a tagged argument we * Perform a stack check * Decrement the stack * Move the continuation onto the stack. * Increment the stack Without any of it being necessary. If I'm not mistaken all of that could be done after we know we need to evaluate the argument. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14791 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler