
[Git][ghc/ghc][master] 2 commits: QuickLook: do a shape test before unifying
by Marge Bot (@marge-bot) 21 May '25
by Marge Bot (@marge-bot) 21 May '25
21 May '25
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
67a177b4 by sheaf at 2025-05-21T10:17:04-04:00
QuickLook: do a shape test before unifying
This commit ensures we do a shape test before unifying. This ensures
we don't try to unify a TyVarTv with a non-tyvar, e.g.
alpha[tyv] := Int
On the way, we refactor simpleUnifyCheck:
1. Move the checkTopShape check into simpleUnifyCheck
2. Refactors simpleUnifyCheck to return a value of the new type
SimpleUnifyResult type. Now, simpleUnifyCheck returns "can unify",
"cannot unify" or "dunno" (with "cannot unify" being the new result
it can return). Now:
- touchabilityTest is included; it it fails we return "cannot unify"
- checkTopShape now returns "cannot unify" instead of "dunno" upon failure
3. Move the call to simpleUnifyCheck out of checkTouchableTyVarEq.
After that, checkTouchableTyVarEq becames a simple call to
checkTyEqRhs, so we inline it.
This allows the logic in canEqCanLHSFinish_try_unification to be simplified.
In particular, we now avoid calling 'checkTopShape' twice.
Two further changes suggested by Simon were also implemented:
- In canEqCanLHSFinish, if checkTyEqRhs returns PuFail with
'do_not_prevent_rewriting', we now **continue with this constraint**.
This allows us to use the constraint for rewriting.
- checkTyEqRhs now has a top-level check to avoid flattening a tyfam app
in a top-level equality of the form alpha ~ F tys, as this is
going around in circles. This simplifies the implementation without
any change in behaviour.
Fixes #25950
Fixes #26030
- - - - -
4020972c by sheaf at 2025-05-21T10:17:04-04:00
FixedRuntimeRepError: omit unhelpful explanation
This commit tweaks the FixedRuntimeRepError case of pprTcSolverReportMsg,
to avoid including an explanation which refers to a type variable that
appears nowhere else.
For example, the old error message could look like the following:
The pattern binding does not have a fixed runtime representation.
Its type is:
T :: TYPE R
Cannot unify ‘R’ with the type variable ‘c0’
because the former is not a concrete ‘RuntimeRep’.
With this commit, we now omit the last two lines, because the concrete
type variable (here 'c0') does not appear in the type displayed to the
user (here 'T :: TYPE R').
- - - - -
15 changed files:
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/Solver/Equality.hs
- compiler/GHC/Tc/Solver/Monad.hs
- compiler/GHC/Tc/Types/Constraint.hs
- compiler/GHC/Tc/Utils/Unify.hs
- testsuite/tests/rep-poly/RepPolyTuple4.stderr
- testsuite/tests/rep-poly/T19709b.stderr
- testsuite/tests/rep-poly/T23903.stderr
- testsuite/tests/simplCore/should_compile/simpl017.stderr
- + testsuite/tests/typecheck/should_compile/T26030.hs
- testsuite/tests/typecheck/should_compile/all.T
- + testsuite/tests/typecheck/should_fail/T25950.hs
- + testsuite/tests/typecheck/should_fail/T25950.stderr
- testsuite/tests/typecheck/should_fail/all.T
Changes:
=====================================
compiler/GHC/Tc/Errors/Ppr.hs
=====================================
@@ -4043,9 +4043,13 @@ pprTcSolverReportMsg _ (FixedRuntimeRepError frr_origs) =
Nothing -> empty
Just o -> other_context o
, case mb_not_conc of
- Nothing -> empty
- Just (conc_tv, not_conc) ->
- unsolved_concrete_eq_explanation conc_tv not_conc ]
+ Just (conc_tv, not_conc)
+ | conc_tv `elemVarSet` tyCoVarsOfType ty
+ -- Only show this message if 'conc_tv' appears somewhere
+ -- in the type, otherwise it's not helpful.
+ -> unsolved_concrete_eq_explanation conc_tv not_conc
+ _ -> empty
+ ]
-- Don't print out the type (only the kind), if the type includes
-- a confusing cast, unless the user passed -fprint-explicit-coercions.
=====================================
compiler/GHC/Tc/Gen/App.hs
=====================================
@@ -2066,18 +2066,22 @@ qlUnify ty1 ty2
= go_flexi1 kappa ty2
go_flexi1 kappa ty2 -- ty2 is zonked
- | -- See Note [QuickLook unification] (UQL1)
- simpleUnifyCheck UC_QuickLook kappa ty2
- = do { co <- unifyKind (Just (TypeThing ty2)) ty2_kind kappa_kind
- -- unifyKind: see (UQL2) in Note [QuickLook unification]
- -- and (MIV2) in Note [Monomorphise instantiation variables]
- ; let ty2' = mkCastTy ty2 co
- ; traceTc "qlUnify:update" $
- ppr kappa <+> text ":=" <+> ppr ty2
- ; liftZonkM $ writeMetaTyVar kappa ty2' }
-
- | otherwise
- = return () -- Occurs-check or forall-bound variable
+ = do { cur_lvl <- getTcLevel
+ -- See Note [Unification preconditions], (UNTOUCHABLE) wrinkles
+ -- Here we are in the TcM monad, which does not track enclosing
+ -- Given equalities; so for quick-look unification we conservatively
+ -- treat /any/ level outside this one as untouchable. Hence cur_lvl.
+ ; case simpleUnifyCheck UC_QuickLook cur_lvl kappa ty2 of
+ SUC_CanUnify ->
+ do { co <- unifyKind (Just (TypeThing ty2)) ty2_kind kappa_kind
+ -- unifyKind: see (UQL2) in Note [QuickLook unification]
+ -- and (MIV2) in Note [Monomorphise instantiation variables]
+ ; let ty2' = mkCastTy ty2 co
+ ; traceTc "qlUnify:update" $
+ ppr kappa <+> text ":=" <+> ppr ty2
+ ; liftZonkM $ writeMetaTyVar kappa ty2' }
+ _ -> return () -- e.g. occurs-check or forall-bound variable
+ }
where
kappa_kind = tyVarKind kappa
ty2_kind = typeKind ty2
=====================================
compiler/GHC/Tc/Solver/Equality.hs
=====================================
@@ -1,5 +1,6 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
module GHC.Tc.Solver.Equality(
@@ -1888,81 +1889,102 @@ canEqCanLHSFinish_try_unification ev eq_rel swapped lhs rhs
| CtWanted wev <- ev -- See Note [Do not unify Givens]
, NomEq <- eq_rel -- See Note [Do not unify representational equalities]
, wantedCtHasNoRewriters wev -- See Note [Unify only if the rewriter set is empty]
- , TyVarLHS tv <- lhs
- = do { given_eq_lvl <- getInnermostGivenEqLevel
- ; if not (touchabilityAndShapeTest given_eq_lvl tv rhs)
- then if | Just can_rhs <- canTyFamEqLHS_maybe rhs
- -> swapAndFinish ev eq_rel swapped (mkTyVarTy tv) can_rhs
- -- See Note [Orienting TyVarLHS/TyFamLHS]
-
- | otherwise
- -> canEqCanLHSFinish_no_unification ev eq_rel swapped lhs rhs
- else
-
- -- We have a touchable unification variable on the left
- do { check_result <- checkTouchableTyVarEq ev tv rhs
- ; case check_result of {
- PuFail reason
+ , TyVarLHS lhs_tv <- lhs
+ = do { given_eq_lvl <- getInnermostGivenEqLevel
+ ; case simpleUnifyCheck UC_Solver given_eq_lvl lhs_tv rhs of
+ SUC_CanUnify ->
+ unify lhs_tv (mkReflRedn Nominal rhs)
+ SUC_CannotUnify
| Just can_rhs <- canTyFamEqLHS_maybe rhs
- -> swapAndFinish ev eq_rel swapped (mkTyVarTy tv) can_rhs
- -- Swap back: see Note [Orienting TyVarLHS/TyFamLHS]
-
- | reason `cterHasOnlyProblems` do_not_prevent_rewriting
- -> canEqCanLHSFinish_no_unification ev eq_rel swapped lhs rhs
-
+ -> swap_and_finish lhs_tv can_rhs -- See Note [Orienting TyVarLHS/TyFamLHS]
| otherwise
- -> tryIrredInstead reason ev eq_rel swapped lhs rhs ;
-
- PuOK _ rhs_redn ->
-
- -- Success: we can solve by unification
- do { -- In the common case where rhs_redn is Refl, we don't need to rewrite
- -- the evidence, even if swapped=IsSwapped. Suppose the original was
- -- [W] co : Int ~ alpha
- -- We unify alpha := Int, and set co := <Int>. No need to
- -- swap to co = sym co'
- -- co' = <Int>
- new_ev <- if isReflCo (reductionCoercion rhs_redn)
- then return ev
- else rewriteEqEvidence emptyRewriterSet ev swapped
- (mkReflRedn Nominal (mkTyVarTy tv)) rhs_redn
-
- ; let tv_ty = mkTyVarTy tv
- final_rhs = reductionReducedType rhs_redn
-
- ; traceTcS "Sneaky unification:" $
- vcat [text "Unifies:" <+> ppr tv <+> text ":=" <+> ppr final_rhs,
- text "Coercion:" <+> pprEq tv_ty final_rhs,
- text "Left Kind is:" <+> ppr (typeKind tv_ty),
- text "Right Kind is:" <+> ppr (typeKind final_rhs) ]
-
- -- Update the unification variable itself
- ; unifyTyVar tv final_rhs
-
- -- Provide Refl evidence for the constraint
- -- Ignore 'swapped' because it's Refl!
- ; setEvBindIfWanted new_ev EvCanonical $
- evCoercion (mkNomReflCo final_rhs)
-
- -- Kick out any constraints that can now be rewritten
- ; kickOutAfterUnification [tv]
-
- ; return (Stop new_ev (text "Solved by unification")) }}}}
-
+ -> finish_no_unify
+ SUC_NotSure ->
+ -- We have a touchable unification variable on the left,
+ -- and the top-shape check succeeded. These are both guaranteed
+ -- by the fact that simpleUnifyCheck did not return SUC_CannotUnify.
+ do { let flags = unifyingLHSMetaTyVar_TEFTask ev lhs_tv
+ ; check_result <- wrapTcS (checkTyEqRhs flags rhs)
+ ; case check_result of
+ PuOK cts rhs_redn ->
+ do { emitWork cts
+ ; unify lhs_tv rhs_redn }
+ PuFail reason
+ | Just can_rhs <- canTyFamEqLHS_maybe rhs
+ -> swap_and_finish lhs_tv can_rhs -- See Note [Orienting TyVarLHS/TyFamLHS]
+ | reason `cterHasOnlyProblems` do_not_prevent_rewriting
+ ->
+ -- ContinueWith, to allow using this constraint for
+ -- rewriting (e.g. alpha[2] ~ beta[3]).
+ do { let role = eqRelRole eq_rel
+ ; new_ev <- rewriteEqEvidence emptyRewriterSet ev swapped
+ (mkReflRedn role (canEqLHSType lhs))
+ (mkReflRedn role rhs)
+ ; continueWith $ Right $
+ EqCt { eq_ev = new_ev, eq_eq_rel = eq_rel
+ , eq_lhs = lhs , eq_rhs = rhs }
+ }
+ | otherwise
+ -> try_irred reason
+ }
+ }
-- Otherwise unification is off the table
| otherwise
- = canEqCanLHSFinish_no_unification ev eq_rel swapped lhs rhs
+ = finish_no_unify
where
- -- Some problems prevent /unification/ but not /rewriting/
- -- Skolem-escape: if we have [W] alpha[2] ~ Maybe b[3]
- -- we can't unify (skolem-escape); but it /is/ canonical,
- -- and hence we /can/ use it for rewriting
- -- Concrete-ness: alpha[conc] ~ b[sk]
- -- We can use it to rewrite; we still have to solve the original
- do_not_prevent_rewriting :: CheckTyEqResult
- do_not_prevent_rewriting = cteProblem cteSkolemEscape S.<>
- cteProblem cteConcrete
+ -- We can't unify, but this equality can go in the inert set
+ -- and be used to rewrite other constraints.
+ finish_no_unify =
+ canEqCanLHSFinish_no_unification ev eq_rel swapped lhs rhs
+
+ -- We can't unify, and this equality should not be used to rewrite
+ -- other constraints (e.g. because it has an occurs check).
+ -- So add it to the inert Irreds.
+ try_irred reason =
+ tryIrredInstead reason ev eq_rel swapped lhs rhs
+
+ -- We can't unify as-is, and want to flip the equality around.
+ -- Example: alpha ~ F tys, flip it around to become the canonical
+ -- equality f tys ~ alpha.
+ swap_and_finish tv can_rhs =
+ swapAndFinish ev eq_rel swapped (mkTyVarTy tv) can_rhs
+
+ -- We can unify; go ahead and do so.
+ unify tv rhs_redn =
+
+ do { -- In the common case where rhs_redn is Refl, we don't need to rewrite
+ -- the evidence, even if swapped=IsSwapped. Suppose the original was
+ -- [W] co : Int ~ alpha
+ -- We unify alpha := Int, and set co := <Int>. No need to
+ -- swap to co = sym co'
+ -- co' = <Int>
+ new_ev <- if isReflCo (reductionCoercion rhs_redn)
+ then return ev
+ else rewriteEqEvidence emptyRewriterSet ev swapped
+ (mkReflRedn Nominal (mkTyVarTy tv)) rhs_redn
+
+ ; let tv_ty = mkTyVarTy tv
+ final_rhs = reductionReducedType rhs_redn
+
+ ; traceTcS "Sneaky unification:" $
+ vcat [text "Unifies:" <+> ppr tv <+> text ":=" <+> ppr final_rhs,
+ text "Coercion:" <+> pprEq tv_ty final_rhs,
+ text "Left Kind is:" <+> ppr (typeKind tv_ty),
+ text "Right Kind is:" <+> ppr (typeKind final_rhs) ]
+
+ -- Update the unification variable itself
+ ; unifyTyVar tv final_rhs
+
+ -- Provide Refl evidence for the constraint
+ -- Ignore 'swapped' because it's Refl!
+ ; setEvBindIfWanted new_ev EvCanonical $
+ evCoercion (mkNomReflCo final_rhs)
+
+ -- Kick out any constraints that can now be rewritten
+ ; kickOutAfterUnification [tv]
+
+ ; return (Stop new_ev (text "Solved by unification")) }
---------------------------
-- Unification is off the table
@@ -1989,6 +2011,17 @@ canEqCanLHSFinish_no_unification ev eq_rel swapped lhs rhs
-- -> swapAndFinish ev eq_rel swapped lhs_ty can_rhs
-- | otherwise
+ | reason `cterHasOnlyProblems` do_not_prevent_rewriting
+ -> do { let role = eqRelRole eq_rel
+ ; new_ev <- rewriteEqEvidence emptyRewriterSet ev swapped
+ (mkReflRedn role (canEqLHSType lhs))
+ (mkReflRedn role rhs)
+ ; continueWith $ Right $
+ EqCt { eq_ev = new_ev, eq_eq_rel = eq_rel
+ , eq_lhs = lhs , eq_rhs = rhs }
+ }
+
+ | otherwise
-> tryIrredInstead reason ev eq_rel swapped lhs rhs
PuOK _ rhs_redn
@@ -2005,6 +2038,18 @@ canEqCanLHSFinish_no_unification ev eq_rel swapped lhs rhs
, eq_lhs = lhs
, eq_rhs = reductionReducedType rhs_redn } } }
+-- | Some problems prevent /unification/ but not /rewriting/:
+--
+-- Skolem-escape: if we have [W] alpha[2] ~ Maybe b[3]
+-- we can't unify (skolem-escape); but it /is/ canonical,
+-- and hence we /can/ use it for rewriting
+--
+-- Concrete-ness: alpha[conc] ~ b[sk]
+-- We can use it to rewrite; we still have to solve the original
+do_not_prevent_rewriting :: CheckTyEqResult
+do_not_prevent_rewriting = cteProblem cteSkolemEscape S.<>
+ cteProblem cteConcrete
+
----------------------
swapAndFinish :: CtEvidence -> EqRel -> SwapFlag
-> TcType -> CanEqLHS -- ty ~ F tys
@@ -2297,8 +2342,9 @@ and we turn this into
[W] Arg alpha ~ cbv1
[W] Res alpha ~ cbv2
-where cbv1 and cbv2 are fresh TauTvs. This is actually done by `break_wanted`
-in `GHC.Tc.Solver.Monad.checkTouchableTyVarEq`.
+where cbv1 and cbv2 are fresh TauTvs. This is actually done within checkTyEqRhs,
+called within canEqCanLHSFinish_try_unification, which will use the BreakWanted
+FamAppBreaker.
Why TauTvs? See [Why TauTvs] below.
@@ -2307,7 +2353,7 @@ directly instead of calling wrapUnifierTcS. (Otherwise, we'd end up
unifying cbv1 and cbv2 immediately, achieving nothing.) Next, we
unify alpha := cbv1 -> cbv2, having eliminated the occurs check. This
unification happens immediately following a successful call to
-checkTouchableTyVarEq, in canEqCanLHSFinish_try_unification.
+checkTyEqRhs, in canEqCanLHSFinish_try_unification.
Now, we're here (including further context from our original example,
from the top of the Note):
=====================================
compiler/GHC/Tc/Solver/Monad.hs
=====================================
@@ -129,7 +129,7 @@ module GHC.Tc.Solver.Monad (
pprEq,
-- Enforcing invariants for type equalities
- checkTypeEq, checkTouchableTyVarEq
+ checkTypeEq
) where
import GHC.Prelude
@@ -228,8 +228,6 @@ import GHC.Data.Graph.Directed
import qualified Data.Set as Set
import GHC.Unit.Module.Graph
-import GHC.Data.Maybe
-
{- *********************************************************************
* *
SolverStage and StopOrContinue
@@ -2416,81 +2414,31 @@ wrapUnifierX ev role do_unifications
************************************************************************
-}
-checkTouchableTyVarEq
- :: CtEvidence
- -> TcTyVar -- A touchable meta-tyvar
- -> TcType -- The RHS
- -> TcS (PuResult () Reduction)
--- Used for Nominal, Wanted equalities, with a touchable meta-tyvar on LHS
--- If checkTouchableTyVarEq tv ty = PuOK cts redn
--- then we can unify
--- tv := ty |> redn
--- with extra wanteds 'cts'
--- If it returns (PuFail reason) we can't unify, and the reason explains why.
-checkTouchableTyVarEq ev lhs_tv rhs
- | simpleUnifyCheck UC_Solver lhs_tv rhs -- An (optional) short-cut
- = do { traceTcS "checkTouchableTyVarEq: simple-check wins" (ppr lhs_tv $$ ppr rhs)
- ; return (pure (mkReflRedn Nominal rhs)) }
-
- | otherwise
- = do { traceTcS "checkTouchableTyVarEq {" (ppr lhs_tv $$ ppr rhs)
- ; check_result <- wrapTcS (check_rhs rhs)
- ; traceTcS "checkTouchableTyVarEq }" (ppr lhs_tv $$ ppr check_result)
- ; case check_result of
- PuFail reason -> return (PuFail reason)
- PuOK cts redn -> do { emitWork cts
- ; return (pure redn) } }
-
- where
- lhs_tv_info = metaTyVarInfo lhs_tv -- lhs_tv should be a meta-tyvar
-
- is_concrete_lhs_tv = isJust $ concreteInfo_maybe lhs_tv_info
-
- check_rhs rhs
- -- Crucial special case for alpha ~ F tys
- -- We don't want to flatten that (F tys)!
- | Just (TyFamLHS tc tys) <- canTyFamEqLHS_maybe rhs
- = if is_concrete_lhs_tv
- then return $ PuFail (cteProblem cteConcrete)
- else recurseIntoFamTyConApp flags tc tys
- | otherwise
- = checkTyEqRhs flags rhs
-
- flags = unifyingLHSMetaTyVar_TEFTask ev lhs_tv
-
-------------------------
checkTypeEq :: CtEvidence -> EqRel -> CanEqLHS -> TcType
-> TcS (PuResult () Reduction)
-- Used for general CanEqLHSs, ones that do
-- not have a touchable type variable on the LHS (i.e. not unifying)
-checkTypeEq ev eq_rel lhs rhs
- | isGiven ev
- = do { traceTcS "checkTypeEq {" (vcat [ text "lhs:" <+> ppr lhs
- , text "rhs:" <+> ppr rhs ])
- ; check_result <- wrapTcS (check_given_rhs rhs)
- ; traceTcS "checkTypeEq }" (ppr check_result)
- ; case check_result of
- PuFail reason -> return (PuFail reason)
- PuOK prs redn -> do { new_givens <- mapBagM mk_new_given prs
- ; emitWork new_givens
- ; updInertSet (addCycleBreakerBindings prs)
- ; return (pure redn) } }
-
- | otherwise -- Wanted
- = do { check_result <- wrapTcS (checkTyEqRhs wanted_flags rhs)
- ; case check_result of
- PuFail reason -> return (PuFail reason)
- PuOK cts redn -> do { emitWork cts
- ; return (pure redn) } }
+checkTypeEq ev eq_rel lhs rhs =
+ case ev of
+ CtGiven {} ->
+ do { traceTcS "checkTypeEq {" (vcat [ text "lhs:" <+> ppr lhs
+ , text "rhs:" <+> ppr rhs ])
+ ; check_result <- wrapTcS (checkTyEqRhs given_flags rhs)
+ ; traceTcS "checkTypeEq }" (ppr check_result)
+ ; case check_result of
+ PuFail reason -> return (PuFail reason)
+ PuOK prs redn -> do { new_givens <- mapBagM mk_new_given prs
+ ; emitWork new_givens
+ ; updInertSet (addCycleBreakerBindings prs)
+ ; return (pure redn) } }
+ CtWanted {} ->
+ do { check_result <- wrapTcS (checkTyEqRhs wanted_flags rhs)
+ ; case check_result of
+ PuFail reason -> return (PuFail reason)
+ PuOK cts redn -> do { emitWork cts
+ ; return (pure redn) } }
where
- check_given_rhs :: TcType -> TcM (PuResult (TcTyVar,TcType) Reduction)
- check_given_rhs rhs
- -- See Note [Special case for top-level of Given equality]
- | Just (TyFamLHS tc tys) <- canTyFamEqLHS_maybe rhs
- = recurseIntoFamTyConApp given_flags tc tys
- | otherwise
- = checkTyEqRhs given_flags rhs
-
+ wanted_flags :: TyEqFlags TcM Ct
wanted_flags = notUnifying_TEFTask occ_prob lhs
-- checkTypeEq deals only with the non-unifying case
@@ -2532,31 +2480,6 @@ restoreTyVarCycles is
(a ~R# b a) is soluble if b later turns out to be Identity
So we treat this as a "soluble occurs check".
-Note [Special case for top-level of Given equality]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We take care when examining
- [G] F ty ~ G (...(F ty)...)
-where both sides are TyFamLHSs. We don't want to flatten that RHS to
- [G] F ty ~ cbv
- [G] G (...(F ty)...) ~ cbv
-Instead we'd like to say "occurs-check" and swap LHS and RHS, which yields a
-canonical constraint
- [G] G (...(F ty)...) ~ F ty
-That tends to rewrite a big type to smaller one. This happens in T15703,
-where we had:
- [G] Pure g ~ From1 (To1 (Pure g))
-Making a loop breaker and rewriting left to right just makes much bigger
-types than swapping it over.
-
-(We might hope to have swapped it over before getting to checkTypeEq,
-but better safe than sorry.)
-
-NB: We never see a TyVarLHS here, such as
- [G] a ~ F tys here
-because we'd have swapped it to
- [G] F tys ~ a
-in canEqCanLHS2, before getting to checkTypeEq.
-
Note [Don't cycle-break Wanteds when not unifying]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Consdier
=====================================
compiler/GHC/Tc/Types/Constraint.hs
=====================================
@@ -279,10 +279,10 @@ We thus perform an occurs-check. There is, of course, some subtlety:
* For type variables, the occurs-check looks deeply including kinds of
type variables. This is because a CEqCan over a meta-variable is
- also used to inform unification, in
- GHC.Tc.Solver.Monad.checkTouchableTyVarEq. If the LHS appears
- anywhere in the RHS, at all, unification will create an infinite
- structure which is bad.
+ also used to inform unification, via `checkTyEqRhs`, called in
+ `canEqCanLHSFinish_try_unification`.
+ If the LHS appears anywhere in the RHS, at all, unification will create
+ an infinite structure, which is bad.
* For type family applications, the occurs-check is shallow; it looks
only in places where we might rewrite. (Specifically, it does not
=====================================
compiler/GHC/Tc/Utils/Unify.hs
=====================================
@@ -29,7 +29,7 @@ module GHC.Tc.Utils.Unify (
-- Various unifications
unifyType, unifyKind, unifyInvisibleType, unifyExpectedType,
unifyExprType, unifyTypeAndEmit, promoteTcType,
- swapOverTyVars, touchabilityAndShapeTest, checkTopShape, lhsPriority,
+ swapOverTyVars, touchabilityTest, checkTopShape, lhsPriority,
UnifyEnv(..), updUEnvLoc, setUEnvRole,
uType,
mightEqualLater,
@@ -55,7 +55,7 @@ module GHC.Tc.Utils.Unify (
TyEqFamApp(..), FamAppBreaker(..),
checkPromoteFreeVars,
- simpleUnifyCheck, UnifyCheckCaller(..),
+ simpleUnifyCheck, UnifyCheckCaller(..), SimpleUnifyResult(..),
fillInferResult,
) where
@@ -2482,10 +2482,9 @@ uUnfilledVar2 :: UnifyEnv -- Precondition: u_role==Nominal
uUnfilledVar2 env@(UE { u_defer = def_eq_ref }) swapped tv1 ty2
= do { cur_lvl <- getTcLevel
-- See Note [Unification preconditions], (UNTOUCHABLE) wrinkles
- -- Here we don't know about given equalities here; so we treat
+ -- Here we don't know about given equalities; so we treat
-- /any/ level outside this one as untouchable. Hence cur_lvl.
- ; if not (touchabilityAndShapeTest cur_lvl tv1 ty2
- && simpleUnifyCheck UC_OnTheFly tv1 ty2)
+ ; if simpleUnifyCheck UC_OnTheFly cur_lvl tv1 ty2 /= SUC_CanUnify
then not_ok_so_defer cur_lvl
else
do { def_eqs <- readTcRef def_eq_ref -- Capture current state of def_eqs
@@ -2530,8 +2529,8 @@ uUnfilledVar2 env@(UE { u_defer = def_eq_ref }) swapped tv1 ty2
do { traceTc "uUnfilledVar2 not ok" $
vcat [ text "tv1:" <+> ppr tv1
, text "ty2:" <+> ppr ty2
- , text "simple-unify-chk:" <+> ppr (simpleUnifyCheck UC_OnTheFly tv1 ty2)
- , text "touchability:" <+> ppr (touchabilityAndShapeTest cur_lvl tv1 ty2)]
+ , text "simple-unify-chk:" <+> ppr (simpleUnifyCheck UC_OnTheFly cur_lvl tv1 ty2)
+ ]
-- Occurs check or an untouchable: just defer
-- NB: occurs check isn't necessarily fatal:
-- eg tv1 occurred in type family parameter
@@ -2590,9 +2589,8 @@ lhsPriority tv
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Question: given a homogeneous equality (alpha ~# ty), when is it OK to
unify alpha := ty?
-
-This note only applied to /homogeneous/ equalities, in which both
-sides have the same kind.
+(This note only applies to /homogeneous/ equalities, in which both
+sides have the same kind.)
There are five reasons not to unify:
@@ -2688,7 +2686,7 @@ Needless to say, all there are wrinkles:
* In the constraint solver, we track where Given equalities occur
and use that to guard unification in
- GHC.Tc.Utils.Unify.touchabilityAndShapeTest. More details in
+ GHC.Tc.Utils.Unify.touchabilityTest. More details in
Note [Tracking Given equalities] in GHC.Tc.Solver.InertSet
Historical note: in the olden days (pre 2021) the constraint solver
@@ -2929,12 +2927,34 @@ data UnifyCheckCaller
= UC_OnTheFly -- Called from the on-the-fly unifier
| UC_QuickLook -- Called from Quick Look
| UC_Solver -- Called from constraint solver
- | UC_Defaulting -- Called when doing top-level defaulting
-simpleUnifyCheck :: UnifyCheckCaller -> TcTyVar -> TcType -> Bool
--- simpleUnifyCheck does a fast check: True <=> unification is OK
--- If it says 'False' then unification might still be OK, but
--- it'll take more work to do -- use the full checkTypeEq
+-- | The result type of 'simpleUnifyCheck'.
+data SimpleUnifyResult
+ -- | Definitely cannot unify (untouchable variable or incompatible top-shape)
+ = SUC_CannotUnify
+ -- | The variable is touchable and the top-shape test passed, but
+ -- it may or may not be OK to unify
+ | SUC_NotSure
+ -- | Definitely OK to unify
+ | SUC_CanUnify
+ deriving stock (Eq, Ord, Show)
+instance Semigroup SimpleUnifyResult where
+ no@SUC_CannotUnify <> _ = no
+ SUC_CanUnify <> r = r
+ _ <> no@SUC_CannotUnify = no
+ r <> SUC_CanUnify = r
+ ns@SUC_NotSure <> SUC_NotSure = ns
+
+instance Outputable SimpleUnifyResult where
+ ppr = \case
+ SUC_CannotUnify -> text "SUC_CannotUnify"
+ SUC_NotSure -> text "SUC_NotSure"
+ SUC_CanUnify -> text "SUC_CanUnify"
+
+simpleUnifyCheck :: UnifyCheckCaller -> TcLevel -> TcTyVar -> TcType -> SimpleUnifyResult
+-- ^ A fast check for unification. May return "not sure", in which case
+-- unification might still be OK, but it'll take more work to do
+-- (use the full 'checkTypeEq').
--
-- * Rejects if lhs_tv occurs in rhs_ty (occurs check)
-- * Rejects foralls unless
@@ -2945,9 +2965,17 @@ simpleUnifyCheck :: UnifyCheckCaller -> TcTyVar -> TcType -> Bool
-- * Does a level-check for type variables, to avoid skolem escape
--
-- This function is pretty heavily used, so it's optimised not to allocate
-simpleUnifyCheck caller lhs_tv rhs
- = go rhs
+simpleUnifyCheck caller given_eq_lvl lhs_tv rhs
+ | not $ touchabilityTest given_eq_lvl lhs_tv
+ = SUC_CannotUnify
+ | not $ checkTopShape lhs_info rhs
+ = SUC_CannotUnify
+ | rhs_is_ok rhs
+ = SUC_CanUnify
+ | otherwise
+ = SUC_NotSure
where
+ lhs_info = metaTyVarInfo lhs_tv
!(occ_in_ty, occ_in_co) = mkOccFolders (tyVarName lhs_tv)
@@ -2967,33 +2995,32 @@ simpleUnifyCheck caller lhs_tv rhs
UC_Solver -> True
UC_QuickLook -> True
UC_OnTheFly -> False
- UC_Defaulting -> True
- go (TyVarTy tv)
+ rhs_is_ok (TyVarTy tv)
| lhs_tv == tv = False
| tcTyVarLevel tv `strictlyDeeperThan` lhs_tv_lvl = False
| lhs_tv_is_concrete, not (isConcreteTyVar tv) = False
| occ_in_ty $! (tyVarKind tv) = False
| otherwise = True
- go (FunTy {ft_af = af, ft_mult = w, ft_arg = a, ft_res = r})
+ rhs_is_ok (FunTy {ft_af = af, ft_mult = w, ft_arg = a, ft_res = r})
| not forall_ok, isInvisibleFunArg af = False
- | otherwise = go w && go a && go r
+ | otherwise = rhs_is_ok w && rhs_is_ok a && rhs_is_ok r
- go (TyConApp tc tys)
+ rhs_is_ok (TyConApp tc tys)
| lhs_tv_is_concrete, not (isConcreteTyCon tc) = False
| not forall_ok, not (isTauTyCon tc) = False
| not fam_ok, not (isFamFreeTyCon tc) = False
- | otherwise = all go tys
+ | otherwise = all rhs_is_ok tys
- go (ForAllTy (Bndr tv _) ty)
- | forall_ok = go (tyVarKind tv) && (tv == lhs_tv || go ty)
+ rhs_is_ok (ForAllTy (Bndr tv _) ty)
+ | forall_ok = rhs_is_ok (tyVarKind tv) && (tv == lhs_tv || rhs_is_ok ty)
| otherwise = False
- go (AppTy t1 t2) = go t1 && go t2
- go (CastTy ty co) = not (occ_in_co co) && go ty
- go (CoercionTy co) = not (occ_in_co co)
- go (LitTy {}) = True
+ rhs_is_ok (AppTy t1 t2) = rhs_is_ok t1 && rhs_is_ok t2
+ rhs_is_ok (CastTy ty co) = not (occ_in_co co) && rhs_is_ok ty
+ rhs_is_ok (CoercionTy co) = not (occ_in_co co)
+ rhs_is_ok (LitTy {}) = True
mkOccFolders :: Name -> (TcType -> Bool, TcCoercion -> Bool)
@@ -3078,8 +3105,13 @@ We must jolly well use that reductionReduced type, even though the
reductionCoercion is Refl. See `canEqCanLHSFinish_no_unification`.
-}
-data PuResult a b = PuFail CheckTyEqResult
- | PuOK (Bag a) b
+data PuResult a b
+ -- | Pure unifier failure.
+ --
+ -- Invariant: the CheckTyEqResult is not 'cteOK'; that it, it specifies a problem.
+ = PuFail CheckTyEqResult
+ -- | Pure unifier success.
+ | PuOK (Bag a) b
deriving stock (Functor, Foldable, Traversable)
instance Applicative (PuResult a) where
@@ -3414,15 +3446,15 @@ famAppBreaker (BreakWanted ev lhs_tv) fam_app
; return (PuOK (singleCt (mkNonCanonical $ CtWanted new_ev))
(mkReduction (HoleCo hole) new_tv_ty)) } }
where
+ fam_app_kind = typeKind fam_app
(lhs_tv_info, lhs_tv_lvl) =
case tcTyVarDetails lhs_tv of
MetaTv { mtv_info = info, mtv_tclvl = lvl } -> (info,lvl)
-- lhs_tv should be a meta-tyvar
- _ -> pprPanic "checkTouchableTyVarEq" (ppr lhs_tv)
- fam_app_kind = typeKind fam_app
- -- See Detail (7) of the Note
+ _ -> pprPanic "famAppBreaker BreakWanted: lhs_tv is not a meta-tyvar"
+ (ppr lhs_tv)
cb_loc = updateCtLocOrigin (ctEvLoc ev) CycleBreakerOrigin
-
+ -- CycleBreakerOrigin: see Detail (7) of Note [Type equality cycles]
instance Outputable (TyEqFlags m a) where
ppr = \case
@@ -3492,12 +3524,95 @@ famAppArgFlags flags = case flags of
-> LC_Check { lc_lvlc = lvl, lc_lenient = False }
lc -> lc
+{- Note [checkTyEqRhs]
+~~~~~~~~~~~~~~~~~~~~~~
+The key function `checkTyEqRhs ty_eq_flags rhs` is called on the
+RHS of a type equality
+ lhs ~ rhs
+and checks to see if `rhs` satisfies, or can be made to satisfy,
+invariants described by `ty_eq_flags`. It can succeded or fail; in
+the latter case it returns a `CheckTyEqResult` that describes why it
+failed.
+
+When `lhs` is a touchable type variable, so unification might happen, then
+`checkTyEqRhs` enforces the unification preconditions of Note [Unification preconditions].
+
+Notably, it can check for things like:
+ * Insoluble occurs check
+ e.g. alpha[tau] ~ [alpha]
+ or F Int ~ [F Int]
+ * Potentially-soluble occurs check
+ e.g. alpha[tau] ~ [F alpha beta]
+ * Impredicativity error:
+ e.g. alpha[tau] ~ (forall a. a->a)
+ * Skolem escape
+ e.g alpha[1] ~ (b[sk:2], Int)
+ * Concreteness error
+ e.g. alpha[conc] ~ r[sk]
+
+Its specific behaviour is governed by the `TyEqFlags` that are passed
+to it; see Note [TyEqFlags].
+
+Note, however, that `checkTyEqRhs` specifically does /not/ check for:
+ * Touchability of the LHS (in the case of a unification variable)
+ * Shape of the LHS (e.g. we can't unify Int with a TyVarTv)
+These things are checked by `simpleUnifyCheck`.
+-}
+
+
+-- | Perform the checks specified by the 'TyEqFlags' on the RHS, in order to
+-- enforce the unification preconditions of Note [Unification preconditions].
+--
+-- See Note [checkTyEqRhs].
checkTyEqRhs :: forall m a
. Monad m
=> TyEqFlags m a
-> TcType -- Already zonked
-> m (PuResult a Reduction)
-checkTyEqRhs flags ty
+checkTyEqRhs flags rhs
+ -- Crucial special case for a top-level equality of the form 'alpha ~ F tys'.
+ -- We don't want to flatten that (F tys), as this gets us right back to where
+ -- we started!
+ --
+ -- See also Note [Special case for top-level of Given equality]
+ | Just (TyFamLHS tc tys) <- canTyFamEqLHS_maybe rhs
+ , not $ tefConcrete flags
+ = recurseIntoFamTyConApp flags tc tys
+ | otherwise
+ = check_ty_eq_rhs flags rhs
+
+{- Note [Special case for top-level of Given equality]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We take care when examining
+ [G] F ty ~ G (...(F ty)...)
+where both sides are TyFamLHSs. We don't want to flatten that RHS to
+ [G] F ty ~ cbv
+ [G] G (...(F ty)...) ~ cbv
+Instead we'd like to say "occurs-check" and swap LHS and RHS, which yields a
+canonical constraint
+ [G] G (...(F ty)...) ~ F ty
+That tends to rewrite a big type to smaller one. This happens in T15703,
+where we had:
+ [G] Pure g ~ From1 (To1 (Pure g))
+Making a loop breaker and rewriting left to right just makes much bigger
+types than swapping it over.
+
+(We might hope to have swapped it over before getting to checkTypeEq,
+but better safe than sorry.)
+
+NB: We never see a TyVarLHS here, such as
+ [G] a ~ F tys here
+because we'd have swapped it to
+ [G] F tys ~ a
+in canEqCanLHS2, before getting to checkTypeEq.
+-}
+
+check_ty_eq_rhs :: forall m a
+ . Monad m
+ => TyEqFlags m a
+ -> TcType -- Already zonked
+ -> m (PuResult a Reduction)
+check_ty_eq_rhs flags ty
= case ty of
LitTy {} -> return $ okCheckRefl ty
TyConApp tc tys -> checkTyConApp flags ty tc tys
@@ -3510,16 +3625,16 @@ checkTyEqRhs flags ty
| isInvisibleFunArg af -- e.g. Num a => blah
-> return $ PuFail impredicativeProblem -- Not allowed (TyEq:F)
| otherwise
- -> do { w_res <- checkTyEqRhs flags w
- ; a_res <- checkTyEqRhs flags a
- ; r_res <- checkTyEqRhs flags r
+ -> do { w_res <- check_ty_eq_rhs flags w
+ ; a_res <- check_ty_eq_rhs flags a
+ ; r_res <- check_ty_eq_rhs flags r
; return (mkFunRedn Nominal af <$> w_res <*> a_res <*> r_res) }
- AppTy fun arg -> do { fun_res <- checkTyEqRhs flags fun
- ; arg_res <- checkTyEqRhs flags arg
+ AppTy fun arg -> do { fun_res <- check_ty_eq_rhs flags fun
+ ; arg_res <- check_ty_eq_rhs flags arg
; return (mkAppRedn <$> fun_res <*> arg_res) }
- CastTy ty co -> do { ty_res <- checkTyEqRhs flags ty
+ CastTy ty co -> do { ty_res <- check_ty_eq_rhs flags ty
; co_res <- checkCo flags co
; return (mkCastRedn1 Nominal ty <$> co_res <*> ty_res) }
@@ -3527,7 +3642,7 @@ checkTyEqRhs flags ty
; return (mkReflCoRedn Nominal <$> co_res) }
ForAllTy {} -> return $ PuFail impredicativeProblem -- Not allowed (TyEq:F)
-{-# INLINEABLE checkTyEqRhs #-}
+{-# INLINEABLE check_ty_eq_rhs #-}
-------------------
checkCo :: Monad m => TyEqFlags m a -> Coercion -> m (PuResult a Coercion)
@@ -3702,14 +3817,14 @@ checkTyConApp flags tc_app tc tys
else do { let (fun_args, extra_args) = splitAt (tyConArity tc) tys
fun_app = mkTyConApp tc fun_args
; fun_res <- checkFamApp flags fun_app tc fun_args
- ; extra_res <- mapCheck (checkTyEqRhs flags) extra_args
+ ; extra_res <- mapCheck (check_ty_eq_rhs flags) extra_args
; return (mkAppRedns <$> fun_res <*> extra_res) }
| Just ty' <- rewriterView tc_app
-- e.g. S a where type S a = F [a]
-- or type S a = Int
-- See Note [Forgetful synonyms in checkTyConApp]
- = checkTyEqRhs flags ty'
+ = check_ty_eq_rhs flags ty'
| not (isTauTyCon tc)
= return $ PuFail impredicativeProblem
@@ -3727,7 +3842,7 @@ recurseIntoTyConApp :: Monad m
-> TyCon -> [TcType]
-> m (PuResult a Reduction)
recurseIntoTyConApp flags tc tys
- = do { tys_res <- mapCheck (checkTyEqRhs flags) tys
+ = do { tys_res <- mapCheck (check_ty_eq_rhs flags) tys
; return (mkTyConAppRedn Nominal tc <$> tys_res) }
recurseIntoFamTyConApp :: Monad m
@@ -3888,7 +4003,7 @@ checkTyVar flags occ_tv
-- unfilled meta-tyvar, we need to ensure that the kind of
-- 'occ_tv' is concrete. Test cases: T23051, T23176.
; let occ_kind = tyVarKind occ_tv
- ; kind_result <- checkTyEqRhs flags occ_kind
+ ; kind_result <- check_ty_eq_rhs flags occ_kind
; for kind_result $ \ kind_redn ->
do { let kind_co = reductionCoercion kind_redn
new_kind = reductionReducedType kind_redn
@@ -4010,16 +4125,15 @@ promote_meta_tyvar info dest_lvl occ_tv
-------------------------
-touchabilityAndShapeTest :: TcLevel -> TcTyVar -> TcType -> Bool
--- This is the key test for untouchability:
+touchabilityTest :: TcLevel -> TcTyVar -> Bool
+-- ^ This is the key test for untouchability:
-- See Note [Unification preconditions] in GHC.Tc.Utils.Unify
-- and Note [Solve by unification] in GHC.Tc.Solver.Equality
--- True <=> touchability and shape are OK
-touchabilityAndShapeTest given_eq_lvl tv rhs
- | MetaTv { mtv_info = info, mtv_tclvl = tv_lvl } <- tcTyVarDetails tv
- , tv_lvl `deeperThanOrSame` given_eq_lvl
- , checkTopShape info rhs
- = True
+--
+-- @True@ <=> the variable is touchable
+touchabilityTest given_eq_lvl tv
+ | MetaTv { mtv_tclvl = tv_lvl } <- tcTyVarDetails tv
+ = tv_lvl `deeperThanOrSame` given_eq_lvl
| otherwise
= False
=====================================
testsuite/tests/rep-poly/RepPolyTuple4.stderr
=====================================
@@ -6,8 +6,6 @@ RepPolyTuple4.hs:8:7: error: [GHC-55287]
When unifying:
• a0 -> b0 -> (# a0, b0 #)
• a -> a -> (# a, a #)
- Cannot unify ‘r’ with the type variable ‘w1’
- because the former is not a concrete ‘RuntimeRep’.
• The second component of the unboxed tuple
does not have a fixed runtime representation.
Its type is:
@@ -15,8 +13,6 @@ RepPolyTuple4.hs:8:7: error: [GHC-55287]
When unifying:
• a0 -> b0 -> (# a0, b0 #)
• a -> a -> (# a, a #)
- Cannot unify ‘r’ with the type variable ‘w0’
- because the former is not a concrete ‘RuntimeRep’.
• In the expression: (#,#) @_ @_
In an equation for ‘bar’: bar = (#,#) @_ @_
=====================================
testsuite/tests/rep-poly/T19709b.stderr
=====================================
@@ -2,11 +2,8 @@ T19709b.hs:11:15: error: [GHC-55287]
• The argument ‘(error @Any "e2")’ of ‘levfun’
does not have a fixed runtime representation.
Its type is:
- a1 :: TYPE r0
- When unifying:
- • a0
- • a1
- Cannot unify ‘Any’ with the type variable ‘r0’
+ a1 :: TYPE c0
+ Cannot unify ‘Any’ with the type variable ‘c0’
because the former is not a concrete ‘RuntimeRep’.
• In the first argument of ‘levfun’, namely ‘(error @Any "e2")’
In the first argument of ‘seq’, namely ‘levfun (error @Any "e2")’
=====================================
testsuite/tests/rep-poly/T23903.stderr
=====================================
@@ -2,11 +2,8 @@ T23903.hs:21:1: error: [GHC-55287]
• The first pattern in the equation for ‘f’
does not have a fixed runtime representation.
Its type is:
- t0 :: TYPE cx0
- When unifying:
- • t0 -> ()
- • a #-> ()
- Cannot unify ‘Rep a’ with the type variable ‘cx0’
+ t0 :: TYPE c0
+ Cannot unify ‘Rep a’ with the type variable ‘c0’
because the former is not a concrete ‘RuntimeRep’.
• The equation for ‘f’ has one visible argument,
but its type ‘a #-> ()’ has none
=====================================
testsuite/tests/simplCore/should_compile/simpl017.stderr
=====================================
@@ -1,20 +1,25 @@
-simpl017.hs:55:12: error: [GHC-46956]
- • Couldn't match type ‘v0’ with ‘v’
- Expected: [E m i] -> E' v m a
- Actual: [E m i] -> E' v0 m a
- because type variable ‘v’ would escape its scope
- This (rigid, skolem) type variable is bound by
- a type expected by the context:
- forall v. [E m i] -> E' v m a
- at simpl017.hs:55:12
- • In the first argument of ‘return’, namely ‘f’
- In a stmt of a 'do' block: return f
+simpl017.hs:55:5: error: [GHC-83865]
+ • Couldn't match type: [E m i] -> E' v0 m a
+ with: forall v. [E m i] -> E' v m a
+ Expected: m (forall v. [E m i] -> E' v m a)
+ Actual: m ([E m i] -> E' v0 m a)
+ • In a stmt of a 'do' block: return f
In the first argument of ‘E’, namely
‘(do let ix :: [E m i] -> m i
ix [i] = runE i
{-# INLINE f #-}
....
return f)’
+ In the expression:
+ E (do let ix :: [E m i] -> m i
+ ix [i] = runE i
+ {-# INLINE f #-}
+ ....
+ return f)
• Relevant bindings include
f :: [E m i] -> E' v0 m a (bound at simpl017.hs:54:9)
+ ix :: [E m i] -> m i (bound at simpl017.hs:52:9)
+ a :: arr i a (bound at simpl017.hs:50:11)
+ liftArray :: arr i a -> E m (forall v. [E m i] -> E' v m a)
+ (bound at simpl017.hs:50:1)
=====================================
testsuite/tests/typecheck/should_compile/T26030.hs
=====================================
@@ -0,0 +1,25 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE GADTs #-}
+
+-- This program was rejected by GHC 9.12 due to a bug with
+-- unification in QuickLook.
+module T26030 where
+
+import Data.Kind
+
+type S :: Type -> Type
+data S a where
+ S1 :: S Bool
+ S2 :: S Char
+
+type F :: Type -> Type
+type family F a where
+ F Bool = Bool
+ F Char = Char
+
+foo :: forall a. S a -> IO (F a)
+foo sa1 = do
+ () <- return ()
+ case sa1 of
+ S1 -> return $ False
+ S2 -> return 'x'
=====================================
testsuite/tests/typecheck/should_compile/all.T
=====================================
@@ -887,6 +887,7 @@ test('T21909b', normal, compile, [''])
test('T21443', normal, compile, [''])
test('T22194', normal, compile, [''])
test('T25744', normal, compile, [''])
+test('T26030', normal, compile, [''])
test('QualifiedRecordUpdate',
[ extra_files(['QualifiedRecordUpdate_aux.hs']) ]
, multimod_compile, ['QualifiedRecordUpdate', '-v0'])
=====================================
testsuite/tests/typecheck/should_fail/T25950.hs
=====================================
@@ -0,0 +1,6 @@
+{-# LANGUAGE PartialTypeSignatures #-}
+
+module T25950 where
+
+fails :: _ => a
+fails = id $ ()
=====================================
testsuite/tests/typecheck/should_fail/T25950.stderr
=====================================
@@ -0,0 +1,9 @@
+T25950.hs:6:9: error: [GHC-25897]
+ • Couldn't match expected type ‘a’ with actual type ‘()’
+ ‘a’ is a rigid type variable bound by
+ the inferred type of fails :: a
+ at T25950.hs:5:1-15
+ • In the expression: id $ ()
+ In an equation for ‘fails’: fails = id $ ()
+ • Relevant bindings include fails :: a (bound at T25950.hs:6:1)
+
=====================================
testsuite/tests/typecheck/should_fail/all.T
=====================================
@@ -726,6 +726,7 @@ test('T17594c', normal, compile_fail, [''])
test('T17594d', normal, compile_fail, [''])
test('T17594g', normal, compile_fail, [''])
+test('T25950', normal, compile_fail, [''])
test('T24470a', normal, compile_fail, [''])
test('T24553', normal, compile_fail, [''])
test('T23739b', normal, compile_fail, [''])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/202b201c968de68f864f4c8abbfec7…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/202b201c968de68f864f4c8abbfec7…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][master] Interpreter: Add limited support for direct primop evaluation.
by Marge Bot (@marge-bot) 21 May '25
by Marge Bot (@marge-bot) 21 May '25
21 May '25
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
202b201c by Andreas Klebinger at 2025-05-21T10:16:14-04:00
Interpreter: Add limited support for direct primop evaluation.
This commit adds support for a number of primops directly
to the interpreter. This avoids the indirection of going
through the primop wrapper for those primops speeding interpretation
of optimized code up massively.
Code involving IntSet runs about 25% faster with optimized core and these
changes. For core without breakpoints it's even more pronouced and I
saw reductions in runtime by up to 50%.
Running GHC itself in the interpreter was sped up by ~15% through this
change.
Additionally this comment does a few other related changes:
testsuite:
* Run foundation test in ghci and ghci-opt ways to test these
primops.
* Vastly expand the foundation test to cover all basic primops
by comparing result with the result of calling the wrapper.
Interpreter:
* When pushing arguments for interpreted primops extend each argument to
at least word with when pushing. This avoids some issues with big
endian. We can revisit this if it causes performance issues.
* Restructure the stack chunk check logic. There are now macros for
read accesses which might cross stack chunk boundries and macros which
omit the checks which are used when we statically know we access an
address in the current stack chunk.
- - - - -
17 changed files:
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/StgToByteCode.hs
- rts/Disassembler.c
- rts/Interpreter.c
- rts/include/rts/Bytecodes.h
- testsuite/tests/codeGen/should_run/all.T
- + testsuite/tests/ghci/all.T
- + testsuite/tests/ghci/ghci-mem-primops.hs
- + testsuite/tests/ghci/ghci-mem-primops.script
- + testsuite/tests/ghci/ghci-mem-primops.stdout
- testsuite/tests/numeric/should_run/all.T
- testsuite/tests/numeric/should_run/foundation.hs
- testsuite/tests/numeric/should_run/foundation.stdout
- utils/genprimopcode/Main.hs
- utils/genprimopcode/Syntax.hs
Changes:
=====================================
compiler/GHC/Builtin/primops.txt.pp
=====================================
@@ -147,6 +147,7 @@ defaults
fixity = Nothing
vector = []
deprecated_msg = {} -- A non-empty message indicates deprecation
+ div_like = False -- Second argument expected to be non zero - used for tests
-- Note [When do out-of-line primops go in primops.txt.pp]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -296,14 +297,18 @@ primop Int8MulOp "timesInt8#" GenPrimOp Int8# -> Int8# -> Int8#
primop Int8QuotOp "quotInt8#" GenPrimOp Int8# -> Int8# -> Int8#
with
effect = CanFail
+ div_like = True
primop Int8RemOp "remInt8#" GenPrimOp Int8# -> Int8# -> Int8#
with
effect = CanFail
+ div_like = True
+
primop Int8QuotRemOp "quotRemInt8#" GenPrimOp Int8# -> Int8# -> (# Int8#, Int8# #)
with
effect = CanFail
+ div_like = True
primop Int8SllOp "uncheckedShiftLInt8#" GenPrimOp Int8# -> Int# -> Int8#
primop Int8SraOp "uncheckedShiftRAInt8#" GenPrimOp Int8# -> Int# -> Int8#
@@ -342,14 +347,17 @@ primop Word8MulOp "timesWord8#" GenPrimOp Word8# -> Word8# -> Word8#
primop Word8QuotOp "quotWord8#" GenPrimOp Word8# -> Word8# -> Word8#
with
effect = CanFail
+ div_like = True
primop Word8RemOp "remWord8#" GenPrimOp Word8# -> Word8# -> Word8#
with
effect = CanFail
+ div_like = True
primop Word8QuotRemOp "quotRemWord8#" GenPrimOp Word8# -> Word8# -> (# Word8#, Word8# #)
with
effect = CanFail
+ div_like = True
primop Word8AndOp "andWord8#" GenPrimOp Word8# -> Word8# -> Word8#
with commutable = True
@@ -400,14 +408,17 @@ primop Int16MulOp "timesInt16#" GenPrimOp Int16# -> Int16# -> Int16#
primop Int16QuotOp "quotInt16#" GenPrimOp Int16# -> Int16# -> Int16#
with
effect = CanFail
+ div_like = True
primop Int16RemOp "remInt16#" GenPrimOp Int16# -> Int16# -> Int16#
with
effect = CanFail
+ div_like = True
primop Int16QuotRemOp "quotRemInt16#" GenPrimOp Int16# -> Int16# -> (# Int16#, Int16# #)
with
effect = CanFail
+ div_like = True
primop Int16SllOp "uncheckedShiftLInt16#" GenPrimOp Int16# -> Int# -> Int16#
primop Int16SraOp "uncheckedShiftRAInt16#" GenPrimOp Int16# -> Int# -> Int16#
@@ -446,14 +457,17 @@ primop Word16MulOp "timesWord16#" GenPrimOp Word16# -> Word16# -> Word16#
primop Word16QuotOp "quotWord16#" GenPrimOp Word16# -> Word16# -> Word16#
with
effect = CanFail
+ div_like = True
primop Word16RemOp "remWord16#" GenPrimOp Word16# -> Word16# -> Word16#
with
effect = CanFail
+ div_like = True
primop Word16QuotRemOp "quotRemWord16#" GenPrimOp Word16# -> Word16# -> (# Word16#, Word16# #)
with
effect = CanFail
+ div_like = True
primop Word16AndOp "andWord16#" GenPrimOp Word16# -> Word16# -> Word16#
with commutable = True
@@ -504,14 +518,17 @@ primop Int32MulOp "timesInt32#" GenPrimOp Int32# -> Int32# -> Int32#
primop Int32QuotOp "quotInt32#" GenPrimOp Int32# -> Int32# -> Int32#
with
effect = CanFail
+ div_like = True
primop Int32RemOp "remInt32#" GenPrimOp Int32# -> Int32# -> Int32#
with
effect = CanFail
+ div_like = True
primop Int32QuotRemOp "quotRemInt32#" GenPrimOp Int32# -> Int32# -> (# Int32#, Int32# #)
with
effect = CanFail
+ div_like = True
primop Int32SllOp "uncheckedShiftLInt32#" GenPrimOp Int32# -> Int# -> Int32#
primop Int32SraOp "uncheckedShiftRAInt32#" GenPrimOp Int32# -> Int# -> Int32#
@@ -550,14 +567,17 @@ primop Word32MulOp "timesWord32#" GenPrimOp Word32# -> Word32# -> Word32#
primop Word32QuotOp "quotWord32#" GenPrimOp Word32# -> Word32# -> Word32#
with
effect = CanFail
+ div_like = True
primop Word32RemOp "remWord32#" GenPrimOp Word32# -> Word32# -> Word32#
with
effect = CanFail
+ div_like = True
primop Word32QuotRemOp "quotRemWord32#" GenPrimOp Word32# -> Word32# -> (# Word32#, Word32# #)
with
effect = CanFail
+ div_like = True
primop Word32AndOp "andWord32#" GenPrimOp Word32# -> Word32# -> Word32#
with commutable = True
@@ -608,10 +628,12 @@ primop Int64MulOp "timesInt64#" GenPrimOp Int64# -> Int64# -> Int64#
primop Int64QuotOp "quotInt64#" GenPrimOp Int64# -> Int64# -> Int64#
with
effect = CanFail
+ div_like = True
primop Int64RemOp "remInt64#" GenPrimOp Int64# -> Int64# -> Int64#
with
effect = CanFail
+ div_like = True
primop Int64SllOp "uncheckedIShiftL64#" GenPrimOp Int64# -> Int# -> Int64#
primop Int64SraOp "uncheckedIShiftRA64#" GenPrimOp Int64# -> Int# -> Int64#
@@ -650,10 +672,12 @@ primop Word64MulOp "timesWord64#" GenPrimOp Word64# -> Word64# -> Word64#
primop Word64QuotOp "quotWord64#" GenPrimOp Word64# -> Word64# -> Word64#
with
effect = CanFail
+ div_like = True
primop Word64RemOp "remWord64#" GenPrimOp Word64# -> Word64# -> Word64#
with
effect = CanFail
+ div_like = True
primop Word64AndOp "and64#" GenPrimOp Word64# -> Word64# -> Word64#
with commutable = True
@@ -737,6 +761,7 @@ primop IntQuotOp "quotInt#" GenPrimOp
zero.
}
with effect = CanFail
+ div_like = True
primop IntRemOp "remInt#" GenPrimOp
Int# -> Int# -> Int#
@@ -744,11 +769,13 @@ primop IntRemOp "remInt#" GenPrimOp
behavior is undefined if the second argument is zero.
}
with effect = CanFail
+ div_like = True
primop IntQuotRemOp "quotRemInt#" GenPrimOp
Int# -> Int# -> (# Int#, Int# #)
{Rounds towards zero.}
with effect = CanFail
+ div_like = True
primop IntAndOp "andI#" GenPrimOp Int# -> Int# -> Int#
{Bitwise "and".}
@@ -886,19 +913,23 @@ primop WordMul2Op "timesWord2#" GenPrimOp
primop WordQuotOp "quotWord#" GenPrimOp Word# -> Word# -> Word#
with effect = CanFail
+ div_like = True
primop WordRemOp "remWord#" GenPrimOp Word# -> Word# -> Word#
with effect = CanFail
+ div_like = True
primop WordQuotRemOp "quotRemWord#" GenPrimOp
Word# -> Word# -> (# Word#, Word# #)
with effect = CanFail
+ div_like = True
primop WordQuotRem2Op "quotRemWord2#" GenPrimOp
Word# -> Word# -> Word# -> (# Word#, Word# #)
{ Takes high word of dividend, then low word of dividend, then divisor.
Requires that high word < divisor.}
with effect = CanFail
+ div_like = True
primop WordAndOp "and#" GenPrimOp Word# -> Word# -> Word#
with commutable = True
@@ -4166,6 +4197,7 @@ primop VecQuotOp "quot#" GenPrimOp
Do not expect high performance. }
with effect = CanFail
vector = INT_VECTOR_TYPES
+ div_like = True
primop VecRemOp "rem#" GenPrimOp
VECTOR -> VECTOR -> VECTOR
@@ -4175,6 +4207,8 @@ primop VecRemOp "rem#" GenPrimOp
Do not expect high performance. }
with effect = CanFail
vector = INT_VECTOR_TYPES
+ div_like = True
+
primop VecNegOp "negate#" GenPrimOp
VECTOR -> VECTOR
=====================================
compiler/GHC/ByteCode/Asm.hs
=====================================
@@ -705,6 +705,143 @@ assembleI platform i = case i of
CCALL off ffi i -> do np <- lit1 $ BCONPtrFFIInfo ffi
emit_ bci_CCALL [wOp off, Op np, SmallOp i]
PRIMCALL -> emit_ bci_PRIMCALL []
+
+ OP_ADD w -> case w of
+ W64 -> emit_ bci_OP_ADD_64 []
+ W32 -> emit_ bci_OP_ADD_32 []
+ W16 -> emit_ bci_OP_ADD_16 []
+ W8 -> emit_ bci_OP_ADD_08 []
+ _ -> unsupported_width
+ OP_SUB w -> case w of
+ W64 -> emit_ bci_OP_SUB_64 []
+ W32 -> emit_ bci_OP_SUB_32 []
+ W16 -> emit_ bci_OP_SUB_16 []
+ W8 -> emit_ bci_OP_SUB_08 []
+ _ -> unsupported_width
+ OP_AND w -> case w of
+ W64 -> emit_ bci_OP_AND_64 []
+ W32 -> emit_ bci_OP_AND_32 []
+ W16 -> emit_ bci_OP_AND_16 []
+ W8 -> emit_ bci_OP_AND_08 []
+ _ -> unsupported_width
+ OP_XOR w -> case w of
+ W64 -> emit_ bci_OP_XOR_64 []
+ W32 -> emit_ bci_OP_XOR_32 []
+ W16 -> emit_ bci_OP_XOR_16 []
+ W8 -> emit_ bci_OP_XOR_08 []
+ _ -> unsupported_width
+ OP_OR w -> case w of
+ W64 -> emit_ bci_OP_OR_64 []
+ W32 -> emit_ bci_OP_OR_32 []
+ W16 -> emit_ bci_OP_OR_16 []
+ W8 -> emit_ bci_OP_OR_08 []
+ _ -> unsupported_width
+ OP_NOT w -> case w of
+ W64 -> emit_ bci_OP_NOT_64 []
+ W32 -> emit_ bci_OP_NOT_32 []
+ W16 -> emit_ bci_OP_NOT_16 []
+ W8 -> emit_ bci_OP_NOT_08 []
+ _ -> unsupported_width
+ OP_NEG w -> case w of
+ W64 -> emit_ bci_OP_NEG_64 []
+ W32 -> emit_ bci_OP_NEG_32 []
+ W16 -> emit_ bci_OP_NEG_16 []
+ W8 -> emit_ bci_OP_NEG_08 []
+ _ -> unsupported_width
+ OP_MUL w -> case w of
+ W64 -> emit_ bci_OP_MUL_64 []
+ W32 -> emit_ bci_OP_MUL_32 []
+ W16 -> emit_ bci_OP_MUL_16 []
+ W8 -> emit_ bci_OP_MUL_08 []
+ _ -> unsupported_width
+ OP_SHL w -> case w of
+ W64 -> emit_ bci_OP_SHL_64 []
+ W32 -> emit_ bci_OP_SHL_32 []
+ W16 -> emit_ bci_OP_SHL_16 []
+ W8 -> emit_ bci_OP_SHL_08 []
+ _ -> unsupported_width
+ OP_ASR w -> case w of
+ W64 -> emit_ bci_OP_ASR_64 []
+ W32 -> emit_ bci_OP_ASR_32 []
+ W16 -> emit_ bci_OP_ASR_16 []
+ W8 -> emit_ bci_OP_ASR_08 []
+ _ -> unsupported_width
+ OP_LSR w -> case w of
+ W64 -> emit_ bci_OP_LSR_64 []
+ W32 -> emit_ bci_OP_LSR_32 []
+ W16 -> emit_ bci_OP_LSR_16 []
+ W8 -> emit_ bci_OP_LSR_08 []
+ _ -> unsupported_width
+
+ OP_NEQ w -> case w of
+ W64 -> emit_ bci_OP_NEQ_64 []
+ W32 -> emit_ bci_OP_NEQ_32 []
+ W16 -> emit_ bci_OP_NEQ_16 []
+ W8 -> emit_ bci_OP_NEQ_08 []
+ _ -> unsupported_width
+ OP_EQ w -> case w of
+ W64 -> emit_ bci_OP_EQ_64 []
+ W32 -> emit_ bci_OP_EQ_32 []
+ W16 -> emit_ bci_OP_EQ_16 []
+ W8 -> emit_ bci_OP_EQ_08 []
+ _ -> unsupported_width
+
+ OP_U_LT w -> case w of
+ W64 -> emit_ bci_OP_U_LT_64 []
+ W32 -> emit_ bci_OP_U_LT_32 []
+ W16 -> emit_ bci_OP_U_LT_16 []
+ W8 -> emit_ bci_OP_U_LT_08 []
+ _ -> unsupported_width
+ OP_S_LT w -> case w of
+ W64 -> emit_ bci_OP_S_LT_64 []
+ W32 -> emit_ bci_OP_S_LT_32 []
+ W16 -> emit_ bci_OP_S_LT_16 []
+ W8 -> emit_ bci_OP_S_LT_08 []
+ _ -> unsupported_width
+ OP_U_GE w -> case w of
+ W64 -> emit_ bci_OP_U_GE_64 []
+ W32 -> emit_ bci_OP_U_GE_32 []
+ W16 -> emit_ bci_OP_U_GE_16 []
+ W8 -> emit_ bci_OP_U_GE_08 []
+ _ -> unsupported_width
+ OP_S_GE w -> case w of
+ W64 -> emit_ bci_OP_S_GE_64 []
+ W32 -> emit_ bci_OP_S_GE_32 []
+ W16 -> emit_ bci_OP_S_GE_16 []
+ W8 -> emit_ bci_OP_S_GE_08 []
+ _ -> unsupported_width
+ OP_U_GT w -> case w of
+ W64 -> emit_ bci_OP_U_GT_64 []
+ W32 -> emit_ bci_OP_U_GT_32 []
+ W16 -> emit_ bci_OP_U_GT_16 []
+ W8 -> emit_ bci_OP_U_GT_08 []
+ _ -> unsupported_width
+ OP_S_GT w -> case w of
+ W64 -> emit_ bci_OP_S_GT_64 []
+ W32 -> emit_ bci_OP_S_GT_32 []
+ W16 -> emit_ bci_OP_S_GT_16 []
+ W8 -> emit_ bci_OP_S_GT_08 []
+ _ -> unsupported_width
+ OP_U_LE w -> case w of
+ W64 -> emit_ bci_OP_U_LE_64 []
+ W32 -> emit_ bci_OP_U_LE_32 []
+ W16 -> emit_ bci_OP_U_LE_16 []
+ W8 -> emit_ bci_OP_U_LE_08 []
+ _ -> unsupported_width
+ OP_S_LE w -> case w of
+ W64 -> emit_ bci_OP_S_LE_64 []
+ W32 -> emit_ bci_OP_S_LE_32 []
+ W16 -> emit_ bci_OP_S_LE_16 []
+ W8 -> emit_ bci_OP_S_LE_08 []
+ _ -> unsupported_width
+
+ OP_INDEX_ADDR w -> case w of
+ W64 -> emit_ bci_OP_INDEX_ADDR_64 []
+ W32 -> emit_ bci_OP_INDEX_ADDR_32 []
+ W16 -> emit_ bci_OP_INDEX_ADDR_16 []
+ W8 -> emit_ bci_OP_INDEX_ADDR_08 []
+ _ -> unsupported_width
+
BRK_FUN arr tick_mod tick_mod_id tickx info_mod info_mod_id infox cc ->
do p1 <- ptr (BCOPtrBreakArray arr)
tick_addr <- lit1 $ BCONPtrFS $ moduleNameFS tick_mod
@@ -726,6 +863,7 @@ assembleI platform i = case i of
where
+ unsupported_width = panic "GHC.ByteCode.Asm: Unsupported Width"
emit_ = emit word_size
literal :: Literal -> m Word
=====================================
compiler/GHC/ByteCode/Instr.hs
=====================================
@@ -14,11 +14,14 @@ module GHC.ByteCode.Instr (
import GHC.Prelude
import GHC.ByteCode.Types
+import GHC.Cmm.Type (Width)
import GHCi.RemoteTypes
import GHC.StgToCmm.Layout ( ArgRep(..) )
import GHC.Utils.Outputable
+import GHC.Unit.Types (UnitId)
import GHC.Types.Name
import GHC.Types.Literal
+import GHC.Types.Unique
import GHC.Core.DataCon
import GHC.Builtin.PrimOps
import GHC.Runtime.Heap.Layout ( StgWord )
@@ -35,8 +38,6 @@ import GHC.Stack.CCS (CostCentre)
import GHC.Stg.Syntax
import GHCi.BreakArray (BreakArray)
import Language.Haskell.Syntax.Module.Name (ModuleName)
-import GHC.Types.Unique
-import GHC.Unit.Types (UnitId)
-- ----------------------------------------------------------------------------
-- Bytecode instructions
@@ -217,6 +218,39 @@ data BCInstr
| PRIMCALL
+ -- Primops - The actual interpreter instructions are flattened into 64/32/16/8 wide
+ -- instructions. But for generating code it's handy to have the width as argument
+ -- to avoid duplication.
+ | OP_ADD !Width
+ | OP_SUB !Width
+ | OP_AND !Width
+ | OP_XOR !Width
+ | OP_MUL !Width
+ | OP_SHL !Width
+ | OP_ASR !Width
+ | OP_LSR !Width
+ | OP_OR !Width
+
+ | OP_NOT !Width
+ | OP_NEG !Width
+
+ | OP_NEQ !Width
+ | OP_EQ !Width
+
+ | OP_U_LT !Width
+ | OP_U_GE !Width
+ | OP_U_GT !Width
+ | OP_U_LE !Width
+
+ | OP_S_LT !Width
+ | OP_S_GE !Width
+ | OP_S_GT !Width
+ | OP_S_LE !Width
+
+ -- Always puts at least a machine word on the stack.
+ -- We zero extend the result we put on the stack according to host byte order.
+ | OP_INDEX_ADDR !Width
+
-- For doing magic ByteArray passing to foreign calls
| SWIZZLE !WordOff -- to the ptr N words down the stack,
!Int -- add M
@@ -397,6 +431,32 @@ instance Outputable BCInstr where
0x2 -> text "(unsafe)"
_ -> empty)
ppr PRIMCALL = text "PRIMCALL"
+
+ ppr (OP_ADD w) = text "OP_ADD_" <> ppr w
+ ppr (OP_SUB w) = text "OP_SUB_" <> ppr w
+ ppr (OP_AND w) = text "OP_AND_" <> ppr w
+ ppr (OP_XOR w) = text "OP_XOR_" <> ppr w
+ ppr (OP_OR w) = text "OP_OR_" <> ppr w
+ ppr (OP_NOT w) = text "OP_NOT_" <> ppr w
+ ppr (OP_NEG w) = text "OP_NEG_" <> ppr w
+ ppr (OP_MUL w) = text "OP_MUL_" <> ppr w
+ ppr (OP_SHL w) = text "OP_SHL_" <> ppr w
+ ppr (OP_ASR w) = text "OP_ASR_" <> ppr w
+ ppr (OP_LSR w) = text "OP_LSR_" <> ppr w
+
+ ppr (OP_EQ w) = text "OP_EQ_" <> ppr w
+ ppr (OP_NEQ w) = text "OP_NEQ_" <> ppr w
+ ppr (OP_S_LT w) = text "OP_S_LT_" <> ppr w
+ ppr (OP_S_GE w) = text "OP_S_GE_" <> ppr w
+ ppr (OP_S_GT w) = text "OP_S_GT_" <> ppr w
+ ppr (OP_S_LE w) = text "OP_S_LE_" <> ppr w
+ ppr (OP_U_LT w) = text "OP_U_LT_" <> ppr w
+ ppr (OP_U_GE w) = text "OP_U_GE_" <> ppr w
+ ppr (OP_U_GT w) = text "OP_U_GT_" <> ppr w
+ ppr (OP_U_LE w) = text "OP_U_LE_" <> ppr w
+
+ ppr (OP_INDEX_ADDR w) = text "OP_INDEX_ADDR_" <> ppr w
+
ppr (SWIZZLE stkoff n) = text "SWIZZLE " <+> text "stkoff" <+> ppr stkoff
<+> text "by" <+> ppr n
ppr ENTER = text "ENTER"
@@ -505,6 +565,31 @@ bciStackUse RETURN{} = 1 -- pushes stg_ret_X for some X
bciStackUse RETURN_TUPLE{} = 1 -- pushes stg_ret_t header
bciStackUse CCALL{} = 0
bciStackUse PRIMCALL{} = 1 -- pushes stg_primcall
+bciStackUse OP_ADD{} = 0 -- We overestimate, it's -1 actually ...
+bciStackUse OP_SUB{} = 0
+bciStackUse OP_AND{} = 0
+bciStackUse OP_XOR{} = 0
+bciStackUse OP_OR{} = 0
+bciStackUse OP_NOT{} = 0
+bciStackUse OP_NEG{} = 0
+bciStackUse OP_MUL{} = 0
+bciStackUse OP_SHL{} = 0
+bciStackUse OP_ASR{} = 0
+bciStackUse OP_LSR{} = 0
+
+bciStackUse OP_NEQ{} = 0
+bciStackUse OP_EQ{} = 0
+bciStackUse OP_S_LT{} = 0
+bciStackUse OP_S_GT{} = 0
+bciStackUse OP_S_LE{} = 0
+bciStackUse OP_S_GE{} = 0
+bciStackUse OP_U_LT{} = 0
+bciStackUse OP_U_GT{} = 0
+bciStackUse OP_U_LE{} = 0
+bciStackUse OP_U_GE{} = 0
+
+bciStackUse OP_INDEX_ADDR{} = 0
+
bciStackUse SWIZZLE{} = 0
bciStackUse BRK_FUN{} = 0
=====================================
compiler/GHC/StgToByteCode.hs
=====================================
@@ -58,6 +58,7 @@ import GHC.Builtin.Uniques
import GHC.Data.FastString
import GHC.Utils.Panic
import GHC.Utils.Exception (evaluate)
+import GHC.CmmToAsm.Config (platformWordWidth)
import GHC.StgToCmm.Closure ( NonVoid(..), fromNonVoid, idPrimRepU,
addIdReps, addArgReps,
assertNonVoidIds, assertNonVoidStgArgs )
@@ -560,8 +561,7 @@ returnUnboxedTuple d s p es = do
-- Compile code to apply the given expression to the remaining args
-- on the stack, returning a HNF.
-schemeE
- :: StackDepth -> Sequel -> BCEnv -> CgStgExpr -> BcM BCInstrList
+schemeE :: StackDepth -> Sequel -> BCEnv -> CgStgExpr -> BcM BCInstrList
schemeE d s p (StgLit lit) = returnUnliftedAtom d s p (StgLitArg lit)
schemeE d s p (StgApp x [])
| isUnliftedType (idType x) = returnUnliftedAtom d s p (StgVarArg x)
@@ -712,8 +712,14 @@ schemeT d s p (StgOpApp (StgFCallOp (CCall ccall_spec) _ty) args result_ty)
then generateCCall d s p ccall_spec result_ty args
else unsupportedCConvException
-schemeT d s p (StgOpApp (StgPrimOp op) args _ty)
- = doTailCall d s p (primOpId op) (reverse args)
+schemeT d s p (StgOpApp (StgPrimOp op) args _ty) = do
+ profile <- getProfile
+ let platform = profilePlatform profile
+ case doPrimOp platform op d s p args of
+ -- Can we do this right in the interpreter?
+ Just prim_code -> prim_code
+ -- Otherwise we have to do a call to the primop wrapper instead :(
+ _ -> doTailCall d s p (primOpId op) (reverse args)
schemeT d s p (StgOpApp (StgPrimCallOp (PrimCall label unit)) args result_ty)
= generatePrimCall d s p label (Just unit) result_ty args
@@ -808,6 +814,300 @@ doTailCall init_d s p fn args = do
(final_d, more_push_code) <- push_seq (d + sz) args
return (final_d, push_code `appOL` more_push_code)
+doPrimOp :: Platform
+ -> PrimOp
+ -> StackDepth
+ -> Sequel
+ -> BCEnv
+ -> [StgArg]
+ -> Maybe (BcM BCInstrList)
+doPrimOp platform op init_d s p args =
+ case op of
+ IntAddOp -> sizedPrimOp OP_ADD
+ Int64AddOp -> only64bit $ sizedPrimOp OP_ADD
+ Int32AddOp -> sizedPrimOp OP_ADD
+ Int16AddOp -> sizedPrimOp OP_ADD
+ Int8AddOp -> sizedPrimOp OP_ADD
+ WordAddOp -> sizedPrimOp OP_ADD
+ Word64AddOp -> only64bit $ sizedPrimOp OP_ADD
+ Word32AddOp -> sizedPrimOp OP_ADD
+ Word16AddOp -> sizedPrimOp OP_ADD
+ Word8AddOp -> sizedPrimOp OP_ADD
+ AddrAddOp -> sizedPrimOp OP_ADD
+
+ IntMulOp -> sizedPrimOp OP_MUL
+ Int64MulOp -> only64bit $ sizedPrimOp OP_MUL
+ Int32MulOp -> sizedPrimOp OP_MUL
+ Int16MulOp -> sizedPrimOp OP_MUL
+ Int8MulOp -> sizedPrimOp OP_MUL
+ WordMulOp -> sizedPrimOp OP_MUL
+ Word64MulOp -> only64bit $ sizedPrimOp OP_MUL
+ Word32MulOp -> sizedPrimOp OP_MUL
+ Word16MulOp -> sizedPrimOp OP_MUL
+ Word8MulOp -> sizedPrimOp OP_MUL
+
+ IntSubOp -> sizedPrimOp OP_SUB
+ WordSubOp -> sizedPrimOp OP_SUB
+ Int64SubOp -> only64bit $ sizedPrimOp OP_SUB
+ Int32SubOp -> sizedPrimOp OP_SUB
+ Int16SubOp -> sizedPrimOp OP_SUB
+ Int8SubOp -> sizedPrimOp OP_SUB
+ Word64SubOp -> only64bit $ sizedPrimOp OP_SUB
+ Word32SubOp -> sizedPrimOp OP_SUB
+ Word16SubOp -> sizedPrimOp OP_SUB
+ Word8SubOp -> sizedPrimOp OP_SUB
+ AddrSubOp -> sizedPrimOp OP_SUB
+
+ IntAndOp -> sizedPrimOp OP_AND
+ WordAndOp -> sizedPrimOp OP_AND
+ Word64AndOp -> only64bit $ sizedPrimOp OP_AND
+ Word32AndOp -> sizedPrimOp OP_AND
+ Word16AndOp -> sizedPrimOp OP_AND
+ Word8AndOp -> sizedPrimOp OP_AND
+
+ IntNotOp -> sizedPrimOp OP_NOT
+ WordNotOp -> sizedPrimOp OP_NOT
+ Word64NotOp -> only64bit $ sizedPrimOp OP_NOT
+ Word32NotOp -> sizedPrimOp OP_NOT
+ Word16NotOp -> sizedPrimOp OP_NOT
+ Word8NotOp -> sizedPrimOp OP_NOT
+
+ IntXorOp -> sizedPrimOp OP_XOR
+ WordXorOp -> sizedPrimOp OP_XOR
+ Word64XorOp -> only64bit $ sizedPrimOp OP_XOR
+ Word32XorOp -> sizedPrimOp OP_XOR
+ Word16XorOp -> sizedPrimOp OP_XOR
+ Word8XorOp -> sizedPrimOp OP_XOR
+
+ IntOrOp -> sizedPrimOp OP_OR
+ WordOrOp -> sizedPrimOp OP_OR
+ Word64OrOp -> only64bit $ sizedPrimOp OP_OR
+ Word32OrOp -> sizedPrimOp OP_OR
+ Word16OrOp -> sizedPrimOp OP_OR
+ Word8OrOp -> sizedPrimOp OP_OR
+
+ WordSllOp -> sizedPrimOp OP_SHL
+ Word64SllOp -> only64bit $ sizedPrimOp OP_SHL -- check 32bit platform
+ Word32SllOp -> sizedPrimOp OP_SHL
+ Word16SllOp -> sizedPrimOp OP_SHL
+ Word8SllOp -> sizedPrimOp OP_SHL
+ IntSllOp -> sizedPrimOp OP_SHL
+ Int64SllOp -> only64bit $ sizedPrimOp OP_SHL
+ Int32SllOp -> sizedPrimOp OP_SHL
+ Int16SllOp -> sizedPrimOp OP_SHL
+ Int8SllOp -> sizedPrimOp OP_SHL
+
+ WordSrlOp -> sizedPrimOp OP_LSR
+ Word64SrlOp -> only64bit $ sizedPrimOp OP_LSR
+ Word32SrlOp -> sizedPrimOp OP_LSR
+ Word16SrlOp -> sizedPrimOp OP_LSR
+ Word8SrlOp -> sizedPrimOp OP_LSR
+ IntSrlOp -> sizedPrimOp OP_LSR
+ Int64SrlOp -> only64bit $ sizedPrimOp OP_LSR -- check 32bit platform
+ Int32SrlOp -> sizedPrimOp OP_LSR
+ Int16SrlOp -> sizedPrimOp OP_LSR
+ Int8SrlOp -> sizedPrimOp OP_LSR
+
+ IntSraOp -> sizedPrimOp OP_ASR
+ Int64SraOp -> only64bit $ sizedPrimOp OP_ASR -- check 32bit platform
+ Int32SraOp -> sizedPrimOp OP_ASR
+ Int16SraOp -> sizedPrimOp OP_ASR
+ Int8SraOp -> sizedPrimOp OP_ASR
+
+
+ IntNeOp -> sizedPrimOp OP_NEQ
+ Int64NeOp -> only64bit $ sizedPrimOp OP_NEQ
+ Int32NeOp -> sizedPrimOp OP_NEQ
+ Int16NeOp -> sizedPrimOp OP_NEQ
+ Int8NeOp -> sizedPrimOp OP_NEQ
+ WordNeOp -> sizedPrimOp OP_NEQ
+ Word64NeOp -> only64bit $ sizedPrimOp OP_NEQ
+ Word32NeOp -> sizedPrimOp OP_NEQ
+ Word16NeOp -> sizedPrimOp OP_NEQ
+ Word8NeOp -> sizedPrimOp OP_NEQ
+ AddrNeOp -> sizedPrimOp OP_NEQ
+
+ IntEqOp -> sizedPrimOp OP_EQ
+ Int64EqOp -> only64bit $ sizedPrimOp OP_EQ
+ Int32EqOp -> sizedPrimOp OP_EQ
+ Int16EqOp -> sizedPrimOp OP_EQ
+ Int8EqOp -> sizedPrimOp OP_EQ
+ WordEqOp -> sizedPrimOp OP_EQ
+ Word64EqOp -> only64bit $ sizedPrimOp OP_EQ
+ Word32EqOp -> sizedPrimOp OP_EQ
+ Word16EqOp -> sizedPrimOp OP_EQ
+ Word8EqOp -> sizedPrimOp OP_EQ
+ AddrEqOp -> sizedPrimOp OP_EQ
+ CharEqOp -> sizedPrimOp OP_EQ
+
+ IntLtOp -> sizedPrimOp OP_S_LT
+ Int64LtOp -> only64bit $ sizedPrimOp OP_S_LT
+ Int32LtOp -> sizedPrimOp OP_S_LT
+ Int16LtOp -> sizedPrimOp OP_S_LT
+ Int8LtOp -> sizedPrimOp OP_S_LT
+ WordLtOp -> sizedPrimOp OP_U_LT
+ Word64LtOp -> only64bit $ sizedPrimOp OP_U_LT
+ Word32LtOp -> sizedPrimOp OP_U_LT
+ Word16LtOp -> sizedPrimOp OP_U_LT
+ Word8LtOp -> sizedPrimOp OP_U_LT
+ AddrLtOp -> sizedPrimOp OP_U_LT
+ CharLtOp -> sizedPrimOp OP_U_LT
+
+ IntGeOp -> sizedPrimOp OP_S_GE
+ Int64GeOp -> only64bit $ sizedPrimOp OP_S_GE
+ Int32GeOp -> sizedPrimOp OP_S_GE
+ Int16GeOp -> sizedPrimOp OP_S_GE
+ Int8GeOp -> sizedPrimOp OP_S_GE
+ WordGeOp -> sizedPrimOp OP_U_GE
+ Word64GeOp -> only64bit $ sizedPrimOp OP_U_GE
+ Word32GeOp -> sizedPrimOp OP_U_GE
+ Word16GeOp -> sizedPrimOp OP_U_GE
+ Word8GeOp -> sizedPrimOp OP_U_GE
+ AddrGeOp -> sizedPrimOp OP_U_GE
+ CharGeOp -> sizedPrimOp OP_U_GE
+
+ IntGtOp -> sizedPrimOp OP_S_GT
+ Int64GtOp -> only64bit $ sizedPrimOp OP_S_GT
+ Int32GtOp -> sizedPrimOp OP_S_GT
+ Int16GtOp -> sizedPrimOp OP_S_GT
+ Int8GtOp -> sizedPrimOp OP_S_GT
+ WordGtOp -> sizedPrimOp OP_U_GT
+ Word64GtOp -> only64bit $ sizedPrimOp OP_U_GT
+ Word32GtOp -> sizedPrimOp OP_U_GT
+ Word16GtOp -> sizedPrimOp OP_U_GT
+ Word8GtOp -> sizedPrimOp OP_U_GT
+ AddrGtOp -> sizedPrimOp OP_U_GT
+ CharGtOp -> sizedPrimOp OP_U_GT
+
+ IntLeOp -> sizedPrimOp OP_S_LE
+ Int64LeOp -> only64bit $ sizedPrimOp OP_S_LE
+ Int32LeOp -> sizedPrimOp OP_S_LE
+ Int16LeOp -> sizedPrimOp OP_S_LE
+ Int8LeOp -> sizedPrimOp OP_S_LE
+ WordLeOp -> sizedPrimOp OP_U_LE
+ Word64LeOp -> only64bit $ sizedPrimOp OP_U_LE
+ Word32LeOp -> sizedPrimOp OP_U_LE
+ Word16LeOp -> sizedPrimOp OP_U_LE
+ Word8LeOp -> sizedPrimOp OP_U_LE
+ AddrLeOp -> sizedPrimOp OP_U_LE
+ CharLeOp -> sizedPrimOp OP_U_LE
+
+ IntNegOp -> sizedPrimOp OP_NEG
+ Int64NegOp -> only64bit $ sizedPrimOp OP_NEG
+ Int32NegOp -> sizedPrimOp OP_NEG
+ Int16NegOp -> sizedPrimOp OP_NEG
+ Int8NegOp -> sizedPrimOp OP_NEG
+
+ IntToWordOp -> mk_conv (platformWordWidth platform)
+ WordToIntOp -> mk_conv (platformWordWidth platform)
+ Int8ToWord8Op -> mk_conv W8
+ Word8ToInt8Op -> mk_conv W8
+ Int16ToWord16Op -> mk_conv W16
+ Word16ToInt16Op -> mk_conv W16
+ Int32ToWord32Op -> mk_conv W32
+ Word32ToInt32Op -> mk_conv W32
+ Int64ToWord64Op -> only64bit $ mk_conv W64
+ Word64ToInt64Op -> only64bit $ mk_conv W64
+ IntToAddrOp -> mk_conv (platformWordWidth platform)
+ AddrToIntOp -> mk_conv (platformWordWidth platform)
+ ChrOp -> mk_conv (platformWordWidth platform) -- Int# and Char# are rep'd the same
+ OrdOp -> mk_conv (platformWordWidth platform)
+
+ -- Memory primops, expand the ghci-mem-primops test if you add more.
+ IndexOffAddrOp_Word8 -> primOpWithRep (OP_INDEX_ADDR W8) W8
+ IndexOffAddrOp_Word16 -> primOpWithRep (OP_INDEX_ADDR W16) W16
+ IndexOffAddrOp_Word32 -> primOpWithRep (OP_INDEX_ADDR W32) W32
+ IndexOffAddrOp_Word64 -> only64bit $ primOpWithRep (OP_INDEX_ADDR W64) W64
+
+ _ -> Nothing
+ where
+ only64bit = if platformWordWidth platform == W64 then id else const Nothing
+ primArg1Width :: StgArg -> Width
+ primArg1Width arg
+ | rep <- (stgArgRepU arg)
+ = case rep of
+ AddrRep -> platformWordWidth platform
+ IntRep -> platformWordWidth platform
+ WordRep -> platformWordWidth platform
+
+ Int64Rep -> W64
+ Word64Rep -> W64
+
+ Int32Rep -> W32
+ Word32Rep -> W32
+
+ Int16Rep -> W16
+ Word16Rep -> W16
+
+ Int8Rep -> W8
+ Word8Rep -> W8
+
+ FloatRep -> unexpectedRep
+ DoubleRep -> unexpectedRep
+
+ BoxedRep{} -> unexpectedRep
+ VecRep{} -> unexpectedRep
+ where
+ unexpectedRep = panic "doPrimOp: Unexpected argument rep"
+
+
+ -- TODO: The slides for the result need to be two words on 32bit for 64bit ops.
+ mkNReturn width
+ | W64 <- width = RETURN L -- L works for 64 bit on any platform
+ | otherwise = RETURN N -- <64bit width, fits in word on all platforms
+
+ mkSlideWords width = if platformWordWidth platform < width then 2 else 1
+
+ -- Push args, execute primop, slide, return_N
+ -- Decides width of operation based on first argument.
+ sizedPrimOp op_inst = Just $ do
+ let width = primArg1Width (head args)
+ prim_code <- mkPrimOpCode init_d s p (op_inst width) $ args
+ let slide = mkSlideW (mkSlideWords width) (bytesToWords platform $ init_d - s) `snocOL` mkNReturn width
+ return $ prim_code `appOL` slide
+
+ -- primOpWithRep op w => operation @op@ resulting in result @w@ wide.
+ primOpWithRep :: BCInstr -> Width -> Maybe (BcM (OrdList BCInstr))
+ primOpWithRep op_inst result_width = Just $ do
+ prim_code <- mkPrimOpCode init_d s p op_inst $ args
+ let slide = mkSlideW (mkSlideWords result_width) (bytesToWords platform $ init_d - s) `snocOL` mkNReturn result_width
+ return $ prim_code `appOL` slide
+
+ -- Coerce the argument, requires them to be the same size
+ mk_conv :: Width -> Maybe (BcM (OrdList BCInstr))
+ mk_conv target_width = Just $ do
+ let width = primArg1Width (head args)
+ massert (width == target_width)
+ (push_code, _bytes) <- pushAtom init_d p (head args)
+ let slide = mkSlideW (mkSlideWords target_width) (bytesToWords platform $ init_d - s) `snocOL` mkNReturn target_width
+ return $ push_code `appOL` slide
+
+-- Push the arguments on the stack and emit the given instruction
+-- Pushes at least one word per non void arg.
+mkPrimOpCode
+ :: StackDepth
+ -> Sequel
+ -> BCEnv
+ -> BCInstr -- The operator
+ -> [StgArg] -- Args, in *reverse* order (must be fully applied)
+ -> BcM BCInstrList
+mkPrimOpCode orig_d _ p op_inst args = app_code
+ where
+ app_code = do
+ profile <- getProfile
+ let _platform = profilePlatform profile
+
+ do_pushery :: StackDepth -> [StgArg] -> BcM BCInstrList
+ do_pushery !d (arg : args) = do
+ (push,arg_bytes) <- pushAtom d p arg
+ more_push_code <- do_pushery (d + arg_bytes) args
+ return (push `appOL` more_push_code)
+ do_pushery !_d [] = do
+ return (unitOL op_inst)
+
+ -- Push on the stack in the reverse order.
+ do_pushery orig_d (reverse args)
+
-- v. similar to CgStackery.findMatch, ToDo: merge
findPushSeq :: [ArgRep] -> (BCInstr, Int, [ArgRep])
findPushSeq (P: P: P: P: P: P: rest)
=====================================
rts/Disassembler.c
=====================================
@@ -62,6 +62,26 @@ disInstr ( StgBCO *bco, int pc )
#error Cannot cope with WORD_SIZE_IN_BITS being nether 32 nor 64
#endif
#define BCO_GET_LARGE_ARG ((instr & bci_FLAG_LARGE_ARGS) ? BCO_READ_NEXT_WORD : BCO_NEXT)
+// For brevity
+#define BELCH_INSTR_NAME(OP_NAME) \
+ case bci_ ## OP_NAME: \
+ debugBelch("OP_NAME\n"); \
+ break
+
+#define BELCH_INSTR_NAME_ALL_SIZES(OP_NAME) \
+ case bci_ ## OP_NAME ## _64: \
+ debugBelch("#OP_NAME" "_64\n"); \
+ break; \
+ case bci_ ## OP_NAME ## _32: \
+ debugBelch("#OP_NAME" "_32\n"); \
+ break; \
+ case bci_ ## OP_NAME ## _16: \
+ debugBelch("#OP_NAME" "_16\n"); \
+ break; \
+ case bci_ ## OP_NAME ## _08: \
+ debugBelch("#OP_NAME" "_08\n"); \
+ break;
+
switch (instr & 0xff) {
case bci_BRK_FUN:
@@ -419,38 +439,20 @@ disInstr ( StgBCO *bco, int pc )
debugBelch("TESTEQ_P %d, fail to %d\n", instrs[pc],
instrs[pc+1]);
pc += 2; break;
- case bci_CASEFAIL:
- debugBelch("CASEFAIL\n" );
- break;
+ BELCH_INSTR_NAME(CASEFAIL);
case bci_JMP:
debugBelch("JMP to %d\n", instrs[pc]);
pc += 1; break;
- case bci_ENTER:
- debugBelch("ENTER\n");
- break;
+ BELCH_INSTR_NAME(ENTER);
+ BELCH_INSTR_NAME(RETURN_P);
+ BELCH_INSTR_NAME(RETURN_N);
+ BELCH_INSTR_NAME(RETURN_F);
+ BELCH_INSTR_NAME(RETURN_D);
+ BELCH_INSTR_NAME(RETURN_L);
+ BELCH_INSTR_NAME(RETURN_V);
+ BELCH_INSTR_NAME(RETURN_T);
- case bci_RETURN_P:
- debugBelch("RETURN_P\n" );
- break;
- case bci_RETURN_N:
- debugBelch("RETURN_N\n" );
- break;
- case bci_RETURN_F:
- debugBelch("RETURN_F\n" );
- break;
- case bci_RETURN_D:
- debugBelch("RETURN_D\n" );
- break;
- case bci_RETURN_L:
- debugBelch("RETURN_L\n" );
- break;
- case bci_RETURN_V:
- debugBelch("RETURN_V\n" );
- break;
- case bci_RETURN_T:
- debugBelch("RETURN_T\n ");
- break;
case bci_BCO_NAME: {
const char *name = (const char*) literals[instrs[pc]];
@@ -459,6 +461,33 @@ disInstr ( StgBCO *bco, int pc )
break;
}
+ BELCH_INSTR_NAME_ALL_SIZES(OP_ADD);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_SUB);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_AND);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_XOR);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_OR);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_NOT);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_NEG);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_MUL);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_SHL);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_ASR);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_LSR);
+
+ BELCH_INSTR_NAME_ALL_SIZES(OP_NEQ);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_EQ);
+
+ BELCH_INSTR_NAME_ALL_SIZES(OP_U_GT);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_U_LE);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_U_GE);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_U_LT);
+
+ BELCH_INSTR_NAME_ALL_SIZES(OP_S_GT);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_S_LE);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_S_GE);
+ BELCH_INSTR_NAME_ALL_SIZES(OP_S_LT);
+
+ BELCH_INSTR_NAME_ALL_SIZES(OP_INDEX_ADDR);
+
default:
barf("disInstr: unknown opcode %u", (unsigned int) instr);
}
=====================================
rts/Interpreter.c
=====================================
@@ -178,23 +178,35 @@ See also Note [Width of parameters] for some more motivation.
#define Sp_plusB(n) ((void *)((StgWord8*)Sp + (ptrdiff_t)(n)))
#define Sp_minusB(n) ((void *)((StgWord8*)Sp - (ptrdiff_t)(n)))
-#define Sp_plusW(n) (Sp_plusB((ptrdiff_t)(n) * (ptrdiff_t)sizeof(W_)))
-#define Sp_minusW(n) (Sp_minusB((ptrdiff_t)(n) * (ptrdiff_t)sizeof(W_)))
+#define Sp_plusW(n) ((void*)Sp_plusB((ptrdiff_t)(n) * (ptrdiff_t)sizeof(W_)))
+#define Sp_plusW64(n) ((void*)Sp_plusB((ptrdiff_t)(n) * (ptrdiff_t)sizeof(StgWord64)))
+#define Sp_minusW(n) ((void*)Sp_minusB((ptrdiff_t)(n) * (ptrdiff_t)sizeof(W_)))
#define Sp_addB(n) (Sp = Sp_plusB(n))
#define Sp_subB(n) (Sp = Sp_minusB(n))
#define Sp_addW(n) (Sp = Sp_plusW(n))
+#define Sp_addW64(n) (Sp = Sp_plusW64(n))
#define Sp_subW(n) (Sp = Sp_minusW(n))
-#define SpW(n) (*(StgWord*)(Sp_plusW(n)))
-#define SpB(n) (*(StgWord*)(Sp_plusB(n)))
+// Assumes stack location is within stack chunk bounds
+#define SpW(n) (*(StgWord*)(Sp_plusW(n)))
+#define SpW64(n) (*(StgWord*)(Sp_plusW64(n)))
-#define WITHIN_CAP_CHUNK_BOUNDS(n) WITHIN_CHUNK_BOUNDS(n, cap->r.rCurrentTSO->stackobj)
+#define WITHIN_CAP_CHUNK_BOUNDS_W(n) WITHIN_CHUNK_BOUNDS_W(n, cap->r.rCurrentTSO->stackobj)
-#define WITHIN_CHUNK_BOUNDS(n, s) \
- (RTS_LIKELY((StgWord*)(Sp_plusW(n)) < ((s)->stack + (s)->stack_size - sizeofW(StgUnderflowFrame))))
+#define WITHIN_CHUNK_BOUNDS_W(n, s) \
+ (RTS_LIKELY(((StgWord*) Sp_plusW(n)) < ((s)->stack + (s)->stack_size - sizeofW(StgUnderflowFrame))))
+#define W64_TO_WDS(n) ((n * sizeof(StgWord64) / sizeof(StgWord)))
+
+// Always safe to use - Return the value at the address
+#define ReadSpW(n) (*((StgWord*) SafeSpWP(n)))
+//Argument is offset in multiples of word64
+#define ReadSpW64(n) (*((StgWord64*) SafeSpWP(W64_TO_WDS(n))))
+// Perhaps confusingly this still reads a full word, merely the offset is in bytes.
+#define ReadSpB(n) (*((StgWord*) SafeSpBP(n)))
+
/* Note [PUSH_L underflow]
~~~~~~~~~~~~~~~~~~~~~~~
BCOs can be nested, resulting in nested BCO stack frames where the inner most
@@ -215,9 +227,9 @@ variables. If a stack overflow happens between the creation of the stack frame
for BCO_1 and BCO_N the RTS might move BCO_N to a new stack chunk while leaving
BCO_1 in place, invalidating a simple offset based reference to the outer stack
frames.
-Therefore `ReadSpW` first performs a bounds check to ensure that accesses onto
+Therefore `SafeSpW` first performs a bounds check to ensure that accesses onto
the stack will succeed. If the target address would not be a valid location for
-the current stack chunk then `slow_spw` function is called, which dereferences
+the current stack chunk then `slow_sp` function is called, which dereferences
the underflow frame to adjust the offset before performing the lookup.
┌->--x | CHK_1 |
@@ -229,14 +241,43 @@ the underflow frame to adjust the offset before performing the lookup.
|---------| | PUSH_L <n>
| BCO_ N | ->-┘
|---------|
+
+To keep things simpler all accesses to the stack which might go beyond the stack
+chunk go through one of the ReadSP* or SafeSP* macros.
+When writing to the stack there is no need for checks, we ensured we have space
+in the current chunk ahead of time. So there we use SpW and it's variants which
+omit the stack bounds check.
+
See ticket #25750
*/
-#define ReadSpW(n) \
- ((WITHIN_CAP_CHUNK_BOUNDS(n)) ? SpW(n): slow_spw(Sp, cap->r.rCurrentTSO->stackobj, n))
+// Returns a pointer to the stack location.
+#define SafeSpWP(n) \
+ ( ((WITHIN_CAP_CHUNK_BOUNDS_W(n)) ? Sp_plusW(n) : slow_spw(Sp, cap->r.rCurrentTSO->stackobj, n)))
+#define SafeSpBP(off_w) \
+ ( (WITHIN_CAP_CHUNK_BOUNDS_W((1+(off_w))/sizeof(StgWord))) ? \
+ Sp_plusB(off_w) : \
+ (void*)((ptrdiff_t)((ptrdiff_t)(off_w) % (ptrdiff_t)sizeof(StgWord)) + (StgWord8*)slow_spw(Sp, cap->r.rCurrentTSO->stackobj, (off_w)/sizeof(StgWord))) \
+ )
+
+/* Note [Interpreter subword primops]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In general the interpreter stack is host-platform word aligned.
+We keep with this convention when evaluating primops for simplicity.
+
+This means:
+
+* All arguments are pushed extended to word size.
+* Results are written to the stack extended to word size.
+
+The only exception are constructor allocations where we push unaligned subwords
+on the stack which are cleaned up by the PACK instruction afterwards.
+
+*/
+
STATIC_INLINE StgPtr
allocate_NONUPD (Capability *cap, int n_words)
{
@@ -392,11 +433,12 @@ StgClosure * copyPAP (Capability *cap, StgPAP *oldpap)
// See Note [PUSH_L underflow] for in which situations this
// slow lookup is needed
-static StgWord
-slow_spw(void *Sp, StgStack *cur_stack, StgWord offset){
- // 1. If in range, access the item from the current stack chunk
- if (WITHIN_CHUNK_BOUNDS(offset, cur_stack)) {
- return SpW(offset);
+// Returns a pointer to the stack location.
+static void*
+slow_spw(void *Sp, StgStack *cur_stack, StgWord offset_words){
+ // 1. If in range, simply return ptr+offset_words pointing into the current stack chunk
+ if (WITHIN_CHUNK_BOUNDS_W(offset_words, cur_stack)) {
+ return Sp_plusW(offset_words);
}
// 2. Not in this stack chunk, so access the underflow frame.
else {
@@ -420,21 +462,19 @@ slow_spw(void *Sp, StgStack *cur_stack, StgWord offset){
// How many words were on the stack
stackWords = (StgWord *)frame - (StgWord *) Sp;
- ASSERT(offset > stackWords);
+ ASSERT(offset_words > stackWords);
// Recursive, in the very unlikely case we have to traverse two
// stack chunks.
- return slow_spw(new_stack->sp, new_stack, offset-stackWords);
+ return slow_spw(new_stack->sp, new_stack, offset_words-stackWords);
}
// 2b. Access the element if there is no underflow frame, it must be right
// at the top of the stack.
else {
// Not actually in the underflow case
- return SpW(offset);
+ return Sp_plusW(offset_words);
}
-
}
-
}
// Compute the pointer tag for the constructor and tag the pointer;
@@ -883,7 +923,7 @@ do_return_nonpointer:
// get the offset of the header of the next stack frame
offset = stack_frame_sizeW((StgClosure *)Sp);
- switch (get_itbl((StgClosure*)(Sp_plusW(offset)))->type) {
+ switch (get_itbl((StgClosure*)(SafeSpWP(offset)))->type) {
case RET_BCO:
// Returning to an interpreted continuation: pop the return frame
@@ -1236,9 +1276,9 @@ run_BCO:
#endif
bci = BCO_NEXT;
- /* We use the high 8 bits for flags, only the highest of which is
- * currently allocated */
- ASSERT((bci & 0xFF00) == (bci & 0x8000));
+ /* We use the high 8 bits for flags. The highest of which is
+ * currently allocated to LARGE_ARGS */
+ ASSERT((bci & 0xFF00) == (bci & ( bci_FLAG_LARGE_ARGS )));
switch (bci & 0xFF) {
@@ -1429,41 +1469,41 @@ run_BCO:
case bci_PUSH8: {
W_ off = BCO_GET_LARGE_ARG;
Sp_subB(1);
- *(StgWord8*)Sp = (StgWord8) *(StgWord*)(Sp_plusB(off+1));
+ *(StgWord8*)Sp = (StgWord8) (ReadSpB(off+1));
goto nextInsn;
}
case bci_PUSH16: {
W_ off = BCO_GET_LARGE_ARG;
Sp_subB(2);
- *(StgWord16*)Sp = (StgWord16) *(StgWord*)(Sp_plusB(off+2));
+ *(StgWord16*)Sp = (StgWord16) (ReadSpB(off+2));
goto nextInsn;
}
case bci_PUSH32: {
W_ off = BCO_GET_LARGE_ARG;
Sp_subB(4);
- *(StgWord32*)Sp = (StgWord32) *(StgWord*)(Sp_plusB(off+4));
+ *(StgWord32*)Sp = (StgWord32) (ReadSpB(off+4));
goto nextInsn;
}
case bci_PUSH8_W: {
W_ off = BCO_GET_LARGE_ARG;
- *(StgWord*)(Sp_minusW(1)) = (StgWord) ((StgWord8) *(StgWord*)(Sp_plusB(off)));
+ *(StgWord*)(Sp_minusW(1)) = (StgWord) ((StgWord8) (ReadSpB(off)));
Sp_subW(1);
goto nextInsn;
}
case bci_PUSH16_W: {
W_ off = BCO_GET_LARGE_ARG;
- *(StgWord*)(Sp_minusW(1)) = (StgWord) ((StgWord16) *(StgWord*)(Sp_plusB(off)));
+ *(StgWord*)(Sp_minusW(1)) = (StgWord) ((StgWord16) (ReadSpB(off)));
Sp_subW(1);
goto nextInsn;
}
case bci_PUSH32_W: {
W_ off = BCO_GET_LARGE_ARG;
- *(StgWord*)(Sp_minusW(1)) = (StgWord) ((StgWord32) *(StgWord*)(Sp_plusB(off)));
+ *(StgWord*)(Sp_minusW(1)) = (StgWord) ((StgWord32) (ReadSpB(off)));
Sp_subW(1);
goto nextInsn;
}
@@ -1953,7 +1993,7 @@ run_BCO:
case bci_TESTLT_I64: {
int discr = BCO_GET_LARGE_ARG;
int failto = BCO_GET_LARGE_ARG;
- StgInt64 stackInt = (*(StgInt64*)Sp);
+ StgInt64 stackInt = ReadSpW64(0);
if (stackInt >= BCO_LITI64(discr))
bciPtr = failto;
goto nextInsn;
@@ -1999,7 +2039,7 @@ run_BCO:
case bci_TESTEQ_I64: {
int discr = BCO_GET_LARGE_ARG;
int failto = BCO_GET_LARGE_ARG;
- StgInt64 stackInt = (*(StgInt64*)Sp);
+ StgInt64 stackInt = ReadSpW64(0);
if (stackInt != BCO_LITI64(discr)) {
bciPtr = failto;
}
@@ -2048,7 +2088,7 @@ run_BCO:
case bci_TESTLT_W64: {
int discr = BCO_GET_LARGE_ARG;
int failto = BCO_GET_LARGE_ARG;
- StgWord64 stackWord = (*(StgWord64*)Sp);
+ StgWord64 stackWord = ReadSpW64(0);
if (stackWord >= BCO_LITW64(discr))
bciPtr = failto;
goto nextInsn;
@@ -2094,7 +2134,7 @@ run_BCO:
case bci_TESTEQ_W64: {
int discr = BCO_GET_LARGE_ARG;
int failto = BCO_GET_LARGE_ARG;
- StgWord64 stackWord = (*(StgWord64*)Sp);
+ StgWord64 stackWord = ReadSpW64(0);
if (stackWord != BCO_LITW64(discr)) {
bciPtr = failto;
}
@@ -2231,7 +2271,7 @@ run_BCO:
case bci_SWIZZLE: {
W_ stkoff = BCO_GET_LARGE_ARG;
StgInt n = BCO_GET_LARGE_ARG;
- (*(StgInt*)(Sp_plusW(stkoff))) += n;
+ (*(StgInt*)(SafeSpWP(stkoff))) += n;
goto nextInsn;
}
@@ -2241,6 +2281,203 @@ run_BCO:
RETURN_TO_SCHEDULER_NO_PAUSE(ThreadRunGHC, ThreadYielding);
}
+// op :: ty -> ty
+#define UN_SIZED_OP(op,ty) \
+ { \
+ if(sizeof(ty) == 8) { \
+ ty r = op ((ty) ReadSpW64(0)); \
+ SpW64(0) = (StgWord64) r; \
+ } else { \
+ ty r = op ((ty) ReadSpW(0)); \
+ SpW(0) = (StgWord) r; \
+ } \
+ goto nextInsn; \
+ }
+
+// op :: ty -> ty -> ty
+#define SIZED_BIN_OP(op,ty) \
+ { \
+ if(sizeof(ty) == 8) { \
+ ty r = ((ty) ReadSpW64(0)) op ((ty) ReadSpW64(1)); \
+ Sp_addW64(1); \
+ SpW64(0) = (StgWord64) r; \
+ } else { \
+ ty r = ((ty) ReadSpW(0)) op ((ty) ReadSpW(1)); \
+ Sp_addW(1); \
+ SpW(0) = (StgWord) r; \
+ }; \
+ goto nextInsn; \
+ }
+
+// op :: ty -> Int -> ty
+#define SIZED_BIN_OP_TY_INT(op,ty) \
+{ \
+ if(sizeof(ty) > sizeof(StgWord)) { \
+ ty r = ((ty) ReadSpW64(0)) op ((ty) ReadSpW(2)); \
+ Sp_addW(1); \
+ SpW64(0) = (StgWord64) r; \
+ } else { \
+ ty r = ((ty) ReadSpW(0)) op ((ty) ReadSpW(1)); \
+ Sp_addW(1); \
+ SpW(0) = (StgWord) r; \
+ }; \
+ goto nextInsn; \
+}
+
+// op :: ty -> ty -> Int
+#define SIZED_BIN_OP_TY_TY_INT(op,ty) \
+{ \
+ if(sizeof(ty) > sizeof(StgWord)) { \
+ ty r = ((ty) ReadSpW64(0)) op ((ty) ReadSpW64(1)); \
+ Sp_addW(3); \
+ SpW(0) = (StgWord) r; \
+ } else { \
+ ty r = ((ty) ReadSpW(0)) op ((ty) ReadSpW(1)); \
+ Sp_addW(1); \
+ SpW(0) = (StgWord) r; \
+ }; \
+ goto nextInsn; \
+}
+
+ case bci_OP_ADD_64: SIZED_BIN_OP(+, StgInt64)
+ case bci_OP_SUB_64: SIZED_BIN_OP(-, StgInt64)
+ case bci_OP_AND_64: SIZED_BIN_OP(&, StgInt64)
+ case bci_OP_XOR_64: SIZED_BIN_OP(^, StgInt64)
+ case bci_OP_OR_64: SIZED_BIN_OP(|, StgInt64)
+ case bci_OP_MUL_64: SIZED_BIN_OP(*, StgInt64)
+ case bci_OP_SHL_64: SIZED_BIN_OP_TY_INT(<<, StgWord64)
+ case bci_OP_LSR_64: SIZED_BIN_OP_TY_INT(>>, StgWord64)
+ case bci_OP_ASR_64: SIZED_BIN_OP_TY_INT(>>, StgInt64)
+
+ case bci_OP_NEQ_64: SIZED_BIN_OP_TY_TY_INT(!=, StgWord64)
+ case bci_OP_EQ_64: SIZED_BIN_OP_TY_TY_INT(==, StgWord64)
+ case bci_OP_U_GT_64: SIZED_BIN_OP_TY_TY_INT(>, StgWord64)
+ case bci_OP_U_GE_64: SIZED_BIN_OP_TY_TY_INT(>=, StgWord64)
+ case bci_OP_U_LT_64: SIZED_BIN_OP_TY_TY_INT(<, StgWord64)
+ case bci_OP_U_LE_64: SIZED_BIN_OP_TY_TY_INT(<=, StgWord64)
+
+ case bci_OP_S_GT_64: SIZED_BIN_OP_TY_TY_INT(>, StgInt64)
+ case bci_OP_S_GE_64: SIZED_BIN_OP_TY_TY_INT(>=, StgInt64)
+ case bci_OP_S_LT_64: SIZED_BIN_OP_TY_TY_INT(<, StgInt64)
+ case bci_OP_S_LE_64: SIZED_BIN_OP_TY_TY_INT(<=, StgInt64)
+
+ case bci_OP_NOT_64: UN_SIZED_OP(~, StgWord64)
+ case bci_OP_NEG_64: UN_SIZED_OP(-, StgInt64)
+
+
+ case bci_OP_ADD_32: SIZED_BIN_OP(+, StgInt32)
+ case bci_OP_SUB_32: SIZED_BIN_OP(-, StgInt32)
+ case bci_OP_AND_32: SIZED_BIN_OP(&, StgInt32)
+ case bci_OP_XOR_32: SIZED_BIN_OP(^, StgInt32)
+ case bci_OP_OR_32: SIZED_BIN_OP(|, StgInt32)
+ case bci_OP_MUL_32: SIZED_BIN_OP(*, StgInt32)
+ case bci_OP_SHL_32: SIZED_BIN_OP_TY_INT(<<, StgWord32)
+ case bci_OP_LSR_32: SIZED_BIN_OP_TY_INT(>>, StgWord32)
+ case bci_OP_ASR_32: SIZED_BIN_OP_TY_INT(>>, StgInt32)
+
+ case bci_OP_NEQ_32: SIZED_BIN_OP_TY_TY_INT(!=, StgWord32)
+ case bci_OP_EQ_32: SIZED_BIN_OP_TY_TY_INT(==, StgWord32)
+ case bci_OP_U_GT_32: SIZED_BIN_OP_TY_TY_INT(>, StgWord32)
+ case bci_OP_U_GE_32: SIZED_BIN_OP_TY_TY_INT(>=, StgWord32)
+ case bci_OP_U_LT_32: SIZED_BIN_OP_TY_TY_INT(<, StgWord32)
+ case bci_OP_U_LE_32: SIZED_BIN_OP_TY_TY_INT(<=, StgWord32)
+
+ case bci_OP_S_GT_32: SIZED_BIN_OP_TY_TY_INT(>, StgInt32)
+ case bci_OP_S_GE_32: SIZED_BIN_OP_TY_TY_INT(>=, StgInt32)
+ case bci_OP_S_LT_32: SIZED_BIN_OP_TY_TY_INT(<, StgInt32)
+ case bci_OP_S_LE_32: SIZED_BIN_OP_TY_TY_INT(<=, StgInt32)
+
+ case bci_OP_NOT_32: UN_SIZED_OP(~, StgWord32)
+ case bci_OP_NEG_32: UN_SIZED_OP(-, StgInt32)
+
+
+ case bci_OP_ADD_16: SIZED_BIN_OP(+, StgInt16)
+ case bci_OP_SUB_16: SIZED_BIN_OP(-, StgInt16)
+ case bci_OP_AND_16: SIZED_BIN_OP(&, StgInt16)
+ case bci_OP_XOR_16: SIZED_BIN_OP(^, StgInt16)
+ case bci_OP_OR_16: SIZED_BIN_OP(|, StgInt16)
+ case bci_OP_MUL_16: SIZED_BIN_OP(*, StgInt16)
+ case bci_OP_SHL_16: SIZED_BIN_OP_TY_INT(<<, StgWord16)
+ case bci_OP_LSR_16: SIZED_BIN_OP_TY_INT(>>, StgWord16)
+ case bci_OP_ASR_16: SIZED_BIN_OP_TY_INT(>>, StgInt16)
+
+ case bci_OP_NEQ_16: SIZED_BIN_OP_TY_TY_INT(!=, StgWord16)
+ case bci_OP_EQ_16: SIZED_BIN_OP_TY_TY_INT(==, StgWord16)
+ case bci_OP_U_GT_16: SIZED_BIN_OP_TY_TY_INT(>, StgWord16)
+ case bci_OP_U_GE_16: SIZED_BIN_OP_TY_TY_INT(>=, StgWord16)
+ case bci_OP_U_LT_16: SIZED_BIN_OP_TY_TY_INT(<, StgWord16)
+ case bci_OP_U_LE_16: SIZED_BIN_OP_TY_TY_INT(<=, StgWord16)
+
+ case bci_OP_S_GT_16: SIZED_BIN_OP(>, StgInt16)
+ case bci_OP_S_GE_16: SIZED_BIN_OP(>=, StgInt16)
+ case bci_OP_S_LT_16: SIZED_BIN_OP(<, StgInt16)
+ case bci_OP_S_LE_16: SIZED_BIN_OP(<=, StgInt16)
+
+ case bci_OP_NOT_16: UN_SIZED_OP(~, StgWord16)
+ case bci_OP_NEG_16: UN_SIZED_OP(-, StgInt16)
+
+
+ case bci_OP_ADD_08: SIZED_BIN_OP(+, StgInt8)
+ case bci_OP_SUB_08: SIZED_BIN_OP(-, StgInt8)
+ case bci_OP_AND_08: SIZED_BIN_OP(&, StgInt8)
+ case bci_OP_XOR_08: SIZED_BIN_OP(^, StgInt8)
+ case bci_OP_OR_08: SIZED_BIN_OP(|, StgInt8)
+ case bci_OP_MUL_08: SIZED_BIN_OP(*, StgInt8)
+ case bci_OP_SHL_08: SIZED_BIN_OP_TY_INT(<<, StgWord8)
+ case bci_OP_LSR_08: SIZED_BIN_OP_TY_INT(>>, StgWord8)
+ case bci_OP_ASR_08: SIZED_BIN_OP_TY_INT(>>, StgInt8)
+
+ case bci_OP_NEQ_08: SIZED_BIN_OP_TY_TY_INT(!=, StgWord8)
+ case bci_OP_EQ_08: SIZED_BIN_OP_TY_TY_INT(==, StgWord8)
+ case bci_OP_U_GT_08: SIZED_BIN_OP_TY_TY_INT(>, StgWord8)
+ case bci_OP_U_GE_08: SIZED_BIN_OP_TY_TY_INT(>=, StgWord8)
+ case bci_OP_U_LT_08: SIZED_BIN_OP_TY_TY_INT(<, StgWord8)
+ case bci_OP_U_LE_08: SIZED_BIN_OP_TY_TY_INT(<=, StgWord8)
+
+ case bci_OP_S_GT_08: SIZED_BIN_OP_TY_TY_INT(>, StgInt8)
+ case bci_OP_S_GE_08: SIZED_BIN_OP_TY_TY_INT(>=, StgInt8)
+ case bci_OP_S_LT_08: SIZED_BIN_OP_TY_TY_INT(<, StgInt8)
+ case bci_OP_S_LE_08: SIZED_BIN_OP_TY_TY_INT(<=, StgInt8)
+
+ case bci_OP_NOT_08: UN_SIZED_OP(~, StgWord8)
+ case bci_OP_NEG_08: UN_SIZED_OP(-, StgInt8)
+
+ case bci_OP_INDEX_ADDR_64:
+ {
+ StgWord64* addr = (StgWord64*) SpW(0);
+ StgInt offset = (StgInt) SpW(1);
+ if(sizeof(StgPtr) == sizeof(StgWord64)) {
+ Sp_addW(1);
+ }
+ SpW64(0) = *(addr+offset);
+ goto nextInsn;
+ }
+
+ case bci_OP_INDEX_ADDR_32:
+ {
+ StgWord32* addr = (StgWord32*) SpW(0);
+ StgInt offset = (StgInt) SpW(1);
+ Sp_addW(1);
+ SpW(0) = (StgWord) *(addr+offset);
+ goto nextInsn;
+ }
+ case bci_OP_INDEX_ADDR_16:
+ {
+ StgWord16* addr = (StgWord16*) SpW(0);
+ StgInt offset = (StgInt) SpW(1);
+ Sp_addW(1);
+ SpW(0) = (StgWord) *(addr+offset);
+ goto nextInsn;
+ }
+ case bci_OP_INDEX_ADDR_08:
+ {
+ StgWord8* addr = (StgWord8*) SpW(0);
+ StgInt offset = (StgInt) SpW(1);
+ Sp_addW(1);
+ SpW(0) = (StgWord) *(addr+offset);
+ goto nextInsn;
+ }
+
case bci_CCALL: {
void *tok;
W_ stk_offset = BCO_GET_LARGE_ARG;
=====================================
rts/include/rts/Bytecodes.h
=====================================
@@ -114,6 +114,107 @@
#define bci_BCO_NAME 88
+#define bci_OP_ADD_64 90
+#define bci_OP_SUB_64 91
+#define bci_OP_AND_64 92
+#define bci_OP_XOR_64 93
+#define bci_OP_NOT_64 94
+#define bci_OP_NEG_64 95
+#define bci_OP_MUL_64 96
+#define bci_OP_SHL_64 97
+#define bci_OP_ASR_64 98
+#define bci_OP_LSR_64 99
+#define bci_OP_OR_64 100
+
+#define bci_OP_NEQ_64 110
+#define bci_OP_EQ_64 111
+#define bci_OP_U_GE_64 112
+#define bci_OP_U_GT_64 113
+#define bci_OP_U_LT_64 114
+#define bci_OP_U_LE_64 115
+#define bci_OP_S_GE_64 116
+#define bci_OP_S_GT_64 117
+#define bci_OP_S_LT_64 118
+#define bci_OP_S_LE_64 119
+
+
+#define bci_OP_ADD_32 130
+#define bci_OP_SUB_32 131
+#define bci_OP_AND_32 132
+#define bci_OP_XOR_32 133
+#define bci_OP_NOT_32 134
+#define bci_OP_NEG_32 135
+#define bci_OP_MUL_32 136
+#define bci_OP_SHL_32 137
+#define bci_OP_ASR_32 138
+#define bci_OP_LSR_32 139
+#define bci_OP_OR_32 140
+
+#define bci_OP_NEQ_32 150
+#define bci_OP_EQ_32 151
+#define bci_OP_U_GE_32 152
+#define bci_OP_U_GT_32 153
+#define bci_OP_U_LT_32 154
+#define bci_OP_U_LE_32 155
+#define bci_OP_S_GE_32 156
+#define bci_OP_S_GT_32 157
+#define bci_OP_S_LT_32 158
+#define bci_OP_S_LE_32 159
+
+
+#define bci_OP_ADD_16 170
+#define bci_OP_SUB_16 171
+#define bci_OP_AND_16 172
+#define bci_OP_XOR_16 173
+#define bci_OP_NOT_16 174
+#define bci_OP_NEG_16 175
+#define bci_OP_MUL_16 176
+#define bci_OP_SHL_16 177
+#define bci_OP_ASR_16 178
+#define bci_OP_LSR_16 179
+#define bci_OP_OR_16 180
+
+#define bci_OP_NEQ_16 190
+#define bci_OP_EQ_16 191
+#define bci_OP_U_GE_16 192
+#define bci_OP_U_GT_16 193
+#define bci_OP_U_LT_16 194
+#define bci_OP_U_LE_16 195
+#define bci_OP_S_GE_16 196
+#define bci_OP_S_GT_16 197
+#define bci_OP_S_LT_16 198
+#define bci_OP_S_LE_16 199
+
+
+#define bci_OP_ADD_08 200
+#define bci_OP_SUB_08 201
+#define bci_OP_AND_08 202
+#define bci_OP_XOR_08 203
+#define bci_OP_NOT_08 204
+#define bci_OP_NEG_08 205
+#define bci_OP_MUL_08 206
+#define bci_OP_SHL_08 207
+#define bci_OP_ASR_08 208
+#define bci_OP_LSR_08 209
+#define bci_OP_OR_08 210
+
+#define bci_OP_NEQ_08 220
+#define bci_OP_EQ_08 221
+#define bci_OP_U_GE_08 222
+#define bci_OP_U_GT_08 223
+#define bci_OP_U_LT_08 224
+#define bci_OP_U_LE_08 225
+#define bci_OP_S_GE_08 226
+#define bci_OP_S_GT_08 227
+#define bci_OP_S_LT_08 228
+#define bci_OP_S_LE_08 229
+
+#define bci_OP_INDEX_ADDR_08 240
+#define bci_OP_INDEX_ADDR_16 241
+#define bci_OP_INDEX_ADDR_32 242
+#define bci_OP_INDEX_ADDR_64 243
+
+
/* If you need to go past 255 then you will run into the flags */
/* If you need to go below 0x0100 then you will run into the instructions */
=====================================
testsuite/tests/codeGen/should_run/all.T
=====================================
@@ -226,7 +226,7 @@ test('T20640b', normal, compile_and_run, [''])
test('T22296',[only_ways(llvm_ways)
,unless(arch('x86_64') or arch('aarch64'), skip)],compile_and_run,[''])
test('T22798', normal, compile_and_run, ['-fregs-graph'])
-test('CheckBoundsOK', normal, compile_and_run, ['-fcheck-prim-bounds'])
+test('CheckBoundsOK', normal, compile_and_run, ['-fcheck-prim-bounds -funoptimized-core-for-interpreter -O'])
test('OrigThunkInfo', normal, compile_and_run, ['-forig-thunk-info'])
test('T24809', req_profiling, compile_and_run, ['-forig-thunk-info -prof'])
=====================================
testsuite/tests/ghci/all.T
=====================================
@@ -0,0 +1,2 @@
+test('ghci-mem-primops', [ extra_ways(['ghci-opt']), only_ways(['ghci', 'ghci-opt']),
+ extra_hc_opts('-fno-unoptimized-core-for-interpreter -O')], ghci_script, ['ghci-mem-primops.script'])
=====================================
testsuite/tests/ghci/ghci-mem-primops.hs
=====================================
@@ -0,0 +1,30 @@
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE ExtendedLiterals #-}
+
+module Main where
+
+-- Test memory primops interpreted in interpreter, extend if you add more.
+import GHC.Word
+import GHC.PrimOps
+import GHC.IO
+import Numeric (showHex)
+
+data Bytes = Bytes { byte_addr :: Addr# }
+
+bytes :: Bytes
+bytes = Bytes "\0\1\2\3\4\5\6\7\8\0"#
+
+main = do
+ let val = 0x1122334455667788#Word64
+ IO (\s -> case writeWord64OffAddr# (byte_addr bytes) 0# val s of s2 -> (# s2,() #))
+ putStrLn . flip showHex "" $ W64# (indexWord64OffAddr# (byte_addr bytes) 0#)
+
+ IO (\s -> case writeWord32OffAddr# (byte_addr bytes) 0# 0x11223344#Word32 s of s2 -> (# s2,() #))
+ putStrLn . flip showHex "" $ W32# (indexWord32OffAddr# (byte_addr bytes) 0#)
+
+ IO (\s -> case writeWord16OffAddr# (byte_addr bytes) 0# 0x1122#Word16 s of s2 -> (# s2,() #))
+ putStrLn . flip showHex "" $ W16# (indexWord16OffAddr# (byte_addr bytes) 0#)
+
+ IO (\s -> case writeWord8OffAddr# (byte_addr bytes) 0# 0x11#Word8 s of s2 -> (# s2,() #))
+ putStrLn . flip showHex "" $ W8# (indexWord8OffAddr# (byte_addr bytes) 0#)
\ No newline at end of file
=====================================
testsuite/tests/ghci/ghci-mem-primops.script
=====================================
@@ -0,0 +1,2 @@
+:l ghci-mem-primops
+:main
\ No newline at end of file
=====================================
testsuite/tests/ghci/ghci-mem-primops.stdout
=====================================
@@ -0,0 +1,4 @@
+1122334455667788
+11223344
+1122
+11
=====================================
testsuite/tests/numeric/should_run/all.T
=====================================
@@ -82,7 +82,7 @@ test('IntegerToFloat', normal, compile_and_run, [''])
test('T20291', normal, compile_and_run, [''])
test('T22282', normal, compile_and_run, [''])
test('T22671', js_fragile(24259), compile_and_run, [''])
-test('foundation', [when(js_arch(), run_timeout_multiplier(2)), js_fragile(24259)], compile_and_run, ['-O -package transformers'])
+test('foundation', [when(js_arch(), run_timeout_multiplier(2)), js_fragile(24259), extra_ways(['optasm','ghci','ghci-opt'])], compile_and_run, ['-package transformers -fno-break-points'])
test('T24066', normal, compile_and_run, [''])
test('div01', normal, compile_and_run, [''])
test('T24245', normal, compile_and_run, [''])
=====================================
testsuite/tests/numeric/should_run/foundation.hs
=====================================
@@ -1,3 +1,15 @@
+{- PARTS OF THIS FILE ARE SEMI-AUTOGENERATED.
+ You can re-generate them by invoking the genprimops utility with --foundation-tests
+ and then integrating the output in this file.
+
+ This test compares the results of various primops between the
+ pre-compiled version (primop wrapper) and the implementation of
+ whatever the test is run with.
+
+ This is particularly helpful when testing the interpreter as it allows us to
+ compare the result of the primop wrappers with the results of interpretation.
+-}
+
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -5,6 +17,9 @@
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE UnboxedTuples #-}
module Main
( main
) where
@@ -16,6 +31,7 @@ import Data.Typeable
import Data.Proxy
import GHC.Int
import GHC.Word
+import GHC.Word
import Data.Function
import GHC.Prim
import Control.Monad.Reader
@@ -26,6 +42,13 @@ import Foreign.Ptr
import Data.List (intercalate)
import Data.IORef
import Unsafe.Coerce
+import GHC.Types
+import Data.Char
+import Data.Semigroup
+import System.Exit
+
+import qualified GHC.Internal.PrimopWrappers as Wrapper
+import qualified GHC.Internal.Prim as Primop
newtype Gen a = Gen { runGen :: (ReaderT LCGGen IO a) }
deriving newtype (Functor, Applicative, Monad)
@@ -98,6 +121,17 @@ arbitraryWord64 = Gen $ do
h <- ask
liftIO (randomWord64 h)
+nonZero :: (Arbitrary a, Num a, Eq a) => Gen (NonZero a)
+nonZero = do
+ x <- arbitrary
+ if x == 0 then nonZero else pure $ NonZero x
+
+newtype NonZero a = NonZero { getNonZero :: a }
+ deriving (Eq,Ord,Bounded,Show)
+
+instance (Arbitrary a, Num a, Eq a) => Arbitrary (NonZero a) where
+ arbitrary = nonZero
+
instance Arbitrary Natural where
arbitrary = integralDownsize . (`mod` 10000) . abs <$> arbitraryInt64
@@ -126,6 +160,13 @@ instance Arbitrary Int16 where
instance Arbitrary Int8 where
arbitrary = integralDownsize <$> arbitraryInt64
+instance Arbitrary Char where
+ arbitrary = do
+ let high = fromIntegral $ fromEnum (maxBound :: Char) :: Word
+ (x::Word) <- arbitrary
+ let x' = mod x high
+ return (chr $ fromIntegral x')
+
int64ToInt :: Int64 -> Int
int64ToInt (I64# i) = I# (int64ToInt# i)
@@ -134,7 +175,7 @@ word64ToWord :: Word64 -> Word
word64ToWord (W64# i) = W# (word64ToWord# i)
-data RunS = RunS { depth :: Int, rg :: LCGGen }
+data RunS = RunS { depth :: Int, rg :: LCGGen, context :: [String] }
newtype LCGGen = LCGGen { randomWord64 :: IO Word64 }
@@ -148,43 +189,75 @@ newLCGGen LCGParams{..} = do
runPropertyCheck (PropertyBinaryOp res desc s1 s2) =
- if res then return True else (putMsg ("Failure: " ++ s1 ++ desc ++ s2) >> return False)
-runPropertyCheck (PropertyAnd a1 a2) = (&&) <$> runPropertyCheck a1 <*> runPropertyCheck a2
-
-runProperty :: Property -> ReaderT RunS IO ()
+ if res then return Success
+ else do
+ ctx <- context <$> ask
+ let msg = "Failure: " ++ s1 ++ desc ++ s2
+ putMsg msg
+ return (Failure [msg : ctx])
+runPropertyCheck (PropertyAnd a1 a2) = (<>) <$> runPropertyCheck a1 <*> runPropertyCheck a2
+
+runProperty :: Property -> ReaderT RunS IO Result
runProperty (Prop p) = do
let iterations = 100
loop iterations iterations
where
- loop iterations 0 = putMsg ("Passed " ++ show iterations ++ " iterations")
+ loop iterations 0 = do
+ putMsg ("Passed " ++ show iterations ++ " iterations")
+ return Success
loop iterations n = do
h <- rg <$> ask
p <- liftIO (runReaderT (runGen p) h)
let (ss, pc) = getCheck p
res <- runPropertyCheck pc
- if res then loop iterations (n-1)
- else putMsg ("With arguments " ++ intercalate ", " ss)
+ case res of
+ Success -> loop iterations (n-1)
+ Failure msgs -> do
+ let msg = ("With arguments " ++ intercalate ", " ss)
+ putMsg msg
+ return (Failure (map (msg :) msgs))
+
+data Result = Success | Failure [[String]]
+
+instance Semigroup Result where
+ Success <> x = x
+ x <> Success = x
+ (Failure xs) <> (Failure ys) = Failure (xs ++ ys)
+
+instance Monoid Result where
+ mempty = Success
putMsg s = do
n <- depth <$> ask
liftIO . putStrLn $ replicate (n * 2) ' ' ++ s
-nest = local (\s -> s { depth = depth s + 1 })
-runTestInternal :: Test -> ReaderT RunS IO ()
+nest c = local (\s -> s { depth = depth s + 1, context = c : context s })
+
+runTestInternal :: Test -> ReaderT RunS IO Result
runTestInternal (Group name tests) = do
- putMsg ("Group " ++ name)
- nest (mapM_ runTestInternal tests)
+ let label = ("Group " ++ name)
+ putMsg label
+ nest label (mconcat <$> mapM runTestInternal tests)
runTestInternal (Property name p) = do
- putMsg ("Running " ++ name)
- nest $ runProperty (property p)
+ let label = ("Running " ++ name)
+ putMsg label
+ nest label $ runProperty (property p)
runTests :: Test -> IO ()
runTests t = do
-- These params are the same ones as glibc uses.
h <- newLCGGen (LCGParams { seed = 1238123213, m = 2^31, a = 1103515245, c = 12345 })
- runReaderT (runTestInternal t) (RunS 0 h)
+ res <- runReaderT (runTestInternal t) (RunS 0 h [])
+ case res of
+ Success -> return ()
+ Failure tests -> do
+ putStrLn $ "These tests failed: \n" ++ intercalate " \n" (map (showStack 0 . reverse) tests)
+ exitFailure
+
+showStack _ [] = ""
+showStack n (s:ss) = replicate n ' ' ++ s ++ "\n" ++ showStack (n + 2) ss
-------------------------------------------------------------------------------
@@ -228,9 +301,8 @@ testMultiplicative _ = Group "Multiplicative"
testDividible :: forall a . (Show a, Eq a, Integral a, Num a, Arbitrary a, Typeable a)
=> Proxy a -> Test
testDividible _ = Group "Divisible"
- [ Property "(x `div` y) * y + (x `mod` y) == x" $ \(a :: a) b ->
- if b == 0 then True === True
- else a === (a `div` b) * b + (a `mod` b)
+ [ Property "(x `div` y) * y + (x `mod` y) == x" $ \(a :: a) (NonZero b) ->
+ a === (a `div` b) * b + (a `mod` b)
]
testOperatorPrecedence :: forall a . (Show a, Eq a, Prelude.Num a, Integral a, Num a, Arbitrary a, Typeable a)
@@ -272,6 +344,590 @@ testNumberRefs = Group "ALL"
, testNumber "Word32" (Proxy :: Proxy Word32)
, testNumber "Word64" (Proxy :: Proxy Word64)
]
+{-
+test_binop :: forall (r1 :: RuntimeRep) (r2 :: RuntimeRep) a r'
+ (b :: TYPE r1) (r :: TYPE r2) . String -> (a -> b) -> (r -> r')
+ -> (b -> b -> r)
+ -> (b -> b -> r)
+ -> Test
+test_binop name unwrap wrap primop wrapper =
+-}
+-- #define TEST_BINOP(name, unwrap, wrap, primop, wrapper) Property name $ \l r -> wrap (primop (unwrap l) (unwrap r)) === wrap (wrapper (unwrap l) (unwrap r))
+
+wInt# :: Int# -> Int
+wInt# = I#
+
+uInt# :: Int -> Int#
+uInt# (I# x) = x
+
+wWord#:: Word# -> Word
+wWord#= W#
+
+uWord# (W# w) = w
+uWord8# (W8# w) = w
+uWord16# (W16# w) = w
+uWord32# (W32# w) = w
+uWord64# (W64# w) = w
+uChar# (C# c) = c
+uInt8# (I8# w) = w
+uInt16# (I16# w) = w
+uInt32# (I32# w) = w
+uInt64# (I64# w) = w
+
+wWord8# = W8#
+wWord16# = W16#
+wWord32# = W32#
+wWord64# = W64#
+wChar# = C#
+wInt8# = I8#
+wInt16# = I16#
+wInt32# = I32#
+wInt64# = I64#
+
+#define WTUP2(f, g, x) (case x of (# a, b #) -> (f a, g b))
+#define WTUP3(f, g, h, x) (case x of (# a, b, c #) -> (f a, g b, h c))
+
+
+class TestPrimop f where
+ testPrimop :: String -> f -> f -> Test
+
+ testPrimopDivLike :: String -> f -> f -> Test
+ testPrimopDivLike _ _ _ = error "Div testing not supported for this type."
+
+{-
+instance TestPrimop (Int# -> Int# -> Int#) where
+ testPrimop s l r = Property s $ \(uInt -> a1) (uInt -> a2) -> (wInt (l a1 a2)) === wInt (r a1 a2)
+
+instance TestPrimop (Word# -> Word# -> Int#) where
+ testPrimop s l r = Property s $ \(uWord -> a1) (uWord -> a2) -> (wInt (l a1 a2)) === wInt (r a1 a2)
+
+instance TestPrimop (Word# -> Int#) where
+ testPrimop s l r = Property s $ \(uWord -> a1) -> (wInt (l a1)) === wInt (r a1)
+
+instance TestPrimop (Word# -> Int# -> Word#) where
+ testPrimop s l r = Property s $ \(uWord -> a1) (uInt -> a2) -> (wWord (l a1 a2)) === wWord (r a1 a2)
+ -}
+
+
+twoNonZero :: (a -> a -> b) -> a -> NonZero a -> b
+twoNonZero f x (NonZero y) = f x y
+
+main = runTests (Group "ALL" [testNumberRefs, testPrimops])
+
+-- Test an interpreted primop vs a compiled primop
+testPrimops = Group "primop"
+ [ testPrimop "gtChar#" Primop.gtChar# Wrapper.gtChar#
+ , testPrimop "geChar#" Primop.geChar# Wrapper.geChar#
+ , testPrimop "eqChar#" Primop.eqChar# Wrapper.eqChar#
+ , testPrimop "neChar#" Primop.neChar# Wrapper.neChar#
+ , testPrimop "ltChar#" Primop.ltChar# Wrapper.ltChar#
+ , testPrimop "leChar#" Primop.leChar# Wrapper.leChar#
+ , testPrimop "ord#" Primop.ord# Wrapper.ord#
+ , testPrimop "int8ToInt#" Primop.int8ToInt# Wrapper.int8ToInt#
+ , testPrimop "intToInt8#" Primop.intToInt8# Wrapper.intToInt8#
+ , testPrimop "negateInt8#" Primop.negateInt8# Wrapper.negateInt8#
+ , testPrimop "plusInt8#" Primop.plusInt8# Wrapper.plusInt8#
+ , testPrimop "subInt8#" Primop.subInt8# Wrapper.subInt8#
+ , testPrimop "timesInt8#" Primop.timesInt8# Wrapper.timesInt8#
+ , testPrimopDivLike "quotInt8#" Primop.quotInt8# Wrapper.quotInt8#
+ , testPrimopDivLike "remInt8#" Primop.remInt8# Wrapper.remInt8#
+ , testPrimopDivLike "quotRemInt8#" Primop.quotRemInt8# Wrapper.quotRemInt8#
+ , testPrimop "uncheckedShiftLInt8#" Primop.uncheckedShiftLInt8# Wrapper.uncheckedShiftLInt8#
+ , testPrimop "uncheckedShiftRAInt8#" Primop.uncheckedShiftRAInt8# Wrapper.uncheckedShiftRAInt8#
+ , testPrimop "uncheckedShiftRLInt8#" Primop.uncheckedShiftRLInt8# Wrapper.uncheckedShiftRLInt8#
+ , testPrimop "int8ToWord8#" Primop.int8ToWord8# Wrapper.int8ToWord8#
+ , testPrimop "eqInt8#" Primop.eqInt8# Wrapper.eqInt8#
+ , testPrimop "geInt8#" Primop.geInt8# Wrapper.geInt8#
+ , testPrimop "gtInt8#" Primop.gtInt8# Wrapper.gtInt8#
+ , testPrimop "leInt8#" Primop.leInt8# Wrapper.leInt8#
+ , testPrimop "ltInt8#" Primop.ltInt8# Wrapper.ltInt8#
+ , testPrimop "neInt8#" Primop.neInt8# Wrapper.neInt8#
+ , testPrimop "word8ToWord#" Primop.word8ToWord# Wrapper.word8ToWord#
+ , testPrimop "wordToWord8#" Primop.wordToWord8# Wrapper.wordToWord8#
+ , testPrimop "plusWord8#" Primop.plusWord8# Wrapper.plusWord8#
+ , testPrimop "subWord8#" Primop.subWord8# Wrapper.subWord8#
+ , testPrimop "timesWord8#" Primop.timesWord8# Wrapper.timesWord8#
+ , testPrimopDivLike "quotWord8#" Primop.quotWord8# Wrapper.quotWord8#
+ , testPrimopDivLike "remWord8#" Primop.remWord8# Wrapper.remWord8#
+ , testPrimopDivLike "quotRemWord8#" Primop.quotRemWord8# Wrapper.quotRemWord8#
+ , testPrimop "andWord8#" Primop.andWord8# Wrapper.andWord8#
+ , testPrimop "orWord8#" Primop.orWord8# Wrapper.orWord8#
+ , testPrimop "xorWord8#" Primop.xorWord8# Wrapper.xorWord8#
+ , testPrimop "notWord8#" Primop.notWord8# Wrapper.notWord8#
+ , testPrimop "uncheckedShiftLWord8#" Primop.uncheckedShiftLWord8# Wrapper.uncheckedShiftLWord8#
+ , testPrimop "uncheckedShiftRLWord8#" Primop.uncheckedShiftRLWord8# Wrapper.uncheckedShiftRLWord8#
+ , testPrimop "word8ToInt8#" Primop.word8ToInt8# Wrapper.word8ToInt8#
+ , testPrimop "eqWord8#" Primop.eqWord8# Wrapper.eqWord8#
+ , testPrimop "geWord8#" Primop.geWord8# Wrapper.geWord8#
+ , testPrimop "gtWord8#" Primop.gtWord8# Wrapper.gtWord8#
+ , testPrimop "leWord8#" Primop.leWord8# Wrapper.leWord8#
+ , testPrimop "ltWord8#" Primop.ltWord8# Wrapper.ltWord8#
+ , testPrimop "neWord8#" Primop.neWord8# Wrapper.neWord8#
+ , testPrimop "int16ToInt#" Primop.int16ToInt# Wrapper.int16ToInt#
+ , testPrimop "intToInt16#" Primop.intToInt16# Wrapper.intToInt16#
+ , testPrimop "negateInt16#" Primop.negateInt16# Wrapper.negateInt16#
+ , testPrimop "plusInt16#" Primop.plusInt16# Wrapper.plusInt16#
+ , testPrimop "subInt16#" Primop.subInt16# Wrapper.subInt16#
+ , testPrimop "timesInt16#" Primop.timesInt16# Wrapper.timesInt16#
+ , testPrimopDivLike "quotInt16#" Primop.quotInt16# Wrapper.quotInt16#
+ , testPrimopDivLike "remInt16#" Primop.remInt16# Wrapper.remInt16#
+ , testPrimopDivLike "quotRemInt16#" Primop.quotRemInt16# Wrapper.quotRemInt16#
+ , testPrimop "uncheckedShiftLInt16#" Primop.uncheckedShiftLInt16# Wrapper.uncheckedShiftLInt16#
+ , testPrimop "uncheckedShiftRAInt16#" Primop.uncheckedShiftRAInt16# Wrapper.uncheckedShiftRAInt16#
+ , testPrimop "uncheckedShiftRLInt16#" Primop.uncheckedShiftRLInt16# Wrapper.uncheckedShiftRLInt16#
+ , testPrimop "int16ToWord16#" Primop.int16ToWord16# Wrapper.int16ToWord16#
+ , testPrimop "eqInt16#" Primop.eqInt16# Wrapper.eqInt16#
+ , testPrimop "geInt16#" Primop.geInt16# Wrapper.geInt16#
+ , testPrimop "gtInt16#" Primop.gtInt16# Wrapper.gtInt16#
+ , testPrimop "leInt16#" Primop.leInt16# Wrapper.leInt16#
+ , testPrimop "ltInt16#" Primop.ltInt16# Wrapper.ltInt16#
+ , testPrimop "neInt16#" Primop.neInt16# Wrapper.neInt16#
+ , testPrimop "word16ToWord#" Primop.word16ToWord# Wrapper.word16ToWord#
+ , testPrimop "wordToWord16#" Primop.wordToWord16# Wrapper.wordToWord16#
+ , testPrimop "plusWord16#" Primop.plusWord16# Wrapper.plusWord16#
+ , testPrimop "subWord16#" Primop.subWord16# Wrapper.subWord16#
+ , testPrimop "timesWord16#" Primop.timesWord16# Wrapper.timesWord16#
+ , testPrimopDivLike "quotWord16#" Primop.quotWord16# Wrapper.quotWord16#
+ , testPrimopDivLike "remWord16#" Primop.remWord16# Wrapper.remWord16#
+ , testPrimopDivLike "quotRemWord16#" Primop.quotRemWord16# Wrapper.quotRemWord16#
+ , testPrimop "andWord16#" Primop.andWord16# Wrapper.andWord16#
+ , testPrimop "orWord16#" Primop.orWord16# Wrapper.orWord16#
+ , testPrimop "xorWord16#" Primop.xorWord16# Wrapper.xorWord16#
+ , testPrimop "notWord16#" Primop.notWord16# Wrapper.notWord16#
+ , testPrimop "uncheckedShiftLWord16#" Primop.uncheckedShiftLWord16# Wrapper.uncheckedShiftLWord16#
+ , testPrimop "uncheckedShiftRLWord16#" Primop.uncheckedShiftRLWord16# Wrapper.uncheckedShiftRLWord16#
+ , testPrimop "word16ToInt16#" Primop.word16ToInt16# Wrapper.word16ToInt16#
+ , testPrimop "eqWord16#" Primop.eqWord16# Wrapper.eqWord16#
+ , testPrimop "geWord16#" Primop.geWord16# Wrapper.geWord16#
+ , testPrimop "gtWord16#" Primop.gtWord16# Wrapper.gtWord16#
+ , testPrimop "leWord16#" Primop.leWord16# Wrapper.leWord16#
+ , testPrimop "ltWord16#" Primop.ltWord16# Wrapper.ltWord16#
+ , testPrimop "neWord16#" Primop.neWord16# Wrapper.neWord16#
+ , testPrimop "int32ToInt#" Primop.int32ToInt# Wrapper.int32ToInt#
+ , testPrimop "intToInt32#" Primop.intToInt32# Wrapper.intToInt32#
+ , testPrimop "negateInt32#" Primop.negateInt32# Wrapper.negateInt32#
+ , testPrimop "plusInt32#" Primop.plusInt32# Wrapper.plusInt32#
+ , testPrimop "subInt32#" Primop.subInt32# Wrapper.subInt32#
+ , testPrimop "timesInt32#" Primop.timesInt32# Wrapper.timesInt32#
+ , testPrimopDivLike "quotInt32#" Primop.quotInt32# Wrapper.quotInt32#
+ , testPrimopDivLike "remInt32#" Primop.remInt32# Wrapper.remInt32#
+ , testPrimopDivLike "quotRemInt32#" Primop.quotRemInt32# Wrapper.quotRemInt32#
+ , testPrimop "uncheckedShiftLInt32#" Primop.uncheckedShiftLInt32# Wrapper.uncheckedShiftLInt32#
+ , testPrimop "uncheckedShiftRAInt32#" Primop.uncheckedShiftRAInt32# Wrapper.uncheckedShiftRAInt32#
+ , testPrimop "uncheckedShiftRLInt32#" Primop.uncheckedShiftRLInt32# Wrapper.uncheckedShiftRLInt32#
+ , testPrimop "int32ToWord32#" Primop.int32ToWord32# Wrapper.int32ToWord32#
+ , testPrimop "eqInt32#" Primop.eqInt32# Wrapper.eqInt32#
+ , testPrimop "geInt32#" Primop.geInt32# Wrapper.geInt32#
+ , testPrimop "gtInt32#" Primop.gtInt32# Wrapper.gtInt32#
+ , testPrimop "leInt32#" Primop.leInt32# Wrapper.leInt32#
+ , testPrimop "ltInt32#" Primop.ltInt32# Wrapper.ltInt32#
+ , testPrimop "neInt32#" Primop.neInt32# Wrapper.neInt32#
+ , testPrimop "word32ToWord#" Primop.word32ToWord# Wrapper.word32ToWord#
+ , testPrimop "wordToWord32#" Primop.wordToWord32# Wrapper.wordToWord32#
+ , testPrimop "plusWord32#" Primop.plusWord32# Wrapper.plusWord32#
+ , testPrimop "subWord32#" Primop.subWord32# Wrapper.subWord32#
+ , testPrimop "timesWord32#" Primop.timesWord32# Wrapper.timesWord32#
+ , testPrimopDivLike "quotWord32#" Primop.quotWord32# Wrapper.quotWord32#
+ , testPrimopDivLike "remWord32#" Primop.remWord32# Wrapper.remWord32#
+ , testPrimopDivLike "quotRemWord32#" Primop.quotRemWord32# Wrapper.quotRemWord32#
+ , testPrimop "andWord32#" Primop.andWord32# Wrapper.andWord32#
+ , testPrimop "orWord32#" Primop.orWord32# Wrapper.orWord32#
+ , testPrimop "xorWord32#" Primop.xorWord32# Wrapper.xorWord32#
+ , testPrimop "notWord32#" Primop.notWord32# Wrapper.notWord32#
+ , testPrimop "uncheckedShiftLWord32#" Primop.uncheckedShiftLWord32# Wrapper.uncheckedShiftLWord32#
+ , testPrimop "uncheckedShiftRLWord32#" Primop.uncheckedShiftRLWord32# Wrapper.uncheckedShiftRLWord32#
+ , testPrimop "word32ToInt32#" Primop.word32ToInt32# Wrapper.word32ToInt32#
+ , testPrimop "eqWord32#" Primop.eqWord32# Wrapper.eqWord32#
+ , testPrimop "geWord32#" Primop.geWord32# Wrapper.geWord32#
+ , testPrimop "gtWord32#" Primop.gtWord32# Wrapper.gtWord32#
+ , testPrimop "leWord32#" Primop.leWord32# Wrapper.leWord32#
+ , testPrimop "ltWord32#" Primop.ltWord32# Wrapper.ltWord32#
+ , testPrimop "neWord32#" Primop.neWord32# Wrapper.neWord32#
+ , testPrimop "int64ToInt#" Primop.int64ToInt# Wrapper.int64ToInt#
+ , testPrimop "intToInt64#" Primop.intToInt64# Wrapper.intToInt64#
+ , testPrimop "negateInt64#" Primop.negateInt64# Wrapper.negateInt64#
+ , testPrimop "plusInt64#" Primop.plusInt64# Wrapper.plusInt64#
+ , testPrimop "subInt64#" Primop.subInt64# Wrapper.subInt64#
+ , testPrimop "timesInt64#" Primop.timesInt64# Wrapper.timesInt64#
+ , testPrimopDivLike "quotInt64#" Primop.quotInt64# Wrapper.quotInt64#
+ , testPrimopDivLike "remInt64#" Primop.remInt64# Wrapper.remInt64#
+ , testPrimop "uncheckedIShiftL64#" Primop.uncheckedIShiftL64# Wrapper.uncheckedIShiftL64#
+ , testPrimop "uncheckedIShiftRA64#" Primop.uncheckedIShiftRA64# Wrapper.uncheckedIShiftRA64#
+ , testPrimop "uncheckedIShiftRL64#" Primop.uncheckedIShiftRL64# Wrapper.uncheckedIShiftRL64#
+ , testPrimop "int64ToWord64#" Primop.int64ToWord64# Wrapper.int64ToWord64#
+ , testPrimop "eqInt64#" Primop.eqInt64# Wrapper.eqInt64#
+ , testPrimop "geInt64#" Primop.geInt64# Wrapper.geInt64#
+ , testPrimop "gtInt64#" Primop.gtInt64# Wrapper.gtInt64#
+ , testPrimop "leInt64#" Primop.leInt64# Wrapper.leInt64#
+ , testPrimop "ltInt64#" Primop.ltInt64# Wrapper.ltInt64#
+ , testPrimop "neInt64#" Primop.neInt64# Wrapper.neInt64#
+ , testPrimop "word64ToWord#" Primop.word64ToWord# Wrapper.word64ToWord#
+ , testPrimop "wordToWord64#" Primop.wordToWord64# Wrapper.wordToWord64#
+ , testPrimop "plusWord64#" Primop.plusWord64# Wrapper.plusWord64#
+ , testPrimop "subWord64#" Primop.subWord64# Wrapper.subWord64#
+ , testPrimop "timesWord64#" Primop.timesWord64# Wrapper.timesWord64#
+ , testPrimopDivLike "quotWord64#" Primop.quotWord64# Wrapper.quotWord64#
+ , testPrimopDivLike "remWord64#" Primop.remWord64# Wrapper.remWord64#
+ , testPrimop "and64#" Primop.and64# Wrapper.and64#
+ , testPrimop "or64#" Primop.or64# Wrapper.or64#
+ , testPrimop "xor64#" Primop.xor64# Wrapper.xor64#
+ , testPrimop "not64#" Primop.not64# Wrapper.not64#
+ , testPrimop "uncheckedShiftL64#" Primop.uncheckedShiftL64# Wrapper.uncheckedShiftL64#
+ , testPrimop "uncheckedShiftRL64#" Primop.uncheckedShiftRL64# Wrapper.uncheckedShiftRL64#
+ , testPrimop "word64ToInt64#" Primop.word64ToInt64# Wrapper.word64ToInt64#
+ , testPrimop "eqWord64#" Primop.eqWord64# Wrapper.eqWord64#
+ , testPrimop "geWord64#" Primop.geWord64# Wrapper.geWord64#
+ , testPrimop "gtWord64#" Primop.gtWord64# Wrapper.gtWord64#
+ , testPrimop "leWord64#" Primop.leWord64# Wrapper.leWord64#
+ , testPrimop "ltWord64#" Primop.ltWord64# Wrapper.ltWord64#
+ , testPrimop "neWord64#" Primop.neWord64# Wrapper.neWord64#
+ , testPrimop "+#" (Primop.+#) (Wrapper.+#)
+ , testPrimop "-#" (Primop.-#) (Wrapper.-#)
+ , testPrimop "*#" (Primop.*#) (Wrapper.*#)
+ , testPrimop "timesInt2#" Primop.timesInt2# Wrapper.timesInt2#
+ , testPrimop "mulIntMayOflo#" Primop.mulIntMayOflo# Wrapper.mulIntMayOflo#
+ , testPrimopDivLike "quotInt#" Primop.quotInt# Wrapper.quotInt#
+ , testPrimopDivLike "remInt#" Primop.remInt# Wrapper.remInt#
+ , testPrimopDivLike "quotRemInt#" Primop.quotRemInt# Wrapper.quotRemInt#
+ , testPrimop "andI#" Primop.andI# Wrapper.andI#
+ , testPrimop "orI#" Primop.orI# Wrapper.orI#
+ , testPrimop "xorI#" Primop.xorI# Wrapper.xorI#
+ , testPrimop "notI#" Primop.notI# Wrapper.notI#
+ , testPrimop "negateInt#" Primop.negateInt# Wrapper.negateInt#
+ , testPrimop "addIntC#" Primop.addIntC# Wrapper.addIntC#
+ , testPrimop "subIntC#" Primop.subIntC# Wrapper.subIntC#
+ , testPrimop ">#" (Primop.>#) (Wrapper.>#)
+ , testPrimop ">=#" (Primop.>=#) (Wrapper.>=#)
+ , testPrimop "==#" (Primop.==#) (Wrapper.==#)
+ , testPrimop "/=#" (Primop./=#) (Wrapper./=#)
+ , testPrimop "<#" (Primop.<#) (Wrapper.<#)
+ , testPrimop "<=#" (Primop.<=#) (Wrapper.<=#)
+ , testPrimop "chr#" Primop.chr# Wrapper.chr#
+ , testPrimop "int2Word#" Primop.int2Word# Wrapper.int2Word#
+ , testPrimop "uncheckedIShiftL#" Primop.uncheckedIShiftL# Wrapper.uncheckedIShiftL#
+ , testPrimop "uncheckedIShiftRA#" Primop.uncheckedIShiftRA# Wrapper.uncheckedIShiftRA#
+ , testPrimop "uncheckedIShiftRL#" Primop.uncheckedIShiftRL# Wrapper.uncheckedIShiftRL#
+ , testPrimop "plusWord#" Primop.plusWord# Wrapper.plusWord#
+ , testPrimop "addWordC#" Primop.addWordC# Wrapper.addWordC#
+ , testPrimop "subWordC#" Primop.subWordC# Wrapper.subWordC#
+ , testPrimop "plusWord2#" Primop.plusWord2# Wrapper.plusWord2#
+ , testPrimop "minusWord#" Primop.minusWord# Wrapper.minusWord#
+ , testPrimop "timesWord#" Primop.timesWord# Wrapper.timesWord#
+ , testPrimop "timesWord2#" Primop.timesWord2# Wrapper.timesWord2#
+ , testPrimopDivLike "quotWord#" Primop.quotWord# Wrapper.quotWord#
+ , testPrimopDivLike "remWord#" Primop.remWord# Wrapper.remWord#
+ , testPrimopDivLike "quotRemWord#" Primop.quotRemWord# Wrapper.quotRemWord#
+ , testPrimop "and#" Primop.and# Wrapper.and#
+ , testPrimop "or#" Primop.or# Wrapper.or#
+ , testPrimop "xor#" Primop.xor# Wrapper.xor#
+ , testPrimop "not#" Primop.not# Wrapper.not#
+ , testPrimop "uncheckedShiftL#" Primop.uncheckedShiftL# Wrapper.uncheckedShiftL#
+ , testPrimop "uncheckedShiftRL#" Primop.uncheckedShiftRL# Wrapper.uncheckedShiftRL#
+ , testPrimop "word2Int#" Primop.word2Int# Wrapper.word2Int#
+ , testPrimop "gtWord#" Primop.gtWord# Wrapper.gtWord#
+ , testPrimop "geWord#" Primop.geWord# Wrapper.geWord#
+ , testPrimop "eqWord#" Primop.eqWord# Wrapper.eqWord#
+ , testPrimop "neWord#" Primop.neWord# Wrapper.neWord#
+ , testPrimop "ltWord#" Primop.ltWord# Wrapper.ltWord#
+ , testPrimop "leWord#" Primop.leWord# Wrapper.leWord#
+ , testPrimop "popCnt8#" Primop.popCnt8# Wrapper.popCnt8#
+ , testPrimop "popCnt16#" Primop.popCnt16# Wrapper.popCnt16#
+ , testPrimop "popCnt32#" Primop.popCnt32# Wrapper.popCnt32#
+ , testPrimop "popCnt64#" Primop.popCnt64# Wrapper.popCnt64#
+ , testPrimop "popCnt#" Primop.popCnt# Wrapper.popCnt#
+ , testPrimop "pdep8#" Primop.pdep8# Wrapper.pdep8#
+ , testPrimop "pdep16#" Primop.pdep16# Wrapper.pdep16#
+ , testPrimop "pdep32#" Primop.pdep32# Wrapper.pdep32#
+ , testPrimop "pdep64#" Primop.pdep64# Wrapper.pdep64#
+ , testPrimop "pdep#" Primop.pdep# Wrapper.pdep#
+ , testPrimop "pext8#" Primop.pext8# Wrapper.pext8#
+ , testPrimop "pext16#" Primop.pext16# Wrapper.pext16#
+ , testPrimop "pext32#" Primop.pext32# Wrapper.pext32#
+ , testPrimop "pext64#" Primop.pext64# Wrapper.pext64#
+ , testPrimop "pext#" Primop.pext# Wrapper.pext#
+ , testPrimop "clz8#" Primop.clz8# Wrapper.clz8#
+ , testPrimop "clz16#" Primop.clz16# Wrapper.clz16#
+ , testPrimop "clz32#" Primop.clz32# Wrapper.clz32#
+ , testPrimop "clz64#" Primop.clz64# Wrapper.clz64#
+ , testPrimop "clz#" Primop.clz# Wrapper.clz#
+ , testPrimop "ctz8#" Primop.ctz8# Wrapper.ctz8#
+ , testPrimop "ctz16#" Primop.ctz16# Wrapper.ctz16#
+ , testPrimop "ctz32#" Primop.ctz32# Wrapper.ctz32#
+ , testPrimop "ctz64#" Primop.ctz64# Wrapper.ctz64#
+ , testPrimop "ctz#" Primop.ctz# Wrapper.ctz#
+ , testPrimop "byteSwap16#" Primop.byteSwap16# Wrapper.byteSwap16#
+ , testPrimop "byteSwap32#" Primop.byteSwap32# Wrapper.byteSwap32#
+ , testPrimop "byteSwap64#" Primop.byteSwap64# Wrapper.byteSwap64#
+ , testPrimop "byteSwap#" Primop.byteSwap# Wrapper.byteSwap#
+ , testPrimop "bitReverse8#" Primop.bitReverse8# Wrapper.bitReverse8#
+ , testPrimop "bitReverse16#" Primop.bitReverse16# Wrapper.bitReverse16#
+ , testPrimop "bitReverse32#" Primop.bitReverse32# Wrapper.bitReverse32#
+ , testPrimop "bitReverse64#" Primop.bitReverse64# Wrapper.bitReverse64#
+ , testPrimop "bitReverse#" Primop.bitReverse# Wrapper.bitReverse#
+ , testPrimop "narrow8Int#" Primop.narrow8Int# Wrapper.narrow8Int#
+ , testPrimop "narrow16Int#" Primop.narrow16Int# Wrapper.narrow16Int#
+ , testPrimop "narrow32Int#" Primop.narrow32Int# Wrapper.narrow32Int#
+ , testPrimop "narrow8Word#" Primop.narrow8Word# Wrapper.narrow8Word#
+ , testPrimop "narrow16Word#" Primop.narrow16Word# Wrapper.narrow16Word#
+ , testPrimop "narrow32Word#" Primop.narrow32Word# Wrapper.narrow32Word#
+ ]
+
+instance TestPrimop (Char# -> Char# -> Int#) where
+ testPrimop s l r = Property s $ \ (uChar#-> x0) (uChar#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+
+instance TestPrimop (Char# -> Int#) where
+ testPrimop s l r = Property s $ \ (uChar#-> x0) -> wInt# (l x0) === wInt# (r x0)
+
+instance TestPrimop (Int# -> Int# -> Int#) where
+ testPrimop s l r = Property s $ \ (uInt#-> x0) (uInt#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uInt#-> x0) (uInt#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+
+instance TestPrimop (Int# -> Int# -> (# Int#,Int# #)) where
+ testPrimop s l r = Property s $ \ (uInt#-> x0) (uInt#-> x1) -> WTUP2(wInt#,wInt#, (l x0 x1)) === WTUP2(wInt#,wInt#, (r x0 x1))
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uInt#-> x0) (uInt#-> x1) -> WTUP2(wInt#,wInt#, (l x0 x1)) === WTUP2(wInt#,wInt#, (r x0 x1))
+
+instance TestPrimop (Int# -> Int# -> (# Int#,Int#,Int# #)) where
+ testPrimop s l r = Property s $ \ (uInt#-> x0) (uInt#-> x1) -> WTUP3(wInt#,wInt#,wInt#, (l x0 x1)) === WTUP3(wInt#,wInt#,wInt#, (r x0 x1))
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uInt#-> x0) (uInt#-> x1) -> WTUP3(wInt#,wInt#,wInt#, (l x0 x1)) === WTUP3(wInt#,wInt#,wInt#, (r x0 x1))
+
+instance TestPrimop (Int# -> Char#) where
+ testPrimop s l r = Property s $ \ (uInt#-> x0) -> wChar# (l x0) === wChar# (r x0)
+
+instance TestPrimop (Int# -> Int#) where
+ testPrimop s l r = Property s $ \ (uInt#-> x0) -> wInt# (l x0) === wInt# (r x0)
+
+instance TestPrimop (Int# -> Int16#) where
+ testPrimop s l r = Property s $ \ (uInt#-> x0) -> wInt16# (l x0) === wInt16# (r x0)
+
+instance TestPrimop (Int# -> Int32#) where
+ testPrimop s l r = Property s $ \ (uInt#-> x0) -> wInt32# (l x0) === wInt32# (r x0)
+
+instance TestPrimop (Int# -> Int64#) where
+ testPrimop s l r = Property s $ \ (uInt#-> x0) -> wInt64# (l x0) === wInt64# (r x0)
+
+instance TestPrimop (Int# -> Int8#) where
+ testPrimop s l r = Property s $ \ (uInt#-> x0) -> wInt8# (l x0) === wInt8# (r x0)
+
+instance TestPrimop (Int# -> Word#) where
+ testPrimop s l r = Property s $ \ (uInt#-> x0) -> wWord# (l x0) === wWord# (r x0)
+
+instance TestPrimop (Int16# -> Int# -> Int16#) where
+ testPrimop s l r = Property s $ \ (uInt16#-> x0) (uInt#-> x1) -> wInt16# (l x0 x1) === wInt16# (r x0 x1)
+
+instance TestPrimop (Int16# -> Int16# -> Int#) where
+ testPrimop s l r = Property s $ \ (uInt16#-> x0) (uInt16#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uInt16#-> x0) (uInt16#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+
+instance TestPrimop (Int16# -> Int16# -> Int16#) where
+ testPrimop s l r = Property s $ \ (uInt16#-> x0) (uInt16#-> x1) -> wInt16# (l x0 x1) === wInt16# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uInt16#-> x0) (uInt16#-> x1) -> wInt16# (l x0 x1) === wInt16# (r x0 x1)
+
+instance TestPrimop (Int16# -> Int16# -> (# Int16#,Int16# #)) where
+ testPrimop s l r = Property s $ \ (uInt16#-> x0) (uInt16#-> x1) -> WTUP2(wInt16#,wInt16#, (l x0 x1)) === WTUP2(wInt16#,wInt16#, (r x0 x1))
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uInt16#-> x0) (uInt16#-> x1) -> WTUP2(wInt16#,wInt16#, (l x0 x1)) === WTUP2(wInt16#,wInt16#, (r x0 x1))
+
+instance TestPrimop (Int16# -> Int#) where
+ testPrimop s l r = Property s $ \ (uInt16#-> x0) -> wInt# (l x0) === wInt# (r x0)
+
+instance TestPrimop (Int16# -> Int16#) where
+ testPrimop s l r = Property s $ \ (uInt16#-> x0) -> wInt16# (l x0) === wInt16# (r x0)
+
+instance TestPrimop (Int16# -> Word16#) where
+ testPrimop s l r = Property s $ \ (uInt16#-> x0) -> wWord16# (l x0) === wWord16# (r x0)
+
+instance TestPrimop (Int32# -> Int# -> Int32#) where
+ testPrimop s l r = Property s $ \ (uInt32#-> x0) (uInt#-> x1) -> wInt32# (l x0 x1) === wInt32# (r x0 x1)
+
+instance TestPrimop (Int32# -> Int32# -> Int#) where
+ testPrimop s l r = Property s $ \ (uInt32#-> x0) (uInt32#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uInt32#-> x0) (uInt32#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+
+instance TestPrimop (Int32# -> Int32# -> Int32#) where
+ testPrimop s l r = Property s $ \ (uInt32#-> x0) (uInt32#-> x1) -> wInt32# (l x0 x1) === wInt32# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uInt32#-> x0) (uInt32#-> x1) -> wInt32# (l x0 x1) === wInt32# (r x0 x1)
+
+instance TestPrimop (Int32# -> Int32# -> (# Int32#,Int32# #)) where
+ testPrimop s l r = Property s $ \ (uInt32#-> x0) (uInt32#-> x1) -> WTUP2(wInt32#,wInt32#, (l x0 x1)) === WTUP2(wInt32#,wInt32#, (r x0 x1))
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uInt32#-> x0) (uInt32#-> x1) -> WTUP2(wInt32#,wInt32#, (l x0 x1)) === WTUP2(wInt32#,wInt32#, (r x0 x1))
+
+instance TestPrimop (Int32# -> Int#) where
+ testPrimop s l r = Property s $ \ (uInt32#-> x0) -> wInt# (l x0) === wInt# (r x0)
+
+instance TestPrimop (Int32# -> Int32#) where
+ testPrimop s l r = Property s $ \ (uInt32#-> x0) -> wInt32# (l x0) === wInt32# (r x0)
+
+instance TestPrimop (Int32# -> Word32#) where
+ testPrimop s l r = Property s $ \ (uInt32#-> x0) -> wWord32# (l x0) === wWord32# (r x0)
+
+instance TestPrimop (Int64# -> Int# -> Int64#) where
+ testPrimop s l r = Property s $ \ (uInt64#-> x0) (uInt#-> x1) -> wInt64# (l x0 x1) === wInt64# (r x0 x1)
+
+instance TestPrimop (Int64# -> Int64# -> Int#) where
+ testPrimop s l r = Property s $ \ (uInt64#-> x0) (uInt64#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uInt64#-> x0) (uInt64#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+
+instance TestPrimop (Int64# -> Int64# -> Int64#) where
+ testPrimop s l r = Property s $ \ (uInt64#-> x0) (uInt64#-> x1) -> wInt64# (l x0 x1) === wInt64# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uInt64#-> x0) (uInt64#-> x1) -> wInt64# (l x0 x1) === wInt64# (r x0 x1)
+
+instance TestPrimop (Int64# -> Int#) where
+ testPrimop s l r = Property s $ \ (uInt64#-> x0) -> wInt# (l x0) === wInt# (r x0)
+
+instance TestPrimop (Int64# -> Int64#) where
+ testPrimop s l r = Property s $ \ (uInt64#-> x0) -> wInt64# (l x0) === wInt64# (r x0)
+
+instance TestPrimop (Int64# -> Word64#) where
+ testPrimop s l r = Property s $ \ (uInt64#-> x0) -> wWord64# (l x0) === wWord64# (r x0)
+
+instance TestPrimop (Int8# -> Int# -> Int8#) where
+ testPrimop s l r = Property s $ \ (uInt8#-> x0) (uInt#-> x1) -> wInt8# (l x0 x1) === wInt8# (r x0 x1)
+
+instance TestPrimop (Int8# -> Int8# -> Int#) where
+ testPrimop s l r = Property s $ \ (uInt8#-> x0) (uInt8#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uInt8#-> x0) (uInt8#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+
+instance TestPrimop (Int8# -> Int8# -> Int8#) where
+ testPrimop s l r = Property s $ \ (uInt8#-> x0) (uInt8#-> x1) -> wInt8# (l x0 x1) === wInt8# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uInt8#-> x0) (uInt8#-> x1) -> wInt8# (l x0 x1) === wInt8# (r x0 x1)
+
+instance TestPrimop (Int8# -> Int8# -> (# Int8#,Int8# #)) where
+ testPrimop s l r = Property s $ \ (uInt8#-> x0) (uInt8#-> x1) -> WTUP2(wInt8#,wInt8#, (l x0 x1)) === WTUP2(wInt8#,wInt8#, (r x0 x1))
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uInt8#-> x0) (uInt8#-> x1) -> WTUP2(wInt8#,wInt8#, (l x0 x1)) === WTUP2(wInt8#,wInt8#, (r x0 x1))
+
+instance TestPrimop (Int8# -> Int#) where
+ testPrimop s l r = Property s $ \ (uInt8#-> x0) -> wInt# (l x0) === wInt# (r x0)
+
+instance TestPrimop (Int8# -> Int8#) where
+ testPrimop s l r = Property s $ \ (uInt8#-> x0) -> wInt8# (l x0) === wInt8# (r x0)
+
+instance TestPrimop (Int8# -> Word8#) where
+ testPrimop s l r = Property s $ \ (uInt8#-> x0) -> wWord8# (l x0) === wWord8# (r x0)
+
+instance TestPrimop (Word# -> Int# -> Word#) where
+ testPrimop s l r = Property s $ \ (uWord#-> x0) (uInt#-> x1) -> wWord# (l x0 x1) === wWord# (r x0 x1)
+
+instance TestPrimop (Word# -> Word# -> Int#) where
+ testPrimop s l r = Property s $ \ (uWord#-> x0) (uWord#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord#-> x0) (uWord#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+
+instance TestPrimop (Word# -> Word# -> Word#) where
+ testPrimop s l r = Property s $ \ (uWord#-> x0) (uWord#-> x1) -> wWord# (l x0 x1) === wWord# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord#-> x0) (uWord#-> x1) -> wWord# (l x0 x1) === wWord# (r x0 x1)
+
+instance TestPrimop (Word# -> Word# -> (# Word#,Int# #)) where
+ testPrimop s l r = Property s $ \ (uWord#-> x0) (uWord#-> x1) -> WTUP2(wWord#,wInt#, (l x0 x1)) === WTUP2(wWord#,wInt#, (r x0 x1))
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord#-> x0) (uWord#-> x1) -> WTUP2(wWord#,wInt#, (l x0 x1)) === WTUP2(wWord#,wInt#, (r x0 x1))
+
+instance TestPrimop (Word# -> Word# -> (# Word#,Word# #)) where
+ testPrimop s l r = Property s $ \ (uWord#-> x0) (uWord#-> x1) -> WTUP2(wWord#,wWord#, (l x0 x1)) === WTUP2(wWord#,wWord#, (r x0 x1))
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord#-> x0) (uWord#-> x1) -> WTUP2(wWord#,wWord#, (l x0 x1)) === WTUP2(wWord#,wWord#, (r x0 x1))
+
+instance TestPrimop (Word# -> Int#) where
+ testPrimop s l r = Property s $ \ (uWord#-> x0) -> wInt# (l x0) === wInt# (r x0)
+
+instance TestPrimop (Word# -> Word#) where
+ testPrimop s l r = Property s $ \ (uWord#-> x0) -> wWord# (l x0) === wWord# (r x0)
+
+instance TestPrimop (Word# -> Word16#) where
+ testPrimop s l r = Property s $ \ (uWord#-> x0) -> wWord16# (l x0) === wWord16# (r x0)
+
+instance TestPrimop (Word# -> Word32#) where
+ testPrimop s l r = Property s $ \ (uWord#-> x0) -> wWord32# (l x0) === wWord32# (r x0)
+
+instance TestPrimop (Word# -> Word64#) where
+ testPrimop s l r = Property s $ \ (uWord#-> x0) -> wWord64# (l x0) === wWord64# (r x0)
+
+instance TestPrimop (Word# -> Word8#) where
+ testPrimop s l r = Property s $ \ (uWord#-> x0) -> wWord8# (l x0) === wWord8# (r x0)
+
+instance TestPrimop (Word16# -> Int# -> Word16#) where
+ testPrimop s l r = Property s $ \ (uWord16#-> x0) (uInt#-> x1) -> wWord16# (l x0 x1) === wWord16# (r x0 x1)
+
+instance TestPrimop (Word16# -> Word16# -> Int#) where
+ testPrimop s l r = Property s $ \ (uWord16#-> x0) (uWord16#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord16#-> x0) (uWord16#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+
+instance TestPrimop (Word16# -> Word16# -> Word16#) where
+ testPrimop s l r = Property s $ \ (uWord16#-> x0) (uWord16#-> x1) -> wWord16# (l x0 x1) === wWord16# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord16#-> x0) (uWord16#-> x1) -> wWord16# (l x0 x1) === wWord16# (r x0 x1)
+
+instance TestPrimop (Word16# -> Word16# -> (# Word16#,Word16# #)) where
+ testPrimop s l r = Property s $ \ (uWord16#-> x0) (uWord16#-> x1) -> WTUP2(wWord16#,wWord16#, (l x0 x1)) === WTUP2(wWord16#,wWord16#, (r x0 x1))
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord16#-> x0) (uWord16#-> x1) -> WTUP2(wWord16#,wWord16#, (l x0 x1)) === WTUP2(wWord16#,wWord16#, (r x0 x1))
+
+instance TestPrimop (Word16# -> Int16#) where
+ testPrimop s l r = Property s $ \ (uWord16#-> x0) -> wInt16# (l x0) === wInt16# (r x0)
+
+instance TestPrimop (Word16# -> Word#) where
+ testPrimop s l r = Property s $ \ (uWord16#-> x0) -> wWord# (l x0) === wWord# (r x0)
+
+instance TestPrimop (Word16# -> Word16#) where
+ testPrimop s l r = Property s $ \ (uWord16#-> x0) -> wWord16# (l x0) === wWord16# (r x0)
+
+instance TestPrimop (Word32# -> Int# -> Word32#) where
+ testPrimop s l r = Property s $ \ (uWord32#-> x0) (uInt#-> x1) -> wWord32# (l x0 x1) === wWord32# (r x0 x1)
+
+instance TestPrimop (Word32# -> Word32# -> Int#) where
+ testPrimop s l r = Property s $ \ (uWord32#-> x0) (uWord32#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord32#-> x0) (uWord32#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+
+instance TestPrimop (Word32# -> Word32# -> Word32#) where
+ testPrimop s l r = Property s $ \ (uWord32#-> x0) (uWord32#-> x1) -> wWord32# (l x0 x1) === wWord32# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord32#-> x0) (uWord32#-> x1) -> wWord32# (l x0 x1) === wWord32# (r x0 x1)
+
+instance TestPrimop (Word32# -> Word32# -> (# Word32#,Word32# #)) where
+ testPrimop s l r = Property s $ \ (uWord32#-> x0) (uWord32#-> x1) -> WTUP2(wWord32#,wWord32#, (l x0 x1)) === WTUP2(wWord32#,wWord32#, (r x0 x1))
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord32#-> x0) (uWord32#-> x1) -> WTUP2(wWord32#,wWord32#, (l x0 x1)) === WTUP2(wWord32#,wWord32#, (r x0 x1))
+
+instance TestPrimop (Word32# -> Int32#) where
+ testPrimop s l r = Property s $ \ (uWord32#-> x0) -> wInt32# (l x0) === wInt32# (r x0)
+
+instance TestPrimop (Word32# -> Word#) where
+ testPrimop s l r = Property s $ \ (uWord32#-> x0) -> wWord# (l x0) === wWord# (r x0)
+
+instance TestPrimop (Word32# -> Word32#) where
+ testPrimop s l r = Property s $ \ (uWord32#-> x0) -> wWord32# (l x0) === wWord32# (r x0)
+
+instance TestPrimop (Word64# -> Int# -> Word64#) where
+ testPrimop s l r = Property s $ \ (uWord64#-> x0) (uInt#-> x1) -> wWord64# (l x0 x1) === wWord64# (r x0 x1)
+
+instance TestPrimop (Word64# -> Word64# -> Int#) where
+ testPrimop s l r = Property s $ \ (uWord64#-> x0) (uWord64#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord64#-> x0) (uWord64#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+
+instance TestPrimop (Word64# -> Word64# -> Word64#) where
+ testPrimop s l r = Property s $ \ (uWord64#-> x0) (uWord64#-> x1) -> wWord64# (l x0 x1) === wWord64# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord64#-> x0) (uWord64#-> x1) -> wWord64# (l x0 x1) === wWord64# (r x0 x1)
+
+instance TestPrimop (Word64# -> Int64#) where
+ testPrimop s l r = Property s $ \ (uWord64#-> x0) -> wInt64# (l x0) === wInt64# (r x0)
+
+instance TestPrimop (Word64# -> Word#) where
+ testPrimop s l r = Property s $ \ (uWord64#-> x0) -> wWord# (l x0) === wWord# (r x0)
+
+instance TestPrimop (Word64# -> Word64#) where
+ testPrimop s l r = Property s $ \ (uWord64#-> x0) -> wWord64# (l x0) === wWord64# (r x0)
+
+instance TestPrimop (Word8# -> Int# -> Word8#) where
+ testPrimop s l r = Property s $ \ (uWord8#-> x0) (uInt#-> x1) -> wWord8# (l x0 x1) === wWord8# (r x0 x1)
+
+instance TestPrimop (Word8# -> Word8# -> Int#) where
+ testPrimop s l r = Property s $ \ (uWord8#-> x0) (uWord8#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord8#-> x0) (uWord8#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
+
+instance TestPrimop (Word8# -> Word8# -> Word8#) where
+ testPrimop s l r = Property s $ \ (uWord8#-> x0) (uWord8#-> x1) -> wWord8# (l x0 x1) === wWord8# (r x0 x1)
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord8#-> x0) (uWord8#-> x1) -> wWord8# (l x0 x1) === wWord8# (r x0 x1)
+
+instance TestPrimop (Word8# -> Word8# -> (# Word8#,Word8# #)) where
+ testPrimop s l r = Property s $ \ (uWord8#-> x0) (uWord8#-> x1) -> WTUP2(wWord8#,wWord8#, (l x0 x1)) === WTUP2(wWord8#,wWord8#, (r x0 x1))
+ testPrimopDivLike s l r = Property s $ twoNonZero $ \ (uWord8#-> x0) (uWord8#-> x1) -> WTUP2(wWord8#,wWord8#, (l x0 x1)) === WTUP2(wWord8#,wWord8#, (r x0 x1))
+
+instance TestPrimop (Word8# -> Int8#) where
+ testPrimop s l r = Property s $ \ (uWord8#-> x0) -> wInt8# (l x0) === wInt8# (r x0)
+instance TestPrimop (Word8# -> Word#) where
+ testPrimop s l r = Property s $ \ (uWord8#-> x0) -> wWord# (l x0) === wWord# (r x0)
-main = runTests testNumberRefs
+instance TestPrimop (Word8# -> Word8#) where
+ testPrimop s l r = Property s $ \ (uWord8#-> x0) -> wWord8# (l x0) === wWord8# (r x0)
=====================================
testsuite/tests/numeric/should_run/foundation.stdout
=====================================
@@ -1,540 +1,1050 @@
Group ALL
- Group Int
- Group Integral
- Running FromIntegral(Integer(a)) == a
- Passed 100 iterations
- Group Property
- Running Eq
- Passed 100 iterations
- Running Show
- Passed 100 iterations
- Running Ord
- Passed 100 iterations
- Running <
- Passed 100 iterations
- Group Additive
- Running a + azero == a
- Passed 100 iterations
- Running azero + a == a
- Passed 100 iterations
- Running a + b == b + a
- Passed 100 iterations
- Group Multiplicative
- Running a * 1 == a
- Passed 100 iterations
- Running 1 * a == a
- Passed 100 iterations
- Running multiplication commutative
- Passed 100 iterations
- Running a * b == Integer(a) * Integer(b)
- Passed 100 iterations
- Group Divisible
- Running (x `div` y) * y + (x `mod` y) == x
- Passed 100 iterations
- Group Precedence
- Running + and - (1)
- Passed 100 iterations
- Running + and - (2)
- Passed 100 iterations
- Running + and * (1)
- Passed 100 iterations
- Running + and * (2)
- Passed 100 iterations
- Running - and * (1)
- Passed 100 iterations
- Running - and * (2)
- Passed 100 iterations
- Running * and ^ (1)
- Passed 100 iterations
- Running * and ^ (2)
- Passed 100 iterations
- Group Int8
- Group Integral
- Running FromIntegral(Integer(a)) == a
- Passed 100 iterations
- Group Property
- Running Eq
- Passed 100 iterations
- Running Show
- Passed 100 iterations
- Running Ord
- Passed 100 iterations
- Running <
- Passed 100 iterations
- Group Additive
- Running a + azero == a
- Passed 100 iterations
- Running azero + a == a
- Passed 100 iterations
- Running a + b == b + a
- Passed 100 iterations
- Group Multiplicative
- Running a * 1 == a
- Passed 100 iterations
- Running 1 * a == a
- Passed 100 iterations
- Running multiplication commutative
- Passed 100 iterations
- Running a * b == Integer(a) * Integer(b)
- Passed 100 iterations
- Group Divisible
- Running (x `div` y) * y + (x `mod` y) == x
- Passed 100 iterations
- Group Precedence
- Running + and - (1)
- Passed 100 iterations
- Running + and - (2)
- Passed 100 iterations
- Running + and * (1)
- Passed 100 iterations
- Running + and * (2)
- Passed 100 iterations
- Running - and * (1)
- Passed 100 iterations
- Running - and * (2)
- Passed 100 iterations
- Running * and ^ (1)
- Passed 100 iterations
- Running * and ^ (2)
- Passed 100 iterations
- Group Int16
- Group Integral
- Running FromIntegral(Integer(a)) == a
- Passed 100 iterations
- Group Property
- Running Eq
- Passed 100 iterations
- Running Show
- Passed 100 iterations
- Running Ord
- Passed 100 iterations
- Running <
- Passed 100 iterations
- Group Additive
- Running a + azero == a
- Passed 100 iterations
- Running azero + a == a
- Passed 100 iterations
- Running a + b == b + a
- Passed 100 iterations
- Group Multiplicative
- Running a * 1 == a
- Passed 100 iterations
- Running 1 * a == a
- Passed 100 iterations
- Running multiplication commutative
- Passed 100 iterations
- Running a * b == Integer(a) * Integer(b)
- Passed 100 iterations
- Group Divisible
- Running (x `div` y) * y + (x `mod` y) == x
- Passed 100 iterations
- Group Precedence
- Running + and - (1)
- Passed 100 iterations
- Running + and - (2)
- Passed 100 iterations
- Running + and * (1)
- Passed 100 iterations
- Running + and * (2)
- Passed 100 iterations
- Running - and * (1)
- Passed 100 iterations
- Running - and * (2)
- Passed 100 iterations
- Running * and ^ (1)
- Passed 100 iterations
- Running * and ^ (2)
- Passed 100 iterations
- Group Int32
- Group Integral
- Running FromIntegral(Integer(a)) == a
- Passed 100 iterations
- Group Property
- Running Eq
- Passed 100 iterations
- Running Show
- Passed 100 iterations
- Running Ord
- Passed 100 iterations
- Running <
- Passed 100 iterations
- Group Additive
- Running a + azero == a
- Passed 100 iterations
- Running azero + a == a
- Passed 100 iterations
- Running a + b == b + a
- Passed 100 iterations
- Group Multiplicative
- Running a * 1 == a
- Passed 100 iterations
- Running 1 * a == a
- Passed 100 iterations
- Running multiplication commutative
- Passed 100 iterations
- Running a * b == Integer(a) * Integer(b)
- Passed 100 iterations
- Group Divisible
- Running (x `div` y) * y + (x `mod` y) == x
- Passed 100 iterations
- Group Precedence
- Running + and - (1)
- Passed 100 iterations
- Running + and - (2)
- Passed 100 iterations
- Running + and * (1)
- Passed 100 iterations
- Running + and * (2)
- Passed 100 iterations
- Running - and * (1)
- Passed 100 iterations
- Running - and * (2)
- Passed 100 iterations
- Running * and ^ (1)
- Passed 100 iterations
- Running * and ^ (2)
- Passed 100 iterations
- Group Int64
- Group Integral
- Running FromIntegral(Integer(a)) == a
- Passed 100 iterations
- Group Property
- Running Eq
- Passed 100 iterations
- Running Show
- Passed 100 iterations
- Running Ord
- Passed 100 iterations
- Running <
- Passed 100 iterations
- Group Additive
- Running a + azero == a
- Passed 100 iterations
- Running azero + a == a
- Passed 100 iterations
- Running a + b == b + a
- Passed 100 iterations
- Group Multiplicative
- Running a * 1 == a
- Passed 100 iterations
- Running 1 * a == a
- Passed 100 iterations
- Running multiplication commutative
- Passed 100 iterations
- Running a * b == Integer(a) * Integer(b)
- Passed 100 iterations
- Group Divisible
- Running (x `div` y) * y + (x `mod` y) == x
- Passed 100 iterations
- Group Precedence
- Running + and - (1)
- Passed 100 iterations
- Running + and - (2)
- Passed 100 iterations
- Running + and * (1)
- Passed 100 iterations
- Running + and * (2)
- Passed 100 iterations
- Running - and * (1)
- Passed 100 iterations
- Running - and * (2)
- Passed 100 iterations
- Running * and ^ (1)
- Passed 100 iterations
- Running * and ^ (2)
- Passed 100 iterations
- Group Integer
- Group Integral
- Running FromIntegral(Integer(a)) == a
- Passed 100 iterations
- Group Property
- Running Eq
- Passed 100 iterations
- Running Show
- Passed 100 iterations
- Running Ord
- Passed 100 iterations
- Running <
- Passed 100 iterations
- Group Additive
- Running a + azero == a
- Passed 100 iterations
- Running azero + a == a
- Passed 100 iterations
- Running a + b == b + a
- Passed 100 iterations
- Group Multiplicative
- Running a * 1 == a
- Passed 100 iterations
- Running 1 * a == a
- Passed 100 iterations
- Running multiplication commutative
- Passed 100 iterations
- Running a * b == Integer(a) * Integer(b)
- Passed 100 iterations
- Group Divisible
- Running (x `div` y) * y + (x `mod` y) == x
- Passed 100 iterations
- Group Precedence
- Running + and - (1)
- Passed 100 iterations
- Running + and - (2)
- Passed 100 iterations
- Running + and * (1)
- Passed 100 iterations
- Running + and * (2)
- Passed 100 iterations
- Running - and * (1)
- Passed 100 iterations
- Running - and * (2)
- Passed 100 iterations
- Running * and ^ (1)
- Passed 100 iterations
- Running * and ^ (2)
- Passed 100 iterations
- Group Word
- Group Integral
- Running FromIntegral(Integer(a)) == a
- Passed 100 iterations
- Group Property
- Running Eq
- Passed 100 iterations
- Running Show
- Passed 100 iterations
- Running Ord
- Passed 100 iterations
- Running <
- Passed 100 iterations
- Group Additive
- Running a + azero == a
- Passed 100 iterations
- Running azero + a == a
- Passed 100 iterations
- Running a + b == b + a
- Passed 100 iterations
- Group Multiplicative
- Running a * 1 == a
- Passed 100 iterations
- Running 1 * a == a
- Passed 100 iterations
- Running multiplication commutative
- Passed 100 iterations
- Running a * b == Integer(a) * Integer(b)
- Passed 100 iterations
- Group Divisible
- Running (x `div` y) * y + (x `mod` y) == x
- Passed 100 iterations
- Group Precedence
- Running + and - (1)
- Passed 100 iterations
- Running + and - (2)
- Passed 100 iterations
- Running + and * (1)
- Passed 100 iterations
- Running + and * (2)
- Passed 100 iterations
- Running - and * (1)
- Passed 100 iterations
- Running - and * (2)
- Passed 100 iterations
- Running * and ^ (1)
- Passed 100 iterations
- Running * and ^ (2)
- Passed 100 iterations
- Group Word8
- Group Integral
- Running FromIntegral(Integer(a)) == a
- Passed 100 iterations
- Group Property
- Running Eq
- Passed 100 iterations
- Running Show
- Passed 100 iterations
- Running Ord
- Passed 100 iterations
- Running <
- Passed 100 iterations
- Group Additive
- Running a + azero == a
- Passed 100 iterations
- Running azero + a == a
- Passed 100 iterations
- Running a + b == b + a
- Passed 100 iterations
- Group Multiplicative
- Running a * 1 == a
- Passed 100 iterations
- Running 1 * a == a
- Passed 100 iterations
- Running multiplication commutative
- Passed 100 iterations
- Running a * b == Integer(a) * Integer(b)
- Passed 100 iterations
- Group Divisible
- Running (x `div` y) * y + (x `mod` y) == x
- Passed 100 iterations
- Group Precedence
- Running + and - (1)
- Passed 100 iterations
- Running + and - (2)
- Passed 100 iterations
- Running + and * (1)
- Passed 100 iterations
- Running + and * (2)
- Passed 100 iterations
- Running - and * (1)
- Passed 100 iterations
- Running - and * (2)
- Passed 100 iterations
- Running * and ^ (1)
- Passed 100 iterations
- Running * and ^ (2)
- Passed 100 iterations
- Group Word16
- Group Integral
- Running FromIntegral(Integer(a)) == a
- Passed 100 iterations
- Group Property
- Running Eq
- Passed 100 iterations
- Running Show
- Passed 100 iterations
- Running Ord
- Passed 100 iterations
- Running <
- Passed 100 iterations
- Group Additive
- Running a + azero == a
- Passed 100 iterations
- Running azero + a == a
- Passed 100 iterations
- Running a + b == b + a
- Passed 100 iterations
- Group Multiplicative
- Running a * 1 == a
- Passed 100 iterations
- Running 1 * a == a
- Passed 100 iterations
- Running multiplication commutative
- Passed 100 iterations
- Running a * b == Integer(a) * Integer(b)
- Passed 100 iterations
- Group Divisible
- Running (x `div` y) * y + (x `mod` y) == x
- Passed 100 iterations
- Group Precedence
- Running + and - (1)
- Passed 100 iterations
- Running + and - (2)
- Passed 100 iterations
- Running + and * (1)
- Passed 100 iterations
- Running + and * (2)
- Passed 100 iterations
- Running - and * (1)
- Passed 100 iterations
- Running - and * (2)
- Passed 100 iterations
- Running * and ^ (1)
- Passed 100 iterations
- Running * and ^ (2)
- Passed 100 iterations
- Group Word32
- Group Integral
- Running FromIntegral(Integer(a)) == a
- Passed 100 iterations
- Group Property
- Running Eq
- Passed 100 iterations
- Running Show
- Passed 100 iterations
- Running Ord
- Passed 100 iterations
- Running <
- Passed 100 iterations
- Group Additive
- Running a + azero == a
- Passed 100 iterations
- Running azero + a == a
- Passed 100 iterations
- Running a + b == b + a
- Passed 100 iterations
- Group Multiplicative
- Running a * 1 == a
- Passed 100 iterations
- Running 1 * a == a
- Passed 100 iterations
- Running multiplication commutative
- Passed 100 iterations
- Running a * b == Integer(a) * Integer(b)
- Passed 100 iterations
- Group Divisible
- Running (x `div` y) * y + (x `mod` y) == x
- Passed 100 iterations
- Group Precedence
- Running + and - (1)
- Passed 100 iterations
- Running + and - (2)
- Passed 100 iterations
- Running + and * (1)
- Passed 100 iterations
- Running + and * (2)
- Passed 100 iterations
- Running - and * (1)
- Passed 100 iterations
- Running - and * (2)
- Passed 100 iterations
- Running * and ^ (1)
- Passed 100 iterations
- Running * and ^ (2)
- Passed 100 iterations
- Group Word64
- Group Integral
- Running FromIntegral(Integer(a)) == a
- Passed 100 iterations
- Group Property
- Running Eq
- Passed 100 iterations
- Running Show
- Passed 100 iterations
- Running Ord
- Passed 100 iterations
- Running <
- Passed 100 iterations
- Group Additive
- Running a + azero == a
- Passed 100 iterations
- Running azero + a == a
- Passed 100 iterations
- Running a + b == b + a
- Passed 100 iterations
- Group Multiplicative
- Running a * 1 == a
- Passed 100 iterations
- Running 1 * a == a
- Passed 100 iterations
- Running multiplication commutative
- Passed 100 iterations
- Running a * b == Integer(a) * Integer(b)
- Passed 100 iterations
- Group Divisible
- Running (x `div` y) * y + (x `mod` y) == x
- Passed 100 iterations
- Group Precedence
- Running + and - (1)
- Passed 100 iterations
- Running + and - (2)
- Passed 100 iterations
- Running + and * (1)
- Passed 100 iterations
- Running + and * (2)
- Passed 100 iterations
- Running - and * (1)
- Passed 100 iterations
- Running - and * (2)
- Passed 100 iterations
- Running * and ^ (1)
- Passed 100 iterations
- Running * and ^ (2)
- Passed 100 iterations
+ Group ALL
+ Group Int
+ Group Integral
+ Running FromIntegral(Integer(a)) == a
+ Passed 100 iterations
+ Group Property
+ Running Eq
+ Passed 100 iterations
+ Running Show
+ Passed 100 iterations
+ Running Ord
+ Passed 100 iterations
+ Running <
+ Passed 100 iterations
+ Group Additive
+ Running a + azero == a
+ Passed 100 iterations
+ Running azero + a == a
+ Passed 100 iterations
+ Running a + b == b + a
+ Passed 100 iterations
+ Group Multiplicative
+ Running a * 1 == a
+ Passed 100 iterations
+ Running 1 * a == a
+ Passed 100 iterations
+ Running multiplication commutative
+ Passed 100 iterations
+ Running a * b == Integer(a) * Integer(b)
+ Passed 100 iterations
+ Group Divisible
+ Running (x `div` y) * y + (x `mod` y) == x
+ Passed 100 iterations
+ Group Precedence
+ Running + and - (1)
+ Passed 100 iterations
+ Running + and - (2)
+ Passed 100 iterations
+ Running + and * (1)
+ Passed 100 iterations
+ Running + and * (2)
+ Passed 100 iterations
+ Running - and * (1)
+ Passed 100 iterations
+ Running - and * (2)
+ Passed 100 iterations
+ Running * and ^ (1)
+ Passed 100 iterations
+ Running * and ^ (2)
+ Passed 100 iterations
+ Group Int8
+ Group Integral
+ Running FromIntegral(Integer(a)) == a
+ Passed 100 iterations
+ Group Property
+ Running Eq
+ Passed 100 iterations
+ Running Show
+ Passed 100 iterations
+ Running Ord
+ Passed 100 iterations
+ Running <
+ Passed 100 iterations
+ Group Additive
+ Running a + azero == a
+ Passed 100 iterations
+ Running azero + a == a
+ Passed 100 iterations
+ Running a + b == b + a
+ Passed 100 iterations
+ Group Multiplicative
+ Running a * 1 == a
+ Passed 100 iterations
+ Running 1 * a == a
+ Passed 100 iterations
+ Running multiplication commutative
+ Passed 100 iterations
+ Running a * b == Integer(a) * Integer(b)
+ Passed 100 iterations
+ Group Divisible
+ Running (x `div` y) * y + (x `mod` y) == x
+ Passed 100 iterations
+ Group Precedence
+ Running + and - (1)
+ Passed 100 iterations
+ Running + and - (2)
+ Passed 100 iterations
+ Running + and * (1)
+ Passed 100 iterations
+ Running + and * (2)
+ Passed 100 iterations
+ Running - and * (1)
+ Passed 100 iterations
+ Running - and * (2)
+ Passed 100 iterations
+ Running * and ^ (1)
+ Passed 100 iterations
+ Running * and ^ (2)
+ Passed 100 iterations
+ Group Int16
+ Group Integral
+ Running FromIntegral(Integer(a)) == a
+ Passed 100 iterations
+ Group Property
+ Running Eq
+ Passed 100 iterations
+ Running Show
+ Passed 100 iterations
+ Running Ord
+ Passed 100 iterations
+ Running <
+ Passed 100 iterations
+ Group Additive
+ Running a + azero == a
+ Passed 100 iterations
+ Running azero + a == a
+ Passed 100 iterations
+ Running a + b == b + a
+ Passed 100 iterations
+ Group Multiplicative
+ Running a * 1 == a
+ Passed 100 iterations
+ Running 1 * a == a
+ Passed 100 iterations
+ Running multiplication commutative
+ Passed 100 iterations
+ Running a * b == Integer(a) * Integer(b)
+ Passed 100 iterations
+ Group Divisible
+ Running (x `div` y) * y + (x `mod` y) == x
+ Passed 100 iterations
+ Group Precedence
+ Running + and - (1)
+ Passed 100 iterations
+ Running + and - (2)
+ Passed 100 iterations
+ Running + and * (1)
+ Passed 100 iterations
+ Running + and * (2)
+ Passed 100 iterations
+ Running - and * (1)
+ Passed 100 iterations
+ Running - and * (2)
+ Passed 100 iterations
+ Running * and ^ (1)
+ Passed 100 iterations
+ Running * and ^ (2)
+ Passed 100 iterations
+ Group Int32
+ Group Integral
+ Running FromIntegral(Integer(a)) == a
+ Passed 100 iterations
+ Group Property
+ Running Eq
+ Passed 100 iterations
+ Running Show
+ Passed 100 iterations
+ Running Ord
+ Passed 100 iterations
+ Running <
+ Passed 100 iterations
+ Group Additive
+ Running a + azero == a
+ Passed 100 iterations
+ Running azero + a == a
+ Passed 100 iterations
+ Running a + b == b + a
+ Passed 100 iterations
+ Group Multiplicative
+ Running a * 1 == a
+ Passed 100 iterations
+ Running 1 * a == a
+ Passed 100 iterations
+ Running multiplication commutative
+ Passed 100 iterations
+ Running a * b == Integer(a) * Integer(b)
+ Passed 100 iterations
+ Group Divisible
+ Running (x `div` y) * y + (x `mod` y) == x
+ Passed 100 iterations
+ Group Precedence
+ Running + and - (1)
+ Passed 100 iterations
+ Running + and - (2)
+ Passed 100 iterations
+ Running + and * (1)
+ Passed 100 iterations
+ Running + and * (2)
+ Passed 100 iterations
+ Running - and * (1)
+ Passed 100 iterations
+ Running - and * (2)
+ Passed 100 iterations
+ Running * and ^ (1)
+ Passed 100 iterations
+ Running * and ^ (2)
+ Passed 100 iterations
+ Group Int64
+ Group Integral
+ Running FromIntegral(Integer(a)) == a
+ Passed 100 iterations
+ Group Property
+ Running Eq
+ Passed 100 iterations
+ Running Show
+ Passed 100 iterations
+ Running Ord
+ Passed 100 iterations
+ Running <
+ Passed 100 iterations
+ Group Additive
+ Running a + azero == a
+ Passed 100 iterations
+ Running azero + a == a
+ Passed 100 iterations
+ Running a + b == b + a
+ Passed 100 iterations
+ Group Multiplicative
+ Running a * 1 == a
+ Passed 100 iterations
+ Running 1 * a == a
+ Passed 100 iterations
+ Running multiplication commutative
+ Passed 100 iterations
+ Running a * b == Integer(a) * Integer(b)
+ Passed 100 iterations
+ Group Divisible
+ Running (x `div` y) * y + (x `mod` y) == x
+ Passed 100 iterations
+ Group Precedence
+ Running + and - (1)
+ Passed 100 iterations
+ Running + and - (2)
+ Passed 100 iterations
+ Running + and * (1)
+ Passed 100 iterations
+ Running + and * (2)
+ Passed 100 iterations
+ Running - and * (1)
+ Passed 100 iterations
+ Running - and * (2)
+ Passed 100 iterations
+ Running * and ^ (1)
+ Passed 100 iterations
+ Running * and ^ (2)
+ Passed 100 iterations
+ Group Integer
+ Group Integral
+ Running FromIntegral(Integer(a)) == a
+ Passed 100 iterations
+ Group Property
+ Running Eq
+ Passed 100 iterations
+ Running Show
+ Passed 100 iterations
+ Running Ord
+ Passed 100 iterations
+ Running <
+ Passed 100 iterations
+ Group Additive
+ Running a + azero == a
+ Passed 100 iterations
+ Running azero + a == a
+ Passed 100 iterations
+ Running a + b == b + a
+ Passed 100 iterations
+ Group Multiplicative
+ Running a * 1 == a
+ Passed 100 iterations
+ Running 1 * a == a
+ Passed 100 iterations
+ Running multiplication commutative
+ Passed 100 iterations
+ Running a * b == Integer(a) * Integer(b)
+ Passed 100 iterations
+ Group Divisible
+ Running (x `div` y) * y + (x `mod` y) == x
+ Passed 100 iterations
+ Group Precedence
+ Running + and - (1)
+ Passed 100 iterations
+ Running + and - (2)
+ Passed 100 iterations
+ Running + and * (1)
+ Passed 100 iterations
+ Running + and * (2)
+ Passed 100 iterations
+ Running - and * (1)
+ Passed 100 iterations
+ Running - and * (2)
+ Passed 100 iterations
+ Running * and ^ (1)
+ Passed 100 iterations
+ Running * and ^ (2)
+ Passed 100 iterations
+ Group Word
+ Group Integral
+ Running FromIntegral(Integer(a)) == a
+ Passed 100 iterations
+ Group Property
+ Running Eq
+ Passed 100 iterations
+ Running Show
+ Passed 100 iterations
+ Running Ord
+ Passed 100 iterations
+ Running <
+ Passed 100 iterations
+ Group Additive
+ Running a + azero == a
+ Passed 100 iterations
+ Running azero + a == a
+ Passed 100 iterations
+ Running a + b == b + a
+ Passed 100 iterations
+ Group Multiplicative
+ Running a * 1 == a
+ Passed 100 iterations
+ Running 1 * a == a
+ Passed 100 iterations
+ Running multiplication commutative
+ Passed 100 iterations
+ Running a * b == Integer(a) * Integer(b)
+ Passed 100 iterations
+ Group Divisible
+ Running (x `div` y) * y + (x `mod` y) == x
+ Passed 100 iterations
+ Group Precedence
+ Running + and - (1)
+ Passed 100 iterations
+ Running + and - (2)
+ Passed 100 iterations
+ Running + and * (1)
+ Passed 100 iterations
+ Running + and * (2)
+ Passed 100 iterations
+ Running - and * (1)
+ Passed 100 iterations
+ Running - and * (2)
+ Passed 100 iterations
+ Running * and ^ (1)
+ Passed 100 iterations
+ Running * and ^ (2)
+ Passed 100 iterations
+ Group Word8
+ Group Integral
+ Running FromIntegral(Integer(a)) == a
+ Passed 100 iterations
+ Group Property
+ Running Eq
+ Passed 100 iterations
+ Running Show
+ Passed 100 iterations
+ Running Ord
+ Passed 100 iterations
+ Running <
+ Passed 100 iterations
+ Group Additive
+ Running a + azero == a
+ Passed 100 iterations
+ Running azero + a == a
+ Passed 100 iterations
+ Running a + b == b + a
+ Passed 100 iterations
+ Group Multiplicative
+ Running a * 1 == a
+ Passed 100 iterations
+ Running 1 * a == a
+ Passed 100 iterations
+ Running multiplication commutative
+ Passed 100 iterations
+ Running a * b == Integer(a) * Integer(b)
+ Passed 100 iterations
+ Group Divisible
+ Running (x `div` y) * y + (x `mod` y) == x
+ Passed 100 iterations
+ Group Precedence
+ Running + and - (1)
+ Passed 100 iterations
+ Running + and - (2)
+ Passed 100 iterations
+ Running + and * (1)
+ Passed 100 iterations
+ Running + and * (2)
+ Passed 100 iterations
+ Running - and * (1)
+ Passed 100 iterations
+ Running - and * (2)
+ Passed 100 iterations
+ Running * and ^ (1)
+ Passed 100 iterations
+ Running * and ^ (2)
+ Passed 100 iterations
+ Group Word16
+ Group Integral
+ Running FromIntegral(Integer(a)) == a
+ Passed 100 iterations
+ Group Property
+ Running Eq
+ Passed 100 iterations
+ Running Show
+ Passed 100 iterations
+ Running Ord
+ Passed 100 iterations
+ Running <
+ Passed 100 iterations
+ Group Additive
+ Running a + azero == a
+ Passed 100 iterations
+ Running azero + a == a
+ Passed 100 iterations
+ Running a + b == b + a
+ Passed 100 iterations
+ Group Multiplicative
+ Running a * 1 == a
+ Passed 100 iterations
+ Running 1 * a == a
+ Passed 100 iterations
+ Running multiplication commutative
+ Passed 100 iterations
+ Running a * b == Integer(a) * Integer(b)
+ Passed 100 iterations
+ Group Divisible
+ Running (x `div` y) * y + (x `mod` y) == x
+ Passed 100 iterations
+ Group Precedence
+ Running + and - (1)
+ Passed 100 iterations
+ Running + and - (2)
+ Passed 100 iterations
+ Running + and * (1)
+ Passed 100 iterations
+ Running + and * (2)
+ Passed 100 iterations
+ Running - and * (1)
+ Passed 100 iterations
+ Running - and * (2)
+ Passed 100 iterations
+ Running * and ^ (1)
+ Passed 100 iterations
+ Running * and ^ (2)
+ Passed 100 iterations
+ Group Word32
+ Group Integral
+ Running FromIntegral(Integer(a)) == a
+ Passed 100 iterations
+ Group Property
+ Running Eq
+ Passed 100 iterations
+ Running Show
+ Passed 100 iterations
+ Running Ord
+ Passed 100 iterations
+ Running <
+ Passed 100 iterations
+ Group Additive
+ Running a + azero == a
+ Passed 100 iterations
+ Running azero + a == a
+ Passed 100 iterations
+ Running a + b == b + a
+ Passed 100 iterations
+ Group Multiplicative
+ Running a * 1 == a
+ Passed 100 iterations
+ Running 1 * a == a
+ Passed 100 iterations
+ Running multiplication commutative
+ Passed 100 iterations
+ Running a * b == Integer(a) * Integer(b)
+ Passed 100 iterations
+ Group Divisible
+ Running (x `div` y) * y + (x `mod` y) == x
+ Passed 100 iterations
+ Group Precedence
+ Running + and - (1)
+ Passed 100 iterations
+ Running + and - (2)
+ Passed 100 iterations
+ Running + and * (1)
+ Passed 100 iterations
+ Running + and * (2)
+ Passed 100 iterations
+ Running - and * (1)
+ Passed 100 iterations
+ Running - and * (2)
+ Passed 100 iterations
+ Running * and ^ (1)
+ Passed 100 iterations
+ Running * and ^ (2)
+ Passed 100 iterations
+ Group Word64
+ Group Integral
+ Running FromIntegral(Integer(a)) == a
+ Passed 100 iterations
+ Group Property
+ Running Eq
+ Passed 100 iterations
+ Running Show
+ Passed 100 iterations
+ Running Ord
+ Passed 100 iterations
+ Running <
+ Passed 100 iterations
+ Group Additive
+ Running a + azero == a
+ Passed 100 iterations
+ Running azero + a == a
+ Passed 100 iterations
+ Running a + b == b + a
+ Passed 100 iterations
+ Group Multiplicative
+ Running a * 1 == a
+ Passed 100 iterations
+ Running 1 * a == a
+ Passed 100 iterations
+ Running multiplication commutative
+ Passed 100 iterations
+ Running a * b == Integer(a) * Integer(b)
+ Passed 100 iterations
+ Group Divisible
+ Running (x `div` y) * y + (x `mod` y) == x
+ Passed 100 iterations
+ Group Precedence
+ Running + and - (1)
+ Passed 100 iterations
+ Running + and - (2)
+ Passed 100 iterations
+ Running + and * (1)
+ Passed 100 iterations
+ Running + and * (2)
+ Passed 100 iterations
+ Running - and * (1)
+ Passed 100 iterations
+ Running - and * (2)
+ Passed 100 iterations
+ Running * and ^ (1)
+ Passed 100 iterations
+ Running * and ^ (2)
+ Passed 100 iterations
+ Group primop
+ Running gtChar#
+ Passed 100 iterations
+ Running geChar#
+ Passed 100 iterations
+ Running eqChar#
+ Passed 100 iterations
+ Running neChar#
+ Passed 100 iterations
+ Running ltChar#
+ Passed 100 iterations
+ Running leChar#
+ Passed 100 iterations
+ Running ord#
+ Passed 100 iterations
+ Running int8ToInt#
+ Passed 100 iterations
+ Running intToInt8#
+ Passed 100 iterations
+ Running negateInt8#
+ Passed 100 iterations
+ Running plusInt8#
+ Passed 100 iterations
+ Running subInt8#
+ Passed 100 iterations
+ Running timesInt8#
+ Passed 100 iterations
+ Running quotInt8#
+ Passed 100 iterations
+ Running remInt8#
+ Passed 100 iterations
+ Running quotRemInt8#
+ Passed 100 iterations
+ Running uncheckedShiftLInt8#
+ Passed 100 iterations
+ Running uncheckedShiftRAInt8#
+ Passed 100 iterations
+ Running uncheckedShiftRLInt8#
+ Passed 100 iterations
+ Running int8ToWord8#
+ Passed 100 iterations
+ Running eqInt8#
+ Passed 100 iterations
+ Running geInt8#
+ Passed 100 iterations
+ Running gtInt8#
+ Passed 100 iterations
+ Running leInt8#
+ Passed 100 iterations
+ Running ltInt8#
+ Passed 100 iterations
+ Running neInt8#
+ Passed 100 iterations
+ Running word8ToWord#
+ Passed 100 iterations
+ Running wordToWord8#
+ Passed 100 iterations
+ Running plusWord8#
+ Passed 100 iterations
+ Running subWord8#
+ Passed 100 iterations
+ Running timesWord8#
+ Passed 100 iterations
+ Running quotWord8#
+ Passed 100 iterations
+ Running remWord8#
+ Passed 100 iterations
+ Running quotRemWord8#
+ Passed 100 iterations
+ Running andWord8#
+ Passed 100 iterations
+ Running orWord8#
+ Passed 100 iterations
+ Running xorWord8#
+ Passed 100 iterations
+ Running notWord8#
+ Passed 100 iterations
+ Running uncheckedShiftLWord8#
+ Passed 100 iterations
+ Running uncheckedShiftRLWord8#
+ Passed 100 iterations
+ Running word8ToInt8#
+ Passed 100 iterations
+ Running eqWord8#
+ Passed 100 iterations
+ Running geWord8#
+ Passed 100 iterations
+ Running gtWord8#
+ Passed 100 iterations
+ Running leWord8#
+ Passed 100 iterations
+ Running ltWord8#
+ Passed 100 iterations
+ Running neWord8#
+ Passed 100 iterations
+ Running int16ToInt#
+ Passed 100 iterations
+ Running intToInt16#
+ Passed 100 iterations
+ Running negateInt16#
+ Passed 100 iterations
+ Running plusInt16#
+ Passed 100 iterations
+ Running subInt16#
+ Passed 100 iterations
+ Running timesInt16#
+ Passed 100 iterations
+ Running quotInt16#
+ Passed 100 iterations
+ Running remInt16#
+ Passed 100 iterations
+ Running quotRemInt16#
+ Passed 100 iterations
+ Running uncheckedShiftLInt16#
+ Passed 100 iterations
+ Running uncheckedShiftRAInt16#
+ Passed 100 iterations
+ Running uncheckedShiftRLInt16#
+ Passed 100 iterations
+ Running int16ToWord16#
+ Passed 100 iterations
+ Running eqInt16#
+ Passed 100 iterations
+ Running geInt16#
+ Passed 100 iterations
+ Running gtInt16#
+ Passed 100 iterations
+ Running leInt16#
+ Passed 100 iterations
+ Running ltInt16#
+ Passed 100 iterations
+ Running neInt16#
+ Passed 100 iterations
+ Running word16ToWord#
+ Passed 100 iterations
+ Running wordToWord16#
+ Passed 100 iterations
+ Running plusWord16#
+ Passed 100 iterations
+ Running subWord16#
+ Passed 100 iterations
+ Running timesWord16#
+ Passed 100 iterations
+ Running quotWord16#
+ Passed 100 iterations
+ Running remWord16#
+ Passed 100 iterations
+ Running quotRemWord16#
+ Passed 100 iterations
+ Running andWord16#
+ Passed 100 iterations
+ Running orWord16#
+ Passed 100 iterations
+ Running xorWord16#
+ Passed 100 iterations
+ Running notWord16#
+ Passed 100 iterations
+ Running uncheckedShiftLWord16#
+ Passed 100 iterations
+ Running uncheckedShiftRLWord16#
+ Passed 100 iterations
+ Running word16ToInt16#
+ Passed 100 iterations
+ Running eqWord16#
+ Passed 100 iterations
+ Running geWord16#
+ Passed 100 iterations
+ Running gtWord16#
+ Passed 100 iterations
+ Running leWord16#
+ Passed 100 iterations
+ Running ltWord16#
+ Passed 100 iterations
+ Running neWord16#
+ Passed 100 iterations
+ Running int32ToInt#
+ Passed 100 iterations
+ Running intToInt32#
+ Passed 100 iterations
+ Running negateInt32#
+ Passed 100 iterations
+ Running plusInt32#
+ Passed 100 iterations
+ Running subInt32#
+ Passed 100 iterations
+ Running timesInt32#
+ Passed 100 iterations
+ Running quotInt32#
+ Passed 100 iterations
+ Running remInt32#
+ Passed 100 iterations
+ Running quotRemInt32#
+ Passed 100 iterations
+ Running uncheckedShiftLInt32#
+ Passed 100 iterations
+ Running uncheckedShiftRAInt32#
+ Passed 100 iterations
+ Running uncheckedShiftRLInt32#
+ Passed 100 iterations
+ Running int32ToWord32#
+ Passed 100 iterations
+ Running eqInt32#
+ Passed 100 iterations
+ Running geInt32#
+ Passed 100 iterations
+ Running gtInt32#
+ Passed 100 iterations
+ Running leInt32#
+ Passed 100 iterations
+ Running ltInt32#
+ Passed 100 iterations
+ Running neInt32#
+ Passed 100 iterations
+ Running word32ToWord#
+ Passed 100 iterations
+ Running wordToWord32#
+ Passed 100 iterations
+ Running plusWord32#
+ Passed 100 iterations
+ Running subWord32#
+ Passed 100 iterations
+ Running timesWord32#
+ Passed 100 iterations
+ Running quotWord32#
+ Passed 100 iterations
+ Running remWord32#
+ Passed 100 iterations
+ Running quotRemWord32#
+ Passed 100 iterations
+ Running andWord32#
+ Passed 100 iterations
+ Running orWord32#
+ Passed 100 iterations
+ Running xorWord32#
+ Passed 100 iterations
+ Running notWord32#
+ Passed 100 iterations
+ Running uncheckedShiftLWord32#
+ Passed 100 iterations
+ Running uncheckedShiftRLWord32#
+ Passed 100 iterations
+ Running word32ToInt32#
+ Passed 100 iterations
+ Running eqWord32#
+ Passed 100 iterations
+ Running geWord32#
+ Passed 100 iterations
+ Running gtWord32#
+ Passed 100 iterations
+ Running leWord32#
+ Passed 100 iterations
+ Running ltWord32#
+ Passed 100 iterations
+ Running neWord32#
+ Passed 100 iterations
+ Running int64ToInt#
+ Passed 100 iterations
+ Running intToInt64#
+ Passed 100 iterations
+ Running negateInt64#
+ Passed 100 iterations
+ Running plusInt64#
+ Passed 100 iterations
+ Running subInt64#
+ Passed 100 iterations
+ Running timesInt64#
+ Passed 100 iterations
+ Running quotInt64#
+ Passed 100 iterations
+ Running remInt64#
+ Passed 100 iterations
+ Running uncheckedIShiftL64#
+ Passed 100 iterations
+ Running uncheckedIShiftRA64#
+ Passed 100 iterations
+ Running uncheckedIShiftRL64#
+ Passed 100 iterations
+ Running int64ToWord64#
+ Passed 100 iterations
+ Running eqInt64#
+ Passed 100 iterations
+ Running geInt64#
+ Passed 100 iterations
+ Running gtInt64#
+ Passed 100 iterations
+ Running leInt64#
+ Passed 100 iterations
+ Running ltInt64#
+ Passed 100 iterations
+ Running neInt64#
+ Passed 100 iterations
+ Running word64ToWord#
+ Passed 100 iterations
+ Running wordToWord64#
+ Passed 100 iterations
+ Running plusWord64#
+ Passed 100 iterations
+ Running subWord64#
+ Passed 100 iterations
+ Running timesWord64#
+ Passed 100 iterations
+ Running quotWord64#
+ Passed 100 iterations
+ Running remWord64#
+ Passed 100 iterations
+ Running and64#
+ Passed 100 iterations
+ Running or64#
+ Passed 100 iterations
+ Running xor64#
+ Passed 100 iterations
+ Running not64#
+ Passed 100 iterations
+ Running uncheckedShiftL64#
+ Passed 100 iterations
+ Running uncheckedShiftRL64#
+ Passed 100 iterations
+ Running word64ToInt64#
+ Passed 100 iterations
+ Running eqWord64#
+ Passed 100 iterations
+ Running geWord64#
+ Passed 100 iterations
+ Running gtWord64#
+ Passed 100 iterations
+ Running leWord64#
+ Passed 100 iterations
+ Running ltWord64#
+ Passed 100 iterations
+ Running neWord64#
+ Passed 100 iterations
+ Running +#
+ Passed 100 iterations
+ Running -#
+ Passed 100 iterations
+ Running *#
+ Passed 100 iterations
+ Running timesInt2#
+ Passed 100 iterations
+ Running mulIntMayOflo#
+ Passed 100 iterations
+ Running quotInt#
+ Passed 100 iterations
+ Running remInt#
+ Passed 100 iterations
+ Running quotRemInt#
+ Passed 100 iterations
+ Running andI#
+ Passed 100 iterations
+ Running orI#
+ Passed 100 iterations
+ Running xorI#
+ Passed 100 iterations
+ Running notI#
+ Passed 100 iterations
+ Running negateInt#
+ Passed 100 iterations
+ Running addIntC#
+ Passed 100 iterations
+ Running subIntC#
+ Passed 100 iterations
+ Running >#
+ Passed 100 iterations
+ Running >=#
+ Passed 100 iterations
+ Running ==#
+ Passed 100 iterations
+ Running /=#
+ Passed 100 iterations
+ Running <#
+ Passed 100 iterations
+ Running <=#
+ Passed 100 iterations
+ Running chr#
+ Passed 100 iterations
+ Running int2Word#
+ Passed 100 iterations
+ Running uncheckedIShiftL#
+ Passed 100 iterations
+ Running uncheckedIShiftRA#
+ Passed 100 iterations
+ Running uncheckedIShiftRL#
+ Passed 100 iterations
+ Running plusWord#
+ Passed 100 iterations
+ Running addWordC#
+ Passed 100 iterations
+ Running subWordC#
+ Passed 100 iterations
+ Running plusWord2#
+ Passed 100 iterations
+ Running minusWord#
+ Passed 100 iterations
+ Running timesWord#
+ Passed 100 iterations
+ Running timesWord2#
+ Passed 100 iterations
+ Running quotWord#
+ Passed 100 iterations
+ Running remWord#
+ Passed 100 iterations
+ Running quotRemWord#
+ Passed 100 iterations
+ Running and#
+ Passed 100 iterations
+ Running or#
+ Passed 100 iterations
+ Running xor#
+ Passed 100 iterations
+ Running not#
+ Passed 100 iterations
+ Running uncheckedShiftL#
+ Passed 100 iterations
+ Running uncheckedShiftRL#
+ Passed 100 iterations
+ Running word2Int#
+ Passed 100 iterations
+ Running gtWord#
+ Passed 100 iterations
+ Running geWord#
+ Passed 100 iterations
+ Running eqWord#
+ Passed 100 iterations
+ Running neWord#
+ Passed 100 iterations
+ Running ltWord#
+ Passed 100 iterations
+ Running leWord#
+ Passed 100 iterations
+ Running popCnt8#
+ Passed 100 iterations
+ Running popCnt16#
+ Passed 100 iterations
+ Running popCnt32#
+ Passed 100 iterations
+ Running popCnt64#
+ Passed 100 iterations
+ Running popCnt#
+ Passed 100 iterations
+ Running pdep8#
+ Passed 100 iterations
+ Running pdep16#
+ Passed 100 iterations
+ Running pdep32#
+ Passed 100 iterations
+ Running pdep64#
+ Passed 100 iterations
+ Running pdep#
+ Passed 100 iterations
+ Running pext8#
+ Passed 100 iterations
+ Running pext16#
+ Passed 100 iterations
+ Running pext32#
+ Passed 100 iterations
+ Running pext64#
+ Passed 100 iterations
+ Running pext#
+ Passed 100 iterations
+ Running clz8#
+ Passed 100 iterations
+ Running clz16#
+ Passed 100 iterations
+ Running clz32#
+ Passed 100 iterations
+ Running clz64#
+ Passed 100 iterations
+ Running clz#
+ Passed 100 iterations
+ Running ctz8#
+ Passed 100 iterations
+ Running ctz16#
+ Passed 100 iterations
+ Running ctz32#
+ Passed 100 iterations
+ Running ctz64#
+ Passed 100 iterations
+ Running ctz#
+ Passed 100 iterations
+ Running byteSwap16#
+ Passed 100 iterations
+ Running byteSwap32#
+ Passed 100 iterations
+ Running byteSwap64#
+ Passed 100 iterations
+ Running byteSwap#
+ Passed 100 iterations
+ Running bitReverse8#
+ Passed 100 iterations
+ Running bitReverse16#
+ Passed 100 iterations
+ Running bitReverse32#
+ Passed 100 iterations
+ Running bitReverse64#
+ Passed 100 iterations
+ Running bitReverse#
+ Passed 100 iterations
+ Running narrow8Int#
+ Passed 100 iterations
+ Running narrow16Int#
+ Passed 100 iterations
+ Running narrow32Int#
+ Passed 100 iterations
+ Running narrow8Word#
+ Passed 100 iterations
+ Running narrow16Word#
+ Passed 100 iterations
+ Running narrow32Word#
+ Passed 100 iterations
=====================================
utils/genprimopcode/Main.hs
=====================================
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -Wno-x-partial #-}
------------------------------------------------------------------
-- A primop-table mangling program --
--
@@ -10,11 +11,12 @@ import Parser
import Syntax
import Data.Char
-import Data.List (union, intersperse, intercalate, nub)
-import Data.Maybe ( catMaybes )
+import Data.List (union, intersperse, intercalate, nub, sort)
+import Data.Maybe ( catMaybes, mapMaybe )
import System.Environment ( getArgs )
import System.IO ( hSetEncoding, stdin, stdout, utf8 )
+
vecOptions :: Entry -> [(String,String,Int)]
vecOptions i =
concat [vecs | OptionVector vecs <- opts i]
@@ -204,6 +206,9 @@ main = getArgs >>= \args ->
"--wired-in-deprecations"
-> putStr (gen_wired_in_deprecations p_o_specs)
+ "--foundation-tests"
+ -> putStr (gen_foundation_tests p_o_specs)
+
_ -> error "Should not happen, known_args out of sync?"
)
@@ -229,7 +234,8 @@ known_args
"--make-haskell-source",
"--make-latex-doc",
"--wired-in-docs",
- "--wired-in-deprecations"
+ "--wired-in-deprecations",
+ "--foundation-tests"
]
------------------------------------------------------------------
@@ -679,6 +685,92 @@ gen_wired_in_deprecations (Info _ entries)
| otherwise = Nothing
+gen_foundation_tests :: Info -> String
+gen_foundation_tests (Info _ entries)
+ = "tests =\n [ "
+ ++ intercalate "\n , " (catMaybes $ map mkTest entries)
+ ++ "\n ]\n"
+ ++ "\n" ++ intercalate "\n" (map mkInstances testable_tys)
+ where
+ testable_tys = nub (sort (mapMaybe (\po -> ty po <$ mkTest po) entries))
+
+ mkInstances inst_ty =
+ let test_lambda = "\\ " ++ intercalate " " (zipWith mkArg [0::Int ..] (arg_tys)) ++ " -> " ++ mk_body "l" ++ " === " ++ mk_body "r"
+ in unlines $
+ [ "instance TestPrimop (" ++ pprTy inst_ty ++ ") where"
+ , " testPrimop s l r = Property s $ " ++ test_lambda ]
+ ++ (if mb_divable_tys
+ then [" testPrimopDivLike s l r = Property s $ twoNonZero $ " ++ test_lambda]
+ else [])
+ where
+ arg_tys = args inst_ty
+ -- eg Int -> Int -> a
+ mb_divable_tys = case arg_tys of
+ [ty1,ty2] -> ty1 == ty2 && ty1 `elem` divableTyCons
+ _ -> False
+
+ mk_body s = res_ty inst_ty (" (" ++ s ++ " " ++ intercalate " " vs ++ ")")
+
+ vs = zipWith (\n _ -> "x" ++ show n) [0::Int ..] (arg_tys)
+
+ mkArg n t = "(" ++ unwrapper t ++ "-> x" ++ show n ++ ")"
+
+
+ wrapper s = "w" ++ s
+ unwrapper s = "u" ++ s
+
+
+ args (TyF (TyApp (TyCon c) []) t2) = c : args t2
+ args (TyApp {}) = []
+ args (TyUTup {}) = []
+ -- If you hit this you will need to handle the foundation tests to handle the
+ -- type it failed on.
+ args arg_ty = error ("Unexpected primop type:" ++ pprTy arg_ty)
+
+ res_ty (TyF _ t2) x = res_ty t2 x
+ res_ty (TyApp (TyCon c) []) x = wrapper c ++ x
+ res_ty (TyUTup tup_tys) x =
+ let wtup = case length tup_tys of
+ 2 -> "WTUP2"
+ 3 -> "WTUP3"
+ -- Only handles primops returning unboxed tuples up to 3 args currently
+ _ -> error "Unexpected primop result type"
+ in wtup ++"(" ++ intercalate "," (map (\a -> res_ty a "") tup_tys ++ [x]) ++ ")"
+ -- If you hit this you will need to handle the foundation tests to handle the
+ -- type it failed on.
+ res_ty unexpected_ty x = error ("Unexpected primop result type:" ++ pprTy unexpected_ty ++ "," ++ x)
+
+
+ wrap qual nm | isLower (head nm) = qual ++ "." ++ nm
+ | otherwise = "(" ++ qual ++ "." ++ nm ++ ")"
+ mkTest po
+ | Just poName <- getName po
+ , is_primop po
+ , not $ is_vector po
+ , poName /= "tagToEnum#"
+ , poName /= "quotRemWord2#"
+ , (testable (ty po))
+ = let testPrimOpHow = if is_divLikeOp po
+ then "testPrimopDivLike"
+ else "testPrimop"
+ in Just $ intercalate " " [testPrimOpHow, "\"" ++ poName ++ "\"", wrap "Primop" poName, wrap "Wrapper" poName]
+ | otherwise = Nothing
+
+
+
+ testable (TyF t1 t2) = testable t1 && testable t2
+ testable (TyC _ t2) = testable t2
+ testable (TyApp tc tys) = testableTyCon tc && all testable tys
+ testable (TyVar _a) = False
+ testable (TyUTup tys) = all testable tys
+
+ testableTyCon (TyCon c) =
+ c `elem` ["Int#", "Word#", "Word8#", "Word16#", "Word32#", "Word64#"
+ , "Int8#", "Int16#", "Int32#", "Int64#", "Char#"]
+ testableTyCon _ = False
+ divableTyCons = ["Int#", "Word#", "Word8#", "Word16#", "Word32#", "Word64#"
+ ,"Int8#", "Int16#", "Int32#", "Int64#"]
+
------------------------------------------------------------------
-- Create PrimOpInfo text from PrimOpSpecs -----------------------
------------------------------------------------------------------
=====================================
utils/genprimopcode/Syntax.hs
=====================================
@@ -53,6 +53,19 @@ is_primtype :: Entry -> Bool
is_primtype (PrimTypeSpec {}) = True
is_primtype _ = False
+is_divLikeOp :: Entry -> Bool
+is_divLikeOp entry = case entry of
+ PrimOpSpec{} -> has_div_like
+ PseudoOpSpec{} -> has_div_like
+ PrimVecOpSpec{} -> has_div_like
+ PrimTypeSpec{} -> False
+ PrimVecTypeSpec{} -> False
+ Section{} -> False
+ where
+ has_div_like = case lookup_attrib "div_like" (opts entry) of
+ Just (OptionTrue{}) -> True
+ _ -> False
+
-- a binding of property to value
data Option
= OptionFalse String -- name = False
@@ -78,7 +91,7 @@ data Ty
| TyVar TyVar
| TyUTup [Ty] -- unboxed tuples; just a TyCon really,
-- but convenient like this
- deriving (Eq,Show)
+ deriving (Eq,Show, Ord)
type TyVar = String
type TyVarBinder = String
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/202b201c968de68f864f4c8abbfec71…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/202b201c968de68f864f4c8abbfec71…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/romes/top-level-bcos-tag] rts: Case continuation BCOs
by Rodrigo Mesquita (@alt-romes) 21 May '25
by Rodrigo Mesquita (@alt-romes) 21 May '25
21 May '25
Rodrigo Mesquita pushed to branch wip/romes/top-level-bcos-tag at Glasgow Haskell Compiler / GHC
Commits:
b9198caf by Rodrigo Mesquita at 2025-05-21T12:07:34+01:00
rts: Case continuation BCOs
TODO
- - - - -
15 changed files:
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/ByteCode/Linker.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/StgToByteCode.hs
- libraries/base/src/GHC/Exts.hs
- libraries/ghc-internal/src/GHC/Internal/Exts.hs
- libraries/ghci/GHCi/CreateBCO.hs
- libraries/ghci/GHCi/ResolvedBCO.hs
- rts/PrimOps.cmm
- rts/Printer.c
- rts/RtsSymbols.c
- rts/StgMiscClosures.cmm
- rts/include/stg/MiscClosures.h
Changes:
=====================================
compiler/GHC/Builtin/primops.txt.pp
=====================================
@@ -3872,12 +3872,13 @@ primop MkApUpd0_Op "mkApUpd0#" GenPrimOp
with
out_of_line = True
-primop NewBCOOp "newBCO#" GenPrimOp
- ByteArray# -> ByteArray# -> Array# a -> Int# -> ByteArray# -> State# s -> (# State# s, BCO #)
- { @'newBCO#' instrs lits ptrs arity bitmap@ creates a new bytecode object. The
+primop NewBCOOp "newBCO2#" GenPrimOp
+ Int8# -> ByteArray# -> ByteArray# -> Array# a -> Int# -> ByteArray# -> State# s -> (# State# s, BCO #)
+ { @'newBCO2#' is_case_cont instrs lits ptrs arity bitmap@ creates a new bytecode object. The
resulting object encodes a function of the given arity with the instructions
encoded in @instrs@, and a static reference table usage bitmap given by
- @bitmap@. }
+ @bitmap@. The @is_case_cont@ boolean indicates whether the BCO is a case
+ continuation (see Note [Case continuation BCOs]) }
with
effect = ReadWriteEffect
out_of_line = True
=====================================
compiler/GHC/ByteCode/Asm.hs
=====================================
@@ -85,7 +85,7 @@ bcoFreeNames :: UnlinkedBCO -> UniqDSet Name
bcoFreeNames bco
= bco_refs bco `uniqDSetMinusUniqSet` mkNameSet [unlinkedBCOName bco]
where
- bco_refs (UnlinkedBCO _ _ _ _ nonptrs ptrs)
+ bco_refs (UnlinkedBCO _ _ _ _ nonptrs ptrs _)
= unionManyUniqDSets (
mkUniqDSet [ n | BCOPtrName n <- elemsFlatBag ptrs ] :
mkUniqDSet [ n | BCONPtrItbl n <- elemsFlatBag nonptrs ] :
@@ -236,7 +236,8 @@ assembleBCO platform
, protoBCOInstrs = instrs
, protoBCOBitmap = bitmap
, protoBCOBitmapSize = bsize
- , protoBCOArity = arity }) = do
+ , protoBCOArity = arity
+ , protoBCOIsCaseCont = isCC }) = do
-- pass 1: collect up the offsets of the local labels.
let initial_offset = 0
@@ -266,7 +267,7 @@ assembleBCO platform
let !insns_arr = mkBCOByteArray $ final_isn_array
!bitmap_arr = mkBCOByteArray $ mkBitmapArray bsize bitmap
- ul_bco = UnlinkedBCO nm arity insns_arr bitmap_arr (fromSmallArray final_lit_array) (fromSmallArray final_ptr_array)
+ ul_bco = UnlinkedBCO nm arity insns_arr bitmap_arr (fromSmallArray final_lit_array) (fromSmallArray final_ptr_array) isCC
-- 8 Aug 01: Finalisers aren't safe when attached to non-primitive
-- objects, since they might get run too early. Disable this until
=====================================
compiler/GHC/ByteCode/Instr.hs
=====================================
@@ -53,7 +53,8 @@ data ProtoBCO a
-- what the BCO came from, for debugging only
protoBCOExpr :: Either [CgStgAlt] CgStgRhs,
-- malloc'd pointers
- protoBCOFFIs :: [FFIInfo]
+ protoBCOFFIs :: [FFIInfo],
+ protoBCOIsCaseCont :: !Bool -- See Note [Case continuation BCOs]
}
-- | A local block label (e.g. identifying a case alternative).
=====================================
compiler/GHC/ByteCode/Linker.hs
=====================================
@@ -59,7 +59,7 @@ linkBCO
-> UnlinkedBCO
-> IO ResolvedBCO
linkBCO interp pkgs_loaded le bco_ix
- (UnlinkedBCO _ arity insns bitmap lits0 ptrs0) = do
+ (UnlinkedBCO _ arity insns bitmap lits0 ptrs0 isCC) = do
-- fromIntegral Word -> Word64 should be a no op if Word is Word64
-- otherwise it will result in a cast to longlong on 32bit systems.
(lits :: [Word]) <- mapM (fmap fromIntegral . lookupLiteral interp pkgs_loaded le) (elemsFlatBag lits0)
@@ -69,7 +69,7 @@ linkBCO interp pkgs_loaded le bco_ix
insns
bitmap
(mkBCOByteArray lits')
- (addListToSS emptySS ptrs))
+ (addListToSS emptySS ptrs) isCC)
lookupLiteral :: Interp -> PkgsLoaded -> LinkerEnv -> BCONPtr -> IO Word
lookupLiteral interp pkgs_loaded le ptr = case ptr of
=====================================
compiler/GHC/ByteCode/Types.hs
=====================================
@@ -167,14 +167,28 @@ newtype ItblPtr = ItblPtr (RemotePtr Heap.StgInfoTable)
newtype AddrPtr = AddrPtr (RemotePtr ())
deriving (NFData)
+{-
+--------------------------------------------------------------------------------
+-- * Byte Code Objects (BCOs)
+--------------------------------------------------------------------------------
+
+Note [Case continuation BCOs]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Does the BCO code depend on stack-pointer-relative offsets?
+... why
+... example
+-}
+
data UnlinkedBCO
= UnlinkedBCO {
unlinkedBCOName :: !Name,
unlinkedBCOArity :: {-# UNPACK #-} !Int,
- unlinkedBCOInstrs :: !(BCOByteArray Word16), -- insns
- unlinkedBCOBitmap :: !(BCOByteArray Word), -- bitmap
+ unlinkedBCOInstrs :: !(BCOByteArray Word16), -- insns
+ unlinkedBCOBitmap :: !(BCOByteArray Word), -- bitmap
unlinkedBCOLits :: !(FlatBag BCONPtr), -- non-ptrs
- unlinkedBCOPtrs :: !(FlatBag BCOPtr) -- ptrs
+ unlinkedBCOPtrs :: !(FlatBag BCOPtr), -- ptrs
+ unlinkedBCOIsCaseCont :: !Bool -- See Note [Case continuation BCOs]
}
instance NFData UnlinkedBCO where
@@ -227,10 +241,11 @@ seqCgBreakInfo CgBreakInfo{..} =
rnf cgb_resty
instance Outputable UnlinkedBCO where
- ppr (UnlinkedBCO nm _arity _insns _bitmap lits ptrs)
+ ppr (UnlinkedBCO nm _arity _insns _bitmap lits ptrs pi)
= sep [text "BCO", ppr nm, text "with",
ppr (sizeFlatBag lits), text "lits",
- ppr (sizeFlatBag ptrs), text "ptrs" ]
+ ppr (sizeFlatBag ptrs), text "ptrs",
+ ppr pi, text "is_pos_indep"]
instance Outputable CgBreakInfo where
ppr info = text "CgBreakInfo" <+>
=====================================
compiler/GHC/StgToByteCode.hs
=====================================
@@ -253,7 +253,11 @@ mkProtoBCO
-> Int -- ^ arity
-> WordOff -- ^ bitmap size
-> [StgWord] -- ^ bitmap
- -> Bool -- ^ True <=> is a return point, rather than a function
+ -> Bool -- ^ True <=> it's a case continuation, rather than a function
+ -- Used for
+ -- (A) Stack check collision and
+ -- (B) Mark the BCO wrt whether it contains non-local stack
+ -- references. See Note [Case continuation BCOs].
-> [FFIInfo]
-> ProtoBCO Name
mkProtoBCO platform _add_bco_name nm instrs_ordlist origin arity bitmap_size bitmap is_ret ffis
@@ -264,7 +268,8 @@ mkProtoBCO platform _add_bco_name nm instrs_ordlist origin arity bitmap_size bit
protoBCOBitmapSize = fromIntegral bitmap_size,
protoBCOArity = arity,
protoBCOExpr = origin,
- protoBCOFFIs = ffis
+ protoBCOFFIs = ffis,
+ protoBCOIsCaseCont = is_ret
}
where
#if MIN_VERSION_rts(1,0,3)
@@ -353,6 +358,9 @@ schemeTopBind (id, rhs)
-- Park the resulting BCO in the monad. Also requires the
-- name of the variable to which this value was bound,
-- so as to give the resulting BCO a name.
+--
+-- The resulting ProtoBCO expects the free variables and the function arguments
+-- to be in the stack directly before it.
schemeR :: [Id] -- Free vars of the RHS, ordered as they
-- will appear in the thunk. Empty for
-- top-level things, which have no free vars.
@@ -391,6 +399,8 @@ schemeR_wrk fvs nm original_body (args, body)
-- them unlike constructor fields.
szsb_args = map (wordsToBytes platform . idSizeW platform) all_args
sum_szsb_args = sum szsb_args
+ -- Make a stack offset for each argument or free var -- they should
+ -- appear contiguous in the stack, in order.
p_init = Map.fromList (zip all_args (mkStackOffsets 0 szsb_args))
-- make the arg bitmap
@@ -1401,7 +1411,7 @@ Note [unboxed tuple bytecodes and tuple_BCO]
tupleBCO :: Platform -> NativeCallInfo -> [(PrimRep, ByteOff)] -> [FFIInfo] -> ProtoBCO Name
tupleBCO platform args_info args =
mkProtoBCO platform Nothing invented_name body_code (Left [])
- 0{-no arity-} bitmap_size bitmap False{-is alts-}
+ 0{-no arity-} bitmap_size bitmap False{-not alts-}
where
{-
The tuple BCO is never referred to by name, so we can get away
@@ -1422,7 +1432,7 @@ tupleBCO platform args_info args =
primCallBCO :: Platform -> NativeCallInfo -> [(PrimRep, ByteOff)] -> [FFIInfo] -> ProtoBCO Name
primCallBCO platform args_info args =
mkProtoBCO platform Nothing invented_name body_code (Left [])
- 0{-no arity-} bitmap_size bitmap False{-is alts-}
+ 0{-no arity-} bitmap_size bitmap False{-not alts-}
where
{-
The primcall BCO is never referred to by name, so we can get away
=====================================
libraries/base/src/GHC/Exts.hs
=====================================
@@ -26,12 +26,12 @@ module GHC.Exts
-- ** Legacy interface for arrays of arrays
module GHC.Internal.ArrayArray,
-- * Primitive operations
- {-# DEPRECATED ["The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14", "These symbols should be imported from ghc-internal instead if needed."] #-}
+ {-# DEPRECATED ["The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 10.14", "These symbols should be imported from ghc-internal instead if needed."] #-}
Prim.BCO,
{-# DEPRECATED ["The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14", "These symbols should be imported from ghc-internal instead if needed."] #-}
Prim.mkApUpd0#,
{-# DEPRECATED ["The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14", "These symbols should be imported from ghc-internal instead if needed."] #-}
- Prim.newBCO#,
+ IExts.newBCO#,
module GHC.Prim,
module GHC.Prim.Ext,
-- ** Running 'RealWorld' state thread
@@ -119,7 +119,7 @@ module GHC.Exts
maxTupleSize
) where
-import GHC.Internal.Exts
+import GHC.Internal.Exts hiding ( newBCO# )
import GHC.Internal.ArrayArray
import GHC.Prim hiding
( coerce
@@ -132,7 +132,7 @@ import GHC.Prim hiding
, isByteArrayWeaklyPinned#, isMutableByteArrayWeaklyPinned#
-- deprecated
- , BCO, mkApUpd0#, newBCO#
+ , BCO, mkApUpd0#
-- Don't re-export vector FMA instructions
, fmaddFloatX4#
@@ -256,8 +256,10 @@ import GHC.Prim hiding
, minWord8X32#
, minWord8X64#
)
+import qualified GHC.Internal.Exts as IExts
+ ( newBCO# )
import qualified GHC.Prim as Prim
- ( BCO, mkApUpd0#, newBCO# )
+ ( BCO, mkApUpd0# )
import GHC.Prim.Ext
=====================================
libraries/ghc-internal/src/GHC/Internal/Exts.hs
=====================================
@@ -163,6 +163,9 @@ module GHC.Internal.Exts
-- * The maximum tuple size
maxTupleSize,
+
+ -- * Interpreter
+ newBCO#
) where
import GHC.Internal.Prim hiding ( coerce, dataToTagSmall#, dataToTagLarge#, whereFrom# )
@@ -469,3 +472,18 @@ resizeSmallMutableArray# arr0 szNew a s0 =
-- accessible\" by word.
considerAccessible :: Bool
considerAccessible = True
+
+--------------------------------------------------------------------------------
+-- Interpreter
+
+{-|
+@'newBCO#' instrs lits ptrs arity bitmap@ creates a new bytecode object. The
+resulting object encodes a function of the given arity with the instructions
+encoded in @instrs@, and a static reference table usage bitmap given by
+@bitmap@.
+
+Note: Case continuation BCOs, with non-local stack references, must be
+constructed using @'newBCO2#' 1@ instead. See Note [Case continuation BCOs].
+-}
+newBCO# :: ByteArray# -> ByteArray# -> Array# a -> Int# -> ByteArray# -> State# s -> (# State# s, BCO #)
+newBCO# b1 b2 a1 i1 b3 s = newBCO2# (intToInt8# 0#) b1 b2 a1 i1 b3 s
=====================================
libraries/ghci/GHCi/CreateBCO.hs
=====================================
@@ -87,11 +87,11 @@ linkBCO' arr ResolvedBCO{..} = do
literals_barr = barr (getBCOByteArray resolvedBCOLits)
PtrsArr marr <- mkPtrsArray arr n_ptrs ptrs
+ let is_case_cont | resolvedBCOIsCaseCont = intToInt8# 1#
+ | otherwise = intToInt8# 0#
IO $ \s ->
case unsafeFreezeArray# marr s of { (# s, arr #) ->
- case newBCO insns_barr literals_barr arr arity# bitmap_barr of { IO io ->
- io s
- }}
+ newBCO2# is_case_cont insns_barr literals_barr arr arity# bitmap_barr s }
-- we recursively link any sub-BCOs while making the ptrs array
=====================================
libraries/ghci/GHCi/ResolvedBCO.hs
=====================================
@@ -45,7 +45,8 @@ data ResolvedBCO
resolvedBCOBitmap :: BCOByteArray Word, -- ^ bitmap
resolvedBCOLits :: BCOByteArray Word,
-- ^ non-ptrs - subword sized entries still take up a full (host) word
- resolvedBCOPtrs :: (SizedSeq ResolvedBCOPtr) -- ^ ptrs
+ resolvedBCOPtrs :: (SizedSeq ResolvedBCOPtr), -- ^ ptrs
+ resolvedBCOIsCaseCont :: !Bool -- ^ See Note [Case continuation BCOs]
}
deriving (Generic, Show)
@@ -86,7 +87,8 @@ instance Binary ResolvedBCO where
put resolvedBCOBitmap
put resolvedBCOLits
put resolvedBCOPtrs
- get = ResolvedBCO <$> get <*> get <*> get <*> get <*> get <*> get
+ put resolvedBCOIsCaseCont
+ get = ResolvedBCO <$> get <*> get <*> get <*> get <*> get <*> get <*> get
-- See Note [BCOByteArray serialization]
instance (Binary a, Storable a, IArray UArray a) => Binary (BCOByteArray a) where
=====================================
rts/PrimOps.cmm
=====================================
@@ -55,6 +55,7 @@ import CLOSURE stg_AP_STACK_info;
import CLOSURE stg_AP_info;
import CLOSURE stg_ARR_WORDS_info;
import CLOSURE stg_BCO_info;
+import CLOSURE stg_CASE_CONT_BCO_info;
import CLOSURE stg_C_FINALIZER_LIST_info;
import CLOSURE stg_DEAD_WEAK_info;
import CLOSURE stg_END_STM_WATCH_QUEUE_closure;
@@ -2434,7 +2435,8 @@ stg_deRefStablePtrzh ( P_ sp )
Bytecode object primitives
------------------------------------------------------------------------- */
-stg_newBCOzh ( P_ instrs,
+stg_newBCO2zh ( CBool is_case_cont,
+ P_ instrs,
P_ literals,
P_ ptrs,
W_ arity,
@@ -2449,7 +2451,16 @@ stg_newBCOzh ( P_ instrs,
bco = Hp - bytes + WDS(1);
// No memory barrier necessary as this is a new allocation.
- SET_HDR(bco, stg_BCO_info, CCS_MAIN);
+ if (is_case_cont > 0) {
+ /* Uses stg_CASE_CONT_BCO_info to construct the BCO frame (rather than stg_BCO_info).
+ * Case continuations may contain non-local references to parent frames. The distinct info table
+ * tag allows the RTS to identify such non-local frames.
+ * See Note [Case continuation BCOs]
+ */
+ SET_HDR(bco, stg_CASE_CONT_BCO_info, CCS_MAIN);
+ } else {
+ SET_HDR(bco, stg_BCO_info, CCS_MAIN);
+ }
StgBCO_instrs(bco) = instrs;
StgBCO_literals(bco) = literals;
=====================================
rts/Printer.c
=====================================
@@ -690,6 +690,8 @@ printStackChunk( StgPtr sp, StgPtr spBottom )
debugBelch("stg_ctoi_V_info" );
} else if (c == (StgWord)&stg_BCO_info) {
debugBelch("stg_BCO_info" );
+ } else if (c == (StgWord)&stg_CASE_CONT_BCO_info) {
+ debugBelch("stg_CASE_CONT_BCO_info" );
} else if (c == (StgWord)&stg_apply_interp_info) {
debugBelch("stg_apply_interp_info" );
} else if (c == (StgWord)&stg_ret_t_info) {
=====================================
rts/RtsSymbols.c
=====================================
@@ -639,7 +639,7 @@ extern char **environ;
SymI_HasDataProto(stg_copySmallMutableArrayzh) \
SymI_HasDataProto(stg_casSmallArrayzh) \
SymI_HasDataProto(stg_copyArray_barrier) \
- SymI_HasDataProto(stg_newBCOzh) \
+ SymI_HasDataProto(stg_newBCO2zh) \
SymI_HasDataProto(stg_newByteArrayzh) \
SymI_HasDataProto(stg_casIntArrayzh) \
SymI_HasDataProto(stg_casInt8Arrayzh) \
=====================================
rts/StgMiscClosures.cmm
=====================================
@@ -464,6 +464,11 @@ INFO_TABLE_RET( stg_dead_thread, RET_SMALL,
/* ----------------------------------------------------------------------------
Entry code for a BCO
+
+ `stg_BCO` and `stg_CASE_CONT_BCO` distinguish between a BCO that refers to
+ non-local variables in its code (using a stack offset) and those that do not.
+ Only case-continuation BCOs should use non-local variables.
+ Otherwise, `stg_BCO` and `stg_CASE_CONT_BCO` behave the same.
------------------------------------------------------------------------- */
INFO_TABLE_FUN( stg_BCO, 3, 0, BCO, "BCO", "BCO", 0, ARG_BCO )
@@ -478,6 +483,15 @@ INFO_TABLE_FUN( stg_BCO, 3, 0, BCO, "BCO", "BCO", 0, ARG_BCO )
jump stg_yield_to_interpreter [];
}
+INFO_TABLE_FUN( stg_CASE_CONT_BCO, 3, 0, BCO, "BCO", "BCO", 0, ARG_BCO )
+{
+ /* Exactly as for stg_BCO */
+ Sp_adj(-2);
+ Sp(1) = R1;
+ Sp(0) = stg_apply_interp_info;
+ jump stg_yield_to_interpreter [];
+}
+
/* ----------------------------------------------------------------------------
Info tables for indirections.
=====================================
rts/include/stg/MiscClosures.h
=====================================
@@ -180,6 +180,7 @@ RTS_ENTRY(stg_BLOCKING_QUEUE_CLEAN);
RTS_ENTRY(stg_BLOCKING_QUEUE_DIRTY);
RTS_FUN(stg_BCO);
+RTS_FUN(stg_CASE_CONT_BCO);
RTS_ENTRY(stg_EVACUATED);
RTS_ENTRY(stg_WEAK);
RTS_ENTRY(stg_DEAD_WEAK);
@@ -577,7 +578,7 @@ RTS_FUN_DECL(stg_deRefWeakzh);
RTS_FUN_DECL(stg_runRWzh);
-RTS_FUN_DECL(stg_newBCOzh);
+RTS_FUN_DECL(stg_newBCO2zh);
RTS_FUN_DECL(stg_mkApUpd0zh);
RTS_FUN_DECL(stg_retryzh);
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/b9198caf9e1955e255325de5c541406…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/b9198caf9e1955e255325de5c541406…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/fendor/ghci-multiple-home-units] 2 commits: Add testcases for GHCi multiple home units
by Hannes Siebenhandl (@fendor) 21 May '25
by Hannes Siebenhandl (@fendor) 21 May '25
21 May '25
Hannes Siebenhandl pushed to branch wip/fendor/ghci-multiple-home-units at Glasgow Haskell Compiler / GHC
Commits:
f367ed48 by fendor at 2025-05-21T13:03:26+02:00
Add testcases for GHCi multiple home units
Adds the following testcases:
* Evaluate code with a single home unit using 'initMulti' initialisation
logic
* More complicated testcase with multiple home units, testing reload
logic and code evaluation.
- - - - -
c5e86adc by fendor at 2025-05-21T13:03:27+02:00
Make GHCi commands compatible with multiple home units
=== Design
We enable all GHCi features that were previously guarded by the `inMulti`
option.
GHCi supported multiple home units up to a certain degree for quite a while now.
The supported feature set was limited, due to a design impasse:
One of the home units must be "active", e.g., there must be one `HomeUnit`
whose `UnitId` is "active" which is returned when calling
```haskell
do
hscActiveUnitId <$> getSession
```
This makes sense in a GHC session, since you are always compiling a particular
Module, but it makes less intuitive sense in an interactive session.
Given an expression to evaluate, we can't easily tell in which "context" the expression
should be parsed, typechecked and evaluated.
That`s why initially, most of GHCi features, except for `:reload`ing were disabled
if the GHCi session had more than one `HomeUnitEnv`.
We lift this restriction, enabling all features of GHCi for the multiple home unit case.
To do this, we fundamentally change the `HomeUnitEnv` graph to be multiple home unit first.
Instead of differentiating the case were we have a single home unit and multiple,
we now always set up a multiple home unit session that scales seamlessly to an arbitrary
amount of home units.
We introduce two new `HomeUnitEnv`s that are always added to the `HomeUnitGraph`.
They are:
The "interactive-ghci", called the `interactiveGhciUnit`, contains the same
`DynFlags` that are used by the `InteractiveContext` for interactive evaluation
of expressions.
This `HomeUnitEnv` is only used on the prompt of GHCi, so we may refer to it as
"interactive-prompt" unit.
See Note [Relation between the `InteractiveContext` and `interactiveGhciUnitId`]
for discussing its role.
And the `interactive-session`, called `interactiveSessionUnit` or
`interactiveSessionUnitId`, which is used for loading Scripts into
GHCi that are not `Target`s of any home unit, via `:load` or `:add`.
Both of these "interactive" home units depend on all other `HomeUnitEnv`s that
are passed as arguments on the cli.
Additionally, the "interactive-ghci" unit depends on `interactive-session`.
We always evaluate expressions in the context of the
"interactive-ghci" session.
Since "interactive-ghci" depends on all home units, we can import any `Module`
from the other home units with ease.
As we have a clear `HomeUnitGraph` hierarchy, we can set `interactiveGhciUnitId`
as the active home unit for the full duration of the GHCi session.
In GHCi, we always set `interactiveGhciUnitId` to be the currently active home unit.
=== Implementation Details
Given this design idea, the implementation is relatively straight
forward.
The core insight is that a `ModuleName` is not sufficient to identify a
`Module` in the `HomeUnitGraph`. Thus, large parts of the PR is simply
about refactoring usages of `ModuleName` to prefer `Module`, which has a
`Unit` attached and is unique over the `HomeUnitGraph`.
Consequentially, most usages of `lookupHPT` are likely to be incorrect and have
been replaced by `lookupHugByModule` which is keyed by a `Module`.
In `GHCi/UI.hs`, we make sure there is only one location where we are
actually translating `ModuleName` to a `Module`:
* `lookupQualifiedModuleName`
If a `ModuleName` is ambiguous, we detect this and report it to the
user.
To avoid repeated lookups of `ModuleName`s, we store the `Module` in the
`InteractiveImport`, which additionally simplifies the interface
loading.
A subtle detail is that the `DynFlags` of the `InteractiveContext` are
now stored both in the `HomeUnitGraph` and in the `InteractiveContext`.
In UI.hs, there are multiple code paths where we are careful to update
the `DynFlags` in both locations.
Most importantly in `addToProgramDynFlags`.
---
There is one metric increase in this commit:
-------------------------
Metric Increase:
T4029
-------------------------
It is an increase from 14.4 MB to 16.1 MB (+11.8%) which sounds like a
pretty big regression at first.
However, we argue this increase is solely caused by using more data
structures for managing multiple home units in the GHCi session.
In particular, due to the design decision of using three home units, the
base memory usage increases... but by how much?
A big contributor is the `UnitState`, of which we have three now, which
on its own 260 KB per instance. That makes an additional memory usage of
520 KB, already explaining a third of the overall memory usage increase.
Then we store more elements in the `HomeUnitGraph`, we have more
`HomeUnitEnv` entries, etc...
While we didn't chase down each byte, we looked at the memory usage over time
for both `-hi` and `-hT` profiles and can say with confidence while the memory
usage increased slightly, we did not introduce any space leak, as
the graph looks almost identical as the memory usage graph of GHC HEAD.
- - - - -
131 changed files:
- compiler/GHC.hs
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Iface/Load.hs
- compiler/GHC/Rename/Unbound.hs
- compiler/GHC/Runtime/Context.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/StgToByteCode.hs
- compiler/GHC/StgToJS/Linker/Linker.hs
- compiler/GHC/Tc/Module.hs
- compiler/GHC/Types/Name/Ppr.hs
- compiler/GHC/Unit/Env.hs
- compiler/GHC/Unit/Home/Graph.hs
- compiler/GHC/Unit/Types.hs
- ghc/GHCi/UI.hs
- ghc/GHCi/UI/Exception.hs
- ghc/GHCi/UI/Info.hs
- ghc/GHCi/UI/Monad.hs
- ghc/Main.hs
- testsuite/driver/testlib.py
- testsuite/tests/driver/T8526/T8526.stdout
- testsuite/tests/driver/fat-iface/fat014.stdout
- testsuite/tests/driver/multipleHomeUnits/multiGHCi.stderr
- testsuite/tests/ghc-api/T6145.hs
- testsuite/tests/ghc-api/annotations-literals/literals.hs
- testsuite/tests/ghc-api/annotations-literals/parsed.hs
- testsuite/tests/ghc-api/apirecomp001/myghc.hs
- testsuite/tests/ghc-api/fixed-nodes/T1.hs
- + testsuite/tests/ghci.debugger/scripts/break031/Makefile
- + testsuite/tests/ghci.debugger/scripts/break031/a/A.hs
- + testsuite/tests/ghci.debugger/scripts/break031/all.T
- + testsuite/tests/ghci.debugger/scripts/break031/b/B.hs
- + testsuite/tests/ghci.debugger/scripts/break031/break031a.script
- + testsuite/tests/ghci.debugger/scripts/break031/break031a.stdout
- + testsuite/tests/ghci.debugger/scripts/break031/break031b.script
- + testsuite/tests/ghci.debugger/scripts/break031/break031b.stderr
- + testsuite/tests/ghci.debugger/scripts/break031/break031b.stdout
- + testsuite/tests/ghci.debugger/scripts/break031/unitA
- + testsuite/tests/ghci.debugger/scripts/break031/unitB
- testsuite/tests/ghci/linking/dyn/T3372.hs
- + testsuite/tests/ghci/prog-mhu001/Makefile
- + testsuite/tests/ghci/prog-mhu001/all.T
- + testsuite/tests/ghci/prog-mhu001/e/E.hs
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001a.script
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001a.stdout
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001b.script
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001b.stdout
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001c.script
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001c.stdout
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001d.script
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001d.stdout
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001e.script
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001e.stdout
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001f.script
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001f.stdout
- + testsuite/tests/ghci/prog-mhu001/unitE
- + testsuite/tests/ghci/prog-mhu001/unitE-main-is
- + testsuite/tests/ghci/prog-mhu002/Makefile
- + testsuite/tests/ghci/prog-mhu002/a/A.hs
- + testsuite/tests/ghci/prog-mhu002/all.T
- + testsuite/tests/ghci/prog-mhu002/b/B.hs
- + testsuite/tests/ghci/prog-mhu002/c/C.hs
- + testsuite/tests/ghci/prog-mhu002/d/Main.hs
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002a.script
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002a.stderr
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002a.stdout
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002b.script
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002b.stderr
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002b.stdout
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002c.script
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002c.stdout
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002d.script
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002d.stdout
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002e.script
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002e.stdout
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002f.script
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002f.stdout
- + testsuite/tests/ghci/prog-mhu002/unitA
- + testsuite/tests/ghci/prog-mhu002/unitB
- + testsuite/tests/ghci/prog-mhu002/unitC
- + testsuite/tests/ghci/prog-mhu002/unitD
- + testsuite/tests/ghci/prog-mhu003/Makefile
- + testsuite/tests/ghci/prog-mhu003/a/A.hs
- + testsuite/tests/ghci/prog-mhu003/all.T
- + testsuite/tests/ghci/prog-mhu003/b/Foo.hs
- + testsuite/tests/ghci/prog-mhu003/c/C.hs
- + testsuite/tests/ghci/prog-mhu003/d/Foo.hs
- + testsuite/tests/ghci/prog-mhu003/prog-mhu003.script
- + testsuite/tests/ghci/prog-mhu003/prog-mhu003.stderr
- + testsuite/tests/ghci/prog-mhu003/prog-mhu003.stdout
- + testsuite/tests/ghci/prog-mhu003/unitA
- + testsuite/tests/ghci/prog-mhu003/unitB
- + testsuite/tests/ghci/prog-mhu003/unitC
- + testsuite/tests/ghci/prog-mhu003/unitD
- + testsuite/tests/ghci/prog-mhu004/Makefile
- + testsuite/tests/ghci/prog-mhu004/a/Foo.hs
- + testsuite/tests/ghci/prog-mhu004/all.T
- + testsuite/tests/ghci/prog-mhu004/b/Foo.hs
- + testsuite/tests/ghci/prog-mhu004/prog-mhu004a.script
- + testsuite/tests/ghci/prog-mhu004/prog-mhu004a.stderr
- + testsuite/tests/ghci/prog-mhu004/prog-mhu004a.stdout
- + testsuite/tests/ghci/prog-mhu004/prog-mhu004b.script
- + testsuite/tests/ghci/prog-mhu004/prog-mhu004b.stdout
- + testsuite/tests/ghci/prog-mhu004/unitA
- + testsuite/tests/ghci/prog-mhu004/unitB
- testsuite/tests/ghci/prog010/ghci.prog010.script
- testsuite/tests/ghci/prog018/prog018.stdout
- + testsuite/tests/ghci/prog020/A.hs
- + testsuite/tests/ghci/prog020/B.hs
- + testsuite/tests/ghci/prog020/Makefile
- + testsuite/tests/ghci/prog020/all.T
- + testsuite/tests/ghci/prog020/ghci.prog020.script
- + testsuite/tests/ghci/prog020/ghci.prog020.stderr
- + testsuite/tests/ghci/prog020/ghci.prog020.stdout
- testsuite/tests/ghci/scripts/T13869.stdout
- testsuite/tests/ghci/scripts/T13997.stdout
- testsuite/tests/ghci/scripts/T17669.stdout
- testsuite/tests/ghci/scripts/T18330.stdout
- testsuite/tests/ghci/scripts/T1914.stdout
- testsuite/tests/ghci/scripts/T20217.stdout
- testsuite/tests/ghci/scripts/T20587.stdout
- testsuite/tests/ghci/scripts/T21110.stderr
- testsuite/tests/ghci/scripts/T6105.stdout
- testsuite/tests/ghci/scripts/T8042.stdout
- testsuite/tests/ghci/scripts/T8042recomp.stdout
- testsuite/tests/ghci/scripts/ghci024.stdout
- testsuite/tests/ghci/scripts/ghci024.stdout-mingw32
- testsuite/tests/ghci/scripts/ghci058.script
- testsuite/tests/ghci/should_run/TopEnvIface.stdout
- testsuite/tests/linters/notes.stdout
- testsuite/tests/quasiquotation/T7918.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/b3fce6ff0835cdbd1bb3d4e71f139a…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/b3fce6ff0835cdbd1bb3d4e71f139a…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/fendor/ghci-multiple-home-units] 44 commits: Support for ARM64 Windows (LLVM-enabled) (fixes #24603)
by Hannes Siebenhandl (@fendor) 21 May '25
by Hannes Siebenhandl (@fendor) 21 May '25
21 May '25
Hannes Siebenhandl pushed to branch wip/fendor/ghci-multiple-home-units at Glasgow Haskell Compiler / GHC
Commits:
9995c2b7 by Serge S. Gulin at 2025-05-04T17:13:36+03:00
Support for ARM64 Windows (LLVM-enabled) (fixes #24603)
1. Add Windows AArch64 cross-compilation support via CI jobs
Introduce new CI configurations for cross-compiling to Windows ARM64 using Debian12Wine, FEX, and MSYS2.
Configure toolchain variables for LLVM MinGW and Wine emulation in CI pipelines.
2. Adjust compiler and RTS for AArch64 Windows compatibility
Reserve register `x18` on Windows and Darwin platforms in AArch64 codegen.
Handle Windows-specific relocations and data sections in AArch64 assembler.
Update PEi386 linker to recognize ARM64 binaries and support exception handling.
Adjust LLVM target definitions and data layouts for new architectures.
Update `ghc-toolchain` and build scripts to handle `TablesNextToCode` on Windows ARM64.
3. Enhance CI scripts and stability
Modify `ci.sh` to handle mingw cross-targets, fixing GHC executable paths and test execution.
Use `diff -w` in tests to ignore whitespace differences, improving cross-platform consistency.
4. Refactor and clean up code
Remove redundant imports in hello.hs test.
Improve error messages and checks for unsupported configurations in the driver.
Add `EXDEV` error code to `errno.js`.
Add async/sync flags to IO logs at `base.js`.
Improve POSIX compatibility for file close at `base.js`: decrease indeterminism for mixed cases of async and sync code.
5. Update dependencies: `Cabal`, `Win32`, `directory`, `process`, `haskeline`, and `unix`.
submodule
Co-authored-by: Cheng Shao <terrorjack(a)type.dance>
Co-authored-by: Dmitrii Egorov <egorov.d.i(a)icloud.com>
Co-authored-by: Andrei Borzenkov <root(a)sandwitch.dev>
- - - - -
50fa8165 by Javran Cheng at 2025-05-05T05:55:39-04:00
Suppress unused do-binding if discarded variable is Any or ZonkAny.
Consider example (#25895):
> do { forever (return ()); blah }
where `forever :: forall a b. IO a -> IO b`.
Nothing constrains `b`, so it will be instantiates with `Any` or
`ZonkAny`.
But we certainly don't want to complain about a discarded do-binding.
Fixes #25895
- - - - -
e46c6b18 by Rodrigo Mesquita at 2025-05-06T09:01:57-04:00
Refactor mkTopLevImportedEnv out of mkTopLevEnv
This makes the code clearer and allows the top-level import context to
be fetched directly from the HomeModInfo through the API (e.g. useful
for the debugger).
- - - - -
0ce0d263 by Rodrigo Mesquita at 2025-05-06T09:01:57-04:00
Export sizeOccEnv from GHC.Types.Name.Occurrence
Counts the number of OccNames in an OccEnv
- - - - -
165f98d8 by Simon Peyton Jones at 2025-05-06T09:02:39-04:00
Fix a bad untouchability bug im simplifyInfer
This patch addresses #26004. The root cause was that simplifyInfer
was willing to unify variables "far out". The fix, in
runTcSWithEvBinds', is to initialise the inert set given-eq level with
the current level. See
(TGE6) in Note [Tracking Given equalities]
in GHC.Tc.Solver.InertSet
Two loosely related refactors:
* Refactored approximateWCX to return just the free type
variables of the un-quantified constraints. That avoids duplication
of work (these free vars are needed in simplifyInfer) and makes it
clearer that the constraints themselves are irrelevant.
* A little local refactor of TcSMode, which reduces the number of
parameters to runTcSWithEvBinds
- - - - -
6e67fa08 by Ben Gamari at 2025-05-08T06:21:21-04:00
llvmGen: Fix built-in variable predicate
Previously the predicate to identify LLVM builtin global variables was
checking for `$llvm` rather than `@llvm` as it should.
- - - - -
a9d0a22c by Ben Gamari at 2025-05-08T06:21:22-04:00
llvmGen: Fix linkage of built-in arrays
LLVM now insists that built-in arrays use Appending linkage, not
Internal.
Fixes #25769.
- - - - -
9c6d2b1b by sheaf at 2025-05-08T06:22:11-04:00
Use mkTrAppChecked in ds_ev_typeable
This change avoids violating the invariant of mkTrApp according to which
the argument should not be a fully saturated function type.
This ensures we don't return false negatives for type equality
involving function types.
Fixes #25998
- - - - -
75cadf81 by Ryan Hendrickson at 2025-05-08T06:22:55-04:00
haddock: Preserve indentation in multiline examples
Intended for use with :{ :}, but doesn't look for those characters. Any
consecutive lines with birdtracks will only have initial whitespace
stripped up to the column of the first line.
- - - - -
fee9b351 by Cheng Shao at 2025-05-08T06:23:36-04:00
ci: re-enable chrome for wasm ghci browser tests
Currently only firefox is enabled for wasm ghci browser tests, for
some reason testing with chrome works on my machine but gets stuck on
gitlab instance runners. This patch re-enables testing with chrome by
passing `--no-sandbox`, since chrome sandboxing doesn't work in
containers without `--cap-add=SYS_ADMIN`.
- - - - -
282df905 by Vladislav Zavialov at 2025-05-09T03:18:25-04:00
Take subordinate 'type' specifiers into account
This patch fixes multiple bugs (#22581, #25983, #25984, #25991)
in name resolution of subordinate import lists.
Bug #22581
----------
In subordinate import lists, the use of the `type` namespace specifier
used to be ignored. For example, this import statement was incorrectly
accepted:
import Prelude (Bool(type True))
Now it results in an error message:
<interactive>:2:17: error: [GHC-51433]
In the import of ‘Prelude’:
a data type called ‘Bool’ is exported,
but its subordinate item ‘True’ is not in the type namespace.
Bug #25983
----------
In subordinate import lists within a `hiding` clause, non-existent
items led to a poor warning message with -Wdodgy-imports. Consider:
import Prelude hiding (Bool(X))
The warning message for this import statement used to misreport the
cause of the problem:
<interactive>:3:24: warning: [GHC-56449] [-Wdodgy-imports]
In the import of ‘Prelude’:
an item called ‘Bool’ is exported, but it is a type.
Now the warning message is correct:
<interactive>:2:24: warning: [GHC-10237] [-Wdodgy-imports]
In the import of ‘Prelude’:
a data type called ‘Bool’ is exported, but it does not export
any constructors or record fields called ‘X’.
Bug #25984
----------
In subordinate import lists within a `hiding` clause, non-existent
items resulted in the entire import declaration being discarded.
For example, this program was incorrectly accepted:
import Prelude hiding (Bool(True,X))
t = True
Now it results in an error message:
<interactive>:2:5: error: [GHC-88464]
Data constructor not in scope: True
Bug #25991
----------
In subordinate import lists, it was not possible to refer to a class
method if there was an associated type of the same name:
module M_helper where
class C a b where
type a # b
(#) :: a -> b -> ()
module M where
import M_helper (C((#)))
This import declaration failed with:
M.hs:2:28: error: [GHC-10237]
In the import of ‘M_helper’:
an item called ‘C’ is exported, but it does not export any children
(constructors, class methods or field names) called ‘#’.
Now it is accepted.
Summary
-------
The changes required to fix these bugs are almost entirely confined to
GHC.Rename.Names. Other than that, there is a new error constructor
BadImportNonTypeSubordinates with error code [GHC-51433].
Test cases:
T22581a T22581b T22581c T22581d
T25983a T25983b T25983c T25983d T25983e T25983f T25983g
T25984a T25984b
T25991a T25991b1 T25991b2
- - - - -
51b0ce8f by Simon Peyton Jones at 2025-05-09T03:19:07-04:00
Slighty improve `dropMisleading`
Fix #26105, by upgrading the (horrible, hacky) `dropMisleading`
function.
This fix makes things a bit better but does not cure the underlying
problem.
- - - - -
7b2d1e6d by Simon Peyton Jones at 2025-05-11T03:24:47-04:00
Refine `noGivenNewtypeReprEqs` to account for quantified constraints
This little MR fixes #26020. We are on the edge of completeness
for newtype equalities (that doesn't change) but this MR makes GHC
a bit more consistent -- and fixes the bug reported.
- - - - -
eaa8093b by Cheng Shao at 2025-05-11T03:25:28-04:00
wasm: mark freeJSVal as INLINE
This patch marks `freeJSVal` as `INLINE` for the wasm backend. I
noticed that the `freeJSVal` invocations are not inlined when
inspecting STG/Cmm dumps of downstream libraries that use release
build of the wasm backend. The performance benefit of inlining here is
very modest, but so is the cost anyway; if you are using `freeJSVal`
at all then you care about every potential chance to improve
performance :)
- - - - -
eac196df by Cheng Shao at 2025-05-11T03:25:28-04:00
wasm: add zero length fast path for fromJSString
This patch adds a zero length fast path for `fromJSString`; when
marshaling a zero-length `JSString` we don't need to allocate an empty
`ByteArray#` at all.
- - - - -
652cba7e by Peng Fan at 2025-05-14T04:24:35-04:00
Add LoongArch NCG support
Not supported before.
- - - - -
c01f4374 by Lin Runze at 2025-05-14T04:24:35-04:00
ci: Add LoongArch64 cross-compile CI for testing
- - - - -
ce6cf240 by Ben Gamari at 2025-05-14T04:25:18-04:00
rts/linker: Don't fail due to RTLD_NOW
In !12264 we started using the NativeObj machinery introduced some time
ago for loading of shared objects. One of the side-effects of this
change is shared objects are now loaded eagerly (i.e. with `RTLD_NOW`).
This is needed by NativeObj to ensure full visibility of the mappings of
the loaded object, which is in turn needed for safe shared object
unloading.
Unfortunately, this change subtly regressed, causing compilation
failures in some programs. Specifically, shared objects which refer to
undefined symbols (e.g. which may be usually provided by either the
executable image or libraries loaded via `dlopen`) will fail to load
with eager binding. This is problematic as GHC loads all package
dependencies while, e.g., evaluating TemplateHaskell splices. This
results in compilation failures in programs depending upon (but not
using at compile-time) packages with undefined symbol references.
To mitigate this NativeObj now first attempts to load an object via
eager binding, reverting to lazy binding (and disabling unloading) on
failure.
See Note [Don't fail due to RTLD_NOW].
Fixes #25943.
- - - - -
88ee8bb5 by Sylvain Henry at 2025-05-14T04:26:15-04:00
Deprecate GHC.JS.Prim.Internal.Build (#23432)
Deprecated as per CLC proposal 329 (https://github.com/haskell/core-libraries-committee/issues/329)
- - - - -
b4ed465b by Cheng Shao at 2025-05-14T04:26:57-04:00
libffi: update to 3.4.8
Bumps libffi submodule.
- - - - -
a3e71296 by Matthew Pickering at 2025-05-14T04:27:38-04:00
Remove leftover trace
- - - - -
2d0ecdc6 by Cheng Shao at 2025-05-14T04:28:19-04:00
Revert "ci: re-enable chrome for wasm ghci browser tests"
This reverts commit fee9b351fa5a35d5778d1252789eacaaf5663ae8.
Unfortunately the chrome test jobs may still timeout on certain
runners (e.g. OpenCape) for unknown reasons.
- - - - -
3b3a5dec by Ben Gamari at 2025-05-15T16:10:01-04:00
Don't emit unprintable characters when printing Uniques
When faced with an unprintable tag we now instead print the codepoint
number.
Fixes #25989.
(cherry picked from commit e832b1fadee66e8d6dd7b019368974756f8f8c46)
- - - - -
e1ef8974 by Mike Pilgrem at 2025-05-16T16:09:14-04:00
Translate iff in Haddock documentation into everyday English
- - - - -
fd64667d by Vladislav Zavialov at 2025-05-20T03:25:08-04:00
Allow the 'data' keyword in import/export lists (#25899)
This patch introduces the 'data' namespace specifier in import and
export lists. The intended use is to import data constructors without
their parent type constructors, e.g.
import Data.Proxy as D (data Proxy)
type DP = D.Proxy -- promoted data constructor
Additionally, it is possible to use 'data' to explicitly qualify any
data constructors or terms, incl. operators and field selectors
import Prelude (Semigroup(data (<>)))
import Data.Function (data (&))
import Data.Monoid (data Dual, data getDual)
x = Dual "Hello" <> Dual "World" & getDual
The implementation mostly builds on top of the existing logic for the
'type' and 'pattern' namespace specifiers, plus there are a few tweaks
to how we generate suggestions in error messages.
- - - - -
acc86753 by Ben Gamari at 2025-05-20T03:25:51-04:00
compiler: Use field selectors when creating BCOs
This makes it easier to grep for these fields.
- - - - -
60a55fd7 by Ben Gamari at 2025-05-20T03:25:51-04:00
compiler: Clarify BCO size
Previously the semantics and size of StgBCO was a bit unclear.
Specifically, the `size` field was documented to contain the size of the
bitmap whereas it was actually the size of the closure *and* bitmap.
Additionally, it was not as clear as it could be that the bitmap was a
full StgLargeBitmap with its own `size` field.
- - - - -
ac9fb269 by Simon Peyton Jones at 2025-05-20T09:19:04-04:00
Track rewriter sets more accurately in constraint solving
This MR addresses #26003, by refactoring the arcane
intricacies of Note [Equalities with incompatible kinds].
NB: now retitled to
Note [Equalities with heterogeneous kinds].
and the main Note for this MR.
In particular:
* Abandon invariant (COERCION-HOLE) in Note [Unification preconditions] in
GHC.Tc.Utils.Unify.
* Abandon invariant (TyEq:CH)) in Note [Canonical equalities] in
GHC.Tc.Types.Constraint.
* Instead: add invariant (REWRITERS) to Note [Unification preconditions]:
unify only if the constraint has an empty rewriter set.
Implementation:
* In canEqCanLHSFinish_try_unification, skip trying unification if there is a
non-empty rewriter set.
* To do this, make sure the rewriter set is zonked; do so in selectNextWorkItem,
which also deals with prioritisation.
* When a coercion hole is filled, kick out inert equalities that have that hole
as a rewriter. It might now be unlocked and available to unify.
* Remove the ad-hoc `ch_hetero_kind` field of `CoercionHole`.
* In `selectNextWorkItem`, priorities equalities withan empty rewriter set.
* Defaulting: see (DE6) in Note [Defaulting equalities]
and Note [Limited defaulting in the ambiguity check]
* Concreteness checks: there is some extra faff to try to get decent
error messages when the FRR (representation-polymorphism) checks
fail. In partiular, add a "When unifying..." explanation when the
representation-polymorphism check arose from another constraint.
- - - - -
86406f48 by Cheng Shao at 2025-05-20T09:19:47-04:00
rts: fix rts_clearMemory logic when sanity checks are enabled
This commit fixes an RTS assertion failure when invoking
rts_clearMemory with +RTS -DS. -DS implies -DZ which asserts that free
blocks contain 0xaa as the designated garbage value. Also adds the
sanity way to rts_clearMemory test to prevent future regression.
Closes #26011.
ChatGPT Codex automatically diagnosed the issue and proposed the
initial patch in a single shot, given a GHC checkout and the following
prompt:
---
Someone is reporting the following error when attempting to use `rts_clearMemory` with the RTS option `-DS`:
```
test.wasm: internal error: ASSERTION FAILED: file rts/sm/Storage.c, line 1216
(GHC version 9.12.2.20250327 for wasm32_unknown_wasi)
Please report this as a GHC bug: https://www.haskell.org/ghc/reportabug
```
What's the culprit? How do I look into this issue?
---
I manually reviewed & revised the patch, tested and submitted it.
- - - - -
7147370b by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: do not allocate strings in bytecode assembler
This patch refactors the compiler to avoid allocating iserv buffers
for BCONPtrStr at assemble-time. Now BCONPtrStr ByteStrings are
recorded as a part of CompiledByteCode, and actual allocation only
happens at link-time. This refactoring is necessary for adding
bytecode serialization functionality, as explained by the revised
comments in this commit.
- - - - -
a67db612 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: make bc_strs serializable
This commit makes the bc_strs field in CompiledByteCode serializable;
similar to previous commit, we preserve the ByteString directly and
defer the actual allocation to link-time, as mentioned in updated
comment.
- - - - -
5faf34ef by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: make bc_itbls serializable
This commit makes bc_itbls in CompiledByteCode serializable. A
dedicated ConInfoTable datatype has been added in ghci which is the
recipe for dynamically making a datacon's info table, containing the
payload of the MkConInfoTable iserv message.
- - - - -
2abaf8c1 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: remove FFIInfo bookkeeping in BCO
This commit removes the bc_ffis field from CompiledByteCode
completely, as well as all the related bookkeeping logic in
GHC.StgToByteCode. bc_ffis is actually *unused* in the rest of GHC
codebase! It is merely a list of FFIInfo, which is just a remote
pointer of the libffi ffi_cif struct; once we allocate the ffi_cif
struct and put its pointer in a CCALL instruction, we'll never free it
anyway. So there is no point of bookkeeping.
- - - - -
adb9e4d2 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: make FFIInfo serializable in BCO
This commit makes all the FFIInfo needed in CCALL instructions
serializable. Previously, when doing STG to BCO lowering, we would
allocate a libffi ffi_cif struct and keep its remote pointer as
FFIInfo; but actually we can just keep the type signature as FFIInfo
and defer the actual allocation to link-time.
- - - - -
200f401b by Cheng Shao at 2025-05-20T17:22:19-04:00
ghci: remove redundant NewBreakModule message
This commit removes the redundant NewBreakModule message from ghci: it
just allocates two strings! This functionality can be implemented with
existing MallocStrings in one iserv call.
- - - - -
ddaadca6 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: make breakpoint module name and unit id serializable
This commit makes breakpoint module name and unit id serializable, in
BRK_FUN instructions as well as ModBreaks. We can simply keep the
module name and unit ids, and defer the buffer allocation to link
time.
- - - - -
a0fde202 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: remove unused newModule
This commit removes the now unused newModule function from GHC.
- - - - -
68c8f140 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: add BCONPtrFS for interned top level string literals in BCO
This commit adds BCONPtrFS as a BCO non-pointer literal kind, which
has the same semantics of BCONPtrStr, except it contains a FastString
instead of a ByteString. By using BCONPtrFS to represent top level
string literals that are already FastString in the compilation
pipeline, we enjoy the FastString interning logic and avoid allocating
a bunch of redundant ByteStrings for the same FastStrings, especially
when we lower the BRK_FUN instruction.
- - - - -
f2b532bc by Peng Fan at 2025-05-20T17:23:15-04:00
hadrian: enable GHCi for loongarch64
- - - - -
8ded2330 by kwxm at 2025-05-20T17:24:07-04:00
Fix bugs in `integerRecipMod` and `integerPowMod`
This fixes #26017.
* `integerRecipMod x 1` now returns `(# 1 | #)` for all x; previously it
incorrectly returned `(# | () #)`, indicating failure.
* `integerPowMod 0 e m` now returns `(# | () #)` for e<0 and m>1, indicating
failure; previously it incorrectly returned `(# 0 | #)`.
- - - - -
c9abb87c by Andreas Klebinger at 2025-05-20T17:24:50-04:00
Specialise: Don't float out constraint components.
It was fairly complex to do so and it doesn't seem to improve anything.
Nofib allocations were unaffected as well.
See also Historical Note [Floating dictionaries out of cases]
- - - - -
e3e63e72 by fendor at 2025-05-21T11:10:29+02:00
Add testcases for GHCi multiple home units
Adds the following testcases:
* Evaluate code with a single home unit using 'initMulti' initialisation
logic
* More complicated testcase with multiple home units, testing reload
logic and code evaluation.
- - - - -
99c64095 by fendor at 2025-05-21T11:54:27+02:00
Make GHCi commands compatible with multiple home units
=== Design
We enable all GHCi features that were previously guarded by the `inMulti`
option.
GHCi supported multiple home units up to a certain degree for quite a while now.
The supported feature set was limited, due to a design impasse:
One of the home units must be "active", e.g., there must be one `HomeUnit`
whose `UnitId` is "active" which is returned when calling
```haskell
do
hscActiveUnitId <$> getSession
```
This makes sense in a GHC session, since you are always compiling a particular
Module, but it makes less intuitive sense in an interactive session.
Given an expression to evaluate, we can't easily tell in which "context" the expression
should be parsed, typechecked and evaluated.
That`s why initially, most of GHCi features, except for `:reload`ing were disabled
if the GHCi session had more than one `HomeUnitEnv`.
We lift this restriction, enabling all features of GHCi for the multiple home unit case.
To do this, we fundamentally change the `HomeUnitEnv` graph to be multiple home unit first.
Instead of differentiating the case were we have a single home unit and multiple,
we now always set up a multiple home unit session that scales seamlessly to an arbitrary
amount of home units.
We introduce two new `HomeUnitEnv`s that are always added to the `HomeUnitGraph`.
They are:
The "interactive-ghci", called the `interactiveGhciUnit`, contains the same
`DynFlags` that are used by the `InteractiveContext` for interactive evaluation
of expressions.
This `HomeUnitEnv` is only used on the prompt of GHCi, so we may refer to it as
"interactive-prompt" unit.
See Note [Relation between the `InteractiveContext` and `interactiveGhciUnitId`]
for discussing its role.
And the `interactive-session`, called `interactiveSessionUnit` or
`interactiveSessionUnitId`, which is used for loading Scripts into
GHCi that are not `Target`s of any home unit, via `:load` or `:add`.
Both of these "interactive" home units depend on all other `HomeUnitEnv`s that
are passed as arguments on the cli.
Additionally, the "interactive-ghci" unit depends on `interactive-session`.
We always evaluate expressions in the context of the
"interactive-ghci" session.
Since "interactive-ghci" depends on all home units, we can import any `Module`
from the other home units with ease.
As we have a clear `HomeUnitGraph` hierarchy, we can set `interactiveGhciUnitId`
as the active home unit for the full duration of the GHCi session.
In GHCi, we always set `interactiveGhciUnitId` to be the currently active home unit.
=== Implementation Details
Given this design idea, the implementation is relatively straight
forward.
The core insight is that a `ModuleName` is not sufficient to identify a
`Module` in the `HomeUnitGraph`. Thus, large parts of the PR is simply
about refactoring usages of `ModuleName` to prefer `Module`, which has a
`Unit` attached and is unique over the `HomeUnitGraph`.
Consequentially, most usages of `lookupHPT` are likely to be incorrect and have
been replaced by `lookupHugByModule` which is keyed by a `Module`.
In `GHCi/UI.hs`, we make sure there is only one location where we are
actually translating `ModuleName` to a `Module`:
* `lookupQualifiedModuleName`
If a `ModuleName` is ambiguous, we detect this and report it to the
user.
To avoid repeated lookups of `ModuleName`s, we store the `Module` in the
`InteractiveImport`, which additionally simplifies the interface
loading.
A subtle detail is that the `DynFlags` of the `InteractiveContext` are
now stored both in the `HomeUnitGraph` and in the `InteractiveContext`.
In UI.hs, there are multiple code paths where we are careful to update
the `DynFlags` in both locations.
Most importantly in `addToProgramDynFlags`.
---
There is one metric increase in this commit:
-------------------------
Metric Increase:
T4029
-------------------------
It is an increase from 14.4 MB to 16.1 MB (+11.8%) which sounds like a
pretty big regression at first.
However, we argue this increase is solely caused by using more data
structures for managing multiple home units in the GHCi session.
In particular, due to the design decision of using three home units, the
base memory usage increases... but by how much?
A big contributor is the `UnitState`, of which we have three now, which
on its own 260 KB per instance. That makes an additional memory usage of
520 KB, already explaining a third of the overall memory usage increase.
Then we store more elements in the `HomeUnitGraph`, we have more
`HomeUnitEnv` entries, etc...
While we didn't chase down each byte, we looked at the memory usage over time
for both `-hi` and `-hT` profiles and can say with confidence while the memory
usage increased slightly, we did not introduce any space leak, as
the graph looks almost identical as the memory usage graph of GHC HEAD.
- - - - -
b3fce6ff by fendor at 2025-05-21T11:54:27+02:00
FIXUP: Multiple Home Units is no longer a special case
- - - - -
381 changed files:
- .gitlab-ci.yml
- .gitlab/ci.sh
- .gitlab/generate-ci/gen_ci.hs
- .gitlab/hello.hs
- .gitlab/jobs.yaml
- compiler/CodeGen.Platform.h
- compiler/GHC.hs
- compiler/GHC/Builtin/Names.hs
- compiler/GHC/Builtin/Types.hs
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/InfoTable.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/ByteCode/Linker.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Cmm/CLabel.hs
- compiler/GHC/CmmToAsm.hs
- compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
- compiler/GHC/CmmToAsm/AArch64/Instr.hs
- compiler/GHC/CmmToAsm/AArch64/Ppr.hs
- compiler/GHC/CmmToAsm/Dwarf/Constants.hs
- + compiler/GHC/CmmToAsm/LA64.hs
- + compiler/GHC/CmmToAsm/LA64/CodeGen.hs
- + compiler/GHC/CmmToAsm/LA64/Cond.hs
- + compiler/GHC/CmmToAsm/LA64/Instr.hs
- + compiler/GHC/CmmToAsm/LA64/Ppr.hs
- + compiler/GHC/CmmToAsm/LA64/RegInfo.hs
- + compiler/GHC/CmmToAsm/LA64/Regs.hs
- compiler/GHC/CmmToAsm/PIC.hs
- compiler/GHC/CmmToAsm/Reg/Graph/TrivColorable.hs
- compiler/GHC/CmmToAsm/Reg/Linear.hs
- compiler/GHC/CmmToAsm/Reg/Linear/AArch64.hs
- compiler/GHC/CmmToAsm/Reg/Linear/FreeRegs.hs
- + compiler/GHC/CmmToAsm/Reg/Linear/LA64.hs
- compiler/GHC/CmmToAsm/Reg/Target.hs
- compiler/GHC/CmmToLlvm/Base.hs
- compiler/GHC/CmmToLlvm/Data.hs
- compiler/GHC/Core/Coercion.hs
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Core/Predicate.hs
- compiler/GHC/Core/TyCo/Rep.hs
- compiler/GHC/Core/TyCo/Tidy.hs
- compiler/GHC/Driver/Backend.hs
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Hs/ImpExp.hs
- compiler/GHC/HsToCore/Binds.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- compiler/GHC/HsToCore/Expr.hs
- compiler/GHC/HsToCore/Pmc/Solver/Types.hs
- compiler/GHC/Iface/Ext/Ast.hs
- compiler/GHC/Iface/Load.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Platform/LoongArch64.hs → compiler/GHC/Platform/LA64.hs
- compiler/GHC/Platform/Regs.hs
- compiler/GHC/Rename/Names.hs
- compiler/GHC/Rename/Unbound.hs
- compiler/GHC/Runtime/Context.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/StgToByteCode.hs
- compiler/GHC/StgToJS/Linker/Linker.hs
- compiler/GHC/Tc/Errors.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Tc/Gen/Export.hs
- compiler/GHC/Tc/Gen/HsType.hs
- compiler/GHC/Tc/Module.hs
- compiler/GHC/Tc/Plugin.hs
- compiler/GHC/Tc/Solver.hs
- compiler/GHC/Tc/Solver/Default.hs
- compiler/GHC/Tc/Solver/Equality.hs
- compiler/GHC/Tc/Solver/InertSet.hs
- compiler/GHC/Tc/Solver/Monad.hs
- compiler/GHC/Tc/Types/Constraint.hs
- compiler/GHC/Tc/Utils/Monad.hs
- compiler/GHC/Tc/Utils/TcMType.hs
- compiler/GHC/Tc/Utils/TcType.hs
- compiler/GHC/Tc/Utils/Unify.hs
- compiler/GHC/Tc/Zonk/TcType.hs
- compiler/GHC/Types/Error/Codes.hs
- compiler/GHC/Types/Hint.hs
- compiler/GHC/Types/Hint/Ppr.hs
- compiler/GHC/Types/Name/Occurrence.hs
- compiler/GHC/Types/Name/Ppr.hs
- compiler/GHC/Types/Unique.hs
- compiler/GHC/Unit/Env.hs
- compiler/GHC/Unit/Home/Graph.hs
- compiler/GHC/Unit/Module/Graph.hs
- compiler/GHC/Unit/Types.hs
- compiler/Language/Haskell/Syntax/Extension.hs
- compiler/Language/Haskell/Syntax/ImpExp.hs
- compiler/ghc.cabal.in
- docs/users_guide/9.14.1-notes.rst
- docs/users_guide/exts/explicit_namespaces.rst
- docs/users_guide/exts/pattern_synonyms.rst
- ghc/GHCi/UI.hs
- ghc/GHCi/UI/Exception.hs
- ghc/GHCi/UI/Info.hs
- ghc/GHCi/UI/Monad.hs
- ghc/Main.hs
- hadrian/bindist/config.mk.in
- hadrian/src/Oracles/Flag.hs
- hadrian/src/Oracles/Setting.hs
- hadrian/src/Rules/BinaryDist.hs
- hadrian/src/Settings/Builders/RunTest.hs
- libffi-tarballs
- libraries/Cabal
- libraries/Win32
- libraries/base/changelog.md
- libraries/base/src/GHC/JS/Prim/Internal/Build.hs
- libraries/base/src/System/CPUTime/Windows.hsc
- libraries/base/tests/perf/encodingAllocations.hs
- libraries/directory
- libraries/ghc-internal/jsbits/base.js
- libraries/ghc-internal/jsbits/errno.js
- libraries/ghc-internal/src/GHC/Internal/Bignum/Integer.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Maybe.hs
- libraries/ghc-internal/src/GHC/Internal/System/Posix/Internals.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Types.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/Run.hs
- libraries/haskeline
- libraries/process
- libraries/unix
- llvm-targets
- m4/fp_cc_supports_target.m4
- m4/fptools_set_platform_vars.m4
- m4/ghc_tables_next_to_code.m4
- rts/PrimOps.cmm
- rts/StgCRun.c
- rts/include/rts/storage/Closures.h
- rts/linker/LoadNativeObjPosix.c
- rts/linker/PEi386.c
- rts/sm/Storage.h
- rts/win32/veh_excn.c
- testsuite/driver/testlib.py
- testsuite/tests/bytecode/T22376/all.T
- testsuite/tests/dependent/should_fail/T11471.stderr
- testsuite/tests/diagnostic-codes/codes.stdout
- testsuite/tests/driver/RecompExports/RecompExports1.stderr
- testsuite/tests/driver/RecompExports/RecompExports4.stderr
- testsuite/tests/driver/T8526/T8526.stdout
- testsuite/tests/driver/fat-iface/fat014.stdout
- testsuite/tests/driver/multipleHomeUnits/multiGHCi.stderr
- testsuite/tests/ffi/should_run/all.T
- testsuite/tests/ghc-api/T6145.hs
- testsuite/tests/ghc-api/annotations-literals/literals.hs
- testsuite/tests/ghc-api/annotations-literals/parsed.hs
- testsuite/tests/ghc-api/apirecomp001/myghc.hs
- testsuite/tests/ghc-api/fixed-nodes/T1.hs
- testsuite/tests/ghc-api/fixed-nodes/all.T
- + testsuite/tests/ghci.debugger/scripts/break031/Makefile
- + testsuite/tests/ghci.debugger/scripts/break031/a/A.hs
- + testsuite/tests/ghci.debugger/scripts/break031/all.T
- + testsuite/tests/ghci.debugger/scripts/break031/b/B.hs
- + testsuite/tests/ghci.debugger/scripts/break031/break031a.script
- + testsuite/tests/ghci.debugger/scripts/break031/break031a.stdout
- + testsuite/tests/ghci.debugger/scripts/break031/break031b.script
- + testsuite/tests/ghci.debugger/scripts/break031/break031b.stderr
- + testsuite/tests/ghci.debugger/scripts/break031/break031b.stdout
- + testsuite/tests/ghci.debugger/scripts/break031/unitA
- + testsuite/tests/ghci.debugger/scripts/break031/unitB
- testsuite/tests/ghci/linking/dyn/T3372.hs
- + testsuite/tests/ghci/prog-mhu001/Makefile
- + testsuite/tests/ghci/prog-mhu001/all.T
- + testsuite/tests/ghci/prog-mhu001/e/E.hs
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001a.script
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001a.stdout
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001b.script
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001b.stdout
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001c.script
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001c.stdout
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001d.script
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001d.stdout
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001e.script
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001e.stdout
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001f.script
- + testsuite/tests/ghci/prog-mhu001/prog-mhu001f.stdout
- + testsuite/tests/ghci/prog-mhu001/unitE
- + testsuite/tests/ghci/prog-mhu001/unitE-main-is
- + testsuite/tests/ghci/prog-mhu002/Makefile
- + testsuite/tests/ghci/prog-mhu002/a/A.hs
- + testsuite/tests/ghci/prog-mhu002/all.T
- + testsuite/tests/ghci/prog-mhu002/b/B.hs
- + testsuite/tests/ghci/prog-mhu002/c/C.hs
- + testsuite/tests/ghci/prog-mhu002/d/Main.hs
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002a.script
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002a.stderr
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002a.stdout
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002b.script
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002b.stderr
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002b.stdout
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002c.script
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002c.stdout
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002d.script
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002d.stdout
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002e.script
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002e.stdout
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002f.script
- + testsuite/tests/ghci/prog-mhu002/prog-mhu002f.stdout
- + testsuite/tests/ghci/prog-mhu002/unitA
- + testsuite/tests/ghci/prog-mhu002/unitB
- + testsuite/tests/ghci/prog-mhu002/unitC
- + testsuite/tests/ghci/prog-mhu002/unitD
- + testsuite/tests/ghci/prog-mhu003/Makefile
- + testsuite/tests/ghci/prog-mhu003/a/A.hs
- + testsuite/tests/ghci/prog-mhu003/all.T
- + testsuite/tests/ghci/prog-mhu003/b/Foo.hs
- + testsuite/tests/ghci/prog-mhu003/c/C.hs
- + testsuite/tests/ghci/prog-mhu003/d/Foo.hs
- + testsuite/tests/ghci/prog-mhu003/prog-mhu003.script
- + testsuite/tests/ghci/prog-mhu003/prog-mhu003.stderr
- + testsuite/tests/ghci/prog-mhu003/prog-mhu003.stdout
- + testsuite/tests/ghci/prog-mhu003/unitA
- + testsuite/tests/ghci/prog-mhu003/unitB
- + testsuite/tests/ghci/prog-mhu003/unitC
- + testsuite/tests/ghci/prog-mhu003/unitD
- + testsuite/tests/ghci/prog-mhu004/Makefile
- + testsuite/tests/ghci/prog-mhu004/a/Foo.hs
- + testsuite/tests/ghci/prog-mhu004/all.T
- + testsuite/tests/ghci/prog-mhu004/b/Foo.hs
- + testsuite/tests/ghci/prog-mhu004/prog-mhu004a.script
- + testsuite/tests/ghci/prog-mhu004/prog-mhu004a.stderr
- + testsuite/tests/ghci/prog-mhu004/prog-mhu004a.stdout
- + testsuite/tests/ghci/prog-mhu004/prog-mhu004b.script
- + testsuite/tests/ghci/prog-mhu004/prog-mhu004b.stdout
- + testsuite/tests/ghci/prog-mhu004/unitA
- + testsuite/tests/ghci/prog-mhu004/unitB
- testsuite/tests/ghci/prog010/ghci.prog010.script
- testsuite/tests/ghci/prog018/prog018.stdout
- testsuite/tests/ghci/scripts/T13869.stdout
- testsuite/tests/ghci/scripts/T13997.stdout
- testsuite/tests/ghci/scripts/T17669.stdout
- testsuite/tests/ghci/scripts/T18330.stdout
- testsuite/tests/ghci/scripts/T1914.stdout
- testsuite/tests/ghci/scripts/T20217.stdout
- testsuite/tests/ghci/scripts/T20587.stdout
- testsuite/tests/ghci/scripts/T21110.stderr
- testsuite/tests/ghci/scripts/T6105.stdout
- testsuite/tests/ghci/scripts/T8042.stdout
- testsuite/tests/ghci/scripts/T8042recomp.stdout
- testsuite/tests/ghci/scripts/ghci024.stdout
- testsuite/tests/ghci/scripts/ghci024.stdout-mingw32
- testsuite/tests/ghci/scripts/ghci058.script
- testsuite/tests/ghci/should_run/TopEnvIface.stdout
- testsuite/tests/indexed-types/should_fail/T8227.stderr
- testsuite/tests/indexed-types/should_fail/T9662.stderr
- testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
- + testsuite/tests/lib/integer/T26017.hs
- + testsuite/tests/lib/integer/T26017.stdout
- testsuite/tests/lib/integer/all.T
- testsuite/tests/lib/integer/integerRecipMod.hs
- testsuite/tests/lib/integer/integerRecipMod.stdout
- testsuite/tests/linters/notes.stdout
- testsuite/tests/module/T21826.stderr
- testsuite/tests/module/mod81.stderr
- testsuite/tests/module/mod91.stderr
- testsuite/tests/partial-sigs/should_fail/T14040a.stderr
- testsuite/tests/partial-sigs/should_fail/T14584.stderr
- testsuite/tests/perf/should_run/ByteCodeAsm.hs
- testsuite/tests/polykinds/T14172.stderr
- testsuite/tests/polykinds/T14846.stderr
- testsuite/tests/printer/T17697.stderr
- testsuite/tests/quasiquotation/T7918.hs
- + testsuite/tests/rename/should_compile/T22581c.hs
- + testsuite/tests/rename/should_compile/T22581c_helper.hs
- + testsuite/tests/rename/should_compile/T22581d.script
- + testsuite/tests/rename/should_compile/T22581d.stdout
- + testsuite/tests/rename/should_compile/T25899a.hs
- + testsuite/tests/rename/should_compile/T25899b.hs
- + testsuite/tests/rename/should_compile/T25899c.hs
- + testsuite/tests/rename/should_compile/T25899c_helper.hs
- + testsuite/tests/rename/should_compile/T25899d.script
- + testsuite/tests/rename/should_compile/T25899d.stdout
- + testsuite/tests/rename/should_compile/T25983a.hs
- + testsuite/tests/rename/should_compile/T25983a.stderr
- + testsuite/tests/rename/should_compile/T25983b.hs
- + testsuite/tests/rename/should_compile/T25983b.stderr
- + testsuite/tests/rename/should_compile/T25983c.hs
- + testsuite/tests/rename/should_compile/T25983c.stderr
- + testsuite/tests/rename/should_compile/T25983d.hs
- + testsuite/tests/rename/should_compile/T25983d.stderr
- + testsuite/tests/rename/should_compile/T25983e.hs
- + testsuite/tests/rename/should_compile/T25983e.stderr
- + testsuite/tests/rename/should_compile/T25983f.hs
- + testsuite/tests/rename/should_compile/T25983f.stderr
- + testsuite/tests/rename/should_compile/T25983g.hs
- + testsuite/tests/rename/should_compile/T25983g.stderr
- + testsuite/tests/rename/should_compile/T25984a.hs
- + testsuite/tests/rename/should_compile/T25984a.stderr
- + testsuite/tests/rename/should_compile/T25984a_helper.hs
- + testsuite/tests/rename/should_compile/T25991a.hs
- + testsuite/tests/rename/should_compile/T25991a_helper.hs
- testsuite/tests/rename/should_compile/all.T
- + testsuite/tests/rename/should_fail/T22581a.hs
- + testsuite/tests/rename/should_fail/T22581a.stderr
- + testsuite/tests/rename/should_fail/T22581a_helper.hs
- + testsuite/tests/rename/should_fail/T22581b.hs
- + testsuite/tests/rename/should_fail/T22581b.stderr
- + testsuite/tests/rename/should_fail/T22581b_helper.hs
- + testsuite/tests/rename/should_fail/T25899e1.hs
- + testsuite/tests/rename/should_fail/T25899e1.stderr
- + testsuite/tests/rename/should_fail/T25899e2.hs
- + testsuite/tests/rename/should_fail/T25899e2.stderr
- + testsuite/tests/rename/should_fail/T25899e3.hs
- + testsuite/tests/rename/should_fail/T25899e3.stderr
- + testsuite/tests/rename/should_fail/T25899e_helper.hs
- + testsuite/tests/rename/should_fail/T25899f.hs
- + testsuite/tests/rename/should_fail/T25899f.stderr
- + testsuite/tests/rename/should_fail/T25899f_helper.hs
- + testsuite/tests/rename/should_fail/T25984b.hs
- + testsuite/tests/rename/should_fail/T25984b.stderr
- + testsuite/tests/rename/should_fail/T25991b1.hs
- + testsuite/tests/rename/should_fail/T25991b1.stderr
- + testsuite/tests/rename/should_fail/T25991b2.hs
- + testsuite/tests/rename/should_fail/T25991b2.stderr
- + testsuite/tests/rename/should_fail/T25991b_helper.hs
- testsuite/tests/rename/should_fail/T9006.stderr
- testsuite/tests/rename/should_fail/all.T
- testsuite/tests/rep-poly/RepPolyArgument.stderr
- testsuite/tests/rep-poly/RepPolyBackpack1.stderr
- testsuite/tests/rep-poly/RepPolyBinder.stderr
- testsuite/tests/rep-poly/RepPolyDoBind.stderr
- testsuite/tests/rep-poly/RepPolyDoBody1.stderr
- testsuite/tests/rep-poly/RepPolyDoBody2.stderr
- testsuite/tests/rep-poly/RepPolyLeftSection2.stderr
- testsuite/tests/rep-poly/RepPolyMagic.stderr
- testsuite/tests/rep-poly/RepPolyMcBind.stderr
- testsuite/tests/rep-poly/RepPolyMcBody.stderr
- testsuite/tests/rep-poly/RepPolyMcGuard.stderr
- testsuite/tests/rep-poly/RepPolyNPlusK.stderr
- testsuite/tests/rep-poly/RepPolyPatBind.stderr
- testsuite/tests/rep-poly/RepPolyRecordUpdate.stderr
- testsuite/tests/rep-poly/RepPolyRightSection.stderr
- testsuite/tests/rep-poly/RepPolyRule1.stderr
- testsuite/tests/rep-poly/RepPolyTuple.stderr
- testsuite/tests/rep-poly/RepPolyTuple4.stderr
- testsuite/tests/rep-poly/RepPolyTupleSection.stderr
- testsuite/tests/rep-poly/RepPolyWrappedVar.stderr
- testsuite/tests/rep-poly/T11473.stderr
- testsuite/tests/rep-poly/T12709.stderr
- testsuite/tests/rep-poly/T12973.stderr
- testsuite/tests/rep-poly/T13233.stderr
- testsuite/tests/rep-poly/T13929.stderr
- testsuite/tests/rep-poly/T14561.stderr
- testsuite/tests/rep-poly/T14561b.stderr
- testsuite/tests/rep-poly/T17817.stderr
- testsuite/tests/rep-poly/T19615.stderr
- testsuite/tests/rep-poly/T19709b.stderr
- testsuite/tests/rep-poly/T21906.stderr
- testsuite/tests/rep-poly/T23903.stderr
- testsuite/tests/rep-poly/UnliftedNewtypesCoerceFail.stderr
- testsuite/tests/rts/all.T
- testsuite/tests/typecheck/no_skolem_info/T14040.stderr
- testsuite/tests/typecheck/should_compile/T25266a.stderr
- + testsuite/tests/typecheck/should_compile/T26020.hs
- + testsuite/tests/typecheck/should_compile/T26020a.hs
- + testsuite/tests/typecheck/should_compile/T26020a_help.hs
- testsuite/tests/typecheck/should_compile/all.T
- testsuite/tests/typecheck/should_fail/T16204c.stderr
- + testsuite/tests/typecheck/should_fail/T26004.hs
- + testsuite/tests/typecheck/should_fail/T26004.stderr
- + testsuite/tests/typecheck/should_fail/T26015.hs
- + testsuite/tests/typecheck/should_fail/T26015.stderr
- testsuite/tests/typecheck/should_fail/T7453.stderr
- testsuite/tests/typecheck/should_fail/T7696.stderr
- testsuite/tests/typecheck/should_fail/T8603.stderr
- testsuite/tests/typecheck/should_fail/all.T
- + testsuite/tests/typecheck/should_run/T25998.hs
- + testsuite/tests/typecheck/should_run/T25998.stdout
- testsuite/tests/typecheck/should_run/all.T
- utils/check-exact/ExactPrint.hs
- utils/ghc-toolchain/exe/Main.hs
- utils/ghc-toolchain/src/GHC/Toolchain/Tools/Cc.hs
- utils/haddock/haddock-library/src/Documentation/Haddock/Parser.hs
- utils/haddock/haddock-library/test/Documentation/Haddock/ParserSpec.hs
- utils/hsc2hs
- utils/llvm-targets/gen-data-layout.sh
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/c3f0c49829b639e327231a2e31a30a…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/c3f0c49829b639e327231a2e31a30a…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 15 commits: compiler: do not allocate strings in bytecode assembler
by Marge Bot (@marge-bot) 21 May '25
by Marge Bot (@marge-bot) 21 May '25
21 May '25
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
7147370b by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: do not allocate strings in bytecode assembler
This patch refactors the compiler to avoid allocating iserv buffers
for BCONPtrStr at assemble-time. Now BCONPtrStr ByteStrings are
recorded as a part of CompiledByteCode, and actual allocation only
happens at link-time. This refactoring is necessary for adding
bytecode serialization functionality, as explained by the revised
comments in this commit.
- - - - -
a67db612 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: make bc_strs serializable
This commit makes the bc_strs field in CompiledByteCode serializable;
similar to previous commit, we preserve the ByteString directly and
defer the actual allocation to link-time, as mentioned in updated
comment.
- - - - -
5faf34ef by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: make bc_itbls serializable
This commit makes bc_itbls in CompiledByteCode serializable. A
dedicated ConInfoTable datatype has been added in ghci which is the
recipe for dynamically making a datacon's info table, containing the
payload of the MkConInfoTable iserv message.
- - - - -
2abaf8c1 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: remove FFIInfo bookkeeping in BCO
This commit removes the bc_ffis field from CompiledByteCode
completely, as well as all the related bookkeeping logic in
GHC.StgToByteCode. bc_ffis is actually *unused* in the rest of GHC
codebase! It is merely a list of FFIInfo, which is just a remote
pointer of the libffi ffi_cif struct; once we allocate the ffi_cif
struct and put its pointer in a CCALL instruction, we'll never free it
anyway. So there is no point of bookkeeping.
- - - - -
adb9e4d2 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: make FFIInfo serializable in BCO
This commit makes all the FFIInfo needed in CCALL instructions
serializable. Previously, when doing STG to BCO lowering, we would
allocate a libffi ffi_cif struct and keep its remote pointer as
FFIInfo; but actually we can just keep the type signature as FFIInfo
and defer the actual allocation to link-time.
- - - - -
200f401b by Cheng Shao at 2025-05-20T17:22:19-04:00
ghci: remove redundant NewBreakModule message
This commit removes the redundant NewBreakModule message from ghci: it
just allocates two strings! This functionality can be implemented with
existing MallocStrings in one iserv call.
- - - - -
ddaadca6 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: make breakpoint module name and unit id serializable
This commit makes breakpoint module name and unit id serializable, in
BRK_FUN instructions as well as ModBreaks. We can simply keep the
module name and unit ids, and defer the buffer allocation to link
time.
- - - - -
a0fde202 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: remove unused newModule
This commit removes the now unused newModule function from GHC.
- - - - -
68c8f140 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: add BCONPtrFS for interned top level string literals in BCO
This commit adds BCONPtrFS as a BCO non-pointer literal kind, which
has the same semantics of BCONPtrStr, except it contains a FastString
instead of a ByteString. By using BCONPtrFS to represent top level
string literals that are already FastString in the compilation
pipeline, we enjoy the FastString interning logic and avoid allocating
a bunch of redundant ByteStrings for the same FastStrings, especially
when we lower the BRK_FUN instruction.
- - - - -
f2b532bc by Peng Fan at 2025-05-20T17:23:15-04:00
hadrian: enable GHCi for loongarch64
- - - - -
8ded2330 by kwxm at 2025-05-20T17:24:07-04:00
Fix bugs in `integerRecipMod` and `integerPowMod`
This fixes #26017.
* `integerRecipMod x 1` now returns `(# 1 | #)` for all x; previously it
incorrectly returned `(# | () #)`, indicating failure.
* `integerPowMod 0 e m` now returns `(# | () #)` for e<0 and m>1, indicating
failure; previously it incorrectly returned `(# 0 | #)`.
- - - - -
c9abb87c by Andreas Klebinger at 2025-05-20T17:24:50-04:00
Specialise: Don't float out constraint components.
It was fairly complex to do so and it doesn't seem to improve anything.
Nofib allocations were unaffected as well.
See also Historical Note [Floating dictionaries out of cases]
- - - - -
4457e7b5 by Andreas Klebinger at 2025-05-21T05:45:40-04:00
Interpreter: Add limited support for direct primop evaluation.
This commit adds support for a number of primops directly
to the interpreter. This avoids the indirection of going
through the primop wrapper for those primops speeding interpretation
of optimized code up massively.
Code involving IntSet runs about 25% faster with optimized core and these
changes. For core without breakpoints it's even more pronouced and I
saw reductions in runtime by up to 50%.
Running GHC itself in the interpreter was sped up by ~15% through this
change.
Additionally this comment does a few other related changes:
testsuite:
* Run foundation test in ghci and ghci-opt ways to test these
primops.
* Vastly expand the foundation test to cover all basic primops
by comparing result with the result of calling the wrapper.
Interpreter:
* When pushing arguments for interpreted primops extend each argument to
at least word with when pushing. This avoids some issues with big
endian. We can revisit this if it causes performance issues.
* Restructure the stack chunk check logic. There are now macros for
read accesses which might cross stack chunk boundries and macros which
omit the checks which are used when we statically know we access an
address in the current stack chunk.
- - - - -
d447a3ac by sheaf at 2025-05-21T05:45:54-04:00
QuickLook: do a shape test before unifying
This commit ensures we do a shape test before unifying. This ensures
we don't try to unify a TyVarTv with a non-tyvar, e.g.
alpha[tyv] := Int
On the way, we refactor simpleUnifyCheck:
1. Move the checkTopShape check into simpleUnifyCheck
2. Refactors simpleUnifyCheck to return a value of the new type
SimpleUnifyResult type. Now, simpleUnifyCheck returns "can unify",
"cannot unify" or "dunno" (with "cannot unify" being the new result
it can return). Now:
- touchabilityTest is included; it it fails we return "cannot unify"
- checkTopShape now returns "cannot unify" instead of "dunno" upon failure
3. Move the call to simpleUnifyCheck out of checkTouchableTyVarEq.
After that, checkTouchableTyVarEq becames a simple call to
checkTyEqRhs, so we inline it.
This allows the logic in canEqCanLHSFinish_try_unification to be simplified.
In particular, we now avoid calling 'checkTopShape' twice.
Two further changes suggested by Simon were also implemented:
- In canEqCanLHSFinish, if checkTyEqRhs returns PuFail with
'do_not_prevent_rewriting', we now **continue with this constraint**.
This allows us to use the constraint for rewriting.
- checkTyEqRhs now has a top-level check to avoid flattening a tyfam app
in a top-level equality of the form alpha ~ F tys, as this is
going around in circles. This simplifies the implementation without
any change in behaviour.
Fixes #25950
Fixes #26030
- - - - -
09778e02 by sheaf at 2025-05-21T05:45:54-04:00
FixedRuntimeRepError: omit unhelpful explanation
This commit tweaks the FixedRuntimeRepError case of pprTcSolverReportMsg,
to avoid including an explanation which refers to a type variable that
appears nowhere else.
For example, the old error message could look like the following:
The pattern binding does not have a fixed runtime representation.
Its type is:
T :: TYPE R
Cannot unify ‘R’ with the type variable ‘c0’
because the former is not a concrete ‘RuntimeRep’.
With this commit, we now omit the last two lines, because the concrete
type variable (here 'c0') does not appear in the type displayed to the
user (here 'T :: TYPE R').
- - - - -
51 changed files:
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/InfoTable.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/ByteCode/Linker.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/StgToByteCode.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/Solver/Equality.hs
- compiler/GHC/Tc/Solver/Monad.hs
- compiler/GHC/Tc/Types/Constraint.hs
- compiler/GHC/Tc/Utils/Unify.hs
- hadrian/src/Oracles/Flag.hs
- libraries/base/changelog.md
- libraries/ghc-internal/src/GHC/Internal/Bignum/Integer.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/Run.hs
- rts/Disassembler.c
- rts/Interpreter.c
- rts/include/rts/Bytecodes.h
- testsuite/tests/bytecode/T22376/all.T
- testsuite/tests/codeGen/should_run/all.T
- + testsuite/tests/ghci/all.T
- + testsuite/tests/ghci/ghci-mem-primops.hs
- + testsuite/tests/ghci/ghci-mem-primops.script
- + testsuite/tests/ghci/ghci-mem-primops.stdout
- + testsuite/tests/lib/integer/T26017.hs
- + testsuite/tests/lib/integer/T26017.stdout
- testsuite/tests/lib/integer/all.T
- testsuite/tests/lib/integer/integerRecipMod.hs
- testsuite/tests/lib/integer/integerRecipMod.stdout
- testsuite/tests/numeric/should_run/all.T
- testsuite/tests/numeric/should_run/foundation.hs
- testsuite/tests/numeric/should_run/foundation.stdout
- testsuite/tests/perf/should_run/ByteCodeAsm.hs
- testsuite/tests/rep-poly/RepPolyTuple4.stderr
- testsuite/tests/rep-poly/T19709b.stderr
- testsuite/tests/rep-poly/T23903.stderr
- testsuite/tests/simplCore/should_compile/simpl017.stderr
- + testsuite/tests/typecheck/should_compile/T26030.hs
- testsuite/tests/typecheck/should_compile/all.T
- + testsuite/tests/typecheck/should_fail/T25950.hs
- + testsuite/tests/typecheck/should_fail/T25950.stderr
- testsuite/tests/typecheck/should_fail/all.T
- utils/genprimopcode/Main.hs
- utils/genprimopcode/Syntax.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/0155f5503c4dff92c5d61f78882e73…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/0155f5503c4dff92c5d61f78882e73…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][master] Specialise: Don't float out constraint components.
by Marge Bot (@marge-bot) 20 May '25
by Marge Bot (@marge-bot) 20 May '25
20 May '25
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
c9abb87c by Andreas Klebinger at 2025-05-20T17:24:50-04:00
Specialise: Don't float out constraint components.
It was fairly complex to do so and it doesn't seem to improve anything.
Nofib allocations were unaffected as well.
See also Historical Note [Floating dictionaries out of cases]
- - - - -
1 changed file:
- compiler/GHC/Core/Opt/Specialise.hs
Changes:
=====================================
compiler/GHC/Core/Opt/Specialise.hs
=====================================
@@ -64,7 +64,7 @@ import GHC.Unit.Module.ModGuts
import GHC.Core.Unfold
import Data.List( partition )
-import Data.List.NonEmpty ( NonEmpty (..) )
+-- import Data.List.NonEmpty ( NonEmpty (..) )
import GHC.Core.Subst (substTickish)
{-
@@ -1277,67 +1277,8 @@ specCase :: SpecEnv
, OutId
, [OutAlt]
, UsageDetails)
-specCase env scrut' case_bndr [Alt con args rhs]
- | -- See Note [Floating dictionaries out of cases]
- interestingDict scrut' (idType case_bndr)
- , not (isDeadBinder case_bndr && null sc_args')
- = do { case_bndr_flt :| sc_args_flt <- mapM clone_me (case_bndr' :| sc_args')
-
- ; let case_bndr_flt' = case_bndr_flt `addDictUnfolding` scrut'
- scrut_bind = mkDB (NonRec case_bndr_flt scrut')
-
- sc_args_flt' = zipWith addDictUnfolding sc_args_flt sc_rhss
- sc_rhss = [ Case (Var case_bndr_flt') case_bndr' (idType sc_arg')
- [Alt con args' (Var sc_arg')]
- | sc_arg' <- sc_args' ]
- cb_set = unitVarSet case_bndr_flt'
- sc_binds = [ DB { db_bind = NonRec sc_arg_flt sc_rhs, db_fvs = cb_set }
- | (sc_arg_flt, sc_rhs) <- sc_args_flt' `zip` sc_rhss ]
-
- flt_binds = scrut_bind : sc_binds
-
- -- Extend the substitution for RHS to map the *original* binders
- -- to their floated versions.
- mb_sc_flts :: [Maybe DictId]
- mb_sc_flts = map (lookupVarEnv clone_env) args'
- clone_env = zipVarEnv sc_args' sc_args_flt'
-
- subst_prs = (case_bndr, Var case_bndr_flt)
- : [ (arg, Var sc_flt)
- | (arg, Just sc_flt) <- args `zip` mb_sc_flts ]
- subst' = se_subst env_rhs
- `Core.extendSubstInScopeList` (case_bndr_flt' : sc_args_flt')
- `Core.extendIdSubstList` subst_prs
- env_rhs' = env_rhs { se_subst = subst' }
-
- ; (rhs', rhs_uds) <- specExpr env_rhs' rhs
- ; let (free_uds, dumped_dbs) = dumpUDs (case_bndr':args') rhs_uds
- all_uds = flt_binds `consDictBinds` free_uds
- alt' = Alt con args' (wrapDictBindsE dumped_dbs rhs')
--- ; pprTrace "specCase" (ppr case_bndr $$ ppr scrut_bind) $
- ; return (Var case_bndr_flt, case_bndr', [alt'], all_uds) }
- where
- (env_rhs, (case_bndr':|args')) = substBndrs env (case_bndr:|args)
- sc_args' = filter is_flt_sc_arg args'
-
- clone_me bndr = do { uniq <- getUniqueM
- ; return (mkUserLocalOrCoVar occ uniq wght ty loc) }
- where
- name = idName bndr
- wght = idMult bndr
- ty = idType bndr
- occ = nameOccName name
- loc = getSrcSpan name
-
- arg_set = mkVarSet args'
- is_flt_sc_arg var = isId var
- && not (isDeadBinder var)
- && isDictTy var_ty
- && tyCoVarsOfType var_ty `disjointVarSet` arg_set
- where
- var_ty = idType var
-
-
+-- We used to float out super class selections here,
+-- but no longer do so. See Historical Note [Floating dictionaries out of cases]
specCase env scrut case_bndr alts
= do { (alts', uds_alts) <- mapAndCombineSM spec_alt alts
; return (scrut, case_bndr', alts', uds_alts) }
@@ -1414,36 +1355,36 @@ Note [tryRules: plan (BEFORE)] in the Simplifier (partly) redundant. That is,
if we run rules in the specialiser, does it matter if we make rules "win" over
inlining in the Simplifier? Yes, it does! See the discussion in #21851.
-Note [Floating dictionaries out of cases]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Consider
+Historical Note [Floating dictionaries out of cases]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Function `specCase` used to give special treatment to a case-expression
+that scrutinised a dictionary, like this:
g = \d. case d of { MkD sc ... -> ...(f sc)... }
-Naively we can't float d2's binding out of the case expression,
-because 'sc' is bound by the case, and that in turn means we can't
-specialise f, which seems a pity.
-
-So we invert the case, by floating out a binding
-for 'sc_flt' thus:
- sc_flt = case d of { MkD sc ... -> sc }
-Now we can float the call instance for 'f'. Indeed this is just
-what'll happen if 'sc' was originally bound with a let binding,
-but case is more efficient, and necessary with equalities. So it's
-good to work with both.
-
-You might think that this won't make any difference, because the
-call instance will only get nuked by the \d. BUT if 'g' itself is
-specialised, then transitively we should be able to specialise f.
-
-In general, given
- case e of cb { MkD sc ... -> ...(f sc)... }
-we transform to
- let cb_flt = e
- sc_flt = case cb_flt of { MkD sc ... -> sc }
- in
- case cb_flt of bg { MkD sc ... -> ....(f sc_flt)... }
-
-The "_flt" things are the floated binds; we use the current substitution
-to substitute sc -> sc_flt in the RHS
+But actually
+
+* We never explicitly case-analyse a dictionary; rather the class-op
+ rules select superclasses from it. (NB: worker/wrapper can unbox
+ tuple dictionaries -- see (DNB1) in Note [Do not unbox class dictionaries];
+ but that's only after worker/wrapper, and specialisation happens before
+ that.)
+
+* Calling `interestingDict` on every scrutinee is hardly sensible;
+ generally `interestingDict` is called only on Constraint-kinded things.
+
+* It was giving a Lint scope error in !14272
+
+So now there is no special case. This Note just records the change
+in case we ever want to reinstate it. The original note was
+added in
+
+ commit c107a00ccf1e641a2d008939cf477c71caa028d5
+ Author: Simon Peyton Jones <simonpj(a)microsoft.com>
+ Date: Thu Aug 12 13:11:33 2010 +0000
+
+ Improve the Specialiser, fixing Trac #4203
+
+End of Historical Note
+
************************************************************************
* *
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/c9abb87ccc0c91cd94f42b3e3627015…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/c9abb87ccc0c91cd94f42b3e3627015…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][master] Fix bugs in `integerRecipMod` and `integerPowMod`
by Marge Bot (@marge-bot) 20 May '25
by Marge Bot (@marge-bot) 20 May '25
20 May '25
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
8ded2330 by kwxm at 2025-05-20T17:24:07-04:00
Fix bugs in `integerRecipMod` and `integerPowMod`
This fixes #26017.
* `integerRecipMod x 1` now returns `(# 1 | #)` for all x; previously it
incorrectly returned `(# | () #)`, indicating failure.
* `integerPowMod 0 e m` now returns `(# | () #)` for e<0 and m>1, indicating
failure; previously it incorrectly returned `(# 0 | #)`.
- - - - -
7 changed files:
- libraries/base/changelog.md
- libraries/ghc-internal/src/GHC/Internal/Bignum/Integer.hs
- + testsuite/tests/lib/integer/T26017.hs
- + testsuite/tests/lib/integer/T26017.stdout
- testsuite/tests/lib/integer/all.T
- testsuite/tests/lib/integer/integerRecipMod.hs
- testsuite/tests/lib/integer/integerRecipMod.stdout
Changes:
=====================================
libraries/base/changelog.md
=====================================
@@ -23,6 +23,9 @@
* `GHC.ExecutionStack.Internal`.
* Deprecate `GHC.JS.Prim.Internal.Build`, as per [CLC #329](https://github.com/haskell/core-libraries-committee/issues/329)
+ * Fix incorrect results of `integerPowMod` when the base is 0 and the exponent is negative, and `integerRecipMod` when the modulus is zero ([#26017](https://gitlab.haskell.org/ghc/ghc/-/issues/26017)).
+
+
## 4.21.0.0 *TBA*
* Change `SrcLoc` to be a strict and unboxed (finishing [CLC proposal #55](https://github.com/haskell/core-libraries-committee/issues/55))
* Introduce `Data.Bounded` module exporting the `Bounded` typeclass (finishing [CLC proposal #208](https://github.com/haskell/core-libraries-committee/issues/208))
=====================================
libraries/ghc-internal/src/GHC/Internal/Bignum/Integer.hs
=====================================
@@ -1333,38 +1333,60 @@ integerGcde a b = case integerGcde# a b of
-- | Computes the modular inverse.
--
--- I.e. y = integerRecipMod# x m
--- = x^(-1) `mod` m
+-- @integerRecipMod# x m@ behaves as follows:
--
--- with 0 < y < |m|
+-- * If m > 1 and gcd x m = 1, it returns an integer y with 0 < y < m such
+-- that x*y is congruent to 1 modulo m.
--
+-- * If m > 1 and gcd x m > 1, it fails.
+--
+-- * If m = 1, it returns @0@ for all x. The computation effectively takes
+-- place in the zero ring, which has a single element 0 with 0+0 = 0*0 = 0:
+-- the element 0 is the multiplicative identity element and is its own
+-- multiplicative inverse.
+--
+-- * If m = 0, it fails.
+--
+-- NB. Successful evaluation returns a value of the form @(# n | #)@; failure is
+-- indicated by returning @(# | () #)@.
integerRecipMod#
:: Integer
-> Natural
-> (# Natural | () #)
integerRecipMod# x m
- | integerIsZero x = (# | () #)
| naturalIsZero m = (# | () #)
- | naturalIsOne m = (# | () #)
+ | naturalIsOne m = (# naturalZero | #)
+ | integerIsZero x = (# | () #)
| True = Backend.integer_recip_mod x m
-- | Computes the modular exponentiation.
--
--- I.e. y = integer_powmod b e m
--- = b^e `mod` m
+-- @integerPowMod# b e m@ behaves as follows:
--
--- with 0 <= y < abs m
+-- * If m > 1 and e >= 0, it returns an integer y with 0 <= y < m
+-- and y congruent to b^e modulo m.
--
--- If e is negative, we use `integerRecipMod#` to try to find a modular
--- multiplicative inverse (which may not exist).
+-- * If m > 1 and e < 0, it uses `integerRecipMod#` to try to find a modular
+-- multiplicative inverse b' (which only exists if gcd b m = 1) and then
+-- caculates (b')^(-e) modulo m (note that -e > 0); if the inverse does not
+-- exist then it fails.
+--
+-- * If m = 1, it returns @0@ for all b and e.
+--
+-- * If m = 0, it fails.
+--
+-- NB. Successful evaluation returns a value of the form @(# n | #)@; failure is
+-- indicated by returning @(# | () #)@.
+
integerPowMod# :: Integer -> Integer -> Natural -> (# Natural | () #)
integerPowMod# !b !e !m
- | naturalIsZero m = (# | () #)
- | naturalIsOne m = (# naturalZero | #)
- | integerIsZero e = (# naturalOne | #)
- | integerIsZero b = (# naturalZero | #)
- | integerIsOne b = (# naturalOne | #)
+ | naturalIsZero m = (# | () #)
+ | naturalIsOne m = (# naturalZero | #)
+ | integerIsZero e = (# naturalOne | #)
+ | integerIsZero b
+ && integerGt e 0 = (# naturalZero | #)
+ | integerIsOne b = (# naturalOne | #)
-- when the exponent is negative, try to find the modular multiplicative
-- inverse and use it instead
| integerIsNegative e = case integerRecipMod# b m of
=====================================
testsuite/tests/lib/integer/T26017.hs
=====================================
@@ -0,0 +1,39 @@
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE MagicHash #-}
+
+module Main (main) where
+
+import Data.List (group)
+import Data.Bits
+import Data.Word
+import Control.Monad
+
+import GHC.Word
+import GHC.Base
+import GHC.Num.Natural
+import GHC.Num.Integer
+
+integerPowMod :: Integer -> Integer -> Natural -> Maybe Natural
+integerPowMod b e m = case integerPowMod# b e m of
+ (# n | #) -> Just n
+ (# | () #) -> Nothing
+
+integerRecipMod :: Integer -> Natural -> Maybe Natural
+integerRecipMod b m =
+ case integerRecipMod# b m of
+ (# n | #) -> Just n
+ (# | () #) -> Nothing
+
+main :: IO ()
+main = do
+ print $ integerPowMod 0 (-1) 17
+ print $ integerPowMod 0 (-1) (2^1000)
+
+ print $ integerPowMod 0 (-100000) 17
+ print $ integerPowMod 0 (-100000) (2^1000)
+
+ print $ integerRecipMod 0 1
+ print $ integerRecipMod 1 1
+ print $ integerRecipMod 7819347813478123471346279134789352789578923 1
+ print $ integerRecipMod (-1) 1
+ print $ integerRecipMod (-7819347813478123471346279134789352789578923) 1
=====================================
testsuite/tests/lib/integer/T26017.stdout
=====================================
@@ -0,0 +1,9 @@
+Nothing
+Nothing
+Nothing
+Nothing
+Just 0
+Just 0
+Just 0
+Just 0
+Just 0
=====================================
testsuite/tests/lib/integer/all.T
=====================================
@@ -27,3 +27,4 @@ test('integerImportExport', normal, compile_and_run, [''])
test('T19345', [], compile_and_run, [''])
test('T20066', [exit_code(1)], compile_and_run, [''])
+test('T26017', [], compile_and_run, [''])
=====================================
testsuite/tests/lib/integer/integerRecipMod.hs
=====================================
@@ -28,6 +28,8 @@ main = do
-- positive modulo
print $ mapMaybe f [-7..71]
- -- modulo == 1 or 0
+ -- modulo == 1 -> succeed and return 0
print (recipModInteger 77 1)
+
+ -- modulo == 0 -> fail
print (recipModInteger 77 0)
=====================================
testsuite/tests/lib/integer/integerRecipMod.stdout
=====================================
@@ -1,3 +1,3 @@
[(-7,149867),(-5,167851),(-1,209813),(1,1),(5,41963),(7,59947),(13,177535),(19,143557),(23,182447),(25,134281),(29,7235),(31,33841),(35,95915),(37,113413),(41,61409),(43,24397),(47,174101),(49,158431),(53,193979),(59,188477),(61,185737),(65,35507),(67,118999),(71,186173)]
-Nothing
+Just 0
Nothing
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/8ded23300367c6e032b3c5a635fd506…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/8ded23300367c6e032b3c5a635fd506…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

20 May '25
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
f2b532bc by Peng Fan at 2025-05-20T17:23:15-04:00
hadrian: enable GHCi for loongarch64
- - - - -
1 changed file:
- hadrian/src/Oracles/Flag.hs
Changes:
=====================================
hadrian/src/Oracles/Flag.hs
=====================================
@@ -165,7 +165,7 @@ ghcWithInterpreter stage = do
anyTargetArch [ ArchX86, ArchX86_64, ArchPPC
, ArchAArch64, ArchS390X
, ArchPPC_64 ELF_V1, ArchPPC_64 ELF_V2
- , ArchRISCV64
+ , ArchRISCV64, ArchLoongArch64
, ArchWasm32 ]
<*> isArmTarget
-- Maybe this should just be false for cross compilers. But for now
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/f2b532bc5a3f9a19d128cad1eb510e1…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/f2b532bc5a3f9a19d128cad1eb510e1…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][master] 9 commits: compiler: do not allocate strings in bytecode assembler
by Marge Bot (@marge-bot) 20 May '25
by Marge Bot (@marge-bot) 20 May '25
20 May '25
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
7147370b by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: do not allocate strings in bytecode assembler
This patch refactors the compiler to avoid allocating iserv buffers
for BCONPtrStr at assemble-time. Now BCONPtrStr ByteStrings are
recorded as a part of CompiledByteCode, and actual allocation only
happens at link-time. This refactoring is necessary for adding
bytecode serialization functionality, as explained by the revised
comments in this commit.
- - - - -
a67db612 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: make bc_strs serializable
This commit makes the bc_strs field in CompiledByteCode serializable;
similar to previous commit, we preserve the ByteString directly and
defer the actual allocation to link-time, as mentioned in updated
comment.
- - - - -
5faf34ef by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: make bc_itbls serializable
This commit makes bc_itbls in CompiledByteCode serializable. A
dedicated ConInfoTable datatype has been added in ghci which is the
recipe for dynamically making a datacon's info table, containing the
payload of the MkConInfoTable iserv message.
- - - - -
2abaf8c1 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: remove FFIInfo bookkeeping in BCO
This commit removes the bc_ffis field from CompiledByteCode
completely, as well as all the related bookkeeping logic in
GHC.StgToByteCode. bc_ffis is actually *unused* in the rest of GHC
codebase! It is merely a list of FFIInfo, which is just a remote
pointer of the libffi ffi_cif struct; once we allocate the ffi_cif
struct and put its pointer in a CCALL instruction, we'll never free it
anyway. So there is no point of bookkeeping.
- - - - -
adb9e4d2 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: make FFIInfo serializable in BCO
This commit makes all the FFIInfo needed in CCALL instructions
serializable. Previously, when doing STG to BCO lowering, we would
allocate a libffi ffi_cif struct and keep its remote pointer as
FFIInfo; but actually we can just keep the type signature as FFIInfo
and defer the actual allocation to link-time.
- - - - -
200f401b by Cheng Shao at 2025-05-20T17:22:19-04:00
ghci: remove redundant NewBreakModule message
This commit removes the redundant NewBreakModule message from ghci: it
just allocates two strings! This functionality can be implemented with
existing MallocStrings in one iserv call.
- - - - -
ddaadca6 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: make breakpoint module name and unit id serializable
This commit makes breakpoint module name and unit id serializable, in
BRK_FUN instructions as well as ModBreaks. We can simply keep the
module name and unit ids, and defer the buffer allocation to link
time.
- - - - -
a0fde202 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: remove unused newModule
This commit removes the now unused newModule function from GHC.
- - - - -
68c8f140 by Cheng Shao at 2025-05-20T17:22:19-04:00
compiler: add BCONPtrFS for interned top level string literals in BCO
This commit adds BCONPtrFS as a BCO non-pointer literal kind, which
has the same semantics of BCONPtrStr, except it contains a FastString
instead of a ByteString. By using BCONPtrFS to represent top level
string literals that are already FastString in the compilation
pipeline, we enjoy the FastString interning logic and avoid allocating
a bunch of redundant ByteStrings for the same FastStrings, especially
when we lower the BRK_FUN instruction.
- - - - -
13 changed files:
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/InfoTable.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/ByteCode/Linker.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/StgToByteCode.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/Run.hs
- testsuite/tests/bytecode/T22376/all.T
- testsuite/tests/perf/should_run/ByteCodeAsm.hs
Changes:
=====================================
compiler/GHC/ByteCode/Asm.hs
=====================================
@@ -29,7 +29,6 @@ import GHC.ByteCode.Instr
import GHC.ByteCode.InfoTable
import GHC.ByteCode.Types
import GHCi.RemoteTypes
-import GHC.Runtime.Interpreter
import GHC.Runtime.Heap.Layout ( fromStgWord, StgWord )
import GHC.Types.Name
@@ -38,6 +37,7 @@ import GHC.Types.Literal
import GHC.Types.Unique.DSet
import GHC.Types.SptEntry
import GHC.Types.Unique.FM
+import GHC.Unit.Types
import GHC.Utils.Outputable
import GHC.Utils.Panic
@@ -52,6 +52,7 @@ import GHC.Cmm.Reg ( GlobalArgRegs(..) )
import GHC.Cmm.CallConv ( allArgRegsCover )
import GHC.Platform
import GHC.Platform.Profile
+import Language.Haskell.Syntax.Module.Name
import Control.Monad
import qualified Control.Monad.Trans.State.Strict as MTL
@@ -65,6 +66,7 @@ import Data.Array.Base ( unsafeWrite )
#endif
import Foreign hiding (shiftL, shiftR)
+import Data.ByteString (ByteString)
import Data.Char (ord)
import Data.Maybe (fromMaybe)
import GHC.Float (castFloatToWord32, castDoubleToWord64)
@@ -104,24 +106,21 @@ bcoFreeNames bco
-- Top level assembler fn.
assembleBCOs
- :: Interp
- -> Profile
+ :: Profile
-> FlatBag (ProtoBCO Name)
-> [TyCon]
- -> AddrEnv
+ -> [(Name, ByteString)]
-> Maybe ModBreaks
-> [SptEntry]
-> IO CompiledByteCode
-assembleBCOs interp profile proto_bcos tycons top_strs modbreaks spt_entries = do
+assembleBCOs profile proto_bcos tycons top_strs modbreaks spt_entries = do
-- TODO: the profile should be bundled with the interpreter: the rts ways are
-- fixed for an interpreter
- itblenv <- mkITbls interp profile tycons
+ let itbls = mkITbls profile tycons
bcos <- mapM (assembleBCO (profilePlatform profile)) proto_bcos
- bcos' <- mallocStrings interp bcos
return CompiledByteCode
- { bc_bcos = bcos'
- , bc_itbls = itblenv
- , bc_ffis = concatMap protoBCOFFIs proto_bcos
+ { bc_bcos = bcos
+ , bc_itbls = itbls
, bc_strs = top_strs
, bc_breaks = modbreaks
, bc_spt_entries = spt_entries
@@ -137,50 +136,17 @@ assembleBCOs interp profile proto_bcos tycons top_strs modbreaks spt_entries = d
-- memory for them, and bake the resulting addresses into the instruction stream
-- in the form of BCONPtrWord arguments.
--
--- Since we do this when assembling, we only allocate the memory when we compile
--- the module, not each time we relink it. However, we do want to take care to
--- malloc the memory all in one go, since that is more efficient with
--- -fexternal-interpreter, especially when compiling in parallel.
+-- We used to allocate remote buffers for BCONPtrStr ByteStrings when
+-- assembling, but this gets in the way of bytecode serialization: we
+-- want the ability to serialize and reload assembled bytecode, so
+-- it's better to preserve BCONPtrStr as-is, and only perform the
+-- actual allocation at link-time.
--
-- Note that, as with top-level string literal bindings, this memory is never
-- freed, so it just leaks if the BCO is unloaded. See Note [Generating code for
-- top-level string literal bindings] in GHC.StgToByteCode for some discussion
-- about why.
--
-mallocStrings :: Interp -> FlatBag UnlinkedBCO -> IO (FlatBag UnlinkedBCO)
-mallocStrings interp ulbcos = do
- let bytestrings = reverse (MTL.execState (mapM_ collect ulbcos) [])
- ptrs <- interpCmd interp (MallocStrings bytestrings)
- return (MTL.evalState (mapM splice ulbcos) ptrs)
- where
- splice bco@UnlinkedBCO{..} = do
- lits <- mapM spliceLit unlinkedBCOLits
- ptrs <- mapM splicePtr unlinkedBCOPtrs
- return bco { unlinkedBCOLits = lits, unlinkedBCOPtrs = ptrs }
-
- spliceLit (BCONPtrStr _) = do
- rptrs <- MTL.get
- case rptrs of
- (RemotePtr p : rest) -> do
- MTL.put rest
- return (BCONPtrWord (fromIntegral p))
- _ -> panic "mallocStrings:spliceLit"
- spliceLit other = return other
-
- splicePtr (BCOPtrBCO bco) = BCOPtrBCO <$> splice bco
- splicePtr other = return other
-
- collect UnlinkedBCO{..} = do
- mapM_ collectLit unlinkedBCOLits
- mapM_ collectPtr unlinkedBCOPtrs
-
- collectLit (BCONPtrStr bs) = do
- strs <- MTL.get
- MTL.put (bs:strs)
- collectLit _ = return ()
-
- collectPtr (BCOPtrBCO bco) = collect bco
- collectPtr _ = return ()
data RunAsmReader = RunAsmReader { isn_array :: {-# UNPACK #-} !(Array.IOUArray Int Word16)
, ptr_array :: {-# UNPACK #-} !(SmallMutableArrayIO BCOPtr)
@@ -736,15 +702,15 @@ assembleI platform i = case i of
ENTER -> emit_ bci_ENTER []
RETURN rep -> emit_ (return_non_tuple rep) []
RETURN_TUPLE -> emit_ bci_RETURN_T []
- CCALL off m_addr i -> do np <- addr m_addr
+ CCALL off ffi i -> do np <- lit1 $ BCONPtrFFIInfo ffi
emit_ bci_CCALL [wOp off, Op np, SmallOp i]
PRIMCALL -> emit_ bci_PRIMCALL []
BRK_FUN arr tick_mod tick_mod_id tickx info_mod info_mod_id infox cc ->
do p1 <- ptr (BCOPtrBreakArray arr)
- tick_addr <- addr tick_mod
- tick_unitid_addr <- addr tick_mod_id
- info_addr <- addr info_mod
- info_unitid_addr <- addr info_mod_id
+ tick_addr <- lit1 $ BCONPtrFS $ moduleNameFS tick_mod
+ info_addr <- lit1 $ BCONPtrFS $ moduleNameFS info_mod
+ tick_unitid_addr <- lit1 $ BCONPtrFS $ unitIdFS tick_mod_id
+ info_unitid_addr <- lit1 $ BCONPtrFS $ unitIdFS info_mod_id
np <- addr cc
emit_ bci_BRK_FUN [ Op p1
, Op tick_addr, Op info_addr
=====================================
compiler/GHC/ByteCode/InfoTable.hs
=====================================
@@ -13,11 +13,9 @@ import GHC.Prelude
import GHC.Platform
import GHC.Platform.Profile
-import GHC.ByteCode.Types
-import GHC.Runtime.Interpreter
+import GHCi.Message
import GHC.Types.Name ( Name, getName )
-import GHC.Types.Name.Env
import GHC.Types.RepType
import GHC.Core.DataCon ( DataCon, dataConRepArgTys, dataConIdentity )
@@ -35,33 +33,38 @@ import GHC.Utils.Panic
-}
-- Make info tables for the data decls in this module
-mkITbls :: Interp -> Profile -> [TyCon] -> IO ItblEnv
-mkITbls interp profile tcs =
- foldr plusNameEnv emptyNameEnv <$>
- mapM mkITbl (filter isDataTyCon tcs)
+mkITbls :: Profile -> [TyCon] -> [(Name, ConInfoTable)]
+mkITbls profile tcs = concatMap mkITbl (filter isDataTyCon tcs)
where
- mkITbl :: TyCon -> IO ItblEnv
+ mkITbl :: TyCon -> [(Name, ConInfoTable)]
mkITbl tc
| dcs `lengthIs` n -- paranoia; this is an assertion.
- = make_constr_itbls interp profile dcs
+ = make_constr_itbls profile dcs
where
dcs = tyConDataCons tc
n = tyConFamilySize tc
mkITbl _ = panic "mkITbl"
-mkItblEnv :: [(Name,ItblPtr)] -> ItblEnv
-mkItblEnv pairs = mkNameEnv [(n, (n,p)) | (n,p) <- pairs]
-
-- Assumes constructors are numbered from zero, not one
-make_constr_itbls :: Interp -> Profile -> [DataCon] -> IO ItblEnv
-make_constr_itbls interp profile cons =
+make_constr_itbls :: Profile -> [DataCon] -> [(Name, ConInfoTable)]
+make_constr_itbls profile cons =
-- TODO: the profile should be bundled with the interpreter: the rts ways are
-- fixed for an interpreter
- mkItblEnv <$> mapM (uncurry mk_itbl) (zip cons [0..])
- where
- mk_itbl :: DataCon -> Int -> IO (Name,ItblPtr)
- mk_itbl dcon conNo = do
- let rep_args = [ prim_rep
+ map (uncurry mk_itbl) (zip cons [0..])
+ where
+ mk_itbl :: DataCon -> Int -> (Name, ConInfoTable)
+ mk_itbl dcon conNo =
+ ( getName dcon,
+ ConInfoTable
+ tables_next_to_code
+ ptrs'
+ nptrs_really
+ conNo
+ (tagForCon platform dcon)
+ descr
+ )
+ where
+ rep_args = [ prim_rep
| arg <- dataConRepArgTys dcon
, prim_rep <- typePrimRep (scaledThing arg) ]
@@ -79,7 +82,3 @@ make_constr_itbls interp profile cons =
platform = profilePlatform profile
constants = platformConstants platform
tables_next_to_code = platformTablesNextToCode platform
-
- r <- interpCmd interp (MkConInfoTable tables_next_to_code ptrs' nptrs_really
- conNo (tagForCon platform dcon) descr)
- return (getName dcon, ItblPtr r)
=====================================
compiler/GHC/ByteCode/Instr.hs
=====================================
@@ -15,7 +15,6 @@ import GHC.Prelude
import GHC.ByteCode.Types
import GHCi.RemoteTypes
-import GHCi.FFI (C_ffi_cif)
import GHC.StgToCmm.Layout ( ArgRep(..) )
import GHC.Utils.Outputable
import GHC.Types.Name
@@ -51,9 +50,7 @@ data ProtoBCO a
protoBCOBitmapSize :: Word,
protoBCOArity :: Int,
-- what the BCO came from, for debugging only
- protoBCOExpr :: Either [CgStgAlt] CgStgRhs,
- -- malloc'd pointers
- protoBCOFFIs :: [FFIInfo]
+ protoBCOExpr :: Either [CgStgAlt] CgStgRhs
}
-- | A local block label (e.g. identifying a case alternative).
@@ -209,7 +206,7 @@ data BCInstr
-- For doing calls to C (via glue code generated by libffi)
| CCALL !WordOff -- stack frame size
- (RemotePtr C_ffi_cif) -- addr of the glue code
+ !FFIInfo -- libffi ffi_cif function prototype
!Word16 -- flags.
--
-- 0x1: call is interruptible
@@ -233,11 +230,11 @@ data BCInstr
-- Breakpoints
| BRK_FUN (ForeignRef BreakArray)
- (RemotePtr ModuleName) -- breakpoint tick module
- (RemotePtr UnitId) -- breakpoint tick module unit id
+ !ModuleName -- breakpoint tick module
+ !UnitId -- breakpoint tick module unit id
!Word16 -- breakpoint tick index
- (RemotePtr ModuleName) -- breakpoint info module
- (RemotePtr UnitId) -- breakpoint info module unit id
+ !ModuleName -- breakpoint info module
+ !UnitId -- breakpoint info module unit id
!Word16 -- breakpoint info index
(RemotePtr CostCentre)
@@ -266,10 +263,9 @@ instance Outputable a => Outputable (ProtoBCO a) where
, protoBCOBitmap = bitmap
, protoBCOBitmapSize = bsize
, protoBCOArity = arity
- , protoBCOExpr = origin
- , protoBCOFFIs = ffis })
+ , protoBCOExpr = origin })
= (text "ProtoBCO" <+> ppr name <> char '#' <> int arity
- <+> text (show ffis) <> colon)
+ <> colon)
$$ nest 3 (case origin of
Left alts ->
vcat (zipWith (<+>) (char '{' : repeat (char ';'))
@@ -393,9 +389,9 @@ instance Outputable BCInstr where
ppr (TESTEQ_P i lab) = text "TESTEQ_P" <+> ppr i <+> text "__" <> ppr lab
ppr CASEFAIL = text "CASEFAIL"
ppr (JMP lab) = text "JMP" <+> ppr lab
- ppr (CCALL off marshal_addr flags) = text "CCALL " <+> ppr off
+ ppr (CCALL off ffi flags) = text "CCALL " <+> ppr off
<+> text "marshal code at"
- <+> text (show marshal_addr)
+ <+> text (show ffi)
<+> (case flags of
0x1 -> text "(interruptible)"
0x2 -> text "(unsafe)"
=====================================
compiler/GHC/ByteCode/Linker.hs
=====================================
@@ -3,6 +3,7 @@
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE RecordWildCards #-}
{-# OPTIONS_GHC -optc-DNON_POSIX_SOURCE #-}
--
-- (c) The University of Glasgow 2002-2006
@@ -85,9 +86,15 @@ lookupLiteral interp pkgs_loaded le ptr = case ptr of
BCONPtrAddr nm -> do
Ptr a# <- lookupAddr interp pkgs_loaded (addr_env le) nm
return (W# (int2Word# (addr2Int# a#)))
- BCONPtrStr _ ->
- -- should be eliminated during assembleBCOs
- panic "lookupLiteral: BCONPtrStr"
+ BCONPtrStr bs -> do
+ RemotePtr p <- fmap head $ interpCmd interp $ MallocStrings [bs]
+ pure $ fromIntegral p
+ BCONPtrFS fs -> do
+ RemotePtr p <- fmap head $ interpCmd interp $ MallocStrings [bytesFS fs]
+ pure $ fromIntegral p
+ BCONPtrFFIInfo (FFIInfo {..}) -> do
+ RemotePtr p <- interpCmd interp $ PrepFFI ffiInfoArgs ffiInfoRet
+ pure $ fromIntegral p
lookupStaticPtr :: Interp -> FastString -> IO (Ptr ())
lookupStaticPtr interp addr_of_label_string = do
=====================================
compiler/GHC/ByteCode/Types.hs
=====================================
@@ -35,6 +35,7 @@ import GHC.Builtin.PrimOps
import GHC.Types.SptEntry
import GHC.Types.SrcLoc
import GHCi.BreakArray
+import GHCi.Message
import GHCi.RemoteTypes
import GHCi.FFI
import Control.DeepSeq
@@ -49,8 +50,8 @@ import qualified GHC.Exts.Heap as Heap
import GHC.Stack.CCS
import GHC.Cmm.Expr ( GlobalRegSet, emptyRegSet, regSetToList )
import GHC.Iface.Syntax
-import Language.Haskell.Syntax.Module.Name (ModuleName)
-import GHC.Unit.Types (UnitId)
+import Language.Haskell.Syntax.Module.Name (ModuleName, mkModuleNameFS)
+import GHC.Unit.Types (UnitId(..))
-- -----------------------------------------------------------------------------
-- Compiled Byte Code
@@ -59,13 +60,10 @@ data CompiledByteCode = CompiledByteCode
{ bc_bcos :: FlatBag UnlinkedBCO
-- ^ Bunch of interpretable bindings
- , bc_itbls :: ItblEnv
+ , bc_itbls :: [(Name, ConInfoTable)]
-- ^ Mapping from DataCons to their info tables
- , bc_ffis :: [FFIInfo]
- -- ^ ffi blocks we allocated
-
- , bc_strs :: AddrEnv
+ , bc_strs :: [(Name, ByteString)]
-- ^ top-level strings (heap allocated)
, bc_breaks :: Maybe ModBreaks
@@ -76,9 +74,10 @@ data CompiledByteCode = CompiledByteCode
-- BCOs. See Note [Grand plan for static forms] in
-- "GHC.Iface.Tidy.StaticPtrTable".
}
- -- ToDo: we're not tracking strings that we malloc'd
-newtype FFIInfo = FFIInfo (RemotePtr C_ffi_cif)
- deriving (Show, NFData)
+
+-- | A libffi ffi_cif function prototype.
+data FFIInfo = FFIInfo { ffiInfoArgs :: ![FFIType], ffiInfoRet :: !FFIType }
+ deriving (Show)
instance Outputable CompiledByteCode where
ppr CompiledByteCode{..} = ppr $ elemsFlatBag bc_bcos
@@ -88,9 +87,8 @@ instance Outputable CompiledByteCode where
seqCompiledByteCode :: CompiledByteCode -> ()
seqCompiledByteCode CompiledByteCode{..} =
rnf bc_bcos `seq`
- seqEltsNameEnv rnf bc_itbls `seq`
- rnf bc_ffis `seq`
- seqEltsNameEnv rnf bc_strs `seq`
+ rnf bc_itbls `seq`
+ rnf bc_strs `seq`
rnf (fmap seqModBreaks bc_breaks)
newtype ByteOff = ByteOff Int
@@ -200,10 +198,13 @@ data BCONPtr
-- | A reference to a top-level string literal; see
-- Note [Generating code for top-level string literal bindings] in GHC.StgToByteCode.
| BCONPtrAddr !Name
- -- | Only used internally in the assembler in an intermediate representation;
- -- should never appear in a fully-assembled UnlinkedBCO.
+ -- | A top-level string literal.
-- Also see Note [Allocating string literals] in GHC.ByteCode.Asm.
| BCONPtrStr !ByteString
+ -- | Same as 'BCONPtrStr' but with benefits of 'FastString' interning logic.
+ | BCONPtrFS !FastString
+ -- | A libffi ffi_cif function prototype.
+ | BCONPtrFFIInfo !FFIInfo
instance NFData BCONPtr where
rnf x = x `seq` ()
@@ -263,9 +264,9 @@ data ModBreaks
-- ^ Array pointing to cost centre for each breakpoint
, modBreaks_breakInfo :: IntMap CgBreakInfo
-- ^ info about each breakpoint from the bytecode generator
- , modBreaks_module :: RemotePtr ModuleName
+ , modBreaks_module :: !ModuleName
-- ^ info about the module in which we are setting the breakpoint
- , modBreaks_module_unitid :: RemotePtr UnitId
+ , modBreaks_module_unitid :: !UnitId
-- ^ The 'UnitId' of the 'ModuleName'
}
@@ -290,8 +291,8 @@ emptyModBreaks = ModBreaks
, modBreaks_decls = array (0,-1) []
, modBreaks_ccs = array (0,-1) []
, modBreaks_breakInfo = IntMap.empty
- , modBreaks_module = toRemotePtr nullPtr
- , modBreaks_module_unitid = toRemotePtr nullPtr
+ , modBreaks_module = mkModuleNameFS nilFS
+ , modBreaks_module_unitid = UnitId nilFS
}
{-
=====================================
compiler/GHC/HsToCore/Breakpoints.hs
=====================================
@@ -34,7 +34,6 @@ mkModBreaks interp mod extendedMixEntries
breakArray <- GHCi.newBreakArray interp count
ccs <- mkCCSArray interp mod count entries
- (mod_ptr, mod_id_ptr) <- GHCi.newModule interp mod
let
locsTicks = listArray (0,count-1) [ tick_loc t | t <- entries ]
varsTicks = listArray (0,count-1) [ tick_ids t | t <- entries ]
@@ -45,8 +44,8 @@ mkModBreaks interp mod extendedMixEntries
, modBreaks_vars = varsTicks
, modBreaks_decls = declsTicks
, modBreaks_ccs = ccs
- , modBreaks_module = mod_ptr
- , modBreaks_module_unitid = mod_id_ptr
+ , modBreaks_module = moduleName mod
+ , modBreaks_module_unitid = toUnitId $ moduleUnit mod
}
mkCCSArray
=====================================
compiler/GHC/Linker/Loader.hs
=====================================
@@ -54,7 +54,7 @@ import GHC.Tc.Utils.Monad
import GHC.Runtime.Interpreter
import GHCi.RemoteTypes
import GHC.Iface.Load
-import GHCi.Message (LoadedDLL)
+import GHCi.Message (ConInfoTable(..), LoadedDLL)
import GHC.ByteCode.Linker
import GHC.ByteCode.Asm
@@ -95,6 +95,7 @@ import GHC.Linker.Types
-- Standard libraries
import Control.Monad
+import Data.ByteString (ByteString)
import qualified Data.Set as Set
import Data.Char (isSpace)
import qualified Data.Foldable as Foldable
@@ -688,8 +689,10 @@ loadDecls interp hsc_env span linkable = do
else do
-- Link the expression itself
let le = linker_env pls
- le2 = le { itbl_env = foldl' (\acc cbc -> plusNameEnv acc (bc_itbls cbc)) (itbl_env le) cbcs
- , addr_env = foldl' (\acc cbc -> plusNameEnv acc (bc_strs cbc)) (addr_env le) cbcs }
+ le2_itbl_env <- linkITbls interp (itbl_env le) (concat $ map bc_itbls cbcs)
+ le2_addr_env <- foldlM (\env cbc -> allocateTopStrings interp (bc_strs cbc) env) (addr_env le) cbcs
+ let le2 = le { itbl_env = le2_itbl_env
+ , addr_env = le2_addr_env }
-- Link the necessary packages and linkables
new_bindings <- linkSomeBCOs interp (pkgs_loaded pls) le2 cbcs
@@ -911,9 +914,9 @@ dynLinkBCOs interp pls bcos = do
le1 = linker_env pls
- ie2 = foldr plusNameEnv (itbl_env le1) (map bc_itbls cbcs)
- ae2 = foldr plusNameEnv (addr_env le1) (map bc_strs cbcs)
- le2 = le1 { itbl_env = ie2, addr_env = ae2 }
+ ie2 <- linkITbls interp (itbl_env le1) (concatMap bc_itbls cbcs)
+ ae2 <- foldlM (\env cbc -> allocateTopStrings interp (bc_strs cbc) env) (addr_env le1) cbcs
+ let le2 = le1 { itbl_env = ie2, addr_env = ae2 }
names_and_refs <- linkSomeBCOs interp (pkgs_loaded pls) le2 cbcs
@@ -958,6 +961,11 @@ makeForeignNamedHValueRefs
makeForeignNamedHValueRefs interp bindings =
mapM (\(n, hvref) -> (n,) <$> mkFinalizedHValue interp hvref) bindings
+linkITbls :: Interp -> ItblEnv -> [(Name, ConInfoTable)] -> IO ItblEnv
+linkITbls interp = foldlM $ \env (nm, itbl) -> do
+ r <- interpCmd interp $ MkConInfoTable itbl
+ evaluate $ extendNameEnv env nm (nm, ItblPtr r)
+
{- **********************************************************************
Unload some object modules
@@ -1614,3 +1622,13 @@ maybePutStr logger s = maybePutSDoc logger (text s)
maybePutStrLn :: Logger -> String -> IO ()
maybePutStrLn logger s = maybePutSDoc logger (text s <> text "\n")
+
+-- | see Note [Generating code for top-level string literal bindings]
+allocateTopStrings ::
+ Interp -> [(Name, ByteString)] -> AddrEnv -> IO AddrEnv
+allocateTopStrings interp topStrings prev_env = do
+ let (bndrs, strings) = unzip topStrings
+ ptrs <- interpCmd interp $ MallocStrings strings
+ evaluate $ extendNameEnvList prev_env (zipWith mk_entry bndrs ptrs)
+ where
+ mk_entry nm ptr = (nm, (nm, AddrPtr ptr))
=====================================
compiler/GHC/Runtime/Interpreter.hs
=====================================
@@ -21,7 +21,6 @@ module GHC.Runtime.Interpreter
, mkCostCentres
, costCentreStackInfo
, newBreakArray
- , newModule
, storeBreakpoint
, breakpointStatus
, getBreakpointVar
@@ -376,14 +375,6 @@ newBreakArray interp size = do
breakArray <- interpCmd interp (NewBreakArray size)
mkFinalizedHValue interp breakArray
-newModule :: Interp -> Module -> IO (RemotePtr ModuleName, RemotePtr UnitId)
-newModule interp mod = do
- let
- mod_name = moduleNameString $ moduleName mod
- mod_id = fastStringToShortByteString $ unitIdFS $ toUnitId $ moduleUnit mod
- (mod_ptr, mod_id_ptr) <- interpCmd interp (NewBreakModule mod_name mod_id)
- pure (castRemotePtr mod_ptr, castRemotePtr mod_id_ptr)
-
storeBreakpoint :: Interp -> ForeignRef BreakArray -> Int -> Int -> IO ()
storeBreakpoint interp ref ix cnt = do -- #19157
withForeignRef ref $ \breakarray ->
=====================================
compiler/GHC/StgToByteCode.hs
=====================================
@@ -67,7 +67,6 @@ import GHC.Data.Bitmap
import GHC.Data.FlatBag as FlatBag
import GHC.Data.OrdList
import GHC.Data.Maybe
-import GHC.Types.Name.Env (mkNameEnv)
import GHC.Types.Tickish
import GHC.Types.SptEntry
@@ -82,7 +81,6 @@ import GHC.Unit.Home.PackageTable (lookupHpt)
import Data.Array
import Data.Coerce (coerce)
-import Data.ByteString (ByteString)
#if MIN_VERSION_rts(1,0,3)
import qualified Data.ByteString.Char8 as BS
#endif
@@ -118,19 +116,15 @@ byteCodeGen hsc_env this_mod binds tycs mb_modBreaks spt_entries
bnd <- binds
case bnd of
StgTopLifted bnd -> [Right bnd]
- StgTopStringLit b str -> [Left (b, str)]
+ StgTopStringLit b str -> [Left (getName b, str)]
flattenBind (StgNonRec b e) = [(b,e)]
flattenBind (StgRec bs) = bs
- stringPtrs <- allocateTopStrings interp strings
(BcM_State{..}, proto_bcos) <-
runBc hsc_env this_mod mb_modBreaks $ do
let flattened_binds = concatMap flattenBind (reverse lifted_binds)
FlatBag.fromList (fromIntegral $ length flattened_binds) <$> mapM schemeTopBind flattened_binds
- when (notNull ffis)
- (panic "GHC.StgToByteCode.byteCodeGen: missing final emitBc?")
-
putDumpFileMaybe logger Opt_D_dump_BCOs
"Proto-BCOs" FormatByteCode
(vcat (intersperse (char ' ') (map ppr $ elemsFlatBag proto_bcos)))
@@ -138,7 +132,7 @@ byteCodeGen hsc_env this_mod binds tycs mb_modBreaks spt_entries
let mod_breaks = case modBreaks of
Nothing -> Nothing
Just mb -> Just mb{ modBreaks_breakInfo = breakInfo }
- cbc <- assembleBCOs interp profile proto_bcos tycs stringPtrs mod_breaks spt_entries
+ cbc <- assembleBCOs profile proto_bcos tycs strings mod_breaks spt_entries
-- Squash space leaks in the CompiledByteCode. This is really
-- important, because when loading a set of modules into GHCi
@@ -152,22 +146,8 @@ byteCodeGen hsc_env this_mod binds tycs mb_modBreaks spt_entries
where dflags = hsc_dflags hsc_env
logger = hsc_logger hsc_env
- interp = hscInterp hsc_env
profile = targetProfile dflags
--- | see Note [Generating code for top-level string literal bindings]
-allocateTopStrings
- :: Interp
- -> [(Id, ByteString)]
- -> IO AddrEnv
-allocateTopStrings interp topStrings = do
- let !(bndrs, strings) = unzip topStrings
- ptrs <- interpCmd interp $ MallocStrings strings
- return $ mkNameEnv (zipWith mk_entry bndrs ptrs)
- where
- mk_entry bndr ptr = let nm = getName bndr
- in (nm, (nm, AddrPtr ptr))
-
{- Note [Generating code for top-level string literal bindings]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As described in Note [Compilation plan for top-level string literals]
@@ -178,9 +158,9 @@ the bytecode compiler: (1) compiling the bindings themselves, and
we deal with them:
1. Top-level string literal bindings are separated from the rest of
- the module. Memory for them is allocated immediately, via
- interpCmd, in allocateTopStrings, and the resulting AddrEnv is
- recorded in the bc_strs field of the CompiledByteCode result.
+ the module. Memory is not allocated until bytecode link-time, the
+ bc_strs field of the CompiledByteCode result records [(Name, ByteString)]
+ directly.
2. When we encounter a reference to a top-level string literal, we
generate a PUSH_ADDR pseudo-instruction, which is assembled to
@@ -254,17 +234,15 @@ mkProtoBCO
-> WordOff -- ^ bitmap size
-> [StgWord] -- ^ bitmap
-> Bool -- ^ True <=> is a return point, rather than a function
- -> [FFIInfo]
-> ProtoBCO Name
-mkProtoBCO platform _add_bco_name nm instrs_ordlist origin arity bitmap_size bitmap is_ret ffis
+mkProtoBCO platform _add_bco_name nm instrs_ordlist origin arity bitmap_size bitmap is_ret
= ProtoBCO {
protoBCOName = nm,
protoBCOInstrs = maybe_add_bco_name $ maybe_add_stack_check peep_d,
protoBCOBitmap = bitmap,
protoBCOBitmapSize = fromIntegral bitmap_size,
protoBCOArity = arity,
- protoBCOExpr = origin,
- protoBCOFFIs = ffis
+ protoBCOExpr = origin
}
where
#if MIN_VERSION_rts(1,0,3)
@@ -334,7 +312,7 @@ schemeTopBind (id, rhs)
-- by just re-using the single top-level definition. So
-- for the worker itself, we must allocate it directly.
-- ioToBc (putStrLn $ "top level BCO")
- emitBc (mkProtoBCO platform add_bco_name
+ pure (mkProtoBCO platform add_bco_name
(getName id) (toOL [PACK data_con 0, RETURN P])
(Right rhs) 0 0 [{-no bitmap-}] False{-not alts-})
@@ -399,7 +377,7 @@ schemeR_wrk fvs nm original_body (args, body)
bitmap = mkBitmap platform bits
body_code <- schemeER_wrk sum_szsb_args p_init body
- emitBc (mkProtoBCO platform add_bco_name nm body_code (Right original_body)
+ pure (mkProtoBCO platform add_bco_name nm body_code (Right original_body)
arity bitmap_size bitmap False{-not alts-})
-- | Introduce break instructions for ticked expressions.
@@ -478,7 +456,7 @@ break_info hsc_env mod current_mod current_mod_breaks
where
check_mod_ptr mb
| mod_ptr <- modBreaks_module mb
- , fromRemotePtr mod_ptr /= nullPtr
+ , not $ nullFS $ moduleNameFS mod_ptr
= Just mb
| otherwise
= Nothing
@@ -546,7 +524,7 @@ returnUnliftedReps d s szb reps = do
-- otherwise use RETURN_TUPLE with a tuple descriptor
nv_reps -> do
let (call_info, args_offsets) = layoutNativeCall profile NativeTupleReturn 0 id nv_reps
- tuple_bco <- emitBc (tupleBCO platform call_info args_offsets)
+ tuple_bco = tupleBCO platform call_info args_offsets
return $ PUSH_UBX (mkNativeCallInfoLit platform call_info) 1 `consOL`
PUSH_BCO tuple_bco `consOL`
unitOL RETURN_TUPLE
@@ -1097,16 +1075,15 @@ doCase d s p scrut bndr alts
scrut_code <- schemeE (d + ret_frame_size_b + save_ccs_size_b)
(d + ret_frame_size_b + save_ccs_size_b)
p scrut
- alt_bco' <- emitBc alt_bco
if ubx_tuple_frame
- then do tuple_bco <- emitBc (tupleBCO platform call_info args_offsets)
- return (PUSH_ALTS_TUPLE alt_bco' call_info tuple_bco
+ then do let tuple_bco = tupleBCO platform call_info args_offsets
+ return (PUSH_ALTS_TUPLE alt_bco call_info tuple_bco
`consOL` scrut_code)
else let scrut_rep = case non_void_arg_reps of
[] -> V
[rep] -> rep
_ -> panic "schemeE(StgCase).push_alts"
- in return (PUSH_ALTS alt_bco' scrut_rep `consOL` scrut_code)
+ in return (PUSH_ALTS alt_bco scrut_rep `consOL` scrut_code)
-- -----------------------------------------------------------------------------
@@ -1398,7 +1375,7 @@ Note [unboxed tuple bytecodes and tuple_BCO]
-}
-tupleBCO :: Platform -> NativeCallInfo -> [(PrimRep, ByteOff)] -> [FFIInfo] -> ProtoBCO Name
+tupleBCO :: Platform -> NativeCallInfo -> [(PrimRep, ByteOff)] -> ProtoBCO Name
tupleBCO platform args_info args =
mkProtoBCO platform Nothing invented_name body_code (Left [])
0{-no arity-} bitmap_size bitmap False{-is alts-}
@@ -1419,7 +1396,7 @@ tupleBCO platform args_info args =
body_code = mkSlideW 0 1 -- pop frame header
`snocOL` RETURN_TUPLE -- and add it again
-primCallBCO :: Platform -> NativeCallInfo -> [(PrimRep, ByteOff)] -> [FFIInfo] -> ProtoBCO Name
+primCallBCO :: Platform -> NativeCallInfo -> [(PrimRep, ByteOff)] -> ProtoBCO Name
primCallBCO platform args_info args =
mkProtoBCO platform Nothing invented_name body_code (Left [])
0{-no arity-} bitmap_size bitmap False{-is alts-}
@@ -1528,7 +1505,7 @@ generatePrimCall d s p target _mb_unit _result_ty args
massert (off == dd + szb)
go (dd + szb) (push:pushes) cs
push_args <- go d [] shifted_args_offsets
- args_bco <- emitBc (primCallBCO platform args_info prim_args_offsets)
+ let args_bco = primCallBCO platform args_info prim_args_offsets
return $ mconcat push_args `appOL`
(push_target `consOL`
push_info `consOL`
@@ -1706,13 +1683,10 @@ generateCCall d0 s p (CCallSpec target _ safety) result_ty args
let ffires = primRepToFFIType platform r_rep
ffiargs = map (primRepToFFIType platform) a_reps
- interp <- hscInterp <$> getHscEnv
- token <- ioToBc $ interpCmd interp (PrepFFI ffiargs ffires)
- recordFFIBc token
let
-- do the call
- do_call = unitOL (CCALL stk_offset token flags)
+ do_call = unitOL (CCALL stk_offset (FFIInfo ffiargs ffires) flags)
where flags = case safety of
PlaySafe -> 0x0
PlayInterruptible -> 0x1
@@ -2311,8 +2285,6 @@ data BcM_State
{ bcm_hsc_env :: HscEnv
, thisModule :: Module -- current module (for breakpoints)
, nextlabel :: Word32 -- for generating local labels
- , ffis :: [FFIInfo] -- ffi info blocks, to free later
- -- Should be free()d when it is GCd
, modBreaks :: Maybe ModBreaks -- info about breakpoints
, breakInfo :: IntMap CgBreakInfo -- ^ Info at breakpoint occurrence.
@@ -2333,7 +2305,7 @@ runBc :: HscEnv -> Module -> Maybe ModBreaks
-> BcM r
-> IO (BcM_State, r)
runBc hsc_env this_mod modBreaks (BcM m)
- = m (BcM_State hsc_env this_mod 0 [] modBreaks IntMap.empty 0)
+ = m (BcM_State hsc_env this_mod 0 modBreaks IntMap.empty 0)
thenBc :: BcM a -> (a -> BcM b) -> BcM b
thenBc (BcM expr) cont = BcM $ \st0 -> do
@@ -2376,14 +2348,6 @@ shouldAddBcoName = do
then Just <$> getCurrentModule
else return Nothing
-emitBc :: ([FFIInfo] -> ProtoBCO Name) -> BcM (ProtoBCO Name)
-emitBc bco
- = BcM $ \st -> return (st{ffis=[]}, bco (ffis st))
-
-recordFFIBc :: RemotePtr C_ffi_cif -> BcM ()
-recordFFIBc a
- = BcM $ \st -> return (st{ffis = FFIInfo a : ffis st}, ())
-
getLabelBc :: BcM LocalLabel
getLabelBc
= BcM $ \st -> do let nl = nextlabel st
=====================================
libraries/ghci/GHCi/Message.hs
=====================================
@@ -11,6 +11,7 @@
--
module GHCi.Message
( Message(..), Msg(..)
+ , ConInfoTable(..)
, THMessage(..), THMsg(..)
, QResult(..)
, EvalStatus_(..), EvalStatus, EvalResult(..), EvalOpts(..), EvalExpr(..)
@@ -41,6 +42,7 @@ import GHC.ForeignSrcLang
import GHC.Fingerprint
import GHC.Conc (pseq, par)
import Control.Concurrent
+import Control.DeepSeq
import Control.Exception
#if MIN_VERSION_base(4,20,0)
import Control.Exception.Context
@@ -117,12 +119,7 @@ data Message a where
-- | Create an info table for a constructor
MkConInfoTable
- :: Bool -- TABLES_NEXT_TO_CODE
- -> Int -- ptr words
- -> Int -- non-ptr words
- -> Int -- constr tag
- -> Int -- pointer tag
- -> ByteString -- constructor desccription
+ :: !ConInfoTable
-> Message (RemotePtr Heap.StgInfoTable)
-- | Evaluate a statement
@@ -244,16 +241,23 @@ data Message a where
:: RemoteRef (ResumeContext ())
-> Message (EvalStatus ())
- -- | Allocate a string for a breakpoint module name.
- -- This uses an empty dummy type because @ModuleName@ isn't available here.
- NewBreakModule
- :: String -- ^ @ModuleName@
- -> BS.ShortByteString -- ^ @UnitId@ for the given @ModuleName@
- -> Message (RemotePtr BreakModule, RemotePtr BreakUnitId)
+deriving instance Show (Message a)
+-- | Used to dynamically create a data constructor's info table at
+-- run-time.
+data ConInfoTable = ConInfoTable {
+ conItblTablesNextToCode :: !Bool, -- ^ TABLES_NEXT_TO_CODE
+ conItblPtrs :: !Int, -- ^ ptr words
+ conItblNPtrs :: !Int, -- ^ non-ptr words
+ conItblConTag :: !Int, -- ^ constr tag
+ conItblPtrTag :: !Int, -- ^ pointer tag
+ conItblDescr :: !ByteString -- ^ constructor desccription
+}
+ deriving (Generic, Show)
-deriving instance Show (Message a)
+instance Binary ConInfoTable
+instance NFData ConInfoTable
-- | Template Haskell return values
data QResult a
@@ -568,7 +572,7 @@ getMessage = do
15 -> Msg <$> MallocStrings <$> get
16 -> Msg <$> (PrepFFI <$> get <*> get)
17 -> Msg <$> FreeFFI <$> get
- 18 -> Msg <$> (MkConInfoTable <$> get <*> get <*> get <*> get <*> get <*> get)
+ 18 -> Msg <$> MkConInfoTable <$> get
19 -> Msg <$> (EvalStmt <$> get <*> get)
20 -> Msg <$> (ResumeStmt <$> get <*> get)
21 -> Msg <$> (AbandonStmt <$> get)
@@ -589,9 +593,8 @@ getMessage = do
36 -> Msg <$> (Seq <$> get)
37 -> Msg <$> return RtsRevertCAFs
38 -> Msg <$> (ResumeSeq <$> get)
- 39 -> Msg <$> (NewBreakModule <$> get <*> get)
- 40 -> Msg <$> (LookupSymbolInDLL <$> get <*> get)
- 41 -> Msg <$> (WhereFrom <$> get)
+ 39 -> Msg <$> (LookupSymbolInDLL <$> get <*> get)
+ 40 -> Msg <$> (WhereFrom <$> get)
_ -> error $ "Unknown Message code " ++ (show b)
putMessage :: Message a -> Put
@@ -615,7 +618,7 @@ putMessage m = case m of
MallocStrings bss -> putWord8 15 >> put bss
PrepFFI args res -> putWord8 16 >> put args >> put res
FreeFFI p -> putWord8 17 >> put p
- MkConInfoTable tc p n t pt d -> putWord8 18 >> put tc >> put p >> put n >> put t >> put pt >> put d
+ MkConInfoTable itbl -> putWord8 18 >> put itbl
EvalStmt opts val -> putWord8 19 >> put opts >> put val
ResumeStmt opts val -> putWord8 20 >> put opts >> put val
AbandonStmt val -> putWord8 21 >> put val
@@ -636,9 +639,8 @@ putMessage m = case m of
Seq a -> putWord8 36 >> put a
RtsRevertCAFs -> putWord8 37
ResumeSeq a -> putWord8 38 >> put a
- NewBreakModule name unitid -> putWord8 39 >> put name >> put unitid
- LookupSymbolInDLL dll str -> putWord8 40 >> put dll >> put str
- WhereFrom a -> putWord8 41 >> put a
+ LookupSymbolInDLL dll str -> putWord8 39 >> put dll >> put str
+ WhereFrom a -> putWord8 40 >> put a
{-
Note [Parallelize CreateBCOs serialization]
=====================================
libraries/ghci/GHCi/Run.hs
=====================================
@@ -74,7 +74,7 @@ run m = case m of
UnloadObj str -> unloadObj str
AddLibrarySearchPath str -> toRemotePtr <$> addLibrarySearchPath str
RemoveLibrarySearchPath ptr -> removeLibrarySearchPath (fromRemotePtr ptr)
- MkConInfoTable tc ptrs nptrs tag ptrtag desc ->
+ MkConInfoTable (ConInfoTable tc ptrs nptrs tag ptrtag desc) ->
toRemotePtr <$> mkConInfoTable tc ptrs nptrs tag ptrtag desc
ResolveObjs -> resolveObjs
FindSystemLibrary str -> findSystemLibrary str
@@ -96,10 +96,6 @@ run m = case m of
MkCostCentres mod ccs -> mkCostCentres mod ccs
CostCentreStackInfo ptr -> ccsToStrings (fromRemotePtr ptr)
NewBreakArray sz -> mkRemoteRef =<< newBreakArray sz
- NewBreakModule name unitid -> do
- namePtr <- newModuleName name
- uidPtr <- newUnitId unitid
- pure (namePtr, uidPtr)
SetupBreakpoint ref ix cnt -> do
arr <- localRef ref;
_ <- setupBreakpoint arr ix cnt
@@ -440,13 +436,6 @@ mkString0 bs = B.unsafeUseAsCStringLen bs $ \(cstr,len) -> do
pokeElemOff (ptr :: Ptr CChar) len 0
return (castRemotePtr (toRemotePtr ptr))
-mkShortByteString0 :: BS.ShortByteString -> IO (RemotePtr ())
-mkShortByteString0 bs = BS.useAsCStringLen bs $ \(cstr,len) -> do
- ptr <- mallocBytes (len+1)
- copyBytes ptr cstr len
- pokeElemOff (ptr :: Ptr CChar) len 0
- return (castRemotePtr (toRemotePtr ptr))
-
mkCostCentres :: String -> [(String,String)] -> IO [RemotePtr CostCentre]
#if defined(PROFILING)
mkCostCentres mod ccs = do
@@ -464,14 +453,6 @@ foreign import ccall unsafe "mkCostCentre"
mkCostCentres _ _ = return []
#endif
-newModuleName :: String -> IO (RemotePtr BreakModule)
-newModuleName name =
- castRemotePtr . toRemotePtr <$> newCString name
-
-newUnitId :: BS.ShortByteString -> IO (RemotePtr BreakUnitId)
-newUnitId name =
- castRemotePtr <$> mkShortByteString0 name
-
getIdValFromApStack :: HValue -> Int -> IO (Maybe HValue)
getIdValFromApStack apStack (I# stackDepth) = do
case getApStackVal# apStack stackDepth of
=====================================
testsuite/tests/bytecode/T22376/all.T
=====================================
@@ -1,2 +1,2 @@
-test('T22376', [req_interp, extra_files(['A.hs', 'B.hs'])], multimod_compile_and_run,
+test('T22376', [extra_files(['A.hs', 'B.hs'])], multimod_compile_and_run,
['T22376', '-O1 -fwrite-if-simplified-core -fbyte-code-and-object-code -fprefer-byte-code'])
=====================================
testsuite/tests/perf/should_run/ByteCodeAsm.hs
=====================================
@@ -49,11 +49,11 @@ instrs = [ STKCHECK 1234
++ [ PUSH_G appAName | _ <- [0..100] ]
++ [ PUSH_BCO fake_proto2 ]
-fake_proto = ProtoBCO appAName instrs [] 0 0 (Left []) []
+fake_proto = ProtoBCO appAName instrs [] 0 0 (Left [])
instrs2 = [ STKCHECK 77, UNPACK 4, SLIDE 0 4, ENTER ]
-fake_proto2 = ProtoBCO appAName instrs2 [] 0 0 (Left []) []
+fake_proto2 = ProtoBCO appAName instrs2 [] 0 0 (Left [])
main :: IO ()
main = do
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/86406f48659a5ab61ce1fd2a2d427f…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/86406f48659a5ab61ce1fd2a2d427f…
You're receiving this email because of your account on gitlab.haskell.org.
1
0