Sebastian Graf pushed to branch wip/sg/enter-data at Glasgow Haskell Compiler / GHC
Commits:
-
75d4e387
by Sebastian Graf at 2026-08-03T13:18:41+02:00
5 changed files:
- + changelog.d/27594
- compiler/GHC/StgToCmm/Expr.hs
- rts/Apply.cmm
- rts/RtsSymbols.c
- rts/include/stg/MiscClosures.h
Changes:
| 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. |
| ... | ... | @@ -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 |
| ... | ... | @@ -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 | *
|
| ... | ... | @@ -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) \
|
| ... | ... | @@ -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);
|