Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
-
c9fa3449
by Sylvain Henry at 2025-11-15T05:15:26-05:00
-
9e469909
by Sylvain Henry at 2025-11-15T05:15:26-05:00
6 changed files:
- compiler/GHC/StgToJS/Apply.hs
- compiler/GHC/StgToJS/Expr.hs
- compiler/GHC/StgToJS/Regs.hs
- compiler/GHC/StgToJS/Rts/Rts.hs
- compiler/GHC/StgToJS/Rts/Types.hs
- testsuite/tests/codeGen/should_run/all.T
Changes:
| ... | ... | @@ -185,7 +185,7 @@ genApp ctx i args |
| 185 | 185 | as' <- concatMapM genArg args
|
| 186 | 186 | ei <- varForEntryId i
|
| 187 | 187 | let ra = mconcat . reverse $
|
| 188 | - zipWith (\r a -> toJExpr r |= a) [R1 ..] as'
|
|
| 188 | + zipWith (\r a -> toJExpr r |= a) regsFromR1 as'
|
|
| 189 | 189 | p <- pushLneFrame n ctx
|
| 190 | 190 | a <- adjSp 1 -- for the header (which will only be written when the thread is suspended)
|
| 191 | 191 | return (ra <> p <> a <> returnS ei, ExprCont)
|
| ... | ... | @@ -464,42 +464,31 @@ specTag spec = Bits.shiftL (specVars spec) 8 Bits..|. specArgs spec |
| 464 | 464 | specTagExpr :: ApplySpec -> JStgExpr
|
| 465 | 465 | specTagExpr = toJExpr . specTag
|
| 466 | 466 | |
| 467 | --- | Build arrays to quickly lookup apply functions
|
|
| 467 | +-- | Build functions to quickly lookup apply functions
|
|
| 468 | 468 | --
|
| 469 | --- h$apply[r << 8 | n] = function application for r regs, n args
|
|
| 470 | --- h$paps[r] = partial application for r registers (number of args is in the object)
|
|
| 469 | +-- h$apply(r << 8 | n) = function application for r regs, n args
|
|
| 470 | +-- h$paps(r) = partial application for r registers (number of args is in the object)
|
|
| 471 | 471 | mkApplyArr :: JSM JStgStat
|
| 472 | 472 | mkApplyArr =
|
| 473 | - do mk_ap_gens <- jFor (|= zero_) (.<. Int 65536) preIncrS
|
|
| 474 | - \j -> hdApply .! j |= hdApGen
|
|
| 475 | - mk_pap_gens <- jFor (|= zero_) (.<. Int 128) preIncrS
|
|
| 476 | - \j -> hdPaps .! j |= hdPapGen
|
|
| 473 | + do paps_fun <- jFunction (name hdPapsStr) \(MkSolo i) -> pure $ SwitchStat i (map case_pap specPap) (returnS hdPapGen)
|
|
| 474 | + apply_fun <- jFunction (name hdApplyStr) \(MkSolo i) -> pure $ SwitchStat i (mapMaybe' case_apply applySpec) (returnS hdApGen)
|
|
| 477 | 475 | return $ mconcat
|
| 478 | - [ name hdApplyStr ||= toJExpr (JList [])
|
|
| 479 | - , name hdPapsStr ||= toJExpr (JList [])
|
|
| 480 | - , ApplStat (hdInitStatic .^ "push")
|
|
| 481 | - [ jLam' $
|
|
| 482 | - mconcat
|
|
| 483 | - [ mk_ap_gens
|
|
| 484 | - , mk_pap_gens
|
|
| 485 | - , mconcat (map assignSpec applySpec)
|
|
| 486 | - , mconcat (map assignPap specPap)
|
|
| 487 | - ]
|
|
| 488 | - ]
|
|
| 476 | + [ paps_fun
|
|
| 477 | + , apply_fun
|
|
| 489 | 478 | ]
|
| 490 | 479 | where
|
| 491 | - assignSpec :: ApplySpec -> JStgStat
|
|
| 492 | - assignSpec spec = case specConv spec of
|
|
| 480 | + case_apply :: ApplySpec -> Maybe (JStgExpr,JStgStat)
|
|
| 481 | + case_apply spec = case specConv spec of
|
|
| 493 | 482 | -- both fast/slow (regs/stack) specialized apply functions have the same
|
| 494 | 483 | -- tags. We store the stack ones in the array because they are used as
|
| 495 | 484 | -- continuation stack frames.
|
| 496 | - StackConv -> hdApply .! specTagExpr spec |= specApplyExpr spec
|
|
| 497 | - RegsConv -> mempty
|
|
| 485 | + StackConv -> Just (specTagExpr spec, returnS (specApplyExpr spec))
|
|
| 486 | + RegsConv -> Nothing
|
|
| 498 | 487 | |
| 499 | 488 | hdPap_ = unpackFS hdPapStr_
|
| 500 | 489 | |
| 501 | - assignPap :: Int -> JStgStat
|
|
| 502 | - assignPap p = hdPaps .! toJExpr p |= global (mkFastString (hdPap_ ++ show p))
|
|
| 490 | + case_pap :: Int -> (JStgExpr, JStgStat)
|
|
| 491 | + case_pap p = (toJExpr p, returnS $ global (mkFastString (hdPap_ ++ show p)))
|
|
| 503 | 492 | |
| 504 | 493 | -- | Push a continuation on the stack
|
| 505 | 494 | --
|
| ... | ... | @@ -619,7 +608,7 @@ genericStackApply cfg = closure info body |
| 619 | 608 | -- compute new tag with consumed register values and args removed
|
| 620 | 609 | , newTag |= ((given_regs-needed_regs).<<.8) .|. (given_args - needed_args)
|
| 621 | 610 | -- find application function for the remaining regs/args
|
| 622 | - , newAp |= hdApply .! newTag
|
|
| 611 | + , newAp |= ApplExpr hdApply [newTag]
|
|
| 623 | 612 | , traceRts cfg (jString "h$ap_gen: next: " + (newAp .^ "n"))
|
| 624 | 613 | |
| 625 | 614 | -- Drop used registers from the stack.
|
| ... | ... | @@ -643,7 +632,7 @@ genericStackApply cfg = closure info body |
| 643 | 632 | -----------------------------
|
| 644 | 633 | [ traceRts cfg (jString "h$ap_gen: undersat")
|
| 645 | 634 | -- find PAP entry function corresponding to given_regs count
|
| 646 | - , p |= hdPaps .! given_regs
|
|
| 635 | + , p |= ApplExpr hdPaps [given_regs]
|
|
| 647 | 636 | |
| 648 | 637 | -- build PAP payload: R1 + tag + given register values
|
| 649 | 638 | , newTag |= ((needed_regs-given_regs) .<<. 8) .|. (needed_args-given_args)
|
| ... | ... | @@ -716,7 +705,7 @@ genericFastApply s = |
| 716 | 705 | do push_all_regs <- pushAllRegs tag
|
| 717 | 706 | return $ mconcat $
|
| 718 | 707 | [ push_all_regs
|
| 719 | - , ap |= hdApply .! tag
|
|
| 708 | + , ap |= ApplExpr hdApply [tag]
|
|
| 720 | 709 | , ifS (ap .===. hdApGen)
|
| 721 | 710 | ((sp |= sp + 2) <> (stack .! (sp-1) |= tag))
|
| 722 | 711 | (sp |= sp + 1)
|
| ... | ... | @@ -750,7 +739,7 @@ genericFastApply s = |
| 750 | 739 | , traceRts s (jString "h$ap_gen_fast: oversat " + sp)
|
| 751 | 740 | , push_args
|
| 752 | 741 | , newTag |= ((myRegs-( arity.>>.8)).<<.8).|.myAr-ar
|
| 753 | - , newAp |= hdApply .! newTag
|
|
| 742 | + , newAp |= ApplExpr hdApply [newTag]
|
|
| 754 | 743 | , ifS (newAp .===. hdApGen)
|
| 755 | 744 | ((sp |= sp + 2) <> (stack .! (sp - 1) |= newTag))
|
| 756 | 745 | (sp |= sp + 1)
|
| ... | ... | @@ -761,7 +750,7 @@ genericFastApply s = |
| 761 | 750 | -- else
|
| 762 | 751 | [traceRts s (jString "h$ap_gen_fast: undersat: " + myRegs + jString " " + tag)
|
| 763 | 752 | , jwhenS (tag .!=. 0) $ mconcat
|
| 764 | - [ p |= hdPaps .! myRegs
|
|
| 753 | + [ p |= ApplExpr hdPaps [myRegs]
|
|
| 765 | 754 | , dat |= toJExpr [r1, ((arity .>>. 8)-myRegs)*256+ar-myAr]
|
| 766 | 755 | , get_regs
|
| 767 | 756 | , r1 |= initClosure s p dat jCurrentCCS
|
| ... | ... | @@ -773,14 +762,24 @@ genericFastApply s = |
| 773 | 762 | pushAllRegs :: JStgExpr -> JSM JStgStat
|
| 774 | 763 | pushAllRegs tag =
|
| 775 | 764 | jVar \regs ->
|
| 776 | - return $ mconcat $
|
|
| 777 | - [ regs |= tag .>>. 8
|
|
| 778 | - , sp |= sp + regs
|
|
| 779 | - , SwitchStat regs (map pushReg [65,64..2]) mempty
|
|
| 780 | - ]
|
|
| 781 | - where
|
|
| 782 | - pushReg :: Int -> (JStgExpr, JStgStat)
|
|
| 783 | - pushReg r = (toJExpr (r-1), stack .! (sp - toJExpr (r - 2)) |= jsReg r)
|
|
| 765 | + let max_low_reg = regNumber maxLowReg
|
|
| 766 | + low_regs = [max_low_reg, max_low_reg-1..2] -- R1 isn't used for arguments
|
|
| 767 | + pushReg :: Int -> (JStgExpr, JStgStat)
|
|
| 768 | + pushReg r = (toJExpr r, stack .! (sp - toJExpr (r - 2)) |= jsReg r)
|
|
| 769 | + in return $ mconcat $
|
|
| 770 | + [ regs |= tag .>>. 8
|
|
| 771 | + , sp |= sp + regs
|
|
| 772 | + -- increment the number of regs by 1, so that it matches register
|
|
| 773 | + -- numbers (R1 is not used for args)
|
|
| 774 | + , postIncrS regs
|
|
| 775 | + -- copy high registers with a loop
|
|
| 776 | + , WhileStat False (regs .>. toJExpr max_low_reg) $ mconcat
|
|
| 777 | + -- rN stored in stack[sp - N - 2] so that r2 is stored in stack[sp], etc.
|
|
| 778 | + [ stack .! (sp - regs - 2) |= highReg_expr regs
|
|
| 779 | + , postDecrS regs
|
|
| 780 | + ]
|
|
| 781 | + , SwitchStat regs (map pushReg low_regs) mempty
|
|
| 782 | + ]
|
|
| 784 | 783 | |
| 785 | 784 | pushArgs :: JStgExpr -> JStgExpr -> JSM JStgStat
|
| 786 | 785 | pushArgs start end =
|
| ... | ... | @@ -906,7 +905,7 @@ stackApply s fun_name nargs nvars = |
| 906 | 905 | [ rs |= (arity .>>. 8)
|
| 907 | 906 | , loadRegs rs
|
| 908 | 907 | , sp |= sp - rs
|
| 909 | - , newAp |= (hdApply .! ((toJExpr nargs-arity0).|.((toJExpr nvars-rs).<<.8)))
|
|
| 908 | + , newAp |= ApplExpr hdApply [(toJExpr nargs-arity0).|.((toJExpr nvars-rs).<<.8)]
|
|
| 910 | 909 | , stack .! sp |= newAp
|
| 911 | 910 | , profStat s pushRestoreCCS
|
| 912 | 911 | , traceRts s (toJExpr (fun_name <> ": new stack frame: ") + (newAp .^ "n"))
|
| ... | ... | @@ -989,7 +988,7 @@ fastApply s fun_name nargs nvars = if nargs == 0 && nvars == 0 |
| 989 | 988 | + rsRemain)
|
| 990 | 989 | , saveRegs rs
|
| 991 | 990 | , sp |= sp + rsRemain + 1
|
| 992 | - , stack .! sp |= hdApply .! ((rsRemain.<<.8).|. (toJExpr nargs - mask8 arity))
|
|
| 991 | + , stack .! sp |= ApplExpr hdApply [(rsRemain.<<.8).|. (toJExpr nargs - mask8 arity)]
|
|
| 993 | 992 | , profStat s pushRestoreCCS
|
| 994 | 993 | , returnS c
|
| 995 | 994 | ]
|
| ... | ... | @@ -1238,14 +1237,30 @@ pap s r = closure (ClosureInfo |
| 1238 | 1237 | , profStat s (enterCostCentreFun currentCCS)
|
| 1239 | 1238 | , extra |= (funOrPapArity c (Just f) .>>. 8) - toJExpr r
|
| 1240 | 1239 | , traceRts s (toJExpr (funcName <> ": pap extra args moving: ") + extra)
|
| 1241 | - , moveBy extra
|
|
| 1240 | + , case r of
|
|
| 1241 | + 0 -> mempty -- in pap_0 we don't shift any register
|
|
| 1242 | + _ -> moveBy extra
|
|
| 1242 | 1243 | , loadOwnArgs d
|
| 1243 | 1244 | , r1 |= c
|
| 1244 | 1245 | , returnS f
|
| 1245 | 1246 | ]
|
| 1246 | - moveBy extra = SwitchStat extra
|
|
| 1247 | - (reverse $ map moveCase [1..maxReg-r-1]) mempty
|
|
| 1248 | - moveCase m = (toJExpr m, jsReg (m+r+1) |= jsReg (m+1))
|
|
| 1247 | + moveBy extra =
|
|
| 1248 | + let max_low_reg = regNumber maxLowReg
|
|
| 1249 | + low_regs = [max_low_reg, max_low_reg-1..2] -- R1 isn't used for arguments
|
|
| 1250 | + move_case m = (toJExpr m, jsReg (m+r) |= jsReg m)
|
|
| 1251 | + in mconcat
|
|
| 1252 | + [ -- increment the number of args by 1, so that it matches register
|
|
| 1253 | + -- numbers (R1 is not used for args)
|
|
| 1254 | + postIncrS extra
|
|
| 1255 | + -- copy high registers with a loop
|
|
| 1256 | + , WhileStat False (extra .>. toJExpr max_low_reg) $ mconcat
|
|
| 1257 | + [ highReg_expr (extra + toJExpr r) |= highReg_expr extra
|
|
| 1258 | + , postDecrS extra
|
|
| 1259 | + ]
|
|
| 1260 | + -- then copy low registers with a case
|
|
| 1261 | + , SwitchStat extra (map move_case low_regs) mempty
|
|
| 1262 | + ]
|
|
| 1263 | + |
|
| 1249 | 1264 | loadOwnArgs d = mconcat $ map (\r ->
|
| 1250 | 1265 | jsReg (r+1) |= dField d (r+2)) [1..r]
|
| 1251 | 1266 | dField d n = SelExpr d (name . mkFastString $ ('d':show (n-1)))
|
| ... | ... | @@ -1274,7 +1289,9 @@ papGen cfg = |
| 1274 | 1289 | (jString "h$pap_gen: expected function or pap")
|
| 1275 | 1290 | , profStat cfg (enterCostCentreFun currentCCS)
|
| 1276 | 1291 | , traceRts cfg (jString "h$pap_gen: generic pap extra args moving: " + or)
|
| 1292 | + -- shift newly applied arguments into appropriate registers
|
|
| 1277 | 1293 | , appS hdMoveRegs2 [or, r]
|
| 1294 | + -- load stored arguments into lowest argument registers (i.e. starting from R2)
|
|
| 1278 | 1295 | , loadOwnArgs d r
|
| 1279 | 1296 | , r1 |= c
|
| 1280 | 1297 | , returnS f
|
| ... | ... | @@ -1285,9 +1302,22 @@ papGen cfg = |
| 1285 | 1302 | funcIdent = name funcName
|
| 1286 | 1303 | funcName = hdPapGenStr
|
| 1287 | 1304 | loadOwnArgs d r =
|
| 1288 | - let prop n = d .^ ("d" <> mkFastString (show $ n+1))
|
|
| 1289 | - loadOwnArg n = (toJExpr n, jsReg (n+1) |= prop n)
|
|
| 1290 | - in SwitchStat r (map loadOwnArg [127,126..1]) mempty
|
|
| 1305 | + let prop n = d .^ (mkFastString ("d" ++ show n))
|
|
| 1306 | + loadOwnArg n = (toJExpr n, jsReg n |= prop n)
|
|
| 1307 | + max_low_reg = regNumber maxLowReg
|
|
| 1308 | + low_regs = [max_low_reg, max_low_reg-1..2] -- R1 isn't used for arguments
|
|
| 1309 | + in mconcat
|
|
| 1310 | + [ -- increment the number of args by 1, so that it matches register
|
|
| 1311 | + -- numbers (R1 is not used for args) and PAP fields (starting from d2)
|
|
| 1312 | + postIncrS r
|
|
| 1313 | + -- copy high registers with a loop
|
|
| 1314 | + , WhileStat False (r .>. toJExpr max_low_reg) $ mconcat
|
|
| 1315 | + [ highReg_expr r |= (d .! (jString (fsLit "d") + r))
|
|
| 1316 | + , postDecrS r
|
|
| 1317 | + ]
|
|
| 1318 | + -- then copy low registers with a case.
|
|
| 1319 | + , SwitchStat r (map loadOwnArg low_regs) mempty
|
|
| 1320 | + ]
|
|
| 1291 | 1321 | |
| 1292 | 1322 | -- general utilities
|
| 1293 | 1323 | -- move the first n registers, starting at R2, m places up (do not use with negative m)
|
| ... | ... | @@ -1301,7 +1331,7 @@ moveRegs2 = jFunction (name hdMoveRegs2) moveSwitch |
| 1301 | 1331 | switchCase n m = (toJExpr $
|
| 1302 | 1332 | (n `Bits.shiftL` 8) Bits..|. m
|
| 1303 | 1333 | , mconcat (map (`moveRegFast` m) [n+1,n..2])
|
| 1304 | - <> BreakStat Nothing {-[j| break; |]-})
|
|
| 1334 | + <> BreakStat Nothing)
|
|
| 1305 | 1335 | moveRegFast n m = jsReg (n+m) |= jsReg n
|
| 1306 | 1336 | -- fallback
|
| 1307 | 1337 | defaultCase n m =
|
| ... | ... | @@ -312,7 +312,7 @@ genBody ctx startReg args e typ = do |
| 312 | 312 | -- load arguments into local variables
|
| 313 | 313 | la <- do
|
| 314 | 314 | args' <- concatMapM genIdArgI args
|
| 315 | - return (declAssignAll args' (fmap toJExpr [startReg..]))
|
|
| 315 | + return (declAssignAll args' (jsRegsFrom startReg))
|
|
| 316 | 316 | |
| 317 | 317 | -- assert that arguments have valid runtime reps
|
| 318 | 318 | lav <- verifyRuntimeReps args
|
| ... | ... | @@ -665,7 +665,7 @@ genCase ctx bnd e at alts l |
| 665 | 665 | | otherwise = do
|
| 666 | 666 | rj <- genRet ctx bnd at alts l
|
| 667 | 667 | let ctx' = ctxSetTop bnd
|
| 668 | - $ ctxSetTarget (assocIdExprs bnd (map toJExpr [R1 ..]))
|
|
| 668 | + $ ctxSetTarget (assocIdExprs bnd jsRegsFromR1)
|
|
| 669 | 669 | $ ctx
|
| 670 | 670 | (ej, _r) <- genExpr ctx' e
|
| 671 | 671 | return (rj <> ej, ExprCont)
|
| ... | ... | @@ -730,7 +730,7 @@ genRet ctx e at as l = freshIdent >>= f |
| 730 | 730 | |
| 731 | 731 | fun free = resetSlots $ do
|
| 732 | 732 | decs <- declVarsForId e
|
| 733 | - load <- flip assignAll (map toJExpr [R1 ..]) . map toJExpr <$> identsForId e
|
|
| 733 | + load <- flip assignAll jsRegsFromR1 . map toJExpr <$> identsForId e
|
|
| 734 | 734 | loadv <- verifyRuntimeReps [e]
|
| 735 | 735 | ras <- loadRetArgs free
|
| 736 | 736 | rasv <- verifyRuntimeReps (map (\(x,_,_)->x) free)
|
| 1 | 1 | {-# LANGUAGE OverloadedStrings #-}
|
| 2 | +{-# LANGUAGE PatternSynonyms #-}
|
|
| 2 | 3 | |
| 3 | 4 | module GHC.StgToJS.Regs
|
| 4 | 5 | ( StgReg (..)
|
| ... | ... | @@ -6,17 +7,25 @@ module GHC.StgToJS.Regs |
| 6 | 7 | , sp
|
| 7 | 8 | , stack
|
| 8 | 9 | , r1, r2, r3, r4
|
| 10 | + , pattern R1, pattern R2, pattern R3, pattern R4
|
|
| 9 | 11 | , regsFromR1
|
| 10 | 12 | , regsFromR2
|
| 13 | + , regsFromTo
|
|
| 14 | + , jsRegsFrom
|
|
| 11 | 15 | , jsRegsFromR1
|
| 12 | 16 | , jsRegsFromR2
|
| 13 | 17 | , StgRet (..)
|
| 14 | - , jsRegToInt
|
|
| 15 | - , intToJSReg
|
|
| 18 | + , regNumber
|
|
| 16 | 19 | , jsReg
|
| 20 | + , highReg
|
|
| 21 | + , highReg_expr
|
|
| 17 | 22 | , maxReg
|
| 23 | + , maxLowReg
|
|
| 18 | 24 | , minReg
|
| 25 | + , minHighReg
|
|
| 19 | 26 | , lowRegs
|
| 27 | + , lowRegsCount
|
|
| 28 | + , lowRegsIdents
|
|
| 20 | 29 | , retRegs
|
| 21 | 30 | , register
|
| 22 | 31 | , foreignRegister
|
| ... | ... | @@ -32,6 +41,7 @@ import GHC.JS.Make |
| 32 | 41 | import GHC.StgToJS.Symbols
|
| 33 | 42 | |
| 34 | 43 | import GHC.Data.FastString
|
| 44 | +import GHC.Utils.Panic.Plain
|
|
| 35 | 45 | |
| 36 | 46 | import Data.Array
|
| 37 | 47 | import qualified Data.ByteString.Char8 as BSC
|
| ... | ... | @@ -39,26 +49,15 @@ import Data.Char |
| 39 | 49 | import Data.Semigroup ((<>))
|
| 40 | 50 | |
| 41 | 51 | -- | General purpose "registers"
|
| 42 | ---
|
|
| 43 | --- The JS backend arbitrarily supports 128 registers
|
|
| 44 | -data StgReg
|
|
| 45 | - = R1 | R2 | R3 | R4 | R5 | R6 | R7 | R8
|
|
| 46 | - | R9 | R10 | R11 | R12 | R13 | R14 | R15 | R16
|
|
| 47 | - | R17 | R18 | R19 | R20 | R21 | R22 | R23 | R24
|
|
| 48 | - | R25 | R26 | R27 | R28 | R29 | R30 | R31 | R32
|
|
| 49 | - | R33 | R34 | R35 | R36 | R37 | R38 | R39 | R40
|
|
| 50 | - | R41 | R42 | R43 | R44 | R45 | R46 | R47 | R48
|
|
| 51 | - | R49 | R50 | R51 | R52 | R53 | R54 | R55 | R56
|
|
| 52 | - | R57 | R58 | R59 | R60 | R61 | R62 | R63 | R64
|
|
| 53 | - | R65 | R66 | R67 | R68 | R69 | R70 | R71 | R72
|
|
| 54 | - | R73 | R74 | R75 | R76 | R77 | R78 | R79 | R80
|
|
| 55 | - | R81 | R82 | R83 | R84 | R85 | R86 | R87 | R88
|
|
| 56 | - | R89 | R90 | R91 | R92 | R93 | R94 | R95 | R96
|
|
| 57 | - | R97 | R98 | R99 | R100 | R101 | R102 | R103 | R104
|
|
| 58 | - | R105 | R106 | R107 | R108 | R109 | R110 | R111 | R112
|
|
| 59 | - | R113 | R114 | R115 | R116 | R117 | R118 | R119 | R120
|
|
| 60 | - | R121 | R122 | R123 | R124 | R125 | R126 | R127 | R128
|
|
| 61 | - deriving (Eq, Ord, Show, Enum, Bounded, Ix)
|
|
| 52 | +newtype StgReg
|
|
| 53 | + = StgReg Int
|
|
| 54 | + deriving (Eq,Ord,Ix)
|
|
| 55 | + |
|
| 56 | +pattern R1, R2, R3, R4 :: StgReg
|
|
| 57 | +pattern R1 = StgReg 0
|
|
| 58 | +pattern R2 = StgReg 1
|
|
| 59 | +pattern R3 = StgReg 2
|
|
| 60 | +pattern R4 = StgReg 3
|
|
| 62 | 61 | |
| 63 | 62 | -- | Stack registers
|
| 64 | 63 | data Special
|
| ... | ... | @@ -78,7 +77,7 @@ instance ToJExpr Special where |
| 78 | 77 | toJExpr Sp = hdStackPtr
|
| 79 | 78 | |
| 80 | 79 | instance ToJExpr StgReg where
|
| 81 | - toJExpr r = registers ! r
|
|
| 80 | + toJExpr r = register r
|
|
| 82 | 81 | |
| 83 | 82 | instance ToJExpr StgRet where
|
| 84 | 83 | toJExpr r = rets ! r
|
| ... | ... | @@ -99,25 +98,42 @@ r2 = toJExpr R2 |
| 99 | 98 | r3 = toJExpr R3
|
| 100 | 99 | r4 = toJExpr R4
|
| 101 | 100 | |
| 101 | +-- | 1-indexed register number (R1 has index 1)
|
|
| 102 | +regNumber :: StgReg -> Int
|
|
| 103 | +regNumber (StgReg r) = r+1
|
|
| 102 | 104 | |
| 103 | -jsRegToInt :: StgReg -> Int
|
|
| 104 | -jsRegToInt = (+1) . fromEnum
|
|
| 105 | +-- | StgReg from 1-indexed number
|
|
| 106 | +regFromNumber :: Int -> StgReg
|
|
| 107 | +regFromNumber r = assert (r >= 1) $ StgReg (r-1)
|
|
| 105 | 108 | |
| 106 | -intToJSReg :: Int -> StgReg
|
|
| 107 | -intToJSReg r = toEnum (r - 1)
|
|
| 109 | +regsFromTo :: StgReg -> StgReg -> [StgReg]
|
|
| 110 | +regsFromTo (StgReg x) (StgReg y) = map StgReg [x .. y]
|
|
| 108 | 111 | |
| 112 | +-- | Register expression from its 1-indexed index
|
|
| 109 | 113 | jsReg :: Int -> JStgExpr
|
| 110 | -jsReg r = toJExpr (intToJSReg r)
|
|
| 114 | +jsReg r = toJExpr (regFromNumber r)
|
|
| 115 | + |
|
| 116 | +minReg :: StgReg
|
|
| 117 | +minReg = R1
|
|
| 111 | 118 | |
| 112 | -maxReg :: Int
|
|
| 113 | -maxReg = jsRegToInt maxBound
|
|
| 119 | +maxReg :: StgReg
|
|
| 120 | +maxReg = regFromNumber maxBound
|
|
| 114 | 121 | |
| 115 | -minReg :: Int
|
|
| 116 | -minReg = jsRegToInt minBound
|
|
| 122 | +lowRegsCount :: Int
|
|
| 123 | +lowRegsCount = 31
|
|
| 124 | + |
|
| 125 | +maxLowReg :: StgReg
|
|
| 126 | +maxLowReg = regFromNumber lowRegsCount
|
|
| 127 | + |
|
| 128 | +-- | First register stored in h$regs array instead of having its own top-level
|
|
| 129 | +-- variable
|
|
| 130 | +minHighReg :: StgReg
|
|
| 131 | +minHighReg = case maxLowReg of
|
|
| 132 | + StgReg r -> StgReg (r+1)
|
|
| 117 | 133 | |
| 118 | 134 | -- | List of registers, starting from R1
|
| 119 | 135 | regsFromR1 :: [StgReg]
|
| 120 | -regsFromR1 = enumFrom R1
|
|
| 136 | +regsFromR1 = regsFromTo R1 maxReg ++ repeat (panic "StgToJS: code requires too many registers")
|
|
| 121 | 137 | |
| 122 | 138 | -- | List of registers, starting from R2
|
| 123 | 139 | regsFromR2 :: [StgReg]
|
| ... | ... | @@ -131,35 +147,59 @@ jsRegsFromR1 = fmap toJExpr regsFromR1 |
| 131 | 147 | jsRegsFromR2 :: [JStgExpr]
|
| 132 | 148 | jsRegsFromR2 = tail jsRegsFromR1
|
| 133 | 149 | |
| 150 | +-- | List of registers, starting from given reg as JExpr
|
|
| 151 | +jsRegsFrom :: StgReg -> [JStgExpr]
|
|
| 152 | +jsRegsFrom (StgReg n) = drop n jsRegsFromR1
|
|
| 153 | + |
|
| 154 | +-- | High register
|
|
| 155 | +highReg :: Int -> JStgExpr
|
|
| 156 | +highReg r = assert (r >= regNumber minHighReg) $ IdxExpr hdRegs (toJExpr (r - regNumber minHighReg))
|
|
| 157 | + |
|
| 158 | +-- | High register indexing with a JS expression
|
|
| 159 | +highReg_expr :: JStgExpr -> JStgExpr
|
|
| 160 | +highReg_expr r = IdxExpr hdRegs (r - toJExpr (regNumber minHighReg))
|
|
| 161 | + |
|
| 162 | + |
|
| 134 | 163 | ---------------------------------------------------
|
| 135 | 164 | -- caches
|
| 136 | 165 | ---------------------------------------------------
|
| 137 | 166 | |
| 138 | -lowRegs :: [Ident]
|
|
| 139 | -lowRegs = map reg_to_ident [R1 .. R31]
|
|
| 140 | - where reg_to_ident = name . mkFastString . (unpackFS hdStr ++) . map toLower . show
|
|
| 167 | +lowRegs :: [StgReg]
|
|
| 168 | +lowRegs = regsFromTo minReg maxLowReg
|
|
| 169 | + |
|
| 170 | +lowRegsIdents :: [Ident]
|
|
| 171 | +lowRegsIdents = map reg_to_ident lowRegs
|
|
| 172 | + where
|
|
| 173 | + -- low regs are named h$r1, h$r2, etc.
|
|
| 174 | + reg_to_ident r = name (mkFastString (unpackFS hdStr ++ "r" ++ show (regNumber r)))
|
|
| 141 | 175 | |
| 142 | 176 | retRegs :: [Ident]
|
| 143 | 177 | retRegs = [name . mkFastStringByteString
|
| 144 | 178 | $ hdB <> BSC.pack (map toLower $ show n) | n <- enumFrom Ret1]
|
| 145 | 179 | |
| 146 | --- cache JExpr representing StgReg
|
|
| 147 | -registers :: Array StgReg JStgExpr
|
|
| 148 | -registers = listArray (minBound, maxBound) (map (global . identFS) lowRegs ++ map regN [R32 .. R128])
|
|
| 149 | - where
|
|
| 150 | - regN :: StgReg -> JStgExpr
|
|
| 151 | - regN r = IdxExpr hdRegs (toJExpr (fromEnum r - 32))
|
|
| 152 | - |
|
| 153 | 180 | -- cache JExpr representing StgRet
|
| 154 | 181 | rets :: Array StgRet JStgExpr
|
| 155 | 182 | rets = listArray (minBound, maxBound) (map retN (enumFrom Ret1))
|
| 156 | 183 | where
|
| 157 | 184 | retN = global . mkFastString . (unpackFS hdStr ++) . map toLower . show
|
| 158 | 185 | |
| 159 | --- | Given a register, return the JS syntax object representing that register
|
|
| 160 | -register :: StgReg -> JStgExpr
|
|
| 161 | -register i = registers ! i
|
|
| 162 | - |
|
| 163 | 186 | -- | Given a register, return the JS syntax object representing that register
|
| 164 | 187 | foreignRegister :: StgRet -> JStgExpr
|
| 165 | 188 | foreignRegister i = rets ! i
|
| 189 | + |
|
| 190 | +-- | Given a register, return the JS syntax object representing that register
|
|
| 191 | +register :: StgReg -> JStgExpr
|
|
| 192 | +register i
|
|
| 193 | + | i <= maxCachedReg = register_cache ! i -- Expressions of common registers are cached.
|
|
| 194 | + | otherwise = make_high_reg i -- Expression of higher registers are made on the fly
|
|
| 195 | + |
|
| 196 | +maxCachedReg :: StgReg
|
|
| 197 | +maxCachedReg = regFromNumber 128
|
|
| 198 | + |
|
| 199 | +-- cache JExpr representing StgReg
|
|
| 200 | +register_cache :: Array StgReg JStgExpr
|
|
| 201 | +register_cache = listArray (minReg, maxCachedReg) (map (global . identFS) lowRegsIdents ++ map make_high_reg (regsFromTo minHighReg maxCachedReg))
|
|
| 202 | + |
|
| 203 | +-- | Make h$regs[XXX] expression for the register
|
|
| 204 | +make_high_reg :: StgReg -> JStgExpr
|
|
| 205 | +make_high_reg r = highReg (regNumber r) |
| ... | ... | @@ -54,7 +54,12 @@ import qualified Data.Bits as Bits |
| 54 | 54 | -- | The garbageCollector resets registers and result variables.
|
| 55 | 55 | garbageCollector :: JSM JStgStat
|
| 56 | 56 | garbageCollector = jBlock
|
| 57 | - [ jFunction' hdResetRegisters (return $ mconcat $ map resetRegister [minBound..maxBound])
|
|
| 57 | + [ jFunction' hdResetRegisters $ return $ mconcat
|
|
| 58 | + [ -- reset low registers explicitly
|
|
| 59 | + mconcat (map resetRegister lowRegs)
|
|
| 60 | + -- reset the whole h$regs array with h$regs.fill(null)
|
|
| 61 | + , toStat $ ApplExpr (hdRegs .^ "fill") [null_]
|
|
| 62 | + ]
|
|
| 58 | 63 | , jFunction' hdResetResultVars (return $ mconcat $ map resetResultVar [minBound..maxBound])
|
| 59 | 64 | ]
|
| 60 | 65 | |
| ... | ... | @@ -249,7 +254,7 @@ declRegs = do |
| 249 | 254 | loaders <- loadRegs
|
| 250 | 255 | return $
|
| 251 | 256 | mconcat [ hdRegsStr ||= toJExpr (JList [])
|
| 252 | - , mconcat (map declReg lowRegs)
|
|
| 257 | + , mconcat (map declReg lowRegsIdents)
|
|
| 253 | 258 | , getters_setters
|
| 254 | 259 | , loaders
|
| 255 | 260 | ]
|
| ... | ... | @@ -259,15 +264,15 @@ declRegs = do |
| 259 | 264 | -- | JS payload to define getters and setters on the registers.
|
| 260 | 265 | regGettersSetters :: JSM JStgStat
|
| 261 | 266 | regGettersSetters =
|
| 262 | - do setters <- jFunction (name hdGetRegStr) (\(MkSolo n) -> return $ SwitchStat n getRegCases mempty)
|
|
| 263 | - getters <- jFunction (name hdSetRegStr) (\(n,v) -> return $ SwitchStat n (setRegCases v) mempty)
|
|
| 267 | + do getters <- jFunction (name hdGetRegStr) (\(MkSolo n) -> return $ SwitchStat n getRegCases (defaultGetRegCase n))
|
|
| 268 | + setters <- jFunction (name hdSetRegStr) (\(n,v) -> return $ SwitchStat n (setRegCases v) (defaultSetRegCase n v))
|
|
| 264 | 269 | return $ setters <> getters
|
| 265 | 270 | where
|
| 266 | - getRegCases =
|
|
| 267 | - map (\r -> (toJExpr (jsRegToInt r) , returnS (toJExpr r))) regsFromR1
|
|
| 268 | - setRegCases :: JStgExpr -> [(JStgExpr,JStgStat)]
|
|
| 269 | - setRegCases v =
|
|
| 270 | - map (\r -> (toJExpr (jsRegToInt r), (toJExpr r |= toJExpr v) <> returnS undefined_)) regsFromR1
|
|
| 271 | + getRegCases = map (\r -> (toJExpr (regNumber r) , returnS (toJExpr r))) lowRegs
|
|
| 272 | + defaultGetRegCase n = returnS (highReg_expr n)
|
|
| 273 | + |
|
| 274 | + setRegCases v = map (\r -> (toJExpr (regNumber r), (toJExpr r |= v) <> BreakStat Nothing)) lowRegs
|
|
| 275 | + defaultSetRegCase n v = highReg_expr n |= v
|
|
| 271 | 276 | |
| 272 | 277 | -- | JS payload that defines the functions to load each register
|
| 273 | 278 | loadRegs :: JSM JStgStat
|
| ... | ... | @@ -69,12 +69,3 @@ stackFrameSize tgt f = |
| 69 | 69 | (tgt |= mask8 tag + 1) -- else set to mask'd tag + 1
|
| 70 | 70 | ]
|
| 71 | 71 | )) |
| 72 | - |
|
| 73 | - --------------------------------------------------------------------------------
|
|
| 74 | --- Register utilities
|
|
| 75 | ---------------------------------------------------------------------------------
|
|
| 76 | - |
|
| 77 | --- | Perform the computation 'f', on the range of registers bounded by 'start'
|
|
| 78 | --- and 'end'.
|
|
| 79 | -withRegs :: StgReg -> StgReg -> (StgReg -> JStgStat) -> JStgStat
|
|
| 80 | -withRegs start end f = mconcat $ fmap f [start..end] |
| ... | ... | @@ -256,4 +256,4 @@ test('T24893', normal, compile_and_run, ['-O']) |
| 256 | 256 | test('CCallConv', [req_c], compile_and_run, ['CCallConv_c.c'])
|
| 257 | 257 | test('T25364', normal, compile_and_run, [''])
|
| 258 | 258 | test('T26061', normal, compile_and_run, [''])
|
| 259 | -test('T26537', js_broken(26558), compile_and_run, ['-O2 -fregs-graph']) |
|
| 259 | +test('T26537', normal, compile_and_run, ['-O2 -fregs-graph']) |