Opened 4 years ago

Closed 2 years ago

#8335 closed task (fixed)

Create more specialized entries to GC

Reported by: jstolarek Owned by: bgamari
Priority: normal Milestone:
Component: Compiler Version: 7.7
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

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).

Change History (2)

comment:1 Changed 2 years ago by bgamari

Owner: set to bgamari

There should be a check in the stack allocator to catch this case. It's possible that this isn't firing. I'll have a look at this.

comment:2 Changed 2 years ago by bgamari

Resolution: fixed
Status: newclosed

I think this may be fixed (at least in the current state of master, a3c78abcbdfe5025dc704acdcd0a85c78cabbd6b).

This program (taken from #8326),

{-# LANGUAGE MagicHash #-}
module Test where

import GHC.Prim
import GHC.Types

f :: Int# -> Int
f x | isTrue# (x ># 0#) = I# x
    | otherwise         = -(I# x)

produces this Core,

f :: Int# -> Int
f =
  \ (x_anw :: Int#) ->
    case tagToEnum# @ Bool (># x_anw 0#) of _ [Occ=Dead] {
      False -> I# (negateInt# x_anw);
      True -> I# x_anw
    }

which is ultimately lowered to this C--,

 Test.f_entry() //  [R2]
         { info_tbl: [(cyv,
                       label: Test.f_info
                       rep:HeapRep static { Fun {arity: 1 fun_type: ArgSpec 4} })]
           stack_info: arg_space: 8 updfr_space: Just 8
         }
     {offset
       cyv:
           Hp = Hp + 16;
           if (Hp > HpLim) goto cyz; else goto cyy;
       cyz:
           HpAlloc = 16;
           R2 = R2;
           R1 = Test.f_closure;
           call (stg_gc_fun)(R2, R1) args: 8, res: 0, upd: 8;
       cyy:
           if (%MO_S_Gt_W64(R2, 0)) goto cyL; else goto cyI;
       cyL:
           I64[Hp - 8] = GHC.Types.I#_con_info;
           I64[Hp] = R2;
           R1 = Hp - 7;
           call (P64[Sp])(R1) args: 8, res: 0, upd: 8;
       cyI:
           I64[Hp - 8] = GHC.Types.I#_con_info;
           I64[Hp] = -R2;
           R1 = Hp - 7;
           call (P64[Sp])(R1) args: 8, res: 0, upd: 8;
     }
 }]

Jan, would you agree that all looks okay here?

Note: See TracTickets for help on using tickets.