Sebastian Graf pushed to branch wip/sg/enter-data at Glasgow Haskell Compiler / GHC

Commits:

5 changed files:

Changes:

  • changelog.d/27594
    1
    +section: codegen
    
    2
    +synopsis: Tagged data pointers are no longer entered when forced in tail position
    
    3
    +issues: #27594
    
    4
    +mrs: !16445
    
    5
    +description:
    
    6
    +  Forcing a data pointer of statically unknown form in tail position now goes
    
    7
    +  through the new RTS stub ``stg_enter_data``, which returns the pointer if it
    
    8
    +  is tagged already.

  • compiler/GHC/StgToCmm/Expr.hs
    ... ... @@ -36,6 +36,8 @@ import GHC.Cmm.BlockId
    36 36
     import GHC.Cmm hiding ( succ )
    
    37 37
     import GHC.Cmm.Info
    
    38 38
     import GHC.Cmm.Utils ( cmmTagMask, mkWordCLit )
    
    39
    +import GHC.Cmm.CLabel ( mkCmmCodeLabel )
    
    40
    +import GHC.Unit ( rtsUnitId )
    
    39 41
     import GHC.Platform.Tag ( mAX_PTR_TAG )
    
    40 42
     import GHC.Core
    
    41 43
     import GHC.Core.DataCon
    
    ... ... @@ -1190,22 +1192,14 @@ emitEnter fun = do
    1190 1192
       ; adjustHpBackwards
    
    1191 1193
       ; sequel      <- getSequel
    
    1192 1194
       ; updfr_off   <- getUpdFrameOff
    
    1193
    -  ; align_check <- stgToCmmAlignCheck <$> getStgToCmmConfig
    
    1194 1195
       ; case sequel of
    
    1195
    -      -- For a return, we have the option of generating a tag-test or
    
    1196
    -      -- not.  If the value is tagged, we can return directly, which
    
    1197
    -      -- is quicker than entering the value.  This is a code
    
    1198
    -      -- size/speed trade-off: when optimising for speed rather than
    
    1199
    -      -- size we could generate the tag test.
    
    1200
    -      --
    
    1201
    -      -- Right now, we do what the old codegen did, and omit the tag
    
    1202
    -      -- test, just generating an enter.
    
    1196
    +      -- For a return we jump to stg_enter_data, which returns an already
    
    1197
    +      -- tagged pointer to our caller and enters an untagged one.
    
    1198
    +      -- See Note [Forcing an unknown data pointer] in rts/Apply.cmm.
    
    1203 1199
           Return -> do
    
    1204
    -        { let entry = entryCode platform
    
    1205
    -                $ closureInfoPtr platform align_check
    
    1206
    -                $ CmmReg (nodeReg platform)
    
    1207
    -        ; emit $ mkJump profile NativeNodeCall entry
    
    1208
    -                        [cmmUntag platform fun] updfr_off
    
    1200
    +        { let enter_data = CmmLit (CmmLabel
    
    1201
    +                             (mkCmmCodeLabel rtsUnitId (fsLit "stg_enter_data")))
    
    1202
    +        ; emit $ mkJump profile NativeNodeCall enter_data [fun] updfr_off
    
    1209 1203
             ; return AssignedDirectly
    
    1210 1204
             }
    
    1211 1205
     
    

  • rts/Apply.cmm
    ... ... @@ -47,6 +47,31 @@ import CLOSURE stg_apply_interp_info;
    47 47
     import CLOSURE stg_restore_cccs_eval_info;
    
    48 48
     #endif
    
    49 49
     
    
    50
    +/* Note [Forcing an unknown data pointer]
    
    51
    + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    52
    + * stg_enter_data forces a pointer to a thunk, a constructor, or an
    
    53
    + * indirection to one, and returns the result to the caller's continuation.
    
    54
    + * emitEnter (GHC.StgToCmm.Expr) jumps here for the pointers getCallMethod
    
    55
    + * classifies as EnterIt: lifted ones whose type rules out functions, so
    
    56
    + * whether they are forced already is unknown until the tag is tested.
    
    57
    + *
    
    58
    + * The stub is stg_ap_0_fast specialised to that domain, where its
    
    59
    + * FUN/PAP/BCO arms are unreachable and an indirection's own entry code
    
    60
    + * follows the indirection. What remains is the tag test and an entry jump.
    
    61
    + *
    
    62
    + * Whether the pointer turns out to be tagged decides which way a program moves:
    
    63
    + * nofib imaginary+spectral is a wash overall, with primetest and exact-reals a
    
    64
    + * percent faster and fft2 and fft a percent slower.
    
    65
    + */
    
    66
    +
    
    67
    +stg_enter_data ( P_ x )
    
    68
    +{
    
    69
    +    if (GETTAG(x) != 0) {
    
    70
    +        return (x);
    
    71
    +    }
    
    72
    +    jump %GET_ENTRY(x) (x);
    
    73
    +}
    
    74
    +
    
    50 75
     /* ----------------------------------------------------------------------------
    
    51 76
      * Evaluate a closure and return it.
    
    52 77
      *
    

  • rts/RtsSymbols.c
    ... ... @@ -842,6 +842,7 @@ extern char **environ;
    842 842
           SymI_HasDataProto(stg_ap_ppppp_info)                                  \
    
    843 843
           SymI_HasDataProto(stg_ap_pppppp_info)                                 \
    
    844 844
           SymI_HasDataProto(stg_ap_0_fast)                                      \
    
    845
    +      SymI_HasDataProto(stg_enter_data)                                     \
    
    845 846
           SymI_HasDataProto(stg_ap_v_fast)                                      \
    
    846 847
           SymI_HasDataProto(stg_ap_f_fast)                                      \
    
    847 848
           SymI_HasDataProto(stg_ap_d_fast)                                      \
    

  • rts/include/stg/MiscClosures.h
    ... ... @@ -300,6 +300,7 @@ RTS_RET(stg_ap_ppppp);
    300 300
     RTS_RET(stg_ap_pppppp);
    
    301 301
     
    
    302 302
     RTS_FUN_DECL(stg_ap_0_fast);
    
    303
    +RTS_FUN_DECL(stg_enter_data);
    
    303 304
     RTS_FUN_DECL(stg_ap_v_fast);
    
    304 305
     RTS_FUN_DECL(stg_ap_f_fast);
    
    305 306
     RTS_FUN_DECL(stg_ap_d_fast);