[GHC] #14791: Move stack checks out of code paths that don't use the stack.

GHC ghc-devs at haskell.org
Sun Feb 11 13:32:48 UTC 2018


#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


More information about the ghc-tickets mailing list