Move stack checks out of code paths that don't use the stack.
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.
Trac metadata
Trac field | Value |
---|---|
Version | 8.2.2 |
Type | Task |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |