Skip to content

Create more specialized entries to GC

Consider this Cmm code (taken from #8326):

    {offset
       cFd: // stack check
           if ((Sp + -16) < SpLim) goto cFr; else goto cFs;
       cFr: // not enough place on the stack, call GC
           R2 = R2;
           R1 = A.f_closure;
           call (stg_gc_fun)(R2, R1) args: 8, res: 0, upd: 8;
       cFs: // scrutinize (x ># 0#)
           _sEU::I64 = R2;
           _sEV::I64 = %MO_S_Gt_W64(R2, 0);
           if (_sEV::I64 != 1) goto cFg; else goto cFo;
       cFg: // False branch
           Hp = Hp + 16;
           if (Hp > HpLim) goto cFy; else goto cFx;
       cFy: // not enough heap, call GC
           HpAlloc = 16;
           I64[Sp - 16] = cFf;
           R1 = _sEV::I64;
           I64[Sp - 8] = _sEU::I64;
           Sp = Sp - 16;
           call stg_gc_unbx_r1(R1) returns to cFf, args: 8, res: 8, upd: 8;
       cFf: // re-do the False branch
           _sEU::I64 = I64[Sp + 8];
           Sp = Sp + 16;
           _sEV::I64 = R1;
           goto cFg;
       cFx: // RHS of False branch
           I64[Hp - 8] = GHC.Types.I#_con_info;
           I64[Hp] = -_sEU::I64;
           R1 = Hp - 7;
           call (P64[Sp])(R1) args: 8, res: 0, upd: 8;
       cFo: // True branch
           Hp = Hp + 16;
           if (Hp > HpLim) goto cFv; else goto cFu;
       cFv: // not enough heap, call GC
           HpAlloc = 16;
           I64[Sp - 16] = cFn;
           R1 = _sEV::I64;
           I64[Sp - 8] = _sEU::I64;
           Sp = Sp - 16;
           call stg_gc_unbx_r1(R1) returns to cFn, args: 8, res: 8, upd: 8;
       cFn: // re-do the True branch
           _sEU::I64 = I64[Sp + 8];
           Sp = Sp + 16;
           _sEV::I64 = R1;
           goto cFo;
       cFu: // RHS of True branch
           I64[Hp - 8] = GHC.Types.I#_con_info;
           I64[Hp] = _sEU::I64;
           R1 = Hp - 7;
           call (P64[Sp])(R1) args: 8, res: 0, upd: 8;
     }

We perform two different calls to garbage collection here. Calling GC after making initial stack check obviously can't use any stack, so we pass parameter to GC in regsiters:

R2 = R2;
R1 = A.f_closure;
call (stg_gc_fun)(R2, R1) args: 8, res: 0, upd: 8;

But in the calls that are made later on inside the function we do put some parameters on the stack, thus increasing stack usage:

cFv: // not enough heap, call GC
    HpAlloc = 16;
    I64[Sp - 16] = cFn;
    R1 = _sEV::I64;
    I64[Sp - 8] = _sEU::I64;
    Sp = Sp - 16;
    call stg_gc_unbx_r1(R1) returns to cFn, args: 8, res: 8, upd: 8;

If we had more specialized entries to GC that would allow us to pass parameters in registers (or in some fixed memory location associated with TCO?) then this function would not require any stack at all. Note that there is a separate issue here - _sEV variable is in fact dead and should be eliminated (see #8327).

Trac metadata
Trac field Value
Version 7.7
Type Task
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information