Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
-
1c50bd7b
by Luite Stegeman at 2026-03-20T12:24:37-04:00
-
bfd7aafd
by Luite Stegeman at 2026-03-20T12:24:37-04:00
14 changed files:
- compiler/GHC/Cmm/Utils.hs
- + compiler/GHC/Platform/Tag.hs
- compiler/GHC/StgToCmm/Closure.hs
- compiler/GHC/StgToCmm/Expr.hs
- compiler/GHC/Tc/Instance/Class.hs
- compiler/GHC/Tc/TyCl/Build.hs
- compiler/GHC/Types/Id/Make.hs
- compiler/GHC/Types/RepType.hs
- compiler/ghc.cabal.in
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- testsuite/tests/simplStg/should_run/all.T
- + testsuite/tests/simplStg/should_run/unpack_enum.hs
- + testsuite/tests/simplStg/should_run/unpack_enum.stdout
Changes:
| ... | ... | @@ -41,7 +41,7 @@ module GHC.Cmm.Utils( |
| 41 | 41 | |
| 42 | 42 | -- Tagging
|
| 43 | 43 | cmmTagMask, cmmPointerMask, cmmUntag, cmmIsTagged, cmmIsNotTagged,
|
| 44 | - cmmConstrTag1, mAX_PTR_TAG, tAG_MASK,
|
|
| 44 | + cmmConstrTag1,
|
|
| 45 | 45 | |
| 46 | 46 | -- Overlap and usage
|
| 47 | 47 | regsOverlap, globalRegsOverlap, regUsedIn, globalRegUsedIn,
|
| ... | ... | @@ -67,6 +67,7 @@ import GHC.Core.TyCon ( PrimRep(..), PrimElemRep(..) ) |
| 67 | 67 | import GHC.Types.RepType ( NvUnaryType, SlotTy (..), typePrimRepU )
|
| 68 | 68 | |
| 69 | 69 | import GHC.Platform
|
| 70 | +import GHC.Platform.Tag (tAG_MASK)
|
|
| 70 | 71 | import GHC.Runtime.Heap.Layout
|
| 71 | 72 | import GHC.Cmm
|
| 72 | 73 | import GHC.Cmm.BlockId
|
| ... | ... | @@ -380,12 +381,6 @@ cmmMkAssign platform expr uq = |
| 380 | 381 | --
|
| 381 | 382 | ---------------------------------------------------
|
| 382 | 383 | |
| 383 | -tAG_MASK :: Platform -> Int
|
|
| 384 | -tAG_MASK platform = (1 `shiftL` pc_TAG_BITS (platformConstants platform)) - 1
|
|
| 385 | - |
|
| 386 | -mAX_PTR_TAG :: Platform -> Int
|
|
| 387 | -mAX_PTR_TAG = tAG_MASK
|
|
| 388 | - |
|
| 389 | 384 | -- Tag bits mask
|
| 390 | 385 | cmmTagMask, cmmPointerMask :: Platform -> CmmExpr
|
| 391 | 386 | cmmTagMask platform = mkIntExpr platform (tAG_MASK platform)
|
| 1 | +-- | Dynamic pointer tagging
|
|
| 2 | +--
|
|
| 3 | +-- See Note [Data constructor dynamic tags]
|
|
| 4 | +module GHC.Platform.Tag
|
|
| 5 | + ( DynTag
|
|
| 6 | + , tAG_MASK
|
|
| 7 | + , mAX_PTR_TAG
|
|
| 8 | + , isSmallFamily
|
|
| 9 | + ) where
|
|
| 10 | + |
|
| 11 | +import GHC.Prelude
|
|
| 12 | + |
|
| 13 | +import GHC.Platform
|
|
| 14 | + |
|
| 15 | +-- | The tag on a pointer (from the dynamic-tagging paper)
|
|
| 16 | +type DynTag = Int
|
|
| 17 | + |
|
| 18 | +{- Note [Data constructor dynamic tags]
|
|
| 19 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 20 | + |
|
| 21 | +The family size of a data type (the number of constructors
|
|
| 22 | +or the arity of a function) can be either:
|
|
| 23 | + * small, if the family size < 2**tag_bits
|
|
| 24 | + * big, otherwise.
|
|
| 25 | + |
|
| 26 | +Small families can have the constructor tag in the tag bits.
|
|
| 27 | +Big families always use the tag values 1..mAX_PTR_TAG to represent
|
|
| 28 | +evaluatedness, the last one lumping together all overflowing ones.
|
|
| 29 | +We don't have very many tag bits: for example, we have 2 bits on
|
|
| 30 | +x86-32 and 3 bits on x86-64.
|
|
| 31 | + |
|
| 32 | +Also see Note [Tagging big families] in GHC.StgToCmm.Expr
|
|
| 33 | + |
|
| 34 | +The interpreter also needs to be updated if we change the
|
|
| 35 | +tagging strategy; see tagConstr in rts/Interpreter.c.
|
|
| 36 | +-}
|
|
| 37 | + |
|
| 38 | +-- | Tag bits mask / maximum pointer tag value, derived from the
|
|
| 39 | +-- number of tag bits on the platform.
|
|
| 40 | +tAG_MASK, mAX_PTR_TAG :: Platform -> Int
|
|
| 41 | +tAG_MASK platform = (1 `shiftL` pc_TAG_BITS (platformConstants platform)) - 1
|
|
| 42 | +mAX_PTR_TAG = tAG_MASK
|
|
| 43 | + |
|
| 44 | +-- | Is a data type family small enough that each constructor can get
|
|
| 45 | +-- its own pointer tag?
|
|
| 46 | +isSmallFamily :: Platform -> Int -> Bool
|
|
| 47 | +isSmallFamily platform fam_size = fam_size <= mAX_PTR_TAG platform |
| ... | ... | @@ -65,12 +65,12 @@ module GHC.StgToCmm.Closure ( |
| 65 | 65 | |
| 66 | 66 | import GHC.Prelude
|
| 67 | 67 | import GHC.Platform
|
| 68 | +import GHC.Platform.Tag (DynTag, mAX_PTR_TAG, isSmallFamily)
|
|
| 68 | 69 | import GHC.Platform.Profile
|
| 69 | 70 | |
| 70 | 71 | import GHC.Stg.Syntax
|
| 71 | 72 | import GHC.Runtime.Heap.Layout
|
| 72 | 73 | import GHC.Cmm
|
| 73 | -import GHC.Cmm.Utils
|
|
| 74 | 74 | import GHC.StgToCmm.Types
|
| 75 | 75 | import GHC.StgToCmm.Sequel
|
| 76 | 76 | |
| ... | ... | @@ -319,31 +319,6 @@ mkLFStringLit = LFUnlifted |
| 319 | 319 | -- Dynamic pointer tagging
|
| 320 | 320 | -----------------------------------------------------
|
| 321 | 321 | |
| 322 | -type DynTag = Int -- The tag on a *pointer*
|
|
| 323 | - -- (from the dynamic-tagging paper)
|
|
| 324 | - |
|
| 325 | --- Note [Data constructor dynamic tags]
|
|
| 326 | --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 327 | ---
|
|
| 328 | --- The family size of a data type (the number of constructors
|
|
| 329 | --- or the arity of a function) can be either:
|
|
| 330 | --- * small, if the family size < 2**tag_bits
|
|
| 331 | --- * big, otherwise.
|
|
| 332 | ---
|
|
| 333 | --- Small families can have the constructor tag in the tag bits.
|
|
| 334 | --- Big families always use the tag values 1..mAX_PTR_TAG to represent
|
|
| 335 | --- evaluatedness, the last one lumping together all overflowing ones.
|
|
| 336 | --- We don't have very many tag bits: for example, we have 2 bits on
|
|
| 337 | --- x86-32 and 3 bits on x86-64.
|
|
| 338 | ---
|
|
| 339 | --- Also see Note [Tagging big families] in GHC.StgToCmm.Expr
|
|
| 340 | ---
|
|
| 341 | --- The interpreter also needs to be updated if we change the
|
|
| 342 | --- tagging strategy; see tagConstr in rts/Interpreter.c.
|
|
| 343 | - |
|
| 344 | -isSmallFamily :: Platform -> Int -> Bool
|
|
| 345 | -isSmallFamily platform fam_size = fam_size <= mAX_PTR_TAG platform
|
|
| 346 | - |
|
| 347 | 322 | tagForCon :: Platform -> DataCon -> DynTag
|
| 348 | 323 | tagForCon platform con = min (dataConTag con) (mAX_PTR_TAG platform)
|
| 349 | 324 | -- NB: 1-indexed
|
| ... | ... | @@ -35,7 +35,8 @@ import GHC.Cmm.Graph |
| 35 | 35 | import GHC.Cmm.BlockId
|
| 36 | 36 | import GHC.Cmm hiding ( succ )
|
| 37 | 37 | import GHC.Cmm.Info
|
| 38 | -import GHC.Cmm.Utils ( cmmTagMask, mkWordCLit, mAX_PTR_TAG )
|
|
| 38 | +import GHC.Cmm.Utils ( cmmTagMask, mkWordCLit )
|
|
| 39 | +import GHC.Platform.Tag ( mAX_PTR_TAG )
|
|
| 39 | 40 | import GHC.Core
|
| 40 | 41 | import GHC.Core.DataCon
|
| 41 | 42 | import GHC.Types.ForeignCall
|
| ... | ... | @@ -52,7 +52,7 @@ import GHC.Core.Class |
| 52 | 52 | import GHC.Core.Utils( mkCast )
|
| 53 | 53 | import GHC.Core ( Expr(..), mkConApp )
|
| 54 | 54 | |
| 55 | -import GHC.StgToCmm.Closure ( isSmallFamily )
|
|
| 55 | +import GHC.Platform.Tag ( isSmallFamily )
|
|
| 56 | 56 | |
| 57 | 57 | import GHC.Utils.Outputable
|
| 58 | 58 | import GHC.Utils.Panic
|
| ... | ... | @@ -178,6 +178,7 @@ buildDataCon fam_envs dc_bang_opts src_name declared_infix prom_info src_bangs |
| 178 | 178 | -- code, which (for Haskell source anyway) will be in the DataName name
|
| 179 | 179 | -- space, and puts it into the VarName name space
|
| 180 | 180 | |
| 181 | + ; platform <- getPlatform
|
|
| 181 | 182 | ; traceIf (text "buildDataCon 1" <+> ppr src_name)
|
| 182 | 183 | ; us <- newUniqueSupply
|
| 183 | 184 | ; let stupid_ctxt = mkDataConStupidTheta rep_tycon (map scaledThing arg_tys) univ_tvs
|
| ... | ... | @@ -192,7 +193,7 @@ buildDataCon fam_envs dc_bang_opts src_name declared_infix prom_info src_bangs |
| 192 | 193 | stupid_ctxt dc_wrk dc_rep
|
| 193 | 194 | dc_wrk = mkDataConWorkId work_name data_con
|
| 194 | 195 | (dc_rep, impl_bangs, str_marks) =
|
| 195 | - initUs_ us (mkDataConRep dc_bang_opts fam_envs wrap_name data_con)
|
|
| 196 | + initUs_ us (mkDataConRep platform dc_bang_opts fam_envs wrap_name data_con)
|
|
| 196 | 197 | |
| 197 | 198 | ; traceIf (text "buildDataCon 2" <+> ppr src_name)
|
| 198 | 199 | ; return data_con }
|
| ... | ... | @@ -95,6 +95,11 @@ import Data.List ( zipWith4 ) |
| 95 | 95 | import GHC.StgToCmm.Types (LambdaFormInfo(..))
|
| 96 | 96 | import GHC.Runtime.Heap.Layout (ArgDescr(ArgUnknown))
|
| 97 | 97 | |
| 98 | +import GHC.Builtin.PrimOps.Ids (primOpId)
|
|
| 99 | +import GHC.Builtin.PrimOps (PrimOp(..))
|
|
| 100 | +import GHC.Platform (Platform)
|
|
| 101 | +import GHC.Platform.Tag (isSmallFamily)
|
|
| 102 | + |
|
| 98 | 103 | {-
|
| 99 | 104 | ************************************************************************
|
| 100 | 105 | * *
|
| ... | ... | @@ -783,12 +788,13 @@ data BangOpts = BangOpts |
| 783 | 788 | , bang_opt_unbox_small :: !Bool -- ^ Unbox small strict fields
|
| 784 | 789 | }
|
| 785 | 790 | |
| 786 | -mkDataConRep :: DataConBangOpts
|
|
| 791 | +mkDataConRep :: Platform
|
|
| 792 | + -> DataConBangOpts
|
|
| 787 | 793 | -> FamInstEnvs
|
| 788 | 794 | -> Name
|
| 789 | 795 | -> DataCon
|
| 790 | 796 | -> UniqSM (DataConRep, [HsImplBang], [StrictnessMark])
|
| 791 | -mkDataConRep dc_bang_opts fam_envs wrap_name data_con
|
|
| 797 | +mkDataConRep platform dc_bang_opts fam_envs wrap_name data_con
|
|
| 792 | 798 | | not wrapper_reqd
|
| 793 | 799 | = return (NoDataConRep, arg_ibangs, rep_strs)
|
| 794 | 800 | |
| ... | ... | @@ -905,12 +911,12 @@ mkDataConRep dc_bang_opts fam_envs wrap_name data_con |
| 905 | 911 | -- detect this later (see test T2334A)
|
| 906 | 912 | | otherwise
|
| 907 | 913 | = case dc_bang_opts of
|
| 908 | - SrcBangOpts bang_opts -> zipWith (dataConSrcToImplBang bang_opts fam_envs)
|
|
| 914 | + SrcBangOpts bang_opts -> zipWith (dataConSrcToImplBang platform bang_opts fam_envs)
|
|
| 909 | 915 | orig_arg_tys orig_bangs
|
| 910 | 916 | FixedBangOpts bangs -> bangs
|
| 911 | 917 | |
| 912 | 918 | (rep_tys_w_strs, wrappers)
|
| 913 | - = unzip (zipWith dataConArgRep all_arg_tys (ev_ibangs ++ arg_ibangs))
|
|
| 919 | + = unzip (zipWith (dataConArgRep platform) all_arg_tys (ev_ibangs ++ arg_ibangs))
|
|
| 914 | 920 | |
| 915 | 921 | (unboxers, boxers) = unzip wrappers
|
| 916 | 922 | (rep_tys, rep_strs) = unzip (concat rep_tys_w_strs)
|
| ... | ... | @@ -1149,24 +1155,25 @@ newLocal name_stem (Scaled w ty) = |
| 1149 | 1155 | -- never on the field of a newtype constructor.
|
| 1150 | 1156 | -- See @Note [HsImplBangs for newtypes]@.
|
| 1151 | 1157 | dataConSrcToImplBang
|
| 1152 | - :: BangOpts
|
|
| 1158 | + :: Platform
|
|
| 1159 | + -> BangOpts
|
|
| 1153 | 1160 | -> FamInstEnvs
|
| 1154 | 1161 | -> Scaled Type
|
| 1155 | 1162 | -> HsSrcBang
|
| 1156 | 1163 | -> HsImplBang
|
| 1157 | 1164 | |
| 1158 | -dataConSrcToImplBang bang_opts fam_envs arg_ty
|
|
| 1165 | +dataConSrcToImplBang platform bang_opts fam_envs arg_ty
|
|
| 1159 | 1166 | (HsSrcBang ann unpk NoSrcStrict)
|
| 1160 | 1167 | | bang_opt_strict_data bang_opts -- StrictData => strict field
|
| 1161 | - = dataConSrcToImplBang bang_opts fam_envs arg_ty
|
|
| 1168 | + = dataConSrcToImplBang platform bang_opts fam_envs arg_ty
|
|
| 1162 | 1169 | (HsSrcBang ann unpk SrcStrict)
|
| 1163 | 1170 | | otherwise -- no StrictData => lazy field
|
| 1164 | 1171 | = HsLazy
|
| 1165 | 1172 | |
| 1166 | -dataConSrcToImplBang _ _ _ (HsSrcBang _ _ SrcLazy)
|
|
| 1173 | +dataConSrcToImplBang _ _ _ _ (HsSrcBang _ _ SrcLazy)
|
|
| 1167 | 1174 | = HsLazy
|
| 1168 | 1175 | |
| 1169 | -dataConSrcToImplBang bang_opts fam_envs arg_ty
|
|
| 1176 | +dataConSrcToImplBang platform bang_opts fam_envs arg_ty
|
|
| 1170 | 1177 | (HsSrcBang _ unpk_prag SrcStrict)
|
| 1171 | 1178 | | isUnliftedType (scaledThing arg_ty)
|
| 1172 | 1179 | -- NB: non-newtype data constructors can't have representation-polymorphic fields
|
| ... | ... | @@ -1179,7 +1186,7 @@ dataConSrcToImplBang bang_opts fam_envs arg_ty |
| 1179 | 1186 | arg_ty' = case mb_co of
|
| 1180 | 1187 | { Just redn -> scaledSet arg_ty (reductionReducedType redn)
|
| 1181 | 1188 | ; Nothing -> arg_ty }
|
| 1182 | - , shouldUnpackArgTy bang_opts unpk_prag fam_envs arg_ty'
|
|
| 1189 | + , shouldUnpackArgTy platform bang_opts unpk_prag fam_envs arg_ty'
|
|
| 1183 | 1190 | = if bang_opt_unbox_disable bang_opts
|
| 1184 | 1191 | then HsStrict True -- Not unpacking because of -O0
|
| 1185 | 1192 | -- See Note [Detecting useless UNPACK pragmas] in GHC.Core.DataCon
|
| ... | ... | @@ -1193,23 +1200,24 @@ dataConSrcToImplBang bang_opts fam_envs arg_ty |
| 1193 | 1200 | -- | Wrappers/Workers and representation following Unpack/Strictness
|
| 1194 | 1201 | -- decisions
|
| 1195 | 1202 | dataConArgRep
|
| 1196 | - :: Scaled Type
|
|
| 1203 | + :: Platform
|
|
| 1204 | + -> Scaled Type
|
|
| 1197 | 1205 | -> HsImplBang
|
| 1198 | 1206 | -> ([(Scaled Type,StrictnessMark)] -- Rep types
|
| 1199 | 1207 | ,(Unboxer,Boxer))
|
| 1200 | 1208 | |
| 1201 | -dataConArgRep arg_ty HsLazy
|
|
| 1209 | +dataConArgRep _ arg_ty HsLazy
|
|
| 1202 | 1210 | = ([(arg_ty, NotMarkedStrict)], (unitUnboxer, unitBoxer))
|
| 1203 | 1211 | |
| 1204 | -dataConArgRep arg_ty (HsStrict _)
|
|
| 1212 | +dataConArgRep _ arg_ty (HsStrict _)
|
|
| 1205 | 1213 | = ([(arg_ty, MarkedStrict)], (unitUnboxer, unitBoxer)) -- Seqs are inserted in STG
|
| 1206 | 1214 | |
| 1207 | -dataConArgRep arg_ty (HsUnpack Nothing)
|
|
| 1208 | - = dataConArgUnpack arg_ty
|
|
| 1215 | +dataConArgRep platform arg_ty (HsUnpack Nothing)
|
|
| 1216 | + = dataConArgUnpack platform arg_ty
|
|
| 1209 | 1217 | |
| 1210 | -dataConArgRep (Scaled w _) (HsUnpack (Just co))
|
|
| 1218 | +dataConArgRep platform (Scaled w _) (HsUnpack (Just co))
|
|
| 1211 | 1219 | | let co_rep_ty = coercionRKind co
|
| 1212 | - , (rep_tys, wrappers) <- dataConArgUnpack (Scaled w co_rep_ty)
|
|
| 1220 | + , (rep_tys, wrappers) <- dataConArgUnpack platform (Scaled w co_rep_ty)
|
|
| 1213 | 1221 | = (rep_tys, wrapCo co co_rep_ty wrappers)
|
| 1214 | 1222 | |
| 1215 | 1223 | |
| ... | ... | @@ -1334,19 +1342,92 @@ problem entirely by treating sums and products differently here. |
| 1334 | 1342 | -}
|
| 1335 | 1343 | |
| 1336 | 1344 | dataConArgUnpack
|
| 1337 | - :: Scaled Type
|
|
| 1345 | + :: Platform
|
|
| 1346 | + -> Scaled Type
|
|
| 1338 | 1347 | -> ( [(Scaled Type, StrictnessMark)] -- Rep types
|
| 1339 | 1348 | , (Unboxer, Boxer) )
|
| 1340 | -dataConArgUnpack scaledTy@(Scaled _ arg_ty)
|
|
| 1349 | +dataConArgUnpack platform scaledTy@(Scaled _ arg_ty)
|
|
| 1341 | 1350 | | Just (tc, tc_args) <- splitTyConApp_maybe arg_ty
|
| 1342 | 1351 | = assert (not (isNewTyCon tc)) $
|
| 1343 | 1352 | case tyConDataCons tc of
|
| 1344 | 1353 | [con] -> dataConArgUnpackProduct scaledTy tc_args con
|
| 1354 | + cons | all (null . dataConOrigArgTys) cons
|
|
| 1355 | + -> dataConArgUnpackEnum platform scaledTy tc_args cons
|
|
| 1345 | 1356 | cons -> dataConArgUnpackSum scaledTy tc_args cons
|
| 1346 | 1357 | | otherwise
|
| 1347 | 1358 | = pprPanic "dataConArgUnpack" (ppr arg_ty)
|
| 1348 | 1359 | -- An interface file specified Unpacked, but we couldn't unpack it
|
| 1349 | 1360 | |
| 1361 | +{- Note [UNPACK for enum types]
|
|
| 1362 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1363 | +When a strict field has an enumeration type (all constructors are nullary),
|
|
| 1364 | +we unpack it to a single narrow primitive word rather than an unboxed sum.
|
|
| 1365 | + |
|
| 1366 | +For example, given:
|
|
| 1367 | + data Color = Red | Green | Blue
|
|
| 1368 | + data Foo = MkFoo {-# UNPACK #-} !Color
|
|
| 1369 | + |
|
| 1370 | +the worker for MkFoo will have a Word8# field.
|
|
| 1371 | + |
|
| 1372 | +Avoiding the intermediate unboxed sum allows us to use branchless conversion
|
|
| 1373 | +operations DataToTag and TagToEnum.
|
|
| 1374 | +-}
|
|
| 1375 | + |
|
| 1376 | +dataConArgUnpackEnum
|
|
| 1377 | + :: Platform
|
|
| 1378 | + -> Scaled Type
|
|
| 1379 | + -> [Type]
|
|
| 1380 | + -> [DataCon]
|
|
| 1381 | + -> ( [(Scaled Type, StrictnessMark)] -- Rep types
|
|
| 1382 | + , (Unboxer, Boxer) )
|
|
| 1383 | +dataConArgUnpackEnum platform (Scaled arg_mult ty) _tc_args cons =
|
|
| 1384 | + ( [ (scaled_enum_ty, MarkedStrict) ] -- See Note [UNPACK for enum types]
|
|
| 1385 | + , ( unboxer, boxer ) )
|
|
| 1386 | + where
|
|
| 1387 | + !enum_sum_arity = length cons
|
|
| 1388 | + conv op e = App (Var (primOpId op)) e
|
|
| 1389 | + |
|
| 1390 | + conv_tag_levpoly op e = App (mkTyApps (Var (primOpId op)) [getLevity ty, ty]) e
|
|
| 1391 | + |
|
| 1392 | + (enum_ty, unbox_convert, box_convert)
|
|
| 1393 | + | enum_sum_arity < 256 = (word8PrimTy, conv WordToWord8Op, conv Word8ToWordOp)
|
|
| 1394 | + | enum_sum_arity < 65536 = (word16PrimTy, conv WordToWord16Op, conv Word16ToWordOp)
|
|
| 1395 | + | otherwise = (wordPrimTy, id, id)
|
|
| 1396 | + scaled_enum_ty = Scaled arg_mult enum_ty
|
|
| 1397 | + |
|
| 1398 | + datatotag_op
|
|
| 1399 | + | isSmallFamily platform enum_sum_arity = DataToTagSmallOp
|
|
| 1400 | + | otherwise = DataToTagLargeOp
|
|
| 1401 | + |
|
| 1402 | + -- Tags are 1-based: add 1 to 0-based DataToTag result
|
|
| 1403 | + add_one e = App (App (Var (primOpId IntAddOp)) e)
|
|
| 1404 | + (Lit (LitNumber LitNumInt 1))
|
|
| 1405 | + -- Subtract 1 to convert back to 0-based for TagToEnum
|
|
| 1406 | + sub_one e = App (App (Var (primOpId IntSubOp)) e)
|
|
| 1407 | + (Lit (LitNumber LitNumInt 1))
|
|
| 1408 | + |
|
| 1409 | + unboxer v = do enum_rep_id <- newLocal (fsLit "unbx_enum") scaled_enum_ty
|
|
| 1410 | + let unbox_fn body
|
|
| 1411 | + = mkSingleAltCase
|
|
| 1412 | + (unbox_convert (App (Var (primOpId IntToWordOp))
|
|
| 1413 | + (add_one (conv_tag_levpoly datatotag_op (Var v)))))
|
|
| 1414 | + enum_rep_id
|
|
| 1415 | + DEFAULT
|
|
| 1416 | + []
|
|
| 1417 | + body
|
|
| 1418 | + return ([enum_rep_id], unbox_fn)
|
|
| 1419 | + |
|
| 1420 | + boxer = Boxer $ \ subst -> do
|
|
| 1421 | + let ty' = TcType.substTyUnchecked subst ty
|
|
| 1422 | + conv_tag' op e = App (mkTyApps (Var (primOpId op)) [ty']) e
|
|
| 1423 | + enum_rep_id <- newLocal (fsLit "bx_enum")
|
|
| 1424 | + (TcType.substScaledTyUnchecked subst scaled_enum_ty)
|
|
| 1425 | + let box_fn = conv_tag'
|
|
| 1426 | + TagToEnumOp
|
|
| 1427 | + (sub_one (App (Var (primOpId WordToIntOp))
|
|
| 1428 | + (box_convert (Var enum_rep_id))))
|
|
| 1429 | + return ([enum_rep_id], box_fn)
|
|
| 1430 | + |
|
| 1350 | 1431 | dataConArgUnpackProduct
|
| 1351 | 1432 | :: Scaled Type
|
| 1352 | 1433 | -> [Type]
|
| ... | ... | @@ -1452,13 +1533,13 @@ mkUbxSumAltTy :: [Type] -> Type |
| 1452 | 1533 | mkUbxSumAltTy [ty] = ty
|
| 1453 | 1534 | mkUbxSumAltTy tys = mkTupleTy Unboxed tys
|
| 1454 | 1535 | |
| 1455 | -shouldUnpackArgTy :: BangOpts -> SrcUnpackedness -> FamInstEnvs -> Scaled Type -> Bool
|
|
| 1536 | +shouldUnpackArgTy :: Platform -> BangOpts -> SrcUnpackedness -> FamInstEnvs -> Scaled Type -> Bool
|
|
| 1456 | 1537 | -- True if we ought to unpack the UNPACK the argument type
|
| 1457 | 1538 | -- See Note [Recursive unboxing]
|
| 1458 | 1539 | -- We look "deeply" inside rather than relying on the DataCons
|
| 1459 | 1540 | -- we encounter on the way, because otherwise we might well
|
| 1460 | 1541 | -- end up relying on ourselves!
|
| 1461 | -shouldUnpackArgTy bang_opts prag fam_envs arg_ty
|
|
| 1542 | +shouldUnpackArgTy platform bang_opts prag fam_envs arg_ty
|
|
| 1462 | 1543 | | Just data_cons <- unpackable_type_datacons (scaledThing arg_ty)
|
| 1463 | 1544 | , all ok_con data_cons -- Returns True only if we can't get a
|
| 1464 | 1545 | -- loop involving these data cons
|
| ... | ... | @@ -1534,7 +1615,7 @@ shouldUnpackArgTy bang_opts prag fam_envs arg_ty |
| 1534 | 1615 | || (bang_opt_unbox_small bang_opts
|
| 1535 | 1616 | && is_small_rep) -- See Note [Unpack one-wide fields]
|
| 1536 | 1617 | where
|
| 1537 | - (rep_tys, _) = dataConArgUnpack arg_ty
|
|
| 1618 | + (rep_tys, _) = dataConArgUnpack platform arg_ty
|
|
| 1538 | 1619 | |
| 1539 | 1620 | -- Takes in the list of reps used to represent the dataCon after it's unpacked
|
| 1540 | 1621 | -- and tells us if they can fit into 8 bytes. See Note [Unpack one-wide fields]
|
| ... | ... | @@ -228,7 +228,7 @@ ubxSumRepType constrs0 |
| 228 | 228 | rep :: [PrimRep] -> SortedSlotTys
|
| 229 | 229 | rep ty = sort (map primRepSlot ty)
|
| 230 | 230 | |
| 231 | - -- constructors start at 1, pick an appropriate slot size for the tag
|
|
| 231 | + -- constructors are 1-based, pick an appropriate slot size for the tag
|
|
| 232 | 232 | tag_slot | length constrs0 < 256 = Word8Slot
|
| 233 | 233 | | length constrs0 < 65536 = Word16Slot
|
| 234 | 234 | -- we use 2147483647 instead of 4294967296 to avoid
|
| ... | ... | @@ -675,6 +675,7 @@ Library |
| 675 | 675 | GHC.Platform.NoRegs
|
| 676 | 676 | GHC.Platform.PPC
|
| 677 | 677 | GHC.Platform.Profile
|
| 678 | + GHC.Platform.Tag
|
|
| 678 | 679 | GHC.Platform.Reg
|
| 679 | 680 | GHC.Platform.Reg.Class
|
| 680 | 681 | GHC.Platform.Reg.Class.NoVectors
|
| 1 | 1 | Found Language.Haskell.Syntax module dependencies
|
| 2 | 2 | GHC.Builtin.Names
|
| 3 | 3 | GHC.Builtin.PrimOps
|
| 4 | +GHC.Builtin.PrimOps.Ids
|
|
| 4 | 5 | GHC.Builtin.Types
|
| 5 | 6 | GHC.Builtin.Types.Literals
|
| 6 | 7 | GHC.Builtin.Types.Prim
|
| ... | ... | @@ -8,6 +9,7 @@ GHC.Builtin.Uniques |
| 8 | 9 | GHC.Cmm.BlockId
|
| 9 | 10 | GHC.Cmm.CLabel
|
| 10 | 11 | GHC.Cmm.Dataflow.Label
|
| 12 | +GHC.Cmm.MachOp
|
|
| 11 | 13 | GHC.Cmm.Type
|
| 12 | 14 | GHC.CmmToAsm.CFG.Weight
|
| 13 | 15 | GHC.Core
|
| ... | ... | @@ -21,10 +23,12 @@ GHC.Core.FVs |
| 21 | 23 | GHC.Core.FamInstEnv
|
| 22 | 24 | GHC.Core.InstEnv
|
| 23 | 25 | GHC.Core.Make
|
| 26 | +GHC.Core.Map.Expr
|
|
| 24 | 27 | GHC.Core.Map.Type
|
| 25 | 28 | GHC.Core.Multiplicity
|
| 26 | 29 | GHC.Core.Opt.Arity
|
| 27 | 30 | GHC.Core.Opt.CallerCC.Types
|
| 31 | +GHC.Core.Opt.ConstantFold
|
|
| 28 | 32 | GHC.Core.Opt.OccurAnal
|
| 29 | 33 | GHC.Core.PatSyn
|
| 30 | 34 | GHC.Core.Ppr
|
| ... | ... | @@ -118,6 +122,7 @@ GHC.Parser.Errors.Basic |
| 118 | 122 | GHC.Platform
|
| 119 | 123 | GHC.Platform.Constants
|
| 120 | 124 | GHC.Platform.Profile
|
| 125 | +GHC.Platform.Tag
|
|
| 121 | 126 | GHC.Platform.Ways
|
| 122 | 127 | GHC.Prelude
|
| 123 | 128 | GHC.Prelude.Basic
|
| 1 | 1 | Found GHC.Parser module dependencies
|
| 2 | 2 | GHC.Builtin.Names
|
| 3 | 3 | GHC.Builtin.PrimOps
|
| 4 | +GHC.Builtin.PrimOps.Ids
|
|
| 4 | 5 | GHC.Builtin.Types
|
| 5 | 6 | GHC.Builtin.Types.Literals
|
| 6 | 7 | GHC.Builtin.Types.Prim
|
| ... | ... | @@ -8,6 +9,7 @@ GHC.Builtin.Uniques |
| 8 | 9 | GHC.Cmm.BlockId
|
| 9 | 10 | GHC.Cmm.CLabel
|
| 10 | 11 | GHC.Cmm.Dataflow.Label
|
| 12 | +GHC.Cmm.MachOp
|
|
| 11 | 13 | GHC.Cmm.Type
|
| 12 | 14 | GHC.CmmToAsm.CFG.Weight
|
| 13 | 15 | GHC.Core
|
| ... | ... | @@ -26,6 +28,7 @@ GHC.Core.Map.Type |
| 26 | 28 | GHC.Core.Multiplicity
|
| 27 | 29 | GHC.Core.Opt.Arity
|
| 28 | 30 | GHC.Core.Opt.CallerCC.Types
|
| 31 | +GHC.Core.Opt.ConstantFold
|
|
| 29 | 32 | GHC.Core.Opt.OccurAnal
|
| 30 | 33 | GHC.Core.PatSyn
|
| 31 | 34 | GHC.Core.Ppr
|
| ... | ... | @@ -137,6 +140,7 @@ GHC.Parser.Types |
| 137 | 140 | GHC.Platform
|
| 138 | 141 | GHC.Platform.Constants
|
| 139 | 142 | GHC.Platform.Profile
|
| 143 | +GHC.Platform.Tag
|
|
| 140 | 144 | GHC.Platform.Ways
|
| 141 | 145 | GHC.Prelude
|
| 142 | 146 | GHC.Prelude.Basic
|
| ... | ... | @@ -20,4 +20,5 @@ test('T13536a', |
| 20 | 20 | |
| 21 | 21 | test('inferTags001', normal, multimod_compile_and_run, ['inferTags001', 'inferTags001_a'])
|
| 22 | 22 | test('T22042', [extra_files(['T22042a.hs']),only_ways('normal'),unless(have_dynamic(), skip)], makefile_test, ['T22042'])
|
| 23 | -test('T23783', normal, multimod_compile_and_run, ['T23783', '-O -v0']) |
|
| \ No newline at end of file | ||
| 23 | +test('T23783', normal, multimod_compile_and_run, ['T23783', '-O -v0'])
|
|
| 24 | +test('unpack_enum', normal, compile_and_run, ['']) |
|
| \ No newline at end of file |
| 1 | +{-# LANGUAGE MagicHash #-}
|
|
| 2 | + |
|
| 3 | +-- | Test branchless enum unboxing.
|
|
| 4 | +-- See Note [UNPACK for enum types] in GHC.Types.Id.Make.
|
|
| 5 | +--
|
|
| 6 | +-- When a strict field has an enumeration type (all nullary constructors),
|
|
| 7 | +-- it should be unpacked to a single narrow primitive word (Word8#, Word16#,
|
|
| 8 | +-- or Word#) rather than an unboxed sum, using dataToTag#/tagToEnum# for
|
|
| 9 | +-- branchless conversion.
|
|
| 10 | + |
|
| 11 | +module Main where
|
|
| 12 | + |
|
| 13 | +import GHC.Exts.Heap.Closures (closureSize, asBox)
|
|
| 14 | +import Control.Exception (evaluate)
|
|
| 15 | + |
|
| 16 | +------------------------------------------------------------
|
|
| 17 | +-- Small enum (2 constructors, like Bool)
|
|
| 18 | +------------------------------------------------------------
|
|
| 19 | + |
|
| 20 | +data Toggle = Off | On
|
|
| 21 | + deriving (Show, Eq)
|
|
| 22 | + |
|
| 23 | +data BoxToggle = BoxToggle {-# UNPACK #-} !Toggle
|
|
| 24 | + {-# UNPACK #-} !Toggle
|
|
| 25 | + deriving (Show)
|
|
| 26 | + |
|
| 27 | +------------------------------------------------------------
|
|
| 28 | +-- Medium enum (5 constructors)
|
|
| 29 | +------------------------------------------------------------
|
|
| 30 | + |
|
| 31 | +data Color = Red | Green | Blue | Yellow | Purple
|
|
| 32 | + deriving (Show, Eq)
|
|
| 33 | + |
|
| 34 | +data BoxColor = BoxColor {-# UNPACK #-} !Color
|
|
| 35 | + {-# UNPACK #-} !Color
|
|
| 36 | + deriving (Show)
|
|
| 37 | + |
|
| 38 | +------------------------------------------------------------
|
|
| 39 | +-- Phantom type parameter enum
|
|
| 40 | +-- Tests that the boxer correctly substitutes type variables.
|
|
| 41 | +------------------------------------------------------------
|
|
| 42 | + |
|
| 43 | +data Proxy a = PA | PB | PC
|
|
| 44 | + deriving (Show, Eq)
|
|
| 45 | + |
|
| 46 | +data BoxProxy = BoxProxy {-# UNPACK #-} !(Proxy Int)
|
|
| 47 | + {-# UNPACK #-} !(Proxy Char)
|
|
| 48 | + deriving (Show)
|
|
| 49 | + |
|
| 50 | +------------------------------------------------------------
|
|
| 51 | +-- Enum with exactly 255 constructors (boundary for Word8#)
|
|
| 52 | +-- With 1-based tags, 255 constructors have tags 1-255 which
|
|
| 53 | +-- fit in Word8#.
|
|
| 54 | +------------------------------------------------------------
|
|
| 55 | + |
|
| 56 | +data E255
|
|
| 57 | + = E255_0 | E255_1 | E255_2 | E255_3 | E255_4 | E255_5 | E255_6 | E255_7
|
|
| 58 | + | E255_8 | E255_9 | E255_10 | E255_11 | E255_12 | E255_13 | E255_14 | E255_15
|
|
| 59 | + | E255_16 | E255_17 | E255_18 | E255_19 | E255_20 | E255_21 | E255_22 | E255_23
|
|
| 60 | + | E255_24 | E255_25 | E255_26 | E255_27 | E255_28 | E255_29 | E255_30 | E255_31
|
|
| 61 | + | E255_32 | E255_33 | E255_34 | E255_35 | E255_36 | E255_37 | E255_38 | E255_39
|
|
| 62 | + | E255_40 | E255_41 | E255_42 | E255_43 | E255_44 | E255_45 | E255_46 | E255_47
|
|
| 63 | + | E255_48 | E255_49 | E255_50 | E255_51 | E255_52 | E255_53 | E255_54 | E255_55
|
|
| 64 | + | E255_56 | E255_57 | E255_58 | E255_59 | E255_60 | E255_61 | E255_62 | E255_63
|
|
| 65 | + | E255_64 | E255_65 | E255_66 | E255_67 | E255_68 | E255_69 | E255_70 | E255_71
|
|
| 66 | + | E255_72 | E255_73 | E255_74 | E255_75 | E255_76 | E255_77 | E255_78 | E255_79
|
|
| 67 | + | E255_80 | E255_81 | E255_82 | E255_83 | E255_84 | E255_85 | E255_86 | E255_87
|
|
| 68 | + | E255_88 | E255_89 | E255_90 | E255_91 | E255_92 | E255_93 | E255_94 | E255_95
|
|
| 69 | + | E255_96 | E255_97 | E255_98 | E255_99 | E255_100 | E255_101 | E255_102 | E255_103
|
|
| 70 | + | E255_104 | E255_105 | E255_106 | E255_107 | E255_108 | E255_109 | E255_110 | E255_111
|
|
| 71 | + | E255_112 | E255_113 | E255_114 | E255_115 | E255_116 | E255_117 | E255_118 | E255_119
|
|
| 72 | + | E255_120 | E255_121 | E255_122 | E255_123 | E255_124 | E255_125 | E255_126 | E255_127
|
|
| 73 | + | E255_128 | E255_129 | E255_130 | E255_131 | E255_132 | E255_133 | E255_134 | E255_135
|
|
| 74 | + | E255_136 | E255_137 | E255_138 | E255_139 | E255_140 | E255_141 | E255_142 | E255_143
|
|
| 75 | + | E255_144 | E255_145 | E255_146 | E255_147 | E255_148 | E255_149 | E255_150 | E255_151
|
|
| 76 | + | E255_152 | E255_153 | E255_154 | E255_155 | E255_156 | E255_157 | E255_158 | E255_159
|
|
| 77 | + | E255_160 | E255_161 | E255_162 | E255_163 | E255_164 | E255_165 | E255_166 | E255_167
|
|
| 78 | + | E255_168 | E255_169 | E255_170 | E255_171 | E255_172 | E255_173 | E255_174 | E255_175
|
|
| 79 | + | E255_176 | E255_177 | E255_178 | E255_179 | E255_180 | E255_181 | E255_182 | E255_183
|
|
| 80 | + | E255_184 | E255_185 | E255_186 | E255_187 | E255_188 | E255_189 | E255_190 | E255_191
|
|
| 81 | + | E255_192 | E255_193 | E255_194 | E255_195 | E255_196 | E255_197 | E255_198 | E255_199
|
|
| 82 | + | E255_200 | E255_201 | E255_202 | E255_203 | E255_204 | E255_205 | E255_206 | E255_207
|
|
| 83 | + | E255_208 | E255_209 | E255_210 | E255_211 | E255_212 | E255_213 | E255_214 | E255_215
|
|
| 84 | + | E255_216 | E255_217 | E255_218 | E255_219 | E255_220 | E255_221 | E255_222 | E255_223
|
|
| 85 | + | E255_224 | E255_225 | E255_226 | E255_227 | E255_228 | E255_229 | E255_230 | E255_231
|
|
| 86 | + | E255_232 | E255_233 | E255_234 | E255_235 | E255_236 | E255_237 | E255_238 | E255_239
|
|
| 87 | + | E255_240 | E255_241 | E255_242 | E255_243 | E255_244 | E255_245 | E255_246 | E255_247
|
|
| 88 | + | E255_248 | E255_249 | E255_250 | E255_251 | E255_252 | E255_253 | E255_254
|
|
| 89 | + deriving (Show, Eq, Enum, Bounded)
|
|
| 90 | + |
|
| 91 | +-- Two E255 fields should fit in a single word (2 x Word8# = 2 bytes),
|
|
| 92 | +-- so the closure should be header (1 word) + 1 payload word = size 2.
|
|
| 93 | +data BoxE255 = BoxE255 {-# UNPACK #-} !E255
|
|
| 94 | + {-# UNPACK #-} !E255
|
|
| 95 | + deriving (Show)
|
|
| 96 | + |
|
| 97 | +------------------------------------------------------------
|
|
| 98 | +-- Enum with exactly 256 constructors (just over Word8# boundary).
|
|
| 99 | +-- With 1-based tags, tag 256 does not fit in Word8#,
|
|
| 100 | +-- so this should use Word16# instead.
|
|
| 101 | +------------------------------------------------------------
|
|
| 102 | + |
|
| 103 | +data E256
|
|
| 104 | + = E256_0 | E256_1 | E256_2 | E256_3 | E256_4 | E256_5 | E256_6 | E256_7
|
|
| 105 | + | E256_8 | E256_9 | E256_10 | E256_11 | E256_12 | E256_13 | E256_14 | E256_15
|
|
| 106 | + | E256_16 | E256_17 | E256_18 | E256_19 | E256_20 | E256_21 | E256_22 | E256_23
|
|
| 107 | + | E256_24 | E256_25 | E256_26 | E256_27 | E256_28 | E256_29 | E256_30 | E256_31
|
|
| 108 | + | E256_32 | E256_33 | E256_34 | E256_35 | E256_36 | E256_37 | E256_38 | E256_39
|
|
| 109 | + | E256_40 | E256_41 | E256_42 | E256_43 | E256_44 | E256_45 | E256_46 | E256_47
|
|
| 110 | + | E256_48 | E256_49 | E256_50 | E256_51 | E256_52 | E256_53 | E256_54 | E256_55
|
|
| 111 | + | E256_56 | E256_57 | E256_58 | E256_59 | E256_60 | E256_61 | E256_62 | E256_63
|
|
| 112 | + | E256_64 | E256_65 | E256_66 | E256_67 | E256_68 | E256_69 | E256_70 | E256_71
|
|
| 113 | + | E256_72 | E256_73 | E256_74 | E256_75 | E256_76 | E256_77 | E256_78 | E256_79
|
|
| 114 | + | E256_80 | E256_81 | E256_82 | E256_83 | E256_84 | E256_85 | E256_86 | E256_87
|
|
| 115 | + | E256_88 | E256_89 | E256_90 | E256_91 | E256_92 | E256_93 | E256_94 | E256_95
|
|
| 116 | + | E256_96 | E256_97 | E256_98 | E256_99 | E256_100 | E256_101 | E256_102 | E256_103
|
|
| 117 | + | E256_104 | E256_105 | E256_106 | E256_107 | E256_108 | E256_109 | E256_110 | E256_111
|
|
| 118 | + | E256_112 | E256_113 | E256_114 | E256_115 | E256_116 | E256_117 | E256_118 | E256_119
|
|
| 119 | + | E256_120 | E256_121 | E256_122 | E256_123 | E256_124 | E256_125 | E256_126 | E256_127
|
|
| 120 | + | E256_128 | E256_129 | E256_130 | E256_131 | E256_132 | E256_133 | E256_134 | E256_135
|
|
| 121 | + | E256_136 | E256_137 | E256_138 | E256_139 | E256_140 | E256_141 | E256_142 | E256_143
|
|
| 122 | + | E256_144 | E256_145 | E256_146 | E256_147 | E256_148 | E256_149 | E256_150 | E256_151
|
|
| 123 | + | E256_152 | E256_153 | E256_154 | E256_155 | E256_156 | E256_157 | E256_158 | E256_159
|
|
| 124 | + | E256_160 | E256_161 | E256_162 | E256_163 | E256_164 | E256_165 | E256_166 | E256_167
|
|
| 125 | + | E256_168 | E256_169 | E256_170 | E256_171 | E256_172 | E256_173 | E256_174 | E256_175
|
|
| 126 | + | E256_176 | E256_177 | E256_178 | E256_179 | E256_180 | E256_181 | E256_182 | E256_183
|
|
| 127 | + | E256_184 | E256_185 | E256_186 | E256_187 | E256_188 | E256_189 | E256_190 | E256_191
|
|
| 128 | + | E256_192 | E256_193 | E256_194 | E256_195 | E256_196 | E256_197 | E256_198 | E256_199
|
|
| 129 | + | E256_200 | E256_201 | E256_202 | E256_203 | E256_204 | E256_205 | E256_206 | E256_207
|
|
| 130 | + | E256_208 | E256_209 | E256_210 | E256_211 | E256_212 | E256_213 | E256_214 | E256_215
|
|
| 131 | + | E256_216 | E256_217 | E256_218 | E256_219 | E256_220 | E256_221 | E256_222 | E256_223
|
|
| 132 | + | E256_224 | E256_225 | E256_226 | E256_227 | E256_228 | E256_229 | E256_230 | E256_231
|
|
| 133 | + | E256_232 | E256_233 | E256_234 | E256_235 | E256_236 | E256_237 | E256_238 | E256_239
|
|
| 134 | + | E256_240 | E256_241 | E256_242 | E256_243 | E256_244 | E256_245 | E256_246 | E256_247
|
|
| 135 | + | E256_248 | E256_249 | E256_250 | E256_251 | E256_252 | E256_253 | E256_254 | E256_255
|
|
| 136 | + deriving (Show, Eq, Enum, Bounded)
|
|
| 137 | + |
|
| 138 | +data BoxE256 = BoxE256 {-# UNPACK #-} !E256
|
|
| 139 | + {-# UNPACK #-} !E256
|
|
| 140 | + deriving (Show)
|
|
| 141 | + |
|
| 142 | +------------------------------------------------------------
|
|
| 143 | +-- Boundary size comparison: 5 fields of E255 (Word8#) vs E256 (Word16#)
|
|
| 144 | +-- With 5 fields, Word8# fits in fewer payload words than Word16#
|
|
| 145 | +-- on all platforms, so we can verify the packing difference.
|
|
| 146 | +------------------------------------------------------------
|
|
| 147 | + |
|
| 148 | +data Box5xE255 = Box5xE255 {-# UNPACK #-} !E255
|
|
| 149 | + {-# UNPACK #-} !E255
|
|
| 150 | + {-# UNPACK #-} !E255
|
|
| 151 | + {-# UNPACK #-} !E255
|
|
| 152 | + {-# UNPACK #-} !E255
|
|
| 153 | + |
|
| 154 | +data Box5xE256 = Box5xE256 {-# UNPACK #-} !E256
|
|
| 155 | + {-# UNPACK #-} !E256
|
|
| 156 | + {-# UNPACK #-} !E256
|
|
| 157 | + {-# UNPACK #-} !E256
|
|
| 158 | + {-# UNPACK #-} !E256
|
|
| 159 | + |
|
| 160 | +------------------------------------------------------------
|
|
| 161 | +-- Test helpers
|
|
| 162 | +------------------------------------------------------------
|
|
| 163 | + |
|
| 164 | +test :: Show a => String -> a -> IO ()
|
|
| 165 | +test name value = do
|
|
| 166 | + putStrLn $ "### " ++ name
|
|
| 167 | + value' <- evaluate value
|
|
| 168 | + print value'
|
|
| 169 | + putStrLn ("size: " ++ show (closureSize $ asBox value'))
|
|
| 170 | + putStrLn ""
|
|
| 171 | + |
|
| 172 | +main :: IO ()
|
|
| 173 | +main = do
|
|
| 174 | + -- Small enum: all constructor combinations
|
|
| 175 | + test "toggle_off_off" (BoxToggle Off Off)
|
|
| 176 | + test "toggle_on_on" (BoxToggle On On)
|
|
| 177 | + test "toggle_off_on" (BoxToggle Off On)
|
|
| 178 | + |
|
| 179 | + -- Medium enum: first, last, and middle constructors
|
|
| 180 | + test "color_first" (BoxColor Red Red)
|
|
| 181 | + test "color_last" (BoxColor Purple Purple)
|
|
| 182 | + test "color_mixed" (BoxColor Green Yellow)
|
|
| 183 | + |
|
| 184 | + -- Phantom type parameter: tests boxer substitution
|
|
| 185 | + test "proxy" (BoxProxy PB PC)
|
|
| 186 | + |
|
| 187 | + -- 255-constructor enum (boundary): first and last tags
|
|
| 188 | + test "e255_first" (BoxE255 E255_0 E255_0)
|
|
| 189 | + test "e255_last" (BoxE255 E255_254 E255_254)
|
|
| 190 | + test "e255_mixed" (BoxE255 E255_0 E255_254)
|
|
| 191 | + |
|
| 192 | + -- 256-constructor enum (just over Word8# boundary): first, last, and mixed
|
|
| 193 | + test "e256_first" (BoxE256 E256_0 E256_0)
|
|
| 194 | + test "e256_last" (BoxE256 E256_255 E256_255)
|
|
| 195 | + test "e256_mixed" (BoxE256 E256_0 E256_255)
|
|
| 196 | + |
|
| 197 | + -- Boundary size comparison: E255 uses Word8# (1 byte per field),
|
|
| 198 | + -- E256 uses Word16# (2 bytes per field). With 5 fields, the Word16#
|
|
| 199 | + -- version needs more payload words than the Word8# version.
|
|
| 200 | + b255 <- evaluate (Box5xE255 E255_0 E255_127 E255_254 E255_0 E255_127)
|
|
| 201 | + b256 <- evaluate (Box5xE256 E256_0 E256_128 E256_255 E256_0 E256_128)
|
|
| 202 | + let s255 = closureSize (asBox b255)
|
|
| 203 | + let s256 = closureSize (asBox b256)
|
|
| 204 | + putStrLn "### boundary_size_check"
|
|
| 205 | + putStrLn $ "e256 (5 x Word16#) larger than e255 (5 x Word8#): " ++ show (s256 > s255)
|
|
| 206 | + putStrLn "" |
| 1 | +### toggle_off_off
|
|
| 2 | +BoxToggle Off Off
|
|
| 3 | +size: 2
|
|
| 4 | + |
|
| 5 | +### toggle_on_on
|
|
| 6 | +BoxToggle On On
|
|
| 7 | +size: 2
|
|
| 8 | + |
|
| 9 | +### toggle_off_on
|
|
| 10 | +BoxToggle Off On
|
|
| 11 | +size: 2
|
|
| 12 | + |
|
| 13 | +### color_first
|
|
| 14 | +BoxColor Red Red
|
|
| 15 | +size: 2
|
|
| 16 | + |
|
| 17 | +### color_last
|
|
| 18 | +BoxColor Purple Purple
|
|
| 19 | +size: 2
|
|
| 20 | + |
|
| 21 | +### color_mixed
|
|
| 22 | +BoxColor Green Yellow
|
|
| 23 | +size: 2
|
|
| 24 | + |
|
| 25 | +### proxy
|
|
| 26 | +BoxProxy PB PC
|
|
| 27 | +size: 2
|
|
| 28 | + |
|
| 29 | +### e255_first
|
|
| 30 | +BoxE255 E255_0 E255_0
|
|
| 31 | +size: 2
|
|
| 32 | + |
|
| 33 | +### e255_last
|
|
| 34 | +BoxE255 E255_254 E255_254
|
|
| 35 | +size: 2
|
|
| 36 | + |
|
| 37 | +### e255_mixed
|
|
| 38 | +BoxE255 E255_0 E255_254
|
|
| 39 | +size: 2
|
|
| 40 | + |
|
| 41 | +### e256_first
|
|
| 42 | +BoxE256 E256_0 E256_0
|
|
| 43 | +size: 2
|
|
| 44 | + |
|
| 45 | +### e256_last
|
|
| 46 | +BoxE256 E256_255 E256_255
|
|
| 47 | +size: 2
|
|
| 48 | + |
|
| 49 | +### e256_mixed
|
|
| 50 | +BoxE256 E256_0 E256_255
|
|
| 51 | +size: 2
|
|
| 52 | + |
|
| 53 | +### boundary_size_check
|
|
| 54 | +e256 (5 x Word16#) larger than e255 (5 x Word8#): True
|
|
| 55 | + |