[Git][ghc/ghc][wip/romes/25636] Allocate static constructors for bytecode
by Rodrigo Mesquita (@alt-romes) 24 Dec '25
by Rodrigo Mesquita (@alt-romes) 24 Dec '25
24 Dec '25
Rodrigo Mesquita pushed to branch wip/romes/25636 at Glasgow Haskell Compiler / GHC
Commits:
0fa83d73 by Rodrigo Mesquita at 2025-12-23T20:00:03+00:00
Allocate static constructors for bytecode
This commit adds support for static constructors when compiling and
linking ByteCode objects.
Top-level StgRhsCon get lowered to ProtoStaticCons rather than to
ProtoBCOs. A ProtoStaticCon gets allocated directly as a data con
application on the heap (using the new primop newConApp#).
Previously, we would allocate a ProtoBCO which, when evaluated, would
PACK and return the constructor.
A few more details are given in Note [Static constructors in Bytecode].
Secondly, this commit also fixes issue #25636 which was caused by
linking *unlifted* constructors in BCO instructions as
- (1) a thunk indexing the array of BCOs in a module
- (2) which evaluated to a BCO which still had to be evaluated to
return the unlifted constructor proper.
The (2) issue has been resolved by allocating the static constructors
directly. The (1) issue can be resolved by ensuring that we allocate all
unlifted top-level constructors eagerly, and leave the knot-tying for
the lifted BCOs and top-level constructors only.
The top-level unlifted constructors are never mutually recursive, so we
can allocate them all in one go as long as we do it in topological
order. Lifted fields of unlifted constructors can still be filled by the
knot-tied lifted variables since in those fields it is fine to keep
those thunks. See Note [Tying the knot in createBCOs] for more details.
Fixes #25636
- - - - -
21 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/Serialize.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Cmm/Liveness.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/StgToByteCode.hs
- compiler/GHC/StgToCmm/Closure.hs
- compiler/GHC/StgToCmm/Prim.hs
- compiler/GHC/StgToJS/Prim.hs
- libraries/ghci/GHCi/CreateBCO.hs
- libraries/ghci/GHCi/ResolvedBCO.hs
- rts/Interpreter.c
- rts/PrimOps.cmm
- rts/RtsSymbols.c
- rts/include/rts/storage/ClosureMacros.h
- rts/include/stg/MiscClosures.h
- + testsuite/tests/codeGen/should_run/T23146/T25636.stdout
- utils/deriveConstants/Main.hs
Changes:
=====================================
compiler/GHC/Builtin/primops.txt.pp
=====================================
@@ -3947,6 +3947,18 @@ primop NewBCOOp "newBCO#" GenPrimOp
effect = ReadWriteEffect
out_of_line = True
+primop NewConAppObjOp "newConAppObj#" GenPrimOp
+ Addr# -> ByteArray# -> Array# a_levpoly -> Word# -> State# s -> (# State# s, b_levpoly #)
+ { @'newConAppObj#' datacon_itbl lits ptrs arity@ creates a new constructor
+ application object on the heap from the info table pointer of the data
+ constructor and the data arguments given in @ptrs@ and @lits@. The
+ resulting object is a heap closure for the constructor application. It is
+ evaluated and properly tagged. The given @arity@ gives the total size of
+ pointers and literals in number of words. }
+ with
+ effect = ReadWriteEffect
+ out_of_line = True
+
primop UnpackClosureOp "unpackClosure#" GenPrimOp
a -> (# Addr#, ByteArray#, Array# b #)
{ @'unpackClosure#' closure@ copies the closure and pointers in the
=====================================
compiler/GHC/ByteCode/Asm.hs
=====================================
@@ -4,6 +4,7 @@
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE PatternSynonyms #-}
{-# OPTIONS_GHC -optc-DNON_POSIX_SOURCE #-}
+{-# LANGUAGE LambdaCase #-}
--
--
-- (c) The University of Glasgow 2002-2006
@@ -21,9 +22,9 @@ module GHC.ByteCode.Asm (
assembleBCO
) where
-import GHC.Prelude hiding ( any )
-
+import GHC.Prelude hiding ( any, words )
+import Data.Maybe
import GHC.ByteCode.Instr
import GHC.ByteCode.InfoTable
import GHC.ByteCode.Types
@@ -37,9 +38,12 @@ import GHC.Types.SptEntry
import GHC.Types.Unique.FM
import GHC.Unit.Types
-import GHC.Utils.Outputable
+import GHC.Utils.Outputable ( Outputable(..), text, (<+>), vcat )
import GHC.Utils.Panic
+import GHC.Builtin.Types.Prim ( addrPrimTy )
+import GHC.Core.Type ( isUnliftedType )
+import GHC.Core.TyCo.Compare ( eqType )
import GHC.Core.TyCon
import GHC.Data.SizedSeq
import GHC.Data.SmallArray
@@ -66,11 +70,13 @@ import Data.Array.Base ( unsafeWrite )
import Foreign hiding (shiftL, shiftR)
import Data.ByteString (ByteString)
import Data.Char (ord)
-import Data.Maybe (fromMaybe)
import GHC.Float (castFloatToWord32, castDoubleToWord64)
import qualified Data.List as List ( any )
import GHC.Exts
+import GHC.Core.DataCon
+import GHC.Data.FlatBag
+import GHC.Types.Id
-- -----------------------------------------------------------------------------
@@ -83,14 +89,23 @@ import GHC.Exts
-- defined by this group of BCOs themselves
bcoFreeNames :: UnlinkedBCO -> UniqDSet Name
bcoFreeNames bco
- = bco_refs bco `uniqDSetMinusUniqSet` mkNameSet [unlinkedBCOName bco]
+ = bco_refs bco
where
- bco_refs (UnlinkedBCO _ _ _ _ nonptrs ptrs)
+ bco_refs UnlinkedBCO{unlinkedBCOName, unlinkedBCOLits, unlinkedBCOPtrs}
+ = unionManyUniqDSets (
+ mkUniqDSet [ n | BCOPtrName n <- elemsFlatBag unlinkedBCOPtrs ] :
+ mkUniqDSet [ n | BCONPtrItbl n <- elemsFlatBag unlinkedBCOLits ] :
+ map bco_refs [ bco | BCOPtrBCO bco <- elemsFlatBag unlinkedBCOPtrs ]
+ ) `uniqDSetMinusUniqSet` mkNameSet [unlinkedBCOName]
+ bco_refs UnlinkedStaticCon{ unlinkedStaticConName, unlinkedStaticConDataConName
+ , unlinkedStaticConLits, unlinkedStaticConPtrs }
= unionManyUniqDSets (
- mkUniqDSet [ n | BCOPtrName n <- elemsFlatBag ptrs ] :
- mkUniqDSet [ n | BCONPtrItbl n <- elemsFlatBag nonptrs ] :
- map bco_refs [ bco | BCOPtrBCO bco <- elemsFlatBag ptrs ]
+ mkUniqDSet [ unlinkedStaticConDataConName ] :
+ mkUniqDSet [ n | BCOPtrName n <- elemsFlatBag unlinkedStaticConPtrs ] :
+ mkUniqDSet [ n | BCONPtrItbl n <- elemsFlatBag unlinkedStaticConLits ] :
+ map bco_refs [ bco | BCOPtrBCO bco <- elemsFlatBag unlinkedStaticConPtrs ]
)
+ `uniqDSetMinusUniqSet` mkNameSet [ unlinkedStaticConName ]
-- -----------------------------------------------------------------------------
-- The bytecode assembler
@@ -147,9 +162,9 @@ assembleBCOs profile proto_bcos tycons top_strs modbreaks spt_entries = do
--
data RunAsmReader = RunAsmReader { isn_array :: {-# UNPACK #-} !(Array.IOUArray Int Word16)
- , ptr_array :: {-# UNPACK #-} !(SmallMutableArrayIO BCOPtr)
- , lit_array :: {-# UNPACK #-} !(SmallMutableArrayIO BCONPtr )
- }
+ , ptr_array :: {-# UNPACK #-} !(SmallMutableArrayIO BCOPtr)
+ , lit_array :: {-# UNPACK #-} !(SmallMutableArrayIO BCONPtr)
+ }
data RunAsmResult = RunAsmResult { final_isn_array :: !(Array.UArray Int Word16)
, final_ptr_array :: !(SmallArray BCOPtr)
@@ -195,6 +210,40 @@ assembleInspectAsm :: Platform -> BCInstr -> InspectAsm ()
assembleInspectAsm p i = assembleI @InspectAsm p i
assembleBCO :: Platform -> ProtoBCO -> IO UnlinkedBCO
+assembleBCO platform
+ (ProtoStaticCon { protoStaticConName
+ , protoStaticCon = dc
+ , protoStaticConData = args
+ }) = do
+ let ptrs = foldr mappendFlatBag emptyFlatBag (mapMaybe idBCOArg args)
+ let nonptrs = foldr mappendFlatBag emptyFlatBag (mapMaybe litBCOArg args)
+ pure UnlinkedStaticCon
+ { unlinkedStaticConName = protoStaticConName
+ , unlinkedStaticConDataConName = dataConName dc
+ , unlinkedStaticConLits = nonptrs
+ , unlinkedStaticConPtrs = ptrs
+ , unlinkedStaticConIsUnlifted = isUnliftedType (idType (dataConWrapId dc))
+ }
+ where
+ litBCOArg (Left l) = Just $ case literal platform l of
+ OnlyOne np -> unitFlatBag np
+ OnlyTwo np1 np2 -> TupleFlatBag np1 np2
+ litBCOArg (Right var)
+ -- Addr# literals are non-pointers
+ | idType var `eqType` addrPrimTy
+ = Just $ unitFlatBag (BCONPtrAddr (getName var))
+ | otherwise
+ = Nothing
+
+ idBCOArg (Left _) = Nothing
+ idBCOArg (Right var)
+ | idType var `eqType` addrPrimTy
+ = Nothing
+ | Just prim <- isPrimOpId_maybe var
+ = Just $ unitFlatBag (BCOPtrPrimOp prim)
+ | otherwise
+ = Just $ unitFlatBag (BCOPtrName (getName var))
+
assembleBCO platform
(ProtoBCO { protoBCOName = nm
, protoBCOInstrs = instrs
@@ -561,9 +610,9 @@ oneTwoLength (OnlyTwo {}) = 2
class Monad m => MonadAssembler m where
ioptr :: IO BCOPtr -> m Word
- lit :: OneOrTwo BCONPtr -> m Word
+ lit :: OneOrTwo BCONPtr -> m Word
label :: LocalLabel -> m ()
- emit :: PlatformWordSize -> Word16 -> [Operand] -> m ()
+ emit :: PlatformWordSize -> Word16 -> [Operand] -> m ()
lit1 :: MonadAssembler m => BCONPtr -> m Word
lit1 p = lit (OnlyOne p)
@@ -603,20 +652,20 @@ assembleI platform i = case i of
tuple_proto
p <- ioptr (liftM BCOPtrBCO ul_bco)
p_tup <- ioptr (liftM BCOPtrBCO ul_tuple_bco)
- info <- word (fromIntegral $
- mkNativeCallInfoSig platform call_info)
+ info <- lit $ word $ fromIntegral $
+ mkNativeCallInfoSig platform call_info
emit_ bci_PUSH_ALTS_T
[Op p, Op info, Op p_tup]
PUSH_PAD8 -> emit_ bci_PUSH_PAD8 []
PUSH_PAD16 -> emit_ bci_PUSH_PAD16 []
PUSH_PAD32 -> emit_ bci_PUSH_PAD32 []
- PUSH_UBX8 lit -> do np <- literal lit
+ PUSH_UBX8 litv -> do np <- lit $ literal platform litv
emit_ bci_PUSH_UBX8 [Op np]
- PUSH_UBX16 lit -> do np <- literal lit
+ PUSH_UBX16 litv -> do np <- lit $ literal platform litv
emit_ bci_PUSH_UBX16 [Op np]
- PUSH_UBX32 lit -> do np <- literal lit
+ PUSH_UBX32 litv -> do np <- lit $ literal platform litv
emit_ bci_PUSH_UBX32 [Op np]
- PUSH_UBX lit nws -> do np <- literal lit
+ PUSH_UBX litv nws -> do np <- lit $ literal platform litv
emit_ bci_PUSH_UBX [Op np, wOp nws]
-- see Note [Generating code for top-level string literal bindings] in GHC.StgToByteCode
PUSH_ADDR nm -> do np <- lit1 (BCONPtrAddr nm)
@@ -644,53 +693,53 @@ assembleI platform i = case i of
PACK dcon sz -> do itbl_no <- lit1 (BCONPtrItbl (getName dcon))
emit_ bci_PACK [Op itbl_no, wOp sz]
LABEL lbl -> label lbl
- TESTLT_I i l -> do np <- int i
+ TESTLT_I i l -> do np <- lit $ int i
emit_ bci_TESTLT_I [Op np, LabelOp l]
- TESTEQ_I i l -> do np <- int i
+ TESTEQ_I i l -> do np <- lit $ int i
emit_ bci_TESTEQ_I [Op np, LabelOp l]
- TESTLT_W w l -> do np <- word w
+ TESTLT_W w l -> do np <- lit $ word w
emit_ bci_TESTLT_W [Op np, LabelOp l]
- TESTEQ_W w l -> do np <- word w
+ TESTEQ_W w l -> do np <- lit $ word w
emit_ bci_TESTEQ_W [Op np, LabelOp l]
- TESTLT_I64 i l -> do np <- word64 (fromIntegral i)
+ TESTLT_I64 i l -> do np <- lit $ word64 platform (fromIntegral i)
emit_ bci_TESTLT_I64 [Op np, LabelOp l]
- TESTEQ_I64 i l -> do np <- word64 (fromIntegral i)
+ TESTEQ_I64 i l -> do np <- lit $ word64 platform (fromIntegral i)
emit_ bci_TESTEQ_I64 [Op np, LabelOp l]
- TESTLT_I32 i l -> do np <- word (fromIntegral i)
+ TESTLT_I32 i l -> do np <- lit $ word (fromIntegral i)
emit_ bci_TESTLT_I32 [Op np, LabelOp l]
- TESTEQ_I32 i l -> do np <- word (fromIntegral i)
+ TESTEQ_I32 i l -> do np <- lit $ word (fromIntegral i)
emit_ bci_TESTEQ_I32 [Op np, LabelOp l]
- TESTLT_I16 i l -> do np <- word (fromIntegral i)
+ TESTLT_I16 i l -> do np <- lit $ word (fromIntegral i)
emit_ bci_TESTLT_I16 [Op np, LabelOp l]
- TESTEQ_I16 i l -> do np <- word (fromIntegral i)
+ TESTEQ_I16 i l -> do np <- lit $ word (fromIntegral i)
emit_ bci_TESTEQ_I16 [Op np, LabelOp l]
- TESTLT_I8 i l -> do np <- word (fromIntegral i)
+ TESTLT_I8 i l -> do np <- lit $ word (fromIntegral i)
emit_ bci_TESTLT_I8 [Op np, LabelOp l]
- TESTEQ_I8 i l -> do np <- word (fromIntegral i)
+ TESTEQ_I8 i l -> do np <- lit $ word (fromIntegral i)
emit_ bci_TESTEQ_I8 [Op np, LabelOp l]
- TESTLT_W64 w l -> do np <- word64 w
+ TESTLT_W64 w l -> do np <- lit $ word64 platform w
emit_ bci_TESTLT_W64 [Op np, LabelOp l]
- TESTEQ_W64 w l -> do np <- word64 w
+ TESTEQ_W64 w l -> do np <- lit $ word64 platform w
emit_ bci_TESTEQ_W64 [Op np, LabelOp l]
- TESTLT_W32 w l -> do np <- word (fromIntegral w)
+ TESTLT_W32 w l -> do np <- lit $ word (fromIntegral w)
emit_ bci_TESTLT_W32 [Op np, LabelOp l]
- TESTEQ_W32 w l -> do np <- word (fromIntegral w)
+ TESTEQ_W32 w l -> do np <- lit $ word (fromIntegral w)
emit_ bci_TESTEQ_W32 [Op np, LabelOp l]
- TESTLT_W16 w l -> do np <- word (fromIntegral w)
+ TESTLT_W16 w l -> do np <- lit $ word (fromIntegral w)
emit_ bci_TESTLT_W16 [Op np, LabelOp l]
- TESTEQ_W16 w l -> do np <- word (fromIntegral w)
+ TESTEQ_W16 w l -> do np <- lit $ word (fromIntegral w)
emit_ bci_TESTEQ_W16 [Op np, LabelOp l]
- TESTLT_W8 w l -> do np <- word (fromIntegral w)
+ TESTLT_W8 w l -> do np <- lit $ word (fromIntegral w)
emit_ bci_TESTLT_W8 [Op np, LabelOp l]
- TESTEQ_W8 w l -> do np <- word (fromIntegral w)
+ TESTEQ_W8 w l -> do np <- lit $ word (fromIntegral w)
emit_ bci_TESTEQ_W8 [Op np, LabelOp l]
- TESTLT_F f l -> do np <- float f
+ TESTLT_F f l -> do np <- lit $ float platform f
emit_ bci_TESTLT_F [Op np, LabelOp l]
- TESTEQ_F f l -> do np <- float f
+ TESTEQ_F f l -> do np <- lit $ float platform f
emit_ bci_TESTEQ_F [Op np, LabelOp l]
- TESTLT_D d l -> do np <- double d
+ TESTLT_D d l -> do np <- lit $ double platform d
emit_ bci_TESTLT_D [Op np, LabelOp l]
- TESTEQ_D d l -> do np <- double d
+ TESTEQ_D d l -> do np <- lit $ double platform d
emit_ bci_TESTEQ_D [Op np, LabelOp l]
TESTLT_P i l -> emit_ bci_TESTLT_P [SmallOp i, LabelOp l]
TESTEQ_P i l -> emit_ bci_TESTEQ_P [SmallOp i, LabelOp l]
@@ -864,84 +913,86 @@ assembleI platform i = case i of
where
unsupported_width = panic "GHC.ByteCode.Asm: Unsupported Width"
- emit_ = emit word_size
-
- literal :: Literal -> m Word
- literal (LitLabel fs _) = litlabel fs
- literal LitNullAddr = word 0
- literal (LitFloat r) = float (fromRational r)
- literal (LitDouble r) = double (fromRational r)
- literal (LitChar c) = int (ord c)
- literal (LitString bs) = lit1 (BCONPtrStr bs)
- -- LitString requires a zero-terminator when emitted
- literal (LitNumber nt i) = case nt of
- LitNumInt -> word (fromIntegral i)
- LitNumWord -> word (fromIntegral i)
- LitNumInt8 -> word8 (fromIntegral i)
- LitNumWord8 -> word8 (fromIntegral i)
- LitNumInt16 -> word16 (fromIntegral i)
- LitNumWord16 -> word16 (fromIntegral i)
- LitNumInt32 -> word32 (fromIntegral i)
- LitNumWord32 -> word32 (fromIntegral i)
- LitNumInt64 -> word64 (fromIntegral i)
- LitNumWord64 -> word64 (fromIntegral i)
- LitNumBigNat -> panic "GHC.ByteCode.Asm.literal: LitNumBigNat"
+ emit_ = emit (platformWordSize platform)
+
+literal :: Platform -> Literal -> OneOrTwo BCONPtr
+literal platform = \case
+ LitLabel fs _ -> OnlyOne (BCONPtrLbl fs)
+ LitNullAddr -> word 0
+ LitFloat r -> float platform (fromRational r)
+ LitDouble r -> double platform (fromRational r)
+ LitChar c -> int (ord c)
+ LitString bs -> OnlyOne (BCONPtrStr bs)
+ -- LitString requires a zero-terminator when emitted
+ LitNumber nt i -> case nt of
+ LitNumInt -> word (fromIntegral i)
+ LitNumWord -> word (fromIntegral i)
+ LitNumInt8 -> word8 platform (fromIntegral i)
+ LitNumWord8 -> word8 platform (fromIntegral i)
+ LitNumInt16 -> word16 platform (fromIntegral i)
+ LitNumWord16 -> word16 platform (fromIntegral i)
+ LitNumInt32 -> word32 platform (fromIntegral i)
+ LitNumWord32 -> word32 platform (fromIntegral i)
+ LitNumInt64 -> word64 platform (fromIntegral i)
+ LitNumWord64 -> word64 platform (fromIntegral i)
+ LitNumBigNat -> panic "GHC.ByteCode.Asm.literal: LitNumBigNat"
-- We can lower 'LitRubbish' to an arbitrary constant, but @NULL@ is most
-- likely to elicit a crash (rather than corrupt memory) in case absence
-- analysis messed up.
- literal (LitRubbish {}) = word 0
-
- litlabel fs = lit1 (BCONPtrLbl fs)
- words ws = lit (fmap BCONPtrWord ws)
- word w = words (OnlyOne w)
- word2 w1 w2 = words (OnlyTwo w1 w2)
- word_size = platformWordSize platform
- word_size_bits = platformWordSizeInBits platform
-
- -- Make lists of host-sized words for literals, so that when the
- -- words are placed in memory at increasing addresses, the
- -- bit pattern is correct for the host's word size and endianness.
- --
- -- Note that we only support host endianness == target endianness for now,
- -- even with the external interpreter. This would need to be fixed to
- -- support host endianness /= target endianness
- int :: Int -> m Word
- int i = word (fromIntegral i)
-
- float :: Float -> m Word
- float f = word32 (castFloatToWord32 f)
-
- double :: Double -> m Word
- double d = word64 (castDoubleToWord64 d)
-
- word64 :: Word64 -> m Word
- word64 ww = case word_size of
- PW4 ->
- let !wl = fromIntegral ww
- !wh = fromIntegral (ww `unsafeShiftR` 32)
- in case platformByteOrder platform of
- LittleEndian -> word2 wl wh
- BigEndian -> word2 wh wl
- PW8 -> word (fromIntegral ww)
-
- word8 :: Word8 -> m Word
- word8 x = case platformByteOrder platform of
- LittleEndian -> word (fromIntegral x)
- BigEndian -> word (fromIntegral x `unsafeShiftL` (word_size_bits - 8))
-
- word16 :: Word16 -> m Word
- word16 x = case platformByteOrder platform of
- LittleEndian -> word (fromIntegral x)
- BigEndian -> word (fromIntegral x `unsafeShiftL` (word_size_bits - 16))
-
- word32 :: Word32 -> m Word
- word32 x = case platformByteOrder platform of
- LittleEndian -> word (fromIntegral x)
- BigEndian -> case word_size of
- PW4 -> word (fromIntegral x)
- PW8 -> word (fromIntegral x `unsafeShiftL` 32)
+ LitRubbish {} -> word 0
+
+words :: OneOrTwo Word -> OneOrTwo BCONPtr
+words ws = fmap BCONPtrWord ws
+
+word :: Word -> OneOrTwo BCONPtr
+word w = words (OnlyOne w)
+word2 :: Word -> Word -> OneOrTwo BCONPtr
+word2 w1 w2 = words (OnlyTwo w1 w2)
+
+-- Make lists of host-sized words for literals, so that when the
+-- words are placed in memory at increasing addresses, the
+-- bit pattern is correct for the host's word size and endianness.
+--
+-- Note that we only support host endianness == target endianness for now,
+-- even with the external interpreter. This would need to be fixed to
+-- support host endianness /= target endianness
+int :: Int -> OneOrTwo BCONPtr
+int i = word (fromIntegral i)
+
+float :: Platform -> Float -> OneOrTwo BCONPtr
+float platform f = word32 platform (castFloatToWord32 f)
+
+double :: Platform -> Double -> OneOrTwo BCONPtr
+double p d = word64 p (castDoubleToWord64 d)
+
+word64 :: Platform -> Word64 -> OneOrTwo BCONPtr
+word64 platform ww = case platformWordSize platform of
+ PW4 ->
+ let !wl = fromIntegral ww
+ !wh = fromIntegral (ww `unsafeShiftR` 32)
+ in case platformByteOrder platform of
+ LittleEndian -> word2 wl wh
+ BigEndian -> word2 wh wl
+ PW8 -> word (fromIntegral ww)
+
+word8 :: Platform -> Word8 -> OneOrTwo BCONPtr
+word8 platform x = case platformByteOrder platform of
+ LittleEndian -> word (fromIntegral x)
+ BigEndian -> word (fromIntegral x `unsafeShiftL` (platformWordSizeInBits platform - 8))
+
+word16 :: Platform -> Word16 -> OneOrTwo BCONPtr
+word16 platform x = case platformByteOrder platform of
+ LittleEndian -> word (fromIntegral x)
+ BigEndian -> word (fromIntegral x `unsafeShiftL` (platformWordSizeInBits platform - 16))
+
+word32 :: Platform -> Word32 -> OneOrTwo BCONPtr
+word32 platform x = case platformByteOrder platform of
+ LittleEndian -> word (fromIntegral x)
+ BigEndian -> case platformWordSize platform of
+ PW4 -> word (fromIntegral x)
+ PW8 -> word (fromIntegral x `unsafeShiftL` 32)
isLargeW :: Word -> Bool
isLargeW n = n > 65535
=====================================
compiler/GHC/ByteCode/Instr.hs
=====================================
@@ -16,6 +16,7 @@ import GHC.Cmm.Type (Width)
import GHC.StgToCmm.Layout ( ArgRep(..) )
import GHC.Utils.Outputable
import GHC.Types.Name
+import GHC.Types.Id
import GHC.Types.Literal
import GHC.Types.Unique
import GHC.Core.DataCon
@@ -43,9 +44,63 @@ data ProtoBCO
protoBCOBitmap :: [StgWord],
protoBCOBitmapSize :: Word,
protoBCOArity :: Int,
- -- what the BCO came from, for debugging only
+ -- | What the BCO came from, for debugging only
protoBCOExpr :: Either [CgStgAlt] CgStgRhs
}
+ -- | A top-level static constructor application object
+ -- See Note [Static constructors in Bytecode]
+ | ProtoStaticCon {
+ protoStaticConName :: Name,
+ -- ^ The name to which this static constructor is bound,
+ -- not to be confused with the DataCon itself.
+ protoStaticCon :: DataCon,
+ -- ^ The DataCon being constructed.
+ -- We use this to construct the right info table.
+ protoStaticConData :: [Either Literal Id],
+ -- ^ The static constructor pointer and non-pointer arguments, sorted
+ -- in the order they should appear at runtime (see 'mkVirtConstrOffsets').
+ -- The pointers always come first, followed by the non-pointers.
+ protoStaticConExpr :: CgStgRhs
+ -- ^ What the static con came from, for debugging only
+ }
+
+{-
+Note [Static constructors in Bytecode]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In bytecode, top-level 'StgRhsCon's are lowered to 'ProtoStaticCon' rather than
+'ProtoBCO'. A 'ProtoStaticCon' represents directly a heap allocated data
+constructor application. We can do this only for top-level 'StgRhsCon's, where
+all the data arguments to the constructor are statically known.
+
+'StgRhsCon's which have free variables are compiled down to BCOs which push the
+arguments and then 'PACK' the constructor, just like 'StgConApp's.
+
+Example:
+
+ Haskell:
+
+ data X = X Char# Char
+ x = X 'a'# 'b'
+
+ Stg:
+
+ x1 = GHC.Types.C#! ['b'#];
+ X.x = X.X! ['a#' x2];
+
+ X.X = \r [arg1 arg2] X.X [arg1 arg2];
+
+ ByteCode:
+ ProtoStaticCon x1:
+ C# [Left 'b'#]
+ ProtoStaticCon X.x:
+ X.X [Left 'a'#, Right x1]
+
+ ProtoBCO X.X:
+ PUSH_LL 0 1
+ PACK X.X 2
+ SLIDE 1 2
+ RETURN P
+-}
-- | A local block label (e.g. identifying a case alternative).
newtype LocalLabel = LocalLabel { getLocalLabel :: Word32 }
@@ -278,6 +333,11 @@ data BCInstr
-- Printing bytecode instructions
instance Outputable ProtoBCO where
+ ppr (ProtoStaticCon nm con args origin)
+ = text "ProtoStaticCon" <+> ppr nm <> colon
+ $$ nest 3 (pprStgRhsShort shortStgPprOpts origin)
+ $$ nest 3 (text "constructor: " <+> ppr con)
+ $$ nest 3 (text "sorted args: " <+> ppr args)
ppr (ProtoBCO { protoBCOName = name
, protoBCOInstrs = instrs
, protoBCOBitmap = bitmap
@@ -469,7 +529,8 @@ instance Outputable BCInstr where
-- stack high water mark, but it doesn't seem worth the hassle.
protoBCOStackUse :: ProtoBCO -> Word
-protoBCOStackUse bco = sum (map bciStackUse (protoBCOInstrs bco))
+protoBCOStackUse ProtoBCO{protoBCOInstrs} = sum (map bciStackUse protoBCOInstrs)
+protoBCOStackUse ProtoStaticCon{} = 0
bciStackUse :: BCInstr -> Word
bciStackUse STKCHECK{} = 0
=====================================
compiler/GHC/ByteCode/Linker.hs
=====================================
@@ -12,6 +12,7 @@ module GHC.ByteCode.Linker
, lookupStaticPtr
, lookupIE
, linkFail
+ , BCOIx(..)
)
where
@@ -46,31 +47,68 @@ import Data.Array.Unboxed
import Foreign.Ptr
import GHC.Exts
-{-
+{- |
Linking interpretables into something we can run
-}
-
linkBCO
:: Interp
-> PkgsLoaded
-> BytecodeLoaderState
- -> NameEnv Int
+ -> NameEnv BCOIx
+ -- ^ A mapping from names to references to other BCOs
+ -- or static constructors in this group.
-> UnlinkedBCO
-> IO ResolvedBCO
-linkBCO interp pkgs_loaded bytecode_state bco_ix
- (UnlinkedBCO _ arity insns bitmap lits0 ptrs0) = 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 bytecode_state) (elemsFlatBag lits0)
- ptrs <- mapM (resolvePtr interp pkgs_loaded bytecode_state bco_ix) (elemsFlatBag ptrs0)
- let lits' = listArray (0 :: Int, fromIntegral (sizeFlatBag lits0)-1) lits
- return $ ResolvedBCO { resolvedBCOIsLE = isLittleEndian
- , resolvedBCOArity = arity
- , resolvedBCOInstrs = insns
- , resolvedBCOBitmap = bitmap
- , resolvedBCOLits = mkBCOByteArray lits'
- , resolvedBCOPtrs = addListToSS emptySS ptrs
- }
+linkBCO interp pkgs_loaded bytecode_state bco_ix unl_bco = do
+ case unl_bco of
+ UnlinkedBCO _ arity insns
+ bitmap lits0 ptrs0 -> do
+ lits <- doLits lits0
+ ptrs <- doPtrs ptrs0
+ return ResolvedBCO
+ { resolvedBCOIsLE = isLittleEndian
+ , resolvedBCOArity = arity
+ , resolvedBCOInstrs = insns
+ , resolvedBCOBitmap = bitmap
+ , resolvedBCOLits = lits
+ , resolvedBCOPtrs = ptrs
+ }
+
+ UnlinkedStaticCon
+ { unlinkedStaticConLits = lits0
+ , unlinkedStaticConPtrs = ptrs0
+ , unlinkedStaticConDataConName
+ , unlinkedStaticConIsUnlifted
+ } -> do
+ Ptr itbl_ptr# <- lookupIE interp pkgs_loaded bytecode_state unlinkedStaticConDataConName
+ lits <- doLits lits0
+ ptrs <- doPtrs ptrs0
+ return ResolvedStaticCon
+ { resolvedBCOIsLE = isLittleEndian
+ , resolvedStaticConInfoPtr = W# (int2Word# (addr2Int# itbl_ptr#))
+ , resolvedStaticConArity = sizeFlatBag lits0 + sizeFlatBag ptrs0
+ , resolvedStaticConLits = lits
+ , resolvedStaticConPtrs = ptrs
+ , resolvedStaticConIsUnlifted = unlinkedStaticConIsUnlifted
+ }
+ where
+ doLits lits0 = do
+ (lits :: [Word]) <- mapM (lookupLiteral interp pkgs_loaded bytecode_state) (elemsFlatBag lits0)
+ let lits' = listArray (0 :: Int, fromIntegral (sizeFlatBag lits0)-1) lits
+ return $ mkBCOByteArray lits'
+ doPtrs ptrs0 = addListToSS emptySS <$> do
+ mapM (resolvePtr interp pkgs_loaded bytecode_state bco_ix) (elemsFlatBag ptrs0)
+
+-- | An index into a BCO or Static Constructor in this group.
+--
+-- We distinguish between lifted and unlifted static constructors because
+-- lifted ones get resolved by tying a knot, since there may be circular
+-- dependencies between them, whereas unlifted ones get constructed in a first
+-- pass.
+data BCOIx = BCOIx !Int
+ | LiftedStaticConIx !Int
+ | UnliftedStaticConIx !Int
+ deriving (Eq, Ord, Show)
lookupLiteral :: Interp -> PkgsLoaded -> BytecodeLoaderState -> BCONPtr -> IO Word
lookupLiteral interp pkgs_loaded bytecode_state ptr = case ptr of
@@ -154,13 +192,16 @@ resolvePtr
:: Interp
-> PkgsLoaded
-> BytecodeLoaderState
- -> NameEnv Int
+ -> NameEnv BCOIx
-> BCOPtr
-> IO ResolvedBCOPtr
resolvePtr interp pkgs_loaded bco_loader_state bco_ix ptr = case ptr of
BCOPtrName nm
- | Just ix <- lookupNameEnv bco_ix nm
- -> return (ResolvedBCORef ix) -- ref to another BCO in this group
+ | Just bix <- lookupNameEnv bco_ix nm
+ -> return $ case bix of
+ BCOIx ix -> ResolvedBCORef ix
+ LiftedStaticConIx ix -> ResolvedStaticConRef ix
+ UnliftedStaticConIx ix -> ResolvedUnliftedStaticConRef ix
| Just (_, rhv) <- lookupNameBytecodeState bco_loader_state nm
-> return (ResolvedBCOPtr (unsafeForeignRefToRemoteRef rhv))
=====================================
compiler/GHC/ByteCode/Serialize.hs
=====================================
@@ -315,22 +315,39 @@ instance Binary CompiledByteCode where
put_ bh bc_spt_entries
instance Binary UnlinkedBCO where
- get bh =
- UnlinkedBCO
- <$> getViaBinName bh
- <*> get bh
- <*> (Binary.decode <$> get bh)
- <*> (Binary.decode <$> get bh)
- <*> get bh
- <*> get bh
+ get bh = do
+ t <- getByte bh
+ case t of
+ 0 -> UnlinkedBCO
+ <$> getViaBinName bh
+ <*> get bh
+ <*> (Binary.decode <$> get bh)
+ <*> (Binary.decode <$> get bh)
+ <*> get bh
+ <*> get bh
+ 1 -> UnlinkedStaticCon
+ <$> getViaBinName bh
+ <*> getViaBinName bh
+ <*> get bh
+ <*> get bh
+ <*> get bh
+ _ -> panic "Binary UnlinkedBCO: invalid byte"
put_ bh UnlinkedBCO {..} = do
+ putByte bh 0
putViaBinName bh unlinkedBCOName
put_ bh unlinkedBCOArity
put_ bh $ Binary.encode unlinkedBCOInstrs
put_ bh $ Binary.encode unlinkedBCOBitmap
put_ bh unlinkedBCOLits
put_ bh unlinkedBCOPtrs
+ put_ bh UnlinkedStaticCon {..} = do
+ putByte bh 1
+ putViaBinName bh unlinkedStaticConName
+ putViaBinName bh unlinkedStaticConDataConName
+ put_ bh unlinkedStaticConLits
+ put_ bh unlinkedStaticConPtrs
+ put_ bh unlinkedStaticConIsUnlifted
instance Binary BCOPtr where
get bh = do
=====================================
compiler/GHC/ByteCode/Types.hs
=====================================
@@ -29,6 +29,7 @@ module GHC.ByteCode.Types
) where
import GHC.Prelude
+import qualified Data.ByteString.Char8 as BS8
import GHC.Data.FastString
import GHC.Data.FlatBag
@@ -248,16 +249,31 @@ data UnlinkedBCO
= UnlinkedBCO {
unlinkedBCOName :: !Name,
unlinkedBCOArity :: {-# UNPACK #-} !Int,
- unlinkedBCOInstrs :: !(BCOByteArray Word16), -- insns
- unlinkedBCOBitmap :: !(BCOByteArray Word), -- bitmap
- unlinkedBCOLits :: !(FlatBag BCONPtr), -- non-ptrs
- unlinkedBCOPtrs :: !(FlatBag BCOPtr) -- ptrs
+ unlinkedBCOInstrs :: !(BCOByteArray Word16), -- insns
+ unlinkedBCOBitmap :: !(BCOByteArray Word), -- bitmap
+ unlinkedBCOLits :: !(FlatBag BCONPtr), -- non-ptrs
+ unlinkedBCOPtrs :: !(FlatBag BCOPtr) -- ptrs
+ }
+ -- | An unlinked top-level static constructor
+ -- See Note [Static constructors in Bytecode]
+ | UnlinkedStaticCon {
+ unlinkedStaticConName :: !Name,
+ -- ^ The name to which this static constructor is bound, not to be
+ -- confused with the name of the static constructor itself
+ -- ('unlinkedStaticConDataConName')
+ unlinkedStaticConDataConName :: !Name,
+ unlinkedStaticConLits :: !(FlatBag BCONPtr), -- non-ptrs
+ unlinkedStaticConPtrs :: !(FlatBag BCOPtr), -- ptrs
+ unlinkedStaticConIsUnlifted :: !Bool
}
instance NFData UnlinkedBCO where
rnf UnlinkedBCO{..} =
rnf unlinkedBCOLits `seq`
rnf unlinkedBCOPtrs
+ rnf UnlinkedStaticCon{..} =
+ rnf unlinkedStaticConLits `seq`
+ rnf unlinkedStaticConPtrs
data BCOPtr
= BCOPtrName !Name
@@ -270,6 +286,12 @@ instance NFData BCOPtr where
rnf (BCOPtrBCO bco) = rnf bco
rnf x = x `seq` ()
+instance Outputable BCOPtr where
+ ppr (BCOPtrName nm) = text "BCOPtrName" <+> ppr nm
+ ppr (BCOPtrPrimOp op) = text "BCOPtrPrimOp" <+> ppr op
+ ppr (BCOPtrBCO bco) = text "BCOPtrBCO" <+> ppr bco
+ ppr (BCOPtrBreakArray mod) = text "<break array for" <+> ppr mod <> char '>'
+
data BCONPtr
= BCONPtrWord {-# UNPACK #-} !Word
| BCONPtrLbl !FastString
@@ -287,6 +309,16 @@ data BCONPtr
-- | A 'CostCentre' remote pointer array's respective 'BreakpointId'
| BCONPtrCostCentre !InternalBreakpointId
+instance Outputable BCONPtr where
+ ppr (BCONPtrWord w) = integer (fromIntegral w)
+ ppr (BCONPtrLbl lbl) = text "<label:" <> ftext lbl <> char '>'
+ ppr (BCONPtrItbl nm) = text "<itbl:" <+> ppr nm <> char '>'
+ ppr (BCONPtrAddr nm) = text "<addr:" <+> ppr nm <> char '>'
+ ppr (BCONPtrStr bs) = text "<string literal: " <+> text (BS8.unpack bs) <> char '>'
+ ppr (BCONPtrFS fs) = text "<fast string literal:" <+> ftext fs <> char '>'
+ ppr (BCONPtrFFIInfo _) = text "<FFIInfo>"
+ ppr (BCONPtrCostCentre bid) = text "<CostCentre for BreakpointId:" <+> ppr bid <> char '>'
+
instance NFData BCONPtr where
rnf x = x `seq` ()
@@ -295,6 +327,12 @@ instance Outputable UnlinkedBCO where
= sep [text "BCO", ppr nm, text "with",
ppr (sizeFlatBag lits), text "lits",
ppr (sizeFlatBag ptrs), text "ptrs" ]
+ ppr (UnlinkedStaticCon nm dc_nm lits ptrs unl)
+ = sep [text "StaticCon", ppr nm, text "for",
+ if unl then text "unlifted" else text "lifted",
+ ppr dc_nm, text "with",
+ ppr (sizeFlatBag lits), text "lits",
+ ppr (sizeFlatBag ptrs), text "ptrs" ]
instance Binary FFIInfo where
get bh = FFIInfo <$> get bh <*> get bh
=====================================
compiler/GHC/Cmm/Liveness.hs
=====================================
@@ -63,7 +63,7 @@ cmmGlobalLiveness platform graph =
-- | On entry to the procedure, there had better not be any LocalReg's live-in.
-- If you see this error it most likely means you are trying to use a variable
--- without it being defined in the given scope.
+-- without it being defined, or initialized, in the given scope.
noLiveOnEntry :: BlockId -> CmmLive LocalReg -> a -> a
noLiveOnEntry bid in_fact x =
if nullRegSet in_fact then x
=====================================
compiler/GHC/Linker/Loader.hs
=====================================
@@ -1043,11 +1043,35 @@ linkSomeBCOs interp pkgs_loaded bytecode_state mods = foldr fun do_link mods []
do_link [] = return []
do_link mods = do
let flat = [ bco | bcos <- mods, bco <- bcos ]
- names = map unlinkedBCOName flat
- bco_ix = mkNameEnv (zip names [0..])
+ unl_objs = filter isUnliftedObj flat
+ lif_objs = filter (not . isUnliftedObj) flat
+ unl_objs_ix = mkNameEnv (zipWith mkBCOIx [0..] unl_objs)
+ lif_objs_ix = mkNameEnv (zipWith mkBCOIx [0..] lif_objs)
+ bco_ix = plusNameEnv unl_objs_ix lif_objs_ix
resolved <- sequence [ linkBCO interp pkgs_loaded bytecode_state bco_ix bco | bco <- flat ]
- hvrefs <- createBCOs interp resolved
- return (zip names hvrefs)
+ hvrefs <- createBCOs interp resolved
+ return (zip (map mkBCOName $ unl_objs ++ lif_objs) hvrefs)
+
+ mkBCOName UnlinkedBCO{unlinkedBCOName}
+ = unlinkedBCOName
+ mkBCOName UnlinkedStaticCon{unlinkedStaticConName}
+ = unlinkedStaticConName
+
+ mkBCOIx ix
+ UnlinkedBCO{unlinkedBCOName}
+ = (unlinkedBCOName, BCOIx ix)
+ mkBCOIx ix
+ UnlinkedStaticCon
+ { unlinkedStaticConName
+ , unlinkedStaticConIsUnlifted }
+ | unlinkedStaticConIsUnlifted
+ = (unlinkedStaticConName, UnliftedStaticConIx ix)
+ | otherwise
+ = (unlinkedStaticConName, LiftedStaticConIx ix)
+
+ isUnliftedObj = \case
+ UnlinkedStaticCon{..} -> unlinkedStaticConIsUnlifted
+ _ -> False
-- | Useful to apply to the result of 'linkSomeBCOs'
makeForeignNamedHValueRefs
=====================================
compiler/GHC/StgToByteCode.hs
=====================================
@@ -301,6 +301,21 @@ argBits platform (rep : args)
-- Compile code for the right-hand side of a top-level binding
schemeTopBind :: (Id, CgStgRhs) -> BcM ProtoBCO
+schemeTopBind (id, rhs@(StgRhsCon _ dc _ _ args _))
+ = do
+ profile <- getProfile
+ let non_voids = addArgReps (assertNonVoidStgArgs args)
+ (_, _, args_offsets)
+ -- Compute the expected runtime ordering for the datacon fields
+ = mkVirtConstrOffsets profile non_voids
+ return ProtoStaticCon
+ { protoStaticConName = getName id
+ , protoStaticCon = dc
+ , protoStaticConData = [ case a of StgLitArg l -> Left l
+ StgVarArg i -> Right i
+ | (NonVoid a, _) <- args_offsets ]
+ , protoStaticConExpr = rhs
+ }
schemeTopBind (id, rhs)
| Just data_con <- isDataConWorkId_maybe id,
isNullaryRepDataCon data_con = do
@@ -321,7 +336,6 @@ schemeTopBind (id, rhs)
| otherwise
= schemeR [{- No free variables -}] (getName id, rhs)
-
-- -----------------------------------------------------------------------------
-- schemeR
@@ -341,22 +355,22 @@ schemeR :: [Id] -- Free vars of the RHS, ordered as they
-- top-level things, which have no free vars.
-> (Name, CgStgRhs)
-> BcM ProtoBCO
-schemeR fvs (nm, rhs)
- = schemeR_wrk fvs nm rhs (collect rhs)
+schemeR fvs (nm, rhs@(StgRhsClosure _ _ _ args body _))
+ = schemeR_wrk fvs nm rhs (args, body)
+schemeR fvs (nm, rhs@(StgRhsCon _cc dc cnum _ticks args _type))
+ -- unlike top-level StgRhsCon, which are static (see schemeTopBind),
+ -- non-top-level StgRhsCon are compiled just like StgRhsClosure StgConApp
+ = schemeR_wrk fvs nm rhs ([], StgConApp dc cnum args [])
-- If an expression is a lambda, return the
-- list of arguments to the lambda (in R-to-L order) and the
-- underlying expression
-collect :: CgStgRhs -> ([Var], CgStgExpr)
-collect (StgRhsClosure _ _ _ args body _) = (args, body)
-collect (StgRhsCon _cc dc cnum _ticks args _typ) = ([], StgConApp dc cnum args [])
-
schemeR_wrk
:: [Id]
-> Name
-> CgStgRhs -- expression e, for debugging only
- -> ([Var], CgStgExpr) -- result of collect on e
+ -> ([Var], CgStgExpr) -- the args and body of an StgRhsClosure
-> BcM ProtoBCO
schemeR_wrk fvs nm original_body (args, body)
= do
@@ -546,7 +560,9 @@ schemeE d s p (StgLet _ext binds body) = do
sizes = map (\rhs_fvs -> sum (map size_w rhs_fvs)) fvss
-- the arity of each rhs
- arities = map (strictGenericLength . fst . collect) rhss
+ stgRhsArity (StgRhsClosure _ _ _ args _ _) = strictGenericLength args
+ stgRhsArity StgRhsCon{} = 0
+ arities = map stgRhsArity rhss
-- This p', d' defn is safe because all the items being pushed
-- are ptrs, so all have size 1 word. d' and p' reflect the stack
@@ -622,7 +638,7 @@ schemeE d s p (StgCase scrut bndr _ alts)
and then compile the code as if it was just the expression E.
-}
--- Compile code to do a tail call. Specifically, push the fn,
+-- | Compile code to do a tail call. Specifically, push the fn,
-- slide the on-stack app back down to the sequel depth,
-- and enter. Four cases:
--
@@ -642,7 +658,6 @@ schemeE d s p (StgCase scrut bndr _ alts)
--
-- 4. Otherwise, it must be a function call. Push the args
-- right to left, SLIDE and ENTER.
-
schemeT :: StackDepth -- Stack depth
-> Sequel -- Sequel depth
-> BCEnv -- stack env
=====================================
compiler/GHC/StgToCmm/Closure.hs
=====================================
@@ -339,7 +339,7 @@ type DynTag = Int -- The tag on a *pointer*
-- Also see Note [Tagging big families] in GHC.StgToCmm.Expr
--
-- The interpreter also needs to be updated if we change the
--- tagging strategy; see tagConstr in rts/Interpreter.c.
+-- tagging strategy; see tagConstr in rts/storage/ClosureMacros.h.
isSmallFamily :: Platform -> Int -> Bool
isSmallFamily platform fam_size = fam_size <= mAX_PTR_TAG platform
=====================================
compiler/GHC/StgToCmm/Prim.hs
=====================================
@@ -1771,6 +1771,7 @@ emitPrimOp cfg primop =
DataToTagLargeOp -> alwaysExternal
MkApUpd0_Op -> alwaysExternal
NewBCOOp -> alwaysExternal
+ NewConAppObjOp -> alwaysExternal
UnpackClosureOp -> alwaysExternal
ListThreadsOp -> alwaysExternal
ClosureSizeOp -> alwaysExternal
=====================================
compiler/GHC/StgToJS/Prim.hs
=====================================
@@ -1165,6 +1165,7 @@ genPrim prof bound ty op = case op of
AnyToAddrOp -> unhandledPrimop op
MkApUpd0_Op -> unhandledPrimop op
NewBCOOp -> unhandledPrimop op
+ NewConAppObjOp -> unhandledPrimop op
UnpackClosureOp -> unhandledPrimop op
ClosureSizeOp -> unhandledPrimop op
GetApStackValOp -> unhandledPrimop op
=====================================
libraries/ghci/GHCi/CreateBCO.hs
=====================================
@@ -1,11 +1,16 @@
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE StandaloneKindSignatures #-}
+{-# LANGUAGE UnliftedNewtypes #-}
+{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE CPP #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE KindSignatures #-}
--
-- (c) The University of Glasgow 2002-2006
@@ -15,103 +20,321 @@
module GHCi.CreateBCO (createBCOs) where
import Prelude -- See note [Why do we import Prelude here?]
+import Data.List (sortBy)
+import Data.Ord (comparing)
import GHCi.ResolvedBCO
import GHCi.RemoteTypes
import GHCi.BreakArray
import GHC.Data.SizedSeq
+import Data.List (partition)
+import Data.Graph
import System.IO (fixIO)
import Control.Monad
import Data.Array.Base
import Foreign hiding (newArray)
-import Unsafe.Coerce (unsafeCoerce)
+import Unsafe.Coerce (unsafeCoerce, unsafeCoerceUnlifted)
import GHC.Arr ( Array(..) )
import GHC.Exts hiding ( BCO, mkApUpd0#, newBCO# )
import GHC.Internal.Base ( BCO, mkApUpd0#, newBCO# )
import GHC.IO
import Control.Exception ( ErrorCall(..) )
+{-
+Note [Tying the knot in createBCOs]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+There are two passes for creating the BCOs:
+
+1. Allocate unlifted static cons, which are never mutual recursive, but may refer
+ to the array constructed in the second pass.
+
+2. Allocate BCOs and lifted static cons, which may have circular references
+ amongst themselves, and also refer to the unlifted cons allocated in the
+ first pass.
+
+Notably, it is crucial that all unlifted static cons are eagerly allocated,
+returning an evaluated and properly tagged unlifted value, and that all
+references to an unlifted static constructor use that unlifted value directly,
+rather than a thunk, to preserve the unliftedness invariants. Not doing so
+resulted in #25636, which was fixed by the commit introducing this Note.
+
+The unlifted static cons must be allocated in topological order, to ensure a
+reference from one to another has already been allocated and can be promptly used.
+
+The BCOs and lifted cons are allocated in 'fixIO', where references to other
+BCOs and static cons in the same group are resolved by writing into the
+'PtrsArr' a thunk that indexes the recursively constructed array of BCOs.
+References to unlifted cons are looked up in the array from the first pass and
+must definitely not be thunks.
+
+References from unlifted cons to BCOs are resolved similarly by constructing a
+thunk into the second pass array, hence why allocating the unlifted cons must
+be inside of the 'fixIO'.
+-}
+
createBCOs :: [ResolvedBCO] -> IO [HValueRef]
-createBCOs bcos = do
+createBCOs objs = do
+
+ let (unl_objs, bcos) = partition isUnliftedObj objs
+
let n_bcos = length bcos
- hvals <- fixIO $ \hvs -> do
- let arr = listArray (0, n_bcos-1) hvs
- mapM (createBCO arr) bcos
- mapM mkRemoteRef hvals
+ -- See Note [Tying the knot in createBCOs]
+ (unl_hvals, hvals) <- fixIO $ \ ~(_, hvs) -> do
+
+ let arr = listArray (0, n_bcos-1) hvs
-createBCO :: Array Int HValue -> ResolvedBCO -> IO HValue
-createBCO _ ResolvedBCO{..} | resolvedBCOIsLE /= isLittleEndian
+ -- First, construct the array of unlifted static cons.
+ --
+ -- Top-level unlifted constructors are never mutual recursive, so we can do
+ -- this by filling the array in topological order.
+ --
+ -- Lifted fields of unlifted data will store
+ -- thunks indexing the `arr` constructed by fixIO.
+ (unl_cons, unl_hvals) <- createUnliftedStaticCons unl_objs arr
+
+ -- Second, construct the lifted BCOs and static cons which may have
+ -- (circular) references to one another in this group. References from this
+ -- group to the unlifted static cons will be resolved by looking them up in
+ -- the array constructed in the first pass.
+ hvals <- mapM (createBCO arr unl_cons) bcos
+ return (unl_hvals, hvals)
+
+ mapM mkRemoteRef (unl_hvals ++ hvals)
+
+ where
+ isUnliftedObj :: ResolvedBCO -> Bool
+ isUnliftedObj = \case
+ ResolvedStaticCon{..} -> resolvedStaticConIsUnlifted
+ _ -> False
+
+createBCO :: Array Int HValue -> UnlConsArr -> ResolvedBCO -> IO HValue
+createBCO _ _ obj | resolvedBCOIsLE obj /= isLittleEndian
= throwIO (ErrorCall $
unlines [ "The endianness of the ResolvedBCO does not match"
, "the systems endianness. Using ghc and iserv in a"
, "mixed endianness setup is not supported!"
])
-createBCO arr bco
- = do linked_bco <- linkBCO' arr bco
- -- Note [Updatable CAF BCOs]
- -- ~~~~~~~~~~~~~~~~~~~~~~~~~
- -- Why do we need mkApUpd0 here? Otherwise top-level
- -- interpreted CAFs don't get updated after evaluation. A
- -- top-level BCO will evaluate itself and return its value
- -- when entered, but it won't update itself. Wrapping the BCO
- -- in an AP_UPD thunk will take care of the update for us.
- --
- -- Furthermore:
- -- (a) An AP thunk *must* point directly to a BCO
- -- (b) A zero-arity BCO *must* be wrapped in an AP thunk
- -- (c) An AP is always fully saturated, so we *can't* wrap
- -- non-zero arity BCOs in an AP thunk.
- --
- -- See #17424.
- if (resolvedBCOArity bco > 0)
- then return (HValue (unsafeCoerce linked_bco))
- else case mkApUpd0# linked_bco of { (# final_bco #) ->
- return (HValue final_bco) }
-
-
-linkBCO' :: Array Int HValue -> ResolvedBCO -> IO BCO
-linkBCO' arr ResolvedBCO{..} = do
- let
- ptrs = ssElts resolvedBCOPtrs
- n_ptrs = sizeSS resolvedBCOPtrs
+createBCO arr unl_arr bco
+ = do linked_thing <- linkBCO' arr unl_arr bco
+ case linked_thing of
+ LinkedBCO bco_arity linked_bco -> do
+ -- Note [Updatable CAF BCOs]
+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~
+ -- Why do we need mkApUpd0 here? Otherwise top-level
+ -- interpreted CAFs don't get updated after evaluation. A
+ -- top-level BCO will evaluate itself and return its value
+ -- when entered, but it won't update itself. Wrapping the BCO
+ -- in an AP_UPD thunk will take care of the update for us.
+ --
+ -- Furthermore:
+ -- (a) An AP thunk *must* point directly to a BCO
+ -- (b) A zero-arity BCO *must* be wrapped in an AP thunk
+ -- (c) An AP is always fully saturated, so we *can't* wrap
+ -- non-zero arity BCOs in an AP thunk.
+ --
+ -- See #17424.
+ if (bco_arity > 0)
+ then return (HValue (unsafeCoerce linked_bco))
+ else case mkApUpd0# linked_bco of { (# final_bco #) ->
+ return (HValue final_bco) }
+ LinkedStaticCon linked_static_con -> do
+ return linked_static_con
+ LinkedUnliftedStaticCon linked_static_con -> do
+ return $! forgetUnliftedHValue linked_static_con
+
+-- | The resulting of linking a BCO or static constructor
+data LinkedBCO
+ = LinkedBCO !Int{-BCO arity-} BCO
+ | LinkedStaticCon HValue
+ | LinkedUnliftedStaticCon UnliftedHValue
+
+-- | Construct an array of unlifted constructor closures given a list of 'UnliftedStaticCons'.
+--
+-- INVARIANT: Top-level unlifted constructors are never mutual recursive, so we
+-- can do this by filling the array in topological order.
+--
+-- Lifted fields of unlifted data will be filled by looking them up in the
+-- given array of lifted resolved objs.
+createUnliftedStaticCons
+ :: [ResolvedBCO] -- ^ 'UnliftedStaticCon's ONLY.
+ -> Array Int HValue -- ^ Lifted resolved objects
+ -> IO (UnlConsArr, [HValue])
+ -- ^ Return both the array to look up the unlifted static constrs by 'BCOIx',
+ -- and a list with the same unlifted objects, albeit the unliftedness is
+ -- forgotten using 'forgetUnliftedHValue' (allowing them to be put into a
+ -- list and later combined with the heap values of lifted objects).
+createUnliftedStaticCons objs lif_arr = do
+
+ -- Get topologically sorted objs with their original indices
+ let topoSortedObjs = topSortObjs objs
+ unl_arr <- newUnlConsArr (length topoSortedObjs)
- !(I# arity#) = resolvedBCOArity
+ -- Process objs in topological order, but write them at their original indexes
+ indexed_vs <- forM topoSortedObjs $ \(origIdx, obj) -> case obj of
+ ResolvedStaticCon{..}
+ | resolvedStaticConIsUnlifted
+ -> do
+ -- Because we topologically sort the objs, all unlifted references we
+ -- care about when linking this BCO will already be filled in.
+ -- The lifted ones are resolved by knot tying (see the fixIO above).
+ lbc <- linkBCO' lif_arr unl_arr obj
+ case lbc of
+ LinkedUnliftedStaticCon linked_static_con -> do
+ writeUnlConsArr origIdx linked_static_con unl_arr -- Write it to its original index position
+ return (origIdx, forgetUnliftedHValue linked_static_con)
+ _ -> error "createUnliftedStaticCons: unexpected lifted ResolvedBCO"
+ _ ->
+ error "createUnliftedStaticCons: unexpected lifted ResolvedBCO"
- !(EmptyArr empty#) = emptyArr -- See Note [BCO empty array]
- barr arr# = if I# (sizeofByteArray# arr#) == 0 then empty# else arr#
- insns_barr = barr (getBCOByteArray resolvedBCOInstrs)
- bitmap_barr = barr (getBCOByteArray resolvedBCOBitmap)
- literals_barr = barr (getBCOByteArray resolvedBCOLits)
+ -- Return them in the original order
+ let vs = map snd $ sortBy (comparing fst) indexed_vs
+ return (unl_arr, vs)
+ where
+ -- Return the topologically sorted objects with their original index.
+ topSortObjs :: [ResolvedBCO] -> [(Int, ResolvedBCO)]
+ topSortObjs objs =
+ let
+ edges = [ ((origIdx, obj), origIdx, getUnlDeps obj)
+ | (origIdx, obj) <- zip [0..] objs ]
- PtrsArr marr <- mkPtrsArray arr n_ptrs ptrs
- IO $ \s ->
- case unsafeFreezeArray# marr s of { (# s, arr #) ->
- case newBCO insns_barr literals_barr arr arity# bitmap_barr of { IO io ->
- io s
- }}
+ getUnlDeps :: ResolvedBCO -> [Int]
+ getUnlDeps (ResolvedStaticCon{..}) =
+ [ k | ptr <- ssElts resolvedStaticConPtrs
+ , ResolvedUnliftedStaticConRef k <- [ptr] ]
+ getUnlDeps _ = []
+ (graph, vertexToNode, _keyToVertex) = graphFromEdges edges
+ sortedVertices = topSort graph
+ in
+ [ ix_obj | v <- sortedVertices
+ , let (ix_obj, _, _) = vertexToNode v ]
+
+linkBCO' :: Array Int HValue -> UnlConsArr -> ResolvedBCO -> IO LinkedBCO
+linkBCO' arr unl_arr resolved_obj =
+ case resolved_obj of
+ ResolvedBCO{..} -> do
+ let
+ ptrs = ssElts resolvedBCOPtrs
+ n_ptrs = sizeSS resolvedBCOPtrs
+
+ !(I# arity#) = resolvedBCOArity
+
+ insns_barr = barr (getBCOByteArray resolvedBCOInstrs)
+ bitmap_barr = barr (getBCOByteArray resolvedBCOBitmap)
+ literals_barr = barr (getBCOByteArray resolvedBCOLits)
+
+ PtrsArr marr <- mkPtrsArray arr unl_arr n_ptrs ptrs
+ IO $ \s ->
+ case unsafeFreezeArray# marr s of { (# s, arr #) ->
+ case newBCO# insns_barr literals_barr arr arity# bitmap_barr s of
+ (# s, hval #) -> (# s, LinkedBCO resolvedBCOArity hval #)
+ }
+ ResolvedStaticCon{..} -> do
+
+ let
+ ptrs = ssElts resolvedStaticConPtrs
+ n_ptrs = sizeSS resolvedStaticConPtrs
+ !(W# data_size#) = resolvedStaticConArity
+
+ literals_barr = barr (getBCOByteArray resolvedStaticConLits)
+
+ !(W# itbl_ptr_w#) = resolvedStaticConInfoPtr
+ !(Ptr itbl_ptr#) = Ptr (int2Addr# (word2Int# itbl_ptr_w#))
+
+ PtrsArr marr <- mkPtrsArray arr unl_arr n_ptrs ptrs
+
+ IO $ \s ->
+ case unsafeFreezeArray# marr s of { (# s, arr #) ->
+ case newConAppObj# itbl_ptr# literals_barr arr data_size# s of
+ (# s, hval #) ->
+ if resolvedStaticConIsUnlifted then
+ (# s, LinkedUnliftedStaticCon (UnliftedHValue (unsafeCoerce# hval)) #)
+ else
+ (# s, LinkedStaticCon (HValue hval) #)
+ }
+ where
+ !(EmptyArr empty#) = emptyArr -- See Note [BCO empty array]
+ barr arr# = if I# (sizeofByteArray# arr#) == 0 then empty# else arr#
-- we recursively link any sub-BCOs while making the ptrs array
-mkPtrsArray :: Array Int HValue -> Word -> [ResolvedBCOPtr] -> IO PtrsArr
-mkPtrsArray arr n_ptrs ptrs = do
+mkPtrsArray :: Array Int HValue -> UnlConsArr -> Word -> [ResolvedBCOPtr] -> IO PtrsArr
+mkPtrsArray arr unl_arr n_ptrs ptrs = do
marr <- newPtrsArray (fromIntegral n_ptrs)
let
fill (ResolvedBCORef n) i =
writePtrsArrayHValue i (arr ! n) marr -- must be lazy!
+ fill (ResolvedStaticConRef n) i = do
+ writePtrsArrayHValue i (arr ! n) marr -- must be lazy!
+ fill (ResolvedUnliftedStaticConRef n) i = do
+ -- must be strict! we want to store the unlifted con,
+ -- not the arr indexing thunk.
+ !unl_val <- readUnlConsArr n unl_arr
+ writePtrsArrayHValue i unl_val marr
fill (ResolvedBCOPtr r) i = do
hv <- localRef r
writePtrsArrayHValue i hv marr
fill (ResolvedBCOStaticPtr r) i = do
writePtrsArrayPtr i (fromRemotePtr r) marr
fill (ResolvedBCOPtrBCO bco) i = do
- bco <- linkBCO' arr bco
- writePtrsArrayBCO i bco marr
+ obj <- linkBCO' arr unl_arr bco
+ case obj of
+ LinkedBCO _ bco ->
+ writePtrsArrayBCO i bco marr
+ LinkedStaticCon linked_static_con ->
+ writePtrsArrayHValue i linked_static_con marr
+ LinkedUnliftedStaticCon linked_static_con -> do
+ let !unl_val = forgetUnliftedHValue linked_static_con
+ writePtrsArrayHValue i unl_val marr
fill (ResolvedBCOPtrBreakArray r) i = do
BA mba <- localRef r
writePtrsArrayMBA i mba marr
zipWithM_ fill ptrs [0..]
return marr
+--------------------------------------------------------------------------------
+-- * Unlifted static constructors
+--------------------------------------------------------------------------------
+
+-- | A heap closure of unlifted type
+type UnliftedHValue :: UnliftedType
+newtype UnliftedHValue = UnliftedHValue (Any @UnliftedType)
+
+-- | Forget that a heap closure is unlifted, and return it as a lifted heap closure.
+-- Note: Going the other way around for an arbitrary heap closure is totally unsafe!
+forgetUnliftedHValue :: UnliftedHValue -> HValue
+forgetUnliftedHValue (UnliftedHValue a) = HValue (unsafeCoerce# a)
+
+-- | A lifted array with unlifted static constructor 'UnliftedHValue's
+data UnlConsArr = UnlConsArr (MutableArray# RealWorld UnliftedHValue)
+
+-- | Create a 'UnlConsArr' of the given size with all elements initialized to
+-- an empty ByteArray#
+newUnlConsArr :: Int -> IO UnlConsArr
+newUnlConsArr (I# arr_size#) = IO $ \s ->
+ -- Zero value to initialize the array.
+ -- Would be better to use undefined but can't for unlifted values.
+ let !(EmptyArr emp_arr#) = emptyArr
+ in case newArray# arr_size# (UnliftedHValue (unsafeCoerceUnlifted emp_arr#)) s of
+ (# s, arr #) -> (# s, UnlConsArr arr #)
+
+-- | Write an unlifted contructor closure into a 'UnlConsArr'
+writeUnlConsArr :: Int -> UnliftedHValue -> UnlConsArr -> IO ()
+writeUnlConsArr (I# i#) unl_hval (UnlConsArr unl_arr#) = IO $ \s ->
+ case writeArray# unl_arr# i# unl_hval s of
+ s -> (# s, () #)
+
+-- | Read an unlifted constructor closure from an 'UnlConsArr',
+-- but forget that the heap closure is unlifted using 'forgetUnliftedHValue'.
+-- This allows us to return it in @IO@ and return it in the final resolved objs list.
+readUnlConsArr :: Int -> UnlConsArr -> IO HValue
+readUnlConsArr (I# n#) (UnlConsArr unl_arr#) = IO $ \s ->
+ case readArray# unl_arr# n# s of
+ (# s, val #) -> (# s, forgetUnliftedHValue val #)
+
+--------------------------------------------------------------------------------
+-- * PtrsArr
+--------------------------------------------------------------------------------
+
data PtrsArr = PtrsArr (MutableArray# RealWorld HValue)
newPtrsArray :: Int -> IO PtrsArr
@@ -145,10 +368,9 @@ writePtrsArrayMBA :: Int -> MutableByteArray# s -> PtrsArr -> IO ()
writePtrsArrayMBA (I# i) mba (PtrsArr arr) = IO $ \s ->
case (unsafeCoerce# writeArray#) arr i mba s of s' -> (# s', () #)
-newBCO :: ByteArray# -> ByteArray# -> Array# a -> Int# -> ByteArray# -> IO BCO
-newBCO instrs lits ptrs arity bitmap = IO $ \s ->
- newBCO# instrs lits ptrs arity bitmap s
-
+--------------------------------------------------------------------------------
+-- * Empty array
+--------------------------------------------------------------------------------
{- Note [BCO empty array]
~~~~~~~~~~~~~~~~~~~~~~
Lots of BCOs have empty ptrs or nptrs, but empty arrays are not free:
@@ -165,3 +387,5 @@ emptyArr = unsafeDupablePerformIO $ IO $ \s ->
case unsafeFreezeByteArray# arr s of { (# s, farr #) ->
(# s, EmptyArr farr #)
}}
+
+
=====================================
libraries/ghci/GHCi/ResolvedBCO.hs
=====================================
@@ -47,6 +47,16 @@ data ResolvedBCO
-- ^ non-ptrs - subword sized entries still take up a full (host) word
resolvedBCOPtrs :: (SizedSeq ResolvedBCOPtr) -- ^ ptrs
}
+ -- | A resolved static constructor
+ -- See Note [Static constructors in Bytecode]
+ | ResolvedStaticCon {
+ resolvedBCOIsLE :: Bool,
+ resolvedStaticConInfoPtr :: {-# UNPACK #-} !Word, -- ^ info ptr Addr# as a Word
+ resolvedStaticConArity :: {-# UNPACK #-} !Word,
+ resolvedStaticConLits :: BCOByteArray Word,
+ resolvedStaticConPtrs :: SizedSeq ResolvedBCOPtr,
+ resolvedStaticConIsUnlifted :: Bool
+ }
deriving (Generic, Show)
-- | Wrapper for a 'ByteArray#'.
@@ -80,13 +90,27 @@ instance Show (BCOByteArray Word) where
-- same endianness.
instance Binary ResolvedBCO where
put ResolvedBCO{..} = do
+ putWord8 0
put resolvedBCOIsLE
put resolvedBCOArity
put resolvedBCOInstrs
put resolvedBCOBitmap
put resolvedBCOLits
put resolvedBCOPtrs
- get = ResolvedBCO <$> get <*> get <*> get <*> get <*> get <*> get
+ put ResolvedStaticCon{..} = do
+ putWord8 1
+ put resolvedBCOIsLE
+ put resolvedStaticConInfoPtr
+ put resolvedStaticConArity
+ put resolvedStaticConLits
+ put resolvedStaticConPtrs
+ put resolvedStaticConIsUnlifted
+ get = do
+ t <- getWord8
+ case t of
+ 0 -> ResolvedBCO <$> get <*> get <*> get <*> get <*> get <*> get
+ 1 -> ResolvedStaticCon <$> get <*> get <*> get <*> get <*> get <*> get
+ _ -> error "Binary ResolvedBCO: invalid byte"
-- See Note [BCOByteArray serialization]
instance (Binary a, Storable a, IArray UArray a) => Binary (BCOByteArray a) where
@@ -96,7 +120,8 @@ instance (Binary a, Storable a, IArray UArray a) => Binary (BCOByteArray a) wher
data ResolvedBCOPtr
= ResolvedBCORef {-# UNPACK #-} !Int
- -- ^ reference to the Nth BCO in the current set
+ -- ^ reference to the Nth BCO in the current set of BCOs and
+ -- lifted static constructors
| ResolvedBCOPtr {-# UNPACK #-} !(RemoteRef HValue)
-- ^ reference to a previously created BCO
| ResolvedBCOStaticPtr {-# UNPACK #-} !(RemotePtr ())
@@ -105,6 +130,12 @@ data ResolvedBCOPtr
-- ^ a nested BCO
| ResolvedBCOPtrBreakArray {-# UNPACK #-} !(RemoteRef BreakArray)
-- ^ Resolves to the MutableArray# inside the BreakArray
+ | ResolvedStaticConRef {-# UNPACK #-} !Int
+ -- ^ reference to the Nth static constructor in the current set of BCOs
+ -- and lifted static constructors
+ | ResolvedUnliftedStaticConRef {-# UNPACK #-} !Int
+ -- ^ reference to the Nth unlifted static constructor in the current set
+ -- of exclusively unlifted static constructors
deriving (Generic, Show)
instance Binary ResolvedBCOPtr
=====================================
rts/Interpreter.c
=====================================
@@ -709,14 +709,6 @@ slow_spw(void *Sp, StgStack *cur_stack, StgWord offset_words){
}
}
-// Compute the pointer tag for the constructor and tag the pointer;
-// see Note [Data constructor dynamic tags] in GHC.StgToCmm.Closure.
-//
-// Note: we need to update this if we change the tagging strategy.
-STATIC_INLINE StgClosure *tagConstr(StgClosure *con) {
- return TAG_CLOSURE(stg_min(TAG_MASK, 1 + GET_TAG(con)), con);
-}
-
static StgWord app_ptrs_itbl[] = {
(W_)&stg_ap_p_info,
(W_)&stg_ap_pp_info,
=====================================
rts/PrimOps.cmm
=====================================
@@ -2208,6 +2208,44 @@ for:
return (bco);
}
+// Ptr InfoTable, [Literals] [Ptrs] ==> CONSTR heap closure
+stg_newConAppObjzh ( W_ datacon_info, P_ literals, P_ ptrs , W_ arity )
+{
+ W_ con_obj, bytes;
+
+ bytes = SIZEOF_StgHeader + WDS(arity);
+
+ ALLOC_PRIM (bytes);
+ con_obj = Hp - bytes + WDS(1);
+
+ // No memory barrier necessary as this is a new allocation.
+ SET_HDR(con_obj, datacon_info, CCS_MAIN);
+
+ // Copy the ptrs followed by nonptrs into the constructor payload
+ W_ i, n_ptrs;
+ n_ptrs = StgMutArrPtrs_ptrs(ptrs);
+ i = 0;
+loop1:
+ if (i < n_ptrs) {
+ StgClosure_payload(con_obj,i) = StgMutArrPtrs_payload(ptrs,i);
+ i = i + 1;
+ goto loop1;
+ }
+ i = 0;
+loop2:
+ if (i < BYTE_ARR_WDS(literals)) {
+ W_ offset;
+ offset = n_ptrs + i;
+ StgClosure_payload(con_obj,offset) = StgArrBytes_payload(literals,i);
+ i = i + 1;
+ goto loop2;
+ }
+
+ W_ tagged_con_obj;
+ (tagged_con_obj) = ccall tagConstr(con_obj);
+ return (tagged_con_obj);
+}
+
stg_mkApUpd0zh ( P_ bco )
{
W_ ap;
=====================================
rts/RtsSymbols.c
=====================================
@@ -634,6 +634,7 @@ extern char **environ;
SymI_HasDataProto(stg_casSmallArrayzh) \
SymI_HasDataProto(stg_copyArray_barrier) \
SymI_HasDataProto(stg_newBCOzh) \
+ SymI_HasDataProto(stg_newConAppObjzh) \
SymI_HasDataProto(stg_newByteArrayzh) \
SymI_HasDataProto(stg_casIntArrayzh) \
SymI_HasDataProto(stg_casInt8Arrayzh) \
@@ -655,7 +656,7 @@ extern char **environ;
SymI_HasDataProto(stg_isMutableByteArrayWeaklyPinnedzh) \
SymI_HasDataProto(stg_shrinkMutableByteArrayzh) \
SymI_HasDataProto(stg_resizzeMutableByteArrayzh) \
- SymI_HasDataProto(stg_shrinkSmallMutableArrayzh) \
+ SymI_HasDataProto(stg_shrinkSmallMutableArrayzh) \
SymI_HasProto(newSpark) \
SymI_HasProto(updateRemembSetPushThunk) \
SymI_HasProto(updateRemembSetPushThunk_) \
=====================================
rts/include/rts/storage/ClosureMacros.h
=====================================
@@ -140,6 +140,16 @@ EXTERN_INLINE StgHalfWord GET_TAG(const StgClosure *con)
return get_itbl(con)->srt;
}
+// Compute the pointer tag for the constructor and tag the pointer;
+// see Note [Data constructor dynamic tags] in GHC.StgToCmm.Closure.
+//
+// Note: we need to update this if we change the tagging strategy.
+EXTERN_INLINE StgClosure *tagConstr(StgClosure *con);
+EXTERN_INLINE StgClosure *tagConstr(StgClosure *con)
+{
+ return TAG_CLOSURE(stg_min(TAG_MASK, 1 + GET_TAG(con)), con);
+}
+
/* -----------------------------------------------------------------------------
Macros for building closures
-------------------------------------------------------------------------- */
=====================================
rts/include/stg/MiscClosures.h
=====================================
@@ -584,6 +584,7 @@ RTS_FUN_DECL(stg_runRWzh);
RTS_FUN_DECL(stg_newBCOzh);
RTS_FUN_DECL(stg_mkApUpd0zh);
+RTS_FUN_DECL(stg_newConAppObjzh);
RTS_FUN_DECL(stg_retryzh);
RTS_FUN_DECL(stg_catchRetryzh);
=====================================
testsuite/tests/codeGen/should_run/T23146/T25636.stdout
=====================================
@@ -0,0 +1 @@
+True
=====================================
utils/deriveConstants/Main.hs
=====================================
@@ -460,9 +460,10 @@ wanteds os = concat
,closureSize Both "StgAnnFrame"
,closureField C "StgAnnFrame" "ann"
- ,closureSize Both "StgMutArrPtrs"
- ,closureField Both "StgMutArrPtrs" "ptrs"
- ,closureField Both "StgMutArrPtrs" "size"
+ ,closureSize Both "StgMutArrPtrs"
+ ,closureField Both "StgMutArrPtrs" "ptrs"
+ ,closureField Both "StgMutArrPtrs" "size"
+ ,closurePayload C "StgMutArrPtrs" "payload"
,closureSize Both "StgSmallMutArrPtrs"
,closureField Both "StgSmallMutArrPtrs" "ptrs"
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/0fa83d730f5732be81d7641dfd0cf03…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/0fa83d730f5732be81d7641dfd0cf03…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
Cheng Shao pushed to branch wip/deepseq-primop at Glasgow Haskell Compiler / GHC
Commits:
ea5fe7e8 by Cheng Shao at 2025-12-23T20:55:39+01:00
WIP
- - - - -
16 changed files:
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/StgToCmm/Prim.hs
- compiler/GHC/StgToJS/Prim.hs
- libraries/base/src/GHC/Base.hs
- libraries/base/src/GHC/Exts.hs
- libraries/ghc-experimental/ghc-experimental.cabal.in
- + libraries/ghc-experimental/src/GHC/DeepSeq.hs
- + rts/DeepSeq.cmm
- rts/RtsSymbols.c
- rts/include/stg/MiscClosures.h
- rts/rts.cabal
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout
- testsuite/tests/interface-stability/ghc-prim-exports.stdout
- + testsuite/tests/primops/should_run/DeepSeqPrimOp.hs
- + testsuite/tests/primops/should_run/DeepSeqPrimOp.stdout
- testsuite/tests/primops/should_run/all.T
Changes:
=====================================
compiler/GHC/Builtin/primops.txt.pp
=====================================
@@ -4537,6 +4537,23 @@ primop PrefetchValueOp0 "prefetchValue0#" GenPrimOp
with effect = ReadWriteEffect
+------------------------------------------------------------------------
+section "Forcing evaluation"
+ {Primitives for forcing evaluation within a state thread.}
+------------------------------------------------------------------------
+
+primop DeepSeqOp "deepseq#" GenPrimOp
+ a -> State# s -> (# State# s, Int#, a #)
+ { @'deepseq#' x s@ deeply evaluates @x@ in the state thread; see
+ 'GHC.DeepSeq.forceIO' for the user-facing semantics. }
+ with
+ out_of_line = True
+ effect = ReadWriteEffect
+ -- See Note [seq# magic] in GHC.Types.Id.Make: we must not let strictness
+ -- analysis see through the sequencing effect.
+ strictness = { \ _arity -> mkClosedDmdSig [ topDmd, topDmd ] topDiv }
+
+
-- Note [RuntimeRep polymorphism in continuation-style primops]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- See below.
=====================================
compiler/GHC/StgToCmm/Prim.hs
=====================================
@@ -1705,6 +1705,7 @@ emitPrimOp cfg primop =
AtomicModifyMutVar2Op -> alwaysExternal
AtomicModifyMutVar_Op -> alwaysExternal
CasMutVarOp -> alwaysExternal
+ DeepSeqOp -> alwaysExternal
CatchOp -> alwaysExternal
RaiseOp -> alwaysExternal
RaiseUnderflowOp -> alwaysExternal
=====================================
compiler/GHC/StgToJS/Prim.hs
=====================================
@@ -1155,6 +1155,8 @@ genPrim prof bound ty op = case op of
------------------------------ Unhandled primops -------------------
+ DeepSeqOp -> unhandledPrimop op
+
AnnotateStackOp -> unhandledPrimop op
NewPromptTagOp -> unhandledPrimop op
=====================================
libraries/base/src/GHC/Base.hs
=====================================
@@ -149,6 +149,9 @@ import GHC.Prim hiding
-- whereFrom# is similarly internal.
, whereFrom#
, isByteArrayWeaklyPinned#, isMutableByteArrayWeaklyPinned#
+ -- Users should use the interface provided by GHC.DeepSeq in
+ -- ghc-experimental.
+ , deepseq#
-- Don't re-export vector FMA instructions
, fmaddFloatX4#
, fmsubFloatX4#
=====================================
libraries/base/src/GHC/Exts.hs
=====================================
@@ -124,6 +124,10 @@ import GHC.Prim hiding
, whereFrom#
, isByteArrayWeaklyPinned#, isMutableByteArrayWeaklyPinned#
+ -- Users should use the interface provided by GHC.DeepSeq in
+ -- ghc-experimental.
+ , deepseq#
+
-- Don't re-export vector FMA instructions
, fmaddFloatX4#
, fmsubFloatX4#
=====================================
libraries/ghc-experimental/ghc-experimental.cabal.in
=====================================
@@ -31,6 +31,7 @@ library
exposed-modules:
Data.Sum.Experimental
Data.Tuple.Experimental
+ GHC.DeepSeq
GHC.PrimOps
GHC.Profiling.Eras
GHC.TypeLits.Experimental
=====================================
libraries/ghc-experimental/src/GHC/DeepSeq.hs
=====================================
@@ -0,0 +1,44 @@
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+
+module GHC.DeepSeq
+ ( force,
+ forceIO,
+ )
+where
+
+import GHC.IO
+import GHC.Internal.Exts
+
+-- | Pure wrapper around 'forceIO'.
+force :: a -> (Bool, a)
+force = unsafePerformIO . forceIO
+
+-- | Deeply evaluate a value in the 'IO' monad, returning the forced value and
+-- a flag indicating whether any unevaluated closure was forced.
+--
+-- This is a primitive analogue of 'Control.DeepSeq.force' / @rnf@ that does
+-- not require an 'NFData' constraint. It traverses algebraic data (constructor
+-- fields), immutable arrays, and the contents of 'MutVar#', 'MVar#',
+-- 'MutableArray#', 'SmallMutableArray#', and live 'Weak#' values.
+--
+-- To mimic typical 'Control.DeepSeq.NFData' instances, it stops at
+-- function-like closures (e.g. functions and partial applications) and at
+-- mutable objects which are not plain containers (e.g. 'TVar#'). Consequently
+-- it is not a drop-in replacement for user-defined 'NFData' instances, which
+-- may choose to force less (or more) depending on semantics.
+--
+-- === Pointer traversal policy
+--
+-- We only follow a pointer when doing so is also possible in Haskell via a
+-- corresponding API. For example, we traverse 'MutVar#', 'MVar#', mutable
+-- arrays, and live weak pointers because you can observe their contents with
+-- operations like @readIORef@, @readMVar@, @readArray@, or @deRefWeak@.
+-- Conversely, we do not peek inside closures whose internals are not
+-- observable from Haskell, such as function closures and their captured free
+-- variables.
+--
+-- Like any deep evaluation, it may not terminate on cyclic structures.
+forceIO :: a -> IO (Bool, a)
+forceIO a = IO $ \s0 -> case deepseq# a s0 of
+ (# s1, flag#, a' #) -> (# s1, (isTrue# flag#, a') #)
=====================================
rts/DeepSeq.cmm
=====================================
@@ -0,0 +1,246 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 2025
+ *
+ * Support for the deepseq# primop.
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "Cmm.h"
+
+/*
+Note [import CLOSURE annotations]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+See Note [import CLOSURE annotations] in rts/Apply.cmm.
+*/
+
+#if !defined(UnregisterisedCompiler)
+import CLOSURE g0;
+import CLOSURE large_alloc_lim;
+#endif
+
+/* -----------------------------------------------------------------------------
+ deepseq#
+
+ Deeply evaluate a value to (approximate) normal form, without requiring an
+ NFData constraint. This is used to provide a primitive analogue of
+ Control.DeepSeq.force / rnf.
+
+ See the primop documentation in compiler/GHC/Builtin/primops.txt.pp for the
+ intended semantics and limitations.
+ -------------------------------------------------------------------------- */
+
+// Worker which performs deep evaluation. This lets us tail-call when traversing
+// the final pointer field, avoiding stack blowup on common spine-recursive
+// structures (e.g. lists).
+//
+// The second argument is a boolean (0/1) accumulator tracking whether any
+// evaluation was forced in the transitive closure so far.
+stg_deepseqWorkzh (P_ p, W_ forced)
+{
+ W_ type, info;
+
+ again: MAYBE_GC(again);
+ STK_CHK_GEN();
+
+ p = UNTAG(p);
+ info = %INFO_PTR(p);
+ type = TO_W_(%INFO_TYPE(%STD_INFO(info)));
+
+ switch [0 .. N_CLOSURE_TYPES] type {
+
+ // Unevaluated things must be evaluated first:
+ case
+ THUNK,
+ THUNK_1_0,
+ THUNK_0_1,
+ THUNK_2_0,
+ THUNK_1_1,
+ THUNK_0_2,
+ THUNK_STATIC,
+ AP,
+ AP_STACK,
+ BLACKHOLE,
+ THUNK_SELECTOR : {
+ (P_ evald) = call %ENTRY_CODE(info) (p);
+ jump stg_deepseqWorkzh(evald, 1);
+ }
+
+ // Follow indirections:
+ case IND, IND_STATIC: {
+ p = %acquire StgInd_indirectee(p);
+ jump stg_deepseqWorkzh(p, forced);
+ }
+
+ // WHITEHOLEs are transient. Yield and try again.
+ case WHITEHOLE: {
+ goto again;
+ }
+
+ // Arrays of pointers: evaluate elements.
+ case
+ MUT_ARR_PTRS_DIRTY,
+ MUT_ARR_PTRS_CLEAN,
+ MUT_ARR_PTRS_FROZEN_DIRTY,
+ MUT_ARR_PTRS_FROZEN_CLEAN: {
+ W_ i_arr, ptrs_arr;
+ ptrs_arr = StgMutArrPtrs_ptrs(p);
+ if (ptrs_arr == 0) { return (forced); }
+ i_arr = ptrs_arr - 1;
+ deepseq_arr_loop0:
+ if (i_arr == 0) ( likely: False ) {
+ // Tail-call the final element to avoid building up a deep stack
+ // when traversing large immutable arrays.
+ jump stg_deepseqWorkzh(P_[p + SIZEOF_StgMutArrPtrs], forced);
+ }
+ (W_ forced_arr) = call stg_deepseqWorkzh(P_[p + SIZEOF_StgMutArrPtrs + WDS(i_arr)], forced);
+ forced = forced_arr;
+ i_arr = i_arr - 1;
+ goto deepseq_arr_loop0;
+ }
+
+ case
+ SMALL_MUT_ARR_PTRS_DIRTY,
+ SMALL_MUT_ARR_PTRS_CLEAN,
+ SMALL_MUT_ARR_PTRS_FROZEN_DIRTY,
+ SMALL_MUT_ARR_PTRS_FROZEN_CLEAN: {
+ W_ i_sarr, ptrs_sarr;
+ ptrs_sarr = StgSmallMutArrPtrs_ptrs(p);
+ if (ptrs_sarr == 0) { return (forced); }
+ i_sarr = ptrs_sarr - 1;
+ deepseq_arr_loop1:
+ if (i_sarr == 0) ( likely: False ) {
+ // Tail-call the final element to avoid building up a deep stack
+ // when traversing large immutable arrays.
+ jump stg_deepseqWorkzh(P_[p + SIZEOF_StgSmallMutArrPtrs], forced);
+ }
+ (W_ forced_sarr) = call stg_deepseqWorkzh(P_[p + SIZEOF_StgSmallMutArrPtrs + WDS(i_sarr)], forced);
+ forced = forced_sarr;
+ i_sarr = i_sarr - 1;
+ goto deepseq_arr_loop1;
+ }
+
+ // Constructors: evaluate their pointer fields.
+ case
+ CONSTR,
+ CONSTR_1_0,
+ CONSTR_0_1,
+ CONSTR_2_0,
+ CONSTR_1_1,
+ CONSTR_0_2,
+ CONSTR_NOCAF: {
+ W_ i_constr, ptrs_constr;
+ ptrs_constr = TO_W_(%INFO_PTRS(%STD_INFO(info)));
+ if (ptrs_constr == 0) { return (forced); }
+ i_constr = 0;
+ deepseq_constr_loop:
+ if (i_constr < ptrs_constr) {
+ // Tail-call the last one. This avoids building up a deep stack
+ // when traversing long lists. We count up so the final pointer
+ // field (e.g. the tail of a list cell) is tail-called.
+ if (i_constr == ptrs_constr - 1) {
+ jump stg_deepseqWorkzh(StgClosure_payload(p,i_constr), forced);
+ }
+ (W_ forced_constr) = call stg_deepseqWorkzh(StgClosure_payload(p,i_constr), forced);
+ forced = forced_constr;
+ i_constr = i_constr + 1;
+ goto deepseq_constr_loop;
+ }
+ return (forced);
+ }
+
+ case
+ MUT_VAR_CLEAN,
+ MUT_VAR_DIRTY: {
+ p = %relaxed StgMutVar_var(p);
+ jump stg_deepseqWorkzh(p, forced);
+ }
+
+ case
+ MVAR_CLEAN,
+ MVAR_DIRTY: {
+ p = %relaxed StgMVar_value(p);
+ jump stg_deepseqWorkzh(p, forced);
+ }
+
+ case WEAK: {
+ // Follow the value of a live weak pointer.
+ jump stg_deepseqWorkzh(StgWeak_value(p), forced);
+ }
+
+ // Anything else: conservatively stop.
+ //
+ // This includes (among other closure types) function-like closures and
+ // mutable objects which are not plain containers (e.g. TVar#),
+ // matching the intended "mimic typical NFData instances" semantics
+ // described in the primop documentation.
+ //
+ // We should never see frames here, but if we do, returning is safer than
+ // entering arbitrary things.
+ default: {
+ return (forced);
+ }}
+}
+
+// deepseq# primop entry point.
+// deepseq# :: forall a s. a -> State# s -> (# State# s, Int#, a #)
+//
+// The State# argument/result has no runtime representation, so the RTS entry
+// only takes the value being forced.
+stg_deepseqzh (P_ p)
+{
+ jump stg_deepseqLoopzh(p, 0);
+}
+
+// Worker which evaluates to a root and then delegates to the deep traversal.
+// The second argument is a boolean (0/1) accumulator tracking whether any
+// evaluation was forced in the transitive closure so far.
+stg_deepseqLoopzh (P_ p, W_ forced)
+{
+ W_ type, info, tag;
+
+ again: MAYBE_GC(again);
+ STK_CHK_GEN();
+
+ tag = GETTAG(p);
+ p = UNTAG(p);
+ info = %INFO_PTR(p);
+ type = TO_W_(%INFO_TYPE(%STD_INFO(info)));
+
+ switch [0 .. N_CLOSURE_TYPES] type {
+
+ // Unevaluated things must be evaluated first:
+ case
+ THUNK,
+ THUNK_1_0,
+ THUNK_0_1,
+ THUNK_2_0,
+ THUNK_1_1,
+ THUNK_0_2,
+ THUNK_STATIC,
+ AP,
+ AP_STACK,
+ BLACKHOLE,
+ THUNK_SELECTOR : {
+ (P_ evald) = call %ENTRY_CODE(info) (p);
+ jump stg_deepseqLoopzh(evald, 1);
+ }
+
+ // Follow indirections:
+ case IND, IND_STATIC: {
+ p = %acquire StgInd_indirectee(p);
+ jump stg_deepseqLoopzh(p, forced);
+ }
+
+ // WHITEHOLEs are transient. Yield and try again.
+ case WHITEHOLE: {
+ goto again;
+ }
+
+ default: {
+ P_ root;
+ root = tag | p;
+ (W_ forced1) = call stg_deepseqWorkzh(root, forced);
+ return (forced1, root);
+ }}
+}
=====================================
rts/RtsSymbols.c
=====================================
@@ -644,6 +644,7 @@ extern char **environ;
SymI_HasDataProto(stg_newMutVarzh) \
SymI_HasDataProto(stg_newTVarzh) \
SymI_HasDataProto(stg_noDuplicatezh) \
+ SymI_HasDataProto(stg_deepseqzh) \
SymI_HasDataProto(stg_atomicModifyMutVar2zh) \
SymI_HasDataProto(stg_atomicModifyMutVarzuzh) \
SymI_HasDataProto(stg_casMutVarzh) \
=====================================
rts/include/stg/MiscClosures.h
=====================================
@@ -531,6 +531,7 @@ RTS_FUN_DECL(stg_raiseUnderflowzh);
RTS_FUN_DECL(stg_raiseOverflowzh);
RTS_FUN_DECL(stg_raiseIOzh);
RTS_FUN_DECL(stg_paniczh);
+RTS_FUN_DECL(stg_deepseqzh);
RTS_FUN_DECL(stg_keepAlivezh);
RTS_FUN_DECL(stg_absentErrorzh);
=====================================
rts/rts.cabal
=====================================
@@ -359,6 +359,7 @@ library
cmm-sources: Apply.cmm
Compact.cmm
ContinuationOps.cmm
+ DeepSeq.cmm
Exception.cmm
HeapStackCheck.cmm
Jumps_D.cmm
=====================================
testsuite/tests/interface-stability/ghc-experimental-exports.stdout
=====================================
@@ -4454,6 +4454,11 @@ module Data.Tuple.Experimental where
data Unit# = ...
getSolo :: forall a. Solo a -> a
+module GHC.DeepSeq where
+ -- Safety: None
+ force :: forall a. a -> (GHC.Internal.Types.Bool, a)
+ forceIO :: forall a. a -> GHC.Internal.Types.IO (GHC.Internal.Types.Bool, a)
+
module GHC.PrimOps where
-- Safety: Unsafe
(*#) :: Int# -> Int# -> Int#
@@ -4924,6 +4929,7 @@ module GHC.PrimOps where
decodeDouble_2Int# :: Double# -> (# Int#, Word#, Word#, Int# #)
decodeDouble_Int64# :: Double# -> (# Int64#, Int# #)
decodeFloat_Int# :: Float# -> (# Int#, Int# #)
+ deepseq# :: forall a d. a -> State# d -> (# State# d, Int#, a #)
delay# :: forall d. Int# -> State# d -> State# d
divideDoubleX2# :: DoubleX2# -> DoubleX2# -> DoubleX2#
divideDoubleX4# :: DoubleX4# -> DoubleX4# -> DoubleX4#
=====================================
testsuite/tests/interface-stability/ghc-prim-exports.stdout
=====================================
@@ -1592,6 +1592,7 @@ module GHC.Prim where
decodeDouble_2Int# :: Double# -> (# Int#, Word#, Word#, Int# #)
decodeDouble_Int64# :: Double# -> (# Int64#, Int# #)
decodeFloat_Int# :: Float# -> (# Int#, Int# #)
+ deepseq# :: forall a d. a -> State# d -> (# State# d, Int#, a #)
delay# :: forall d. Int# -> State# d -> State# d
divideDoubleX2# :: DoubleX2# -> DoubleX2# -> DoubleX2#
divideDoubleX4# :: DoubleX4# -> DoubleX4# -> DoubleX4#
@@ -3156,6 +3157,7 @@ module GHC.PrimopWrappers where
decodeDouble_2Int# :: GHC.Internal.Prim.Double# -> (# GHC.Internal.Prim.Int#, GHC.Internal.Prim.Word#, GHC.Internal.Prim.Word#, GHC.Internal.Prim.Int# #)
decodeDouble_Int64# :: GHC.Internal.Prim.Double# -> (# GHC.Internal.Prim.Int64#, GHC.Internal.Prim.Int# #)
decodeFloat_Int# :: GHC.Internal.Prim.Float# -> (# GHC.Internal.Prim.Int#, GHC.Internal.Prim.Int# #)
+ deepseq# :: forall a s. a -> GHC.Internal.Prim.State# s -> (# GHC.Internal.Prim.State# s, GHC.Internal.Prim.Int#, a #)
delay# :: forall s. GHC.Internal.Prim.Int# -> GHC.Internal.Prim.State# s -> GHC.Internal.Prim.State# s
divideFloat# :: GHC.Internal.Prim.Float# -> GHC.Internal.Prim.Float# -> GHC.Internal.Prim.Float#
double2Float# :: GHC.Internal.Prim.Double# -> GHC.Internal.Prim.Float#
=====================================
testsuite/tests/primops/should_run/DeepSeqPrimOp.hs
=====================================
@@ -0,0 +1,85 @@
+module Main (main) where
+
+import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar)
+import Control.Exception (SomeException, try)
+import Data.Array (Array, listArray)
+import Data.Array.IO (IOArray, newArray)
+import Data.IORef (IORef, newIORef)
+import GHC.DeepSeq (forceIO)
+import System.Mem.Weak (mkWeak)
+
+deepEvaluate :: a -> IO a
+deepEvaluate a = do
+ (_, a') <- forceIO a
+ pure a'
+
+deepEvaluateWithFlag :: a -> IO (Bool, a)
+deepEvaluateWithFlag = forceIO
+
+mkThunk :: Int -> Int
+mkThunk x = x + 1
+{-# NOINLINE mkThunk #-}
+
+boomVal :: Int
+boomVal = error "boom"
+{-# NOINLINE boomVal #-}
+
+funVal :: Int -> Int
+funVal _ = boomVal
+{-# NOINLINE funVal #-}
+
+main :: IO ()
+main = do
+ r1 <- try (deepEvaluate (1 :: Int, error "boom") >> pure ()) :: IO (Either SomeException ())
+ case r1 of
+ Left _ -> putStrLn "thunk-forced"
+ Right _ -> putStrLn "unexpected-no-exn"
+
+ r2 <- try (deepEvaluate funVal) :: IO (Either SomeException (Int -> Int))
+ case r2 of
+ Left _ -> putStrLn "unexpected-exn"
+ Right _ -> putStrLn "fun-ok"
+
+ (forced2, ()) <- deepEvaluateWithFlag ()
+ if not forced2
+ then putStrLn "noforce-ok"
+ else putStrLn "noforce-bad"
+
+ let v = (1 :: Int, mkThunk 2)
+ (forced3, v') <- deepEvaluateWithFlag v
+ if forced3 && snd v' == 3
+ then putStrLn "thunk-ok"
+ else putStrLn "unexpected"
+
+ let arr :: Array Int Int
+ arr = listArray (0, 0) [boomVal]
+ r3 <- try (deepEvaluate arr >> pure ()) :: IO (Either SomeException ())
+ case r3 of
+ Left _ -> putStrLn "array-thunk-forced"
+ Right _ -> putStrLn "array-unforced"
+
+ ioArr <- newArray (0, 0) boomVal :: IO (IOArray Int Int)
+ r4 <- try (deepEvaluate ioArr >> pure ()) :: IO (Either SomeException ())
+ case r4 of
+ Left _ -> putStrLn "ioarray-thunk-forced"
+ Right _ -> putStrLn "ioarray-unforced"
+
+ ref <- newIORef boomVal :: IO (IORef Int)
+ r5 <- try (deepEvaluate ref >> pure ()) :: IO (Either SomeException ())
+ case r5 of
+ Left _ -> putStrLn "ioref-thunk-forced"
+ Right _ -> putStrLn "ioref-unforced"
+
+ mvar <- newEmptyMVar :: IO (MVar Int)
+ putMVar mvar boomVal
+ r6 <- try (deepEvaluate mvar >> pure ()) :: IO (Either SomeException ())
+ case r6 of
+ Left _ -> putStrLn "mvar-thunk-forced"
+ Right _ -> putStrLn "mvar-unforced"
+
+ keyRef <- newIORef ()
+ weak <- mkWeak keyRef boomVal Nothing
+ r7 <- try (deepEvaluate weak >> pure ()) :: IO (Either SomeException ())
+ case r7 of
+ Left _ -> putStrLn "weak-thunk-forced"
+ Right _ -> putStrLn "weak-unforced"
=====================================
testsuite/tests/primops/should_run/DeepSeqPrimOp.stdout
=====================================
@@ -0,0 +1,9 @@
+thunk-forced
+fun-ok
+noforce-ok
+thunk-ok
+array-thunk-forced
+ioarray-thunk-forced
+ioref-thunk-forced
+mvar-thunk-forced
+weak-thunk-forced
=====================================
testsuite/tests/primops/should_run/all.T
=====================================
@@ -17,6 +17,7 @@ test('T13825-compile', normal, compile_and_run, [''])
test('T16164', normal, compile_and_run, [''])
test('ShowPrim', normal, compile_and_run, [''])
test('T12492', normal, compile_and_run, [''])
+test('DeepSeqPrimOp', [js_skip, extra_ways(['ghci','ghci-opt']), extra_hc_opts('-package ghc-experimental')], compile_and_run, [''])
test('ArithInt8', normal, compile_and_run, [''])
test('ArithWord8', normal, compile_and_run, [''])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/ea5fe7e8a34d93db03eb3af1d4d838e…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/ea5fe7e8a34d93db03eb3af1d4d838e…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/grow-block-free] rts: opportunistically grow the MutableByteArray# in-place in resizeMutableByteArray#
by Cheng Shao (@TerrorJack) 24 Dec '25
by Cheng Shao (@TerrorJack) 24 Dec '25
24 Dec '25
Cheng Shao pushed to branch wip/grow-block-free at Glasgow Haskell Compiler / GHC
Commits:
4e7adb8c by Cheng Shao at 2025-12-23T19:59:40+01:00
rts: opportunistically grow the MutableByteArray# in-place in resizeMutableByteArray#
Following !15234, this patch improves `resizeMutableByteArray#` memory
efficiency by growing the `MutableByteArray#` in-place if possible,
addressing an old todo comment here.
- - - - -
1 changed file:
- rts/PrimOps.cmm
Changes:
=====================================
rts/PrimOps.cmm
=====================================
@@ -258,20 +258,35 @@ stg_shrinkMutableByteArrayzh ( gcptr mba, W_ new_size )
stg_resizzeMutableByteArrayzh ( gcptr mba, W_ new_size )
// MutableByteArray# s -> Int# -> State# s -> (# State# s,MutableByteArray# s #)
{
+ W_ old_size, old_wds, new_wds, new_free;
+ W_ bd;
+
ASSERT(new_size `ge` 0);
- if (new_size <= StgArrBytes_bytes(mba)) {
+ old_size = StgArrBytes_bytes(mba);
+ if (new_size <= old_size) {
call stg_shrinkMutableByteArrayzh(mba, new_size);
return (mba);
+ }
+
+ bd = Bdescr(mba);
+ old_wds = BYTES_TO_WDS(SIZEOF_StgArrBytes) + ROUNDUP_BYTES_TO_WDS(old_size);
+ new_wds = BYTES_TO_WDS(SIZEOF_StgArrBytes) + ROUNDUP_BYTES_TO_WDS(new_size);
+ new_free = mba + WDS(new_wds);
+
+ // Just like stg_shrinkMutableByteArrayzh above, we try to grow mba
+ // in-place if possible. The conditions are similar to the
+ // conditions when we can set bd->free when shrinking mba, and we
+ // also need to check that we don't grow past the end of current block.
+ if (bdescr_free(bd) == mba + WDS(old_wds) &&
+ (bd == StgRegTable_rCurrentAlloc(BaseReg) || bd == Capability_pinned_object_block(MyCapability())) &&
+ new_free <= bdescr_start(bd) + (TO_W_(bdescr_blocks(bd)) * BLOCK_SIZE)) {
+ bdescr_free(bd) = new_free;
+ StgArrBytes_bytes(mba) = new_size;
+ return (mba);
} else {
(P_ new_mba) = call stg_newByteArrayzh(new_size);
- // maybe at some point in the future we may be able to grow the
- // MBA in-place w/o copying if we know the space after the
- // current MBA is still available, as often we want to grow the
- // MBA shortly after we allocated the original MBA. So maybe no
- // further allocations have occurred by then.
-
// copy over old content
prim %memcpy(BYTE_ARR_CTS(new_mba), BYTE_ARR_CTS(mba),
StgArrBytes_bytes(mba), SIZEOF_W);
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/4e7adb8cf245cabc9bce7e766b6b566…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/4e7adb8cf245cabc9bce7e766b6b566…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/fix-26670] Decoupling Language.Haskell.Syntax.Binds from GHC.Types.Basic by transfering...
by recursion-ninja (@recursion-ninja) 24 Dec '25
by recursion-ninja (@recursion-ninja) 24 Dec '25
24 Dec '25
recursion-ninja pushed to branch wip/fix-26670 at Glasgow Haskell Compiler / GHC
Commits:
9c8251ee by Recursion Ninja at 2025-12-23T13:49:31-05:00
Decoupling Language.Haskell.Syntax.Binds from GHC.Types.Basic by transfering InlinePragma types between the modules.
* Moved InlinePragma data-types to Language.Haskell.Syntax.Binds.InlinePragma
* Partitioned of Arity type synonyms to GHC.Types.Arity
* InlinePragma is now extensible via Trees That Grow
* Activation is now extensible via Trees That Grow
* Maybe Arity change to more descriptive InlineSaturation data-type
* InlineSaturation information removed from InlinePragma during GHS parsing pass
* Cleaned up the exposed module interfaces of the new modules
- - - - -
64 changed files:
- compiler/GHC/Builtin/PrimOps/Ids.hs
- compiler/GHC/Core.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Opt/CSE.hs
- compiler/GHC/Core/Opt/CprAnal.hs
- compiler/GHC/Core/Opt/DmdAnal.hs
- compiler/GHC/Core/Opt/OccurAnal.hs
- compiler/GHC/Core/Opt/Pipeline.hs
- compiler/GHC/Core/Opt/Pipeline/Types.hs
- compiler/GHC/Core/Opt/Simplify.hs
- compiler/GHC/Core/Opt/Simplify/Env.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- compiler/GHC/Core/Opt/SpecConstr.hs
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Core/Opt/WorkWrap.hs
- compiler/GHC/Core/Ppr.hs
- compiler/GHC/Core/Rules.hs
- compiler/GHC/Core/SimpleOpt.hs
- compiler/GHC/Core/Unfold/Make.hs
- compiler/GHC/CoreToIface.hs
- compiler/GHC/Driver/Config/Core/Lint.hs
- compiler/GHC/Driver/Config/Core/Opt/Simplify.hs
- compiler/GHC/Hs/Binds.hs
- + compiler/GHC/Hs/Extension.hs-boot
- compiler/GHC/Hs/Instances.hs
- compiler/GHC/HsToCore.hs
- compiler/GHC/HsToCore/Binds.hs
- compiler/GHC/HsToCore/Errors/Types.hs
- compiler/GHC/HsToCore/Foreign/C.hs
- compiler/GHC/HsToCore/Foreign/JavaScript.hs
- compiler/GHC/HsToCore/Quote.hs
- compiler/GHC/HsToCore/Ticks.hs
- compiler/GHC/Iface/Make.hs
- compiler/GHC/Iface/Syntax.hs
- compiler/GHC/Iface/Tidy.hs
- compiler/GHC/IfaceToCore.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/Lexer.x
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Rename/Bind.hs
- compiler/GHC/Tc/Deriv/Generics.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Tc/Gen/Arrow.hs
- compiler/GHC/Tc/Gen/Sig.hs
- compiler/GHC/Tc/Instance/Typeable.hs
- compiler/GHC/Tc/TyCl/Instance.hs
- compiler/GHC/Tc/Utils/Instantiate.hs
- compiler/GHC/ThToHs.hs
- + compiler/GHC/Types/Arity.hs
- compiler/GHC/Types/Basic.hs
- compiler/GHC/Types/Hint.hs
- compiler/GHC/Types/Id.hs
- compiler/GHC/Types/Id/Info.hs
- compiler/GHC/Types/Id/Make.hs
- + compiler/GHC/Types/InlinePragma.hs
- compiler/GHC/Utils/Binary.hs
- compiler/GHC/Utils/Outputable.hs
- compiler/Language/Haskell/Syntax/Binds.hs
- + compiler/Language/Haskell/Syntax/Binds/InlinePragma.hs
- compiler/Language/Haskell/Syntax/Decls.hs
- compiler/Language/Haskell/Syntax/Extension.hs
- compiler/ghc.cabal.in
- utils/check-exact/ExactPrint.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9c8251ee90669f8fda4627116cc9069…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9c8251ee90669f8fda4627116cc9069…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/deepseq-primop] 20 commits: rts: workaround -Werror=maybe-uninitialized false positives
by Cheng Shao (@TerrorJack) 24 Dec '25
by Cheng Shao (@TerrorJack) 24 Dec '25
24 Dec '25
Cheng Shao pushed to branch wip/deepseq-primop at Glasgow Haskell Compiler / GHC
Commits:
224446a2 by Cheng Shao at 2025-12-20T07:49:54-05:00
rts: workaround -Werror=maybe-uninitialized false positives
In some cases gcc might report -Werror=maybe-uninitialized that we
know are false positives, but need to workaround it to make validate
builds with -Werror pass.
- - - - -
251ec087 by Cheng Shao at 2025-12-20T07:49:54-05:00
hadrian: use -Og as C/C++ optimization level when debugging
This commit enables -Og as optimization level when compiling the debug
ways of rts. According to gcc documentation
(https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-Og)
-Og is a better choice than -O0 for producing debuggable code. It's
also supported by clang as well, so it makes sense to use it as a
default for debugging. Also add missing -g3 flag to C++ compilation
flags in +debug_info flavour transformer.
- - - - -
fb586c67 by Cheng Shao at 2025-12-20T07:50:36-05:00
compiler: replace DList with OrdList
This patch removes `DList` logic from the compiler and replaces it
with `OrdList` which also supports O(1) concatenation and should be
more memory efficient than the church-encoded `DList`.
- - - - -
8149c987 by Cheng Shao at 2025-12-20T17:06:51-05:00
hadrian: add with_profiled_libs flavour transformer
This patch adds a `with_profiled_libs` flavour transformer to hadrian
which is the exact opposite of `no_profiled_libs`. It adds profiling
ways to stage1+ rts/library ways, and doesn't alter other flavour
settings. It is useful when needing to test profiling logic locally
with a quick flavour.
- - - - -
746b18cd by Cheng Shao at 2025-12-20T17:06:51-05:00
hadrian: fix missing profiled dynamic libraries in profiled_ghc
This commit fixes the profiled_ghc flavour transformer to include
profiled dynamic libraries as well, since they're supported by GHC
since !12595.
- - - - -
4dd7e3b9 by Cheng Shao at 2025-12-20T17:07:33-05:00
ci: set http.postBuffer to mitigate perf notes timeout on some runners
This patch sets http.postBuffer to mitigate the timeout when fetching
perf notes on some runners with slow internet connection. Fixes #26684.
- - - - -
bc36268a by Wolfgang Jeltsch at 2025-12-21T16:23:24-05:00
Remove unused known keys and names for type representations
This removes the known-key and corresponding name variables for
`TrName`, `TrNameD`, `TypeRep`, `KindRepTypeLitD`, `TypeLitSort`, and
`mkTrType`, as they are apparently nowhere used in GHC’s source code.
- - - - -
ff5050e9 by Wolfgang Jeltsch at 2025-12-21T16:24:04-05:00
Remove unused known keys and names for natural operations
This removes the known-key and corresponding name variables for
`naturalAndNot`, `naturalLog2`, `naturalLogBaseWord`, `naturalLogBase`,
`naturalPowMod`, `naturalSizeInBase`, `naturalToFloat`, and
`naturalToDouble`, as they are apparently nowhere used in GHC’s source
code.
- - - - -
424388c2 by Wolfgang Jeltsch at 2025-12-21T16:24:45-05:00
Remove the unused known key and name for `Fingerprint`
This removes the variables for the known key and the name of the
`Fingerprint` data constructor, as they are apparently nowhere used in
GHC’s source code.
- - - - -
a1ed86fe by Wolfgang Jeltsch at 2025-12-21T16:25:26-05:00
Remove the unused known key and name for `failIO`
This removes the variables for the known key and the name of the
`failIO` operation, as they are apparently nowhere used in GHC’s source
code.
- - - - -
b8220daf by Wolfgang Jeltsch at 2025-12-21T16:26:07-05:00
Remove the unused known key and name for `liftM`
This removes the variables for the known key and the name of the `liftM`
operation, as they are apparently nowhere used in GHC’s source code.
- - - - -
eb0628b1 by Wolfgang Jeltsch at 2025-12-21T16:26:47-05:00
Fix the documentation of `hIsClosed`
- - - - -
db1ce858 by sheaf at 2025-12-22T17:11:17-05:00
Do deep subsumption when computing valid hole fits
This commit makes a couple of improvements to the code that
computes "valid hole fits":
1. It uses deep subsumption for data constructors.
This matches up the multiplicities, as per
Note [Typechecking data constructors].
This fixes #26338 (test: LinearHoleFits).
2. It now suggests (non-unidirectional) pattern synonyms as valid
hole fits. This fixes #26339 (test: PatSynHoleFit).
3. It uses 'stableNameCmp', to make the hole fit output deterministic.
-------------------------
Metric Increase:
hard_hole_fits
-------------------------
- - - - -
72ee9100 by sheaf at 2025-12-22T17:11:17-05:00
Speed up hole fits with a quick pre-test
This speeds up the machinery for valid hole fits by doing a small
check to rule out obviously wrong hole fits, such as:
1. A hole fit identifier whose type has a different TyCon at the head,
after looking through foralls and (=>) arrows, e.g.:
hole_ty = Int
cand_ty = Maybe a
or
hole_ty = forall a b. a -> b
cand_ty = forall x y. Either x y
2. A hole fit identifier that is not polymorphic when the hole type
is polymorphic, e.g.
hole_ty = forall a. a -> a
cand_ty = Int -> Int
-------------------------
Metric Decrease:
hard_hole_fits
-------------------------
- - - - -
30e513ba by Cheng Shao at 2025-12-22T17:12:00-05:00
configure: remove unused win32-tarballs.md5sum
This patch removes the unused `win32-tarballs.md5sum` file from the
tree. The current mingw tarball download logic in
`mk/get-win32-tarballs.py` fetches and checks against `SHA256SUM` from
the same location where the tarballs are fetched, and this file has
been unused for a few years.
- - - - -
a2d52b3b by Wolfgang Jeltsch at 2025-12-23T04:47:33-05:00
Add an operation `System.IO.hGetNewlineMode`
This commit also contains some small code and documentation changes for
related operations, for the sake of consistency.
- - - - -
b26d134a by Cheng Shao at 2025-12-23T04:48:15-05:00
rts: opportunistically reclaim slop space in shrinkMutableByteArray#
Previously, `shrinkMutableByteArray#` shrinks a `MutableByteArray#`
in-place by assigning the new size to it, and zeroing the extra slop
space. That slop space is not reclaimed and wasted. But it's often the
case that we allocate a `MutableByteArray#` upfront, then shrink it
shortly after, so the `MutableByteArray#` closure sits right at the
end of a nursery block; this patch identifies such chances, and also
shrink `bd->free` if possible, reducing heap space fragmentation.
Co-authored-by: Codex <codex(a)openai.com>
-------------------------
Metric Decrease:
T10678
-------------------------
- - - - -
a322b593 by Cheng Shao at 2025-12-23T12:49:53+01:00
WIP
- - - - -
55dcac0f by Cheng Shao at 2025-12-23T12:49:53+01:00
WIP
- - - - -
ecaa4a74 by Cheng Shao at 2025-12-23T19:46:55+01:00
WIP
- - - - -
66 changed files:
- .gitattributes
- .gitlab/ci.sh
- compiler/GHC/Builtin/Names.hs
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/Core/DataCon.hs
- compiler/GHC/Parser/String.hs
- compiler/GHC/StgToCmm/InfoTableProv.hs
- compiler/GHC/StgToCmm/Prim.hs
- compiler/GHC/StgToJS/Prim.hs
- compiler/GHC/Tc/Errors/Hole.hs
- compiler/GHC/Tc/Errors/Hole/FitTypes.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/Utils/Unify.hs
- docs/users_guide/9.16.1-notes.rst
- hadrian/doc/flavours.md
- hadrian/src/Flavour.hs
- hadrian/src/Settings/Packages.hs
- libraries/base/changelog.md
- libraries/base/src/GHC/Base.hs
- libraries/base/src/GHC/Exts.hs
- libraries/base/src/System/IO.hs
- libraries/ghc-experimental/ghc-experimental.cabal.in
- + libraries/ghc-experimental/src/GHC/DeepSeq.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle.hs
- libraries/ghc-internal/src/GHC/Internal/System/IO.hs
- − mk/win32-tarballs.md5sum
- + rts/DeepSeq.cmm
- rts/PrimOps.cmm
- rts/RtsSymbols.c
- rts/include/stg/MiscClosures.h
- rts/linker/InitFini.c
- rts/rts.cabal
- rts/sm/Sanity.c
- testsuite/tests/ghci/scripts/T8353.stderr
- testsuite/tests/interface-stability/base-exports.stdout
- testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
- testsuite/tests/interface-stability/base-exports.stdout-mingw32
- testsuite/tests/interface-stability/base-exports.stdout-ws-32
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout
- testsuite/tests/interface-stability/ghc-prim-exports.stdout
- testsuite/tests/overloadedrecflds/should_fail/DRFHoleFits.stderr
- testsuite/tests/perf/compiler/hard_hole_fits.stderr
- testsuite/tests/plugins/test-hole-plugin.stderr
- + testsuite/tests/primops/should_run/DeepSeqPrimOp.hs
- + testsuite/tests/primops/should_run/DeepSeqPrimOp.stdout
- testsuite/tests/primops/should_run/all.T
- testsuite/tests/th/T15321.stderr
- testsuite/tests/typecheck/should_compile/T13050.stderr
- testsuite/tests/typecheck/should_compile/T14273.stderr
- testsuite/tests/typecheck/should_compile/T14590.stderr
- testsuite/tests/typecheck/should_compile/T25180.stderr
- testsuite/tests/typecheck/should_compile/abstract_refinement_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/constraint_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/free_monad_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/hole_constraints.stderr
- testsuite/tests/typecheck/should_compile/holes.stderr
- testsuite/tests/typecheck/should_compile/holes2.stderr
- testsuite/tests/typecheck/should_compile/holes3.stderr
- testsuite/tests/typecheck/should_compile/refinement_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/subsumption_sort_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/type_in_type_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/valid_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/valid_hole_fits_interactions.stderr
- testsuite/tests/typecheck/should_fail/T14884.stderr
- utils/deriveConstants/Main.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/8dc16ccbae000ad4d1ffc2dc9fda0d…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/8dc16ccbae000ad4d1ffc2dc9fda0d…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/romes/25636] 42 commits: docs: drop obsolete warning about -fexternal-interpreter on windows
by Rodrigo Mesquita (@alt-romes) 23 Dec '25
by Rodrigo Mesquita (@alt-romes) 23 Dec '25
23 Dec '25
Rodrigo Mesquita pushed to branch wip/romes/25636 at Glasgow Haskell Compiler / GHC
Commits:
2c2a3ef3 by Cheng Shao at 2025-12-15T11:51:53-05:00
docs: drop obsolete warning about -fexternal-interpreter on windows
This patch drops an obsolete warning about -fexternal-interpreter not
supported on windows; it is supported since a long time ago, including
the profiled way.
- - - - -
68573aa5 by Marc Scholten at 2025-12-15T11:53:00-05:00
haddock: Drop Haddock.Backends.HaddockDB as it's unused
- - - - -
b230d549 by mangoiv at 2025-12-16T15:17:45-05:00
base: generalize delete{Firsts,}By
When we delete{Firsts,}By we should not require the
lists to be the same type. This is an especially useful
generalisation in the case of deleteFirstsBy because we
can skip an invocation of the map function.
This change was discussed on the core-libraries-committee's bug
tracker at https://github.com/haskell/core-libraries-committee/issues/372.
- - - - -
6a2b43e3 by Cheng Shao at 2025-12-16T15:18:30-05:00
compiler: clean up redundant LANGUAGE pragmas
This patch bumps `default-language` of `ghc`/`ghc-bin` from `GHC2021`
to `GHC2024` (which is supported in ghc 9.10, current boot ghc lower
version bound), and also cleans up redundant `LANGUAGE` pragmas (as
well as `default-extensions`/`other-extensions`) that are already
implied by `GHC2024`.
Co-authored-by: Codex <codex(a)openai.com>
- - - - -
fca9cd7c by sheaf at 2025-12-18T13:18:18-05:00
X86 CodeGen: fix assign_eax_sse_regs
We must set %al to the number of SSE2 registers that contain arguments
(in case we are dealing with a varargs function). The logic for counting
how many arguments reside in SSE2 registers was incorrect, as it used
'isFloatFormat', which incorrectly ignores vector registers.
We now instead do case analysis on the register class:
is_sse_reg r =
case targetClassOfReg platform r of
RcFloatOrVector -> True
RcInteger -> False
This change is necessary to prevent segfaults in T20030_test1j, because
subsequent commits change the format calculations, resulting in vector
formats more often.
- - - - -
53150617 by sheaf at 2025-12-18T13:18:19-05:00
X86 regUsageOfInstr: fix format for IMUL
When used with 8-bit operands, the IMUL instruction returns the result
in the lower 16 bits of %rax (also known as %ax). This is different
than for the other sizes, where an input at 16, 32 or 64 bits will
result in 16, 32 or 64 bits of output in both %rax and %rdx.
This doesn't affect the behaviour of the compiler, because we don't
allow partial writes at sub-word sizes. The rationale is explained
in Wrinkle [Don't allow scalar partial writes] in Note [Register formats in liveness analysis],
in GHC.CmmToAsm.Reg.Liveness.
- - - - -
c7a56dd1 by sheaf at 2025-12-18T13:18:19-05:00
Liveness analysis: consider register formats
This commit updates the register allocator to be a bit more careful in
situations in which a single register is used at multiple different
formats, e.g. when xmm1 is used both to store a Double# and a DoubleX2#.
This is done by introducing the 'Regs' newtype around 'UniqSet RegWithFormat',
for which the combining operations take the larger of the two formats
instead of overriding the format.
Operations on 'Regs' are defined in 'GHC.CmmToAsm.Reg.Regs'. There is
a modest compile-time cost for the additional overhead for tracking
register formats, which causes the metric increases of this commit.
The subtle aspects of the implementation are outlined in
Note [Register formats in liveness analysis] in GHC.CmmToAsm.Reg.Liveness.
Fixes #26411 #26611
-------------------------
Metric Increase:
T12707
T26425
T3294
-------------------------
- - - - -
c2e83339 by sheaf at 2025-12-18T13:18:19-05:00
Register allocator: reload at same format as spill
This commit ensures that if we spill a register onto the stack at a
given format, we then always reload the register at this same format.
This ensures we don't end up in a situation where we spill F64x2 but end
up only reloading the lower F64. This first reload would make us believe
the whole data is in a register, thus silently losing the upper 64 bits
of the spilled register's contents.
Fixes #26526
- - - - -
55ab583b by sheaf at 2025-12-18T13:18:19-05:00
Register allocation: writes redefine format
As explained in Note [Allocated register formats] in GHC.CmmToAsm.Reg.Linear,
we consider all writes to redefine the format of the register.
This ensures that in a situation such as
movsd .Ln6m(%rip),%v1
shufpd $0,%v1,%v1
we properly consider the broadcast operation to change the format of %v1
from F64 to F64x2.
This completes the fix to #26411 (test in T26411b).
- - - - -
951402ed by Vladislav Zavialov at 2025-12-18T13:19:05-05:00
Parser: improve mkModuleImpExp, remove checkImportSpec
1. The `mkModuleImpExp` helper now knows whether it is processing an import or
export list item, and uses this information to produce a more accurate error
message for `import M (T(..,x))` with PatternSynonyms disabled.
The old message incorrectly referred to this case as an export form.
2. The `checkImportSpec` helper is removed in favor of more comprehensive error
checking in `mkModuleImpExp`.
3. Additionaly, the invariants of `ImpExpList` and `ImpExpAllWith` have been
made more explicit in the comments and assertions (calls to 'panic').
Test case: import-syntax-no-ext
- - - - -
47d83d96 by Vladislav Zavialov at 2025-12-18T13:19:06-05:00
Subordinate namespace-specified wildcards (#25901)
Add support for subordinate namespace-specified wildcards
`X(type ..)` and `X(data ..)` to import and export lists.
Examples:
import M (Cls(type ..)) -- imports Cls and all its associated types
import M (Cls(data ..)) -- imports Cls and all its methods
module M (R(data ..), C(type ..)) where
-- exports R and all its data constructors and record fields;
-- exports C and all its associated types, but not its methods
The scope of this change is limited to the case where the wildcard is the only
subordinate import/export item, whereas the more complex forms `X(type .., f)`
or `X(type .., data ..)` are unsupported and raise the newly introduced
PsErrUnsupportedExplicitNamespace error. This restriction may be lifted later.
Summary of the changes:
1. Refactor IEThingAll to store its extension field XIEThingAll as a record
IEThingAllExt instead of a tuple.
2. Extend the AST by adding a NamespaceSpecifier field to IEThingAllExt,
representing an optional namespace specifier `type` or `data` in front
of a subordinate wildcard `X(..)`.
3. Extend the grammar in Parser.y with productions for `type ..` and `data ..`
in subordinate import/export items.
4. Introduce `filterByNamespaceGREs` to filter [GlobalRdrElt] by a
NamespaceSpecifier; use it in `filterImports` and `exports_from_avail`
to account for the namespace specifier in IEThingAll.
5. Improve diagnostics by storing more information in DodgyImportsEmptyParent
and DodgyExportsEmptyParent.
Test cases:
T25901_sub_e T25901_sub_f T25901_sub_g T25901_sub_a
T25901_sub_b T25901_sub_c T25901_sub_d T25901_sub_w
DodgyImports02 DodgyImports03 DodgyImports04
- - - - -
eac418bb by Recursion Ninja at 2025-12-18T13:19:48-05:00
Removing the 'Data' instance for 'InstEnv'.
The 'Data' instance is blocking work on Trees that Grow, and the
'Data' instance seem to have been added without a clear purpose.
- - - - -
e920e038 by Recursion Ninja at 2025-12-18T13:19:48-05:00
'Decouple Language.Haskell.Syntax.Decls' from 'GHC.Unit.Module.Warnings'
- - - - -
bd38b76c by Cheng Shao at 2025-12-18T13:20:31-05:00
testsuite: improve coverage of foundation test
This patch refactors the `foundation` test a bit to improve coverage:
- Instead of using a hard-coded seed, a random seed is now taken from
the command line, and printed upon test failure. This improves test
coverage over many future CI runs, and shall a failure occur, the
seed is available in the CI log for local reproduction.
- The iterations count is bumped to 1000 instead of 100, similar to
the bump in `test-primops`. Runtime timeout is bumped 2x just to be
safe.
- Improve `newLCGGen` by using non-atomic loads/stores on a
`MutableByteArray#` for storing mutable `Word64`, this test doesn't
use parallelism in the first place
- Fixed a few compiler warnings and removed redundant pragmas and
imports
Co-authored-by: Codex <codex(a)openai.com>
- - - - -
3995187c by Sylvain Henry at 2025-12-18T13:21:45-05:00
Doc: document -pgmi "" (#26634)
- - - - -
5729418c by Cheng Shao at 2025-12-18T13:22:29-05:00
rts: use __builtin_mul_overflow for hs_mulIntMayOflo
This patch uses `__builtin_mul_overflow` to implement
`hs_mulIntMayOflo`. This is a GNU C checked arithmetic builtin
function supported by gcc/clang, is type-generic so works for both
32-bit/64-bit, and makes the code both more efficient and easier to
read/maintain than the previous hand rolled logic.
- - - - -
1ca4b49a by Cheng Shao at 2025-12-18T13:23:11-05:00
compiler/rts: fix ABI mismatch in barf() invocations
This patch fixes a long-standing issue of ABI mismatch in `barf()`
invocations, both in compiler-emitted code and in hand written Cmm
code:
- In RTS, we have `barf()` which reports a fatal internal error
message and exits the program.
- `barf()` is a variadic C function! When used as a callee of a
foreign call with `ccall` calling convention instead of `capi`,
there is an ABI mismatch between the caller and the callee!
- Unfortunately, both the compiler and the Cmm sources contain many
places where we call `barf()` via `ccall` convention!! Like, when
you write `foreign "C" barf("foo object (%p) entered!", R1)`, it
totally doesn't do what you think it'll do at all!! The second
argument `R1` is not properly passed in `va_list`, and the behavior
is completely undefined!!
- Even more unfortunately, this issue has been sitting around long
enough because the ABI mismatch is subtle enough on normie platforms
like x64 and arm64.
- But there are platforms like wasm32 that are stricter about ABI, and
the broken `barf()` invocations already causes trouble for wasm
backend: we had to use ugly hacks like `barf(errmsg, NULL)` to make
`wasm-ld` happy, and even with this band-aid, compiler-generated
`barf()` invocations are still broken, resulting in regressions in
certain debug-related functionality, e.g. `-dtag-inference-checks`
is broken on wasm32 (#22882).
This patch properly fixes the issue:
- We add non-variadic `barf` wrappers in the RTS that can be used as
`ccall` callees
- Both the compiler `emitBarf` logic and the hand-written Cmm are
changed to call these wrappers
- `emitBarf` now also properly annotates the foreign call as
`CmmNeverReturns` to indicate it's a noreturn call to enable more
efficient code generation
`-dtag-inference-checks` now works on wasm. Closes #22882.
Co-authored-by: Codex <codex(a)openai.com>
- - - - -
b3dd23b9 by Vilim Lendvaj at 2025-12-18T13:23:57-05:00
Remove outdated comment
The Traversable instance for ZipList is no longer in
GHC.Internal.Data.Traversable. In fact, it is right below this very comment.
- - - - -
9a9c2f03 by Cheng Shao at 2025-12-18T13:24:39-05:00
compiler: remove unused OtherSection logic
This patch removes the OtherSection logic in Cmm, given it's never
actually used by any of our backends.
- - - - -
91edd292 by Wolfgang Jeltsch at 2025-12-19T03:18:19-05:00
Remove unused known-key and name variables for generics
This removes the known-key and corresponding name variables for `K1`,
`M1`, `R`, `D`, `C`, `S`, and `URec` from `GHC.Generics`, as they are
apparently nowhere used in GHC’s source code.
- - - - -
73ee7e38 by Wolfgang Jeltsch at 2025-12-19T03:19:02-05:00
Remove unused known keys and names for generics classes
This removes the known-key and corresponding name variables for
`Datatype`, `Constructor`, and `Selector` from `GHC.Generics`, as they
are apparently nowhere used in GHC’s source code.
- - - - -
f69c5f14 by Cheng Shao at 2025-12-19T03:19:45-05:00
wasm: fix handling of ByteArray#/MutableByteArray# arguments in JSFFI imports
This patch fixes the handling of ByteArray#/MutableByteArray#
arguments in JSFFI imports, see the amended note and manual for
explanation. Also adds a test to witness the fix.
Co-authored-by: Codex <codex(a)openai.com>
- - - - -
224446a2 by Cheng Shao at 2025-12-20T07:49:54-05:00
rts: workaround -Werror=maybe-uninitialized false positives
In some cases gcc might report -Werror=maybe-uninitialized that we
know are false positives, but need to workaround it to make validate
builds with -Werror pass.
- - - - -
251ec087 by Cheng Shao at 2025-12-20T07:49:54-05:00
hadrian: use -Og as C/C++ optimization level when debugging
This commit enables -Og as optimization level when compiling the debug
ways of rts. According to gcc documentation
(https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-Og)
-Og is a better choice than -O0 for producing debuggable code. It's
also supported by clang as well, so it makes sense to use it as a
default for debugging. Also add missing -g3 flag to C++ compilation
flags in +debug_info flavour transformer.
- - - - -
fb586c67 by Cheng Shao at 2025-12-20T07:50:36-05:00
compiler: replace DList with OrdList
This patch removes `DList` logic from the compiler and replaces it
with `OrdList` which also supports O(1) concatenation and should be
more memory efficient than the church-encoded `DList`.
- - - - -
8149c987 by Cheng Shao at 2025-12-20T17:06:51-05:00
hadrian: add with_profiled_libs flavour transformer
This patch adds a `with_profiled_libs` flavour transformer to hadrian
which is the exact opposite of `no_profiled_libs`. It adds profiling
ways to stage1+ rts/library ways, and doesn't alter other flavour
settings. It is useful when needing to test profiling logic locally
with a quick flavour.
- - - - -
746b18cd by Cheng Shao at 2025-12-20T17:06:51-05:00
hadrian: fix missing profiled dynamic libraries in profiled_ghc
This commit fixes the profiled_ghc flavour transformer to include
profiled dynamic libraries as well, since they're supported by GHC
since !12595.
- - - - -
4dd7e3b9 by Cheng Shao at 2025-12-20T17:07:33-05:00
ci: set http.postBuffer to mitigate perf notes timeout on some runners
This patch sets http.postBuffer to mitigate the timeout when fetching
perf notes on some runners with slow internet connection. Fixes #26684.
- - - - -
bc36268a by Wolfgang Jeltsch at 2025-12-21T16:23:24-05:00
Remove unused known keys and names for type representations
This removes the known-key and corresponding name variables for
`TrName`, `TrNameD`, `TypeRep`, `KindRepTypeLitD`, `TypeLitSort`, and
`mkTrType`, as they are apparently nowhere used in GHC’s source code.
- - - - -
ff5050e9 by Wolfgang Jeltsch at 2025-12-21T16:24:04-05:00
Remove unused known keys and names for natural operations
This removes the known-key and corresponding name variables for
`naturalAndNot`, `naturalLog2`, `naturalLogBaseWord`, `naturalLogBase`,
`naturalPowMod`, `naturalSizeInBase`, `naturalToFloat`, and
`naturalToDouble`, as they are apparently nowhere used in GHC’s source
code.
- - - - -
424388c2 by Wolfgang Jeltsch at 2025-12-21T16:24:45-05:00
Remove the unused known key and name for `Fingerprint`
This removes the variables for the known key and the name of the
`Fingerprint` data constructor, as they are apparently nowhere used in
GHC’s source code.
- - - - -
a1ed86fe by Wolfgang Jeltsch at 2025-12-21T16:25:26-05:00
Remove the unused known key and name for `failIO`
This removes the variables for the known key and the name of the
`failIO` operation, as they are apparently nowhere used in GHC’s source
code.
- - - - -
b8220daf by Wolfgang Jeltsch at 2025-12-21T16:26:07-05:00
Remove the unused known key and name for `liftM`
This removes the variables for the known key and the name of the `liftM`
operation, as they are apparently nowhere used in GHC’s source code.
- - - - -
eb0628b1 by Wolfgang Jeltsch at 2025-12-21T16:26:47-05:00
Fix the documentation of `hIsClosed`
- - - - -
db1ce858 by sheaf at 2025-12-22T17:11:17-05:00
Do deep subsumption when computing valid hole fits
This commit makes a couple of improvements to the code that
computes "valid hole fits":
1. It uses deep subsumption for data constructors.
This matches up the multiplicities, as per
Note [Typechecking data constructors].
This fixes #26338 (test: LinearHoleFits).
2. It now suggests (non-unidirectional) pattern synonyms as valid
hole fits. This fixes #26339 (test: PatSynHoleFit).
3. It uses 'stableNameCmp', to make the hole fit output deterministic.
-------------------------
Metric Increase:
hard_hole_fits
-------------------------
- - - - -
72ee9100 by sheaf at 2025-12-22T17:11:17-05:00
Speed up hole fits with a quick pre-test
This speeds up the machinery for valid hole fits by doing a small
check to rule out obviously wrong hole fits, such as:
1. A hole fit identifier whose type has a different TyCon at the head,
after looking through foralls and (=>) arrows, e.g.:
hole_ty = Int
cand_ty = Maybe a
or
hole_ty = forall a b. a -> b
cand_ty = forall x y. Either x y
2. A hole fit identifier that is not polymorphic when the hole type
is polymorphic, e.g.
hole_ty = forall a. a -> a
cand_ty = Int -> Int
-------------------------
Metric Decrease:
hard_hole_fits
-------------------------
- - - - -
30e513ba by Cheng Shao at 2025-12-22T17:12:00-05:00
configure: remove unused win32-tarballs.md5sum
This patch removes the unused `win32-tarballs.md5sum` file from the
tree. The current mingw tarball download logic in
`mk/get-win32-tarballs.py` fetches and checks against `SHA256SUM` from
the same location where the tarballs are fetched, and this file has
been unused for a few years.
- - - - -
a2d52b3b by Wolfgang Jeltsch at 2025-12-23T04:47:33-05:00
Add an operation `System.IO.hGetNewlineMode`
This commit also contains some small code and documentation changes for
related operations, for the sake of consistency.
- - - - -
b26d134a by Cheng Shao at 2025-12-23T04:48:15-05:00
rts: opportunistically reclaim slop space in shrinkMutableByteArray#
Previously, `shrinkMutableByteArray#` shrinks a `MutableByteArray#`
in-place by assigning the new size to it, and zeroing the extra slop
space. That slop space is not reclaimed and wasted. But it's often the
case that we allocate a `MutableByteArray#` upfront, then shrink it
shortly after, so the `MutableByteArray#` closure sits right at the
end of a nursery block; this patch identifies such chances, and also
shrink `bd->free` if possible, reducing heap space fragmentation.
Co-authored-by: Codex <codex(a)openai.com>
-------------------------
Metric Decrease:
T10678
-------------------------
- - - - -
4ad5ceb1 by Rodrigo Mesquita at 2025-12-23T17:51:42+00:00
Add test for #25636
The existing test behaviour of "T23146_liftedeq" changed because the
simplifier now does a bit more inlining. We can restore the previous bad
behavior by using an OPAQUE pragma.
This test doubles as a test for #25636 when run in ghci, so we add it as
such.
- - - - -
2328c598 by Rodrigo Mesquita at 2025-12-23T17:51:42+00:00
refactor: protoBCOName is always a Name
Simplifies the code by removing the unnecessary type argument to
ProtoBCO which was always 'Name'
- - - - -
ff3fe777 by Rodrigo Mesquita at 2025-12-23T17:55:01+00:00
99.9%
TODO: Write the Note
TODO: Commit message
- - - - -
581 changed files:
- .gitattributes
- .gitlab/ci.sh
- compiler/GHC.hs
- compiler/GHC/Builtin/Names.hs
- compiler/GHC/Builtin/PrimOps.hs
- compiler/GHC/Builtin/PrimOps/Ids.hs
- compiler/GHC/Builtin/Types/Literals.hs
- compiler/GHC/Builtin/Utils.hs
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/Breakpoints.hs
- compiler/GHC/ByteCode/InfoTable.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/ByteCode/Linker.hs
- compiler/GHC/ByteCode/Serialize.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Cmm.hs
- compiler/GHC/Cmm/BlockId.hs
- compiler/GHC/Cmm/CLabel.hs
- compiler/GHC/Cmm/CommonBlockElim.hs
- compiler/GHC/Cmm/Config.hs
- compiler/GHC/Cmm/ContFlowOpt.hs
- compiler/GHC/Cmm/Dataflow.hs
- compiler/GHC/Cmm/Dataflow/Block.hs
- compiler/GHC/Cmm/Dataflow/Graph.hs
- compiler/GHC/Cmm/Dataflow/Label.hs
- compiler/GHC/Cmm/DebugBlock.hs
- compiler/GHC/Cmm/Dominators.hs
- compiler/GHC/Cmm/Expr.hs
- compiler/GHC/Cmm/Graph.hs
- compiler/GHC/Cmm/Info/Build.hs
- compiler/GHC/Cmm/LRegSet.hs
- compiler/GHC/Cmm/LayoutStack.hs
- compiler/GHC/Cmm/Lint.hs
- compiler/GHC/Cmm/Liveness.hs
- compiler/GHC/Cmm/MachOp.hs
- compiler/GHC/Cmm/Node.hs
- compiler/GHC/Cmm/Parser.y
- compiler/GHC/Cmm/ProcPoint.hs
- compiler/GHC/Cmm/Reducibility.hs
- compiler/GHC/Cmm/Reg.hs
- compiler/GHC/Cmm/Sink.hs
- compiler/GHC/Cmm/Switch.hs
- compiler/GHC/Cmm/Switch/Implement.hs
- compiler/GHC/Cmm/ThreadSanitizer.hs
- compiler/GHC/Cmm/UniqueRenamer.hs
- compiler/GHC/Cmm/Utils.hs
- compiler/GHC/CmmToAsm/AArch64/Ppr.hs
- compiler/GHC/CmmToAsm/BlockLayout.hs
- compiler/GHC/CmmToAsm/CFG.hs
- compiler/GHC/CmmToAsm/CPrim.hs
- compiler/GHC/CmmToAsm/Dwarf/Types.hs
- compiler/GHC/CmmToAsm/Format.hs
- compiler/GHC/CmmToAsm/LA64/CodeGen.hs
- compiler/GHC/CmmToAsm/LA64/Ppr.hs
- compiler/GHC/CmmToAsm/Monad.hs
- compiler/GHC/CmmToAsm/PPC/CodeGen.hs
- compiler/GHC/CmmToAsm/PPC/Ppr.hs
- compiler/GHC/CmmToAsm/Ppr.hs
- compiler/GHC/CmmToAsm/RV64/CodeGen.hs
- compiler/GHC/CmmToAsm/RV64/Ppr.hs
- compiler/GHC/CmmToAsm/Reg/Graph.hs
- compiler/GHC/CmmToAsm/Reg/Graph/Coalesce.hs
- compiler/GHC/CmmToAsm/Reg/Graph/Spill.hs
- compiler/GHC/CmmToAsm/Reg/Graph/SpillClean.hs
- compiler/GHC/CmmToAsm/Reg/Graph/SpillCost.hs
- compiler/GHC/CmmToAsm/Reg/Linear.hs
- compiler/GHC/CmmToAsm/Reg/Linear/Base.hs
- compiler/GHC/CmmToAsm/Reg/Linear/JoinToTargets.hs
- compiler/GHC/CmmToAsm/Reg/Linear/State.hs
- compiler/GHC/CmmToAsm/Reg/Linear/X86.hs
- compiler/GHC/CmmToAsm/Reg/Linear/X86_64.hs
- compiler/GHC/CmmToAsm/Reg/Liveness.hs
- + compiler/GHC/CmmToAsm/Reg/Regs.hs
- compiler/GHC/CmmToAsm/Reg/Target.hs
- compiler/GHC/CmmToAsm/Wasm.hs
- compiler/GHC/CmmToAsm/Wasm/Asm.hs
- compiler/GHC/CmmToAsm/Wasm/FromCmm.hs
- compiler/GHC/CmmToAsm/Wasm/Types.hs
- compiler/GHC/CmmToAsm/X86/CodeGen.hs
- compiler/GHC/CmmToAsm/X86/Instr.hs
- compiler/GHC/CmmToAsm/X86/Ppr.hs
- compiler/GHC/CmmToC.hs
- compiler/GHC/CmmToLlvm/Base.hs
- compiler/GHC/CmmToLlvm/CodeGen.hs
- compiler/GHC/CmmToLlvm/Data.hs
- compiler/GHC/Core/Coercion.hs
- compiler/GHC/Core/Coercion.hs-boot
- compiler/GHC/Core/Coercion/Axiom.hs
- compiler/GHC/Core/DataCon.hs
- compiler/GHC/Core/FamInstEnv.hs
- compiler/GHC/Core/InstEnv.hs
- compiler/GHC/Core/LateCC/OverloadedCalls.hs
- compiler/GHC/Core/LateCC/TopLevelBinds.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Lint/Interactive.hs
- compiler/GHC/Core/Map/Expr.hs
- compiler/GHC/Core/Map/Type.hs
- compiler/GHC/Core/Opt/CallerCC.hs
- compiler/GHC/Core/Opt/ConstantFold.hs
- compiler/GHC/Core/Opt/Monad.hs
- compiler/GHC/Core/Opt/SpecConstr.hs
- compiler/GHC/Core/Ppr.hs
- compiler/GHC/Core/Predicate.hs
- compiler/GHC/Core/SimpleOpt.hs
- compiler/GHC/Core/TyCo/Compare.hs
- compiler/GHC/Core/TyCo/Rep.hs
- compiler/GHC/Core/TyCon.hs
- compiler/GHC/Core/TyCon/Env.hs
- compiler/GHC/Core/Type.hs
- compiler/GHC/Core/Type.hs-boot
- compiler/GHC/Core/Unify.hs
- compiler/GHC/CoreToStg.hs
- compiler/GHC/Data/Bag.hs
- compiler/GHC/Data/FastString.hs
- compiler/GHC/Data/Graph/Collapse.hs
- compiler/GHC/Data/Graph/Color.hs
- compiler/GHC/Data/Graph/Directed.hs
- compiler/GHC/Data/List/Infinite.hs
- compiler/GHC/Data/List/NonEmpty.hs
- compiler/GHC/Data/Maybe.hs
- compiler/GHC/Data/Pair.hs
- compiler/GHC/Data/Stream.hs
- compiler/GHC/Data/Strict.hs
- compiler/GHC/Data/StringBuffer.hs
- compiler/GHC/Data/TrieMap.hs
- compiler/GHC/Data/Word64Map.hs
- compiler/GHC/Driver/Backend.hs
- compiler/GHC/Driver/Backpack.hs
- compiler/GHC/Driver/CmdLine.hs
- compiler/GHC/Driver/CodeOutput.hs
- compiler/GHC/Driver/Config/StgToCmm.hs
- compiler/GHC/Driver/Config/Tidy.hs
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Env.hs
- compiler/GHC/Driver/Env/KnotVars.hs
- compiler/GHC/Driver/Errors.hs
- compiler/GHC/Driver/Errors/Ppr.hs
- compiler/GHC/Driver/Errors/Types.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/GenerateCgIPEStub.hs
- compiler/GHC/Driver/Hooks.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Driver/Make.hs
- compiler/GHC/Driver/MakeSem.hs
- compiler/GHC/Driver/Pipeline.hs
- compiler/GHC/Driver/Pipeline/Execute.hs
- compiler/GHC/Driver/Pipeline/LogQueue.hs
- compiler/GHC/Driver/Pipeline/Monad.hs
- compiler/GHC/Driver/Pipeline/Phases.hs
- compiler/GHC/Driver/Plugins.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Driver/Session/Inspect.hs
- compiler/GHC/Driver/Session/Units.hs
- compiler/GHC/Hs.hs
- compiler/GHC/Hs/Basic.hs
- compiler/GHC/Hs/Binds.hs
- compiler/GHC/Hs/Decls.hs
- compiler/GHC/Hs/Doc.hs
- compiler/GHC/Hs/Doc.hs-boot
- compiler/GHC/Hs/DocString.hs
- compiler/GHC/Hs/Dump.hs
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/Hs/Expr.hs-boot
- compiler/GHC/Hs/Extension.hs
- compiler/GHC/Hs/ImpExp.hs
- compiler/GHC/Hs/Instances.hs
- compiler/GHC/Hs/Lit.hs
- compiler/GHC/Hs/Pat.hs
- compiler/GHC/Hs/Pat.hs-boot
- compiler/GHC/Hs/Stats.hs
- compiler/GHC/Hs/Type.hs
- compiler/GHC/Hs/Utils.hs
- compiler/GHC/HsToCore/Arrows.hs
- compiler/GHC/HsToCore/Binds.hs
- compiler/GHC/HsToCore/Docs.hs
- compiler/GHC/HsToCore/Errors/Ppr.hs
- compiler/GHC/HsToCore/Errors/Types.hs
- compiler/GHC/HsToCore/Expr.hs
- compiler/GHC/HsToCore/Foreign/Decl.hs
- compiler/GHC/HsToCore/Foreign/Wasm.hs
- compiler/GHC/HsToCore/ListComp.hs
- compiler/GHC/HsToCore/Match.hs
- compiler/GHC/HsToCore/Match/Literal.hs
- compiler/GHC/HsToCore/Monad.hs
- compiler/GHC/HsToCore/Pmc.hs
- compiler/GHC/HsToCore/Pmc/Check.hs
- compiler/GHC/HsToCore/Pmc/Desugar.hs
- compiler/GHC/HsToCore/Pmc/Solver.hs
- compiler/GHC/HsToCore/Pmc/Solver/Types.hs
- compiler/GHC/HsToCore/Pmc/Types.hs
- compiler/GHC/HsToCore/Pmc/Utils.hs
- compiler/GHC/HsToCore/Quote.hs
- compiler/GHC/HsToCore/Utils.hs
- compiler/GHC/Iface/Binary.hs
- compiler/GHC/Iface/Decl.hs
- compiler/GHC/Iface/Env.hs
- compiler/GHC/Iface/Errors.hs
- compiler/GHC/Iface/Errors/Ppr.hs
- compiler/GHC/Iface/Errors/Types.hs
- compiler/GHC/Iface/Ext/Ast.hs
- compiler/GHC/Iface/Ext/Debug.hs
- compiler/GHC/Iface/Ext/Types.hs
- compiler/GHC/Iface/Ext/Utils.hs
- compiler/GHC/Iface/Load.hs
- compiler/GHC/Iface/Recomp.hs
- compiler/GHC/Iface/Rename.hs
- compiler/GHC/Iface/Syntax.hs
- compiler/GHC/Iface/Tidy.hs
- compiler/GHC/Iface/Type.hs
- compiler/GHC/Iface/Warnings.hs
- compiler/GHC/IfaceToCore.hs
- compiler/GHC/JS/Ident.hs
- compiler/GHC/JS/JStg/Monad.hs
- compiler/GHC/JS/JStg/Syntax.hs
- compiler/GHC/JS/Make.hs
- compiler/GHC/JS/Optimizer.hs
- compiler/GHC/JS/Ppr.hs
- compiler/GHC/JS/Syntax.hs
- compiler/GHC/JS/Transform.hs
- compiler/GHC/Linker/Deps.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Linker/Types.hs
- compiler/GHC/Llvm/MetaData.hs
- compiler/GHC/Llvm/Ppr.hs
- compiler/GHC/Llvm/Types.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/Annotation.hs
- compiler/GHC/Parser/Errors/Basic.hs
- compiler/GHC/Parser/Errors/Ppr.hs
- compiler/GHC/Parser/Errors/Types.hs
- compiler/GHC/Parser/Lexer.x
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Parser/PostProcess/Haddock.hs
- compiler/GHC/Parser/String.hs
- compiler/GHC/Parser/Types.hs
- compiler/GHC/Platform.hs
- compiler/GHC/Platform/Reg/Class.hs
- compiler/GHC/Platform/Reg/Class/NoVectors.hs
- compiler/GHC/Platform/Reg/Class/Separate.hs
- compiler/GHC/Platform/Reg/Class/Unified.hs
- compiler/GHC/Rename/Bind.hs
- compiler/GHC/Rename/Env.hs
- compiler/GHC/Rename/Expr.hs
- compiler/GHC/Rename/Expr.hs-boot
- compiler/GHC/Rename/HsType.hs
- compiler/GHC/Rename/Module.hs
- compiler/GHC/Rename/Names.hs
- compiler/GHC/Rename/Pat.hs
- compiler/GHC/Rename/Splice.hs
- compiler/GHC/Rename/Unbound.hs
- compiler/GHC/Rename/Utils.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Runtime/Heap/Layout.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/Runtime/Interpreter/JS.hs
- compiler/GHC/Runtime/Interpreter/Process.hs
- compiler/GHC/Runtime/Interpreter/Types.hs
- compiler/GHC/Runtime/Interpreter/Types/SymbolCache.hs
- compiler/GHC/Settings/IO.hs
- compiler/GHC/Stg/Debug.hs
- compiler/GHC/Stg/EnforceEpt.hs
- compiler/GHC/Stg/EnforceEpt/Rewrite.hs
- compiler/GHC/Stg/EnforceEpt/TagSig.hs
- compiler/GHC/Stg/EnforceEpt/Types.hs
- compiler/GHC/Stg/FVs.hs
- compiler/GHC/Stg/Lift/Analysis.hs
- compiler/GHC/Stg/Lift/Monad.hs
- compiler/GHC/Stg/Lift/Types.hs
- compiler/GHC/Stg/Lint.hs
- compiler/GHC/Stg/Pipeline.hs
- compiler/GHC/Stg/Syntax.hs
- compiler/GHC/Stg/Unarise.hs
- compiler/GHC/Stg/Utils.hs
- compiler/GHC/StgToByteCode.hs
- compiler/GHC/StgToCmm.hs
- compiler/GHC/StgToCmm/ArgRep.hs
- compiler/GHC/StgToCmm/Bind.hs
- compiler/GHC/StgToCmm/CgUtils.hs
- compiler/GHC/StgToCmm/Closure.hs
- compiler/GHC/StgToCmm/ExtCode.hs
- compiler/GHC/StgToCmm/InfoTableProv.hs
- compiler/GHC/StgToCmm/Lit.hs
- compiler/GHC/StgToCmm/Monad.hs
- compiler/GHC/StgToCmm/Prim.hs
- compiler/GHC/StgToCmm/Utils.hs
- compiler/GHC/StgToJS/Apply.hs
- compiler/GHC/StgToJS/Arg.hs
- compiler/GHC/StgToJS/CodeGen.hs
- compiler/GHC/StgToJS/DataCon.hs
- compiler/GHC/StgToJS/Deps.hs
- compiler/GHC/StgToJS/Expr.hs
- compiler/GHC/StgToJS/ExprCtx.hs
- compiler/GHC/StgToJS/FFI.hs
- compiler/GHC/StgToJS/Heap.hs
- compiler/GHC/StgToJS/Linker/Linker.hs
- compiler/GHC/StgToJS/Linker/Opt.hs
- compiler/GHC/StgToJS/Linker/Types.hs
- compiler/GHC/StgToJS/Literal.hs
- compiler/GHC/StgToJS/Monad.hs
- compiler/GHC/StgToJS/Object.hs
- compiler/GHC/StgToJS/Prim.hs
- compiler/GHC/StgToJS/Rts/Rts.hs
- compiler/GHC/StgToJS/Rts/Types.hs
- compiler/GHC/StgToJS/Sinker/Collect.hs
- compiler/GHC/StgToJS/Sinker/Sinker.hs
- compiler/GHC/StgToJS/Sinker/StringsUnfloat.hs
- compiler/GHC/StgToJS/Types.hs
- compiler/GHC/StgToJS/Utils.hs
- compiler/GHC/SysTools.hs
- compiler/GHC/SysTools/Ar.hs
- compiler/GHC/SysTools/BaseDir.hs
- compiler/GHC/SysTools/Cpp.hs
- compiler/GHC/SysTools/Tasks.hs
- compiler/GHC/SysTools/Terminal.hs
- compiler/GHC/Tc/Deriv.hs
- compiler/GHC/Tc/Deriv/Functor.hs
- compiler/GHC/Tc/Deriv/Generate.hs
- compiler/GHC/Tc/Deriv/Generics.hs
- compiler/GHC/Tc/Deriv/Utils.hs
- compiler/GHC/Tc/Errors.hs
- compiler/GHC/Tc/Errors/Hole.hs
- compiler/GHC/Tc/Errors/Hole/FitTypes.hs
- compiler/GHC/Tc/Errors/Hole/Plugin.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Tc/Errors/Types/PromotionErr.hs
- compiler/GHC/Tc/Gen/Annotation.hs
- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/Gen/Arrow.hs
- compiler/GHC/Tc/Gen/Bind.hs
- compiler/GHC/Tc/Gen/Default.hs
- compiler/GHC/Tc/Gen/Do.hs
- compiler/GHC/Tc/Gen/Export.hs
- compiler/GHC/Tc/Gen/Expr.hs
- compiler/GHC/Tc/Gen/Foreign.hs
- compiler/GHC/Tc/Gen/Head.hs
- compiler/GHC/Tc/Gen/HsType.hs
- compiler/GHC/Tc/Gen/Match.hs
- compiler/GHC/Tc/Gen/Pat.hs
- compiler/GHC/Tc/Gen/Splice.hs
- compiler/GHC/Tc/Instance/Family.hs
- compiler/GHC/Tc/Instance/FunDeps.hs
- compiler/GHC/Tc/Instance/Typeable.hs
- compiler/GHC/Tc/Module.hs
- compiler/GHC/Tc/Solver.hs
- compiler/GHC/Tc/Solver/Equality.hs
- compiler/GHC/Tc/Solver/InertSet.hs
- compiler/GHC/Tc/Solver/Irred.hs
- compiler/GHC/Tc/Solver/Monad.hs
- compiler/GHC/Tc/Solver/Types.hs
- compiler/GHC/Tc/TyCl.hs
- compiler/GHC/Tc/TyCl/Instance.hs
- compiler/GHC/Tc/TyCl/PatSyn.hs
- compiler/GHC/Tc/TyCl/Utils.hs
- compiler/GHC/Tc/Types.hs
- compiler/GHC/Tc/Types/Constraint.hs
- compiler/GHC/Tc/Types/ErrCtxt.hs
- compiler/GHC/Tc/Types/Evidence.hs
- compiler/GHC/Tc/Types/Origin.hs
- compiler/GHC/Tc/Utils/Backpack.hs
- compiler/GHC/Tc/Utils/Env.hs
- compiler/GHC/Tc/Utils/Instantiate.hs
- compiler/GHC/Tc/Utils/TcMType.hs
- compiler/GHC/Tc/Utils/TcType.hs
- compiler/GHC/Tc/Utils/Unify.hs
- compiler/GHC/Tc/Validity.hs
- compiler/GHC/Tc/Zonk/Monad.hs
- compiler/GHC/Tc/Zonk/Type.hs
- compiler/GHC/ThToHs.hs
- compiler/GHC/Types/Annotations.hs
- compiler/GHC/Types/Avail.hs
- compiler/GHC/Types/Basic.hs
- compiler/GHC/Types/CompleteMatch.hs
- compiler/GHC/Types/CostCentre.hs
- compiler/GHC/Types/CostCentre/State.hs
- compiler/GHC/Types/DefaultEnv.hs
- compiler/GHC/Types/Demand.hs
- compiler/GHC/Types/Error.hs
- compiler/GHC/Types/Error/Codes.hs
- compiler/GHC/Types/FieldLabel.hs
- compiler/GHC/Types/Fixity.hs
- compiler/GHC/Types/ForeignCall.hs
- compiler/GHC/Types/ForeignStubs.hs
- compiler/GHC/Types/GREInfo.hs
- compiler/GHC/Types/Hint.hs
- compiler/GHC/Types/Hint/Ppr.hs
- compiler/GHC/Types/Id/Info.hs
- compiler/GHC/Types/Id/Make.hs
- compiler/GHC/Types/Literal.hs
- compiler/GHC/Types/Name.hs
- compiler/GHC/Types/Name/Cache.hs
- compiler/GHC/Types/Name/Occurrence.hs
- compiler/GHC/Types/Name/Reader.hs
- compiler/GHC/Types/Name/Set.hs
- compiler/GHC/Types/PkgQual.hs
- compiler/GHC/Types/RepType.hs
- compiler/GHC/Types/SaneDouble.hs
- compiler/GHC/Types/SourceText.hs
- compiler/GHC/Types/SrcLoc.hs
- compiler/GHC/Types/Tickish.hs
- compiler/GHC/Types/TyThing.hs
- compiler/GHC/Types/Unique/DFM.hs
- compiler/GHC/Types/Unique/DSet.hs
- compiler/GHC/Types/Unique/FM.hs
- compiler/GHC/Types/Unique/Map.hs
- compiler/GHC/Types/Unique/SDFM.hs
- compiler/GHC/Types/Unique/Set.hs
- compiler/GHC/Types/Var.hs
- compiler/GHC/Unit.hs
- compiler/GHC/Unit/Env.hs
- compiler/GHC/Unit/Finder.hs
- compiler/GHC/Unit/Home/PackageTable.hs
- compiler/GHC/Unit/Info.hs
- compiler/GHC/Unit/Module.hs
- compiler/GHC/Unit/Module/Deps.hs
- compiler/GHC/Unit/Module/Graph.hs
- compiler/GHC/Unit/Module/ModIface.hs
- compiler/GHC/Unit/Module/ModSummary.hs
- compiler/GHC/Unit/Module/Status.hs
- compiler/GHC/Unit/Module/Warnings.hs
- compiler/GHC/Unit/Module/WholeCoreBindings.hs
- compiler/GHC/Unit/State.hs
- compiler/GHC/Unit/Types.hs
- compiler/GHC/Unit/Types.hs-boot
- compiler/GHC/Utils/Binary.hs
- compiler/GHC/Utils/Binary/Typeable.hs
- compiler/GHC/Utils/Exception.hs
- compiler/GHC/Utils/Json.hs
- compiler/GHC/Utils/Logger.hs
- compiler/GHC/Utils/Misc.hs
- compiler/GHC/Utils/Monad/Codensity.hs
- compiler/GHC/Utils/Outputable.hs
- compiler/GHC/Utils/Panic.hs
- compiler/GHC/Utils/Panic/Plain.hs
- compiler/GHC/Wasm/ControlFlow.hs
- compiler/GHC/Wasm/ControlFlow/FromCmm.hs
- compiler/Language/Haskell/Syntax.hs
- compiler/Language/Haskell/Syntax/Basic.hs
- compiler/Language/Haskell/Syntax/Binds.hs
- compiler/Language/Haskell/Syntax/Decls.hs
- compiler/Language/Haskell/Syntax/Expr.hs
- compiler/Language/Haskell/Syntax/Expr.hs-boot
- compiler/Language/Haskell/Syntax/Extension.hs
- compiler/Language/Haskell/Syntax/ImpExp.hs
- compiler/Language/Haskell/Syntax/Lit.hs
- compiler/Language/Haskell/Syntax/Pat.hs
- compiler/Language/Haskell/Syntax/Pat.hs-boot
- compiler/Language/Haskell/Syntax/Type.hs
- compiler/ghc.cabal.in
- docs/users_guide/9.16.1-notes.rst
- docs/users_guide/ghci.rst
- docs/users_guide/phases.rst
- docs/users_guide/wasm.rst
- ghc/GHC/Driver/Session/Lint.hs
- ghc/GHC/Driver/Session/Mode.hs
- ghc/GHCi/Leak.hs
- ghc/GHCi/UI.hs
- ghc/GHCi/UI/Exception.hs
- ghc/GHCi/UI/Info.hs
- ghc/GHCi/UI/Monad.hs
- ghc/Main.hs
- ghc/ghc-bin.cabal.in
- hadrian/doc/flavours.md
- hadrian/src/Flavour.hs
- hadrian/src/Settings/Packages.hs
- libraries/base/changelog.md
- libraries/base/src/System/IO.hs
- libraries/ghc-internal/src/GHC/Internal/Data/OldList.hs
- libraries/ghc-internal/src/GHC/Internal/Functor/ZipList.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle.hs
- libraries/ghc-internal/src/GHC/Internal/System/IO.hs
- libraries/ghci/GHCi/CreateBCO.hs
- libraries/ghci/GHCi/ResolvedBCO.hs
- − mk/win32-tarballs.md5sum
- rts/Apply.cmm
- rts/Compact.cmm
- rts/ContinuationOps.cmm
- rts/Exception.cmm
- rts/Interpreter.c
- rts/Jumps.h
- rts/PrimOps.cmm
- rts/RtsMessages.c
- rts/RtsSymbols.c
- rts/StgMiscClosures.cmm
- rts/StgStartup.cmm
- rts/include/Stg.h
- rts/include/rts/Messages.h
- rts/include/rts/storage/ClosureMacros.h
- rts/include/stg/MiscClosures.h
- rts/linker/InitFini.c
- rts/prim/mulIntMayOflo.c
- rts/sm/Sanity.c
- testsuite/tests/codeGen/should_run/T23146/T23146_liftedeq.hs
- + testsuite/tests/codeGen/should_run/T23146/T25636.script
- + testsuite/tests/codeGen/should_run/T23146/T25636.stdout
- testsuite/tests/codeGen/should_run/T23146/all.T
- testsuite/tests/diagnostic-codes/codes.stdout
- testsuite/tests/ghci/scripts/T8353.stderr
- testsuite/tests/haddock/should_compile_flag_haddock/T17544_kw.stderr
- testsuite/tests/interface-stability/base-exports.stdout
- testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
- testsuite/tests/interface-stability/base-exports.stdout-mingw32
- testsuite/tests/interface-stability/base-exports.stdout-ws-32
- testsuite/tests/jsffi/all.T
- + testsuite/tests/jsffi/bytearrayarg.hs
- + testsuite/tests/jsffi/bytearrayarg.mjs
- + testsuite/tests/jsffi/bytearrayarg.stdout
- testsuite/tests/numeric/should_run/all.T
- testsuite/tests/numeric/should_run/foundation.hs
- testsuite/tests/numeric/should_run/foundation.stdout
- testsuite/tests/overloadedrecflds/should_fail/DRFHoleFits.stderr
- testsuite/tests/patsyn/should_fail/all.T
- + testsuite/tests/patsyn/should_fail/import-syntax-no-ext.hs
- + testsuite/tests/patsyn/should_fail/import-syntax-no-ext.stderr
- testsuite/tests/perf/compiler/hard_hole_fits.stderr
- testsuite/tests/perf/should_run/all.T
- testsuite/tests/plugins/test-hole-plugin.stderr
- + testsuite/tests/rename/should_compile/T25901_sub_e.hs
- + testsuite/tests/rename/should_compile/T25901_sub_f.hs
- + testsuite/tests/rename/should_compile/T25901_sub_f.stderr
- + testsuite/tests/rename/should_compile/T25901_sub_g.hs
- + testsuite/tests/rename/should_compile/T25901_sub_g.stderr
- + testsuite/tests/rename/should_compile/T25901_sub_g_helper.hs
- testsuite/tests/rename/should_compile/all.T
- testsuite/tests/rename/should_fail/T23570b.stderr
- + testsuite/tests/rename/should_fail/T25901_sub_a.hs
- + testsuite/tests/rename/should_fail/T25901_sub_a.stderr
- + testsuite/tests/rename/should_fail/T25901_sub_b.hs
- + testsuite/tests/rename/should_fail/T25901_sub_b.stderr
- + testsuite/tests/rename/should_fail/T25901_sub_c.hs
- + testsuite/tests/rename/should_fail/T25901_sub_c.stderr
- + testsuite/tests/rename/should_fail/T25901_sub_c_helper.hs
- + testsuite/tests/rename/should_fail/T25901_sub_d.hs
- + testsuite/tests/rename/should_fail/T25901_sub_d.stderr
- + testsuite/tests/rename/should_fail/T25901_sub_d_helper.hs
- + testsuite/tests/rename/should_fail/T25901_sub_w.hs
- + testsuite/tests/rename/should_fail/T25901_sub_w.stderr
- testsuite/tests/rename/should_fail/all.T
- + testsuite/tests/simd/should_run/T26411.hs
- + testsuite/tests/simd/should_run/T26411.stdout
- + testsuite/tests/simd/should_run/T26411b.hs
- + testsuite/tests/simd/should_run/T26411b.stdout
- testsuite/tests/simd/should_run/all.T
- testsuite/tests/simplStg/should_compile/all.T
- testsuite/tests/th/T15321.stderr
- testsuite/tests/typecheck/should_compile/T13050.stderr
- testsuite/tests/typecheck/should_compile/T14273.stderr
- testsuite/tests/typecheck/should_compile/T14590.stderr
- testsuite/tests/typecheck/should_compile/T25180.stderr
- testsuite/tests/typecheck/should_compile/abstract_refinement_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/constraint_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/free_monad_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/hole_constraints.stderr
- testsuite/tests/typecheck/should_compile/holes.stderr
- testsuite/tests/typecheck/should_compile/holes2.stderr
- testsuite/tests/typecheck/should_compile/holes3.stderr
- testsuite/tests/typecheck/should_compile/refinement_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/subsumption_sort_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/type_in_type_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/valid_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/valid_hole_fits_interactions.stderr
- testsuite/tests/typecheck/should_fail/T14884.stderr
- testsuite/tests/warnings/should_compile/DodgyExports03.stderr
- testsuite/tests/warnings/should_compile/DodgyImports.stderr
- + testsuite/tests/warnings/should_compile/DodgyImports02.hs
- + testsuite/tests/warnings/should_compile/DodgyImports02.stderr
- + testsuite/tests/warnings/should_compile/DodgyImports03.hs
- + testsuite/tests/warnings/should_compile/DodgyImports03.stderr
- + testsuite/tests/warnings/should_compile/DodgyImports03_helper.hs
- + testsuite/tests/warnings/should_compile/DodgyImports04.hs
- + testsuite/tests/warnings/should_compile/DodgyImports04.stderr
- testsuite/tests/warnings/should_compile/DodgyImports_hiding.stderr
- testsuite/tests/warnings/should_compile/all.T
- utils/check-exact/ExactPrint.hs
- utils/deriveConstants/Main.hs
- utils/genapply/Main.hs
- utils/haddock/haddock-api/haddock-api.cabal
- − utils/haddock/haddock-api/src/Haddock/Backends/HaddockDB.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Create.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/87b492bcb6f66da1b673a7227c5f2b…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/87b492bcb6f66da1b673a7227c5f2b…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/T26682] Add debug tracing to Specialise
by Simon Peyton Jones (@simonpj) 23 Dec '25
by Simon Peyton Jones (@simonpj) 23 Dec '25
23 Dec '25
Simon Peyton Jones pushed to branch wip/T26682 at Glasgow Haskell Compiler / GHC
Commits:
7fc54ebd by Simon Peyton Jones at 2025-12-23T17:49:16+00:00
Add debug tracing to Specialise
- - - - -
1 changed file:
- compiler/GHC/Core/Opt/Specialise.hs
Changes:
=====================================
compiler/GHC/Core/Opt/Specialise.hs
=====================================
@@ -804,20 +804,22 @@ spec_imports :: SpecEnv -- Passed in so that all top-level Ids are in s
, [CoreBind] ) -- Specialised bindings
spec_imports env callers dict_binds calls
= do { let import_calls = dVarEnvElts calls
--- ; debugTraceMsg (text "specImports {" <+>
--- vcat [ text "calls:" <+> ppr import_calls
--- , text "dict_binds:" <+> ppr dict_binds ])
+ ; debugTraceMsg (text "specImports {" <+>
+ vcat [ text "calls:" <+> ppr import_calls
+ , text "dict_binds:" <+> ppr dict_binds ])
; (env, rules, spec_binds) <- go env import_calls
--- ; debugTraceMsg (text "End specImports }" <+> ppr import_calls)
+ ; debugTraceMsg (text "End specImports }" <+> ppr import_calls)
; return (env, rules, spec_binds) }
where
go :: SpecEnv -> [CallInfoSet] -> CoreM (SpecEnv, [CoreRule], [CoreBind])
go env [] = return (env, [], [])
go env (cis : other_calls)
- = do { -- debugTraceMsg (text "specImport {" <+> ppr cis)
+ = do { debugTraceMsg (text "specImport {" <+> vcat [ ppr cis
+ , text "callers" <+> ppr callers
+ , text "dict_binds" <+> ppr dict_binds ])
; (env, rules1, spec_binds1) <- spec_import env callers dict_binds cis
- ; -- debugTraceMsg (text "specImport }" <+> ppr cis)
+ ; debugTraceMsg (text "specImport }" <+> ppr cis)
; (env, rules2, spec_binds2) <- go env other_calls
; return (env, rules1 ++ rules2, spec_binds1 ++ spec_binds2) }
@@ -834,13 +836,16 @@ spec_import :: SpecEnv -- Passed in so that all top-level Ids are
, [CoreBind] ) -- Specialised bindings
spec_import env callers dict_binds cis@(CIS fn _)
| isIn "specImport" fn callers
- = return (env, [], []) -- No warning. This actually happens all the time
- -- when specialising a recursive function, because
- -- the RHS of the specialised function contains a recursive
- -- call to the original function
+ = do { debugTraceMsg (text "specImport1-bad" <+> (ppr fn $$ text "callers" <+> ppr callers))
+ ; return (env, [], []) }
+ -- No warning. This actually happens all the time
+ -- when specialising a recursive function, because
+ -- the RHS of the specialised function contains a recursive
+ -- call to the original function
| null good_calls
- = return (env, [], [])
+ = do { debugTraceMsg (text "specImport1-no-good" <+> (ppr cis $$ text "dict_binds" <+> ppr dict_binds))
+ ; return (env, [], []) }
| Just rhs <- canSpecImport dflags fn
= do { -- Get rules from the external package state
@@ -849,12 +854,12 @@ spec_import env callers dict_binds cis@(CIS fn _)
; eps_rules <- getExternalRuleBase
; let rule_env = se_rules env `updExternalPackageRules` eps_rules
--- ; debugTraceMsg (text "specImport1" <+> vcat
--- [ text "function:" <+> ppr fn
--- , text "good calls:" <+> ppr good_calls
--- , text "existing rules:" <+> ppr (getRules rule_env fn)
--- , text "rhs:" <+> ppr rhs
--- , text "dict_binds:" <+> ppr dict_binds ])
+ ; debugTraceMsg (text "specImport1" <+> vcat
+ [ text "function:" <+> ppr fn
+ , text "good calls:" <+> ppr good_calls
+ , text "existing rules:" <+> ppr (getRules rule_env fn)
+ , text "rhs:" <+> ppr rhs
+ , text "dict_binds:" <+> ppr dict_binds ])
; (rules1, spec_pairs, MkUD { ud_binds = dict_binds1, ud_calls = new_calls })
<- runSpecM $ specCalls True env (getRules rule_env fn) good_calls fn rhs
@@ -889,7 +894,9 @@ spec_import env callers dict_binds cis@(CIS fn _)
; return (env, rules2 ++ rules1, final_binds) }
| otherwise
- = do { tryWarnMissingSpecs dflags callers fn good_calls
+ = do { debugTraceMsg (hang (text "specImport1-missed")
+ 2 (vcat [ppr cis, text "can-spec" <+> ppr (canSpecImport dflags fn)]))
+ ; tryWarnMissingSpecs dflags callers fn good_calls
; return (env, [], [])}
where
@@ -1698,15 +1705,15 @@ specCalls spec_imp env existing_rules calls_for_me fn rhs
-- , text "useful: " <+> ppr useful
-- , text "already_covered:" <+> ppr already_covered
-- , text "useful: " <+> ppr useful
--- , text "all_rule_bndrs:" <+> ppr all_rule_bndrs
+-- , text "all_rule_bndrs:" <+> ppr (sep (map (pprBndr LambdaBind) all_rule_bndrs))
-- , text "rule_lhs_args:" <+> ppr rule_lhs_args
--- , text "spec_bndrs:" <+> ppr spec_bndrs
+-- , text "spec_bndrs:" <+> ppr (sep (map (pprBndr LambdaBind) spec_bndrs))
-- , text "dx_binds:" <+> ppr dx_binds
-- , text "spec_args: " <+> ppr spec_args
--- , text "rhs_bndrs" <+> ppr rhs_bndrs
+-- , text "rhs_bndrs" <+> ppr (sep (map (pprBndr LambdaBind) rhs_bndrs))
-- , text "rhs_body" <+> ppr rhs_body
--- , text "subst''" <+> ppr subst'' ]) $
--- return ()
+-- , text "subst''" <+> ppr subst''
+-- ]) $ return ()
; if not useful -- No useful specialisation
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/7fc54ebd834042921deb4c3755b04b1…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/7fc54ebd834042921deb4c3755b04b1…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/T23162-part2] 11 commits: Do deep subsumption when computing valid hole fits
by Simon Peyton Jones (@simonpj) 23 Dec '25
by Simon Peyton Jones (@simonpj) 23 Dec '25
23 Dec '25
Simon Peyton Jones pushed to branch wip/T23162-part2 at Glasgow Haskell Compiler / GHC
Commits:
db1ce858 by sheaf at 2025-12-22T17:11:17-05:00
Do deep subsumption when computing valid hole fits
This commit makes a couple of improvements to the code that
computes "valid hole fits":
1. It uses deep subsumption for data constructors.
This matches up the multiplicities, as per
Note [Typechecking data constructors].
This fixes #26338 (test: LinearHoleFits).
2. It now suggests (non-unidirectional) pattern synonyms as valid
hole fits. This fixes #26339 (test: PatSynHoleFit).
3. It uses 'stableNameCmp', to make the hole fit output deterministic.
-------------------------
Metric Increase:
hard_hole_fits
-------------------------
- - - - -
72ee9100 by sheaf at 2025-12-22T17:11:17-05:00
Speed up hole fits with a quick pre-test
This speeds up the machinery for valid hole fits by doing a small
check to rule out obviously wrong hole fits, such as:
1. A hole fit identifier whose type has a different TyCon at the head,
after looking through foralls and (=>) arrows, e.g.:
hole_ty = Int
cand_ty = Maybe a
or
hole_ty = forall a b. a -> b
cand_ty = forall x y. Either x y
2. A hole fit identifier that is not polymorphic when the hole type
is polymorphic, e.g.
hole_ty = forall a. a -> a
cand_ty = Int -> Int
-------------------------
Metric Decrease:
hard_hole_fits
-------------------------
- - - - -
30e513ba by Cheng Shao at 2025-12-22T17:12:00-05:00
configure: remove unused win32-tarballs.md5sum
This patch removes the unused `win32-tarballs.md5sum` file from the
tree. The current mingw tarball download logic in
`mk/get-win32-tarballs.py` fetches and checks against `SHA256SUM` from
the same location where the tarballs are fetched, and this file has
been unused for a few years.
- - - - -
a2d52b3b by Wolfgang Jeltsch at 2025-12-23T04:47:33-05:00
Add an operation `System.IO.hGetNewlineMode`
This commit also contains some small code and documentation changes for
related operations, for the sake of consistency.
- - - - -
b26d134a by Cheng Shao at 2025-12-23T04:48:15-05:00
rts: opportunistically reclaim slop space in shrinkMutableByteArray#
Previously, `shrinkMutableByteArray#` shrinks a `MutableByteArray#`
in-place by assigning the new size to it, and zeroing the extra slop
space. That slop space is not reclaimed and wasted. But it's often the
case that we allocate a `MutableByteArray#` upfront, then shrink it
shortly after, so the `MutableByteArray#` closure sits right at the
end of a nursery block; this patch identifies such chances, and also
shrink `bd->free` if possible, reducing heap space fragmentation.
Co-authored-by: Codex <codex(a)openai.com>
-------------------------
Metric Decrease:
T10678
-------------------------
- - - - -
81c413c4 by Simon Peyton Jones at 2025-12-23T16:11:24+00:00
Improved fundeps for closed type families
The big payload of this commit is to execute the plan suggested
in #23162, by improving the way that we generate functional
dependencies for closed type families.
It is all described in Note [Exploiting closed type families]
Most of the changes are in GHC.Tc.Solver.FunDeps
Other small changes
* GHC.Tc.Solver.bumpReductionDepth. This function brings together the code that
* Bumps the depth
* Checks for overflow
Previously the two were separated, sometimes quite widely.
* GHC.Core.Unify.niFixSubst: minor improvement, removing an unnecessary
itraetion in the base case.
* GHC.Core.Unify: no need to pass an InScopeSet to
tcUnifyTysForInjectivity. It can calculate one for itself; and it is
never inspected anyway so it's free to do so.
* GHC.Tc.Errors.Ppr: slight impovement to the error message for
reduction-stack overflow, when a constraint (rather than a type) is
involved.
* GHC.Tc.Solver.Monad.wrapUnifier: small change to the API
- - - - -
dd279145 by Simon Peyton Jones at 2025-12-23T16:11:24+00:00
Add missing (KK4) to kick-out criteria
There was a missing case in kick-out that meant we could fail
to solve an eminently-solvable constraint.
See the new notes about (KK4)
- - - - -
028e57df by Simon Peyton Jones at 2025-12-23T16:11:24+00:00
Some small refactorings of error reporting in the typechecker
This is just a tidy-up commit.
* Add ei_insoluble to ErrorItem, to cache insolubility.
Small tidy-up.
* Remove `is_ip` and `mkIPErr` from GHC.Tc.Errors; instead enhance mkDictErr
to handle implicit parameters. Small refactor.
- - - - -
f328b01e by Simon Peyton Jones at 2025-12-23T16:11:24+00:00
Better fundeps for type-family Givens
This commit addresses #22652, by recording when the fundeps for
a constraint are definitely insoluble. That in turn improves the
perspicacity of the pattern-match overlap checker.
See Note [Insoluble fundeps]
- - - - -
24c59428 by Simon Peyton Jones at 2025-12-23T16:11:24+00:00
Fix a buglet in niFixSubst
The MR of which this is part failed an assertion check extendTvSubst
because we extended the TvSubst with a CoVar. Boo.
This tiny patch fixes it, and adds the regression test from #13882
that showed it up.
- - - - -
0cc9db43 by Simon Peyton Jones at 2025-12-23T16:11:24+00:00
More on insolubility
- - - - -
103 changed files:
- .gitattributes
- compiler/GHC/Core/DataCon.hs
- compiler/GHC/Core/FamInstEnv.hs
- compiler/GHC/Core/TyCo/Subst.hs
- compiler/GHC/Core/TyCon.hs
- compiler/GHC/Core/Unify.hs
- compiler/GHC/HsToCore/Monad.hs
- compiler/GHC/Tc/Errors.hs
- compiler/GHC/Tc/Errors/Hole.hs
- compiler/GHC/Tc/Errors/Hole/FitTypes.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/Gen/Splice.hs
- compiler/GHC/Tc/Solver.hs
- compiler/GHC/Tc/Solver/Default.hs
- compiler/GHC/Tc/Solver/Dict.hs
- compiler/GHC/Tc/Solver/Equality.hs
- compiler/GHC/Tc/Solver/FunDeps.hs
- compiler/GHC/Tc/Solver/InertSet.hs
- compiler/GHC/Tc/Solver/Monad.hs
- compiler/GHC/Tc/Solver/Rewrite.hs
- compiler/GHC/Tc/Types/Constraint.hs
- compiler/GHC/Tc/Types/CtLoc.hs
- compiler/GHC/Tc/Utils/Monad.hs
- compiler/GHC/Tc/Utils/Unify.hs
- compiler/GHC/Types/TyThing.hs
- docs/users_guide/9.16.1-notes.rst
- libraries/base/changelog.md
- libraries/base/src/System/IO.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle.hs
- libraries/ghc-internal/src/GHC/Internal/System/IO.hs
- linters/lint-codes/LintCodes/Static.hs
- − mk/win32-tarballs.md5sum
- rts/PrimOps.cmm
- testsuite/tests/ghci/scripts/T8353.stderr
- testsuite/tests/indexed-types/should_compile/CEqCanOccursCheck.hs
- testsuite/tests/indexed-types/should_fail/T12522a.hs
- testsuite/tests/indexed-types/should_fail/T26176.stderr
- testsuite/tests/interface-stability/base-exports.stdout
- testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
- testsuite/tests/interface-stability/base-exports.stdout-mingw32
- testsuite/tests/interface-stability/base-exports.stdout-ws-32
- testsuite/tests/overloadedrecflds/should_fail/DRFHoleFits.stderr
- testsuite/tests/parser/should_fail/RecordDotSyntaxFail10.stderr
- testsuite/tests/parser/should_fail/RecordDotSyntaxFail13.stderr
- testsuite/tests/perf/compiler/hard_hole_fits.stderr
- testsuite/tests/plugins/test-hole-plugin.stderr
- testsuite/tests/pmcheck/should_compile/T15753c.hs
- + testsuite/tests/pmcheck/should_compile/T15753c.stderr
- testsuite/tests/pmcheck/should_compile/T15753d.hs
- + testsuite/tests/pmcheck/should_compile/T15753d.stderr
- + testsuite/tests/pmcheck/should_compile/T22652.hs
- + testsuite/tests/pmcheck/should_compile/T22652a.hs
- testsuite/tests/pmcheck/should_compile/all.T
- + testsuite/tests/polykinds/T13882.hs
- testsuite/tests/polykinds/all.T
- testsuite/tests/quantified-constraints/T15316A.stderr
- testsuite/tests/quantified-constraints/T17267.stderr
- testsuite/tests/quantified-constraints/T17267a.stderr
- testsuite/tests/quantified-constraints/T17267b.stderr
- testsuite/tests/quantified-constraints/T17267c.stderr
- testsuite/tests/quantified-constraints/T17267e.stderr
- testsuite/tests/quantified-constraints/T17458.stderr
- testsuite/tests/th/T15321.stderr
- testsuite/tests/typecheck/should_compile/T13050.stderr
- testsuite/tests/typecheck/should_compile/T14273.stderr
- testsuite/tests/typecheck/should_compile/T14590.stderr
- testsuite/tests/typecheck/should_compile/T16188.hs
- testsuite/tests/typecheck/should_compile/T25180.stderr
- testsuite/tests/typecheck/should_compile/abstract_refinement_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/constraint_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/free_monad_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/hole_constraints.stderr
- testsuite/tests/typecheck/should_compile/holes.stderr
- testsuite/tests/typecheck/should_compile/holes2.stderr
- testsuite/tests/typecheck/should_compile/holes3.stderr
- testsuite/tests/typecheck/should_compile/refinement_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/subsumption_sort_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/type_in_type_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/valid_hole_fits.stderr
- testsuite/tests/typecheck/should_compile/valid_hole_fits_interactions.stderr
- testsuite/tests/typecheck/should_fail/ContextStack1.stderr
- testsuite/tests/typecheck/should_fail/FD3.stderr
- testsuite/tests/typecheck/should_fail/FunDepOrigin1b.stderr
- testsuite/tests/typecheck/should_fail/T13506.stderr
- testsuite/tests/typecheck/should_fail/T14884.stderr
- testsuite/tests/typecheck/should_fail/T15767.stderr
- testsuite/tests/typecheck/should_fail/T19415.stderr
- testsuite/tests/typecheck/should_fail/T19415b.stderr
- testsuite/tests/typecheck/should_fail/T22924b.stderr
- + testsuite/tests/typecheck/should_fail/T23162b.hs
- + testsuite/tests/typecheck/should_fail/T23162b.stderr
- + testsuite/tests/typecheck/should_fail/T23162c.hs
- + testsuite/tests/typecheck/should_fail/T23162d.hs
- testsuite/tests/typecheck/should_fail/T5236.stderr
- testsuite/tests/typecheck/should_fail/T5978.stderr
- testsuite/tests/typecheck/should_fail/T9612.stderr
- testsuite/tests/typecheck/should_fail/TcCoercibleFail.stderr
- testsuite/tests/typecheck/should_fail/all.T
- testsuite/tests/typecheck/should_fail/tcfail143.stderr
- utils/deriveConstants/Main.hs
- utils/haddock/haddock-api/src/Haddock/Convert.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/737e11ab072e7d481b046d32376909…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/737e11ab072e7d481b046d32376909…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
23 Dec '25
Simon Peyton Jones pushed new branch wip/T26607-core-lint at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/T26607-core-lint
You're receiving this email because of your account on gitlab.haskell.org.
1
0
23 Dec '25
Simon Peyton Jones pushed to branch wip/T26548 at Glasgow Haskell Compiler / GHC
Commits:
ff484efd by Simon Peyton Jones at 2025-12-23T16:53:58+00:00
Remove white space
- - - - -
1 changed file:
- compiler/GHC/Core/Opt/Simplify/Utils.hs
Changes:
=====================================
compiler/GHC/Core/Opt/Simplify/Utils.hs
=====================================
@@ -1055,8 +1055,6 @@ Reason for (a):
were evaluated, nothing more. That in turn make the enclosing function
too big to inline elsewhere.
-
-
Reason for (b): we want to inline integerCompare here
integerLt# :: Integer -> Integer -> Bool#
integerLt# (IS x) (IS y) = x <# y
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/ff484efd3f799b1122740b31855a234…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/ff484efd3f799b1122740b31855a234…
You're receiving this email because of your account on gitlab.haskell.org.
1
0