Simon Peyton Jones pushed to branch wip/T26314 at Glasgow Haskell Compiler / GHC
Commits:
-
ca03226d
by Ben Gamari at 2025-08-18T13:43:20+00:00
-
783cd7d6
by Cheng Shao at 2025-08-18T20:13:14-04:00
-
58e46da9
by fendor at 2025-08-18T20:13:56-04:00
-
45dbfa23
by Cheng Shao at 2025-08-18T20:14:37-04:00
-
ebc187bc
by Simon Peyton Jones at 2025-08-19T14:24:42+01:00
7 changed files:
- compiler/GHC/StgToByteCode.hs
- compiler/GHC/Tc/Solver/Dict.hs
- compiler/GHC/Tc/Solver/Monad.hs
- compiler/GHC/Tc/Solver/Solve.hs
- configure.ac
- libffi-tarballs
- rts/Hash.c
Changes:
| ... | ... | @@ -84,11 +84,11 @@ import Data.Coerce (coerce) |
| 84 | 84 | #if MIN_VERSION_rts(1,0,3)
|
| 85 | 85 | import qualified Data.ByteString.Char8 as BS
|
| 86 | 86 | #endif
|
| 87 | -import Data.Map (Map)
|
|
| 88 | 87 | import Data.IntMap (IntMap)
|
| 89 | 88 | import qualified Data.Map as Map
|
| 90 | 89 | import qualified Data.IntMap as IntMap
|
| 91 | -import qualified GHC.Data.FiniteMap as Map
|
|
| 90 | +import GHC.Types.Unique.Map (UniqMap)
|
|
| 91 | +import qualified GHC.Types.Unique.Map as UniqMap
|
|
| 92 | 92 | import Data.Ord
|
| 93 | 93 | import Data.Either ( partitionEithers )
|
| 94 | 94 | |
| ... | ... | @@ -209,7 +209,7 @@ type StackDepth = ByteOff |
| 209 | 209 | |
| 210 | 210 | -- | Maps Ids to their stack depth. This allows us to avoid having to mess with
|
| 211 | 211 | -- it after each push/pop.
|
| 212 | -type BCEnv = Map Id StackDepth -- To find vars on the stack
|
|
| 212 | +type BCEnv = UniqMap Id StackDepth -- To find vars on the stack
|
|
| 213 | 213 | |
| 214 | 214 | {-
|
| 215 | 215 | ppBCEnv :: BCEnv -> SDoc
|
| ... | ... | @@ -379,7 +379,7 @@ schemeR_wrk fvs nm original_body (args, body) |
| 379 | 379 | sum_szsb_args = sum szsb_args
|
| 380 | 380 | -- Make a stack offset for each argument or free var -- they should
|
| 381 | 381 | -- appear contiguous in the stack, in order.
|
| 382 | - p_init = Map.fromList (zip all_args (mkStackOffsets 0 szsb_args))
|
|
| 382 | + p_init = UniqMap.listToUniqMap (zip all_args (mkStackOffsets 0 szsb_args))
|
|
| 383 | 383 | |
| 384 | 384 | -- make the arg bitmap
|
| 385 | 385 | bits = argBits platform (reverse (map (idArgRep platform) all_args))
|
| ... | ... | @@ -442,7 +442,7 @@ fvsToEnv :: BCEnv -> CgStgRhs -> [Id] |
| 442 | 442 | -- it, have to agree about this layout
|
| 443 | 443 | |
| 444 | 444 | fvsToEnv p rhs = [v | v <- dVarSetElems $ freeVarsOfRhs rhs,
|
| 445 | - v `Map.member` p]
|
|
| 445 | + v `UniqMap.elemUniqMap` p]
|
|
| 446 | 446 | |
| 447 | 447 | -- -----------------------------------------------------------------------------
|
| 448 | 448 | -- schemeE
|
| ... | ... | @@ -533,7 +533,7 @@ schemeE d s p (StgLet _xlet |
| 533 | 533 | alloc_code <- mkConAppCode d s p data_con args
|
| 534 | 534 | platform <- targetPlatform <$> getDynFlags
|
| 535 | 535 | let !d2 = d + wordSize platform
|
| 536 | - body_code <- schemeE d2 s (Map.insert x d2 p) body
|
|
| 536 | + body_code <- schemeE d2 s (UniqMap.addToUniqMap p x d2) body
|
|
| 537 | 537 | return (alloc_code `appOL` body_code)
|
| 538 | 538 | -- General case for let. Generates correct, if inefficient, code in
|
| 539 | 539 | -- all situations.
|
| ... | ... | @@ -557,7 +557,7 @@ schemeE d s p (StgLet _ext binds body) = do |
| 557 | 557 | -- after the closures have been allocated in the heap (but not
|
| 558 | 558 | -- filled in), and pointers to them parked on the stack.
|
| 559 | 559 | offsets = mkStackOffsets d (genericReplicate n_binds (wordSize platform))
|
| 560 | - p' = Map.insertList (zipEqual xs offsets) p
|
|
| 560 | + p' = UniqMap.addListToUniqMap p $ zipEqual xs offsets
|
|
| 561 | 561 | d' = d + wordsToBytes platform n_binds
|
| 562 | 562 | |
| 563 | 563 | -- ToDo: don't build thunks for things with no free variables
|
| ... | ... | @@ -1180,7 +1180,7 @@ doCase d s p scrut bndr alts |
| 1180 | 1180 | |
| 1181 | 1181 | -- Env in which to compile the alts, not including
|
| 1182 | 1182 | -- any vars bound by the alts themselves
|
| 1183 | - p_alts = Map.insert bndr d_bndr p
|
|
| 1183 | + p_alts = UniqMap.addToUniqMap p bndr d_bndr
|
|
| 1184 | 1184 | |
| 1185 | 1185 | bndr_ty = idType bndr
|
| 1186 | 1186 | isAlgCase = isAlgType bndr_ty
|
| ... | ... | @@ -1208,12 +1208,11 @@ doCase d s p scrut bndr alts |
| 1208 | 1208 | |
| 1209 | 1209 | stack_bot = d_alts
|
| 1210 | 1210 | |
| 1211 | - p' = Map.insertList
|
|
| 1211 | + p' = UniqMap.addListToUniqMap p_alts
|
|
| 1212 | 1212 | [ (arg, tuple_start -
|
| 1213 | 1213 | wordsToBytes platform (nativeCallSize call_info) +
|
| 1214 | 1214 | offset)
|
| 1215 | 1215 | | (NonVoid arg, offset) <- args_offsets]
|
| 1216 | - p_alts
|
|
| 1217 | 1216 | in do
|
| 1218 | 1217 | rhs_code <- schemeE stack_bot s p' rhs
|
| 1219 | 1218 | return (NoDiscr, rhs_code)
|
| ... | ... | @@ -1227,10 +1226,9 @@ doCase d s p scrut bndr alts |
| 1227 | 1226 | stack_bot = d_alts + wordsToBytes platform size
|
| 1228 | 1227 | |
| 1229 | 1228 | -- convert offsets from Sp into offsets into the virtual stack
|
| 1230 | - p' = Map.insertList
|
|
| 1229 | + p' = UniqMap.addListToUniqMap p_alts
|
|
| 1231 | 1230 | [ (arg, stack_bot - ByteOff offset)
|
| 1232 | 1231 | | (NonVoid arg, offset) <- args_offsets ]
|
| 1233 | - p_alts
|
|
| 1234 | 1232 | |
| 1235 | 1233 | in do
|
| 1236 | 1234 | massert isAlgCase
|
| ... | ... | @@ -1312,12 +1310,13 @@ doCase d s p scrut bndr alts |
| 1312 | 1310 | -- NB: unboxed tuple cases bind the scrut binder to the same offset
|
| 1313 | 1311 | -- as one of the alt binders, so we have to remove any duplicates here:
|
| 1314 | 1312 | -- 'toAscList' takes care of sorting the result, which was previously done after the application of 'filter'.
|
| 1315 | - rel_slots = IntSet.toAscList $ IntSet.fromList $ Map.elems $ Map.mapMaybeWithKey spread p
|
|
| 1316 | - spread id offset | isUnboxedTupleType (idType id) ||
|
|
| 1317 | - isUnboxedSumType (idType id) = Nothing
|
|
| 1318 | - | isFollowableArg (idArgRep platform id) = Just (fromIntegral rel_offset)
|
|
| 1319 | - | otherwise = Nothing
|
|
| 1320 | - where rel_offset = bytesToWords platform (d - offset)
|
|
| 1313 | + rel_slots = IntSet.toAscList $ UniqMap.nonDetFoldUniqMap go IntSet.empty p
|
|
| 1314 | + go (var, offset) !acc
|
|
| 1315 | + | isUnboxedTupleType (idType var) || isUnboxedSumType (idType var)
|
|
| 1316 | + = acc
|
|
| 1317 | + | isFollowableArg (idArgRep platform var)
|
|
| 1318 | + = fromIntegral (bytesToWords platform (d - offset)) `IntSet.insert` acc
|
|
| 1319 | + | otherwise = acc
|
|
| 1321 | 1320 | |
| 1322 | 1321 | bitmap = intsToReverseBitmap platform bitmap_size' pointers
|
| 1323 | 1322 | |
| ... | ... | @@ -2546,7 +2545,7 @@ instance Outputable Discr where |
| 2546 | 2545 | |
| 2547 | 2546 | |
| 2548 | 2547 | lookupBCEnv_maybe :: Id -> BCEnv -> Maybe ByteOff
|
| 2549 | -lookupBCEnv_maybe = Map.lookup
|
|
| 2548 | +lookupBCEnv_maybe v env = UniqMap.lookupUniqMap env v
|
|
| 2550 | 2549 | |
| 2551 | 2550 | idSizeW :: Platform -> Id -> WordOff
|
| 2552 | 2551 | idSizeW platform = WordOff . argRepSizeW platform . idArgRep platform
|
| ... | ... | @@ -588,22 +588,24 @@ solving fails and we use the superclass of C: |
| 588 | 588 | The moving parts are relatively simple:
|
| 589 | 589 | |
| 590 | 590 | * To attempt to solve the constraint completely, we just recursively
|
| 591 | - call the constraint solver. See the use of `tryTcS` in
|
|
| 591 | + call the constraint solver. See the use of `tryShortCutTcS` in
|
|
| 592 | 592 | `tcShortCutSolver`.
|
| 593 | 593 | |
| 594 | -* When this attempted recursive solving, we set a special mode
|
|
| 595 | - `TcSShortCut`, which signals that we are trying to solve using only
|
|
| 596 | - top-level instances. We switch on `TcSShortCut` mode in
|
|
| 597 | - `tryShortCutSolver`.
|
|
| 594 | +* When this attempted recursive solving, in `tryShortCutTcS`, we
|
|
| 595 | + - start with an empty inert set: no Givens and no Wanteds
|
|
| 596 | + - set a special mode `TcSShortCut`, which signals that we are trying to solve
|
|
| 597 | + using only top-level instances.
|
|
| 598 | 598 | |
| 599 | -* When in TcSShortCut mode, we behave specially in a few places:
|
|
| 600 | - - `tryInertDicts`, where we would otherwise look for a Given to solve our Wanted
|
|
| 601 | - - `GHC.Tc.Solver.Monad.lookupInertDict` similarly
|
|
| 602 | - - `noMatchableGivenDicts`, which also consults the Givens
|
|
| 603 | - - `matchLocalInst`, which would otherwise consult Given quantified constraints
|
|
| 604 | - - `GHC.Tc.Solver.Instance.Class.matchInstEnv`: when short-cut solving, don't
|
|
| 605 | - pick overlappable top-level instances
|
|
| 606 | - - `GHC.Tc.Solver.Solve.runTcPluginsWanted`: don't pass any Givens to the plugin
|
|
| 599 | +* When in TcSShortCut mode, since there are no Givens we can short-circuit;
|
|
| 600 | + these are all just optimisations:
|
|
| 601 | + - `tryInertDicts`
|
|
| 602 | + - `GHC.Tc.Solver.Monad.lookupInertDict`
|
|
| 603 | + - `noMatchableGivenDicts`
|
|
| 604 | + - `matchLocalInst`
|
|
| 605 | + - `GHC.Tc.Solver.Solve.runTcPluginsWanted`
|
|
| 606 | + |
|
| 607 | +* In `GHC.Tc.Solver.Instance.Class.matchInstEnv`: when short-cut solving,
|
|
| 608 | + don't pick overlappable top-level instances
|
|
| 607 | 609 | |
| 608 | 610 | Some wrinkles:
|
| 609 | 611 | |
| ... | ... | @@ -770,14 +772,14 @@ tryInertDicts dict_ct |
| 770 | 772 | |
| 771 | 773 | try_inert_dicts :: TcSMode -> InertCans -> DictCt -> TcS (StopOrContinue ())
|
| 772 | 774 | try_inert_dicts mode inerts dict_w@(DictCt { di_ev = ev_w, di_cls = cls, di_tys = tys })
|
| 773 | - | not (mode == TcSShortCut) -- Ignore the inerts (esp Givens) in short-cut mode
|
|
| 774 | - -- See Note [Shortcut solving]
|
|
| 775 | + | not (mode == TcSShortCut) -- Optimisation: ignore the inerts (esp Givens) in
|
|
| 776 | + -- short-cut mode. See Note [Shortcut solving]
|
|
| 775 | 777 | , Just dict_i <- lookupInertDict inerts cls tys
|
| 776 | 778 | , let ev_i = dictCtEvidence dict_i
|
| 777 | 779 | loc_i = ctEvLoc ev_i
|
| 778 | 780 | loc_w = ctEvLoc ev_w
|
| 779 | 781 | = -- There is a matching dictionary in the inert set
|
| 780 | - do { -- First to try to solve it /completely/ from top level instances
|
|
| 782 | + do { -- For a Wanted, first to try to solve it /completely/ from top level instances
|
|
| 781 | 783 | -- See Note [Shortcut solving]
|
| 782 | 784 | ; short_cut_worked <- tryShortCutSolver (isGiven ev_i) dict_w
|
| 783 | 785 | |
| ... | ... | @@ -833,11 +835,7 @@ tryShortCutSolver try_short_cut dict_w@(DictCt { di_ev = ev_w }) |
| 833 | 835 | , gopt Opt_SolveConstantDicts dflags
|
| 834 | 836 | -- Enabled by the -fsolve-constant-dicts flag
|
| 835 | 837 | |
| 836 | - -> tryTcS $ -- tryTcS tries to completely solve some contraints
|
|
| 837 | - -- Inherit the current solved_dicts, so that one invocation of
|
|
| 838 | - -- tryShortCutSolver can benefit from the work of earlier invocations
|
|
| 839 | - -- See wrinkle (SCS3) of Note [Shortcut solving]
|
|
| 840 | - setTcSMode TcSShortCut $
|
|
| 838 | + -> tryShortCutTcS $ -- tryTcS tries to completely solve some contraints
|
|
| 841 | 839 | do { residual <- solveSimpleWanteds (unitBag (CDictCan dict_w))
|
| 842 | 840 | ; return (isEmptyBag residual) }
|
| 843 | 841 | |
| ... | ... | @@ -977,7 +975,7 @@ matchClassInst dflags mode inerts clas tys loc |
| 977 | 975 | noMatchableGivenDicts :: TcSMode -> InertSet -> CtLoc -> Class -> [TcType] -> Bool
|
| 978 | 976 | noMatchableGivenDicts mode inerts@(IS { inert_cans = inert_cans }) loc_w clas tys
|
| 979 | 977 | | TcSShortCut <- mode
|
| 980 | - = True -- In TcSShortCut mode we behave as if there were no Givens at all
|
|
| 978 | + = True -- Optimisation: in TcSShortCut mode there are no Givens
|
|
| 981 | 979 | | otherwise
|
| 982 | 980 | = not $ anyBag matchable_given $
|
| 983 | 981 | findDictsByClass (inert_dicts inert_cans) clas
|
| ... | ... | @@ -1153,8 +1151,7 @@ matchLocalInst :: TcPredType -> CtLoc -> TcS ClsInstResult |
| 1153 | 1151 | -- Look up the predicate in Given quantified constraints,
|
| 1154 | 1152 | -- which are effectively just local instance declarations.
|
| 1155 | 1153 | matchLocalInst body_pred loc
|
| 1156 | - = do { -- In TcSShortCut mode we do not look at Givens;
|
|
| 1157 | - -- c.f. tryInertDicts
|
|
| 1154 | + = do { -- Optimisation: in TcSShortCut mode there are no Givens (c.f. tryInertDicts)
|
|
| 1158 | 1155 | mode <- getTcSMode
|
| 1159 | 1156 | ; case mode of
|
| 1160 | 1157 | { TcSShortCut -> do { traceTcS "matchLocalInst:TcSShortCut" (ppr body_pred)
|
| ... | ... | @@ -19,7 +19,7 @@ module GHC.Tc.Solver.Monad ( |
| 19 | 19 | runTcS, runTcSEarlyAbort, runTcSWithEvBinds, runTcSInerts,
|
| 20 | 20 | failTcS, warnTcS, addErrTcS, wrapTcS, ctLocWarnTcS,
|
| 21 | 21 | runTcSEqualities,
|
| 22 | - nestTcS, nestImplicTcS, tryTcS,
|
|
| 22 | + nestTcS, nestImplicTcS, tryShortCutTcS,
|
|
| 23 | 23 | setEvBindsTcS, setTcLevelTcS,
|
| 24 | 24 | emitFunDepWanteds,
|
| 25 | 25 | |
| ... | ... | @@ -1259,20 +1259,31 @@ nestTcS (TcS thing_inside) |
| 1259 | 1259 | |
| 1260 | 1260 | ; return res }
|
| 1261 | 1261 | |
| 1262 | -tryTcS :: TcS Bool -> TcS Bool
|
|
| 1262 | +tryShortCutTcS :: TcS Bool -> TcS Bool
|
|
| 1263 | 1263 | -- Like nestTcS, but
|
| 1264 | --- (a) be a no-op if the nested computation returns Nothing
|
|
| 1264 | +-- (a) be a no-op if the nested computation returns False
|
|
| 1265 | 1265 | -- (b) if (but only if) success, propagate nested bindings to the caller
|
| 1266 | 1266 | -- Use only by the short-cut solver;
|
| 1267 | 1267 | -- see Note [Shortcut solving] in GHC.Tc.Solver.Dict
|
| 1268 | -tryTcS (TcS thing_inside)
|
|
| 1268 | +tryShortCutTcS (TcS thing_inside)
|
|
| 1269 | 1269 | = TcS $ \ env@(TcSEnv { tcs_inerts = inerts_var
|
| 1270 | 1270 | , tcs_ev_binds = old_ev_binds_var }) ->
|
| 1271 | - do { old_inerts <- TcM.readTcRef inerts_var
|
|
| 1272 | - ; new_inert_var <- TcM.newTcRef old_inerts
|
|
| 1271 | + do { -- Initialise a fresh inert set, with no Givens and no Wanteds
|
|
| 1272 | + -- (i.e. empty `inert_cans`)
|
|
| 1273 | + -- But inherit all the InertSet cache fields; in particular
|
|
| 1274 | + -- * the given_eq_lvl, so we don't accidentally unify a
|
|
| 1275 | + -- unification variable from outside a GADT match
|
|
| 1276 | + -- * the `solved_dicts`; see wrinkle (SCS3) of Note [Shortcut solving]
|
|
| 1277 | + -- * the `famapp_cache`; similarly
|
|
| 1278 | + old_inerts <- TcM.readTcRef inerts_var
|
|
| 1279 | + ; let given_eq_lvl = inert_given_eq_lvl (inert_cans old_inerts)
|
|
| 1280 | + new_inerts = old_inerts { inert_cans = emptyInertCans given_eq_lvl }
|
|
| 1281 | + ; new_inert_var <- TcM.newTcRef new_inerts
|
|
| 1282 | + |
|
| 1273 | 1283 | ; new_wl_var <- TcM.newTcRef emptyWorkList
|
| 1274 | 1284 | ; new_ev_binds_var <- TcM.cloneEvBindsVar old_ev_binds_var
|
| 1275 | - ; let nest_env = env { tcs_ev_binds = new_ev_binds_var
|
|
| 1285 | + ; let nest_env = env { tcs_mode = TcSShortCut
|
|
| 1286 | + , tcs_ev_binds = new_ev_binds_var
|
|
| 1276 | 1287 | , tcs_inerts = new_inert_var
|
| 1277 | 1288 | , tcs_worklist = new_wl_var }
|
| 1278 | 1289 |
| ... | ... | @@ -1679,8 +1679,9 @@ runTcPluginsWanted wanted |
| 1679 | 1679 | ; if null solvers then return (False, wanted) else
|
| 1680 | 1680 | |
| 1681 | 1681 | do { -- Find the set of Givens to give to the plugin.
|
| 1682 | - -- If TcSMode = TcSShortCut, we are solving with
|
|
| 1683 | - -- no Givens so don't return any (#26258)!
|
|
| 1682 | + -- Optimisation: if TcSMode = TcSShortCut, we are solving with
|
|
| 1683 | + -- no Givens so don't bother to look (#26258 was a bug in an earlier
|
|
| 1684 | + -- version when we left the Givens in the inert set)
|
|
| 1684 | 1685 | -- See Note [Shortcut solving] in GHC.Tc.Solver.Dict
|
| 1685 | 1686 | mode <- getTcSMode
|
| 1686 | 1687 | ; given <- case mode of
|
| ... | ... | @@ -536,7 +536,7 @@ AC_SUBST(InstallNameToolCmd) |
| 536 | 536 | # versions of LLVM simultaneously, but that stopped working around
|
| 537 | 537 | # 3.5/3.6 release of LLVM.
|
| 538 | 538 | LlvmMinVersion=13 # inclusive
|
| 539 | -LlvmMaxVersion=20 # not inclusive
|
|
| 539 | +LlvmMaxVersion=21 # not inclusive
|
|
| 540 | 540 | AC_SUBST([LlvmMinVersion])
|
| 541 | 541 | AC_SUBST([LlvmMaxVersion])
|
| 542 | 542 |
| 1 | -Subproject commit a5480d7e7f86a9bb5b44dd1156a92f69f7c185ec |
|
| 1 | +Subproject commit 7c51059557b68d29820a0a87cebfa6fe73c8adf5 |
| ... | ... | @@ -81,7 +81,7 @@ hashWord(const HashTable *table, StgWord key) |
| 81 | 81 | int bucket;
|
| 82 | 82 | |
| 83 | 83 | /* Strip the boring zero bits */
|
| 84 | - key >>= sizeof(StgWord);
|
|
| 84 | + key /= sizeof(StgWord);
|
|
| 85 | 85 | |
| 86 | 86 | /* Mod the size of the hash table (a power of 2) */
|
| 87 | 87 | bucket = key & table->mask1;
|