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 |