Andreas Klebinger pushed to branch wip/andreask/cbv_array at Glasgow Haskell Compiler / GHC
Commits:
-
471d9a01
by Andreas Klebinger at 2025-11-09T17:32:56+01:00
17 changed files:
- compiler/GHC/Builtin/PrimOps.hs
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/Stg/EnforceEpt.hs
- compiler/GHC/Stg/EnforceEpt/Rewrite.hs
- compiler/GHC/StgToCmm/Prim.hs
- compiler/GHC/StgToJS/Prim.hs
- compiler/GHC/Types/Id.hs
- compiler/GHC/Types/Id/Info.hs
- compiler/Setup.hs
- hadrian/src/Rules/Generate.hs
- hadrian/src/Rules/Lint.hs
- hadrian/src/Settings/Builders/GenPrimopCode.hs
- utils/genprimopcode/Lexer.x
- utils/genprimopcode/Main.hs
- utils/genprimopcode/Parser.y
- utils/genprimopcode/ParserM.hs
- utils/genprimopcode/Syntax.hs
Changes:
| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | |
| 10 | 10 | module GHC.Builtin.PrimOps (
|
| 11 | 11 | PrimOp(..), PrimOpVecCat(..), allThePrimOps,
|
| 12 | - primOpType, primOpSig, primOpResultType,
|
|
| 12 | + primOpType, primOpSig, primOpResultType, primOpCbv,
|
|
| 13 | 13 | primOpTag, maxPrimOpTag, primOpOcc,
|
| 14 | 14 | primOpWrapperId,
|
| 15 | 15 | pprPrimOp,
|
| ... | ... | @@ -146,6 +146,22 @@ primOpStrictness :: PrimOp -> Arity -> DmdSig |
| 146 | 146 | -- this function isn't exported.
|
| 147 | 147 | #include "primop-strictness.hs-incl"
|
| 148 | 148 | |
| 149 | +{-
|
|
| 150 | +************************************************************************
|
|
| 151 | +* *
|
|
| 152 | +\subsubsection{Call by value info}
|
|
| 153 | +* *
|
|
| 154 | +************************************************************************
|
|
| 155 | + |
|
| 156 | +Some primops require us to only pass evaluated and properly tagged
|
|
| 157 | +pointers for boxed arguments.
|
|
| 158 | + |
|
| 159 | +See Note [Evaluated and Properly Tagged]
|
|
| 160 | +-}
|
|
| 161 | + |
|
| 162 | +primOpCbv :: PrimOp -> [CbvMark]
|
|
| 163 | +#include "primop-cbv.hs-incl"
|
|
| 164 | + |
|
| 149 | 165 | {-
|
| 150 | 166 | ************************************************************************
|
| 151 | 167 | * *
|
| ... | ... | @@ -150,6 +150,7 @@ defaults |
| 150 | 150 | div_like = False -- Second argument expected to be non zero - used for tests
|
| 151 | 151 | shift_like = False -- Second argument expected to be atmost first argument's word size -1 - used for tests
|
| 152 | 152 | defined_bits = Nothing -- The number of bits the operation is defined for (if not all bits)
|
| 153 | + cbv_marks = []
|
|
| 153 | 154 | |
| 154 | 155 | -- Note [When do out-of-line primops go in primops.txt.pp]
|
| 155 | 156 | -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -1621,6 +1622,28 @@ primop ReadArrayOp "readArray#" GenPrimOp |
| 1621 | 1622 | effect = ReadWriteEffect
|
| 1622 | 1623 | can_fail_warning = YesWarnCanFail
|
| 1623 | 1624 | |
| 1625 | +primop ReadStrictArrayOp "unsafeReadStrictArray#" GenPrimOp
|
|
| 1626 | + MutableArray# s a -> Int# -> State# s -> (# State# s, a #)
|
|
| 1627 | + {Read from specified index of mutable array. Result is evaluated.
|
|
| 1628 | + |
|
| 1629 | + GHC will assume the value at the given index has been written
|
|
| 1630 | + by writeStrictArray#. This can allow GHC to elid an eval check when using the
|
|
| 1631 | + read value. Potentially given a performance benefit.
|
|
| 1632 | + |
|
| 1633 | + WARNING: Behaviour is undefined if the value read
|
|
| 1634 | + was not written using writeStrictArray#.
|
|
| 1635 | + |
|
| 1636 | + At runtime "strict" arrays and regular arrays have the same representation.
|
|
| 1637 | + The only difference is in the read/write operations.
|
|
| 1638 | + |
|
| 1639 | + The strict write operations ensure stored values are evaluated and properly
|
|
| 1640 | + tagged. Strict reads assume this fact, allowing GHC to sometimes avoid
|
|
| 1641 | + checking for thunks when using the read value.
|
|
| 1642 | + }
|
|
| 1643 | + with
|
|
| 1644 | + effect = ReadWriteEffect
|
|
| 1645 | + can_fail_warning = YesWarnCanFail
|
|
| 1646 | + |
|
| 1624 | 1647 | primop WriteArrayOp "writeArray#" GenPrimOp
|
| 1625 | 1648 | MutableArray# s a_levpoly -> Int# -> a_levpoly -> State# s -> State# s
|
| 1626 | 1649 | {Write to specified index of mutable array.}
|
| ... | ... | @@ -1629,6 +1652,15 @@ primop WriteArrayOp "writeArray#" GenPrimOp |
| 1629 | 1652 | can_fail_warning = YesWarnCanFail
|
| 1630 | 1653 | code_size = 2 -- card update too
|
| 1631 | 1654 | |
| 1655 | +primop WriteStrictArrayOp "writeStrictArray#" GenPrimOp
|
|
| 1656 | + MutableArray# s a_levpoly -> Int# -> a_levpoly -> State# s -> State# s
|
|
| 1657 | + {Write to specified index of mutable array. Evaluates the argument before writing it.}
|
|
| 1658 | + with
|
|
| 1659 | + effect = ReadWriteEffect
|
|
| 1660 | + can_fail_warning = YesWarnCanFail
|
|
| 1661 | + code_size = 2 -- card update too
|
|
| 1662 | + cbv_marks = [!,!,!]
|
|
| 1663 | + |
|
| 1632 | 1664 | primop SizeofArrayOp "sizeofArray#" GenPrimOp
|
| 1633 | 1665 | Array# a_levpoly -> Int#
|
| 1634 | 1666 | {Return the number of elements in the array.}
|
| ... | ... | @@ -1637,6 +1669,23 @@ primop SizeofMutableArrayOp "sizeofMutableArray#" GenPrimOp |
| 1637 | 1669 | MutableArray# s a_levpoly -> Int#
|
| 1638 | 1670 | {Return the number of elements in the array.}
|
| 1639 | 1671 | |
| 1672 | +primop IndexStrictArrayOp "unsafeIndexStrictArray#" GenPrimOp
|
|
| 1673 | + Array# a_levpoly -> Int# -> (# a_levpoly #)
|
|
| 1674 | + {Read from the specified index of an immutable array. The result is packaged
|
|
| 1675 | + into an unboxed unary tuple; the result itself is evaluated.
|
|
| 1676 | + Pattern matching on the tuple forces the indexing of the
|
|
| 1677 | + array to happen.
|
|
| 1678 | + |
|
| 1679 | + GHC will assume the value at the given index has been written
|
|
| 1680 | + by writeStrictArray#. This can allow GHC to elid an eval check when using the
|
|
| 1681 | + read value. Potentially given a performance benefit.
|
|
| 1682 | + |
|
| 1683 | + WARNING: Behaviour is undefined if the value read
|
|
| 1684 | + was not written using writeStrictArray#.
|
|
| 1685 | + }
|
|
| 1686 | + with
|
|
| 1687 | + effect = CanFail
|
|
| 1688 | + |
|
| 1640 | 1689 | primop IndexArrayOp "indexArray#" GenPrimOp
|
| 1641 | 1690 | Array# a_levpoly -> Int# -> (# a_levpoly #)
|
| 1642 | 1691 | {Read from the specified index of an immutable array. The result is packaged
|
| ... | ... | @@ -1838,6 +1887,27 @@ primop ReadSmallArrayOp "readSmallArray#" GenPrimOp |
| 1838 | 1887 | effect = ReadWriteEffect
|
| 1839 | 1888 | can_fail_warning = YesWarnCanFail
|
| 1840 | 1889 | |
| 1890 | +primop ReadSmallStrictArrayOp "unsafeReadSmallStrictArray#" GenPrimOp
|
|
| 1891 | + SmallMutableArray# s a -> Int# -> State# s -> (# State# s, a #)
|
|
| 1892 | + {Read from specified index of mutable array.
|
|
| 1893 | + |
|
| 1894 | + GHC will assume the value at the given index has been evaluted *and tagged*
|
|
| 1895 | + by writeStrictArray#. This can allow GHC to elid an eval check when using the
|
|
| 1896 | + read value. Potentially given a performance benefit.
|
|
| 1897 | + |
|
| 1898 | + WARNING: Behaviour is undefined if the value read
|
|
| 1899 | + was not written using writeStrictArray#.
|
|
| 1900 | + |
|
| 1901 | + At runtime "strict" arrays and regular arrays have the same representation.
|
|
| 1902 | + The only difference is in the read/write operations.
|
|
| 1903 | + |
|
| 1904 | + The strict write operations ensure stored values are evaluated and properly
|
|
| 1905 | + tagged. Strict reads assume this fact, allowing GHC to sometimes avoid
|
|
| 1906 | + checking for thunks when using the read value.}
|
|
| 1907 | + with
|
|
| 1908 | + effect = ReadWriteEffect
|
|
| 1909 | + can_fail_warning = YesWarnCanFail
|
|
| 1910 | + |
|
| 1841 | 1911 | primop WriteSmallArrayOp "writeSmallArray#" GenPrimOp
|
| 1842 | 1912 | SmallMutableArray# s a_levpoly -> Int# -> a_levpoly -> State# s -> State# s
|
| 1843 | 1913 | {Write to specified index of mutable array.}
|
| ... | ... | @@ -1845,6 +1915,16 @@ primop WriteSmallArrayOp "writeSmallArray#" GenPrimOp |
| 1845 | 1915 | effect = ReadWriteEffect
|
| 1846 | 1916 | can_fail_warning = YesWarnCanFail
|
| 1847 | 1917 | |
| 1918 | +primop WriteSmallStrictArrayOp "writeSmallStrictArray#" GenPrimOp
|
|
| 1919 | + SmallMutableArray# s a_levpoly -> Int# -> a_levpoly -> State# s -> State# s
|
|
| 1920 | + {Write to specified index of mutable array.
|
|
| 1921 | + |
|
| 1922 | + Evaluates the argument before storing it.}
|
|
| 1923 | + with
|
|
| 1924 | + effect = ReadWriteEffect
|
|
| 1925 | + can_fail_warning = YesWarnCanFail
|
|
| 1926 | + cbv_marks = [!,!,!]
|
|
| 1927 | + |
|
| 1848 | 1928 | primop SizeofSmallArrayOp "sizeofSmallArray#" GenPrimOp
|
| 1849 | 1929 | SmallArray# a_levpoly -> Int#
|
| 1850 | 1930 | {Return the number of elements in the array.}
|
| ... | ... | @@ -1870,6 +1950,20 @@ primop IndexSmallArrayOp "indexSmallArray#" GenPrimOp |
| 1870 | 1950 | with
|
| 1871 | 1951 | effect = CanFail
|
| 1872 | 1952 | |
| 1953 | +primop IndexSmallStrictArrayOp "unsafeIndexSmallStrictArray#" GenPrimOp
|
|
| 1954 | + SmallArray# a -> Int# -> (# a #)
|
|
| 1955 | + {Read from specified index of immutable array. Result is packaged into
|
|
| 1956 | + an unboxed singleton;
|
|
| 1957 | + |
|
| 1958 | + GHC will assume the value at the given index has been written
|
|
| 1959 | + by writeSmallStrictArray#. This can allow GHC to elid an eval check when using the
|
|
| 1960 | + read value. Potentially given a performance benefit.
|
|
| 1961 | + |
|
| 1962 | + WARNING: Behaviour is undefined if the value read
|
|
| 1963 | + was not written using writeSmallStrictArray#}
|
|
| 1964 | + with
|
|
| 1965 | + effect = CanFail
|
|
| 1966 | + |
|
| 1873 | 1967 | primop UnsafeFreezeSmallArrayOp "unsafeFreezeSmallArray#" GenPrimOp
|
| 1874 | 1968 | SmallMutableArray# s a_levpoly -> State# s -> (# State# s, SmallArray# a_levpoly #)
|
| 1875 | 1969 | {Make a mutable array immutable, without copying.}
|
| ... | ... | @@ -9,6 +9,7 @@ module GHC.Stg.EnforceEpt ( enforceEpt ) where |
| 9 | 9 | |
| 10 | 10 | import GHC.Prelude hiding (id)
|
| 11 | 11 | |
| 12 | +import qualified GHC.Builtin.PrimOps as PrimOps
|
|
| 12 | 13 | import GHC.Core.DataCon
|
| 13 | 14 | import GHC.Core.Type
|
| 14 | 15 | import GHC.Types.Id
|
| ... | ... | @@ -354,6 +355,16 @@ inferTags for_bytecode binds = |
| 354 | 355 | -- pprTrace "Binds" (pprGenStgTopBindings shortStgPprOpts $ binds) $
|
| 355 | 356 | snd (mapAccumL inferTagTopBind (initEnv for_bytecode) binds)
|
| 356 | 357 | |
| 358 | +inferPrimAppResult :: PrimOps.PrimOp -> TagInfo
|
|
| 359 | +inferPrimAppResult op =
|
|
| 360 | + case op of
|
|
| 361 | + PrimOps.ReadSmallStrictArrayOp -> TagTuple [TagProper]
|
|
| 362 | + PrimOps.ReadStrictArrayOp -> TagTuple [TagProper]
|
|
| 363 | + PrimOps.IndexSmallStrictArrayOp -> TagTuple [TagProper]
|
|
| 364 | + PrimOps.IndexStrictArrayOp -> TagTuple [TagProper]
|
|
| 365 | + _ -> TagDunno
|
|
| 366 | + |
|
| 367 | + |
|
| 357 | 368 | -----------------------
|
| 358 | 369 | inferTagTopBind :: TagEnv 'CodeGen -> GenStgTopBinding 'CodeGen
|
| 359 | 370 | -> (TagEnv 'CodeGen, GenStgTopBinding 'InferTaggedBinders)
|
| ... | ... | @@ -409,11 +420,14 @@ inferTagExpr env (StgTick tick body) |
| 409 | 420 | where
|
| 410 | 421 | (info, body') = inferTagExpr env body
|
| 411 | 422 | |
| 412 | -inferTagExpr _ (StgOpApp op args ty)
|
|
| 423 | +inferTagExpr _ (StgOpApp op args ty) =
|
|
| 413 | 424 | -- Which primops guarantee to return a properly tagged value?
|
| 414 | 425 | -- Probably none, and that is the conservative assumption anyway.
|
| 415 | 426 | -- (And foreign calls definitely need not make promises.)
|
| 416 | - = (TagDunno, StgOpApp op args ty)
|
|
| 427 | + case op of
|
|
| 428 | + StgPrimOp prim_op -> (inferPrimAppResult prim_op, StgOpApp op args ty)
|
|
| 429 | + StgPrimCallOp {} -> (TagDunno, StgOpApp op args ty)
|
|
| 430 | + StgFCallOp {} -> (TagDunno, StgOpApp op args ty)
|
|
| 417 | 431 | |
| 418 | 432 | inferTagExpr env (StgLet ext bind body)
|
| 419 | 433 | = (info, StgLet ext bind' body')
|
| ... | ... | @@ -12,7 +12,7 @@ where |
| 12 | 12 | |
| 13 | 13 | import GHC.Prelude
|
| 14 | 14 | |
| 15 | -import GHC.Builtin.PrimOps ( PrimOp(..) )
|
|
| 15 | +import GHC.Builtin.PrimOps ( PrimOp(..), primOpCbv )
|
|
| 16 | 16 | import GHC.Types.Basic ( CbvMark (..), isMarkedCbv
|
| 17 | 17 | , TopLevelFlag(..), isTopLevel )
|
| 18 | 18 | import GHC.Types.Id
|
| ... | ... | @@ -399,8 +399,7 @@ rewriteExpr (StgTick t e) = StgTick t <$!> rewriteExpr e |
| 399 | 399 | rewriteExpr e@(StgConApp {}) = rewriteConApp e
|
| 400 | 400 | rewriteExpr e@(StgApp {}) = rewriteApp e
|
| 401 | 401 | rewriteExpr (StgLit lit) = return $! (StgLit lit)
|
| 402 | -rewriteExpr (StgOpApp op args res_ty) = (StgOpApp op) <$!> rewriteArgs args <*> pure res_ty
|
|
| 403 | - |
|
| 402 | +rewriteExpr (StgOpApp op args res_ty) = rewriteOpApp (StgOpApp op args res_ty)
|
|
| 404 | 403 | |
| 405 | 404 | rewriteCase :: InferStgExpr -> RM TgStgExpr
|
| 406 | 405 | rewriteCase (StgCase scrut bndr alt_type alts) =
|
| ... | ... | @@ -452,6 +451,21 @@ rewriteConApp (StgConApp con cn args tys) = do |
| 452 | 451 | |
| 453 | 452 | rewriteConApp _ = panic "Impossible"
|
| 454 | 453 | |
| 454 | +{-# INLINE eptArgs #-}
|
|
| 455 | +-- Evaluate the relevant arguments, and construct an expression with the ids substituted
|
|
| 456 | +-- for their evaluated parts.
|
|
| 457 | +eptArgs :: [CbvMark] -> [StgArg] -> ([StgArg] -> TgStgExpr) -> RM TgStgExpr
|
|
| 458 | +eptArgs relevant_marks args mkExpr = do
|
|
| 459 | + argTags <- mapM isArgTagged args
|
|
| 460 | + let argInfo = zipWith3 ((,,)) args (relevant_marks++repeat NotMarkedCbv) argTags :: [(StgArg, CbvMark, Bool)]
|
|
| 461 | + |
|
| 462 | + -- untagged cbv arguments
|
|
| 463 | + cbvArgs = map fstOf3 . filter (\x -> sndOf3 x == MarkedCbv && thdOf3 x == False) $ argInfo
|
|
| 464 | + -- We only need to force ids
|
|
| 465 | + cbvArgIds = [x | StgVarArg x <- cbvArgs] :: [Id]
|
|
| 466 | + mkSeqs args cbvArgIds mkExpr
|
|
| 467 | + |
|
| 468 | + |
|
| 455 | 469 | -- Special case: Atomic binders, usually in a case context like `case f of ...`.
|
| 456 | 470 | rewriteApp :: InferStgExpr -> RM TgStgExpr
|
| 457 | 471 | rewriteApp (StgApp f []) = do
|
| ... | ... | @@ -464,19 +478,8 @@ rewriteApp (StgApp f args) |
| 464 | 478 | , relevant_marks <- dropWhileEndLE (not . isMarkedCbv) marks
|
| 465 | 479 | , any isMarkedCbv relevant_marks
|
| 466 | 480 | = assertPpr (length relevant_marks <= length args) (ppr f $$ ppr args $$ ppr relevant_marks)
|
| 467 | - unliftArg relevant_marks
|
|
| 468 | - |
|
| 469 | - where
|
|
| 470 | - -- If the function expects any argument to be call-by-value ensure the argument is already
|
|
| 471 | - -- evaluated.
|
|
| 472 | - unliftArg relevant_marks = do
|
|
| 473 | - argTags <- mapM isArgTagged args
|
|
| 474 | - let argInfo = zipWith3 ((,,)) args (relevant_marks++repeat NotMarkedCbv) argTags :: [(StgArg, CbvMark, Bool)]
|
|
| 475 | - |
|
| 476 | - -- untagged cbv argument positions
|
|
| 477 | - cbvArgInfo = filter (\x -> sndOf3 x == MarkedCbv && thdOf3 x == False) argInfo
|
|
| 478 | - cbvArgIds = [x | StgVarArg x <- map fstOf3 cbvArgInfo] :: [Id]
|
|
| 479 | - mkSeqs args cbvArgIds (\cbv_args -> StgApp f cbv_args)
|
|
| 481 | + -- Enforce relevant args are evaluated and tagged.
|
|
| 482 | + eptArgs relevant_marks args (\cbv_args -> StgApp f cbv_args)
|
|
| 480 | 483 | |
| 481 | 484 | rewriteApp (StgApp f args) = return $ StgApp f args
|
| 482 | 485 | rewriteApp _ = panic "Impossible"
|
| ... | ... | @@ -500,10 +503,14 @@ So for these we should call `rewriteArgs`. |
| 500 | 503 | |
| 501 | 504 | rewriteOpApp :: InferStgExpr -> RM TgStgExpr
|
| 502 | 505 | rewriteOpApp (StgOpApp op args res_ty) = case op of
|
| 506 | + -- Should we just use cbv marks for DataToTag?
|
|
| 503 | 507 | op@(StgPrimOp primOp)
|
| 504 | 508 | | primOp == DataToTagSmallOp || primOp == DataToTagLargeOp
|
| 505 | 509 | -- see Note [Rewriting primop arguments]
|
| 506 | 510 | -> (StgOpApp op) <$!> rewriteArgs args <*> pure res_ty
|
| 511 | + | marks <- primOpCbv primOp
|
|
| 512 | + , not (null marks)
|
|
| 513 | + -> eptArgs marks args (\tagged_args -> (StgOpApp op tagged_args res_ty))
|
|
| 507 | 514 | _ -> pure $! StgOpApp op args res_ty
|
| 508 | 515 | rewriteOpApp _ = panic "Impossible"
|
| 509 | 516 |
| ... | ... | @@ -380,17 +380,29 @@ emitPrimOp cfg primop = |
| 380 | 380 | |
| 381 | 381 | ReadArrayOp -> \[obj, ix] -> opIntoRegs $ \[res] ->
|
| 382 | 382 | doReadPtrArrayOp res obj ix
|
| 383 | + ReadStrictArrayOp -> \[obj, ix] -> opIntoRegs $ \[res] ->
|
|
| 384 | + doReadPtrArrayOp res obj ix
|
|
| 383 | 385 | IndexArrayOp -> \[obj, ix] -> opIntoRegs $ \[res] ->
|
| 384 | 386 | doReadPtrArrayOp res obj ix
|
| 387 | + IndexStrictArrayOp -> \[obj, ix] -> opIntoRegs $ \[res] ->
|
|
| 388 | + doReadPtrArrayOp res obj ix
|
|
| 385 | 389 | WriteArrayOp -> \[obj, ix, v] -> opIntoRegs $ \[] ->
|
| 386 | 390 | doWritePtrArrayOp obj ix v
|
| 391 | + WriteStrictArrayOp -> \[obj, ix, v] -> opIntoRegs $ \[] ->
|
|
| 392 | + doWritePtrArrayOp obj ix v
|
|
| 387 | 393 | |
| 388 | 394 | ReadSmallArrayOp -> \[obj, ix] -> opIntoRegs $ \[res] ->
|
| 389 | 395 | doReadSmallPtrArrayOp res obj ix
|
| 396 | + ReadSmallStrictArrayOp -> \[obj, ix] -> opIntoRegs $ \[res] ->
|
|
| 397 | + doReadSmallPtrArrayOp res obj ix
|
|
| 390 | 398 | IndexSmallArrayOp -> \[obj, ix] -> opIntoRegs $ \[res] ->
|
| 391 | 399 | doReadSmallPtrArrayOp res obj ix
|
| 400 | + IndexSmallStrictArrayOp -> \[obj, ix] -> opIntoRegs $ \[res] ->
|
|
| 401 | + doReadSmallPtrArrayOp res obj ix
|
|
| 392 | 402 | WriteSmallArrayOp -> \[obj,ix,v] -> opIntoRegs $ \[] ->
|
| 393 | 403 | doWriteSmallPtrArrayOp obj ix v
|
| 404 | + WriteSmallStrictArrayOp -> \[obj,ix,v] -> opIntoRegs $ \[] ->
|
|
| 405 | + doWriteSmallPtrArrayOp obj ix v
|
|
| 394 | 406 | |
| 395 | 407 | -- Getting the size of pointer arrays
|
| 396 | 408 |
| ... | ... | @@ -559,7 +559,9 @@ genPrim prof bound ty op = case op of |
| 559 | 559 | |
| 560 | 560 | NewArrayOp -> \[r] [l,e] -> pure $ PrimInline $ r |= app hdNewArrayStr [l,e]
|
| 561 | 561 | ReadArrayOp -> \[r] [a,i] -> pure $ PrimInline $ bnd_arr bound a i (r |= a .! i)
|
| 562 | + ReadStrictArrayOp -> \[r] [a,i] -> pure $ PrimInline $ bnd_arr bound a i (r |= a .! i)
|
|
| 562 | 563 | WriteArrayOp -> \[] [a,i,v] -> pure $ PrimInline $ bnd_arr bound a i (a .! i |= v)
|
| 564 | + WriteStrictArrayOp -> \[] [a,i,v] -> pure $ PrimInline $ bnd_arr bound a i (a .! i |= v)
|
|
| 563 | 565 | SizeofArrayOp -> \[r] [a] -> pure $ PrimInline $ r |= a .^ lngth
|
| 564 | 566 | SizeofMutableArrayOp -> \[r] [a] -> pure $ PrimInline $ r |= a .^ lngth
|
| 565 | 567 | IndexArrayOp -> \[r] [a,i] -> pure $ PrimInline $ bnd_arr bound a i (r |= a .! i)
|
| ... | ... | @@ -623,7 +625,9 @@ genPrim prof bound ty op = case op of |
| 623 | 625 | |
| 624 | 626 | NewSmallArrayOp -> \[a] [n,e] -> pure $ PrimInline $ a |= app hdNewArrayStr [n,e]
|
| 625 | 627 | ReadSmallArrayOp -> \[r] [a,i] -> pure $ PrimInline $ bnd_arr bound a i (r |= a .! i)
|
| 628 | + ReadSmallStrictArrayOp -> \[r] [a,i] -> pure $ PrimInline $ bnd_arr bound a i (r |= a .! i)
|
|
| 626 | 629 | WriteSmallArrayOp -> \[] [a,i,e] -> pure $ PrimInline $ bnd_arr bound a i (a .! i |= e)
|
| 630 | + WriteSmallStrictArrayOp -> \[] [a,i,e] -> pure $ PrimInline $ bnd_arr bound a i (a .! i |= e) -- todo check-tags?
|
|
| 627 | 631 | SizeofSmallArrayOp -> \[r] [a] -> pure $ PrimInline $ r |= a .^ lngth
|
| 628 | 632 | SizeofSmallMutableArrayOp -> \[r] [a] -> pure $ PrimInline $ r |= a .^ lngth
|
| 629 | 633 | IndexSmallArrayOp -> \[r] [a,i] -> pure $ PrimInline $ bnd_arr bound a i (r |= a .! i)
|
| ... | ... | @@ -513,8 +513,8 @@ isDFunId id = case Var.idDetails id of |
| 513 | 513 | _ -> False
|
| 514 | 514 | |
| 515 | 515 | isPrimOpId_maybe id = case Var.idDetails id of
|
| 516 | - PrimOpId op _ -> Just op
|
|
| 517 | - _ -> Nothing
|
|
| 516 | + PrimOpId op _ -> Just op
|
|
| 517 | + _ -> Nothing
|
|
| 518 | 518 | |
| 519 | 519 | isFCallId id = case Var.idDetails id of
|
| 520 | 520 | FCallId _ -> True
|
| ... | ... | @@ -845,7 +845,7 @@ setIdCbvMarks id marks |
| 845 | 845 | |
| 846 | 846 | idCbvMarks_maybe :: Id -> Maybe [CbvMark]
|
| 847 | 847 | idCbvMarks_maybe id = case idDetails id of
|
| 848 | - WorkerLikeId marks -> Just marks
|
|
| 848 | + WorkerLikeId marks -> Just marks
|
|
| 849 | 849 | JoinId _arity marks -> marks
|
| 850 | 850 | _ -> Nothing
|
| 851 | 851 |
| ... | ... | @@ -395,7 +395,7 @@ pprIdDetails VanillaId = empty |
| 395 | 395 | pprIdDetails other = brackets (pp other)
|
| 396 | 396 | where
|
| 397 | 397 | pp VanillaId = panic "pprIdDetails"
|
| 398 | - pp (WorkerLikeId dmds) = text "StrictWorker" <> parens (ppr dmds)
|
|
| 398 | + pp (WorkerLikeId dmds) = text "StrictWorker" <> pp_marks dmds
|
|
| 399 | 399 | pp (DataConWorkId _) = text "DataCon"
|
| 400 | 400 | pp (DataConWrapId _) = text "DataConWrapper"
|
| 401 | 401 | pp (ClassOpId {}) = text "ClassOp"
|
| ... | ... | @@ -410,6 +410,9 @@ pprIdDetails other = brackets (pp other) |
| 410 | 410 | pp CoVarId = text "CoVarId"
|
| 411 | 411 | pp (JoinId arity marks) = text "JoinId" <> parens (int arity) <> parens (ppr marks)
|
| 412 | 412 | |
| 413 | + pp_marks [] = empty
|
|
| 414 | + pp_marks xs = ppr xs
|
|
| 415 | + |
|
| 413 | 416 | {-
|
| 414 | 417 | ************************************************************************
|
| 415 | 418 | * *
|
| ... | ... | @@ -47,6 +47,7 @@ primopIncls = |
| 47 | 47 | , ("primop-commutable.hs-incl" , "--commutable")
|
| 48 | 48 | , ("primop-code-size.hs-incl" , "--code-size")
|
| 49 | 49 | , ("primop-strictness.hs-incl" , "--strictness")
|
| 50 | + , ("primop-cbv.hs-incl" , "--cbv")
|
|
| 50 | 51 | , ("primop-is-work-free.hs-incl" , "--is-work-free")
|
| 51 | 52 | , ("primop-is-cheap.hs-incl" , "--is-cheap")
|
| 52 | 53 | , ("primop-fixity.hs-incl" , "--fixity")
|
| ... | ... | @@ -92,6 +92,7 @@ compilerDependencies = do |
| 92 | 92 | , "primop-out-of-line.hs-incl"
|
| 93 | 93 | , "primop-primop-info.hs-incl"
|
| 94 | 94 | , "primop-strictness.hs-incl"
|
| 95 | + , "primop-cbv.hs-incl"
|
|
| 95 | 96 | , "primop-is-work-free.hs-incl"
|
| 96 | 97 | , "primop-is-cheap.hs-incl"
|
| 97 | 98 | , "primop-tag.hs-incl"
|
| ... | ... | @@ -111,6 +111,7 @@ hsIncls path = [ path </> "primop-vector-tycons.hs-incl" |
| 111 | 111 | , path </> "primop-tag.hs-incl"
|
| 112 | 112 | , path </> "primop-list.hs-incl"
|
| 113 | 113 | , path </> "primop-strictness.hs-incl"
|
| 114 | + , path </> "primop-cbv.hs-incl"
|
|
| 114 | 115 | , path </> "primop-is-work-free.hs-incl"
|
| 115 | 116 | , path </> "primop-is-cheap.hs-incl"
|
| 116 | 117 | , path </> "primop-fixity.hs-incl"
|
| ... | ... | @@ -14,6 +14,7 @@ genPrimopCodeBuilderArgs = builder GenPrimopCode ? mconcat |
| 14 | 14 | , output "//primop-commutable.hs-incl" ? arg "--commutable"
|
| 15 | 15 | , output "//primop-code-size.hs-incl" ? arg "--code-size"
|
| 16 | 16 | , output "//primop-strictness.hs-incl" ? arg "--strictness"
|
| 17 | + , output "//primop-cbv.hs-incl" ? arg "--cbv"
|
|
| 17 | 18 | , output "//primop-is-work-free.hs-incl" ? arg "--is-work-free"
|
| 18 | 19 | , output "//primop-is-cheap.hs-incl" ? arg "--is-cheap"
|
| 19 | 20 | , output "//primop-fixity.hs-incl" ? arg "--fixity"
|
| ... | ... | @@ -36,6 +36,8 @@ words :- |
| 36 | 36 | <0> "]" { mkT TCloseBracket }
|
| 37 | 37 | <0> "<" { mkT TOpenAngle }
|
| 38 | 38 | <0> ">" { mkT TCloseAngle }
|
| 39 | + <0> "!" { mkT TBang }
|
|
| 40 | + <0> "~" { mkT TTilde }
|
|
| 39 | 41 | <0> "section" { mkT TSection }
|
| 40 | 42 | <0> "primop" { mkT TPrimop }
|
| 41 | 43 | <0> "pseudoop" { mkT TPseudoop }
|
| ... | ... | @@ -62,6 +64,7 @@ words :- |
| 62 | 64 | <0> "WarnIfEffectIsCanFail" { mkT TWarnIfEffectIsCanFail }
|
| 63 | 65 | <0> "YesWarnCanFail" { mkT TYesWarnCanFail }
|
| 64 | 66 | <0> "vector" { mkT TVector }
|
| 67 | + <0> "cbv_marks" { mkT TCbv_marks }
|
|
| 65 | 68 | <0> "bytearray_access_ops" { mkT TByteArrayAccessOps }
|
| 66 | 69 | <0> "addr_access_ops" { mkT TAddrAccessOps }
|
| 67 | 70 | <0> "thats_all_folks" { mkT TThatsAllFolks }
|
| ... | ... | @@ -170,6 +170,11 @@ main = getArgs >>= \args -> |
| 170 | 170 | "strictness"
|
| 171 | 171 | "primOpStrictness" p_o_specs)
|
| 172 | 172 | |
| 173 | + "--cbv"
|
|
| 174 | + -> putStr (gen_switch_from_attribs
|
|
| 175 | + "cbv_marks"
|
|
| 176 | + "primOpCbv" p_o_specs)
|
|
| 177 | + |
|
| 173 | 178 | "--fixity"
|
| 174 | 179 | -> putStr (gen_switch_from_attribs
|
| 175 | 180 | "fixity"
|
| ... | ... | @@ -228,6 +233,7 @@ known_args |
| 228 | 233 | "--is-work-free",
|
| 229 | 234 | "--is-cheap",
|
| 230 | 235 | "--strictness",
|
| 236 | + "--cbv",
|
|
| 231 | 237 | "--fixity",
|
| 232 | 238 | "--primop-effects",
|
| 233 | 239 | "--primop-primop-info",
|
| ... | ... | @@ -318,6 +324,7 @@ gen_hs_source (Info defaults entries) = |
| 318 | 324 | opt (OptionInteger n v) = n ++ " = " ++ show v
|
| 319 | 325 | opt (OptionVector _) = ""
|
| 320 | 326 | opt (OptionFixity mf) = "fixity = " ++ show mf
|
| 327 | + opt (OptionCbvMarks marks) = "cbv_marks = " ++ show marks
|
|
| 321 | 328 | opt (OptionEffect eff) = "effect = " ++ show eff
|
| 322 | 329 | opt (OptionDefinedBits bc) = "defined_bits = " ++ show bc
|
| 323 | 330 | opt (OptionCanFailWarnFlag wf) = "can_fail_warning = " ++ show wf
|
| ... | ... | @@ -645,6 +652,11 @@ gen_switch_from_attribs attrib_name fn_name (Info defaults entries) |
| 645 | 652 | getAltRhs (OptionString _ s) = s
|
| 646 | 653 | getAltRhs (OptionVector _) = "True"
|
| 647 | 654 | getAltRhs (OptionFixity mf) = show mf
|
| 655 | + getAltRhs (OptionCbvMarks marks) =
|
|
| 656 | + "[" ++ concat (intersperse "," (map showMark marks)) ++ "]"
|
|
| 657 | + where
|
|
| 658 | + showMark True = "MarkedCbv"
|
|
| 659 | + showMark False = "NotMarkedCbv"
|
|
| 648 | 660 | getAltRhs (OptionEffect eff) = show eff
|
| 649 | 661 | getAltRhs (OptionDefinedBits bc) = show bc
|
| 650 | 662 | getAltRhs (OptionCanFailWarnFlag wf) = show wf
|
| ... | ... | @@ -30,6 +30,8 @@ import AccessOps |
| 30 | 30 | ']' { TCloseBracket }
|
| 31 | 31 | '<' { TOpenAngle }
|
| 32 | 32 | '>' { TCloseAngle }
|
| 33 | + '!' { TBang }
|
|
| 34 | + '~' { TTilde }
|
|
| 33 | 35 | section { TSection }
|
| 34 | 36 | primop { TPrimop }
|
| 35 | 37 | pseudoop { TPseudoop }
|
| ... | ... | @@ -56,6 +58,7 @@ import AccessOps |
| 56 | 58 | WarnIfEffectIsCanFail { TWarnIfEffectIsCanFail }
|
| 57 | 59 | YesWarnCanFail { TYesWarnCanFail }
|
| 58 | 60 | vector { TVector }
|
| 61 | + cbv_marks { TCbv_marks }
|
|
| 59 | 62 | SCALAR { TSCALAR }
|
| 60 | 63 | VECTOR { TVECTOR }
|
| 61 | 64 | VECTUPLE { TVECTUPLE }
|
| ... | ... | @@ -87,6 +90,7 @@ pOption : lowerName '=' false { OptionFalse $1 } |
| 87 | 90 | | lowerName '=' pStuffBetweenBraces { OptionString $1 $3 }
|
| 88 | 91 | | lowerName '=' integer { OptionInteger $1 $3 }
|
| 89 | 92 | | vector '=' pVectorTemplate { OptionVector $3 }
|
| 93 | + | cbv_marks '=' pCbvMarks { OptionCbvMarks $3 }
|
|
| 90 | 94 | | fixity '=' pInfix { OptionFixity $3 }
|
| 91 | 95 | | effect '=' pEffect { OptionEffect $3 }
|
| 92 | 96 | | defined_bits '=' pGoodBits { OptionDefinedBits $3 }
|
| ... | ... | @@ -175,6 +179,18 @@ pInside :: { String } |
| 175 | 179 | pInside : '{' pInsides '}' { "{" ++ $2 ++ "}" }
|
| 176 | 180 | | noBraces { $1 }
|
| 177 | 181 | |
| 182 | +pCbvMarks :: { [Bool] }
|
|
| 183 | +pCbvMarks : '[' pMarks ']' { $2 }
|
|
| 184 | + |
|
| 185 | +pMarks :: { [Bool] }
|
|
| 186 | +pMarks : pMark ',' pMarks { [$1] ++ $3 }
|
|
| 187 | + | pMark { [$1] }
|
|
| 188 | + | {- empty -} { [] }
|
|
| 189 | + |
|
| 190 | +pMark :: { Bool }
|
|
| 191 | +pMark : '!' { True }
|
|
| 192 | + | '~' { False }
|
|
| 193 | + |
|
| 178 | 194 | pVectorTemplate :: { [(String, String, Int)] }
|
| 179 | 195 | pVectorTemplate : '[' pVectors ']' { $2 }
|
| 180 | 196 |
| ... | ... | @@ -75,6 +75,8 @@ init_state = St { |
| 75 | 75 | |
| 76 | 76 | data Token = TEOF
|
| 77 | 77 | | TArrow
|
| 78 | + | TBang
|
|
| 79 | + | TTilde
|
|
| 78 | 80 | | TDArrow
|
| 79 | 81 | | TEquals
|
| 80 | 82 | | TComma
|
| ... | ... | @@ -122,6 +124,7 @@ data Token = TEOF |
| 122 | 124 | | TWarnIfEffectIsCanFail
|
| 123 | 125 | | TYesWarnCanFail
|
| 124 | 126 | | TVector
|
| 127 | + | TCbv_marks
|
|
| 125 | 128 | | TSCALAR
|
| 126 | 129 | | TVECTOR
|
| 127 | 130 | | TVECTUPLE
|
| ... | ... | @@ -83,6 +83,7 @@ data Option |
| 83 | 83 | | OptionEffect PrimOpEffect -- effect = NoEffect | DoNotSpeculate | CanFail | ThrowsException | ReadWriteEffect | FallibleReadWriteEffect
|
| 84 | 84 | | OptionCanFailWarnFlag PrimOpCanFailWarnFlag -- can_fail_warning = DoNotWarnCanFail | WarnIfEffectIsCanFail | YesWarnCanFail
|
| 85 | 85 | | OptionDefinedBits (Maybe Word) -- defined_bits = Just 16 | Nothing
|
| 86 | + | OptionCbvMarks [Bool] -- defined_bits = Just 16 | Nothing
|
|
| 86 | 87 | deriving Show
|
| 87 | 88 | |
| 88 | 89 | -- categorises primops
|
| ... | ... | @@ -200,6 +201,7 @@ get_attrib_name (OptionTrue nm) = nm |
| 200 | 201 | get_attrib_name (OptionString nm _) = nm
|
| 201 | 202 | get_attrib_name (OptionInteger nm _) = nm
|
| 202 | 203 | get_attrib_name (OptionVector _) = "vector"
|
| 204 | +get_attrib_name (OptionCbvMarks _) = "cbv_marks"
|
|
| 203 | 205 | get_attrib_name (OptionFixity _) = "fixity"
|
| 204 | 206 | get_attrib_name (OptionEffect _) = "effect"
|
| 205 | 207 | get_attrib_name (OptionCanFailWarnFlag _) = "can_fail_warning"
|