
[Git][ghc/ghc][wip/fendor/ghci-debugger-unitid] Add `UnitId` to `EvalBreakpoint`
by Hannes Siebenhandl (@fendor) 23 Apr '25
by Hannes Siebenhandl (@fendor) 23 Apr '25
23 Apr '25
Hannes Siebenhandl pushed to branch wip/fendor/ghci-debugger-unitid at Glasgow Haskell Compiler / GHC
Commits:
7aa8d812 by fendor at 2025-04-23T15:52:27+02:00
Add `UnitId` to `EvalBreakpoint`
The `EvalBreakpoint` is used to communicate that a breakpoint was
encountered during code evaluation.
This `EvalBreakpoint` needs to be converted to an `InternalBreakpointId`
which stores a `Module` to uniquely find the correct `Module` in the
Home Package Table.
The `EvalBreakpoint` used to store only a `ModuleName` which is then
converted to a `Module` based on the currently active home unit.
This is incorrect in the face of multiple home units, the break point
could be in an entirely other home unit!
To fix this, we additionally store the `UnitId` of the `Module` in
`EvalBreakpoint` to later reconstruct the correct `Module`
All of the changes are the consequence of extending `EvalBreakpoint`
with the additional `ShortByteString` of the `UnitId`.
For performance reasons, we store the `ShortByteString` backing the
`UnitId` directly, avoiding marshalling overhead.
- - - - -
11 changed files:
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/StgToByteCode.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/Run.hs
- rts/Exception.cmm
- rts/Interpreter.c
Changes:
=====================================
compiler/GHC/ByteCode/Asm.hs
=====================================
@@ -732,13 +732,16 @@ assembleI platform i = case i of
CCALL off m_addr i -> do np <- addr m_addr
emit_ bci_CCALL [wOp off, Op np, SmallOp i]
PRIMCALL -> emit_ bci_PRIMCALL []
- BRK_FUN arr tick_mod tickx info_mod infox cc ->
+ BRK_FUN arr tick_mod tick_mod_id tickx info_mod info_mod_id infox cc ->
do p1 <- ptr (BCOPtrBreakArray arr)
tick_addr <- addr tick_mod
+ tick_unitid_addr <- addr tick_mod_id
info_addr <- addr info_mod
+ info_unitid_addr <- addr info_mod_id
np <- addr cc
emit_ bci_BRK_FUN [ Op p1
, Op tick_addr, Op info_addr
+ , Op tick_unitid_addr, Op info_unitid_addr
, SmallOp tickx, SmallOp infox
, Op np
]
=====================================
compiler/GHC/ByteCode/Instr.hs
=====================================
@@ -37,6 +37,7 @@ import GHC.Stg.Syntax
import GHCi.BreakArray (BreakArray)
import Language.Haskell.Syntax.Module.Name (ModuleName)
import GHC.Types.Unique
+import GHC.Unit.Types (UnitId)
-- ----------------------------------------------------------------------------
-- Bytecode instructions
@@ -233,8 +234,10 @@ data BCInstr
-- Breakpoints
| BRK_FUN (ForeignRef BreakArray)
(RemotePtr ModuleName) -- breakpoint tick module
+ (RemotePtr UnitId) -- breakpoint tick module unit id
!Word16 -- breakpoint tick index
(RemotePtr ModuleName) -- breakpoint info module
+ (RemotePtr UnitId) -- breakpoint info module unit id
!Word16 -- breakpoint info index
(RemotePtr CostCentre)
@@ -403,10 +406,10 @@ instance Outputable BCInstr where
ppr ENTER = text "ENTER"
ppr (RETURN pk) = text "RETURN " <+> ppr pk
ppr (RETURN_TUPLE) = text "RETURN_TUPLE"
- ppr (BRK_FUN _ _tick_mod tickx _info_mod infox _)
+ ppr (BRK_FUN _ _tick_mod _tick_mod_id tickx _info_mod _info_mod_id infox _)
= text "BRK_FUN" <+> text "<breakarray>"
- <+> text "<tick_module>" <+> ppr tickx
- <+> text "<info_module>" <+> ppr infox
+ <+> text "<tick_module>" <+> text "<tick_module_unitid>" <+> ppr tickx
+ <+> text "<info_module>" <+> text "<info_module_unitid>" <+> ppr infox
<+> text "<cc>"
#if MIN_VERSION_rts(1,0,3)
ppr (BCO_NAME nm) = text "BCO_NAME" <+> text (show nm)
=====================================
compiler/GHC/ByteCode/Types.hs
=====================================
@@ -50,6 +50,7 @@ import GHC.Stack.CCS
import GHC.Cmm.Expr ( GlobalRegSet, emptyRegSet, regSetToList )
import GHC.Iface.Syntax
import Language.Haskell.Syntax.Module.Name (ModuleName)
+import GHC.Unit.Types (UnitId)
-- -----------------------------------------------------------------------------
-- Compiled Byte Code
@@ -263,6 +264,9 @@ data ModBreaks
, modBreaks_breakInfo :: IntMap CgBreakInfo
-- ^ info about each breakpoint from the bytecode generator
, modBreaks_module :: RemotePtr ModuleName
+ -- ^ info about the module in which we are setting the breakpoint
+ , modBreaks_module_unitid :: RemotePtr UnitId
+ -- ^ The 'UnitId' of the 'ModuleName'
}
seqModBreaks :: ModBreaks -> ()
@@ -273,7 +277,8 @@ seqModBreaks ModBreaks{..} =
rnf modBreaks_decls `seq`
rnf modBreaks_ccs `seq`
rnf (fmap seqCgBreakInfo modBreaks_breakInfo) `seq`
- rnf modBreaks_module
+ rnf modBreaks_module `seq`
+ rnf modBreaks_module_unitid
-- | Construct an empty ModBreaks
emptyModBreaks :: ModBreaks
@@ -286,6 +291,7 @@ emptyModBreaks = ModBreaks
, modBreaks_ccs = array (0,-1) []
, modBreaks_breakInfo = IntMap.empty
, modBreaks_module = toRemotePtr nullPtr
+ , modBreaks_module_unitid = toRemotePtr nullPtr
}
{-
=====================================
compiler/GHC/HsToCore/Breakpoints.hs
=====================================
@@ -34,7 +34,7 @@ mkModBreaks interp mod extendedMixEntries
breakArray <- GHCi.newBreakArray interp count
ccs <- mkCCSArray interp mod count entries
- mod_ptr <- GHCi.newModuleName interp (moduleName mod)
+ (mod_ptr, mod_id_ptr) <- GHCi.newModule interp mod
let
locsTicks = listArray (0,count-1) [ tick_loc t | t <- entries ]
varsTicks = listArray (0,count-1) [ tick_ids t | t <- entries ]
@@ -46,6 +46,7 @@ mkModBreaks interp mod extendedMixEntries
, modBreaks_decls = declsTicks
, modBreaks_ccs = ccs
, modBreaks_module = mod_ptr
+ , modBreaks_module_unitid = mod_id_ptr
}
mkCCSArray
=====================================
compiler/GHC/Runtime/Eval.hs
=====================================
@@ -345,7 +345,7 @@ handleRunStatus step expr bindings final_ids status history0 = do
-- Just case: we stopped at a breakpoint
EvalBreak apStack_ref (Just eval_break) resume_ctxt ccs -> do
- ibi <- liftIO $ evalBreakpointToId (hsc_HPT hsc_env) eval_break
+ let ibi = evalBreakpointToId eval_break
tick_brks <- liftIO $ readModBreaks hsc_env (ibi_tick_mod ibi)
let
span = modBreaks_locs tick_brks ! ibi_tick_index ibi
=====================================
compiler/GHC/Runtime/Interpreter.hs
=====================================
@@ -21,7 +21,7 @@ module GHC.Runtime.Interpreter
, mkCostCentres
, costCentreStackInfo
, newBreakArray
- , newModuleName
+ , newModule
, storeBreakpoint
, breakpointStatus
, getBreakpointVar
@@ -93,9 +93,8 @@ import GHC.Utils.Outputable(brackets, ppr, showSDocUnsafe)
import GHC.Utils.Fingerprint
import GHC.Unit.Module
-import GHC.Unit.Module.ModIface
import GHC.Unit.Home.ModInfo
-import GHC.Unit.Home.PackageTable
+import GHC.Unit.Home.Graph (lookupHugByModule)
import GHC.Unit.Env
#if defined(HAVE_INTERNAL_INTERPRETER)
@@ -377,9 +376,13 @@ newBreakArray interp size = do
breakArray <- interpCmd interp (NewBreakArray size)
mkFinalizedHValue interp breakArray
-newModuleName :: Interp -> ModuleName -> IO (RemotePtr ModuleName)
-newModuleName interp mod_name =
- castRemotePtr <$> interpCmd interp (NewBreakModule (moduleNameString mod_name))
+newModule :: Interp -> Module -> IO (RemotePtr ModuleName, RemotePtr UnitId)
+newModule interp mod = do
+ let
+ mod_name = moduleNameString $ moduleName mod
+ mod_id = fastStringToShortByteString $ unitIdFS $ toUnitId $ moduleUnit mod
+ (mod_ptr, mod_id_ptr) <- interpCmd interp (NewBreakModule mod_name mod_id)
+ pure (castRemotePtr mod_ptr, castRemotePtr mod_id_ptr)
storeBreakpoint :: Interp -> ForeignRef BreakArray -> Int -> Int -> IO ()
storeBreakpoint interp ref ix cnt = do -- #19157
@@ -415,19 +418,21 @@ seqHValue interp unit_env ref =
status <- interpCmd interp (Seq hval)
handleSeqHValueStatus interp unit_env status
-evalBreakpointToId :: HomePackageTable -> EvalBreakpoint -> IO InternalBreakpointId
-evalBreakpointToId hpt eval_break =
- let load_mod x = mi_module . hm_iface . expectJust <$> lookupHpt hpt (mkModuleName x)
- in do
- tickl <- load_mod (eb_tick_mod eval_break)
- infol <- load_mod (eb_info_mod eval_break)
- return
- InternalBreakpointId
- { ibi_tick_mod = tickl
- , ibi_tick_index = eb_tick_index eval_break
- , ibi_info_mod = infol
- , ibi_info_index = eb_info_index eval_break
- }
+evalBreakpointToId :: EvalBreakpoint -> InternalBreakpointId
+evalBreakpointToId eval_break =
+ let
+ mkUnitId u = fsToUnit $ mkFastStringShortByteString u
+
+ toModule u n = mkModule (mkUnitId u) (mkModuleName n)
+ tickl = toModule (eb_tick_mod_unit eval_break) (eb_tick_mod eval_break)
+ infol = toModule (eb_info_mod_unit eval_break) (eb_info_mod eval_break)
+ in
+ InternalBreakpointId
+ { ibi_tick_mod = tickl
+ , ibi_tick_index = eb_tick_index eval_break
+ , ibi_info_mod = infol
+ , ibi_info_index = eb_info_index eval_break
+ }
-- | Process the result of a Seq or ResumeSeq message. #2950
handleSeqHValueStatus :: Interp -> UnitEnv -> EvalStatus () -> IO (EvalResult ())
@@ -447,12 +452,12 @@ handleSeqHValueStatus interp unit_env eval_status =
mkGeneralSrcSpan (fsLit "<unknown>")
Just break -> do
- bi <- evalBreakpointToId (ue_hpt unit_env) break
+ let bi = evalBreakpointToId break
-- Just case: Stopped at a breakpoint, extract SrcSpan information
-- from the breakpoint.
breaks_tick <- getModBreaks . expectJust <$>
- lookupHpt (ue_hpt unit_env) (moduleName (ibi_tick_mod bi))
+ lookupHugByModule (ibi_tick_mod bi) (ue_home_unit_graph unit_env)
put $ brackets . ppr $
(modBreaks_locs breaks_tick) ! ibi_tick_index bi
=====================================
compiler/GHC/StgToByteCode.hs
=====================================
@@ -416,7 +416,7 @@ schemeER_wrk d p (StgTick (Breakpoint tick_ty tick_no fvs tick_mod) rhs) = do
Nothing -> pure code
Just current_mod_breaks -> break_info hsc_env tick_mod current_mod mb_current_mod_breaks >>= \case
Nothing -> pure code
- Just ModBreaks {modBreaks_flags = breaks, modBreaks_module = tick_mod_ptr, modBreaks_ccs = cc_arr} -> do
+ Just ModBreaks {modBreaks_flags = breaks, modBreaks_module = tick_mod_ptr, modBreaks_module_unitid = tick_mod_id_ptr, modBreaks_ccs = cc_arr} -> do
platform <- profilePlatform <$> getProfile
let idOffSets = getVarOffSets platform d p fvs
ty_vars = tyCoVarsOfTypesWellScoped (tick_ty:map idType fvs)
@@ -425,6 +425,7 @@ schemeER_wrk d p (StgTick (Breakpoint tick_ty tick_no fvs tick_mod) rhs) = do
breakInfo = dehydrateCgBreakInfo ty_vars (map toWord idOffSets) tick_ty
let info_mod_ptr = modBreaks_module current_mod_breaks
+ info_mod_id_ptr = modBreaks_module_unitid current_mod_breaks
infox <- newBreakInfo breakInfo
let cc | Just interp <- hsc_interp hsc_env
@@ -437,7 +438,7 @@ schemeER_wrk d p (StgTick (Breakpoint tick_ty tick_no fvs tick_mod) rhs) = do
in if fromIntegral r == x
then r
else pprPanic "schemeER_wrk: breakpoint tick/info index too large!" (ppr x)
- breakInstr = BRK_FUN breaks tick_mod_ptr (toW16 tick_no) info_mod_ptr (toW16 infox) cc
+ breakInstr = BRK_FUN breaks tick_mod_ptr tick_mod_id_ptr (toW16 tick_no) info_mod_ptr info_mod_id_ptr (toW16 infox) cc
return $ breakInstr `consOL` code
schemeER_wrk d p rhs = schemeE d 0 p rhs
=====================================
libraries/ghci/GHCi/Message.hs
=====================================
@@ -23,6 +23,7 @@ module GHCi.Message
, getMessage, putMessage, getTHMessage, putTHMessage
, Pipe, mkPipeFromHandles, mkPipeFromContinuations, remoteCall, remoteTHCall, readPipe, writePipe
, BreakModule
+ , BreakUnitId
, LoadedDLL
) where
@@ -51,6 +52,7 @@ import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Builder as B
import qualified Data.ByteString.Lazy as LB
+import qualified Data.ByteString.Short as BS
import Data.Dynamic
import Data.Typeable (TypeRep)
import Data.IORef
@@ -245,8 +247,9 @@ data Message a where
-- | Allocate a string for a breakpoint module name.
-- This uses an empty dummy type because @ModuleName@ isn't available here.
NewBreakModule
- :: String
- -> Message (RemotePtr BreakModule)
+ :: String -- ^ @ModuleName@
+ -> BS.ShortByteString -- ^ @UnitId@ for the given @ModuleName@
+ -> Message (RemotePtr BreakModule, RemotePtr BreakUnitId)
deriving instance Show (Message a)
@@ -410,10 +413,12 @@ data EvalStatus_ a b
instance Binary a => Binary (EvalStatus_ a b)
data EvalBreakpoint = EvalBreakpoint
- { eb_tick_mod :: String -- ^ Breakpoint tick module
- , eb_tick_index :: Int -- ^ Breakpoint tick index
- , eb_info_mod :: String -- ^ Breakpoint info module
- , eb_info_index :: Int -- ^ Breakpoint info index
+ { eb_tick_mod :: String -- ^ Breakpoint tick module
+ , eb_tick_mod_unit :: BS.ShortByteString -- ^ Breakpoint tick module unit id
+ , eb_tick_index :: Int -- ^ Breakpoint tick index
+ , eb_info_mod :: String -- ^ Breakpoint info module
+ , eb_info_mod_unit :: BS.ShortByteString -- ^ Breakpoint tick module unit id
+ , eb_info_index :: Int -- ^ Breakpoint info index
}
deriving (Generic, Show)
@@ -430,6 +435,10 @@ instance Binary a => Binary (EvalResult a)
-- that type isn't available here.
data BreakModule
+-- | A dummy type that tags the pointer to a breakpoint's @UnitId@, because
+-- that type isn't available here.
+data BreakUnitId
+
-- | A dummy type that tags pointers returned by 'LoadDLL'.
data LoadedDLL
@@ -580,7 +589,7 @@ getMessage = do
36 -> Msg <$> (Seq <$> get)
37 -> Msg <$> return RtsRevertCAFs
38 -> Msg <$> (ResumeSeq <$> get)
- 39 -> Msg <$> (NewBreakModule <$> get)
+ 39 -> Msg <$> (NewBreakModule <$> get <*> get)
40 -> Msg <$> (LookupSymbolInDLL <$> get <*> get)
41 -> Msg <$> (WhereFrom <$> get)
_ -> error $ "Unknown Message code " ++ (show b)
@@ -627,7 +636,7 @@ putMessage m = case m of
Seq a -> putWord8 36 >> put a
RtsRevertCAFs -> putWord8 37
ResumeSeq a -> putWord8 38 >> put a
- NewBreakModule name -> putWord8 39 >> put name
+ NewBreakModule name unitid -> putWord8 39 >> put name >> put unitid
LookupSymbolInDLL dll str -> putWord8 40 >> put dll >> put str
WhereFrom a -> putWord8 41 >> put a
=====================================
libraries/ghci/GHCi/Run.hs
=====================================
@@ -33,6 +33,7 @@ import Control.DeepSeq
import Control.Exception
import Control.Monad
import Data.ByteString (ByteString)
+import qualified Data.ByteString.Short as BS
import qualified Data.ByteString.Unsafe as B
import GHC.Exts
import qualified GHC.Exts.Heap as Heap
@@ -95,7 +96,10 @@ run m = case m of
MkCostCentres mod ccs -> mkCostCentres mod ccs
CostCentreStackInfo ptr -> ccsToStrings (fromRemotePtr ptr)
NewBreakArray sz -> mkRemoteRef =<< newBreakArray sz
- NewBreakModule name -> newModuleName name
+ NewBreakModule name unitid -> do
+ namePtr <- newModuleName name
+ uidPtr <- newUnitId unitid
+ pure (namePtr, uidPtr)
SetupBreakpoint ref ix cnt -> do
arr <- localRef ref;
_ <- setupBreakpoint arr ix cnt
@@ -335,7 +339,7 @@ withBreakAction opts breakMVar statusMVar act
-- as soon as it is hit, or in resetBreakAction below.
onBreak :: BreakpointCallback
- onBreak tick_mod# tickx# info_mod# infox# is_exception apStack = do
+ onBreak tick_mod# tick_mod_uid# tickx# info_mod# info_mod_uid# infox# is_exception apStack = do
tid <- myThreadId
let resume = ResumeContext
{ resumeBreakMVar = breakMVar
@@ -349,8 +353,10 @@ withBreakAction opts breakMVar statusMVar act
then pure Nothing
else do
tick_mod <- peekCString (Ptr tick_mod#)
+ tick_mod_uid <- BS.packCString (Ptr tick_mod_uid#)
info_mod <- peekCString (Ptr info_mod#)
- pure (Just (EvalBreakpoint tick_mod (I# tickx#) info_mod (I# infox#)))
+ info_mod_uid <- BS.packCString (Ptr info_mod_uid#)
+ pure (Just (EvalBreakpoint tick_mod tick_mod_uid (I# tickx#) info_mod info_mod_uid (I# infox#)))
putMVar statusMVar $ EvalBreak apStack_r breakpoint resume_r ccs
takeMVar breakMVar
@@ -400,8 +406,10 @@ resetStepFlag = poke stepFlag 0
type BreakpointCallback
= Addr# -- pointer to the breakpoint tick module name
+ -> Addr# -- pointer to the breakpoint tick module unit id
-> Int# -- breakpoint tick index
-> Addr# -- pointer to the breakpoint info module name
+ -> Addr# -- pointer to the breakpoint info module unit id
-> Int# -- breakpoint info index
-> Bool -- exception?
-> HValue -- the AP_STACK, or exception
@@ -414,8 +422,8 @@ noBreakStablePtr :: StablePtr BreakpointCallback
noBreakStablePtr = unsafePerformIO $ newStablePtr noBreakAction
noBreakAction :: BreakpointCallback
-noBreakAction _ _ _ _ False _ = putStrLn "*** Ignoring breakpoint"
-noBreakAction _ _ _ _ True _ = return () -- exception: just continue
+noBreakAction _ _ _ _ _ _ False _ = putStrLn "*** Ignoring breakpoint"
+noBreakAction _ _ _ _ _ _ True _ = return () -- exception: just continue
-- Malloc and copy the bytes. We don't have any way to monitor the
-- lifetime of this memory, so it just leaks.
@@ -432,6 +440,13 @@ mkString0 bs = B.unsafeUseAsCStringLen bs $ \(cstr,len) -> do
pokeElemOff (ptr :: Ptr CChar) len 0
return (castRemotePtr (toRemotePtr ptr))
+mkShortByteString0 :: BS.ShortByteString -> IO (RemotePtr ())
+mkShortByteString0 bs = BS.useAsCStringLen bs $ \(cstr,len) -> do
+ ptr <- mallocBytes (len+1)
+ copyBytes ptr cstr len
+ pokeElemOff (ptr :: Ptr CChar) len 0
+ return (castRemotePtr (toRemotePtr ptr))
+
mkCostCentres :: String -> [(String,String)] -> IO [RemotePtr CostCentre]
#if defined(PROFILING)
mkCostCentres mod ccs = do
@@ -453,6 +468,10 @@ newModuleName :: String -> IO (RemotePtr BreakModule)
newModuleName name =
castRemotePtr . toRemotePtr <$> newCString name
+newUnitId :: BS.ShortByteString -> IO (RemotePtr BreakUnitId)
+newUnitId name =
+ castRemotePtr <$> mkShortByteString0 name
+
getIdValFromApStack :: HValue -> Int -> IO (Maybe HValue)
getIdValFromApStack apStack (I# stackDepth) = do
case getApStackVal# apStack stackDepth of
=====================================
rts/Exception.cmm
=====================================
@@ -535,12 +535,16 @@ retry_pop_stack:
// be per-thread.
CInt[rts_stop_on_exception] = 0;
("ptr" ioAction) = ccall deRefStablePtr (W_[rts_breakpoint_io_action] "ptr");
- Sp = Sp - WDS(13);
- Sp(12) = exception;
- Sp(11) = stg_raise_ret_info;
- Sp(10) = exception;
- Sp(9) = ghczminternal_GHCziInternalziTypes_True_closure; // True <=> an exception
- Sp(8) = stg_ap_ppv_info;
+ Sp = Sp - WDS(17);
+ Sp(16) = exception;
+ Sp(15) = stg_raise_ret_info;
+ Sp(14) = exception;
+ Sp(13) = ghczminternal_GHCziInternalziTypes_True_closure; // True <=> an exception
+ Sp(12) = stg_ap_ppv_info;
+ Sp(11) = 0;
+ Sp(10) = stg_ap_n_info;
+ Sp(9) = 0;
+ Sp(8) = stg_ap_n_info;
Sp(7) = 0;
Sp(6) = stg_ap_n_info;
Sp(5) = 0;
=====================================
rts/Interpreter.c
=====================================
@@ -1245,9 +1245,9 @@ run_BCO:
/* check for a breakpoint on the beginning of a let binding */
case bci_BRK_FUN:
{
- int arg1_brk_array, arg2_tick_mod, arg3_info_mod, arg4_tick_index, arg5_info_index;
+ int arg1_brk_array, arg2_tick_mod, arg3_info_mod, arg4_tick_mod_id, arg5_info_mod_id, arg6_tick_index, arg7_info_index;
#if defined(PROFILING)
- int arg6_cc;
+ int arg8_cc;
#endif
StgArrBytes *breakPoints;
int returning_from_break;
@@ -1264,10 +1264,12 @@ run_BCO:
arg1_brk_array = BCO_GET_LARGE_ARG;
arg2_tick_mod = BCO_GET_LARGE_ARG;
arg3_info_mod = BCO_GET_LARGE_ARG;
- arg4_tick_index = BCO_NEXT;
- arg5_info_index = BCO_NEXT;
+ arg4_tick_mod_id = BCO_GET_LARGE_ARG;
+ arg5_info_mod_id = BCO_GET_LARGE_ARG;
+ arg6_tick_index = BCO_NEXT;
+ arg7_info_index = BCO_NEXT;
#if defined(PROFILING)
- arg6_cc = BCO_GET_LARGE_ARG;
+ arg8_cc = BCO_GET_LARGE_ARG;
#else
BCO_GET_LARGE_ARG;
#endif
@@ -1280,7 +1282,7 @@ run_BCO:
#if defined(PROFILING)
cap->r.rCCCS = pushCostCentre(cap->r.rCCCS,
- (CostCentre*)BCO_LIT(arg6_cc));
+ (CostCentre*)BCO_LIT(arg8_cc));
#endif
// if we are returning from a break then skip this section
@@ -1292,11 +1294,11 @@ run_BCO:
// stop the current thread if either the
// "rts_stop_next_breakpoint" flag is true OR if the
// ignore count for this particular breakpoint is zero
- StgInt ignore_count = ((StgInt*)breakPoints->payload)[arg4_tick_index];
+ StgInt ignore_count = ((StgInt*)breakPoints->payload)[arg6_tick_index];
if (rts_stop_next_breakpoint == false && ignore_count > 0)
{
// decrement and write back ignore count
- ((StgInt*)breakPoints->payload)[arg4_tick_index] = --ignore_count;
+ ((StgInt*)breakPoints->payload)[arg6_tick_index] = --ignore_count;
}
else if (rts_stop_next_breakpoint == true || ignore_count == 0)
{
@@ -1330,8 +1332,10 @@ run_BCO:
// continue execution of this BCO when the IO action returns.
//
// ioAction :: Addr# -- the breakpoint tick module
+ // -> Addr# -- the breakpoint tick module unit id
// -> Int# -- the breakpoint tick index
// -> Addr# -- the breakpoint info module
+ // -> Addr# -- the breakpoint info module unit id
// -> Int# -- the breakpoint info index
// -> Bool -- exception?
// -> HValue -- the AP_STACK, or exception
@@ -1340,17 +1344,21 @@ run_BCO:
ioAction = (StgClosure *) deRefStablePtr (
rts_breakpoint_io_action);
- Sp_subW(15);
- SpW(14) = (W_)obj;
- SpW(13) = (W_)&stg_apply_interp_info;
- SpW(12) = (W_)new_aps;
- SpW(11) = (W_)False_closure; // True <=> an exception
- SpW(10) = (W_)&stg_ap_ppv_info;
- SpW(9) = (W_)arg5_info_index;
+ Sp_subW(19);
+ SpW(18) = (W_)obj;
+ SpW(17) = (W_)&stg_apply_interp_info;
+ SpW(16) = (W_)new_aps;
+ SpW(15) = (W_)False_closure; // True <=> an exception
+ SpW(14) = (W_)&stg_ap_ppv_info;
+ SpW(13) = (W_)arg7_info_index;
+ SpW(12) = (W_)&stg_ap_n_info;
+ SpW(11) = (W_)BCO_LIT(arg5_info_mod_id);
+ SpW(10) = (W_)&stg_ap_n_info;
+ SpW(9) = (W_)BCO_LIT(arg3_info_mod);
SpW(8) = (W_)&stg_ap_n_info;
- SpW(7) = (W_)BCO_LIT(arg3_info_mod);
+ SpW(7) = (W_)arg6_tick_index;
SpW(6) = (W_)&stg_ap_n_info;
- SpW(5) = (W_)arg4_tick_index;
+ SpW(5) = (W_)BCO_LIT(arg4_tick_mod_id);
SpW(4) = (W_)&stg_ap_n_info;
SpW(3) = (W_)BCO_LIT(arg2_tick_mod);
SpW(2) = (W_)&stg_ap_n_info;
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/7aa8d812ce8dc1c822f30878088a22d…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/7aa8d812ce8dc1c822f30878088a22d…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/fendor/ghci-debugger-unitid] Add `UnitId` to `EvalBreakpoint`
by Hannes Siebenhandl (@fendor) 23 Apr '25
by Hannes Siebenhandl (@fendor) 23 Apr '25
23 Apr '25
Hannes Siebenhandl pushed to branch wip/fendor/ghci-debugger-unitid at Glasgow Haskell Compiler / GHC
Commits:
9a1f0313 by fendor at 2025-04-23T15:51:33+02:00
Add `UnitId` to `EvalBreakpoint`
The `EvalBreakpoint` is used to communicate that a breakpoint was
encountered during code evaluation.
This `EvalBreakpoint` needs to be converted to an `InternalBreakpointId`
which stores a `Module` to uniquely find the correct `Module` in the
Home Package Table.
The `EvalBreakpoint` used to store only a `ModuleName` which is then
converted to a `Module` based on the currently active home unit.
This is incorrect in the face of multiple home units, the break point
could be in an entirely other home unit!
To fix this, we additionally store the `UnitId` of the `Module` in
`EvalBreakpoint` to later reconstruct the correct `Module`
All of the changes are the consequence of extending `EvalBreakpoint`
with the additional `ShortByteString` of the `UnitId`.
For performance reasons, we store the `ShortByteString` backing the
`UnitId` directly, avoiding marshalling overhead.
- - - - -
11 changed files:
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/StgToByteCode.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/Run.hs
- rts/Exception.cmm
- rts/Interpreter.c
Changes:
=====================================
compiler/GHC/ByteCode/Asm.hs
=====================================
@@ -732,13 +732,16 @@ assembleI platform i = case i of
CCALL off m_addr i -> do np <- addr m_addr
emit_ bci_CCALL [wOp off, Op np, SmallOp i]
PRIMCALL -> emit_ bci_PRIMCALL []
- BRK_FUN arr tick_mod tickx info_mod infox cc ->
+ BRK_FUN arr tick_mod tick_mod_id tickx info_mod info_mod_id infox cc ->
do p1 <- ptr (BCOPtrBreakArray arr)
tick_addr <- addr tick_mod
+ tick_unitid_addr <- addr tick_mod_id
info_addr <- addr info_mod
+ info_unitid_addr <- addr info_mod_id
np <- addr cc
emit_ bci_BRK_FUN [ Op p1
, Op tick_addr, Op info_addr
+ , Op tick_unitid_addr, Op info_unitid_addr
, SmallOp tickx, SmallOp infox
, Op np
]
=====================================
compiler/GHC/ByteCode/Instr.hs
=====================================
@@ -37,6 +37,7 @@ import GHC.Stg.Syntax
import GHCi.BreakArray (BreakArray)
import Language.Haskell.Syntax.Module.Name (ModuleName)
import GHC.Types.Unique
+import GHC.Unit.Types (UnitId)
-- ----------------------------------------------------------------------------
-- Bytecode instructions
@@ -233,8 +234,10 @@ data BCInstr
-- Breakpoints
| BRK_FUN (ForeignRef BreakArray)
(RemotePtr ModuleName) -- breakpoint tick module
+ (RemotePtr UnitId) -- breakpoint tick module unit id
!Word16 -- breakpoint tick index
(RemotePtr ModuleName) -- breakpoint info module
+ (RemotePtr UnitId) -- breakpoint info module unit id
!Word16 -- breakpoint info index
(RemotePtr CostCentre)
@@ -403,10 +406,10 @@ instance Outputable BCInstr where
ppr ENTER = text "ENTER"
ppr (RETURN pk) = text "RETURN " <+> ppr pk
ppr (RETURN_TUPLE) = text "RETURN_TUPLE"
- ppr (BRK_FUN _ _tick_mod tickx _info_mod infox _)
+ ppr (BRK_FUN _ _tick_mod _tick_mod_id tickx _info_mod _info_mod_id infox _)
= text "BRK_FUN" <+> text "<breakarray>"
- <+> text "<tick_module>" <+> ppr tickx
- <+> text "<info_module>" <+> ppr infox
+ <+> text "<tick_module>" <+> text "<tick_module_unitid>" <+> ppr tickx
+ <+> text "<info_module>" <+> text "<info_module_unitid>" <+> ppr infox
<+> text "<cc>"
#if MIN_VERSION_rts(1,0,3)
ppr (BCO_NAME nm) = text "BCO_NAME" <+> text (show nm)
=====================================
compiler/GHC/ByteCode/Types.hs
=====================================
@@ -50,6 +50,7 @@ import GHC.Stack.CCS
import GHC.Cmm.Expr ( GlobalRegSet, emptyRegSet, regSetToList )
import GHC.Iface.Syntax
import Language.Haskell.Syntax.Module.Name (ModuleName)
+import GHC.Unit.Types (UnitId)
-- -----------------------------------------------------------------------------
-- Compiled Byte Code
@@ -263,6 +264,9 @@ data ModBreaks
, modBreaks_breakInfo :: IntMap CgBreakInfo
-- ^ info about each breakpoint from the bytecode generator
, modBreaks_module :: RemotePtr ModuleName
+ -- ^ info about the module in which we are setting the breakpoint
+ , modBreaks_module_unitid :: RemotePtr UnitId
+ -- ^ The 'UnitId' of the 'ModuleName'
}
seqModBreaks :: ModBreaks -> ()
@@ -273,7 +277,8 @@ seqModBreaks ModBreaks{..} =
rnf modBreaks_decls `seq`
rnf modBreaks_ccs `seq`
rnf (fmap seqCgBreakInfo modBreaks_breakInfo) `seq`
- rnf modBreaks_module
+ rnf modBreaks_module `seq`
+ rnf modBreaks_module_unitid
-- | Construct an empty ModBreaks
emptyModBreaks :: ModBreaks
@@ -286,6 +291,7 @@ emptyModBreaks = ModBreaks
, modBreaks_ccs = array (0,-1) []
, modBreaks_breakInfo = IntMap.empty
, modBreaks_module = toRemotePtr nullPtr
+ , modBreaks_module_unitid = toRemotePtr nullPtr
}
{-
=====================================
compiler/GHC/HsToCore/Breakpoints.hs
=====================================
@@ -34,7 +34,7 @@ mkModBreaks interp mod extendedMixEntries
breakArray <- GHCi.newBreakArray interp count
ccs <- mkCCSArray interp mod count entries
- mod_ptr <- GHCi.newModuleName interp (moduleName mod)
+ (mod_ptr, mod_id_ptr) <- GHCi.newModule interp mod
let
locsTicks = listArray (0,count-1) [ tick_loc t | t <- entries ]
varsTicks = listArray (0,count-1) [ tick_ids t | t <- entries ]
@@ -46,6 +46,7 @@ mkModBreaks interp mod extendedMixEntries
, modBreaks_decls = declsTicks
, modBreaks_ccs = ccs
, modBreaks_module = mod_ptr
+ , modBreaks_module_unitid = mod_id_ptr
}
mkCCSArray
=====================================
compiler/GHC/Runtime/Eval.hs
=====================================
@@ -345,7 +345,7 @@ handleRunStatus step expr bindings final_ids status history0 = do
-- Just case: we stopped at a breakpoint
EvalBreak apStack_ref (Just eval_break) resume_ctxt ccs -> do
- ibi <- liftIO $ evalBreakpointToId (hsc_HPT hsc_env) eval_break
+ let ibi = evalBreakpointToId eval_break
tick_brks <- liftIO $ readModBreaks hsc_env (ibi_tick_mod ibi)
let
span = modBreaks_locs tick_brks ! ibi_tick_index ibi
=====================================
compiler/GHC/Runtime/Interpreter.hs
=====================================
@@ -21,7 +21,7 @@ module GHC.Runtime.Interpreter
, mkCostCentres
, costCentreStackInfo
, newBreakArray
- , newModuleName
+ , newModule
, storeBreakpoint
, breakpointStatus
, getBreakpointVar
@@ -93,9 +93,8 @@ import GHC.Utils.Outputable(brackets, ppr, showSDocUnsafe)
import GHC.Utils.Fingerprint
import GHC.Unit.Module
-import GHC.Unit.Module.ModIface
import GHC.Unit.Home.ModInfo
-import GHC.Unit.Home.PackageTable
+import GHC.Unit.Home.Graph (lookupHugByModule)
import GHC.Unit.Env
#if defined(HAVE_INTERNAL_INTERPRETER)
@@ -377,9 +376,13 @@ newBreakArray interp size = do
breakArray <- interpCmd interp (NewBreakArray size)
mkFinalizedHValue interp breakArray
-newModuleName :: Interp -> ModuleName -> IO (RemotePtr ModuleName)
-newModuleName interp mod_name =
- castRemotePtr <$> interpCmd interp (NewBreakModule (moduleNameString mod_name))
+newModule :: Interp -> Module -> IO (RemotePtr ModuleName, RemotePtr UnitId)
+newModule interp mod = do
+ let
+ mod_name = moduleNameString $ moduleName mod
+ mod_id = fastStringToShortByteString $ unitIdFS $ toUnitId $ moduleUnit mod
+ (mod_ptr, mod_id_ptr) <- interpCmd interp (NewBreakModule mod_name mod_id)
+ pure (castRemotePtr mod_ptr, castRemotePtr mod_id_ptr)
storeBreakpoint :: Interp -> ForeignRef BreakArray -> Int -> Int -> IO ()
storeBreakpoint interp ref ix cnt = do -- #19157
@@ -415,19 +418,21 @@ seqHValue interp unit_env ref =
status <- interpCmd interp (Seq hval)
handleSeqHValueStatus interp unit_env status
-evalBreakpointToId :: HomePackageTable -> EvalBreakpoint -> IO InternalBreakpointId
-evalBreakpointToId hpt eval_break =
- let load_mod x = mi_module . hm_iface . expectJust <$> lookupHpt hpt (mkModuleName x)
- in do
- tickl <- load_mod (eb_tick_mod eval_break)
- infol <- load_mod (eb_info_mod eval_break)
- return
- InternalBreakpointId
- { ibi_tick_mod = tickl
- , ibi_tick_index = eb_tick_index eval_break
- , ibi_info_mod = infol
- , ibi_info_index = eb_info_index eval_break
- }
+evalBreakpointToId :: EvalBreakpoint -> InternalBreakpointId
+evalBreakpointToId eval_break =
+ let
+ mkUnitId u = fsToUnit $ mkFastStringShortByteString u
+
+ toModule u n = mkModule (mkUnitId u) (mkModuleName n)
+ tickl = toModule (eb_tick_mod_unit eval_break) (eb_tick_mod eval_break)
+ infol = toModule (eb_info_mod_unit eval_break) (eb_info_mod eval_break)
+ in
+ InternalBreakpointId
+ { ibi_tick_mod = tickl
+ , ibi_tick_index = eb_tick_index eval_break
+ , ibi_info_mod = infol
+ , ibi_info_index = eb_info_index eval_break
+ }
-- | Process the result of a Seq or ResumeSeq message. #2950
handleSeqHValueStatus :: Interp -> UnitEnv -> EvalStatus () -> IO (EvalResult ())
@@ -447,12 +452,12 @@ handleSeqHValueStatus interp unit_env eval_status =
mkGeneralSrcSpan (fsLit "<unknown>")
Just break -> do
- bi <- evalBreakpointToId (ue_hpt unit_env) break
+ let bi = evalBreakpointToId break
-- Just case: Stopped at a breakpoint, extract SrcSpan information
-- from the breakpoint.
breaks_tick <- getModBreaks . expectJust <$>
- lookupHpt (ue_hpt unit_env) (moduleName (ibi_tick_mod bi))
+ lookupHugByModule (ibi_tick_mod bi) (ue_home_unit_graph unit_env)
put $ brackets . ppr $
(modBreaks_locs breaks_tick) ! ibi_tick_index bi
=====================================
compiler/GHC/StgToByteCode.hs
=====================================
@@ -416,7 +416,7 @@ schemeER_wrk d p (StgTick (Breakpoint tick_ty tick_no fvs tick_mod) rhs) = do
Nothing -> pure code
Just current_mod_breaks -> break_info hsc_env tick_mod current_mod mb_current_mod_breaks >>= \case
Nothing -> pure code
- Just ModBreaks {modBreaks_flags = breaks, modBreaks_module = tick_mod_ptr, modBreaks_ccs = cc_arr} -> do
+ Just ModBreaks {modBreaks_flags = breaks, modBreaks_module = tick_mod_ptr, modBreaks_module_unitid = tick_mod_id_ptr, modBreaks_ccs = cc_arr} -> do
platform <- profilePlatform <$> getProfile
let idOffSets = getVarOffSets platform d p fvs
ty_vars = tyCoVarsOfTypesWellScoped (tick_ty:map idType fvs)
@@ -425,6 +425,7 @@ schemeER_wrk d p (StgTick (Breakpoint tick_ty tick_no fvs tick_mod) rhs) = do
breakInfo = dehydrateCgBreakInfo ty_vars (map toWord idOffSets) tick_ty
let info_mod_ptr = modBreaks_module current_mod_breaks
+ info_mod_id_ptr = modBreaks_module_unitid current_mod_breaks
infox <- newBreakInfo breakInfo
let cc | Just interp <- hsc_interp hsc_env
@@ -437,7 +438,7 @@ schemeER_wrk d p (StgTick (Breakpoint tick_ty tick_no fvs tick_mod) rhs) = do
in if fromIntegral r == x
then r
else pprPanic "schemeER_wrk: breakpoint tick/info index too large!" (ppr x)
- breakInstr = BRK_FUN breaks tick_mod_ptr (toW16 tick_no) info_mod_ptr (toW16 infox) cc
+ breakInstr = BRK_FUN breaks tick_mod_ptr tick_mod_id_ptr (toW16 tick_no) info_mod_ptr info_mod_id_ptr (toW16 infox) cc
return $ breakInstr `consOL` code
schemeER_wrk d p rhs = schemeE d 0 p rhs
=====================================
libraries/ghci/GHCi/Message.hs
=====================================
@@ -23,6 +23,7 @@ module GHCi.Message
, getMessage, putMessage, getTHMessage, putTHMessage
, Pipe, mkPipeFromHandles, mkPipeFromContinuations, remoteCall, remoteTHCall, readPipe, writePipe
, BreakModule
+ , BreakUnitId
, LoadedDLL
) where
@@ -51,6 +52,7 @@ import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Builder as B
import qualified Data.ByteString.Lazy as LB
+import qualified Data.ByteString.Short as BS
import Data.Dynamic
import Data.Typeable (TypeRep)
import Data.IORef
@@ -245,8 +247,9 @@ data Message a where
-- | Allocate a string for a breakpoint module name.
-- This uses an empty dummy type because @ModuleName@ isn't available here.
NewBreakModule
- :: String
- -> Message (RemotePtr BreakModule)
+ :: String -- ^ @ModuleName@
+ -> BS.ShortByteString -- ^ @UnitId@ for the given @ModuleName@
+ -> Message (RemotePtr BreakModule, RemotePtr BreakUnitId)
deriving instance Show (Message a)
@@ -410,10 +413,12 @@ data EvalStatus_ a b
instance Binary a => Binary (EvalStatus_ a b)
data EvalBreakpoint = EvalBreakpoint
- { eb_tick_mod :: String -- ^ Breakpoint tick module
- , eb_tick_index :: Int -- ^ Breakpoint tick index
- , eb_info_mod :: String -- ^ Breakpoint info module
- , eb_info_index :: Int -- ^ Breakpoint info index
+ { eb_tick_mod :: String -- ^ Breakpoint tick module
+ , eb_tick_mod_unit :: BS.ShortByteString -- ^ Breakpoint tick module unit id
+ , eb_tick_index :: Int -- ^ Breakpoint tick index
+ , eb_info_mod :: String -- ^ Breakpoint info module
+ , eb_info_mod_unit :: BS.ShortByteString -- ^ Breakpoint tick module unit id
+ , eb_info_index :: Int -- ^ Breakpoint info index
}
deriving (Generic, Show)
@@ -430,6 +435,10 @@ instance Binary a => Binary (EvalResult a)
-- that type isn't available here.
data BreakModule
+-- | A dummy type that tags the pointer to a breakpoint's @UnitId@, because
+-- that type isn't available here.
+data BreakUnitId
+
-- | A dummy type that tags pointers returned by 'LoadDLL'.
data LoadedDLL
@@ -580,7 +589,7 @@ getMessage = do
36 -> Msg <$> (Seq <$> get)
37 -> Msg <$> return RtsRevertCAFs
38 -> Msg <$> (ResumeSeq <$> get)
- 39 -> Msg <$> (NewBreakModule <$> get)
+ 39 -> Msg <$> (NewBreakModule <$> get <*> get)
40 -> Msg <$> (LookupSymbolInDLL <$> get <*> get)
41 -> Msg <$> (WhereFrom <$> get)
_ -> error $ "Unknown Message code " ++ (show b)
@@ -627,7 +636,7 @@ putMessage m = case m of
Seq a -> putWord8 36 >> put a
RtsRevertCAFs -> putWord8 37
ResumeSeq a -> putWord8 38 >> put a
- NewBreakModule name -> putWord8 39 >> put name
+ NewBreakModule name unitid -> putWord8 39 >> put name >> put unitid
LookupSymbolInDLL dll str -> putWord8 40 >> put dll >> put str
WhereFrom a -> putWord8 41 >> put a
=====================================
libraries/ghci/GHCi/Run.hs
=====================================
@@ -43,6 +43,7 @@ import GHC.Conc.Sync
import GHC.IO hiding ( bracket )
import System.Mem.Weak ( deRefWeak )
import Unsafe.Coerce
+import qualified Data.ByteString.Short as BS
-- -----------------------------------------------------------------------------
-- Implement messages
@@ -95,7 +96,10 @@ run m = case m of
MkCostCentres mod ccs -> mkCostCentres mod ccs
CostCentreStackInfo ptr -> ccsToStrings (fromRemotePtr ptr)
NewBreakArray sz -> mkRemoteRef =<< newBreakArray sz
- NewBreakModule name -> newModuleName name
+ NewBreakModule name unitid -> do
+ namePtr <- newModuleName name
+ uidPtr <- newUnitId unitid
+ pure (namePtr, uidPtr)
SetupBreakpoint ref ix cnt -> do
arr <- localRef ref;
_ <- setupBreakpoint arr ix cnt
@@ -335,7 +339,7 @@ withBreakAction opts breakMVar statusMVar act
-- as soon as it is hit, or in resetBreakAction below.
onBreak :: BreakpointCallback
- onBreak tick_mod# tickx# info_mod# infox# is_exception apStack = do
+ onBreak tick_mod# tick_mod_uid# tickx# info_mod# info_mod_uid# infox# is_exception apStack = do
tid <- myThreadId
let resume = ResumeContext
{ resumeBreakMVar = breakMVar
@@ -349,8 +353,10 @@ withBreakAction opts breakMVar statusMVar act
then pure Nothing
else do
tick_mod <- peekCString (Ptr tick_mod#)
+ tick_mod_uid <- BS.packCString (Ptr tick_mod_uid#)
info_mod <- peekCString (Ptr info_mod#)
- pure (Just (EvalBreakpoint tick_mod (I# tickx#) info_mod (I# infox#)))
+ info_mod_uid <- BS.packCString (Ptr info_mod_uid#)
+ pure (Just (EvalBreakpoint tick_mod tick_mod_uid (I# tickx#) info_mod info_mod_uid (I# infox#)))
putMVar statusMVar $ EvalBreak apStack_r breakpoint resume_r ccs
takeMVar breakMVar
@@ -400,8 +406,10 @@ resetStepFlag = poke stepFlag 0
type BreakpointCallback
= Addr# -- pointer to the breakpoint tick module name
+ -> Addr# -- pointer to the breakpoint tick module unit id
-> Int# -- breakpoint tick index
-> Addr# -- pointer to the breakpoint info module name
+ -> Addr# -- pointer to the breakpoint info module unit id
-> Int# -- breakpoint info index
-> Bool -- exception?
-> HValue -- the AP_STACK, or exception
@@ -414,8 +422,8 @@ noBreakStablePtr :: StablePtr BreakpointCallback
noBreakStablePtr = unsafePerformIO $ newStablePtr noBreakAction
noBreakAction :: BreakpointCallback
-noBreakAction _ _ _ _ False _ = putStrLn "*** Ignoring breakpoint"
-noBreakAction _ _ _ _ True _ = return () -- exception: just continue
+noBreakAction _ _ _ _ _ _ False _ = putStrLn "*** Ignoring breakpoint"
+noBreakAction _ _ _ _ _ _ True _ = return () -- exception: just continue
-- Malloc and copy the bytes. We don't have any way to monitor the
-- lifetime of this memory, so it just leaks.
@@ -432,6 +440,13 @@ mkString0 bs = B.unsafeUseAsCStringLen bs $ \(cstr,len) -> do
pokeElemOff (ptr :: Ptr CChar) len 0
return (castRemotePtr (toRemotePtr ptr))
+mkShortByteString0 :: BS.ShortByteString -> IO (RemotePtr ())
+mkShortByteString0 bs = BS.useAsCStringLen bs $ \(cstr,len) -> do
+ ptr <- mallocBytes (len+1)
+ copyBytes ptr cstr len
+ pokeElemOff (ptr :: Ptr CChar) len 0
+ return (castRemotePtr (toRemotePtr ptr))
+
mkCostCentres :: String -> [(String,String)] -> IO [RemotePtr CostCentre]
#if defined(PROFILING)
mkCostCentres mod ccs = do
@@ -453,6 +468,10 @@ newModuleName :: String -> IO (RemotePtr BreakModule)
newModuleName name =
castRemotePtr . toRemotePtr <$> newCString name
+newUnitId :: BS.ShortByteString -> IO (RemotePtr BreakUnitId)
+newUnitId name =
+ castRemotePtr <$> mkShortByteString0 name
+
getIdValFromApStack :: HValue -> Int -> IO (Maybe HValue)
getIdValFromApStack apStack (I# stackDepth) = do
case getApStackVal# apStack stackDepth of
=====================================
rts/Exception.cmm
=====================================
@@ -535,12 +535,16 @@ retry_pop_stack:
// be per-thread.
CInt[rts_stop_on_exception] = 0;
("ptr" ioAction) = ccall deRefStablePtr (W_[rts_breakpoint_io_action] "ptr");
- Sp = Sp - WDS(13);
- Sp(12) = exception;
- Sp(11) = stg_raise_ret_info;
- Sp(10) = exception;
- Sp(9) = ghczminternal_GHCziInternalziTypes_True_closure; // True <=> an exception
- Sp(8) = stg_ap_ppv_info;
+ Sp = Sp - WDS(17);
+ Sp(16) = exception;
+ Sp(15) = stg_raise_ret_info;
+ Sp(14) = exception;
+ Sp(13) = ghczminternal_GHCziInternalziTypes_True_closure; // True <=> an exception
+ Sp(12) = stg_ap_ppv_info;
+ Sp(11) = 0;
+ Sp(10) = stg_ap_n_info;
+ Sp(9) = 0;
+ Sp(8) = stg_ap_n_info;
Sp(7) = 0;
Sp(6) = stg_ap_n_info;
Sp(5) = 0;
=====================================
rts/Interpreter.c
=====================================
@@ -1245,9 +1245,9 @@ run_BCO:
/* check for a breakpoint on the beginning of a let binding */
case bci_BRK_FUN:
{
- int arg1_brk_array, arg2_tick_mod, arg3_info_mod, arg4_tick_index, arg5_info_index;
+ int arg1_brk_array, arg2_tick_mod, arg3_info_mod, arg4_tick_mod_id, arg5_info_mod_id, arg6_tick_index, arg7_info_index;
#if defined(PROFILING)
- int arg6_cc;
+ int arg8_cc;
#endif
StgArrBytes *breakPoints;
int returning_from_break;
@@ -1264,10 +1264,12 @@ run_BCO:
arg1_brk_array = BCO_GET_LARGE_ARG;
arg2_tick_mod = BCO_GET_LARGE_ARG;
arg3_info_mod = BCO_GET_LARGE_ARG;
- arg4_tick_index = BCO_NEXT;
- arg5_info_index = BCO_NEXT;
+ arg4_tick_mod_id = BCO_GET_LARGE_ARG;
+ arg5_info_mod_id = BCO_GET_LARGE_ARG;
+ arg6_tick_index = BCO_NEXT;
+ arg7_info_index = BCO_NEXT;
#if defined(PROFILING)
- arg6_cc = BCO_GET_LARGE_ARG;
+ arg8_cc = BCO_GET_LARGE_ARG;
#else
BCO_GET_LARGE_ARG;
#endif
@@ -1280,7 +1282,7 @@ run_BCO:
#if defined(PROFILING)
cap->r.rCCCS = pushCostCentre(cap->r.rCCCS,
- (CostCentre*)BCO_LIT(arg6_cc));
+ (CostCentre*)BCO_LIT(arg8_cc));
#endif
// if we are returning from a break then skip this section
@@ -1292,11 +1294,11 @@ run_BCO:
// stop the current thread if either the
// "rts_stop_next_breakpoint" flag is true OR if the
// ignore count for this particular breakpoint is zero
- StgInt ignore_count = ((StgInt*)breakPoints->payload)[arg4_tick_index];
+ StgInt ignore_count = ((StgInt*)breakPoints->payload)[arg6_tick_index];
if (rts_stop_next_breakpoint == false && ignore_count > 0)
{
// decrement and write back ignore count
- ((StgInt*)breakPoints->payload)[arg4_tick_index] = --ignore_count;
+ ((StgInt*)breakPoints->payload)[arg6_tick_index] = --ignore_count;
}
else if (rts_stop_next_breakpoint == true || ignore_count == 0)
{
@@ -1330,8 +1332,10 @@ run_BCO:
// continue execution of this BCO when the IO action returns.
//
// ioAction :: Addr# -- the breakpoint tick module
+ // -> Addr# -- the breakpoint tick module unit id
// -> Int# -- the breakpoint tick index
// -> Addr# -- the breakpoint info module
+ // -> Addr# -- the breakpoint info module unit id
// -> Int# -- the breakpoint info index
// -> Bool -- exception?
// -> HValue -- the AP_STACK, or exception
@@ -1340,17 +1344,21 @@ run_BCO:
ioAction = (StgClosure *) deRefStablePtr (
rts_breakpoint_io_action);
- Sp_subW(15);
- SpW(14) = (W_)obj;
- SpW(13) = (W_)&stg_apply_interp_info;
- SpW(12) = (W_)new_aps;
- SpW(11) = (W_)False_closure; // True <=> an exception
- SpW(10) = (W_)&stg_ap_ppv_info;
- SpW(9) = (W_)arg5_info_index;
+ Sp_subW(19);
+ SpW(18) = (W_)obj;
+ SpW(17) = (W_)&stg_apply_interp_info;
+ SpW(16) = (W_)new_aps;
+ SpW(15) = (W_)False_closure; // True <=> an exception
+ SpW(14) = (W_)&stg_ap_ppv_info;
+ SpW(13) = (W_)arg7_info_index;
+ SpW(12) = (W_)&stg_ap_n_info;
+ SpW(11) = (W_)BCO_LIT(arg5_info_mod_id);
+ SpW(10) = (W_)&stg_ap_n_info;
+ SpW(9) = (W_)BCO_LIT(arg3_info_mod);
SpW(8) = (W_)&stg_ap_n_info;
- SpW(7) = (W_)BCO_LIT(arg3_info_mod);
+ SpW(7) = (W_)arg6_tick_index;
SpW(6) = (W_)&stg_ap_n_info;
- SpW(5) = (W_)arg4_tick_index;
+ SpW(5) = (W_)BCO_LIT(arg4_tick_mod_id);
SpW(4) = (W_)&stg_ap_n_info;
SpW(3) = (W_)BCO_LIT(arg2_tick_mod);
SpW(2) = (W_)&stg_ap_n_info;
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9a1f0313b2011cdd9adccba59d15c1c…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9a1f0313b2011cdd9adccba59d15c1c…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/fendor/ghci-debugger-unitid] 4 commits: Simplifier: Constant fold invald tagToEnum# calls to bottom expr.
by Hannes Siebenhandl (@fendor) 23 Apr '25
by Hannes Siebenhandl (@fendor) 23 Apr '25
23 Apr '25
Hannes Siebenhandl pushed to branch wip/fendor/ghci-debugger-unitid at Glasgow Haskell Compiler / GHC
Commits:
2e204269 by Andreas Klebinger at 2025-04-22T12:20:41+02:00
Simplifier: Constant fold invald tagToEnum# calls to bottom expr.
When applying tagToEnum# to a out-of-range value it's best to simply
constant fold it to a bottom expression. That potentially allows more
dead code elimination and makes debugging easier.
Fixes #25976
- - - - -
7250fc0c by Matthew Pickering at 2025-04-22T16:24:04-04:00
Move -fno-code note into Downsweep module
This note was left behind when all the code which referred to it was
moved into the GHC.Driver.Downsweep module
- - - - -
d2dc89b4 by Matthew Pickering at 2025-04-22T16:24:04-04:00
Apply editing notes to Note [-fno-code mode] suggested by sheaf
These notes were suggested in https://gitlab.haskell.org/ghc/ghc/-/merge_requests/14241
- - - - -
4d463c97 by fendor at 2025-04-23T12:24:28+02:00
Add `UnitId` to `EvalBreakpoint`
The `EvalBreakpoint` is used to communicate that a breakpoint was
encountered during code evaluation.
This `EvalBreakpoint` needs to be converted to an `InternalBreakpointId`
which stores a `Module` to uniquely find the correct `Module` in the
Home Package Table.
The `EvalBreakpoint` used to store only a `ModuleName` which is then
converted to a `Module` based on the currently active home unit.
This is incorrect in the face of multiple home units, the break point
could be in an entirely other home unit!
To fix this, we additionally store the `UnitId` of the `Module` in
`EvalBreakpoint` to later reconstruct the correct `Module`
All of the changes are the consequence of extending `EvalBreakpoint`
with the additional `ShortByteString` of the `UnitId`.
For performance reasons, we store the `ShortByteString` backing the
`UnitId` directly, avoiding marshalling overhead.
- - - - -
16 changed files:
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Core/Opt/ConstantFold.hs
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/Make.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/StgToByteCode.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/Run.hs
- rts/Exception.cmm
- rts/Interpreter.c
- + testsuite/tests/simplCore/should_compile/T25976.hs
- testsuite/tests/simplCore/should_compile/all.T
Changes:
=====================================
compiler/GHC/ByteCode/Asm.hs
=====================================
@@ -732,13 +732,16 @@ assembleI platform i = case i of
CCALL off m_addr i -> do np <- addr m_addr
emit_ bci_CCALL [wOp off, Op np, SmallOp i]
PRIMCALL -> emit_ bci_PRIMCALL []
- BRK_FUN arr tick_mod tickx info_mod infox cc ->
+ BRK_FUN arr tick_mod tick_mod_id tickx info_mod info_mod_id infox cc ->
do p1 <- ptr (BCOPtrBreakArray arr)
tick_addr <- addr tick_mod
+ tick_unitid_addr <- addr tick_mod_id
info_addr <- addr info_mod
+ info_unitid_addr <- addr info_mod_id
np <- addr cc
emit_ bci_BRK_FUN [ Op p1
, Op tick_addr, Op info_addr
+ , Op tick_unitid_addr, Op info_unitid_addr
, SmallOp tickx, SmallOp infox
, Op np
]
=====================================
compiler/GHC/ByteCode/Instr.hs
=====================================
@@ -37,6 +37,7 @@ import GHC.Stg.Syntax
import GHCi.BreakArray (BreakArray)
import Language.Haskell.Syntax.Module.Name (ModuleName)
import GHC.Types.Unique
+import GHC.Unit.Types (UnitId)
-- ----------------------------------------------------------------------------
-- Bytecode instructions
@@ -233,8 +234,10 @@ data BCInstr
-- Breakpoints
| BRK_FUN (ForeignRef BreakArray)
(RemotePtr ModuleName) -- breakpoint tick module
+ (RemotePtr UnitId) -- breakpoint tick module unit id
!Word16 -- breakpoint tick index
(RemotePtr ModuleName) -- breakpoint info module
+ (RemotePtr UnitId) -- breakpoint info module unit id
!Word16 -- breakpoint info index
(RemotePtr CostCentre)
@@ -403,10 +406,10 @@ instance Outputable BCInstr where
ppr ENTER = text "ENTER"
ppr (RETURN pk) = text "RETURN " <+> ppr pk
ppr (RETURN_TUPLE) = text "RETURN_TUPLE"
- ppr (BRK_FUN _ _tick_mod tickx _info_mod infox _)
+ ppr (BRK_FUN _ _tick_mod _tick_mod_id tickx _info_mod _info_mod_id infox _)
= text "BRK_FUN" <+> text "<breakarray>"
- <+> text "<tick_module>" <+> ppr tickx
- <+> text "<info_module>" <+> ppr infox
+ <+> text "<tick_module>" <+> text "<tick_module_unitid>" <+> ppr tickx
+ <+> text "<info_module>" <+> text "<info_module_unitid>" <+> ppr infox
<+> text "<cc>"
#if MIN_VERSION_rts(1,0,3)
ppr (BCO_NAME nm) = text "BCO_NAME" <+> text (show nm)
=====================================
compiler/GHC/ByteCode/Types.hs
=====================================
@@ -50,6 +50,7 @@ import GHC.Stack.CCS
import GHC.Cmm.Expr ( GlobalRegSet, emptyRegSet, regSetToList )
import GHC.Iface.Syntax
import Language.Haskell.Syntax.Module.Name (ModuleName)
+import GHC.Unit.Types (UnitId)
-- -----------------------------------------------------------------------------
-- Compiled Byte Code
@@ -263,6 +264,9 @@ data ModBreaks
, modBreaks_breakInfo :: IntMap CgBreakInfo
-- ^ info about each breakpoint from the bytecode generator
, modBreaks_module :: RemotePtr ModuleName
+ -- ^ info about the module in which we are setting the breakpoint
+ , modBreaks_module_unitid :: RemotePtr UnitId
+ -- ^ The 'UnitId' of the 'ModuleName'
}
seqModBreaks :: ModBreaks -> ()
@@ -273,7 +277,8 @@ seqModBreaks ModBreaks{..} =
rnf modBreaks_decls `seq`
rnf modBreaks_ccs `seq`
rnf (fmap seqCgBreakInfo modBreaks_breakInfo) `seq`
- rnf modBreaks_module
+ rnf modBreaks_module `seq`
+ rnf modBreaks_module_unitid
-- | Construct an empty ModBreaks
emptyModBreaks :: ModBreaks
@@ -286,6 +291,7 @@ emptyModBreaks = ModBreaks
, modBreaks_ccs = array (0,-1) []
, modBreaks_breakInfo = IntMap.empty
, modBreaks_module = toRemotePtr nullPtr
+ , modBreaks_module_unitid = toRemotePtr nullPtr
}
{-
=====================================
compiler/GHC/Core/Opt/ConstantFold.hs
=====================================
@@ -69,7 +69,6 @@ import GHC.Cmm.MachOp ( FMASign(..) )
import GHC.Cmm.Type ( Width(..) )
import GHC.Data.FastString
-import GHC.Data.Maybe ( orElse )
import GHC.Utils.Outputable
import GHC.Utils.Misc
@@ -1997,6 +1996,14 @@ because we don't expect the user to call tagToEnum# at all; we merely
generate calls in derived instances of Enum. So we compromise: a
rewrite rule rewrites a bad instance of tagToEnum# to an error call,
and emits a warning.
+
+We also do something similar if we can see that the argument of tagToEnum is out
+of bounds, e.g. `tagToEnum# 99# :: Bool`.
+Replacing this with an error expression is better for two reasons:
+* It allow us to eliminate more dead code in cases like `case tagToEnum# 99# :: Bool of ...`
+* Should we actually end up executing the relevant code at runtime the user will
+ see a meaningful error message, instead of a segfault or incorrect result.
+See #25976.
-}
tagToEnumRule :: RuleM CoreExpr
@@ -2008,9 +2015,13 @@ tagToEnumRule = do
Just (tycon, tc_args) | isEnumerationTyCon tycon -> do
let tag = fromInteger i
correct_tag dc = (dataConTagZ dc) == tag
- (dc:rest) <- return $ filter correct_tag (tyConDataCons_maybe tycon `orElse` [])
- massert (null rest)
- return $ mkTyApps (Var (dataConWorkId dc)) tc_args
+ Just dataCons <- pure $ tyConDataCons_maybe tycon
+ case filter correct_tag dataCons of
+ (dc:rest) -> do
+ massert (null rest)
+ pure $ mkTyApps (Var (dataConWorkId dc)) tc_args
+ -- Literal is out of range, e.g. tagToEnum @Bool #4
+ [] -> pure $ mkImpossibleExpr ty "tagToEnum: Argument out of range"
-- See Note [tagToEnum#]
_ -> warnPprTrace True "tagToEnum# on non-enumeration type" (ppr ty) $
=====================================
compiler/GHC/Driver/Downsweep.hs
=====================================
@@ -947,6 +947,71 @@ enableCodeGenWhen logger tmpfs staticLife dynLife unit_env mod_graph = do
hostFullWays
in dflags_c
+{- Note [-fno-code mode]
+~~~~~~~~~~~~~~~~~~~~~~~~
+GHC offers the flag -fno-code for the purpose of parsing and typechecking a
+program without generating object files. This is intended to be used by tooling
+and IDEs to provide quick feedback on any parser or type errors as cheaply as
+possible.
+
+When GHC is invoked with -fno-code, no object files or linked output will be
+generated. As many errors and warnings as possible will be generated, as if
+-fno-code had not been passed. The session DynFlags will have
+backend == NoBackend.
+
+-fwrite-interface
+~~~~~~~~~~~~~~~~
+Whether interface files are generated in -fno-code mode is controlled by the
+-fwrite-interface flag. The -fwrite-interface flag is a no-op if -fno-code is
+not also passed. Recompilation avoidance requires interface files, so passing
+-fno-code without -fwrite-interface should be avoided. If -fno-code were
+re-implemented today, there would be no need for -fwrite-interface as it
+would considered always on; this behaviour is as it is for backwards compatibility.
+
+================================================================
+IN SUMMARY: ALWAYS PASS -fno-code AND -fwrite-interface TOGETHER
+================================================================
+
+Template Haskell
+~~~~~~~~~~~~~~~~
+A module using Template Haskell may invoke an imported function from inside a
+splice. This will cause the type-checker to attempt to execute that code, which
+would fail if no object files had been generated. See #8025. To rectify this,
+during the downsweep we patch the DynFlags in the ModSummary of any home module
+that is imported by a module that uses Template Haskell to generate object
+code.
+
+The flavour of the generated code depends on whether `-fprefer-byte-code` is enabled
+or not in the module which needs the code generation. If the module requires byte-code then
+dependencies will generate byte-code, otherwise they will generate object files.
+In the case where some modules require byte-code and some object files, both are
+generated by enabling `-fbyte-code-and-object-code`, the test "fat015" tests these
+configurations.
+
+The object files (and interface files if -fwrite-interface is disabled) produced
+for Template Haskell are written to temporary files.
+
+Note that since Template Haskell can run arbitrary IO actions, -fno-code mode
+is no more secure than running without it.
+
+Potential TODOS:
+~~~~~
+* Remove -fwrite-interface and have interface files always written in -fno-code
+ mode
+* Both .o and .dyn_o files are generated for template haskell, but we only need
+ .dyn_o. Fix it.
+* In make mode, a message like
+ Compiling A (A.hs, /tmp/ghc_123.o)
+ is shown if downsweep enabled object code generation for A. Perhaps we should
+ show "nothing" or "temporary object file" instead. Note that one
+ can currently use -keep-tmp-files and inspect the generated file with the
+ current behaviour.
+* Offer a -no-codedir command line option, and write what were temporary
+ object files there. This would speed up recompilation.
+* Use existing object files (if they are up to date) instead of always
+ generating temporary ones.
+-}
+
-- | Populate the Downsweep cache with the root modules.
mkRootMap
:: [ModuleNodeInfo]
=====================================
compiler/GHC/Driver/Make.hs
=====================================
@@ -1246,70 +1246,6 @@ addSptEntries hsc_env mlinkable =
, spt <- bc_spt_entries bco
]
-{- Note [-fno-code mode]
-~~~~~~~~~~~~~~~~~~~~~~~~
-GHC offers the flag -fno-code for the purpose of parsing and typechecking a
-program without generating object files. This is intended to be used by tooling
-and IDEs to provide quick feedback on any parser or type errors as cheaply as
-possible.
-
-When GHC is invoked with -fno-code no object files or linked output will be
-generated. As many errors and warnings as possible will be generated, as if
--fno-code had not been passed. The session DynFlags will have
-backend == NoBackend.
-
--fwrite-interface
-~~~~~~~~~~~~~~~~
-Whether interface files are generated in -fno-code mode is controlled by the
--fwrite-interface flag. The -fwrite-interface flag is a no-op if -fno-code is
-not also passed. Recompilation avoidance requires interface files, so passing
--fno-code without -fwrite-interface should be avoided. If -fno-code were
-re-implemented today, -fwrite-interface would be discarded and it would be
-considered always on; this behaviour is as it is for backwards compatibility.
-
-================================================================
-IN SUMMARY: ALWAYS PASS -fno-code AND -fwrite-interface TOGETHER
-================================================================
-
-Template Haskell
-~~~~~~~~~~~~~~~~
-A module using template haskell may invoke an imported function from inside a
-splice. This will cause the type-checker to attempt to execute that code, which
-would fail if no object files had been generated. See #8025. To rectify this,
-during the downsweep we patch the DynFlags in the ModSummary of any home module
-that is imported by a module that uses template haskell, to generate object
-code.
-
-The flavour of the generated code depends on whether `-fprefer-byte-code` is enabled
-or not in the module which needs the code generation. If the module requires byte-code then
-dependencies will generate byte-code, otherwise they will generate object files.
-In the case where some modules require byte-code and some object files, both are
-generated by enabling `-fbyte-code-and-object-code`, the test "fat015" tests these
-configurations.
-
-The object files (and interface files if -fwrite-interface is disabled) produced
-for template haskell are written to temporary files.
-
-Note that since template haskell can run arbitrary IO actions, -fno-code mode
-is no more secure than running without it.
-
-Potential TODOS:
-~~~~~
-* Remove -fwrite-interface and have interface files always written in -fno-code
- mode
-* Both .o and .dyn_o files are generated for template haskell, but we only need
- .dyn_o. Fix it.
-* In make mode, a message like
- Compiling A (A.hs, /tmp/ghc_123.o)
- is shown if downsweep enabled object code generation for A. Perhaps we should
- show "nothing" or "temporary object file" instead. Note that one
- can currently use -keep-tmp-files and inspect the generated file with the
- current behaviour.
-* Offer a -no-codedir command line option, and write what were temporary
- object files there. This would speed up recompilation.
-* Use existing object files (if they are up to date) instead of always
- generating temporary ones.
--}
-- Note [When source is considered modified]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
=====================================
compiler/GHC/HsToCore/Breakpoints.hs
=====================================
@@ -34,7 +34,7 @@ mkModBreaks interp mod extendedMixEntries
breakArray <- GHCi.newBreakArray interp count
ccs <- mkCCSArray interp mod count entries
- mod_ptr <- GHCi.newModuleName interp (moduleName mod)
+ (mod_ptr, mod_id_ptr) <- GHCi.newModule interp mod
let
locsTicks = listArray (0,count-1) [ tick_loc t | t <- entries ]
varsTicks = listArray (0,count-1) [ tick_ids t | t <- entries ]
@@ -46,6 +46,7 @@ mkModBreaks interp mod extendedMixEntries
, modBreaks_decls = declsTicks
, modBreaks_ccs = ccs
, modBreaks_module = mod_ptr
+ , modBreaks_module_unitid = mod_id_ptr
}
mkCCSArray
=====================================
compiler/GHC/Runtime/Eval.hs
=====================================
@@ -345,7 +345,7 @@ handleRunStatus step expr bindings final_ids status history0 = do
-- Just case: we stopped at a breakpoint
EvalBreak apStack_ref (Just eval_break) resume_ctxt ccs -> do
- ibi <- liftIO $ evalBreakpointToId (hsc_HPT hsc_env) eval_break
+ let ibi = evalBreakpointToId eval_break
tick_brks <- liftIO $ readModBreaks hsc_env (ibi_tick_mod ibi)
let
span = modBreaks_locs tick_brks ! ibi_tick_index ibi
=====================================
compiler/GHC/Runtime/Interpreter.hs
=====================================
@@ -21,7 +21,7 @@ module GHC.Runtime.Interpreter
, mkCostCentres
, costCentreStackInfo
, newBreakArray
- , newModuleName
+ , newModule
, storeBreakpoint
, breakpointStatus
, getBreakpointVar
@@ -93,9 +93,7 @@ import GHC.Utils.Outputable(brackets, ppr, showSDocUnsafe)
import GHC.Utils.Fingerprint
import GHC.Unit.Module
-import GHC.Unit.Module.ModIface
import GHC.Unit.Home.ModInfo
-import GHC.Unit.Home.PackageTable
import GHC.Unit.Env
#if defined(HAVE_INTERNAL_INTERPRETER)
@@ -119,6 +117,7 @@ import qualified GHC.InfoProv as InfoProv
import GHC.Builtin.Names
import GHC.Types.Name
+import qualified GHC.Unit.Home.Graph as HUG
-- Standard libraries
import GHC.Exts
@@ -377,9 +376,13 @@ newBreakArray interp size = do
breakArray <- interpCmd interp (NewBreakArray size)
mkFinalizedHValue interp breakArray
-newModuleName :: Interp -> ModuleName -> IO (RemotePtr ModuleName)
-newModuleName interp mod_name =
- castRemotePtr <$> interpCmd interp (NewBreakModule (moduleNameString mod_name))
+newModule :: Interp -> Module -> IO (RemotePtr ModuleName, RemotePtr UnitId)
+newModule interp mod = do
+ let
+ mod_name = moduleNameString $ moduleName mod
+ mod_id = fastStringToShortByteString $ unitIdFS $ toUnitId $ moduleUnit mod
+ (mod_ptr, mod_id_ptr) <- interpCmd interp (NewBreakModule mod_name mod_id)
+ pure (castRemotePtr mod_ptr, castRemotePtr mod_id_ptr)
storeBreakpoint :: Interp -> ForeignRef BreakArray -> Int -> Int -> IO ()
storeBreakpoint interp ref ix cnt = do -- #19157
@@ -415,19 +418,21 @@ seqHValue interp unit_env ref =
status <- interpCmd interp (Seq hval)
handleSeqHValueStatus interp unit_env status
-evalBreakpointToId :: HomePackageTable -> EvalBreakpoint -> IO InternalBreakpointId
-evalBreakpointToId hpt eval_break =
- let load_mod x = mi_module . hm_iface . expectJust <$> lookupHpt hpt (mkModuleName x)
- in do
- tickl <- load_mod (eb_tick_mod eval_break)
- infol <- load_mod (eb_info_mod eval_break)
- return
- InternalBreakpointId
- { ibi_tick_mod = tickl
- , ibi_tick_index = eb_tick_index eval_break
- , ibi_info_mod = infol
- , ibi_info_index = eb_info_index eval_break
- }
+evalBreakpointToId :: EvalBreakpoint -> InternalBreakpointId
+evalBreakpointToId eval_break =
+ let
+ mkUnitId u = fsToUnit $ mkFastStringShortByteString u
+
+ toModule u n = mkModule (mkUnitId u) (mkModuleName n)
+ tickl = toModule (eb_tick_mod_unit eval_break) (eb_tick_mod eval_break)
+ infol = toModule (eb_info_mod_unit eval_break) (eb_info_mod eval_break)
+ in
+ InternalBreakpointId
+ { ibi_tick_mod = tickl
+ , ibi_tick_index = eb_tick_index eval_break
+ , ibi_info_mod = infol
+ , ibi_info_index = eb_info_index eval_break
+ }
-- | Process the result of a Seq or ResumeSeq message. #2950
handleSeqHValueStatus :: Interp -> UnitEnv -> EvalStatus () -> IO (EvalResult ())
@@ -447,12 +452,12 @@ handleSeqHValueStatus interp unit_env eval_status =
mkGeneralSrcSpan (fsLit "<unknown>")
Just break -> do
- bi <- evalBreakpointToId (ue_hpt unit_env) break
+ let bi = evalBreakpointToId break
-- Just case: Stopped at a breakpoint, extract SrcSpan information
-- from the breakpoint.
breaks_tick <- getModBreaks . expectJust <$>
- lookupHpt (ue_hpt unit_env) (moduleName (ibi_tick_mod bi))
+ HUG.lookupHugByModule (ibi_tick_mod bi) (ue_home_unit_graph unit_env)
put $ brackets . ppr $
(modBreaks_locs breaks_tick) ! ibi_tick_index bi
=====================================
compiler/GHC/StgToByteCode.hs
=====================================
@@ -416,7 +416,7 @@ schemeER_wrk d p (StgTick (Breakpoint tick_ty tick_no fvs tick_mod) rhs) = do
Nothing -> pure code
Just current_mod_breaks -> break_info hsc_env tick_mod current_mod mb_current_mod_breaks >>= \case
Nothing -> pure code
- Just ModBreaks {modBreaks_flags = breaks, modBreaks_module = tick_mod_ptr, modBreaks_ccs = cc_arr} -> do
+ Just ModBreaks {modBreaks_flags = breaks, modBreaks_module = tick_mod_ptr, modBreaks_module_unitid = tick_mod_id_ptr, modBreaks_ccs = cc_arr} -> do
platform <- profilePlatform <$> getProfile
let idOffSets = getVarOffSets platform d p fvs
ty_vars = tyCoVarsOfTypesWellScoped (tick_ty:map idType fvs)
@@ -425,6 +425,7 @@ schemeER_wrk d p (StgTick (Breakpoint tick_ty tick_no fvs tick_mod) rhs) = do
breakInfo = dehydrateCgBreakInfo ty_vars (map toWord idOffSets) tick_ty
let info_mod_ptr = modBreaks_module current_mod_breaks
+ info_mod_id_ptr = modBreaks_module_unitid current_mod_breaks
infox <- newBreakInfo breakInfo
let cc | Just interp <- hsc_interp hsc_env
@@ -437,7 +438,7 @@ schemeER_wrk d p (StgTick (Breakpoint tick_ty tick_no fvs tick_mod) rhs) = do
in if fromIntegral r == x
then r
else pprPanic "schemeER_wrk: breakpoint tick/info index too large!" (ppr x)
- breakInstr = BRK_FUN breaks tick_mod_ptr (toW16 tick_no) info_mod_ptr (toW16 infox) cc
+ breakInstr = BRK_FUN breaks tick_mod_ptr tick_mod_id_ptr (toW16 tick_no) info_mod_ptr info_mod_id_ptr (toW16 infox) cc
return $ breakInstr `consOL` code
schemeER_wrk d p rhs = schemeE d 0 p rhs
=====================================
libraries/ghci/GHCi/Message.hs
=====================================
@@ -23,6 +23,7 @@ module GHCi.Message
, getMessage, putMessage, getTHMessage, putTHMessage
, Pipe, mkPipeFromHandles, mkPipeFromContinuations, remoteCall, remoteTHCall, readPipe, writePipe
, BreakModule
+ , BreakUnitId
, LoadedDLL
) where
@@ -62,6 +63,7 @@ import qualified GHC.Boot.TH.Syntax as TH
import System.Exit
import System.IO
import System.IO.Error
+import qualified Data.ByteString.Short as BS
-- -----------------------------------------------------------------------------
-- The RPC protocol between GHC and the interactive server
@@ -245,8 +247,9 @@ data Message a where
-- | Allocate a string for a breakpoint module name.
-- This uses an empty dummy type because @ModuleName@ isn't available here.
NewBreakModule
- :: String
- -> Message (RemotePtr BreakModule)
+ :: String -- ^ @ModuleName@
+ -> BS.ShortByteString -- ^ @UnitId@ for the given @ModuleName@
+ -> Message (RemotePtr BreakModule, RemotePtr BreakUnitId)
deriving instance Show (Message a)
@@ -410,10 +413,12 @@ data EvalStatus_ a b
instance Binary a => Binary (EvalStatus_ a b)
data EvalBreakpoint = EvalBreakpoint
- { eb_tick_mod :: String -- ^ Breakpoint tick module
- , eb_tick_index :: Int -- ^ Breakpoint tick index
- , eb_info_mod :: String -- ^ Breakpoint info module
- , eb_info_index :: Int -- ^ Breakpoint info index
+ { eb_tick_mod :: String -- ^ Breakpoint tick module
+ , eb_tick_mod_unit :: BS.ShortByteString -- ^ Breakpoint tick module unit id
+ , eb_tick_index :: Int -- ^ Breakpoint tick index
+ , eb_info_mod :: String -- ^ Breakpoint info module
+ , eb_info_mod_unit :: BS.ShortByteString -- ^ Breakpoint tick module unit id
+ , eb_info_index :: Int -- ^ Breakpoint info index
}
deriving (Generic, Show)
@@ -430,6 +435,10 @@ instance Binary a => Binary (EvalResult a)
-- that type isn't available here.
data BreakModule
+-- | A dummy type that tags the pointer to a breakpoint's @UnitId@, because
+-- that type isn't available here.
+data BreakUnitId
+
-- | A dummy type that tags pointers returned by 'LoadDLL'.
data LoadedDLL
@@ -580,7 +589,7 @@ getMessage = do
36 -> Msg <$> (Seq <$> get)
37 -> Msg <$> return RtsRevertCAFs
38 -> Msg <$> (ResumeSeq <$> get)
- 39 -> Msg <$> (NewBreakModule <$> get)
+ 39 -> Msg <$> (NewBreakModule <$> get <*> get)
40 -> Msg <$> (LookupSymbolInDLL <$> get <*> get)
41 -> Msg <$> (WhereFrom <$> get)
_ -> error $ "Unknown Message code " ++ (show b)
@@ -627,7 +636,7 @@ putMessage m = case m of
Seq a -> putWord8 36 >> put a
RtsRevertCAFs -> putWord8 37
ResumeSeq a -> putWord8 38 >> put a
- NewBreakModule name -> putWord8 39 >> put name
+ NewBreakModule name unitid -> putWord8 39 >> put name >> put unitid
LookupSymbolInDLL dll str -> putWord8 40 >> put dll >> put str
WhereFrom a -> putWord8 41 >> put a
=====================================
libraries/ghci/GHCi/Run.hs
=====================================
@@ -43,6 +43,7 @@ import GHC.Conc.Sync
import GHC.IO hiding ( bracket )
import System.Mem.Weak ( deRefWeak )
import Unsafe.Coerce
+import qualified Data.ByteString.Short as BS
-- -----------------------------------------------------------------------------
-- Implement messages
@@ -95,7 +96,10 @@ run m = case m of
MkCostCentres mod ccs -> mkCostCentres mod ccs
CostCentreStackInfo ptr -> ccsToStrings (fromRemotePtr ptr)
NewBreakArray sz -> mkRemoteRef =<< newBreakArray sz
- NewBreakModule name -> newModuleName name
+ NewBreakModule name unitid -> do
+ namePtr <- newModuleName name
+ uidPtr <- newUnitId unitid
+ pure (namePtr, uidPtr)
SetupBreakpoint ref ix cnt -> do
arr <- localRef ref;
_ <- setupBreakpoint arr ix cnt
@@ -335,7 +339,7 @@ withBreakAction opts breakMVar statusMVar act
-- as soon as it is hit, or in resetBreakAction below.
onBreak :: BreakpointCallback
- onBreak tick_mod# tickx# info_mod# infox# is_exception apStack = do
+ onBreak tick_mod# tick_mod_uid# tickx# info_mod# info_mod_uid# infox# is_exception apStack = do
tid <- myThreadId
let resume = ResumeContext
{ resumeBreakMVar = breakMVar
@@ -349,8 +353,10 @@ withBreakAction opts breakMVar statusMVar act
then pure Nothing
else do
tick_mod <- peekCString (Ptr tick_mod#)
+ tick_mod_uid <- BS.packCString (Ptr tick_mod_uid#)
info_mod <- peekCString (Ptr info_mod#)
- pure (Just (EvalBreakpoint tick_mod (I# tickx#) info_mod (I# infox#)))
+ info_mod_uid <- BS.packCString (Ptr info_mod_uid#)
+ pure (Just (EvalBreakpoint tick_mod tick_mod_uid (I# tickx#) info_mod info_mod_uid (I# infox#)))
putMVar statusMVar $ EvalBreak apStack_r breakpoint resume_r ccs
takeMVar breakMVar
@@ -400,8 +406,10 @@ resetStepFlag = poke stepFlag 0
type BreakpointCallback
= Addr# -- pointer to the breakpoint tick module name
+ -> Addr# -- pointer to the breakpoint tick module unit id
-> Int# -- breakpoint tick index
-> Addr# -- pointer to the breakpoint info module name
+ -> Addr# -- pointer to the breakpoint info module unit id
-> Int# -- breakpoint info index
-> Bool -- exception?
-> HValue -- the AP_STACK, or exception
@@ -414,8 +422,8 @@ noBreakStablePtr :: StablePtr BreakpointCallback
noBreakStablePtr = unsafePerformIO $ newStablePtr noBreakAction
noBreakAction :: BreakpointCallback
-noBreakAction _ _ _ _ False _ = putStrLn "*** Ignoring breakpoint"
-noBreakAction _ _ _ _ True _ = return () -- exception: just continue
+noBreakAction _ _ _ _ _ _ False _ = putStrLn "*** Ignoring breakpoint"
+noBreakAction _ _ _ _ _ _ True _ = return () -- exception: just continue
-- Malloc and copy the bytes. We don't have any way to monitor the
-- lifetime of this memory, so it just leaks.
@@ -432,6 +440,13 @@ mkString0 bs = B.unsafeUseAsCStringLen bs $ \(cstr,len) -> do
pokeElemOff (ptr :: Ptr CChar) len 0
return (castRemotePtr (toRemotePtr ptr))
+mkShortByteString0 :: BS.ShortByteString -> IO (RemotePtr ())
+mkShortByteString0 bs = BS.useAsCStringLen bs $ \(cstr,len) -> do
+ ptr <- mallocBytes (len+1)
+ copyBytes ptr cstr len
+ pokeElemOff (ptr :: Ptr CChar) len 0
+ return (castRemotePtr (toRemotePtr ptr))
+
mkCostCentres :: String -> [(String,String)] -> IO [RemotePtr CostCentre]
#if defined(PROFILING)
mkCostCentres mod ccs = do
@@ -453,6 +468,10 @@ newModuleName :: String -> IO (RemotePtr BreakModule)
newModuleName name =
castRemotePtr . toRemotePtr <$> newCString name
+newUnitId :: BS.ShortByteString -> IO (RemotePtr BreakUnitId)
+newUnitId name =
+ castRemotePtr <$> mkShortByteString0 name
+
getIdValFromApStack :: HValue -> Int -> IO (Maybe HValue)
getIdValFromApStack apStack (I# stackDepth) = do
case getApStackVal# apStack stackDepth of
=====================================
rts/Exception.cmm
=====================================
@@ -535,12 +535,16 @@ retry_pop_stack:
// be per-thread.
CInt[rts_stop_on_exception] = 0;
("ptr" ioAction) = ccall deRefStablePtr (W_[rts_breakpoint_io_action] "ptr");
- Sp = Sp - WDS(13);
- Sp(12) = exception;
- Sp(11) = stg_raise_ret_info;
- Sp(10) = exception;
- Sp(9) = ghczminternal_GHCziInternalziTypes_True_closure; // True <=> an exception
- Sp(8) = stg_ap_ppv_info;
+ Sp = Sp - WDS(17);
+ Sp(16) = exception;
+ Sp(15) = stg_raise_ret_info;
+ Sp(14) = exception;
+ Sp(13) = ghczminternal_GHCziInternalziTypes_True_closure; // True <=> an exception
+ Sp(12) = stg_ap_ppv_info;
+ Sp(11) = 0;
+ Sp(10) = stg_ap_n_info;
+ Sp(9) = 0;
+ Sp(8) = stg_ap_n_info;
Sp(7) = 0;
Sp(6) = stg_ap_n_info;
Sp(5) = 0;
=====================================
rts/Interpreter.c
=====================================
@@ -1245,9 +1245,9 @@ run_BCO:
/* check for a breakpoint on the beginning of a let binding */
case bci_BRK_FUN:
{
- int arg1_brk_array, arg2_tick_mod, arg3_info_mod, arg4_tick_index, arg5_info_index;
+ int arg1_brk_array, arg2_tick_mod, arg3_info_mod, arg4_tick_mod_id, arg5_info_mod_id, arg6_tick_index, arg7_info_index;
#if defined(PROFILING)
- int arg6_cc;
+ int arg8_cc;
#endif
StgArrBytes *breakPoints;
int returning_from_break;
@@ -1264,10 +1264,12 @@ run_BCO:
arg1_brk_array = BCO_GET_LARGE_ARG;
arg2_tick_mod = BCO_GET_LARGE_ARG;
arg3_info_mod = BCO_GET_LARGE_ARG;
- arg4_tick_index = BCO_NEXT;
- arg5_info_index = BCO_NEXT;
+ arg4_tick_mod_id = BCO_GET_LARGE_ARG;
+ arg5_info_mod_id = BCO_GET_LARGE_ARG;
+ arg6_tick_index = BCO_NEXT;
+ arg7_info_index = BCO_NEXT;
#if defined(PROFILING)
- arg6_cc = BCO_GET_LARGE_ARG;
+ arg8_cc = BCO_GET_LARGE_ARG;
#else
BCO_GET_LARGE_ARG;
#endif
@@ -1280,7 +1282,7 @@ run_BCO:
#if defined(PROFILING)
cap->r.rCCCS = pushCostCentre(cap->r.rCCCS,
- (CostCentre*)BCO_LIT(arg6_cc));
+ (CostCentre*)BCO_LIT(arg8_cc));
#endif
// if we are returning from a break then skip this section
@@ -1292,11 +1294,11 @@ run_BCO:
// stop the current thread if either the
// "rts_stop_next_breakpoint" flag is true OR if the
// ignore count for this particular breakpoint is zero
- StgInt ignore_count = ((StgInt*)breakPoints->payload)[arg4_tick_index];
+ StgInt ignore_count = ((StgInt*)breakPoints->payload)[arg6_tick_index];
if (rts_stop_next_breakpoint == false && ignore_count > 0)
{
// decrement and write back ignore count
- ((StgInt*)breakPoints->payload)[arg4_tick_index] = --ignore_count;
+ ((StgInt*)breakPoints->payload)[arg6_tick_index] = --ignore_count;
}
else if (rts_stop_next_breakpoint == true || ignore_count == 0)
{
@@ -1330,8 +1332,10 @@ run_BCO:
// continue execution of this BCO when the IO action returns.
//
// ioAction :: Addr# -- the breakpoint tick module
+ // -> Addr# -- the breakpoint tick module unit id
// -> Int# -- the breakpoint tick index
// -> Addr# -- the breakpoint info module
+ // -> Addr# -- the breakpoint info module unit id
// -> Int# -- the breakpoint info index
// -> Bool -- exception?
// -> HValue -- the AP_STACK, or exception
@@ -1340,17 +1344,21 @@ run_BCO:
ioAction = (StgClosure *) deRefStablePtr (
rts_breakpoint_io_action);
- Sp_subW(15);
- SpW(14) = (W_)obj;
- SpW(13) = (W_)&stg_apply_interp_info;
- SpW(12) = (W_)new_aps;
- SpW(11) = (W_)False_closure; // True <=> an exception
- SpW(10) = (W_)&stg_ap_ppv_info;
- SpW(9) = (W_)arg5_info_index;
+ Sp_subW(19);
+ SpW(18) = (W_)obj;
+ SpW(17) = (W_)&stg_apply_interp_info;
+ SpW(16) = (W_)new_aps;
+ SpW(15) = (W_)False_closure; // True <=> an exception
+ SpW(14) = (W_)&stg_ap_ppv_info;
+ SpW(13) = (W_)arg7_info_index;
+ SpW(12) = (W_)&stg_ap_n_info;
+ SpW(11) = (W_)BCO_LIT(arg5_info_mod_id);
+ SpW(10) = (W_)&stg_ap_n_info;
+ SpW(9) = (W_)BCO_LIT(arg3_info_mod);
SpW(8) = (W_)&stg_ap_n_info;
- SpW(7) = (W_)BCO_LIT(arg3_info_mod);
+ SpW(7) = (W_)arg6_tick_index;
SpW(6) = (W_)&stg_ap_n_info;
- SpW(5) = (W_)arg4_tick_index;
+ SpW(5) = (W_)BCO_LIT(arg4_tick_mod_id);
SpW(4) = (W_)&stg_ap_n_info;
SpW(3) = (W_)BCO_LIT(arg2_tick_mod);
SpW(2) = (W_)&stg_ap_n_info;
=====================================
testsuite/tests/simplCore/should_compile/T25976.hs
=====================================
@@ -0,0 +1,10 @@
+{-# LANGUAGE MagicHash #-}
+
+module T25976 where
+
+import GHC.PrimOps (tagToEnum#)
+
+-- Spoiler - it's all dead code since tagToEnum 3# is undefined
+main = case (tagToEnum# 4# :: Bool) of
+ True -> print "Dead Code"
+ False -> print "Dead Code"
=====================================
testsuite/tests/simplCore/should_compile/all.T
=====================================
@@ -541,3 +541,5 @@ test('T25883', normal, compile_grep_core, [''])
test('T25883b', normal, compile_grep_core, [''])
test('T25883c', normal, compile_grep_core, [''])
test('T25883d', [extra_files(['T25883d_import.hs'])], multimod_compile_filter, ['T25883d', '-O -ddump-simpl -dno-typeable-binds -dsuppress-all -dsuppress-uniques', r'grep -e "y ="'])
+
+test('T25976', [grep_errmsg('Dead Code')], compile, ['-O -ddump-simpl -dsuppress-uniques -dno-typeable-binds'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/e7bb646b06c1d10f163311a7923f0e…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/e7bb646b06c1d10f163311a7923f0e…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/strict-level] 2 commits: SetLevels: Track binding context
by Zubin (@wz1000) 23 Apr '25
by Zubin (@wz1000) 23 Apr '25
23 Apr '25
Zubin pushed to branch wip/strict-level at Glasgow Haskell Compiler / GHC
Commits:
2f29500c by Ben Gamari at 2025-04-23T15:52:30+05:30
SetLevels: Track binding context
In preparation to use this information to provide more context-sensitive
naming for generated `lvl_` identifiers as propsed in #25802.
- - - - -
13bdd461 by Ben Gamari at 2025-04-23T15:52:30+05:30
SetLevels: Name `lvl` binders according to context
In general we should strive to maintain some amount of information about
the provenance of generated bindings.
Addresses #25802.
- - - - -
2 changed files:
- compiler/GHC/Core/Opt/SetLevels.hs
- testsuite/tests/codeGen/should_compile/T25177.stderr
Changes:
=====================================
compiler/GHC/Core/Opt/SetLevels.hs
=====================================
@@ -109,7 +109,7 @@ import GHC.Types.Literal ( litIsTrivial )
import GHC.Types.Demand ( DmdSig, prependArgsDmdSig )
import GHC.Types.Cpr ( CprSig, prependArgsCprSig )
import GHC.Types.Name ( getOccName, mkSystemVarName )
-import GHC.Types.Name.Occurrence ( occNameFS )
+import GHC.Types.Name.Occurrence ( occNameFS, occNameString )
import GHC.Types.Unique ( hasKey )
import GHC.Types.Tickish ( tickishIsCode )
import GHC.Types.Unique.Supply
@@ -126,6 +126,7 @@ import GHC.Utils.Misc
import GHC.Utils.Outputable
import GHC.Utils.Panic
+import Data.List ( intercalate )
import Data.Maybe
{-
@@ -635,7 +636,7 @@ lvlMFE env strict_ctxt ann_expr
= do { expr1 <- lvlFloatRhs abs_vars dest_lvl rhs_env NonRecursive
is_bot_lam NotJoinPoint ann_expr
-- Treat the expr just like a right-hand side
- ; var <- newLvlVar expr1 NotJoinPoint is_mk_static
+ ; var <- newLvlVar env expr1 NotJoinPoint is_mk_static
; let var2 = annotateBotStr var float_n_lams mb_bot_str
; return (Let (NonRec (TB var2 (FloatMe dest_lvl)) expr1)
(mkVarApps (Var var2) abs_vars)) }
@@ -656,7 +657,7 @@ lvlMFE env strict_ctxt ann_expr
Case expr1 (stayPut l1r ubx_bndr) box_ty
[Alt DEFAULT [] (App boxing_expr (Var ubx_bndr))]
- ; var <- newLvlVar float_rhs NotJoinPoint is_mk_static
+ ; var <- newLvlVar env float_rhs NotJoinPoint is_mk_static
; let l1u = incMinorLvlFrom env
use_expr = Case (mkVarApps (Var var) abs_vars)
(stayPut l1u bx_bndr) expr_ty
@@ -1219,41 +1220,42 @@ lvlBind :: LevelEnv
-> CoreBindWithFVs
-> LvlM (LevelledBind, LevelEnv)
-lvlBind env (AnnNonRec bndr rhs)
+lvlBind env0 (AnnNonRec bndr rhs)
| isTyVar bndr -- Don't float TyVar binders (simplifier gets rid of them pronto)
|| isCoVar bndr -- Don't float CoVars: difficult to fix up CoVar occurrences
-- (see extendPolyLvlEnv)
- || not (wantToFloat env NonRecursive dest_lvl is_join is_top_bindable)
+ || not (wantToFloat env0 NonRecursive dest_lvl is_join is_top_bindable)
= -- No float
- do { rhs' <- lvlRhs env NonRecursive is_bot_lam mb_join_arity rhs
- ; let bind_lvl = incMinorLvl (le_ctxt_lvl env)
- (env', [bndr']) = substAndLvlBndrs NonRecursive env bind_lvl [bndr]
- ; return (NonRec bndr' rhs', env') }
+ do { rhs' <- lvlRhs env1 NonRecursive is_bot_lam mb_join_arity rhs
+ ; let bind_lvl = incMinorLvl (le_ctxt_lvl env1)
+ (env2, [bndr']) = substAndLvlBndrs NonRecursive env1 bind_lvl [bndr]
+ ; return (NonRec bndr' rhs', env2) }
-- Otherwise we are going to float
| null abs_vars
= do { -- No type abstraction; clone existing binder
- rhs' <- lvlFloatRhs [] dest_lvl env NonRecursive
+ rhs' <- lvlFloatRhs [] dest_lvl env1 NonRecursive
is_bot_lam NotJoinPoint rhs
- ; (env', [bndr']) <- cloneLetVars NonRecursive env dest_lvl [bndr]
+ ; (env2, [bndr']) <- cloneLetVars NonRecursive env1 dest_lvl [bndr]
; let bndr2 = annotateBotStr bndr' 0 mb_bot_str
- ; return (NonRec (TB bndr2 (FloatMe dest_lvl)) rhs', env') }
+ ; return (NonRec (TB bndr2 (FloatMe dest_lvl)) rhs', env2) }
| otherwise
= do { -- Yes, type abstraction; create a new binder, extend substitution, etc
- rhs' <- lvlFloatRhs abs_vars dest_lvl env NonRecursive
+ rhs' <- lvlFloatRhs abs_vars dest_lvl env1 NonRecursive
is_bot_lam NotJoinPoint rhs
- ; (env', [bndr']) <- newPolyBndrs dest_lvl env abs_vars [bndr]
+ ; (env2, [bndr']) <- newPolyBndrs dest_lvl env1 abs_vars [bndr]
; let bndr2 = annotateBotStr bndr' n_extra mb_bot_str
- ; return (NonRec (TB bndr2 (FloatMe dest_lvl)) rhs', env') }
+ ; return (NonRec (TB bndr2 (FloatMe dest_lvl)) rhs', env2) }
where
+ env1 = pushBindContext env0 bndr
bndr_ty = idType bndr
ty_fvs = tyCoVarsOfType bndr_ty
rhs_fvs = freeVarsOf rhs
bind_fvs = rhs_fvs `unionDVarSet` dIdFreeVars bndr
- abs_vars = abstractVars dest_lvl env bind_fvs
- dest_lvl = destLevel env bind_fvs ty_fvs (isFunction rhs) is_bot_lam
+ abs_vars = abstractVars dest_lvl env0 bind_fvs
+ dest_lvl = destLevel env0 bind_fvs ty_fvs (isFunction rhs) is_bot_lam
deann_rhs = deAnnotate rhs
mb_bot_str = exprBotStrictness_maybe deann_rhs
@@ -1273,7 +1275,8 @@ lvlBind env (AnnRec pairs)
= -- No float
do { let bind_lvl = incMinorLvl (le_ctxt_lvl env)
(env', bndrs') = substAndLvlBndrs Recursive env bind_lvl bndrs
- lvl_rhs (b,r) = lvlRhs env' Recursive is_bot (idJoinPointHood b) r
+ lvl_rhs (b,r) = lvlRhs env'' Recursive is_bot (idJoinPointHood b) r
+ where env'' = pushBindContext env' b
; rhss' <- mapM lvl_rhs pairs
; return (Rec (bndrs' `zip` rhss'), env') }
@@ -1298,8 +1301,9 @@ lvlBind env (AnnRec pairs)
-- mutually recursive functions, but it's quite a bit more complicated
--
-- This all seems a bit ad hoc -- sigh
- let (rhs_env, abs_vars_w_lvls) = lvlLamBndrs env dest_lvl abs_vars
+ let (rhs_env, abs_vars_w_lvls) = lvlLamBndrs env' dest_lvl abs_vars
rhs_lvl = le_ctxt_lvl rhs_env
+ env' = pushBindContext env bndr
(rhs_env', [new_bndr]) <- cloneLetVars Recursive rhs_env rhs_lvl [bndr]
let
@@ -1307,7 +1311,7 @@ lvlBind env (AnnRec pairs)
(body_env1, lam_bndrs1) = substBndrsSL NonRecursive rhs_env' lam_bndrs
(body_env2, lam_bndrs2) = lvlLamBndrs body_env1 rhs_lvl lam_bndrs1
new_rhs_body <- lvlRhs body_env2 Recursive is_bot NotJoinPoint rhs_body
- (poly_env, [poly_bndr]) <- newPolyBndrs dest_lvl env abs_vars [bndr]
+ (poly_env, [poly_bndr]) <- newPolyBndrs dest_lvl env' abs_vars [bndr]
return (Rec [(TB poly_bndr (FloatMe dest_lvl)
, mkLams abs_vars_w_lvls $
mkLams lam_bndrs2 $
@@ -1332,9 +1336,10 @@ lvlBind env (AnnRec pairs)
-- function in a Rec, and we don't much care what
-- happens to it. False is simple!
- do_rhs env (_,rhs) = lvlFloatRhs abs_vars dest_lvl env Recursive
- is_bot NotJoinPoint
- rhs
+ do_rhs env (b,rhs) =
+ lvlFloatRhs abs_vars dest_lvl env' Recursive
+ is_bot NotJoinPoint rhs
+ where env' = pushBindContext env b
-- Finding the free vars of the binding group is annoying
bind_fvs = ((unionDVarSets [ freeVarsOf rhs | (_, rhs) <- pairs])
@@ -1632,16 +1637,17 @@ countFreeIds = nonDetStrictFoldUDFM add 0 . getUniqDSet
-}
data LevelEnv
- = LE { le_switches :: FloatOutSwitches
- , le_ctxt_lvl :: !Level -- The current level
- , le_lvl_env :: VarEnv Level -- Domain is *post-cloned* TyVars and Ids
+ = LE { le_switches :: FloatOutSwitches
+ , le_bind_ctxt :: [Id]
+ , le_ctxt_lvl :: !Level -- The current level
+ , le_lvl_env :: VarEnv Level -- Domain is *post-cloned* TyVars and Ids
-- See Note [le_subst and le_env]
- , le_subst :: Subst -- Domain is pre-cloned TyVars and Ids
- -- The Id -> CoreExpr in the Subst is ignored
- -- (since we want to substitute a LevelledExpr for
- -- an Id via le_env) but we do use the Co/TyVar substs
- , le_env :: IdEnv ([OutVar], LevelledExpr) -- Domain is pre-cloned Ids
+ , le_subst :: Subst -- Domain is pre-cloned TyVars and Ids
+ -- The Id -> CoreExpr in the Subst is ignored
+ -- (since we want to substitute a LevelledExpr for
+ -- an Id via le_env) but we do use the Co/TyVar substs
+ , le_env :: IdEnv ([OutVar], LevelledExpr) -- Domain is pre-cloned Ids
}
{- Note [le_subst and le_env]
@@ -1678,6 +1684,7 @@ The domain of the le_lvl_env is the *post-cloned* Ids
initialEnv :: FloatOutSwitches -> CoreProgram -> LevelEnv
initialEnv float_lams binds
= LE { le_switches = float_lams
+ , le_bind_ctxt = []
, le_ctxt_lvl = tOP_LEVEL
, le_lvl_env = emptyVarEnv
, le_subst = mkEmptySubst in_scope_toplvl
@@ -1690,6 +1697,9 @@ initialEnv float_lams binds
-- to a later one. So here we put all the top-level binders in scope before
-- we start, to satisfy the lookupIdSubst invariants (#20200 and #20294)
+pushBindContext :: LevelEnv -> Id -> LevelEnv
+pushBindContext env i = env { le_bind_ctxt = i : le_bind_ctxt env }
+
addLvl :: Level -> VarEnv Level -> OutVar -> VarEnv Level
addLvl dest_lvl env v' = extendVarEnv env v' dest_lvl
@@ -1829,11 +1839,12 @@ newPolyBndrs dest_lvl
| otherwise
= new_bndr
-newLvlVar :: LevelledExpr -- The RHS of the new binding
+newLvlVar :: LevelEnv
+ -> LevelledExpr -- The RHS of the new binding
-> JoinPointHood -- Its join arity, if it is a join point
-> Bool -- True <=> the RHS looks like (makeStatic ...)
-> LvlM Id
-newLvlVar lvld_rhs join_arity_maybe is_mk_static
+newLvlVar env lvld_rhs join_arity_maybe is_mk_static
= do { uniq <- getUniqueM
; return (add_join_info (mk_id uniq rhs_ty))
}
@@ -1848,7 +1859,12 @@ newLvlVar lvld_rhs join_arity_maybe is_mk_static
= mkExportedVanillaId (mkSystemVarName uniq (mkFastString "static_ptr"))
rhs_ty
| otherwise
- = mkSysLocal (mkFastString "lvl") uniq ManyTy rhs_ty
+ = mkSysLocal stem uniq ManyTy rhs_ty
+
+ stem =
+ case le_bind_ctxt env of
+ [] -> mkFastString "lvl"
+ ctx -> mkFastString $ intercalate "_" ("lvl" : map (occNameString . getOccName) ctx)
-- | Clone the binders bound by a single-alternative case.
cloneCaseBndrs :: LevelEnv -> Level -> [Var] -> LvlM (LevelEnv, [Var])
=====================================
testsuite/tests/codeGen/should_compile/T25177.stderr
=====================================
@@ -7,9 +7,9 @@ foo = \ ds -> case ds of { D a ds1 -> W# a }
d = D 10## RUBBISH(IntRep)
-lvl = foo d
+lvl_d = foo d
-bar1 = \ _ eta -> case lvl of { W# ipv -> (# eta, () #) }
+bar1 = \ _ eta -> case lvl_d of { W# ipv -> (# eta, () #) }
bar = bar1 `cast` <Co:6> :: ...
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/7cf39c79bdedc3f2a4736a92994d43…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/7cf39c79bdedc3f2a4736a92994d43…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/strict-level] 198 commits: Remove most of `GHC.Internal.Pack`
by Zubin (@wz1000) 23 Apr '25
by Zubin (@wz1000) 23 Apr '25
23 Apr '25
Zubin pushed to branch wip/strict-level at Glasgow Haskell Compiler / GHC
Commits:
3b78e139 by John Ericson at 2025-03-03T15:27:39-05:00
Remove most of `GHC.Internal.Pack`
Since bd82ac9f4716e28b185758ae514691d5a50c003f when `GHC.Pack` was
deleted, it is no longer used except for one function by the RTS.
- - - - -
b4fe0850 by Rodrigo Mesquita at 2025-03-03T15:28:16-05:00
ghci: Don't set virtualCWD on every iteration
The calls to withVirtualCWD were introduced to fix #2973, but this bug
is no longer reproducible, even when `withVirtualCWD` is dropped.
This cleanup was originally motivated by the performance of :steplocal,
but the performance problem has now been fixed at its root in the next
commit.
Even then, `withVirtualCWD` seems to now be an unnecessary artifact, and
removing it simplifies the interpreter with no apparent drawbacks (testsuite is
also happy with this change)
- - - - -
73ba1e6e by Rodrigo Mesquita at 2025-03-03T15:28:16-05:00
ghci debugger: improve break/resume control flow
After interpreting bytecode (`evalStmt`), we may want to hand off
control to "GHCi.UI" in order to display an interactive break prompt:
1. When an /active/ breakpoint (one set with :break ...) is hit
2. At any breakpoint, when using :step from a breakpoint
3. At any breakpoint in the same function f, when :steplocal is called
from a breakpoint in f
4. At any breakpoint in the same module, when :stepmodule is used
Whether to pass control to the UI is now fully determined by
`handleRunStatus` which transforms an `EvalStatus_` into an
`ExecResult`. When `ExecBreak` is returned from `handleRunStatus` to
GHCi, it always means GHCi breaks.
`handleRunStatus` determines whether to loop and resume evaluation right away, or
when to return to GHCi (by returning `ExecBreak` or `ExecComplete`).
- (1) is queried using the `BreakpointStatus` message (the
`breakpointStatus` call)
- (2,3,4) are determined by the predicate `breakHere step span`, which
inspects the improved `SingleStep` type to determine whether we care
about this breakpoint even if it is not active.
This refactor solves two big performance problems with the previous control flow:
- We no longer call `withArgs/withProgram` repeatedly in the
break/resume loop, but rather just once "at the top".
- We now avoid computing the expensive `bindLocalsAtBreakpoint` for
breakpoints we'd never inspect.
In the interpreter_steplocal test added, calling `:steplocal` after breaking on `main = fib 25`
now takes 12 seconds rather than 49 seconds on my machine.
```
interpreter_steplocal(ghci) ghc/alloc 6,124,821,176 540,181,392 -91.2% GOOD
```
Fixes #25779
-------------------------
Metric Decrease:
interpreter_steplocal
-------------------------
- - - - -
c78d8f55 by Cheng Shao at 2025-03-03T20:54:41+00:00
rts: fix top handler closure type signatures
This commit fixes the runIO/runNonIO closure type signatures in the
RTS which should be extern StgClosure. This allows us to remove an
unnecessary type cast in the C foreign desugaring logic, as well as
unneeded complications of JSFFI desugaring logic that also needs to
generate C stubs that may refer to those top handler closures.
Otherwise, we'll have to take special care to avoid generating "extern
StgClosure" declarations for them as we would for other closures, just
to avoid conflicting type signature error at stub compile time.
- - - - -
a204df3a by Cheng Shao at 2025-03-03T20:54:41+00:00
compiler: allow arbitrary label string for JSFFI exports
This commit allows arbitrary label string to appear in a foreign
export declaration, as long as the calling convention is javascript.
Well, doesn't make sense to enforce it's a C function symbol for a
JSFFI declaration anyway, and it gets in the way of implementing the
"sync" flavour of exports.
- - - - -
03ebab52 by Cheng Shao at 2025-03-03T20:54:41+00:00
compiler: wasm backend JSFFI sync exports
This commit implements the synchronous flavour of the wasm backend
JSFFI exports:
- `foreign export javascript "foo sync"` exports a top-level Haskell
binding as a synchronous JS function
- `foreign import javascript "wrapper sync"` dynamically exports a
Haskell function closure as a synchronous JS function
- `foreign import javascript unsafe` is now re-entrant by lowering to
a safe ccall
- Also fix the issue that JSFFI dynamic exports didn't really work in
TH & ghci (#25473)
- - - - -
b6ae908b by Cheng Shao at 2025-03-03T20:54:41+00:00
testsuite: test wasm backend JSFFI sync exports
This commit repurposes some existing JSFFI test cases to make them
cover JSFFI sync exports as well.
- - - - -
edae2874 by Cheng Shao at 2025-03-03T20:54:41+00:00
docs: document wasm backend JSFFI sync exports
This commit updates wasm backend documentation to reflect the new
JSFFI sync exports feature.
- - - - -
9b54eecb by Cheng Shao at 2025-03-03T20:56:21+00:00
wasm: add error message to WouldBlockException
This commit attaches an error message to WouldBlockException, for now
the error message consists of the JS async import code snippet that
thunk is trying to block for. This is useful for debugging synchronous
callbacks that accidentally call an async JS function.
- - - - -
c331eebf by Cheng Shao at 2025-03-04T09:11:45-05:00
compiler: avoid overwriting existing writers in putWithTables
This patch makes `putWithTables` avoid overwriting all existing
UserData writers in the handle. This is crucial for GHC API users that
use putWithUserData/getWithUserData for serialization logic that
involve Names.
- - - - -
e9b7802b by Matthew Pickering at 2025-03-04T09:12:21-05:00
ghci: Serialise mi_top_env
When loading core from interface files (or from a bytecode object in
future) it's important to store what the top-level context of a module
is.
Otherwise, when you load the module into GHCi from the interface files,
only exported identifiers from the top-level module are in scope on the
repl.
See the added test which demonstrates what this enables.
The context at the GHCi prompt is everything that's in-scope in the
TopEnvIface module. Since TopEnvIface imports identifier "a", we can
evaluate "a" in the repl.
In addition to all this, we can use this information in order to
implement reifyModule in a more principled manner.
This becomes even more important when you're debugging and what to set
break-points on functions which are not imported.
- - - - -
73e02068 by Matthew Pickering at 2025-03-04T09:12:21-05:00
Implement reifyModule in terms of mi_top_env
mi_top_env provides precisely the information that reifyModule needs,
the user written imports.
This is important as it unblocks !9604 and #22188
Fixes #8489
- - - - -
0a99825d by Ben Gamari at 2025-03-04T09:12:57-05:00
hadrian: Refactor handling of test suite environment
Previously we would set the environment variables used to run the
testsuite driver using `setEnv` to set them in the Hadrian process.
While looking into failures of a fix to #25752 I noticed this and took
the opportunity to refactor.
- - - - -
7ca72844 by Alan Zimmerman at 2025-03-04T09:13:34-05:00
[EPA] Sync with the ghc-exactprint repo
This brings it into line with the changes in
https://hackage.haskell.org/package/ghc-exactprint-1.12.0.0
But also keeps the latest changes from master.
- - - - -
8f6cc90c by Matthew Pickering at 2025-03-05T04:48:02-05:00
perf: Speed up the bytecode assembler
This commit contains a number of optimisations to the bytecode
assembler. In programs which generate a large amount of bytecode, the
assembler is called a lot of times on many instructions.
1. Specialise the assembleI function for the two intepreters to avoid
having to materialise the intermediate free-monad like structure.
2. Directly compute the UArray and SmallArray needed rather than going
via the intermediate SizedSeq
3. Use optimised monads
4. Define unrolled "any" and "mapM6" functions which can be inlined
and avoid calling recursive functions.
The resulting generated code is much more direct.
Before:
./ByteCodeAsm /home/matt/ghc-profiling-light/_build/stage1/lib/ +RTS -s
48,923,125,664 bytes allocated in the heap
678,221,152 bytes copied during GC
395,648 bytes maximum residency (2 sample(s))
50,040 bytes maximum slop
6 MiB total memory in use (0 MiB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 11731 colls, 0 par 0.419s 0.425s 0.0000s 0.0004s
Gen 1 2 colls, 0 par 0.001s 0.001s 0.0007s 0.0012s
INIT time 0.000s ( 0.000s elapsed)
MUT time 6.466s ( 6.484s elapsed)
GC time 0.421s ( 0.426s elapsed)
EXIT time 0.000s ( 0.000s elapsed)
Total time 6.887s ( 6.910s elapsed)
After:
1,518,321,200 bytes allocated in the heap
4,299,552 bytes copied during GC
322,288 bytes maximum residency (2 sample(s))
50,280 bytes maximum slop
6 MiB total memory in use (0 MiB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 369 colls, 0 par 0.003s 0.003s 0.0000s 0.0002s
Gen 1 2 colls, 0 par 0.001s 0.001s 0.0007s 0.0012s
INIT time 0.001s ( 0.001s elapsed)
MUT time 0.465s ( 0.466s elapsed)
GC time 0.004s ( 0.004s elapsed)
EXIT time 0.000s ( 0.000s elapsed)
Total time 0.470s ( 0.471s elapsed)
- - - - -
f2d43e11 by Teo Camarasu at 2025-03-05T04:48:40-05:00
ghc-boot-th: expose all TH packages from proper GHC.Boot.* modules
Previously we defined some modules here in the GHC.Internal namespace.
Others were merely re-exposed from GHC.Internal.
Re-exposed modules weren't handled correctly by Haddock, so the
Haddocks for the `template-haskell` library couldn't see them.
This change also makes the home package of these modules a bit clearer.
Work towards #25705
- - - - -
91ef82df by Teo Camarasu at 2025-03-05T04:48:40-05:00
ghc-boot-th: fix synopsis formatting
`@...@` syntax doesn't seem to work in synposes and is just kept by
Haddock verbatim.
- - - - -
eb9fe1ec by Brandon Chinn at 2025-03-05T04:49:17-05:00
Collapse string gaps as \& (#25784)
In 9.10, "\65\ \0" would result in "A0", but in 9.12, it results in
"\650", due to the string refactoring I did in !13128. Previously, we
were resolving escape codes and collapsing string gaps as we come across
them, but after the refactor, string processing is broken out into
phases, which is both more readable and useful for multiline strings.
- - - - -
8037f487 by Cheng Shao at 2025-03-05T04:49:54-05:00
ghc-experimental: make JSVal abstract in GHC.Wasm.Prim
This commit makes JSVal an abstract type in the export list of
GHC.Wasm.Prim. JSVal's internal representation is supposed to be a non
user facing implementation detail subject to change at any time. We
should only expose things that are newtypes of JSVal, not JSVal
itself.
- - - - -
4f342431 by Cheng Shao at 2025-03-05T04:49:54-05:00
wasm: make JSVal internal Weak# point to lifted JSVal
JSVal has an internal Weak# with the unlifted JSVal# object as key to
arrange its builtin finalization logic. The Weak# used to designate
Unit_closure as a dummy value; now this commit designates the lifted
JSVal closure as the Weak# value. This allows the implementation of
mkWeakJSVal which can be used to observe the liveliness of a JSVal and
attach a user-specified finalizer.
- - - - -
55af20e6 by Cheng Shao at 2025-03-05T04:49:54-05:00
ghc-experimental: add mkWeakJSVal
This commit adds a mkWeakJSVal function that can be used to set up a
Weak pointer with a JSVal key to observe the key's lifetime and
optionally attach a finalizer.
- - - - -
8273d7d1 by Matthew Pickering at 2025-03-05T04:50:30-05:00
simplifier: Zap Id unfoldings before constructing InScopeSet in simpleOptExpr
Care must be taken to remove unfoldings from `Var`s collected by exprFreeVars
before using them to construct an in-scope set hence `zapIdUnfolding` in `init_subst`.
Consider calling `simpleOptExpr` on an expression like
```
case x of (a,b) -> (x,a)
```
* One of those two occurrences of x has an unfolding (the one in (x,a), with
unfolding x = (a,b)) and the other does not. (Inside a case GHC adds
unfolding-info to the scrutinee's Id.)
* But exprFreeVars just builds a set, so it's a bit random which occurrence is collected.
* Then simpleOptExpr replaces each occurrence of x with the one in the in-scope set.
* Bad bad bad: then the x in case x of ... may be replaced with a version that has an unfolding.
Fixes #25790
- - - - -
07fe6d1d by Rodrigo Mesquita at 2025-03-05T04:51:07-05:00
docs: Fix ghci :doc documentation
Fixes #25799
- - - - -
a510b861 by Matthew Pickering at 2025-03-06T11:43:23+00:00
Add flag to control whether self-recompilation information is written to interface
This patch adds the flag -fwrite-if-self-recomp which controls whether
interface files contain the information necessary to answer the
question:
Do I need to recompile myself or is this current interface file
suitable?
Why? Most packages are only built once either by a distribution or cabal
and then placed into an immutable store, after which we will never ask
this question. Therefore we can derive two benefits from omitting this
information.
* Primary motivation: It vastly reduces the surface area for creating
non-deterministic interface files. See issue #10424 which motivated a
proper fix to that issue. Distributions have long contained versions
of GHC which just have broken self-recompilation checking (in order to
get deterministic interface files).
* Secondary motivation: This reduces the size of interface files
slightly.. the `mi_usages` field can be quite big but probably this
isn't such a great benefit.
* Third motivation: Conceptually clarity about which parts of an
interface file are used in order to **communicate** with subsequent
packages about the **interface** for a module. And which parts are
used to self-communicate during recompilation checking.
The main tracking issue is #22188 but fixes issues such as #10424 in a
proper way.
- - - - -
5b05c27b by Matthew Pickering at 2025-03-06T11:43:23+00:00
Disable self recomp in release flavour
The interface files that we distribute should not contain any
information which is used by the recompilation checking logic since
source file will never be compiled again.
I am not 100% sure this won't cause unexpected issues, there many be
downstream consumers which are incorrectly using the information from
interfaces, but this commit can be reverted if we detect issues.
- - - - -
1d4c9824 by Matthew Craven at 2025-03-06T18:11:59-05:00
Cmm: Add surface syntax for Word/Float bitcast ops
- - - - -
25c4a2a2 by Matthew Craven at 2025-03-06T18:11:59-05:00
Cmm: Add constant-folding for Word->Float bitcasts
- - - - -
30bdea67 by Matthew Craven at 2025-03-06T18:11:59-05:00
Add tests for #25771
- - - - -
44bf5fa1 by Matthew Pickering at 2025-03-07T13:48:18+00:00
iface: Store flags in interface files
When reporting the reason why a module is recompiled (using
`-dump-hi-diffs`), it is much more informative to inform the user about
which flag exactly has changed, rather than just an opaque reference to
a hash.
Now, when the user enables `-fwrite-if-self-recomp-flags`
there is a difference the precise part of the flags is
reported:
```
codegen flags changed:
before: [Opt_NoTypeableBinds, Opt_OmitYields]
after: [Opt_NoTypeableBinds, Opt_OmitYields, Opt_DictsStrict]
```
Fixes #25571
- - - - -
324222bd by Oleg Grenrus at 2025-03-08T08:50:18-05:00
Run fix-whitespace on compiler/
https://hackage.haskell.org/package/fix-whitespace
IMO this should be included into lint suite
- - - - -
1e53277a by sheaf at 2025-03-08T16:32:25-05:00
Allow defaulting of representational equalities
This commit generalises the defaulting of equality constraints that
was introduced in 663daf8d (with follow-up in 6863503c) to allow
the defaulting of *representational* equality constraints.
Now we default a representational equality
ty1 ~R# ty2
by unifying ty1 ~# ty2.
This allows the following defaulting to take place:
- Coercible alpha[tau] Int ==> alpha := Int
- Coercible (IO beta[tau]) (IO Char) ==> beta := Char
See Note [Defaulting representational equalities] in GHC.Tc.Solver.Default
for more details.
Fixes #21003
- - - - -
d6c40afc by Andreas Klebinger at 2025-03-08T16:33:02-05:00
Revert "Use `Infinite` in unique generation, and clean up some other partial uni patterns as well."
This reverts commit 643dd3d86968c527ba07ece9cc337728dbdfe2a0.
As described in #25817 this commit introduced a subtle bug in AArch64
code generation. So for the time being I will simply revert it
wholesale.
- - - - -
68310e11 by Andreas Klebinger at 2025-03-08T16:33:39-05:00
Properly describe acceptance window for stat tests.
The relative metric is already in %, so no need to multiply by 100.
- - - - -
cca68421 by Cheng Shao at 2025-03-08T22:04:42-05:00
wasm: do not use wasm type reflection in dyld
The wasm dynamic linker used to depend on v8's experimental wasm type
reflection support to generate stub functions when treating GOT.func
items that aren't exported by any loaded library yet. However, as we
work towards wasm ghci browser mode (#25399), we need to ensure the
wasm dyld logic is portable across browsers. So this commit removes
the usage of wasm type reflection in wasm dyld, and it shall only be
added many months later when this feature is widely available in
browsers.
- - - - -
75fcc5c9 by Cheng Shao at 2025-03-08T22:05:19-05:00
wasm: don't create a wasm global for dyld poison
There's a much more efficient way to convert an unsigned i32 to a
signed one. Thanks, o3-mini-high.
- - - - -
fd40eaa1 by Cheng Shao at 2025-03-08T22:05:19-05:00
wasm: revamp JSFFI internal implementation and documentation
This patch revamps the wasm backend's JSFFI internal implementation
and documentation:
- `JSValManager` logic to allocate a key is simplified to simple
bumping. According to experiments with all major browsers, the
internal `Map` would overflow the heap much earlier before we really
exhaust the 32-bit key space, so there's no point in the extra
complexity.
- `freeJSVal` is now idempotent and safe to call more than once. This
is achieved by attaching the `StablePtr#` to the `JSVal#` closure
and nullifying it when calling `freeJSVal`, so the same stable
pointer cannot be double freed.
- `mkWeakJSVal` no longer exposes the internal `Weak#` pointer and
always creates a new `Weak#` on the fly. Otherwise by finalizing
that `Weak#`, user could accidentally drop the `JSVal`, but
`mkWeakJSVal` is only supposed to create a `Weak` that observes the
`JSVal`'s liveliness without actually interfering it.
- `PromisePendingException` is no longer exported since it's never
meant to be caught by user code; it's a severe bug if it's actually
raised at runtime.
- Everything exported by user-facing `GHC.Wasm.Prim` now has proper
haddock documentation.
- Note [JSVal representation for wasm] has been updated to reflect the
new JSVal# memory layout.
- - - - -
cbae3708 by Ben Gamari at 2025-03-11T06:09:58-04:00
users guide: Fix typo
- - - - -
1951eb7a by Ben Gamari at 2025-03-11T06:10:35-04:00
testsuite: Don't count fragile passes as failures in JUnit output
As noted in #25806, the testsuite driver's JUnit output
previously considered passes of fragile tests to be failures. Fix this.
Closes #25806.
- - - - -
589f40b9 by Matthew Pickering at 2025-03-11T06:11:11-04:00
Use panic rather than error in expectJust
Otherwise, we would not get a callstack printed out when the exception
occurs.
Fixes #25829
- - - - -
d450e88e by sheaf at 2025-03-11T06:42:59-04:00
Solve Wanted quantified constraints from Givens
This commit ensures we directly solve Wanted quantified constraints from
matching inert Given quantified constraints,instead of going through the
trouble of emitting an implication constraint and processing that.
This is not just an optimisation; it makes our lives easier when
generating RULEs for specialisation.
See Note [Solving Wanted QCs from Given QCs] for details
Fixes #25758
- - - - -
48daaf53 by Ben Gamari at 2025-03-11T06:42:59-04:00
testsuite: Add testcase for #25577
- - - - -
d2ffb0ce by Ben Gamari at 2025-03-11T06:42:59-04:00
testsuite/ghc-api: Eliminate Makefile usage from various GHC API tests
These tests can be expressed perfectly well using the testsuite driver
itself.
- - - - -
2275b642 by Ben Gamari at 2025-03-11T06:42:59-04:00
rts/linker/MachO: Assert that GOT relocations have GOT entries
In #25577 we found that some GOT relocation types were not being given
relocation entries. Add assertions to catch this sort of failure in the
future.
- - - - -
8c96bcb4 by Ben Gamari at 2025-03-11T06:42:59-04:00
rts/linker/MachO: Account for internal GOT references in GOT construction
Previously we failed to give GOT slots to symbols which were referred to
by GOT relocations in the same module. This lead to #25577.
Fix this by explicitly traversing relocation lists and maintaining a
`needs_got` flag for each symbol.
Fixes #25577.
- - - - -
7b84c588 by Vladislav Zavialov at 2025-03-11T06:43:02-04:00
One list in ConPat (part of #25127)
This patch changes PrefixCon to use one list instead of two:
-data HsConDetails tyarg arg rec
- = PrefixCon [tyarg] [arg]
+data HsConDetails arg rec
+ = PrefixCon [arg]
| RecCon rec
| InfixCon arg arg
The [tyarg] list is now gone. To understand the effect of this change,
recall that there are three instantiations of HsConDetails:
1. type HsConPatDetails p =
HsConDetails (HsConPatTyArg (NoGhcTc p)) -- tyarg
(LPat p) -- arg
(HsRecFields p (LPat p)) -- rec
2. type HsConDeclH98Details pass =
HsConDetails Void -- tyarg
(HsScaled pass (LBangType pass)) -- arg
(XRec pass [LConDeclField pass]) -- rec
3. type HsPatSynDetails pass =
HsConDetails Void -- tyarg
(LIdP pass) -- arg
[RecordPatSynField pass] -- rec
In cases (2) and (3), tyarg was instantiated to Void, so the [tyarg]
list was always empty. Its removal is basically a no-op.
The interesting case is (1), which is used in ConPat to represent
pattern matching of the form (MkE @tp1 @tp2 p1 p2).
With this patch, its representation is changed as follows:
ConPat "MkE" [tp1, tp2] [p1, p2] -- old
ConPat "MkE" [InvisP tp1, InvisP tp2, p1, p2] -- new
The new mixed-list representation is consintent with lambdas, where
InvisP is already used to deal with \ @tp1 @tp2 p1 p2 -> body.
The immediate effect of the new representation is an improvement to
error messages. Consider the pattern (Con x @t y). Previously it
resulted in a parse error because @t could not occur after x. Now it is
reported as [GHC-14964]. Test case: TyAppPat_MisplacedApplication.
In the long term, this is intended as preparation for #18389 and #25127,
which would make (Con x @t y) potentially valid, e.g. if its type is
Con :: forall a -> forall b. (a, b) -> T
The TH AST is left unchanged for the moment to avoid breakage.
- - - - -
cce869ea by Vladislav Zavialov at 2025-03-11T06:43:02-04:00
Error message with EmptyCase and RequiredTypeArguments (#25004)
Fix a panic triggered by a combination of \case{} and forall t ->
ghci> let f :: forall (xs :: Type) -> (); f = \case {}
panic! (the 'impossible' happened)
GHC version 9.10.1:
Util: only
The new error message looks like this:
ghci> let f :: forall (xs :: Type) -> (); f = \case {}
<interactive>:5:41: error: [GHC-48010]
• Empty list of alternatives in \case expression
checked against a forall-type: forall xs -> ...
This is achieved as follows:
* A new data type, BadEmptyCaseReason, is now used to describe
why an empty case has been rejected. Used in TcRnEmptyCase.
* HsMatchContextRn is passed to tcMatches, so that the type checker
can attach the syntactic context to the error message.
* tcMatches now rejects type arguments if the list of alternatives is
empty. This is what fixes the bug.
- - - - -
37d8b50b by sheaf at 2025-03-11T06:43:06-04:00
user's guide: consolidate defaulting documentation
This commit adds a new section on defaulting, which consolidates various
parts of documentation surrounding defaulting into one central place.
It explains type class defaulting in detail, extensions to it with
OverloadedStrings, NamedDefaults and ExtendedDefaultRules, as well
as other defaulting mechanisms (e.g. kind-based defaulting such as
RuntimeRep defaulting, and defaulting of equalities).
- - - - -
0c9fd8d4 by sheaf at 2025-03-11T06:43:06-04:00
user's guide: flesh out XOverloadedStrings docs
This commit extends the documentation of the OverloadedStrings extension
with some usage information, in particular suggestions to:
- use default declarations, such as `default (Text)` or
`default IsString(Text)` (with the NamedDefaults extension),
- enable the ExtendedDefaultRules extension to relax the requirement
that a defaultable type variable must only appear in unary standard
classes
Fixes #23388
- - - - -
2df171d4 by sheaf at 2025-03-11T06:43:06-04:00
user's guide: NamedDefaults vs ExtendedDefaultRules
This commit clarifies the defaulting rules with NamedDefaults,
in particular in situations where a type variable appears in other
constraints than standard/unary constraints.
- - - - -
77df05d0 by Matthew Pickering at 2025-03-11T06:43:07-04:00
Take into account all flags when computing iface_hash
The "interface hash" should contain a hash of everything in the
interface file. We are not doing that yet but at least a start is to
include a hash of everything in `mi_self_recomp`, rather than just
`mi_src_hash` and `mi_usages`.
In particular, this fixes #25837, a bug where we should recompile a
`dyn_hi` file but fail to do so.
- - - - -
48b8f110 by Matthew Pickering at 2025-03-11T06:43:07-04:00
Pass -fPIC to dynamicToo001 test to avoid platform dependence issues
On darwin platforms, `-fPIC` is always enabled but on linux it is only
enabled in the dynamic flavour. This can cause a difference in
interface files (see #25836).
The purpose of this test isn't to test module A recompilation, so we
avoid this platform dependency by always passing `-fPIC`.
- - - - -
03c72f01 by Matthew Pickering at 2025-03-11T06:43:07-04:00
Remove mi_used_th field from interface files
In the distant past, recompilation checking was disabled for interfaces which used
TemplateHaskell, but for several years now recompilation checking has
been more fine-grained. This has rendered this field unused and
lingering in an interface file.
- - - - -
6bb0e261 by Matthew Pickering at 2025-03-11T06:43:07-04:00
Remove mi_hpc field from interface files
The `mi_hpc` field is not used for anything as far as I can discern so
there is no reason to record in the private interface of a module that
there are modules in the transitive closure which use `hpc`.
You can freely mix modules which use `-fhpc` and ones which don't.
Whether to recompile a module due to `-fhpc` being passed to the module
itself is determined in `fingerprintDynFlags`.
- - - - -
b6d5b091 by Simon Peyton Jones at 2025-03-11T22:39:23-04:00
We can't UNPACK multi-constructor GADTs
This MR fixes #25672
See Note [Unpacking GADTs and existentials] in GHC.Types.Id.Make
- - - - -
8eae151d by Teo Camarasu at 2025-03-11T22:40:00-04:00
template-haskell: Add explicit exports lists to all remaining modules
- - - - -
db621b58 by Teo Camarasu at 2025-03-11T22:40:00-04:00
template-haskell: fix haddocks
It seems that we need a direct dependency on ghc-internal, otherwise
Haddock cannot find our haddocks
The bug seems to be caused by Hadrian because if I rebuild with
cabal-install (without this extra dependency) then I get accurate
Haddocks.
Resolves #25705
- - - - -
64ea68d9 by Ben Gamari at 2025-03-12T07:11:51-04:00
mk-ghcup-metadata: Clean up and add type annotations
Getting this file right has historically been quite painful as it is a
dynamically-typed script running only late in the release pipeline.
- - - - -
b3f80b07 by Ben Gamari at 2025-03-12T07:12:27-04:00
rts: Drop imports of pthreads functions in cmm sources
These are no longer used. I noticed these while looking for uses of
__PIC__ in Cmm sources.
- - - - -
915a6781 by Matthew Pickering at 2025-03-13T01:46:41-04:00
interfaces: Ensure that forceModIface deeply forces a ModIface
A ModIface is the result of compilation that we keep for a long time in
memory. Therefore, it's very important to manage what we are going to
retain and remove any external references to things which we might have
captured compilation.
If storing your ModIface in memory uses too much space, then store
less things or make it use a more efficient representation.
In the past there have been many space leak bugs by not sufficiently
forcing a ModIface (#15111)
This patch adds all the missing NFData instances for all the places I
could find where we weren't deeply forcing the structure.
- - - - -
24d373a6 by Matthew Craven at 2025-03-13T01:47:18-04:00
Add interface-stability test for ghc-prim
- - - - -
0cb1db92 by sheaf at 2025-03-14T13:11:44-04:00
Don't report used duplicate record fields as unused
This commit fixes the bug reported in #24035 in which the import of a
duplicate record field could be erroneously reported as unused.
The issue is that an import of the form "import M (fld)" can import
several different 'Name's, and we should only report an error if ALL
of those 'Name's are unused, not if ANY are.
Note [Reporting unused imported duplicate record fields]
in GHC.Rename.Names explains the solution to this problem.
Fixes #24035
- - - - -
f1830d74 by Matthew Pickering at 2025-03-14T13:12:21-04:00
binary: Directly copy ShortByteString to buffer rather than go via ByteString
This avoids allocating an intermediate bytestring. I just noticed on a
profile that `putFS` was allocating, and it seemed strange to me why
since it should just copy the contents of the FastString into the
already allocated buffer. It turned out we were going indirectly via a
ByteString.
Fixes #25861
- - - - -
b15fca2b by Matthew Pickering at 2025-03-15T05:36:40-04:00
iface: Store logical parts of ModIface together
The ModIface structure is divided into several logical parts:
1. mi_mod_info: Basic module metadata (name, version, etc.)
2. mi_public: The public interface of the module (the ABI), which includes:
- Exports, declarations, fixities, warnings, annotations
- Class and type family instances
- Rewrite rules and COMPLETE pragmas
- Safe Haskell and package trust information
- ABI hashes for recompilation checking
4. mi_self_recomp: Information needed for self-recompilation checking
(see Note [Self recompilation information in interface files])
5. mi_simplified_core: Optional simplified Core for bytecode generation
(only present when -fwrite-if-simplified-core is enabled)
6. mi_docs: Optional documentation (only present when -haddock is enabled)
7. mi_top_env: Information about the top-level environment of the original source
8. mi_ext_fields: Additional fields for extensibility
This structure helps organize the interface data according to its purpose and usage
patterns. Different parts of the compiler use different fields. By separating them
logically in the interface we can arrange to only deserialize the fields that are needed.
This patch also enforces the invariant that the fields of ModIface are
lazy. If you are keeping a ModIface on disk, then force it using
`forceModIface`. Otherwise, when the `ModIface` is read from disk, only
the parts which are needed from the interface will be deserialised.
In a follow-up patch I will tackle follow-up issues:
* Recompilation checking doesn't take into account exported named defaults (#25855)
* Recompilation checking does not take into account COMPLETE pragmas (#25854)
* mi_deps_ field in an interface is confused about whether the
information is for self-recompilation checking or part of the ABI
(#25844)
Fixes #25845
-------------------------
Metric Decrease:
MultiLayerModulesDefsGhciWithCore
-------------------------
- - - - -
c758cb71 by Ben Gamari at 2025-03-15T05:37:17-04:00
configure: Fix incorrect SettingsLlvmAsFlags value
Previously this was set to `LlvmAsCmd` rather than `LlvmAsFlags`,
resulting in #25856.
- - - - -
cfaaca14 by sheaf at 2025-03-18T20:05:03-04:00
Fix buglet in isEmptyWorkList
There was a missing case in GHC.Tc.Solver.InertSet.isEmptyWorkList; it
mistakenly ignored the 'wl_rw_eqs' field. This commit simply fixes that.
No test case.
- - - - -
9f9fe0b3 by sheaf at 2025-03-18T20:05:03-04:00
Add mapMaybeTM method to TrieMap class
This commit adds a new method to the TrieMap class, mapMaybeTM, and
adds implementations to all the instances.
mapMaybeTM is useful when filtering containers that contain other
containers.
- - - - -
393531ff by Simon Peyton Jones at 2025-03-18T20:05:03-04:00
Specialising expressions -- at last
This MR addresses #24359, which implements the GHC proposal 493 on SPECIALISE pragmas.
* The old code path (using SpecSig and SpecPrag) still exists.
* The new code path (using SpecSigE and SpecPragE) runs alongside it.
* All SPECIALISE pragmas are routed through the new code path, except
if you give multiple type sigs, when the old code path is still used.
* Main documentation: Note [Handling new-form SPECIALISE pragmas] in
GHC.Tc.Gen.Sig`
Thanks to @sheaf for helping with this MR.
The Big Thing is to introduce
{-# SPECIALISE forall x. f @Int x True #-}
where you can give type arguments and value argument to specialise; and
you can quantify them with forall, just as in Rules.
I thought it was going to be pretty simple, but it was a Long, Long Saga.
Highlights
* Overview Note [Handling new-form SPECIALISE pragmas] in GHC.Tc.Gen.Sig
- New data constructor `SpecSigE` in data type `L.H.S.Binds.Sig`
- New data construtor `SpecPragE` in data type `GHC.Hs.Binds.TcSpecPrag`
- Renamer: uses `checkSpecESigShape` to decide which function to assocate the
SPECIALISE pragma with
- Some of the action is in `GHC.Tc.Gen.Sig.tcSpecPrag`
- The rest is in `GHC.HsToCore.Binds.dsSpec`
* We use a new TcS mode, TcSFullySolve, when simplifying the Wanteds
that arise from the specialise expression. The mechanism is explained
in Note [TcSFullySolve] in GHC.Tc.Solver.Monad. The reason why we need
to do this is explained in Note [Fully solving constraints for specialisation]
in GHC.Tc.Gen.Sig.
* All of GHC.Tc.Gen.Rule is moved into GHC.Tc.Gen.Sig, because the code is
very closely related.
* The forall'd binders for SPECIALISE are the same as those for a RULE, so I
refactored, introducing data type `L.H.S.Binds.RuleBndrs`, with functions
to rename, zonk, typecheck it. I refactored this data type a bit; nicer now.
* On the LHS of RULES, or SPECIALISE, we want to disable the tricky mechanims
described in Note [Desugaring non-canonical evidence] in GHC.HsToCore.Expr.
Previously it wasn't fully disabled (just set to the empty set), and that
didn't quite work in the new regime.
* There are knock-on changes to Template Haskell.
* For the LHS of a RULE and a SPECIALISE expression, I wanted to simplify
it /without/ inlining the let-bindings for evidence variables. I added
a flag `so_inline` to the SimpleOpt optimiser to support this. The
entry point is `GHC.Core.SimpleOpt.simpleOptExprNoInline`
* Since forever we have had a hack for type variables on the LHS of
RULES. I took the opportunity to tidy this up. The main action is
in the zonker. See GHC.Tc.Zonk.Type Note [Free tyvars on rule LHS],
and especially data construtor `SkolemiseFlexi`
in data type `GHC.Tc.Zonk.Env.ZonkFlexi`
* Move `scopedSort` from GHC.Core.TyCo.FVs to GHC.Core.Predicate
Reason: it now works for Ids as well, and I wanted to use isEvVar,
which is defined in GHC.Core.Predicate
Avoiding module loops meant that instead of exporting GHC.Core.TyCo.Tidy
from GHC.Core.Type, modules now import the former directly.
I also took the opportunity to remove unused exports
from GHC.Core.Type.hs-boot
* Flag stuff:
- Add flag `-Wdeprecated-pragmas` and use it to control the warning when
using old-style SPECIALISE pragmas with multiple type ascriptions,
- Add flag `-Wuseless-specialisations` and use it to control the warning emitted
when GHC determines that a SPECIALISE pragma would have no effect. Don't
want if the SPECIALISE is SPECIALISE INLINE (#4444)
In response to #25389, we continue to generate these seemingly code for these
seemingly useless SPECIALISE pragmas
- Adds deprecations to Template Haskell `pragSpecD` and `pracSpecInlD`,
* Split up old-style SPECIALISE pragmas in GHC.Internal.Float,
GHC.Internal.Numeric, GHC.Internal.Real
* Remove useless SPECIALISE pragmas in Data.Array (updating the array submodule)
Smaller things:
- Update the Users Guide
- Add mention of the changes to the 9.14 release notes as well as
the Template Haskell changelog,
- - - - -
1884dd1a by Simon Peyton Jones at 2025-03-18T20:05:03-04:00
Add -Wrule-lhs-equalities warning
This commit adds a new warning, controlled by the warning flag,
-Wrule-lhs-equalities, which is emitted when the LHS of a RULE gives
rise to equality constraints that previous GHC versions would have
quantified over.
GHC instead discards such RULES, as GHC was never able to generate
a rule template that would ever fire; it's better to be explicit about
the fact that the RULE doesn't work.
- - - - -
b00b3ef0 by Ben Gamari at 2025-03-18T20:05:41-04:00
compiler: Add export list to GHC.SysTools.Process
This also revealed that `readProcessEnvWithExitCode` and its local
helpers were dead code.
- - - - -
25850b22 by ARATA Mizuki at 2025-03-18T20:06:25-04:00
Fix code generation for SSE vector operations
The new implementation generates correct code
even if the registers overlap.
Closes #25859
- - - - -
e576468c by Andreas Klebinger at 2025-03-18T20:07:02-04:00
Bump nofib submodule.
Fixes #25867. (Ben-raytrace being broken by library changes)
- - - - -
443fc8b1 by Sjoerd Visscher at 2025-03-19T12:01:04-04:00
Multiplicity annotation on records
Needing to store multiplicity annotations on records triggered a refactoring of AST of data declarations:
Moved HsBangTy and HsRecTy from HsType to HsTypeGhcPsExt, the extension of HsType during parsing, since they are only needed during parsing.
New HsConDeclField that stores all source data shared by all constructor declaration fields: unpackedness, strictness, multiplicity, documentation and the type of the field.
Merged HsMultAnn and HsArrowOf, so all multiplicity annotations share the same data type.
HsBang was no longer needed as a separate type, and was inlined into HsSrcBang.
- - - - -
313cf271 by Ben Gamari at 2025-03-19T12:01:43-04:00
gitlab-ci: Drop CentOS 7 binary distributions
CentOS 7 is EoL and moreover we cannot even build images for it.
See #25061.
- - - - -
5b94f99f by Ben Gamari at 2025-03-19T12:02:21-04:00
rts: Ensure that WinIO flag is set when --io-manager=auto
As noted in #25838, previously `selectIOManager` failed to set
`rts_IOManagerIsWin32Native` in its `IO_MNGR_FLAG_AUTO`. This meant
that the MIO path was taken when WinIO was supposedly selected,
resulting in chaos.
Fixes #25838.
- - - - -
1a3f1131 by Peng Fan at 2025-03-19T12:03:10-04:00
Pass the mcmodel=medium parameter to CC via GHC
Ensure that GHC-driver builds default to mcmodel=medium, so that GHC
passes this default parameter to CC without having to add it to the
compiled project.
Commit e70d41406b5d5638b42c4d8222cd03e76bbfeb86 does not ensure that all
GHC-built object files have a default model of medium, and will raise an
R_LARCH_B26 overflow error.
- - - - -
27cf7361 by Matthew Craven at 2025-03-19T12:03:48-04:00
Add interface-stability test for ghc-bignum
As with ghc-prim, it makes sense to have some protection against
accidental interface changes to this package caused by changes
in ghc-internal.
- - - - -
25d46547 by Matthew Craven at 2025-03-19T12:03:48-04:00
Add README reference for the interface-stability tests
- - - - -
5d65393e by Simon Peyton Jones at 2025-03-20T05:41:24-04:00
Remove the Core flattener
This big MR entirely removes the "flattener" that took a type and
replaced each type-family application with a fresh type variable.
The flattener had its origin in the paper
Injective type families for Haskell
But (a) #25657 showed that flattening doesn't really work.
(b) since we wrote the paper we have introduced the so-called
"fine-grained" unifier GHC.Core.Unify, which can return
* SurelyApart
* Unifiable subst
* MaybeApart subst
where the MaybeApart says that the two types are not unifiable by a
substitution, but could (perhaps) be unified "later" after some type
family reductions. This turns out to subsume flattening.
This MR does a major refactor of GHC.Core.Unify to make it capable of
subsuming flattening. The main payload is described in
Note [Apartness and type families]
and its many wrinkles.
The key (non-refactoring) implementation change is to add `um_fam_env`
to the `UMState` in the unification monad.
Careful review with Richard revealed various bugs in the treament of
`kco`, the kind coercion carried around by the unifier, so that is
substantially fixed too: see Note [Kind coercions in Unify].
Compile-time performance is improved by 0.1% with a few improvements over
1% and one worsening by 1.3% namely T9872a. (I have not investigated the
latter.)
Metric Decrease:
T9872b
T9872c
TcPlugin_RewritePerf
Metric Increase:
T9872a
- - - - -
9003ef0a by sheaf at 2025-03-20T05:42:08-04:00
Remove SDoc from UnknownSubordinate/MissingBinding
This commit replaces unstructured SDoc arguments in error message constructors
with uses of the following two datatypes:
- SigLike: for different kinds of signatures (e.g. standalone kind signatures,
fixity signatures, COMPLETE pragmas, etc)
- Subordinate: for class methods, associated types, and record fields
The following error message constructors now no longer have any SDocs in them:
- TcRnIllegalBuiltinSyntax: SDoc -> SigLike
- MissingBinding: SDoc -> SigLike
- UnknownSubordinate: SDoc -> (Name, Subordinate)
- SuggestMoveToDeclarationSite: SDoc -> SigLike
- - - - -
4329f3b6 by sheaf at 2025-03-20T05:42:08-04:00
Remove SDocs from HsDocContext
This commit removes the remaining SDocs from the HsDocContext data type.
It adds the following constructors:
ClassInstanceCtx -- Class instances
ClassMethodSigCtx -- Class method signatures
SpecialiseSigCtx -- SPECIALISE pragmas
PatSynSigCtx -- Pattern synonym signatures
We now report a bit more information for errors while renaming class instances,
which slightly improves renamer-emitted error messages.
- - - - -
75c29aa1 by sheaf at 2025-03-20T05:42:08-04:00
Reject instance with non-class head in renamer
This commit modifies rnClsInstDecl so that, when renaming, we reject a class
instance declaration in which the head is not a class. Before this change, it
would get rejected in the type-checker, but that meant that the renamer could
emit unhelpful error messages, e.g.:
data Foo m a
instance Foo m where
fmap _ x = case x of
would rather unhelpfully say:
‘fmap’ is not a (visible) method of class ‘Foo’
when of course 'Foo' is not even a class. We now reject the above program
with the following error message:
Illegal instance for data type ‘Foo’.
Instance heads must be of the form
C ty_1 ... ty_n
where ‘C’ is a class.
Fixes #22688
- - - - -
a8f543a9 by Cheng Shao at 2025-03-20T18:47:19-04:00
testsuite: mark T7919 as fragile on i386 as well
T7919 may also fail i386 CI jobs with test timeout.
- - - - -
256ac29c by sheaf at 2025-03-20T18:48:07-04:00
Don't cache solved [W] HasCallStack constraints
This commit ensures we do not add solved Wanted constraints that mention
HasCallStack or HasExceptionContext constraints to the set of solved
Wanted dictionary constraints: caching them is invalid, because re-using
such cached dictionaries means using an old call-stack instead of
constructing a new one, as was reported in #25529.
Fixes #25529.
- - - - -
47646ce2 by Andrew Lelechenko at 2025-03-20T18:48:43-04:00
Improve haddock-visible documentation for GHC.Driver.Flags
- - - - -
2e4e15ed by Sylvain Henry at 2025-03-21T17:49:36-04:00
Document -fnum-constant-folding (#25862)
- - - - -
044a6e08 by sheaf at 2025-03-21T17:50:24-04:00
LLVM: fix typo in padLiveArgs
This commit fixes a serious bug in the padLiveArgs function, which
was incorrectly computing too many padding registers. This caused
segfaults, e.g. in the UnboxedTuples test.
Fixes #25770
Fixes #25773
- - - - -
1745c749 by Teo Camarasu at 2025-03-22T18:42:37-04:00
template-haskell: remove Language.Haskell.TH.Lib.Internal
This module is purely used for the implementation of TH quote
desugarring.
Historically this needed to be exposed from `template-haskell`, since
that's the package that the desugarred expressions referenced but since
https://gitlab.haskell.org/ghc/ghc/-/merge_requests/12479, this is no
longer the case.
Now these identifiers are in `ghc-internal`.
Note that this module has carried the following warning for a long time:
> This is not a part of the public API, and as such, there are no API guarantees for this
module from version to version.
Resolves #24766
- - - - -
3bc507db by Alan Zimmerman at 2025-03-22T18:43:13-04:00
EPA: Fix exact printing of SPECIALISE pragma
This commit fixes two minor issues with exactprinting of the
SPECIALISE pragma after !12319 landed
- The span for the RHS did not include the optional signature type
- The `::` was printed twice when the legacy path was used
Closes #25885
- - - - -
bdf93da8 by sheaf at 2025-03-24T11:25:12+01:00
Renamer: improve handling of export children
This commit refactors the 'childGREPriority' function which is used when
renaming subordinate items in export lists and class declarations.
Instead of having a complicated LookupChild parameter, we now simply pass the
GREInfo of the parent, which allows us to decide what is a valid child:
- classes can have children that are in the type constructor namespace,
- promoted data constructors should be treated the same as normal data
constructors.
Fixes #24027
- - - - -
1dbc7846 by Matthew Pickering at 2025-03-24T15:35:17-04:00
Revert "mk-ghcup-metadata: Clean up and add type annotations"
This reverts commit 64ea68d9a206ec4db5020b0a3fc563199ab18be3.
See #25889
- - - - -
6941c825 by doyougnu at 2025-03-25T10:05:58-04:00
base: construct compat RTSFlags
-- see CLC #289
- - - - -
730e6f77 by doyougnu at 2025-03-25T10:06:02-04:00
base: construct compat GHC.Stats
-- see CLC #289
- - - - -
cd9e6605 by Ben Gamari at 2025-03-25T17:59:52-04:00
rel_eng/upload: Clarify usage directions
Previously it was not made clear that the directory name is significant.
- - - - -
7d18c19b by Cheng Shao at 2025-03-25T22:00:56+00:00
ghci: make the Pipe type opaque
This commit makes the Pipe type in ghci opaque, and introduce the
mkPipeFromHandles constructor for creating a Pipe from a pair of
Handles. Pipe is now just a pair of receiver/sender continuations
under the hood. This allows a Pipe to be potentially backed by other
IPC mechanisms (e.g. WebSockets) which is essential for wasm ghci
browser mode.
- - - - -
a2103fd2 by Cheng Shao at 2025-03-25T22:00:56+00:00
ghci: use improved Pipe logic for wasm iserv
This commit makes wasm iserv take advantage of the Pipe refactoring by
passing binary receiver/sender js callbacks from the dyld script. This
paves the way for piping the binary messages through WebSockets in
order to run wasm iserv in the browser, but more importantly, it
allows us to get rid of a horrible hack in the dyld script: we no
longer have to fake magical wasi file descriptors that are backed by
nodejs blocking I/O! The legacy hack was due to these facts:
- iserv only supported exchanging binary messages via handles backed
by file descriptors
- In wasi you can't access host file descriptors passed by host ghc
- The nodejs wasi implementation only allows mapping host directories
into the wasi vfs, not host file descriptors
- Named pipes with file paths (mkfifo) doesn't work well with nodejs
wasi implementation, causes spurious testsuite failures on macos
But starting from this point, we can fully take advantage of
non-blocking I/O on the js side.
- - - - -
fa2fbd2b by Cheng Shao at 2025-03-25T22:00:56+00:00
ghci: fix ^C handling for wasm iserv
This commit fixes ^C handling for wasm iserv. Previously we didn't
handle it at all, so ^C would kill the node process and host ghc would
then crash as well. But native ghc with external interpreter can
handle ^C just fine and wasm should be no different. Hence the fix:
wasm iserv exports its signal handler as a js callback to be handled
by the dyld script. Also see added note for details.
- - - - -
efcebed6 by Cheng Shao at 2025-03-25T22:00:56+00:00
wasm: fix post-link.mjs for browser
The wasm ghci browser mode needs to run dyld.mjs in the browser which
imports post-link.mjs. This script makes post-link.mjs runnable in the
browser by deferring node-specific module imports to their actual use
sites.
- - - - -
27bb73c6 by Cheng Shao at 2025-03-25T22:00:56+00:00
wasm: use console.assert in dyld script
This commit uses console.assert() instead of node-specific strict
assert in the dyld script, in order to make it runnable in the
browser. console.assert() only warns and doesn't crash upon assertion
failure, but this is fine; we can always trivially define a strict
assert function shall it be necessary when debugging, and there hasn't
been such an assertion failure seen in the wild for long enough.
- - - - -
929df0ba by Cheng Shao at 2025-03-25T22:00:56+00:00
wasm: asyncify the dylink.0 custom section parser
This commit refactors the simple binary parser in the dyld script in
charge of parsing the dylink.0 custom section. Previously the parser
was synchronous and operated on the entire input buffer; this was
simple and easy and worked well enough when the input wasm modules are
instantly read from local filesystem.
However, when running dyld in the browser, the wasm modules are
transferred via fetch() requests. The host ghc and the browser might
not be on the same machine, so slow network uplink does need to be
considered. We only need to parse dylink.0 custom section to extract
dependency info, and dylink.0 is the very first custom section in the
wasm shared library binary payload, so the parsing process should not
require fetch() to complete and should return the parsing result asap.
Hence the refactorings in this commit: asyncify the parser, make it
only consume as many bytes as needed by invoking an async consumer
callback. The input is a readable stream from the fetch() response;
once the response is available, the async wasm compilation can start
in the background, and dylink.0 parsing shall end asap which results
in more wasm shared libraries to be loaded earlier. Profit.
- - - - -
9a697181 by Cheng Shao at 2025-03-25T22:00:56+00:00
wasm: fix dyld setImmediate usage in browser
The wasm dyld script used to only run in node and directly uses
setImmediate in globalThis. In case of browsers, it needs to import
setImmediate from the prelude, hence this commit.
- - - - -
d9b71e82 by Cheng Shao at 2025-03-25T22:00:57+00:00
wasm: fix dyld downsweep filepath handling in browser
The wasm dyld downsweep logic used to rely on nodejs path module to
handle filepaths. That's not available in browsers, so this commit
implements poor man's filepath handling in js, which is not elegant
for sure but works for both nodejs and the browser.
- - - - -
7003a399 by Cheng Shao at 2025-03-25T22:00:57+00:00
wasm: isolate nodejs-specific logic with the isNode flag in dyld
As we move towards supporting running the dyld script in the browser,
this commit implements the isNode module-level binding which is true
if dyld is running in nodejs. The nodejs-specific bits are gated under
isNode.
For the browser case, this commit introduces @bjorn3/browser_wasi_shim
as the wasi implementation; we already use it in quite a few projects
and it simply works.
- - - - -
22ba2a78 by Cheng Shao at 2025-03-25T22:00:57+00:00
wasm: isolate dyld side effects that might require IPC
This commit spins out a DyLDHost class from DyLD that handles side
effects that must be run in the same host environment that runs
wasm32-wasi-ghc. When the dyld script runs in the browser, it'll need
to do IPC to find libraries, fetch wasm library, etc, and the other
side of dyld that runs on nodejs would simply expose the DyLDHost
methods as endpoints for WebSockets/HTTP.
- - - - -
e93fc33d by Cheng Shao at 2025-03-25T22:00:57+00:00
wasm: implement wasm ghci browser mode
This commit implements the rest of dyld logic that delivers the ghci
browser mode:
- The dyld script can now fully run in the browser. It communicates
back with dyld-on-nodejs via WebSockets and also plain HTTP 1.1
requests.
- The host dyld starts a server and acts as a broker between the GHC
process and the browser side. GHC doesn't need to know anything
about the browser mode; no driver flags need to be added and no
recompilation needs to happen, the GHC driver continues to use the
original iserv binary messages protocol.
- The dyld broker doesn't need to parse any message between the
browser dyld and GHC; it merely sets up WebSockets connections to
redirect these messages as well as ^C signals.
- Plain HTTP 1.1 is used for IPC requests (e.g. downloading a wasm
module).
- The dyld broker serves a main.js script that bootstraps iserv in the
browser, and a main.html empty page playground for testing. CORS is
enabled so it could be possible to inject iserv into other websites
and use ghci to play with them.
- All the RPC logic is opaque to the DyLD class, the majority of the
wasm dynamic linker code is already portable and runs fine in
firefox/chrome/webkit.
Closes #25399.
- - - - -
fc576798 by Cheng Shao at 2025-03-25T22:00:57+00:00
wasm: add puppeteer/playwright support for ghci browser mode
This commit adds support for using puppeteer/playwright for
automatically launching a headless browser that backs the ghci browser
mode. This is useful for testing the ghci browser mode as a part of
GHC testsuite, and it's also convenient for local development since
the step to start iserv can be automated away.
- - - - -
ad7e271d by Cheng Shao at 2025-03-25T22:00:57+00:00
wasm: support wasi console redirect for the ghci browser mode
This commit adds optional support for redirecting wasi console
stdout/stderr back to the host when running wasm ghci browser mode. By
default, the wasi console outputs are only available under F12
devtools console, but in case of testing against a mobile browser, the
devtools console may not be readily available, and it would be more
convenient to at least get wasi console output on the host side.
The redirection logic is simple, just adding another two WebSockets
connections that pump the line-buffered textual messages back to
host.
- - - - -
731217ce by Cheng Shao at 2025-03-25T22:00:57+00:00
wasm: add brotli compression for ghci browser mode
This commit adds brotli compression for wasm shared libraries for ghci
browser mode. With BROTLI_MIN_QUALITY, the overhead is negligible, and
it helps reducing amount of transferred data when the browser connects
to the server over a slow connection.
- - - - -
ac70e643 by Cheng Shao at 2025-03-26T13:37:19+00:00
testsuite: add browser001 test for wasm ghci browser mode
This commit adds support for testing the wasm ghci browser mode in the
testsuite, as well as a simple first test case browser001 that makes
use of TH, JSFFI and browser-specific DOM API. See added note and
comments for details.
- - - - -
6ef5c0d2 by Cheng Shao at 2025-03-26T13:37:24+00:00
docs: add wasm ghci subsection in user manual
This commit updates the user manual to add wasm ghci subsection.
- - - - -
37381bcf by Cheng Shao at 2025-03-26T13:37:24+00:00
docs: update Note [The Wasm Dynamic Linker]
This commit updates Note [The Wasm Dynamic Linker] to reflect recent
developments, in particular the wasm ghci browser mode.
- - - - -
4b5a0f61 by Cheng Shao at 2025-03-26T13:37:24+00:00
ci: bump DOCKER_REV and test wasm ghci browser mode
This commit bumps the ci-images revision for updated wasm toolchain,
and adds the launch options required to test wasm ghci browser mode.
- - - - -
c6a3bc8f by Cheng Shao at 2025-03-26T13:37:24+00:00
driver: implement wasm ghci browser mode flags
This commit implements GHC driver flags that enable the wasm ghci
browser mode.
- - - - -
f75e823e by Cheng Shao at 2025-03-26T18:01:54-04:00
rts: add hs_try_putmvar_with_value to RTS API
This commit adds hs_try_putmvar_with_value to rts. It allows more
flexibility than hs_try_putmvar by taking an additional value argument
as a closure to be put into the MVar. This function is used & tested
by the wasm backend runtime, though it makes sense to expose it as a
public facing RTS API function as well.
- - - - -
9cd9f347 by Cheng Shao at 2025-03-26T18:01:54-04:00
wasm: use MVar as JSFFI import blocking mechanism
Previously, when blocking on a JSFFI import, we push a custom
stg_jsffi_block stack frame and arrange the `promise.then` callback to
write to that stack frame. It turns out we can simply use the good old
MVar to implement the blocking logic, with a few benefits:
- Less maintenance burden. We can drop the stg_jsffi_block related Cmm
code without loss of functionality.
- It interacts better with existing async exception mechanism. throwTo
would properly block the caller if the target thread is masking
async exceptions.
- - - - -
da34f0aa by Cheng Shao at 2025-03-26T18:01:54-04:00
wasm: properly pin the raiseJSException closure
We used to use keepAlive# to pin the raiseJSException closure when
blocking on a JSFFI import thunk, since it can potentially be used by
RTS. But raiseJSException may be used in other places as well (e.g.
the promise.throwTo logic), and it's better to simply unconditionally
pin it in the JSFFI initialization logic.
- - - - -
dc904bfd by Cheng Shao at 2025-03-26T18:01:54-04:00
wasm: implement promise.throwTo() for async JSFFI exports
This commit implements promise.throwTo() for wasm backend JSFFI
exports. This allows the JavaScript side to interrupt Haskell
computation by raising an async exception. See subsequent docs/test
commits for more details.
- - - - -
7f80455e by Cheng Shao at 2025-03-26T18:01:55-04:00
testsuite: add test for wasm promise.throwTo() logic
This commit adds a test case to test the wasm backend
promise.throwTo() logic.
- - - - -
afdd3fe7 by Cheng Shao at 2025-03-26T18:01:55-04:00
docs: document the wasm backend promise.throwTo() feature
- - - - -
65dc65dc by sheaf at 2025-03-26T18:02:43-04:00
Refactor CtEvidence into Given/Wanted
This commit is a simple refactoring which splits up the CtEvidence,
giving each constructor its own datatype:
data CtEvidence
= CtGiven GivenCtEvidence
| CtWanted WantedCtEvidence
data GivenCtEvidence =
GivenCt
{ ctev_pred :: TcPredType
, ctev_evar :: EvVar
, ctev_loc :: CtLoc }
data WantedCtEvidence =
WantedCt
{ ctev_pred :: TcPredType
, ctev_dest :: TcEvDest
, ctev_loc :: CtLoc
, ctev_rewriters :: RewriterSet }
This enables a few minor simplifications in the code, notably removing
a panic from GHC.Tc.Solver.Solve.solveWantedForAll_implic.
Fixes #25848
- - - - -
ada04031 by sheaf at 2025-03-26T18:03:27-04:00
Export lists: same prio for NoParent & RightParent
This commit ensures that, when we are renaming children in an export
list item such as
module M ( P(A,B,C) )
we consider children with NoParent to have the same priority as children
which have the correct parent (P in this case). This is because we
should **not** prioritise a data constructor (with the right parent)
over a pattern synonym we are bundling (which, before bundling, has
no parent).
Fixes #25892
- - - - -
721628a0 by Adriaan Leijnse at 2025-03-27T09:10:10-04:00
TTG: Replace HsUnboundVar with HsHole
Context:
The HsUnboundVar constructor in Language.Haskell.Syntax.Expr contained a
RdrName, which stood in the way of the work towards a dedicated
haskell-syntax library. The constructor was overloaded for unbound
variables, anonymous and named holes, and parse errors.
This commit:
Replaces HsUnboundVar with HsHole. In the surface syntax HsHole only
represents an anonymous expression hole ("_"). It is extended with the
XHole type family.
In the concrete GHC implementation of the language on the other hand,
HsHole is used for "any thing which is not necessarily a valid or fully
defined program fragment, but for which a type can be derived". This use
is similar to how HsUnboundVar was used, but the parse error case is now
made explicit with a ParseError case for XHole. This is in anticipation
of future work on a fault tolerant compilation pipeline.
- - - - -
dbd852f5 by Ben Gamari at 2025-03-27T09:10:48-04:00
rel_eng: Finish removal of CentOS jobs
Remove centos7 from release fetch and ghcup metadata generation scripts.
Closes #25893.
- - - - -
0e0231e7 by Matthew Pickering at 2025-03-28T18:36:33-04:00
hadrian: Make hash_unit_ids into a flavour transformer (and enable for release flavour)
The primary reason for this change is to make the `release` flavour
enable `--hash-unit-ids` by default without any further user intervention.
* Packagers don't have to be aware of this special flag they should be
using.
* release builds on CI are uniformly testing with hashes (see !13418)
Fixes #25379
- - - - -
9fc54c12 by Rodrigo Mesquita at 2025-03-28T18:37:10-04:00
driver: Move DynFlags consistency fixes off Main
These consistency fixes found in Main.hs are required for the proper
functioning of the compiler and should live together with all remaining
fixes in `makeDynFlagsConsistent`.
This is especially relevant to GHC applications that shouldn't have to
copy/fix themselves possibly inconsistent DynFlags.
Additionally, outputs information when verbosity is high about these
consistency fixes that were previously quiet, adds information to the
Note on consistency of DynFlags, and improves one of the fixes that
incorrectly used `dynNow`.
- - - - -
2fdd0be9 by sheaf at 2025-03-28T18:37:53-04:00
Remove GhcHint from TcRnNotInScope constructor
This is a tiny refactoring which:
- removes GhcHint/ImportError fields from some constructors of
TcRnMessage, using the TcRnMessageDetailed mechanism instead to
report this informaiton:
- removes the GhcHint and ImportErrors fields from TcRnNotInScope
- removes the GhcHint field from TcRnTermNameInType
- ensures that we only include these hints and import errors when the
-fhelpful-errors flag is turned on
Fixes #25874
- - - - -
9e5cd064 by ARATA Mizuki at 2025-03-31T14:53:34-04:00
Better support for SSE3 and SSE4.1
In particular:
* Pass appropriate attributes to LLVM
* Define preprocessor macros for them
- - - - -
c2c7dd51 by ARATA Mizuki at 2025-03-31T14:53:34-04:00
x86: Add support for SSSE3
This commit adds the `-mssse3` flag, which controls usage of SSSE3 instructions in x86 code generation.
- - - - -
d7c62580 by ARATA Mizuki at 2025-03-31T14:53:34-04:00
x86 NCG SIMD: Implement 128-bit integer vector arithmetics
This commit implements the following operations on integer vectors:
* negateIntNXM#
* plus{Int,Word}NXM#
* minus{Int,Word}NXM#
* times{Int,Word}NXM#
* quot{Int,Word}NXM#
* rem{Int,Word}NXM#
* min{Int,Word}NXM#
* max{Int,Word}NXM#
where (N,M) is one of (8,16), (16,8), (32,4), or (64,2).
Closes #25643
- - - - -
f5ea4e7e by ARATA Mizuki at 2025-03-31T14:53:34-04:00
x86 NCG SIMD: Implement 128-bit integer vector shuffle
This commit implements the following operations:
* shuffle{Int,Word}8X16#
* shuffle{Int,Word}16X8#
* shuffle{Int,Word}32X4#
* shuffle{Int,Word}64X2#
See #25643
- - - - -
5eeb6645 by Simon Peyton Jones at 2025-03-31T14:54:16-04:00
Re-jig the way that the Simplifier tries RULES
As #25170 showed, if a new RULE appears, it could change the simplifier's
behaviour a bit, even if it never fires; and that messes up deterministic
compilation. (This was particularly nasty if the rule wasn't even transitively
below the module being compiled.)
This MR rejigs the use of `tryRules` so that behaviour does not change
when a new, unrelated RULE is added. It's described in
* Note [When to apply rewrite rules]
* Note [tryRules: plan (BEFORE)]
* Note [tryRules: plan (AFTER)]
The main change is in the refactored version of
* simplOutId
* rebuildCall
The little state machine that was embedded in ArgInfo is gone.
As I wandered around the Simplifier I also found opportunities for
some loosely-related refactoring:
* In several places, the /substitution/ in the SimpleEnv is empty;
all we care about is the in-scope set and the flags. So
- I made a synonym `SimplEnvIS` that embodies that invariant,
- used it in a number of type signatures (notably `rebuild`)
- added some assertion checks (via `checkSimlEnvIS`)
* I moved the hanlding of `runRW` out of `rebuildCall` (where we
would have to test repeatedly) and into the new `simplOutId`, which
fires up `rebuildCall`. Now it is only tested once.
-------------------------
Metric Decrease:
T9020
T9961
-------------------------
- - - - -
f534474a by sheaf at 2025-03-31T14:54:59-04:00
Add comment: no qualified Names in the LocalRdrEnv
This commit adds a reference to section 5.5.1 of the Haskell 2010 report,
to explain that qualified names can't occur in the LocalRdrEnv.
Fixes #25875
- - - - -
d5ea80c6 by Patrick at 2025-03-31T14:55:42-04:00
Fix deadlock/loop in interface rehydration (#25858)
In #25858, GHC hangs when processing modules with class defaults due to a
circular dependency in the interface rehydration process. The deadlock/loop
occurred when eager class defaults rehydration accessed not-yet-complete module details.
To fix the immediate deadlock/loop.
`tcIfaceDefaults` is refactored, we use the class name directly from the iface
and use `forM` for lazy loading the class, which algins with the handling of other fields
of ModDetails. This laziness ensure rehydration waits for HomePackageTable (HPT) to
be updated and prevent premature evaluation of ModDetails inside `fixIO``.
As suggested by Matthew, class defaults importing is also refactored
to align with the compiler's established interface loading conventions.
- add class defaults field to ExternalPackageState (EPS).
- rehydrate and store class defaults in EPS at `loadInterface`.
- Instead of using `tcIfaceDefaults` in `tcRnImports`, we add and use
`tcGetClsDefaults` to read defaults directly from HPT or EPS
when importing modules.
Tests:
- T25858, T25858v1-2: Test class hydration in defaults
- T25858v3-4: Test type list hydration in defaults
New Note [Tricky rehydrating IfaceDefaults loop] is added.
Thanks to @sheaf (Sam), @mpickering (Matthew), and @simonpj (Simon) for their
valuable input and analysis.
Fixes #25858.
- - - - -
2d419d8d by Matthew Pickering at 2025-04-02T16:12:36-04:00
Use unsafePerformIO in definition of computeFingerprint
computeFingerprint is morally a pure function, which is implemented by
mutating a buffer. Using unsafePerformIO inside the definition allows it
to be used in pure contexts, fixing one place where an ad-hoc call to
unsafePerformIO is already needed.
- - - - -
ccdf979b by Matthew Pickering at 2025-04-02T16:12:37-04:00
driver: Fix recompilation checking for exported defaults
Since the exported defaults are not associated with any identifier from
the module, they are just added to the export hash rather than
the fine-grained recompilation logic.
Fixes #25855
- - - - -
c5bf9892 by Matthew Pickering at 2025-04-02T16:12:37-04:00
driver: Fix recompilation checking for COMPLETE pragmas
A {-# COMPLETE P, Q #-} pragma is associated with the pattern synonyms P
and Q during recompilation checking. Therefore, the existence of a
pattern synonym becomes part of the ABI hash for P and Q.
Then if a module uses these pattern synonyms and a complete pragma
changes, it will trigger recompilation in that module.
Fixes #25854
- - - - -
d0fd9370 by sheaf at 2025-04-02T16:14:05-04:00
Handle named default exports separately
This commit changes the way we check for duplicate exports of named
default declarations. They are now treated entirely separately from
other exports, because in an export list of the form
module M ( default Cls, Cls )
the default declaration does not export the class 'Cls', but only its
default declarations.
Also fixes a bug in Backpack where named default exports were getting
dropped entirely. No test for that.
Fixes #25857
- - - - -
62d04494 by Cheng Shao at 2025-04-03T05:56:17-04:00
ci: add x86_64-linux-ubuntu24_04 nightly/release jobs
- - - - -
327952e4 by Cheng Shao at 2025-04-03T05:56:17-04:00
rel-eng: add ubuntu24_04 bindists to ghcup metadata and fetch gitlab scripts
- - - - -
aa1e3b8b by sheaf at 2025-04-03T05:57:24-04:00
GHC settings: always unescape escaped spaces
In #25204, it was noted that GHC didn't properly deal with having
spaces in its executable path, as it would compute an invalid path
for the C compiler.
The original fix in 31bf85ee49fe2ca0b17eaee0774e395f017a9373 used a
trick: escape spaces before splitting up flags into a list. This fixed
the behaviour with extra flags (e.g. -I), but forgot to also unescape
for non-flags, e.g. for an executable path (such as the C compiler).
This commit rectifies this oversight by consistently unescaping the
spaces that were introduced in order to split up argument lists.
Fixes #25204
- - - - -
34a9b55d by lazyLambda at 2025-04-04T06:22:26-04:00
Driver: make MonadComprehensions imply ParallelListComp
This commit changes GHC.Driver.Flags.impliedXFlags to make the
MonadComprehensions extension enable the ParallelListComp extension.
Fixes #25645
- - - - -
d99eb7cd by sheaf at 2025-04-04T06:23:28-04:00
NamedDefaults: handle poly-kinded unary classes
With this commit, we accept named default declarations for poly-kinded
classes such as Typeable, e.g.
default Typeable (Char)
This used to fail because we assumed the kind of the class was monomorphic,
e.g.
Type -> Constraint
(Type -> Type) -> Constraint
Nat -> Constraint
Now, we can handle a simple polymorphic class such as
Typeable :: forall k. k -> Constraint
Note that we keep the restriction that the class must only have
one visible argument.
This is all explained in the new Note [Instance check for default declarations]
in GHC.Tc.Gen.Default.
Fixes #25882
- - - - -
4cbc90de by sheaf at 2025-04-04T11:39:05-04:00
LLVM: add type annotations to AtomicFetch_cmm.cmm
- - - - -
e2237305 by sheaf at 2025-04-04T11:39:05-04:00
Cmm lint: lint argument types of CallishMachOps
This commit adds a new check to Cmm lint to ensure that the argument
types to a CallishMachOp are correct. The lack of this check was
detected in the AtomicFetch test: the literals being passed as the
second arguments to operations such as 'fetch_add', 'fetch_and'... were
of the wrong width, which tripped up the LLVM backend.
- - - - -
9363e547 by Cheng Shao at 2025-04-04T11:39:50-04:00
ci: add ghc-wasm-meta integration testing jobs
This patch adds ghc-wasm-meta integration testing jobs to the CI
pipeline, which are only triggered via the `test-wasm` MR label or
manually when the `wasm` label is set.
These jobs will fetch the wasm bindists and test them against a
variety of downstream projects, similarly to head.hackage jobs for
native bindists, offering a convenient way to catch potential
downstream breakage while refactoring the wasm backend.
- - - - -
27029e60 by Adam Gundry at 2025-04-04T11:40:36-04:00
base: Minor fixes to GHC.Records haddocks
This corrects a stale reference to OverloadedRecordFields (which should
be OverloadedRecordDot), fixes the haddock link syntax and adds an
@since pragma.
- - - - -
f827c4c6 by Rodrigo Mesquita at 2025-04-07T11:22:10-04:00
Parametrize default logger action with Handles
Introduce `defaultLogActionWithHandles` to allow GHC applications to use
GHC's formatting but using custom handles.
`defaultLogAction` is then trivially reimplemented as
```
defaultLogActionWithHandles stdout stderr
```
- - - - -
5dade5fd by sheaf at 2025-04-07T11:23:02-04:00
Finer-grained recompilation checking for exports
This commit refines the recompilation checking logic, to avoid
recompiling modules with an explicit import list when the modules they
import start exporting new items.
More specifically, when:
1. module N imports module M,
2. M is changed, but in a way that:
a. preserves the exports that N imports
b. does not introduce anything that forces recompilation downstream,
such as orphan instances
then we no longer require recompilation of N.
Note that there is more to (2a) as initially meets the eye:
- if N includes a whole module or "import hiding" import of M,
then we require that the export list of M does not change,
- if N only includes explicit imports, we check that the imported
items don't change, e.g.
- if we have @import M(T(K, f), g)@, we must check that N
continues to export all these identifiers, with the same Avail
structure (i.e. we should error if N stops bundling K or f with
T)
- if we have @import M(T(..))@, we must check that the children
of T have not changed
See Note [When to recompile when export lists change?] in GHC.Iface.Recomp.
This is all tested in the new tests RecompExports{1,2,3,4,5}
Fixes #25881
- - - - -
f32d6c2b by Andreas Klebinger at 2025-04-07T22:01:25-04:00
NCG: AArch64 - Add -finter-module-far-jumps.
When enabled the arm backend will assume jumps to targets outside of the
current module are further than 128MB away.
This will allow for code to work if:
* The current module results in less than 128MB of code.
* The whole program is loaded within a 4GB memory region.
We have seen a few reports of broken linkers (#24648) where this flag might allow
a program to compile/run successfully at a very small performance cost.
-------------------------
Metric Increase:
T783
-------------------------
- - - - -
553c280b by Andreas Klebinger at 2025-04-07T22:02:11-04:00
Revert "rts: fix small argument passing on big-endian arch (fix #23387)"
Based on analysis documented in #25791 this doesn't fully fix the big
while introducing new bugs on little endian architectures.
A more complete fix will have to be implemented to fix #23387
This reverts commit 4f02d3c1a7b707e609bb3aea1dc6324fa19a5c39.
- - - - -
b0dc6599 by Andreas Klebinger at 2025-04-07T22:02:11-04:00
Interpreter: Fixes to handling of subword value reads/writes.
Load subword values as full words from the stack truncating/expanding as
neccesary when dealing with subwords. This way byte order is implicitly
correct.
This commit also fixes the order in which we are pushing literals onto
the stack on big endian archs.
Last but not least we enable a test for ghci which actually tests these
subword operations.
- - - - -
ed38c09b by Cheng Shao at 2025-04-07T22:02:53-04:00
testsuite: don't test WasmControlFlow stdout
This patch solves a potential test flakiness in `WasmControlFlow` by
removing `WasmControlFlow.stdout` which is not so portable/stable as
it seems. See added `Note [WasmControlFlow]` for more detailed
explanation.
- - - - -
f807c590 by Rodrigo Mesquita at 2025-04-08T17:41:51-04:00
debugger: Add docs to obtainTermFromId
- - - - -
5dba052d by Rodrigo Mesquita at 2025-04-08T17:41:51-04:00
Move logic to find and set Breakpoint to GHC
Breakpoints are uniquely identified by a module and an index unique
within that module. `ModBreaks` of a Module contains arrays mapping from
this unique breakpoint index to information about each breakpoint. For
instance, `modBreaks_locs` stores the `SrcSpan` for each breakpoint.
To find a breakpoint using the line number you need to go through all
breakpoints in the array for a given module and look at the line and
column stored in the `SrcSpan`s. Similarly for columns and finding
breakpoints by name.
This logic previously lived within the `GHCi` application sources,
however, it is common to any GHC applications wanting to set
breakpoints, like the upcoming `ghc-debugger`.
This commit moves this logic for finding and setting breakpoints to the
GHC library so it can be used by both `ghci` and `ghc-debugger`.
- - - - -
bc0b9f73 by Rodrigo Mesquita at 2025-04-08T17:41:51-04:00
Refactor and move logic for identifier breakpoints
Breakpoints can be set on functions using syntax of the form
`[Module.]function`. The parsing, resolution (e.g. inferring implicit
module), and validation of this syntax for referring to functions was
tightly coupled with its GHCi use.
This commit extracts the general purpose bits of resolving this syntax
into `GHC.Runtime.Debugger.Breakpoints` so it can be further used by
other GHC applications and to improve the code structure of GHCi.
Moreover, a few utilities that do splitting and joining of identifiers
as strings were moved to `GHC.Runtime.Eval.Utils`, which also can be
used in the future to clean up `GHC.Runtime.Eval` a bit.
- - - - -
4f728d21 by Rodrigo Mesquita at 2025-04-08T17:41:51-04:00
debugger: derive Ord for BreakpointIds
- - - - -
5528771c by Rodrigo Mesquita at 2025-04-08T17:41:51-04:00
debugger: Move context utils from GHCi to GHC
Moves `enclosingTickSpan`, `getCurrentBreakSpan`, and
`getCurrentBreakModule`, general utilities on the internal debugger
state, into the GHC library.
- - - - -
4871f543 by sheaf at 2025-04-08T17:42:43-04:00
Implicit quantification in type synonyms: add test
This adds a test for ticket #24090, which involves implicit
quantification in type synonyms.
The underlying issue was fixed in 0d4ee209dfe53e5074d786487f531dabc36d561c.
- - - - -
48917d3c by sheaf at 2025-04-08T17:42:44-04:00
Turn on implicit-rhs-quantification by default
This flag was added to GHC 9.8, and will be removed in a future GHC
release. In preparation, this commit adds it to the default warning
flags.
- - - - -
629be068 by Rodrigo Mesquita at 2025-04-08T17:43:26-04:00
debugger: Add breakpoints to every Stmt
While single-stepping through a Haskell program we stop at every
breakpoint. However, we don't introduce breakpoints at every single
expression (e.g. single variables) because they would be too many and
uninteresting.
That said, in a do-block, it is expected that stepping over would break
at every line, even if it isn't particularly interesting (e.g. a single
arg like getArgs). Moreover, let-statements in do-blocks, despite only
being evaluated once needed, lead to surprising jumps while stepping
through because some have outermost (outside the let) breakpoints
while others don't.
This commit makes every statement in a do-block have a breakpoint.
This leads to predictable stepping through in a do-block.
Duplicate breakpoints in the same location are avoided using the
existing blacklist mechanism, which was missing a check in one relevant place.
Fixes #25932
- - - - -
99a3affd by Matthew Pickering at 2025-04-08T17:44:08-04:00
driver: refactor: Split downsweep and MakeAction into separate modules.
This will facilitate using the downsweep functions in other parts of
the compiler than just --make mode.
Also, the GHC.Driver.Make module was huge. Now it's still huge but
slightly smaller!
- - - - -
ecfec4df by sheaf at 2025-04-09T14:13:12-04:00
Store user-written qualification in the GhcRn AST
This commit ensures we store the original user-written module
qualification in the renamed AST. This allows us to take into account
the user-written qualification in error messages.
Fixes #25877
- - - - -
97c884e2 by sheaf at 2025-04-09T14:13:12-04:00
TcRnIllegalTermLevelUse: simpler error when possible
This commit makes GHC emit a simple error message in the case of an
illegal term-level use of a data constructor: we will try to report an
out-of-scope error instead of a "Illegal term level use" error, as the
latter might be a bit overwhelming for newcomers.
We do this when we have a data constructor import suggestion to provide
to the user. For example:
module M where { data A = A }
module N where
import M(A)
x = Bool
-- Illegal term-level use of Bool
y = A
-- Data constructor not in scope: A.
-- Perhaps add 'A' to the import list of 'M'.
This commit also revamps the "similar names" suggestion mechanism,
and in particular its treatment of name spaces. Now, which name spaces
we suggest is based solely on what we are looking for, and no longer on
the NameSpace of the Name we have. This is because, for illegal term-level
use errors, it doesn't make much sense to change the suggestions based
on the fact that we resolved to e.g. a type constructor/class; what
matters is what we were expecting to see in this position.
See GHC.Rename.Unbound.{suggestionIsRelevant,relevantNameSpace} as well
as the new constructors to GHC.Tc.Errors.Types.WhatLooking.
Fixes #23982
- - - - -
bff645ab by Rodrigo Mesquita at 2025-04-09T14:13:57-04:00
driver: Split Session functions out of Main
This commit moves out functions that help in creating and validating a
GHC multi session from Main into the ghc library where they can be used by
other GHC applications.
Moreover, `Mode` processing and `checkOptions` linting were moved to
separate modules within the ghc-bin executable package.
In particular:
- Move `Mode` types and functions (referring to the mode GHC is running
on) to `ghc-bin:GHC.Driver.Session.Mode`
- Move `checkOptions` and aux functions, which validates GHC DynFlags
based on the mode, to `ghc-bin:GHC.Driver.Session.Lint`
- Moves `initMulti`, `initMake`, and aux functions, which initializes a make/multi-unit
session, into `ghc:GHC.Driver.Session.Units`.
- - - - -
501b015e by Rodrigo Mesquita at 2025-04-09T14:13:57-04:00
docs: Improve haddock of ExecComplete
- - - - -
dea98988 by Andreas Klebinger at 2025-04-09T19:23:57-04:00
Avoid oversaturing constructor workers.
Constructor applications always need to take the exact number of
arguments. If we can't ensure that instead apply the constructor worker
like a regular function.
Fixes #23865
- - - - -
f1acdd2c by sheaf at 2025-04-09T19:25:41-04:00
NamedDefaults: require the class to be standard
We now only default type variables if they only appear in constraints
of the form `C v`, where `C` is either a standard class or a class with
an in-scope default declaration.
This rectifies an oversight in the original implementation of the
NamedDefault extensions that was remarked in #25775; that implementation
allowed type variables to appear in unary constraints which had arbitrary
classes at the head.
See the rewritten Note [How type-class constraints are defaulted] for
details of the implementation.
Fixes #25775
Fixes #25778
- - - - -
5712e0d6 by Vladislav Zavialov at 2025-04-10T05:17:38+00:00
Retry type/class declarations and instances (#12088)
Retry type/class declarations and instances to account for non-lexical
dependencies arising from type/data family instances.
This patch improves the kind checker's ability to use type instances in kind
checking of other declarations in the same module.
* Key change: tcTyAndClassDecls now does multiple passes over the TyClGroups,
as long as it is able to make progress.
See the new Note [Retrying TyClGroups] in GHC.Tc.TyCl
* Supporting change: FVs of a TyClGroup are now recorded in its extension
field, namely XCTyClGroup.
See the new Note [Prepare TyClGroup FVs] in GHC.Rename.Module
* Instances are no longer inserted at the earliest positions where their FVs
are bound. This is a simplification.
See the new Note [Put instances at the end] in GHC.Rename.Module
* Automatic unpacking is now more predictable, but fewer fields get unpacked
by default. Use explicit {-# UNPACK #-} pragmas instead.
See the new Note [Flaky -funbox-strict-fields with type/data families]
For the wide range of newly accepted programs, consult the added test cases.
Fixed tickets:
#12088, #12239, #14668, #15561, #16410, #16448, #16693,
#19611, #20875, #21172, #22257, #25238, #25834
Metric Decrease:
T8095
- - - - -
bc73a78d by sheaf at 2025-04-10T15:07:24-04:00
checkFamApp: don't be so eager to cycle break
As remarked in #25933, a pure refactoring of checkTyEqRhs in
ab77fc8c7adebd610aa0bd99d653f9a6cc78a374 inadvertently changed behaviour,
as it caused GHC to introduce cycle-breaker variables in some
unnecessary circumstances.
This commit refactors 'GHC.Tc.Utils.Unify.checkFamApp' in a way that
should restore the old behaviour, so that, when possible, we first
recur into the arguments and only introduce a cycle breaker if this
recursion fails (e.g. due to an occurs check failure).
Fixes #25933
- - - - -
3acd8182 by Andreas Klebinger at 2025-04-10T22:32:12-04:00
Expand docs for RTS flag `-M`.
The behaviour of how/when exceptions are raised was not really covered
in the docs.
- - - - -
026c1a39 by Adam Sandberg Ericsson at 2025-04-10T22:32:56-04:00
add cases for more SchedulerStatus codes in rts_checkSchedStatus
- - - - -
5977c6a1 by sheaf at 2025-04-10T22:33:46-04:00
Squash warnings in GHC.Runtime.Heap.Inspect
There were incomplete record selector warnings in GHC.Runtime.Heap.Inspect
due to the use of the partial 'dataArgs' record selector. This is fixed
by passing the fields to the 'extractSubTerms' function directly,
rather than passing a value of the parent data type.
- - - - -
6a3e38f5 by Andreas Klebinger at 2025-04-11T15:13:53-04:00
hadrian: Make ghcWithInterpreter the universal source of truth about availability of the interpreter
We were doing some ad-hoc checks in different places in hadrian to
determine whether we supported the interprter or not. Now this check if
confined to one function, `ghcWithInterpreter`, and all the places which
use this information consult `ghcWithInterpreter` to determine what to
do.
Fixes #25533.
- - - - -
207de6f1 by Matthew Pickering at 2025-04-11T15:14:37-04:00
testsuite: Fix running TH tests with profiled dynamic compiler
Previously, I had failed to update the ghc_th_way_flags logic for the
profiled dynamic compiler.
In addition to this `ghc_dynamic` was incorrectly set for profiled
dynamic compiler.
I also updated MultiLayerModulesTH_OneShot test to work for any compiler
linkage rather than just dynamic.
Fixes #25947
-------------------------
Metric Decrease:
MultiLayerModulesTH_Make
-------------------------
- - - - -
5455f2b9 by Matthew Pickering at 2025-04-12T08:31:36-04:00
driver: Add support for "Fixed" nodes in the ModuleGraph
A fixed node in the module graph is one which we presume is already
built. It's therefore up to the user to make sure that the interface
file and any relevant artifacts are available for a fixed node.
Fixed/Compile nodes are represented by the ModuleNodeInfo type, which
abstracts the common parts of Fixed/Compile nodes with accessor
functions of type `ModuleNodeInfo -> ...`.
Fixed nodes can only depend on other fixed nodes. This invariant can be
checked by the function `checkModuleGraph` or `mkModuleGraphChecked`.
--make mode is modified to work with fixed mode. In order to "compile" a
fixed node, the artifacts are just loaded into the HomePackageTable.
Currently nothing in the compiler will produce Fixed nodes but this is
tested with the FixedNodes GHC API test.
In subsequent patches we are going to remove the ExternalModuleGraph and
use Fixed nodes for modules in the module graph in oneshot mode.
Fixes #25920
- - - - -
ad64d5c2 by Cheng Shao at 2025-04-12T08:32:19-04:00
ci: remove manual case of ghc-wasm-meta downstream testing jobs
This patch removes the manual case of ghc-wasm-meta downstream testing
jobs; now the only way of including them in the pipeline and running
them is via the test-wasm label.
The reason of the removal is it proves to be problematic for MRs with
only the wasm label; the wasm job would succeed, then the pipeline
status would be waiting for manual action instead of succeeding. There
needs to be separate jobs for the label-triggered and manual-triggered
cases, but I don't think it's worth that extra complexity, the
label-triggered case is already sufficient.
- - - - -
b34890c7 by Vladislav Zavialov at 2025-04-13T01:08:21+03:00
Fix EmptyCase panic in tcMatches (#25960)
Due to faulty reasoning in Note [Pattern types for EmptyCase],
tcMatches was too keen to panic.
* Old (incorrect) assumption: pat_tys is a singleton list.
This does not hold when \case{} is checked against a function type
preceded by invisible forall. See the new T25960 test case.
* New (hopefully correct) assumption: vis_pat_tys is a singleton list.
This should follow from:
checkArgCounts :: MatchGroup GhcRn ... -> TcM VisArity
checkArgCounts (MG { mg_alts = L _ [] })
= return 1
...
- - - - -
84806ebc by Vladislav Zavialov at 2025-04-13T11:40:08-04:00
Remove unused type: TokenLocation
- - - - -
05eb50df by Vladislav Zavialov at 2025-04-13T19:16:38-04:00
Register EpToken in Parser.PostProcess.Haddock (#22558)
This change allows us to reject more badly placed Haddock comments.
Examples:
module
-- | Bad comment for the module
T17544_kw where
data Foo -- | Bad comment for MkFoo
where MkFoo :: Foo
newtype Bar -- | Bad comment for MkBar
where MkBar :: () -> Bar
class Cls a
-- | Bad comment for clsmethod
where
clsmethod :: a
- - - - -
01944e5e by Vladislav Zavialov at 2025-04-13T19:17:21-04:00
Reject puns in T2T (#24153)
This patch implements pun detection in T2T. Consider:
x = 42
f, g :: forall a -> ...
f (type x) = g x
In accordance with the specification, the `g x` function call is renamed
as a term, so `x` refers to the top-level binding `x = 42`, not to the
type variable binding `type x` as one might expect.
This is somewhat counterintuitive because `g` expects a type argument.
Forbidding puns in T2T allows us to produce a helpful error message:
Test.hs:5:16: error: [GHC-09591]
Illegal punned variable occurrence in a required type argument.
The name ‘x’ could refer to:
‘x’ defined at Test.hs:3:1
‘x’ bound at Test.hs:5:9
This commit is a follow up to 0dfb1fa799af254c8a1e1045fc3996af2d57a613
where checking for puns was left as future work.
- - - - -
cc580552 by Vladislav Zavialov at 2025-04-13T19:18:02-04:00
Additional test cases for #12088, #13790
Extract more test cases from ticket discussions, including multi-module
examples. Follow up to 5712e0d646f611dfbfedfd7ef6dff3a18c016edb
- - - - -
d47bf776 by Matthew Pickering at 2025-04-14T16:44:41+01:00
driver: Use ModuleGraph for oneshot and --make mode
This patch uses the `hsc_mod_graph` field for both oneshot and --make
mode. Therefore, if part of the compiler requires usage of the module
graph, you do so in a uniform way for the two different modes.
The `ModuleGraph` describes the relationship between the modules in the
home package and units in external packages. The `ModuleGraph` can be
queried when information about the transitive closure of a package is
needed. For example, the primary use of the ModuleGraph from within the
compiler is in the loader, which needs to know the transitive closure of
a module so it can load all the relevant objects for evaluation.
In --make mode, downsweep computes the ModuleGraph before any
compilation starts.
In oneshot mode, a thunk is created at the start of compilation, which
when forced will compute the module graph beneath the current module.
The thunk is only forced at the moment when the user uses Template
Haskell.
Finally, there are some situations where we need to discover what
dependencies to load but haven't loaded a module graph at all. In this
case, there is a fallback which computes the transitive closure on the
fly and doesn't cache the result. Presumably if you are going to call
getLinkDeps a lot, you would compute the right ModuleGraph before you
started.
Importantly, this removes the ExternalModuleGraph abstraction. This was quite
awkward to work with since it stored information about the home package
inside the EPS.
This patch will also be very useful when implementing explicit level
imports, which requires more significant use of the module graph in
order to determine which level instances are available at.
Towards #25795
-------------------------
Metric Decrease:
MultiLayerModulesTH_Make
MultiLayerModulesTH_OneShot
-------------------------
- - - - -
395e0ad1 by sheaf at 2025-04-16T12:33:26-04:00
base: remove .Internal modules (e.g. GHC.TypeLits)
This commit removes the following internal modules from base,
as per CLC proposal 217:
- GHC.TypeNats.Internal
- GHC.TypeLits.Internal
- GHC.ExecutionStack.Internal
Fixes #25007
- - - - -
e0f3ff11 by Patrick at 2025-04-17T04:31:12-04:00
Refactor Handling of Multiple Default Declarations
Fixes: #25912, #25914, #25934
Previously, GHC discarded all loaded defaults (tcg_default) when local
defaults were encountered during typechecking. According to the
exportable-named-default proposal (sections 2.4.2 and 2.4.3), local
defaults should be merged into tcg_default, retaining any defaults
already present while overriding where necessary.
Key Changes:
* Introduce DefaultProvenance to track the origin of default declarations
(local, imported, or built-in), replacing the original cd_module
in ClassDefaults with cd_provenance :: DefaultProvenance.
* Rename tcDefaults to tcDefaultDecls, limiting its responsibility to only
converting renamed class defaults into ClassDefaults.
* Add extendDefaultEnvWithLocalDefaults to merge local defaults into the
environment, with proper duplication checks:
- Duplicate local defaults for a class trigger an error.
- Local defaults override imported or built-in defaults.
* Update and add related notes: Note [Builtin class defaults],
Note [DefaultProvenance].
* Add regression tests: T25912, T25914, T25934.
Thanks sam and simon for the help on this patch.
Co-authored-by: sheaf <sam.derbyshire(a)gmail.com>
- - - - -
386f1854 by Teo Camarasu at 2025-04-17T04:31:55-04:00
template-haskell: Remove `addrToByteArrayName` and `addrToByteArray`
These were part of the implementation of the `Lift ByteArray` instance and were errornously exported because this module lacked an explicit export list. They have no usages on Hackage.
Resolves #24782
- - - - -
b96e2f77 by Sylvain Henry at 2025-04-18T20:46:33-04:00
RTS: remove target info and fix host info (#24058)
The RTS isn't a compiler, hence it doesn't have a target and we remove
the reported target info displayed by "+RTS --info". We also fix the
host info displayed by "+RTS --info": the host of the RTS is the
RTS-building compiler's target, not the compiler's host (wrong when
doing cross-compilation).
- - - - -
6d9965f4 by Sylvain Henry at 2025-04-18T20:46:33-04:00
RTS: remove build info
As per the discussion in !13967, there is no reason to tag the RTS with
information about the build platform.
- - - - -
d52e9b3f by Vladislav Zavialov at 2025-04-18T20:47:15-04:00
Diagnostics: remove the KindMismatch constructor (#25957)
The KindMismatch constructor was only used as an intermediate
representation in pretty-printing.
Its removal addresses a problem detected by the "codes" test case:
[GHC-89223] is untested (constructor = KindMismatch)
In a concious deviation from the usual procedure, the error code
GHC-89223 is removed entirely rather than marked as Outdated.
The reason is that it never was user-facing in the first place.
- - - - -
e2f2f9d0 by Vladislav Zavialov at 2025-04-20T10:53:39-04:00
Add name for -Wunusable-unpack-pragmas
This warning had no name or flag and was triggered unconditionally.
Now it is part of -Wdefault.
In GHC.Tc.TyCl.tcTyClGroupsPass's strict mode, we now have to
force-enable this warning to ensure that detection of flawed groups
continues to work even if the user disables the warning with the
-Wno-unusable-unpack-pragmas option. Test case: T3990c
Also, the misnamed BackpackUnpackAbstractType is now called
UnusableUnpackPragma.
- - - - -
6caa6508 by Adam Gundry at 2025-04-20T10:54:22-04:00
Fix specialisation of incoherent instances (fixes #25883)
GHC normally assumes that class constraints are canonical, meaning that
the specialiser is allowed to replace one dictionary argument with another
provided that they have the same type. The `-fno-specialise-incoherents`
flag alters INCOHERENT instance definitions so that they will prevent
specialisation in some cases, by inserting `nospec`.
This commit fixes a bug in 7124e4ad76d98f1fc246ada4fd7bf64413ff2f2e, which
treated some INCOHERENT instance matches as if `-fno-specialise-incoherents`
was in effect, thereby unnecessarily preventing specialisation. In addition
it updates the relevant `Note [Rules for instance lookup]` and adds a new
`Note [Canonicity for incoherent matches]`.
- - - - -
0426fd6c by Adam Gundry at 2025-04-20T10:54:23-04:00
Add regression test for #23429
- - - - -
eec96527 by Adam Gundry at 2025-04-20T10:54:23-04:00
user's guide: update specification of overlapping/incoherent instances
The description of the instance resolution algorithm in the user's
guide was slightly out of date, because it mentioned in-scope given
constraints only at the end, whereas the implementation checks for
their presence before any of the other steps.
This also adds a warning to the user's guide about the impact of
incoherent instances on specialisation, and more clearly documents
some of the other effects of `-XIncoherentInstances`.
- - - - -
a00eeaec by Matthew Craven at 2025-04-20T10:55:03-04:00
Fix bytecode generation for `tagToEnum# <LITERAL>`
Fixes #25975.
- - - - -
2e204269 by Andreas Klebinger at 2025-04-22T12:20:41+02:00
Simplifier: Constant fold invald tagToEnum# calls to bottom expr.
When applying tagToEnum# to a out-of-range value it's best to simply
constant fold it to a bottom expression. That potentially allows more
dead code elimination and makes debugging easier.
Fixes #25976
- - - - -
7250fc0c by Matthew Pickering at 2025-04-22T16:24:04-04:00
Move -fno-code note into Downsweep module
This note was left behind when all the code which referred to it was
moved into the GHC.Driver.Downsweep module
- - - - -
d2dc89b4 by Matthew Pickering at 2025-04-22T16:24:04-04:00
Apply editing notes to Note [-fno-code mode] suggested by sheaf
These notes were suggested in https://gitlab.haskell.org/ghc/ghc/-/merge_requests/14241
- - - - -
07575d15 by Ben Gamari at 2025-04-23T15:10:22+05:30
SetLevels: Make Level strict
There is no benefit to collecting thunks for (+1) operations.
- - - - -
903d8369 by Ben Gamari at 2025-04-23T15:13:53+05:30
SetLevels: Track binding context
In preparation to use this information to provide more context-sensitive
naming for generated `lvl_` identifiers as propsed in #25802.
- - - - -
7cf39c79 by Ben Gamari at 2025-04-23T15:14:33+05:30
SetLevels: Name `lvl` binders according to context
In general we should strive to maintain some amount of information about
the provenance of generated bindings.
Addresses #25802.
- - - - -
960 changed files:
- .gitlab-ci.yml
- .gitlab/generate-ci/gen_ci.hs
- .gitlab/jobs.yaml
- .gitlab/rel_eng/fetch-gitlab-artifacts/fetch_gitlab.py
- .gitlab/rel_eng/mk-ghcup-metadata/mk_ghcup_metadata.py
- .gitlab/rel_eng/upload.sh
- .gitlab/rel_eng/upload_ghc_libs.py
- compiler/GHC.hs
- compiler/GHC/Builtin/Names/TH.hs
- compiler/GHC/Builtin/PrimOps/Ids.hs
- compiler/GHC/Builtin/Types.hs
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Cmm/CallConv.hs
- compiler/GHC/Cmm/Dataflow/Label.hs
- compiler/GHC/Cmm/Lint.hs
- compiler/GHC/Cmm/Liveness.hs
- compiler/GHC/Cmm/MachOp.hs
- compiler/GHC/Cmm/Opt.hs
- compiler/GHC/Cmm/Parser.y
- compiler/GHC/Cmm/ThreadSanitizer.hs
- compiler/GHC/Cmm/Type.hs
- compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
- compiler/GHC/CmmToAsm/Config.hs
- compiler/GHC/CmmToAsm/PPC/CodeGen.hs
- compiler/GHC/CmmToAsm/RV64/CodeGen.hs
- compiler/GHC/CmmToAsm/Reg/Linear/Base.hs
- compiler/GHC/CmmToAsm/X86/CodeGen.hs
- compiler/GHC/CmmToAsm/X86/Instr.hs
- compiler/GHC/CmmToAsm/X86/Ppr.hs
- compiler/GHC/CmmToAsm/X86/RegInfo.hs
- compiler/GHC/CmmToC.hs
- compiler/GHC/CmmToLlvm/Base.hs
- compiler/GHC/CmmToLlvm/CodeGen.hs
- compiler/GHC/Core.hs
- compiler/GHC/Core/Coercion/Axiom.hs
- compiler/GHC/Core/Coercion/Opt.hs
- compiler/GHC/Core/DataCon.hs
- compiler/GHC/Core/FamInstEnv.hs
- compiler/GHC/Core/InstEnv.hs
- compiler/GHC/Core/LateCC/TopLevelBinds.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Make.hs
- compiler/GHC/Core/Map/Expr.hs
- compiler/GHC/Core/Map/Type.hs
- compiler/GHC/Core/Opt/CSE.hs
- compiler/GHC/Core/Opt/CallerCC/Types.hs
- compiler/GHC/Core/Opt/ConstantFold.hs
- compiler/GHC/Core/Opt/SetLevels.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/Utils.hs
- compiler/GHC/Core/Predicate.hs
- compiler/GHC/Core/Rules.hs
- compiler/GHC/Core/Rules/Config.hs
- compiler/GHC/Core/SimpleOpt.hs
- compiler/GHC/Core/Subst.hs
- compiler/GHC/Core/Tidy.hs
- compiler/GHC/Core/TyCo/Compare.hs
- compiler/GHC/Core/TyCo/FVs.hs
- compiler/GHC/Core/TyCo/Ppr.hs
- compiler/GHC/Core/TyCo/Rep.hs
- compiler/GHC/Core/TyCo/Subst.hs
- compiler/GHC/Core/TyCo/Tidy.hs
- compiler/GHC/Core/TyCon.hs
- compiler/GHC/Core/Type.hs
- compiler/GHC/Core/Type.hs-boot
- compiler/GHC/Core/Unify.hs
- compiler/GHC/CoreToIface.hs
- compiler/GHC/CoreToStg.hs
- compiler/GHC/CoreToStg/Prep.hs
- compiler/GHC/Data/BooleanFormula.hs
- compiler/GHC/Data/FlatBag.hs
- compiler/GHC/Data/Graph/Color.hs
- compiler/GHC/Data/Maybe.hs
- compiler/GHC/Data/SmallArray.hs
- compiler/GHC/Data/Strict.hs
- compiler/GHC/Data/TrieMap.hs
- compiler/GHC/Driver/Backpack.hs
- compiler/GHC/Driver/Config.hs
- compiler/GHC/Driver/Config/CmmToAsm.hs
- compiler/GHC/Driver/Config/StgToCmm.hs
- + compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Env.hs
- compiler/GHC/Driver/Env/Types.hs
- compiler/GHC/Driver/Errors/Ppr.hs
- compiler/GHC/Driver/Errors/Types.hs
- compiler/GHC/Driver/Flags.hs
- + compiler/GHC/Driver/IncludeSpecs.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Driver/Make.hs
- + compiler/GHC/Driver/MakeAction.hs
- compiler/GHC/Driver/MakeFile.hs
- + compiler/GHC/Driver/Messager.hs
- compiler/GHC/Driver/Pipeline.hs-boot
- compiler/GHC/Driver/Pipeline/Execute.hs
- compiler/GHC/Driver/Session.hs
- + compiler/GHC/Driver/Session/Units.hs
- compiler/GHC/Hs/Binds.hs
- compiler/GHC/Hs/Decls.hs
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/Hs/Extension.hs
- compiler/GHC/Hs/ImpExp.hs
- compiler/GHC/Hs/Instances.hs
- compiler/GHC/Hs/Pat.hs
- compiler/GHC/Hs/Specificity.hs
- compiler/GHC/Hs/Stats.hs
- compiler/GHC/Hs/Syn/Type.hs
- compiler/GHC/Hs/Type.hs
- compiler/GHC/Hs/Utils.hs
- compiler/GHC/HsToCore.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/C.hs
- compiler/GHC/HsToCore/Foreign/Call.hs
- compiler/GHC/HsToCore/Foreign/Wasm.hs
- compiler/GHC/HsToCore/Match.hs
- compiler/GHC/HsToCore/Match/Constructor.hs
- compiler/GHC/HsToCore/Monad.hs
- compiler/GHC/HsToCore/Pmc/Desugar.hs
- compiler/GHC/HsToCore/Quote.hs
- compiler/GHC/HsToCore/Ticks.hs
- compiler/GHC/HsToCore/Types.hs
- compiler/GHC/HsToCore/Usage.hs
- compiler/GHC/Iface/Binary.hs
- compiler/GHC/Iface/Decl.hs
- compiler/GHC/Iface/Env.hs
- compiler/GHC/Iface/Ext/Ast.hs
- + compiler/GHC/Iface/Flags.hs
- compiler/GHC/Iface/Load.hs
- compiler/GHC/Iface/Make.hs
- compiler/GHC/Iface/Recomp.hs
- compiler/GHC/Iface/Recomp/Binary.hs
- compiler/GHC/Iface/Recomp/Flags.hs
- + compiler/GHC/Iface/Recomp/Types.hs
- compiler/GHC/Iface/Rename.hs
- compiler/GHC/Iface/Syntax.hs
- compiler/GHC/Iface/Tidy.hs
- compiler/GHC/Iface/Type.hs
- compiler/GHC/IfaceToCore.hs
- compiler/GHC/IfaceToCore.hs-boot
- compiler/GHC/JS/Opt/Expr.hs
- compiler/GHC/JS/Opt/Simple.hs
- compiler/GHC/Linker/Deps.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/Annotation.hs
- compiler/GHC/Parser/Errors/Ppr.hs
- compiler/GHC/Parser/Errors/Types.hs
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Parser/PostProcess/Haddock.hs
- compiler/GHC/Parser/String.hs
- compiler/GHC/Platform.hs
- compiler/GHC/Platform/LoongArch64.hs
- compiler/GHC/Plugins.hs
- compiler/GHC/Rename/Bind.hs
- compiler/GHC/Rename/Env.hs
- compiler/GHC/Rename/Expr.hs
- compiler/GHC/Rename/Fixity.hs
- 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/Debugger.hs
- + compiler/GHC/Runtime/Debugger/Breakpoints.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Runtime/Eval/Types.hs
- + compiler/GHC/Runtime/Eval/Utils.hs
- compiler/GHC/Runtime/Heap/Inspect.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/Runtime/Interpreter/JS.hs
- compiler/GHC/Runtime/Interpreter/Types.hs
- compiler/GHC/Runtime/Interpreter/Wasm.hs
- compiler/GHC/Runtime/Loader.hs
- compiler/GHC/Settings/IO.hs
- compiler/GHC/Stg/CSE.hs
- compiler/GHC/Stg/Unarise.hs
- compiler/GHC/StgToByteCode.hs
- compiler/GHC/StgToCmm/Config.hs
- compiler/GHC/StgToCmm/Prim.hs
- compiler/GHC/StgToCmm/TagCheck.hs
- compiler/GHC/SysTools/Cpp.hs
- compiler/GHC/SysTools/Process.hs
- compiler/GHC/Tc/Deriv.hs
- compiler/GHC/Tc/Deriv/Generate.hs
- compiler/GHC/Tc/Deriv/Generics.hs
- compiler/GHC/Tc/Errors.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/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/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/Rule.hs
- compiler/GHC/Tc/Gen/Sig.hs
- compiler/GHC/Tc/Gen/Splice.hs
- compiler/GHC/Tc/Gen/Splice.hs-boot
- compiler/GHC/Tc/Instance/Family.hs
- compiler/GHC/Tc/Instance/FunDeps.hs
- compiler/GHC/Tc/Module.hs
- compiler/GHC/Tc/Plugin.hs
- compiler/GHC/Tc/Solver.hs
- compiler/GHC/Tc/Solver/Default.hs
- compiler/GHC/Tc/Solver/Dict.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/Rewrite.hs
- compiler/GHC/Tc/Solver/Solve.hs
- compiler/GHC/Tc/Solver/Types.hs
- compiler/GHC/Tc/TyCl.hs
- compiler/GHC/Tc/TyCl/Build.hs
- compiler/GHC/Tc/TyCl/Class.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/Types/TH.hs
- compiler/GHC/Tc/Types/TcRef.hs
- compiler/GHC/Tc/Utils/Backpack.hs
- compiler/GHC/Tc/Utils/Env.hs
- compiler/GHC/Tc/Utils/Instantiate.hs
- compiler/GHC/Tc/Utils/Monad.hs
- compiler/GHC/Tc/Utils/TcMType.hs
- compiler/GHC/Tc/Utils/TcType.hs
- compiler/GHC/Tc/Utils/Unify.hs
- compiler/GHC/Tc/Validity.hs
- compiler/GHC/Tc/Zonk/Env.hs
- compiler/GHC/Tc/Zonk/TcType.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/Breakpoint.hs
- compiler/GHC/Types/CostCentre.hs
- compiler/GHC/Types/CostCentre/State.hs
- compiler/GHC/Types/DefaultEnv.hs
- compiler/GHC/Types/Error/Codes.hs
- compiler/GHC/Types/ForeignCall.hs
- compiler/GHC/Types/GREInfo.hs
- compiler/GHC/Types/Hint.hs
- compiler/GHC/Types/Hint/Ppr.hs
- compiler/GHC/Types/HpcInfo.hs
- compiler/GHC/Types/Id.hs
- compiler/GHC/Types/Id/Make.hs
- compiler/GHC/Types/Literal.hs
- compiler/GHC/Types/Name.hs
- compiler/GHC/Types/Name/Occurrence.hs
- compiler/GHC/Types/Name/Ppr.hs
- compiler/GHC/Types/Name/Reader.hs
- compiler/GHC/Types/PkgQual.hs
- compiler/GHC/Types/ProfAuto.hs
- compiler/GHC/Types/SafeHaskell.hs
- compiler/GHC/Types/SourceFile.hs
- compiler/GHC/Types/SptEntry.hs
- compiler/GHC/Types/SrcLoc.hs
- compiler/GHC/Types/TyThing/Ppr.hs
- compiler/GHC/Types/Unique/Supply.hs
- compiler/GHC/Types/Var.hs
- compiler/GHC/Types/Var/Env.hs
- compiler/GHC/Unit/External.hs
- compiler/GHC/Unit/Finder.hs
- compiler/GHC/Unit/Module/Deps.hs
- − compiler/GHC/Unit/Module/External/Graph.hs
- compiler/GHC/Unit/Module/Graph.hs
- compiler/GHC/Unit/Module/ModDetails.hs
- compiler/GHC/Unit/Module/ModGuts.hs
- compiler/GHC/Unit/Module/ModIface.hs
- compiler/GHC/Unit/Module/ModNodeKey.hs
- compiler/GHC/Unit/Types.hs
- compiler/GHC/Utils/Binary.hs
- compiler/GHC/Utils/Logger.hs
- compiler/GHC/Utils/Outputable.hs
- compiler/GHC/Utils/Panic.hs
- compiler/GHC/Utils/Unique.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/Extension.hs
- compiler/Language/Haskell/Syntax/Pat.hs
- compiler/Language/Haskell/Syntax/Type.hs
- compiler/Language/Haskell/Syntax/Type.hs-boot
- compiler/ghc.cabal.in
- configure.ac
- docs/users_guide/9.14.1-notes.rst
- docs/users_guide/expected-undocumented-flags.txt
- docs/users_guide/exts/ffi.rst
- docs/users_guide/exts/instances.rst
- docs/users_guide/exts/linear_types.rst
- docs/users_guide/exts/monad_comprehensions.rst
- docs/users_guide/exts/named_defaults.rst
- docs/users_guide/exts/overloaded_strings.rst
- docs/users_guide/exts/parallel_list_comprehensions.rst
- docs/users_guide/exts/poly_kinds.rst
- docs/users_guide/exts/pragmas.rst
- + docs/users_guide/exts/type_defaulting.rst
- docs/users_guide/exts/types.rst
- docs/users_guide/ghci.rst
- docs/users_guide/phases.rst
- docs/users_guide/runtime_control.rst
- docs/users_guide/using-concurrent.rst
- docs/users_guide/using-optimisation.rst
- docs/users_guide/using-warnings.rst
- docs/users_guide/using.rst
- docs/users_guide/wasm.rst
- + ghc/GHC/Driver/Session/Lint.hs
- + ghc/GHC/Driver/Session/Mode.hs
- ghc/GHCi/UI.hs
- ghc/GHCi/UI/Monad.hs
- ghc/Main.hs
- ghc/ghc-bin.cabal.in
- hadrian/doc/flavours.md
- hadrian/src/CommandLine.hs
- hadrian/src/Flavour.hs
- hadrian/src/Flavour/Type.hs
- hadrian/src/Hadrian/Haskell/Hash.hs
- hadrian/src/Oracles/Flag.hs
- hadrian/src/Oracles/Setting.hs
- hadrian/src/Rules/Generate.hs
- hadrian/src/Rules/Test.hs
- hadrian/src/Settings.hs
- hadrian/src/Settings/Builders/Cabal.hs
- hadrian/src/Settings/Builders/RunTest.hs
- hadrian/src/Settings/Default.hs
- hadrian/src/Settings/Flavours/Release.hs
- hadrian/src/Settings/Packages.hs
- libraries/array
- libraries/base/base.cabal.in
- libraries/base/changelog.md
- − libraries/base/src/GHC/ExecutionStack/Internal.hs
- libraries/base/src/GHC/RTS/Flags.hs
- libraries/base/src/GHC/Records.hs
- libraries/base/src/GHC/Stats.hs
- − libraries/base/src/GHC/TypeLits/Internal.hs
- − libraries/base/src/GHC/TypeNats/Internal.hs
- + libraries/ghc-boot-th/GHC/Boot/TH/Lib.hs
- libraries/ghc-boot-th/GHC/Internal/TH/Lib/Map.hs → libraries/ghc-boot-th/GHC/Boot/TH/Lib/Map.hs
- + libraries/ghc-boot-th/GHC/Boot/TH/Lift.hs
- libraries/ghc-boot-th/GHC/Internal/TH/Ppr.hs → libraries/ghc-boot-th/GHC/Boot/TH/Ppr.hs
- libraries/ghc-boot-th/GHC/Internal/TH/PprLib.hs → libraries/ghc-boot-th/GHC/Boot/TH/PprLib.hs
- + libraries/ghc-boot-th/GHC/Boot/TH/Quote.hs
- + libraries/ghc-boot-th/GHC/Boot/TH/Syntax.hs
- libraries/ghc-boot-th/ghc-boot-th.cabal.in
- libraries/ghc-boot/GHC/Serialized.hs
- libraries/ghc-experimental/src/GHC/Wasm/Prim.hs
- + libraries/ghc-internal/cbits/int64x2minmax.c
- + libraries/ghc-internal/cbits/vectorQuotRem.c
- libraries/ghc-internal/ghc-internal.cabal.in
- libraries/ghc-internal/src/GHC/Internal/Float.hs
- libraries/ghc-internal/src/GHC/Internal/Numeric.hs
- libraries/ghc-internal/src/GHC/Internal/Pack.hs
- libraries/ghc-internal/src/GHC/Internal/Real.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Lib.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Syntax.hs
- libraries/ghc-internal/src/GHC/Internal/TypeError.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Exports.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Flag.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Imports.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Types.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/ResolvedBCO.hs
- libraries/ghci/GHCi/Server.hs
- libraries/ghci/GHCi/Signals.hs
- libraries/ghci/GHCi/TH.hs
- libraries/ghci/GHCi/TH/Binary.hs
- libraries/template-haskell/Language/Haskell/TH/Lib.hs
- − libraries/template-haskell/Language/Haskell/TH/Lib/Internal.hs
- libraries/template-haskell/Language/Haskell/TH/Ppr.hs
- libraries/template-haskell/Language/Haskell/TH/PprLib.hs
- libraries/template-haskell/Language/Haskell/TH/Quote.hs
- libraries/template-haskell/Language/Haskell/TH/Syntax.hs
- libraries/template-haskell/changelog.md
- libraries/template-haskell/template-haskell.cabal.in
- m4/fp_settings.m4
- m4/fptools_set_c_ld_flags.m4
- nofib
- rts/HeapStackCheck.cmm
- rts/IOManager.c
- rts/Interpreter.c
- rts/PrimOps.cmm
- rts/RtsAPI.c
- rts/RtsSymbols.c
- rts/RtsUtils.c
- rts/include/HsFFI.h
- rts/include/RtsAPI.h
- rts/linker/MachO.c
- rts/linker/MachOTypes.h
- rts/wasm/JSFFI.c
- rts/wasm/blocker.cmm
- rts/wasm/jsval.cmm
- rts/wasm/scheduler.cmm
- testsuite/config/ghc
- testsuite/driver/junit.py
- testsuite/driver/perf_notes.py
- testsuite/driver/testlib.py
- testsuite/ghc-config/ghc-config.hs
- testsuite/mk/boilerplate.mk
- testsuite/tests/backpack/should_fail/bkpfail51.stderr
- + testsuite/tests/bytecode/T25975.hs
- + testsuite/tests/bytecode/T25975.stdout
- testsuite/tests/bytecode/all.T
- + testsuite/tests/cmm/opt/T25771.cmm
- + testsuite/tests/cmm/opt/T25771.stderr
- testsuite/tests/cmm/opt/all.T
- testsuite/tests/cmm/should_run/AtomicFetch_cmm.cmm
- testsuite/tests/codeGen/should_compile/T25177.stderr
- testsuite/tests/codeGen/should_run/all.T
- + testsuite/tests/core-to-stg/T23865.hs
- testsuite/tests/core-to-stg/all.T
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- + testsuite/tests/deSugar/should_compile/T10251.stderr
- + testsuite/tests/default/T25775.hs
- + testsuite/tests/default/T25775.stderr
- + testsuite/tests/default/T25857.hs
- + testsuite/tests/default/T25857.stderr
- + testsuite/tests/default/T25858.hs
- + testsuite/tests/default/T25858.stdout
- + testsuite/tests/default/T25858v1.hs
- + testsuite/tests/default/T25858v1.stdout
- + testsuite/tests/default/T25858v1_helper.hs
- + testsuite/tests/default/T25858v2.hs
- + testsuite/tests/default/T25858v2.stdout
- + testsuite/tests/default/T25858v2_helper.hs
- + testsuite/tests/default/T25858v3.hs
- + testsuite/tests/default/T25858v3.stdout
- + testsuite/tests/default/T25858v3_helper.hs
- + testsuite/tests/default/T25858v4.hs
- + testsuite/tests/default/T25858v4.stdout
- + testsuite/tests/default/T25882.hs
- + testsuite/tests/default/T25912.hs
- + testsuite/tests/default/T25912.stdout
- + testsuite/tests/default/T25912_helper.hs
- + testsuite/tests/default/T25914.hs
- + testsuite/tests/default/T25934.hs
- testsuite/tests/default/all.T
- testsuite/tests/default/default-fail01.stderr
- testsuite/tests/default/default-fail02.stderr
- testsuite/tests/default/default-fail03.stderr
- testsuite/tests/default/default-fail04.stderr
- testsuite/tests/default/default-fail08.hs
- testsuite/tests/default/default-fail08.stderr
- + testsuite/tests/dependent/should_compile/GADTSingletons.hs
- + testsuite/tests/dependent/should_compile/T12088a.hs
- + testsuite/tests/dependent/should_compile/T12088b.hs
- + testsuite/tests/dependent/should_compile/T12088c.hs
- + testsuite/tests/dependent/should_compile/T12088d.hs
- + testsuite/tests/dependent/should_compile/T12088e.hs
- + testsuite/tests/dependent/should_compile/T12088f.hs
- + testsuite/tests/dependent/should_compile/T12088g.hs
- + testsuite/tests/dependent/should_compile/T12088i.hs
- + testsuite/tests/dependent/should_compile/T12088j.hs
- + testsuite/tests/dependent/should_compile/T12088mm1.hs
- + testsuite/tests/dependent/should_compile/T12088mm1_helper.hs
- + testsuite/tests/dependent/should_compile/T12088mm2.hs
- + testsuite/tests/dependent/should_compile/T12088mm2_helper.hs
- + testsuite/tests/dependent/should_compile/T12088mm3.hs
- + testsuite/tests/dependent/should_compile/T12088mm3_helper.hs
- + testsuite/tests/dependent/should_compile/T12088sg1.hs
- + testsuite/tests/dependent/should_compile/T12088sg2.hs
- + testsuite/tests/dependent/should_compile/T12088sg3.hs
- + testsuite/tests/dependent/should_compile/T12239.hs
- + testsuite/tests/dependent/should_compile/T13790.hs
- + testsuite/tests/dependent/should_compile/T14668a.hs
- + testsuite/tests/dependent/should_compile/T14668b.hs
- + testsuite/tests/dependent/should_compile/T15561.hs
- + testsuite/tests/dependent/should_compile/T16410.hs
- + testsuite/tests/dependent/should_compile/T16448.hs
- + testsuite/tests/dependent/should_compile/T16693.hs
- + testsuite/tests/dependent/should_compile/T19611.hs
- + testsuite/tests/dependent/should_compile/T20875.hs
- + testsuite/tests/dependent/should_compile/T21172.hs
- + testsuite/tests/dependent/should_compile/T22257a.hs
- + testsuite/tests/dependent/should_compile/T22257b.hs
- + testsuite/tests/dependent/should_compile/T25238.hs
- + testsuite/tests/dependent/should_compile/T25834.hs
- testsuite/tests/dependent/should_compile/all.T
- testsuite/tests/dependent/should_fail/T16326_Fail8.stderr
- testsuite/tests/deriving/should_compile/T17324.stderr
- testsuite/tests/deriving/should_compile/T17339.stderr
- testsuite/tests/diagnostic-codes/codes.stdout
- + testsuite/tests/driver/RecompCompletePragma/A1.hs
- + testsuite/tests/driver/RecompCompletePragma/A2.hs
- + testsuite/tests/driver/RecompCompletePragma/A3.hs
- + testsuite/tests/driver/RecompCompletePragma/A4.hs
- + testsuite/tests/driver/RecompCompletePragma/B1.hs
- + testsuite/tests/driver/RecompCompletePragma/C1.hs
- + testsuite/tests/driver/RecompCompletePragma/C2.hs
- + testsuite/tests/driver/RecompCompletePragma/C3.hs
- + testsuite/tests/driver/RecompCompletePragma/Makefile
- + testsuite/tests/driver/RecompCompletePragma/RecompCompleteFixity.stderr
- + testsuite/tests/driver/RecompCompletePragma/RecompCompleteFixity.stdout
- + testsuite/tests/driver/RecompCompletePragma/RecompCompleteFixityA.hs
- + testsuite/tests/driver/RecompCompletePragma/RecompCompleteFixityB.hs
- + testsuite/tests/driver/RecompCompletePragma/RecompCompleteIndependence.hs
- + testsuite/tests/driver/RecompCompletePragma/RecompCompleteIndependence.stdout
- + testsuite/tests/driver/RecompCompletePragma/RecompCompletePragma.stderr
- + testsuite/tests/driver/RecompCompletePragma/RecompCompletePragma.stdout
- + testsuite/tests/driver/RecompCompletePragma/RecompCompletePragma2.stdout
- + testsuite/tests/driver/RecompCompletePragma/RecompCompletePragmaA.hs
- + testsuite/tests/driver/RecompCompletePragma/RecompCompletePragmaB.hs
- + testsuite/tests/driver/RecompCompletePragma/all.T
- + testsuite/tests/driver/RecompExportedDefault/A.hs
- + testsuite/tests/driver/RecompExportedDefault/A2.hs
- + testsuite/tests/driver/RecompExportedDefault/A3.hs
- + testsuite/tests/driver/RecompExportedDefault/A4.hs
- + testsuite/tests/driver/RecompExportedDefault/Makefile
- + testsuite/tests/driver/RecompExportedDefault/RecompExportedDefault.hs
- + testsuite/tests/driver/RecompExportedDefault/RecompExportedDefault.stdout
- + testsuite/tests/driver/RecompExportedDefault/all.T
- + testsuite/tests/driver/RecompExports/Makefile
- + testsuite/tests/driver/RecompExports/RecompExports1.stderr
- + testsuite/tests/driver/RecompExports/RecompExports1.stdout
- + testsuite/tests/driver/RecompExports/RecompExports1_M.hs_1
- + testsuite/tests/driver/RecompExports/RecompExports1_M.hs_2
- + testsuite/tests/driver/RecompExports/RecompExports1_M.hs_3
- + testsuite/tests/driver/RecompExports/RecompExports1_N.hs
- + testsuite/tests/driver/RecompExports/RecompExports2.stderr
- + testsuite/tests/driver/RecompExports/RecompExports2.stdout
- + testsuite/tests/driver/RecompExports/RecompExports2_M.hs_1
- + testsuite/tests/driver/RecompExports/RecompExports2_M.hs_2
- + testsuite/tests/driver/RecompExports/RecompExports2_M.hs_3
- + testsuite/tests/driver/RecompExports/RecompExports2_N.hs
- + testsuite/tests/driver/RecompExports/RecompExports3.stderr
- + testsuite/tests/driver/RecompExports/RecompExports3.stdout
- + testsuite/tests/driver/RecompExports/RecompExports3_M.hs_1
- + testsuite/tests/driver/RecompExports/RecompExports3_M.hs_2
- + testsuite/tests/driver/RecompExports/RecompExports3_M.hs_3
- + testsuite/tests/driver/RecompExports/RecompExports3_N.hs
- + testsuite/tests/driver/RecompExports/RecompExports4.stderr
- + testsuite/tests/driver/RecompExports/RecompExports4.stdout
- + testsuite/tests/driver/RecompExports/RecompExports4_M.hs_1
- + testsuite/tests/driver/RecompExports/RecompExports4_M.hs_2
- + testsuite/tests/driver/RecompExports/RecompExports4_N.hs
- + testsuite/tests/driver/RecompExports/RecompExports5.stdout
- + testsuite/tests/driver/RecompExports/RecompExports5_M.hs_1
- + testsuite/tests/driver/RecompExports/RecompExports5_M.hs_2
- + testsuite/tests/driver/RecompExports/RecompExports5_N.hs
- + testsuite/tests/driver/RecompExports/all.T
- testsuite/tests/driver/T20459.stderr
- testsuite/tests/driver/T24196/T24196.stderr
- testsuite/tests/driver/T24275/T24275.stderr
- testsuite/tests/driver/dynamicToo/dynamicToo001/Makefile
- + testsuite/tests/driver/dynamicToo/dynamicToo001/T25837.stdout
- + testsuite/tests/driver/dynamicToo/dynamicToo001/T25837Module.hs
- testsuite/tests/driver/dynamicToo/dynamicToo001/test.T
- testsuite/tests/driver/inline-check.stderr
- + testsuite/tests/driver/self-recomp/Makefile
- + testsuite/tests/driver/self-recomp/SelfRecomp01.hs
- + testsuite/tests/driver/self-recomp/SelfRecomp02.hs
- + testsuite/tests/driver/self-recomp/SelfRecomp03.hs
- + testsuite/tests/driver/self-recomp/SelfRecomp04.hs
- + testsuite/tests/driver/self-recomp/SelfRecomp04.stdout
- + testsuite/tests/driver/self-recomp/all.T
- testsuite/tests/ffi/should_compile/all.T
- testsuite/tests/ghc-api/Makefile
- testsuite/tests/ghc-api/T18522-dbg-ppr.hs
- + testsuite/tests/ghc-api/T25577.hs
- testsuite/tests/ghc-api/all.T
- testsuite/tests/ghc-api/exactprint/Test20239.stderr
- + testsuite/tests/ghc-api/fixed-nodes/FixedNodes.hs
- + testsuite/tests/ghc-api/fixed-nodes/FixedNodes.stdout
- + testsuite/tests/ghc-api/fixed-nodes/InterfaceModuleGraph.hs
- + testsuite/tests/ghc-api/fixed-nodes/InterfaceModuleGraph.stdout
- + testsuite/tests/ghc-api/fixed-nodes/Makefile
- + testsuite/tests/ghc-api/fixed-nodes/ModuleGraphInvariants.hs
- + testsuite/tests/ghc-api/fixed-nodes/ModuleGraphInvariants.stdout
- + testsuite/tests/ghc-api/fixed-nodes/T1.hs
- + testsuite/tests/ghc-api/fixed-nodes/T1A.hs
- + testsuite/tests/ghc-api/fixed-nodes/T1B.hs
- + testsuite/tests/ghc-api/fixed-nodes/T1C.hs
- + testsuite/tests/ghc-api/fixed-nodes/all.T
- testsuite/tests/ghc-api/settings-escape/T11938.hs → testsuite/tests/ghc-api/settings-escape/T24265.hs
- testsuite/tests/ghc-api/settings-escape/T11938.stderr → testsuite/tests/ghc-api/settings-escape/T24265.stderr
- + testsuite/tests/ghc-api/settings-escape/T25204.hs
- + testsuite/tests/ghc-api/settings-escape/T25204.stdout
- + testsuite/tests/ghc-api/settings-escape/T25204_C.c
- testsuite/tests/ghc-api/settings-escape/all.T
- + testsuite/tests/ghc-api/settings-escape/ghc-install-folder/ghc version.h
- testsuite/tests/ghc-api/settings-escape/ghc-install-folder/lib/.gitkeep → testsuite/tests/ghc-api/settings-escape/ghc-install-folder/lib with spaces/.gitkeep
- testsuite/tests/ghc-e/should_fail/T9930fail.stderr
- + testsuite/tests/ghci-browser/all.T
- + testsuite/tests/ghci-browser/browser001.script
- + testsuite/tests/ghci-browser/browser001.stdout
- + testsuite/tests/ghci.debugger/scripts/T25932.hs
- + testsuite/tests/ghci.debugger/scripts/T25932.script
- + testsuite/tests/ghci.debugger/scripts/T25932.stdout
- testsuite/tests/ghci.debugger/scripts/T8487.script
- testsuite/tests/ghci.debugger/scripts/all.T
- testsuite/tests/ghci.debugger/scripts/break018.script
- testsuite/tests/ghci.debugger/scripts/break018.stdout
- testsuite/tests/ghci.debugger/scripts/dynbrk004.stdout
- testsuite/tests/ghci.debugger/scripts/dynbrk007.script
- testsuite/tests/ghci.debugger/scripts/dynbrk007.stdout
- testsuite/tests/ghci/scripts/T12550.stdout
- testsuite/tests/ghci/scripts/T4175.stdout
- testsuite/tests/ghci/scripts/ghci024.stdout
- testsuite/tests/ghci/scripts/ghci024.stdout-mingw32
- testsuite/tests/ghci/scripts/ghci064.stdout
- testsuite/tests/ghci/should_run/Makefile
- + testsuite/tests/ghci/should_run/T25790.hs
- + testsuite/tests/ghci/should_run/T25790.script
- + testsuite/tests/ghci/should_run/TopEnvIface.hs
- + testsuite/tests/ghci/should_run/TopEnvIface.stdout
- + testsuite/tests/ghci/should_run/TopEnvIface2.hs
- testsuite/tests/ghci/should_run/all.T
- testsuite/tests/haddock/should_compile_flag_haddock/T17544.stderr
- testsuite/tests/haddock/should_compile_flag_haddock/T17544_kw.hs
- testsuite/tests/haddock/should_compile_flag_haddock/T17544_kw.stderr
- testsuite/tests/haddock/should_compile_flag_haddock/T24221.stderr
- testsuite/tests/hpc/fork/hpc_fork.stdout
- testsuite/tests/hpc/function/tough.stdout
- testsuite/tests/hpc/function2/tough2.stdout
- + testsuite/tests/indexed-types/should_compile/T25657.hs
- testsuite/tests/indexed-types/should_compile/all.T
- testsuite/tests/indexed-types/should_fail/T8550.stderr
- testsuite/tests/interface-stability/README.mkd
- testsuite/tests/interface-stability/all.T
- 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-bignum-exports.stdout
- + testsuite/tests/interface-stability/ghc-prim-exports.stdout
- + testsuite/tests/interface-stability/ghc-prim-exports.stdout-mingw32
- testsuite/tests/interface-stability/template-haskell-exports.stdout
- testsuite/tests/jsffi/all.T
- + testsuite/tests/jsffi/cancel.hs
- + testsuite/tests/jsffi/cancel.mjs
- + testsuite/tests/jsffi/cancel.stdout
- testsuite/tests/jsffi/jsffigc.hs
- testsuite/tests/jsffi/jsffigc.mjs
- testsuite/tests/jsffi/jsffisleep.hs
- testsuite/tests/jsffi/jsffisleep.stdout
- testsuite/tests/jsffi/textconv.hs
- testsuite/tests/jsffi/textconv.mjs
- + testsuite/tests/linear/should_compile/NonLinearRecord.hs
- testsuite/tests/linear/should_compile/all.T
- + testsuite/tests/linear/should_fail/LinearRecFieldMany.hs
- + testsuite/tests/linear/should_fail/LinearRecFieldMany.stderr
- testsuite/tests/linear/should_fail/all.T
- testsuite/tests/linters/notes.stdout
- + testsuite/tests/llvm/should_run/T25770.hs
- + testsuite/tests/llvm/should_run/T25770.stdout
- testsuite/tests/llvm/should_run/all.T
- testsuite/tests/module/T11970A.stderr
- testsuite/tests/module/all.T
- testsuite/tests/module/mod132.stderr
- testsuite/tests/module/mod147.stderr
- testsuite/tests/module/mod176.stderr
- testsuite/tests/module/mod58.stderr
- testsuite/tests/module/mod73.hs
- testsuite/tests/module/mod73.stderr
- testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail06.stderr
- testsuite/tests/parser/should_compile/DumpParsedAst.stderr
- testsuite/tests/parser/should_compile/DumpRenamedAst.stderr
- testsuite/tests/parser/should_compile/DumpSemis.stderr
- testsuite/tests/parser/should_compile/KindSigs.stderr
- testsuite/tests/parser/should_compile/OpaqueParseWarn1.stderr
- testsuite/tests/parser/should_compile/T14189.stderr
- testsuite/tests/parser/should_compile/T15279.stderr
- testsuite/tests/parser/should_compile/T20452.stderr
- testsuite/tests/parser/should_fail/T3811c.stderr
- testsuite/tests/parser/should_fail/T7848.stderr
- testsuite/tests/parser/should_fail/readFail038.stderr
- testsuite/tests/parser/should_fail/unpack_inside_type.stderr
- + testsuite/tests/parser/should_run/T25784.hs
- + testsuite/tests/parser/should_run/T25784.stdout
- testsuite/tests/parser/should_run/all.T
- testsuite/tests/partial-sigs/should_fail/WildcardInInstanceHead.stderr
- testsuite/tests/perf/compiler/Makefile
- testsuite/tests/perf/compiler/WWRec.hs
- testsuite/tests/perf/compiler/all.T
- testsuite/tests/perf/compiler/hard_hole_fits.hs
- testsuite/tests/perf/compiler/hard_hole_fits.stderr
- + testsuite/tests/perf/should_run/ByteCodeAsm.hs
- testsuite/tests/perf/should_run/all.T
- testsuite/tests/plugins/T20803-plugin/FixErrorsPlugin.hs
- testsuite/tests/plugins/defaulting-plugin/DefaultLifted.hs
- testsuite/tests/plugins/plugins10.stdout
- testsuite/tests/plugins/static-plugins.stdout
- testsuite/tests/polykinds/T18300.hs
- testsuite/tests/polykinds/T18300.stderr
- testsuite/tests/primops/should_run/all.T
- testsuite/tests/printer/Makefile
- testsuite/tests/printer/T18791.stderr
- testsuite/tests/printer/Test24533.stdout
- + testsuite/tests/printer/Test25885.hs
- testsuite/tests/printer/all.T
- testsuite/tests/quasiquotation/T7918.hs
- testsuite/tests/rename/should_compile/T14881.stderr
- + testsuite/tests/rename/should_compile/T24027.hs
- + testsuite/tests/rename/should_compile/T24027_aux.hs
- + testsuite/tests/rename/should_compile/T24035.hs
- + testsuite/tests/rename/should_compile/T24035_aux.hs
- + testsuite/tests/rename/should_compile/T24035b.hs
- + testsuite/tests/rename/should_compile/T24035b.stderr
- + testsuite/tests/rename/should_compile/T25892.hs
- + testsuite/tests/rename/should_compile/T25892_aux.hs
- testsuite/tests/rename/should_compile/all.T
- testsuite/tests/rename/should_fail/SimilarNamesImport.stderr
- testsuite/tests/rename/should_fail/T16114.stderr
- testsuite/tests/rename/should_fail/T18240a.stderr
- testsuite/tests/rename/should_fail/T19843c.stderr
- testsuite/tests/rename/should_fail/T22478b.stderr
- testsuite/tests/rename/should_fail/T22478e.stderr
- testsuite/tests/rename/should_fail/T22478f.stderr
- + testsuite/tests/rename/should_fail/T22688.hs
- + testsuite/tests/rename/should_fail/T22688.stderr
- testsuite/tests/rename/should_fail/T23510a.hs
- testsuite/tests/rename/should_fail/T23510a.stderr
- + testsuite/tests/rename/should_fail/T23982.hs
- + testsuite/tests/rename/should_fail/T23982.stderr
- + testsuite/tests/rename/should_fail/T23982_aux.hs
- + testsuite/tests/rename/should_fail/T23982b.hs
- + testsuite/tests/rename/should_fail/T23982b.stderr
- + testsuite/tests/rename/should_fail/T23982b_aux.hs
- + testsuite/tests/rename/should_fail/T25877.hs
- + testsuite/tests/rename/should_fail/T25877.stderr
- + testsuite/tests/rename/should_fail/T25877_aux.hs
- testsuite/tests/rename/should_fail/T5951.stderr
- testsuite/tests/rename/should_fail/all.T
- testsuite/tests/rep-poly/T14561b.stderr
- testsuite/tests/rep-poly/UnliftedNewtypesCoerceFail.stderr
- testsuite/tests/roles/should_compile/T8958.stderr
- testsuite/tests/rts/T13082/Makefile
- testsuite/tests/rts/T13082/T13082_fail.stderr → testsuite/tests/rts/T13082/T13082_fail.stdout
- testsuite/tests/rts/all.T
- testsuite/tests/saks/should_fail/T16722.stderr
- testsuite/tests/saks/should_fail/saks_fail003.stderr
- testsuite/tests/showIface/Orphans.stdout
- testsuite/tests/simd/should_run/all.T
- + testsuite/tests/simd/should_run/doublex2_arith.hs
- + testsuite/tests/simd/should_run/doublex2_arith.stdout
- + testsuite/tests/simd/should_run/doublex2_arith_baseline.hs
- + testsuite/tests/simd/should_run/doublex2_arith_baseline.stdout
- + testsuite/tests/simd/should_run/doublex2_fma.hs
- + testsuite/tests/simd/should_run/doublex2_fma.stdout
- + testsuite/tests/simd/should_run/floatx4_arith.hs
- + testsuite/tests/simd/should_run/floatx4_arith.stdout
- + testsuite/tests/simd/should_run/floatx4_arith_baseline.hs
- + testsuite/tests/simd/should_run/floatx4_arith_baseline.stdout
- + testsuite/tests/simd/should_run/floatx4_fma.hs
- + testsuite/tests/simd/should_run/floatx4_fma.stdout
- + testsuite/tests/simd/should_run/int16x8_arith.hs
- + testsuite/tests/simd/should_run/int16x8_arith.stdout
- + testsuite/tests/simd/should_run/int16x8_arith_baseline.hs
- + testsuite/tests/simd/should_run/int16x8_arith_baseline.stdout
- + testsuite/tests/simd/should_run/int16x8_shuffle.hs
- + testsuite/tests/simd/should_run/int16x8_shuffle.stdout
- + testsuite/tests/simd/should_run/int16x8_shuffle_baseline.hs
- + testsuite/tests/simd/should_run/int16x8_shuffle_baseline.stdout
- + testsuite/tests/simd/should_run/int32x4_arith.hs
- + testsuite/tests/simd/should_run/int32x4_arith.stdout
- + testsuite/tests/simd/should_run/int32x4_arith_baseline.hs
- + testsuite/tests/simd/should_run/int32x4_arith_baseline.stdout
- + testsuite/tests/simd/should_run/int32x4_shuffle.hs
- + testsuite/tests/simd/should_run/int32x4_shuffle.stdout
- + testsuite/tests/simd/should_run/int32x4_shuffle_baseline.hs
- + testsuite/tests/simd/should_run/int32x4_shuffle_baseline.stdout
- + testsuite/tests/simd/should_run/int64x2_arith.hs
- + testsuite/tests/simd/should_run/int64x2_arith.stdout
- + testsuite/tests/simd/should_run/int64x2_arith_baseline.hs
- + testsuite/tests/simd/should_run/int64x2_arith_baseline.stdout
- + testsuite/tests/simd/should_run/int64x2_shuffle.hs
- + testsuite/tests/simd/should_run/int64x2_shuffle.stdout
- + testsuite/tests/simd/should_run/int64x2_shuffle_baseline.hs
- + testsuite/tests/simd/should_run/int64x2_shuffle_baseline.stdout
- + testsuite/tests/simd/should_run/int8x16_arith.hs
- + testsuite/tests/simd/should_run/int8x16_arith.stdout
- + testsuite/tests/simd/should_run/int8x16_arith_baseline.hs
- + testsuite/tests/simd/should_run/int8x16_arith_baseline.stdout
- + testsuite/tests/simd/should_run/int8x16_shuffle.hs
- + testsuite/tests/simd/should_run/int8x16_shuffle.stdout
- + testsuite/tests/simd/should_run/int8x16_shuffle_baseline.hs
- + testsuite/tests/simd/should_run/int8x16_shuffle_baseline.stdout
- + testsuite/tests/simd/should_run/word16x8_arith.hs
- + testsuite/tests/simd/should_run/word16x8_arith.stdout
- + testsuite/tests/simd/should_run/word16x8_arith_baseline.hs
- + testsuite/tests/simd/should_run/word16x8_arith_baseline.stdout
- + testsuite/tests/simd/should_run/word32x4_arith.hs
- + testsuite/tests/simd/should_run/word32x4_arith.stdout
- + testsuite/tests/simd/should_run/word32x4_arith_baseline.hs
- + testsuite/tests/simd/should_run/word32x4_arith_baseline.stdout
- + testsuite/tests/simd/should_run/word64x2_arith.hs
- + testsuite/tests/simd/should_run/word64x2_arith.stdout
- + testsuite/tests/simd/should_run/word64x2_arith_baseline.hs
- + testsuite/tests/simd/should_run/word64x2_arith_baseline.stdout
- + testsuite/tests/simd/should_run/word8x16_arith.hs
- + testsuite/tests/simd/should_run/word8x16_arith.stdout
- + testsuite/tests/simd/should_run/word8x16_arith_baseline.hs
- + testsuite/tests/simd/should_run/word8x16_arith_baseline.stdout
- + testsuite/tests/simplCore/should_compile/DsSpecPragmas.hs
- + testsuite/tests/simplCore/should_compile/DsSpecPragmas.stderr
- testsuite/tests/simplCore/should_compile/Makefile
- testsuite/tests/simplCore/should_compile/RewriteHigherOrderPatterns.stderr
- testsuite/tests/simplCore/should_compile/T12603.stdout
- testsuite/tests/simplCore/should_compile/T15445.stderr
- testsuite/tests/simplCore/should_compile/T18013.stderr
- testsuite/tests/simplCore/should_compile/T18668.stderr
- testsuite/tests/simplCore/should_compile/T23307c.stderr
- + testsuite/tests/simplCore/should_compile/T24359a.hs
- + testsuite/tests/simplCore/should_compile/T24359a.stderr
- + testsuite/tests/simplCore/should_compile/T25389.hs
- + testsuite/tests/simplCore/should_compile/T25389.stderr
- + testsuite/tests/simplCore/should_compile/T25883.hs
- + testsuite/tests/simplCore/should_compile/T25883.substr-simpl
- + testsuite/tests/simplCore/should_compile/T25883b.hs
- + testsuite/tests/simplCore/should_compile/T25883b.substr-simpl
- + testsuite/tests/simplCore/should_compile/T25883c.hs
- + testsuite/tests/simplCore/should_compile/T25883c.substr-simpl
- + testsuite/tests/simplCore/should_compile/T25883d.hs
- + testsuite/tests/simplCore/should_compile/T25883d.stderr
- + testsuite/tests/simplCore/should_compile/T25883d_import.hs
- + testsuite/tests/simplCore/should_compile/T25976.hs
- + testsuite/tests/simplCore/should_compile/T3990b.hs
- + testsuite/tests/simplCore/should_compile/T3990b.stdout
- + testsuite/tests/simplCore/should_compile/T3990c.hs
- + testsuite/tests/simplCore/should_compile/T3990c.stdout
- testsuite/tests/simplCore/should_compile/T4398.stderr
- testsuite/tests/simplCore/should_compile/T5821.hs
- testsuite/tests/simplCore/should_compile/T8537.stderr
- + testsuite/tests/simplCore/should_compile/T9578b.hs
- testsuite/tests/simplCore/should_compile/all.T
- − testsuite/tests/simplCore/should_compile/simpl016.stderr
- + testsuite/tests/simplCore/should_fail/T25117a.hs
- + testsuite/tests/simplCore/should_fail/T25117a.stderr
- + testsuite/tests/simplCore/should_fail/T25117b.hs
- + testsuite/tests/simplCore/should_fail/T25117b.stderr
- + testsuite/tests/simplCore/should_fail/T25672.hs
- + testsuite/tests/simplCore/should_fail/T25672.stderr
- testsuite/tests/simplCore/should_fail/all.T
- + testsuite/tests/simplCore/should_run/T23429.hs
- + testsuite/tests/simplCore/should_run/T23429.stdout
- + testsuite/tests/simplCore/should_run/T24359b.hs
- + testsuite/tests/simplCore/should_run/T24359b.stdout
- testsuite/tests/simplCore/should_run/all.T
- + testsuite/tests/th/T13123.stderr
- testsuite/tests/th/T15365.stderr
- testsuite/tests/th/T1835.stdout
- testsuite/tests/th/T19363.stdout
- testsuite/tests/th/T7064.stdout
- testsuite/tests/th/TH_pragma.hs
- testsuite/tests/th/TH_pragma.stderr
- testsuite/tests/typecheck/should_compile/InstanceGivenOverlap.hs
- testsuite/tests/typecheck/should_compile/LoopOfTheDay1.hs
- testsuite/tests/typecheck/should_compile/LoopOfTheDay2.hs
- testsuite/tests/typecheck/should_compile/LoopOfTheDay3.hs
- + testsuite/tests/typecheck/should_compile/RuleEqs.hs
- + testsuite/tests/typecheck/should_compile/RuleEqs.stderr
- testsuite/tests/typecheck/should_compile/T10504.stderr
- + testsuite/tests/typecheck/should_compile/T21003.hs
- testsuite/tests/typecheck/should_compile/T2494.stderr
- + testsuite/tests/typecheck/should_compile/T25960.hs
- testsuite/tests/typecheck/should_compile/T7050.stderr
- + testsuite/tests/typecheck/should_compile/TcSpecPragmas.hs
- + testsuite/tests/typecheck/should_compile/TcSpecPragmas.stderr
- testsuite/tests/typecheck/should_compile/all.T
- testsuite/tests/typecheck/should_compile/tc186.hs
- testsuite/tests/typecheck/should_compile/tc212.hs
- testsuite/tests/typecheck/should_fail/ExplicitSpecificity5.stderr
- testsuite/tests/typecheck/should_fail/ExplicitSpecificity6.stderr
- + testsuite/tests/typecheck/should_fail/SpecPragmasFail.hs
- + testsuite/tests/typecheck/should_fail/SpecPragmasFail.stderr
- testsuite/tests/typecheck/should_fail/T10495.hs
- testsuite/tests/typecheck/should_fail/T10495.stderr
- testsuite/tests/typecheck/should_fail/T12729.stderr
- testsuite/tests/typecheck/should_fail/T12921.stderr
- testsuite/tests/typecheck/should_fail/T16394.stderr
- testsuite/tests/typecheck/should_fail/T19109.stderr
- testsuite/tests/typecheck/should_fail/T19978.stderr
- testsuite/tests/typecheck/should_fail/T23776.stderr
- + testsuite/tests/typecheck/should_fail/T24090a.hs
- + testsuite/tests/typecheck/should_fail/T24090a.stderr
- + testsuite/tests/typecheck/should_fail/T24090b.hs
- testsuite/tests/wcompat-warnings/WCompatWarningsOn.stderr → testsuite/tests/typecheck/should_fail/T24090b.stderr
- + testsuite/tests/typecheck/should_fail/T25004.hs
- + testsuite/tests/typecheck/should_fail/T25004.stderr
- + testsuite/tests/typecheck/should_fail/T25004k.hs
- + testsuite/tests/typecheck/should_fail/T25004k.stderr
- testsuite/tests/typecheck/should_fail/T3966.stderr
- + testsuite/tests/typecheck/should_fail/T3966b.hs
- + testsuite/tests/typecheck/should_fail/T3966b.stderr
- testsuite/tests/typecheck/should_fail/T5853.stderr
- testsuite/tests/typecheck/should_fail/T6018fail.stderr
- testsuite/tests/typecheck/should_fail/T7210.stderr
- testsuite/tests/typecheck/should_fail/TyAppPat_MisplacedApplication.hs
- testsuite/tests/typecheck/should_fail/TyAppPat_MisplacedApplication.stderr
- testsuite/tests/typecheck/should_fail/all.T
- + testsuite/tests/typecheck/should_run/T25529.hs
- + testsuite/tests/typecheck/should_run/T25529.stdout
- testsuite/tests/typecheck/should_run/all.T
- testsuite/tests/unboxedsums/unpack_sums_5.stderr
- + testsuite/tests/vdq-rta/should_fail/T23738_fail_pun.hs
- + testsuite/tests/vdq-rta/should_fail/T23738_fail_pun.stderr
- testsuite/tests/vdq-rta/should_fail/all.T
- + testsuite/tests/warnings/should_compile/SpecMultipleTys.hs
- + testsuite/tests/warnings/should_compile/SpecMultipleTys.stderr
- testsuite/tests/warnings/should_compile/T19296.stderr
- testsuite/tests/warnings/should_compile/WarnNoncanonical.stderr
- testsuite/tests/warnings/should_compile/all.T
- + testsuite/tests/warnings/should_fail/SpecEMultipleTys.hs
- + testsuite/tests/warnings/should_fail/SpecEMultipleTys.stderr
- testsuite/tests/warnings/should_fail/all.T
- testsuite/tests/wasm/should_run/control-flow/README.md
- − testsuite/tests/wasm/should_run/control-flow/WasmControlFlow.stdout
- testsuite/tests/wasm/should_run/control-flow/all.T
- testsuite/tests/wcompat-warnings/Template.hs
- utils/check-exact/ExactPrint.hs
- utils/check-exact/Main.hs
- utils/check-exact/Parsers.hs
- utils/check-exact/Transform.hs
- utils/check-exact/Utils.hs
- utils/dump-decls/Main.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Hoogle.hs
- utils/haddock/haddock-api/src/Haddock/Backends/LaTeX.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs
- utils/haddock/haddock-api/src/Haddock/Convert.hs
- utils/haddock/haddock-api/src/Haddock/GhcUtils.hs
- utils/haddock/haddock-api/src/Haddock/Interface.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Create.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Rename.hs
- utils/haddock/haddock-api/src/Haddock/Interface/RenameType.hs
- utils/haddock/haddock-api/src/Haddock/Types.hs
- utils/haddock/html-test/ref/LinearTypes.html
- utils/haddock/html-test/src/LinearTypes.hs
- utils/haddock/latex-test/ref/LinearTypes/LinearTypes.tex
- utils/haddock/latex-test/src/LinearTypes/LinearTypes.hs
- utils/jsffi/dyld.mjs
- utils/jsffi/post-link.mjs
- utils/jsffi/prelude.mjs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/aa009886182ee82920019d97743b36…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/aa009886182ee82920019d97743b36…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/supersven/riscv-fix-switch-jump-tables] 16 commits: driver: Use ModuleGraph for oneshot and --make mode
by Sven Tennie (@supersven) 23 Apr '25
by Sven Tennie (@supersven) 23 Apr '25
23 Apr '25
Sven Tennie pushed to branch wip/supersven/riscv-fix-switch-jump-tables at Glasgow Haskell Compiler / GHC
Commits:
d47bf776 by Matthew Pickering at 2025-04-14T16:44:41+01:00
driver: Use ModuleGraph for oneshot and --make mode
This patch uses the `hsc_mod_graph` field for both oneshot and --make
mode. Therefore, if part of the compiler requires usage of the module
graph, you do so in a uniform way for the two different modes.
The `ModuleGraph` describes the relationship between the modules in the
home package and units in external packages. The `ModuleGraph` can be
queried when information about the transitive closure of a package is
needed. For example, the primary use of the ModuleGraph from within the
compiler is in the loader, which needs to know the transitive closure of
a module so it can load all the relevant objects for evaluation.
In --make mode, downsweep computes the ModuleGraph before any
compilation starts.
In oneshot mode, a thunk is created at the start of compilation, which
when forced will compute the module graph beneath the current module.
The thunk is only forced at the moment when the user uses Template
Haskell.
Finally, there are some situations where we need to discover what
dependencies to load but haven't loaded a module graph at all. In this
case, there is a fallback which computes the transitive closure on the
fly and doesn't cache the result. Presumably if you are going to call
getLinkDeps a lot, you would compute the right ModuleGraph before you
started.
Importantly, this removes the ExternalModuleGraph abstraction. This was quite
awkward to work with since it stored information about the home package
inside the EPS.
This patch will also be very useful when implementing explicit level
imports, which requires more significant use of the module graph in
order to determine which level instances are available at.
Towards #25795
-------------------------
Metric Decrease:
MultiLayerModulesTH_Make
MultiLayerModulesTH_OneShot
-------------------------
- - - - -
395e0ad1 by sheaf at 2025-04-16T12:33:26-04:00
base: remove .Internal modules (e.g. GHC.TypeLits)
This commit removes the following internal modules from base,
as per CLC proposal 217:
- GHC.TypeNats.Internal
- GHC.TypeLits.Internal
- GHC.ExecutionStack.Internal
Fixes #25007
- - - - -
e0f3ff11 by Patrick at 2025-04-17T04:31:12-04:00
Refactor Handling of Multiple Default Declarations
Fixes: #25912, #25914, #25934
Previously, GHC discarded all loaded defaults (tcg_default) when local
defaults were encountered during typechecking. According to the
exportable-named-default proposal (sections 2.4.2 and 2.4.3), local
defaults should be merged into tcg_default, retaining any defaults
already present while overriding where necessary.
Key Changes:
* Introduce DefaultProvenance to track the origin of default declarations
(local, imported, or built-in), replacing the original cd_module
in ClassDefaults with cd_provenance :: DefaultProvenance.
* Rename tcDefaults to tcDefaultDecls, limiting its responsibility to only
converting renamed class defaults into ClassDefaults.
* Add extendDefaultEnvWithLocalDefaults to merge local defaults into the
environment, with proper duplication checks:
- Duplicate local defaults for a class trigger an error.
- Local defaults override imported or built-in defaults.
* Update and add related notes: Note [Builtin class defaults],
Note [DefaultProvenance].
* Add regression tests: T25912, T25914, T25934.
Thanks sam and simon for the help on this patch.
Co-authored-by: sheaf <sam.derbyshire(a)gmail.com>
- - - - -
386f1854 by Teo Camarasu at 2025-04-17T04:31:55-04:00
template-haskell: Remove `addrToByteArrayName` and `addrToByteArray`
These were part of the implementation of the `Lift ByteArray` instance and were errornously exported because this module lacked an explicit export list. They have no usages on Hackage.
Resolves #24782
- - - - -
b96e2f77 by Sylvain Henry at 2025-04-18T20:46:33-04:00
RTS: remove target info and fix host info (#24058)
The RTS isn't a compiler, hence it doesn't have a target and we remove
the reported target info displayed by "+RTS --info". We also fix the
host info displayed by "+RTS --info": the host of the RTS is the
RTS-building compiler's target, not the compiler's host (wrong when
doing cross-compilation).
- - - - -
6d9965f4 by Sylvain Henry at 2025-04-18T20:46:33-04:00
RTS: remove build info
As per the discussion in !13967, there is no reason to tag the RTS with
information about the build platform.
- - - - -
d52e9b3f by Vladislav Zavialov at 2025-04-18T20:47:15-04:00
Diagnostics: remove the KindMismatch constructor (#25957)
The KindMismatch constructor was only used as an intermediate
representation in pretty-printing.
Its removal addresses a problem detected by the "codes" test case:
[GHC-89223] is untested (constructor = KindMismatch)
In a concious deviation from the usual procedure, the error code
GHC-89223 is removed entirely rather than marked as Outdated.
The reason is that it never was user-facing in the first place.
- - - - -
e2f2f9d0 by Vladislav Zavialov at 2025-04-20T10:53:39-04:00
Add name for -Wunusable-unpack-pragmas
This warning had no name or flag and was triggered unconditionally.
Now it is part of -Wdefault.
In GHC.Tc.TyCl.tcTyClGroupsPass's strict mode, we now have to
force-enable this warning to ensure that detection of flawed groups
continues to work even if the user disables the warning with the
-Wno-unusable-unpack-pragmas option. Test case: T3990c
Also, the misnamed BackpackUnpackAbstractType is now called
UnusableUnpackPragma.
- - - - -
6caa6508 by Adam Gundry at 2025-04-20T10:54:22-04:00
Fix specialisation of incoherent instances (fixes #25883)
GHC normally assumes that class constraints are canonical, meaning that
the specialiser is allowed to replace one dictionary argument with another
provided that they have the same type. The `-fno-specialise-incoherents`
flag alters INCOHERENT instance definitions so that they will prevent
specialisation in some cases, by inserting `nospec`.
This commit fixes a bug in 7124e4ad76d98f1fc246ada4fd7bf64413ff2f2e, which
treated some INCOHERENT instance matches as if `-fno-specialise-incoherents`
was in effect, thereby unnecessarily preventing specialisation. In addition
it updates the relevant `Note [Rules for instance lookup]` and adds a new
`Note [Canonicity for incoherent matches]`.
- - - - -
0426fd6c by Adam Gundry at 2025-04-20T10:54:23-04:00
Add regression test for #23429
- - - - -
eec96527 by Adam Gundry at 2025-04-20T10:54:23-04:00
user's guide: update specification of overlapping/incoherent instances
The description of the instance resolution algorithm in the user's
guide was slightly out of date, because it mentioned in-scope given
constraints only at the end, whereas the implementation checks for
their presence before any of the other steps.
This also adds a warning to the user's guide about the impact of
incoherent instances on specialisation, and more clearly documents
some of the other effects of `-XIncoherentInstances`.
- - - - -
a00eeaec by Matthew Craven at 2025-04-20T10:55:03-04:00
Fix bytecode generation for `tagToEnum# <LITERAL>`
Fixes #25975.
- - - - -
2e204269 by Andreas Klebinger at 2025-04-22T12:20:41+02:00
Simplifier: Constant fold invald tagToEnum# calls to bottom expr.
When applying tagToEnum# to a out-of-range value it's best to simply
constant fold it to a bottom expression. That potentially allows more
dead code elimination and makes debugging easier.
Fixes #25976
- - - - -
7250fc0c by Matthew Pickering at 2025-04-22T16:24:04-04:00
Move -fno-code note into Downsweep module
This note was left behind when all the code which referred to it was
moved into the GHC.Driver.Downsweep module
- - - - -
d2dc89b4 by Matthew Pickering at 2025-04-22T16:24:04-04:00
Apply editing notes to Note [-fno-code mode] suggested by sheaf
These notes were suggested in https://gitlab.haskell.org/ghc/ghc/-/merge_requests/14241
- - - - -
7a6d5536 by Sven Tennie at 2025-04-23T11:16:46+02:00
RV64: Introduce J instruction (non-local jumps) and don't deallocate stack slots for J_TBL (#25738)
J_TBL result in local jumps, there should not deallocate stack slots
(see Note [extra spill slots].)
J is for non-local jumps, these may need to deallocate stack slots.
- - - - -
103 changed files:
- compiler/GHC/CmmToAsm/RV64/CodeGen.hs
- compiler/GHC/CmmToAsm/RV64/Instr.hs
- compiler/GHC/CmmToAsm/RV64/Ppr.hs
- compiler/GHC/Core/InstEnv.hs
- compiler/GHC/Core/Opt/ConstantFold.hs
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/Env.hs
- compiler/GHC/Driver/Env/Types.hs
- compiler/GHC/Driver/Errors/Ppr.hs
- compiler/GHC/Driver/Errors/Types.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Driver/Make.hs
- compiler/GHC/Driver/MakeAction.hs
- + compiler/GHC/Driver/Messager.hs
- compiler/GHC/Driver/Pipeline.hs-boot
- compiler/GHC/Driver/Pipeline/Execute.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Iface/Load.hs
- compiler/GHC/Iface/Recomp.hs
- compiler/GHC/IfaceToCore.hs
- compiler/GHC/Linker/Deps.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Runtime/Loader.hs
- compiler/GHC/StgToByteCode.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Tc/Gen/Default.hs
- compiler/GHC/Tc/Gen/Export.hs
- compiler/GHC/Tc/Module.hs
- compiler/GHC/Tc/Solver/Dict.hs
- compiler/GHC/Tc/TyCl.hs
- compiler/GHC/Tc/Utils/Env.hs
- compiler/GHC/Tc/Utils/Monad.hs
- compiler/GHC/Types/DefaultEnv.hs
- compiler/GHC/Types/Error/Codes.hs
- compiler/GHC/Unit/External.hs
- compiler/GHC/Unit/Finder.hs
- − compiler/GHC/Unit/Module/External/Graph.hs
- compiler/GHC/Unit/Module/Graph.hs
- compiler/GHC/Unit/Module/ModNodeKey.hs
- compiler/ghc.cabal.in
- configure.ac
- docs/users_guide/9.14.1-notes.rst
- docs/users_guide/exts/instances.rst
- docs/users_guide/using-warnings.rst
- hadrian/src/Settings/Packages.hs
- libraries/base/base.cabal.in
- libraries/base/changelog.md
- − libraries/base/src/GHC/ExecutionStack/Internal.hs
- − libraries/base/src/GHC/TypeLits/Internal.hs
- − libraries/base/src/GHC/TypeNats/Internal.hs
- libraries/template-haskell/Language/Haskell/TH/Syntax.hs
- libraries/template-haskell/changelog.md
- rts/RtsUtils.c
- testsuite/ghc-config/ghc-config.hs
- + testsuite/tests/bytecode/T25975.hs
- + testsuite/tests/bytecode/T25975.stdout
- testsuite/tests/bytecode/all.T
- + testsuite/tests/default/T25912.hs
- + testsuite/tests/default/T25912.stdout
- + testsuite/tests/default/T25912_helper.hs
- + testsuite/tests/default/T25914.hs
- + testsuite/tests/default/T25934.hs
- testsuite/tests/default/all.T
- testsuite/tests/default/default-fail03.stderr
- testsuite/tests/diagnostic-codes/codes.stdout
- + testsuite/tests/ghc-api/fixed-nodes/InterfaceModuleGraph.hs
- + testsuite/tests/ghc-api/fixed-nodes/InterfaceModuleGraph.stdout
- testsuite/tests/ghc-api/fixed-nodes/all.T
- 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/template-haskell-exports.stdout
- testsuite/tests/linters/notes.stdout
- testsuite/tests/module/mod58.stderr
- testsuite/tests/plugins/defaulting-plugin/DefaultLifted.hs
- testsuite/tests/simplCore/should_compile/Makefile
- testsuite/tests/simplCore/should_compile/T23307c.stderr
- + testsuite/tests/simplCore/should_compile/T25883.hs
- + testsuite/tests/simplCore/should_compile/T25883.substr-simpl
- + testsuite/tests/simplCore/should_compile/T25883b.hs
- + testsuite/tests/simplCore/should_compile/T25883b.substr-simpl
- + testsuite/tests/simplCore/should_compile/T25883c.hs
- + testsuite/tests/simplCore/should_compile/T25883c.substr-simpl
- + testsuite/tests/simplCore/should_compile/T25883d.hs
- + testsuite/tests/simplCore/should_compile/T25883d.stderr
- + testsuite/tests/simplCore/should_compile/T25883d_import.hs
- + testsuite/tests/simplCore/should_compile/T25976.hs
- + testsuite/tests/simplCore/should_compile/T3990c.hs
- + testsuite/tests/simplCore/should_compile/T3990c.stdout
- testsuite/tests/simplCore/should_compile/all.T
- testsuite/tests/simplCore/should_fail/T25672.stderr
- + testsuite/tests/simplCore/should_run/T23429.hs
- + testsuite/tests/simplCore/should_run/T23429.stdout
- testsuite/tests/simplCore/should_run/all.T
- testsuite/tests/typecheck/should_compile/T7050.stderr
- testsuite/tests/typecheck/should_fail/T3966.stderr
- + testsuite/tests/typecheck/should_fail/T3966b.hs
- + testsuite/tests/typecheck/should_fail/T3966b.stderr
- testsuite/tests/typecheck/should_fail/all.T
- testsuite/tests/unboxedsums/unpack_sums_5.stderr
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/0f976bb84be8649ab5baf6d8476f06…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/0f976bb84be8649ab5baf6d8476f06…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

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

[Git][ghc/ghc][wip/T23298-test] 4 commits: Simplifier: Constant fold invald tagToEnum# calls to bottom expr.
by Simon Peyton Jones (@simonpj) 23 Apr '25
by Simon Peyton Jones (@simonpj) 23 Apr '25
23 Apr '25
Simon Peyton Jones pushed to branch wip/T23298-test at Glasgow Haskell Compiler / GHC
Commits:
2e204269 by Andreas Klebinger at 2025-04-22T12:20:41+02:00
Simplifier: Constant fold invald tagToEnum# calls to bottom expr.
When applying tagToEnum# to a out-of-range value it's best to simply
constant fold it to a bottom expression. That potentially allows more
dead code elimination and makes debugging easier.
Fixes #25976
- - - - -
7250fc0c by Matthew Pickering at 2025-04-22T16:24:04-04:00
Move -fno-code note into Downsweep module
This note was left behind when all the code which referred to it was
moved into the GHC.Driver.Downsweep module
- - - - -
d2dc89b4 by Matthew Pickering at 2025-04-22T16:24:04-04:00
Apply editing notes to Note [-fno-code mode] suggested by sheaf
These notes were suggested in https://gitlab.haskell.org/ghc/ghc/-/merge_requests/14241
- - - - -
90ee5634 by Simon Peyton Jones at 2025-04-23T08:58:22+01:00
Test for #23298
- - - - -
8 changed files:
- compiler/GHC/Core/Opt/ConstantFold.hs
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/Make.hs
- + testsuite/tests/gadt/T23298.hs
- + testsuite/tests/gadt/T23298.stderr
- testsuite/tests/gadt/all.T
- + testsuite/tests/simplCore/should_compile/T25976.hs
- testsuite/tests/simplCore/should_compile/all.T
Changes:
=====================================
compiler/GHC/Core/Opt/ConstantFold.hs
=====================================
@@ -69,7 +69,6 @@ import GHC.Cmm.MachOp ( FMASign(..) )
import GHC.Cmm.Type ( Width(..) )
import GHC.Data.FastString
-import GHC.Data.Maybe ( orElse )
import GHC.Utils.Outputable
import GHC.Utils.Misc
@@ -1997,6 +1996,14 @@ because we don't expect the user to call tagToEnum# at all; we merely
generate calls in derived instances of Enum. So we compromise: a
rewrite rule rewrites a bad instance of tagToEnum# to an error call,
and emits a warning.
+
+We also do something similar if we can see that the argument of tagToEnum is out
+of bounds, e.g. `tagToEnum# 99# :: Bool`.
+Replacing this with an error expression is better for two reasons:
+* It allow us to eliminate more dead code in cases like `case tagToEnum# 99# :: Bool of ...`
+* Should we actually end up executing the relevant code at runtime the user will
+ see a meaningful error message, instead of a segfault or incorrect result.
+See #25976.
-}
tagToEnumRule :: RuleM CoreExpr
@@ -2008,9 +2015,13 @@ tagToEnumRule = do
Just (tycon, tc_args) | isEnumerationTyCon tycon -> do
let tag = fromInteger i
correct_tag dc = (dataConTagZ dc) == tag
- (dc:rest) <- return $ filter correct_tag (tyConDataCons_maybe tycon `orElse` [])
- massert (null rest)
- return $ mkTyApps (Var (dataConWorkId dc)) tc_args
+ Just dataCons <- pure $ tyConDataCons_maybe tycon
+ case filter correct_tag dataCons of
+ (dc:rest) -> do
+ massert (null rest)
+ pure $ mkTyApps (Var (dataConWorkId dc)) tc_args
+ -- Literal is out of range, e.g. tagToEnum @Bool #4
+ [] -> pure $ mkImpossibleExpr ty "tagToEnum: Argument out of range"
-- See Note [tagToEnum#]
_ -> warnPprTrace True "tagToEnum# on non-enumeration type" (ppr ty) $
=====================================
compiler/GHC/Driver/Downsweep.hs
=====================================
@@ -947,6 +947,71 @@ enableCodeGenWhen logger tmpfs staticLife dynLife unit_env mod_graph = do
hostFullWays
in dflags_c
+{- Note [-fno-code mode]
+~~~~~~~~~~~~~~~~~~~~~~~~
+GHC offers the flag -fno-code for the purpose of parsing and typechecking a
+program without generating object files. This is intended to be used by tooling
+and IDEs to provide quick feedback on any parser or type errors as cheaply as
+possible.
+
+When GHC is invoked with -fno-code, no object files or linked output will be
+generated. As many errors and warnings as possible will be generated, as if
+-fno-code had not been passed. The session DynFlags will have
+backend == NoBackend.
+
+-fwrite-interface
+~~~~~~~~~~~~~~~~
+Whether interface files are generated in -fno-code mode is controlled by the
+-fwrite-interface flag. The -fwrite-interface flag is a no-op if -fno-code is
+not also passed. Recompilation avoidance requires interface files, so passing
+-fno-code without -fwrite-interface should be avoided. If -fno-code were
+re-implemented today, there would be no need for -fwrite-interface as it
+would considered always on; this behaviour is as it is for backwards compatibility.
+
+================================================================
+IN SUMMARY: ALWAYS PASS -fno-code AND -fwrite-interface TOGETHER
+================================================================
+
+Template Haskell
+~~~~~~~~~~~~~~~~
+A module using Template Haskell may invoke an imported function from inside a
+splice. This will cause the type-checker to attempt to execute that code, which
+would fail if no object files had been generated. See #8025. To rectify this,
+during the downsweep we patch the DynFlags in the ModSummary of any home module
+that is imported by a module that uses Template Haskell to generate object
+code.
+
+The flavour of the generated code depends on whether `-fprefer-byte-code` is enabled
+or not in the module which needs the code generation. If the module requires byte-code then
+dependencies will generate byte-code, otherwise they will generate object files.
+In the case where some modules require byte-code and some object files, both are
+generated by enabling `-fbyte-code-and-object-code`, the test "fat015" tests these
+configurations.
+
+The object files (and interface files if -fwrite-interface is disabled) produced
+for Template Haskell are written to temporary files.
+
+Note that since Template Haskell can run arbitrary IO actions, -fno-code mode
+is no more secure than running without it.
+
+Potential TODOS:
+~~~~~
+* Remove -fwrite-interface and have interface files always written in -fno-code
+ mode
+* Both .o and .dyn_o files are generated for template haskell, but we only need
+ .dyn_o. Fix it.
+* In make mode, a message like
+ Compiling A (A.hs, /tmp/ghc_123.o)
+ is shown if downsweep enabled object code generation for A. Perhaps we should
+ show "nothing" or "temporary object file" instead. Note that one
+ can currently use -keep-tmp-files and inspect the generated file with the
+ current behaviour.
+* Offer a -no-codedir command line option, and write what were temporary
+ object files there. This would speed up recompilation.
+* Use existing object files (if they are up to date) instead of always
+ generating temporary ones.
+-}
+
-- | Populate the Downsweep cache with the root modules.
mkRootMap
:: [ModuleNodeInfo]
=====================================
compiler/GHC/Driver/Make.hs
=====================================
@@ -1246,70 +1246,6 @@ addSptEntries hsc_env mlinkable =
, spt <- bc_spt_entries bco
]
-{- Note [-fno-code mode]
-~~~~~~~~~~~~~~~~~~~~~~~~
-GHC offers the flag -fno-code for the purpose of parsing and typechecking a
-program without generating object files. This is intended to be used by tooling
-and IDEs to provide quick feedback on any parser or type errors as cheaply as
-possible.
-
-When GHC is invoked with -fno-code no object files or linked output will be
-generated. As many errors and warnings as possible will be generated, as if
--fno-code had not been passed. The session DynFlags will have
-backend == NoBackend.
-
--fwrite-interface
-~~~~~~~~~~~~~~~~
-Whether interface files are generated in -fno-code mode is controlled by the
--fwrite-interface flag. The -fwrite-interface flag is a no-op if -fno-code is
-not also passed. Recompilation avoidance requires interface files, so passing
--fno-code without -fwrite-interface should be avoided. If -fno-code were
-re-implemented today, -fwrite-interface would be discarded and it would be
-considered always on; this behaviour is as it is for backwards compatibility.
-
-================================================================
-IN SUMMARY: ALWAYS PASS -fno-code AND -fwrite-interface TOGETHER
-================================================================
-
-Template Haskell
-~~~~~~~~~~~~~~~~
-A module using template haskell may invoke an imported function from inside a
-splice. This will cause the type-checker to attempt to execute that code, which
-would fail if no object files had been generated. See #8025. To rectify this,
-during the downsweep we patch the DynFlags in the ModSummary of any home module
-that is imported by a module that uses template haskell, to generate object
-code.
-
-The flavour of the generated code depends on whether `-fprefer-byte-code` is enabled
-or not in the module which needs the code generation. If the module requires byte-code then
-dependencies will generate byte-code, otherwise they will generate object files.
-In the case where some modules require byte-code and some object files, both are
-generated by enabling `-fbyte-code-and-object-code`, the test "fat015" tests these
-configurations.
-
-The object files (and interface files if -fwrite-interface is disabled) produced
-for template haskell are written to temporary files.
-
-Note that since template haskell can run arbitrary IO actions, -fno-code mode
-is no more secure than running without it.
-
-Potential TODOS:
-~~~~~
-* Remove -fwrite-interface and have interface files always written in -fno-code
- mode
-* Both .o and .dyn_o files are generated for template haskell, but we only need
- .dyn_o. Fix it.
-* In make mode, a message like
- Compiling A (A.hs, /tmp/ghc_123.o)
- is shown if downsweep enabled object code generation for A. Perhaps we should
- show "nothing" or "temporary object file" instead. Note that one
- can currently use -keep-tmp-files and inspect the generated file with the
- current behaviour.
-* Offer a -no-codedir command line option, and write what were temporary
- object files there. This would speed up recompilation.
-* Use existing object files (if they are up to date) instead of always
- generating temporary ones.
--}
-- Note [When source is considered modified]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
=====================================
testsuite/tests/gadt/T23298.hs
=====================================
@@ -0,0 +1,25 @@
+{-# LANGUAGE GADTs #-}
+module T23298 where
+
+import Data.Kind (Type)
+
+type HList :: Type -> Type
+data HList a where
+ HCons :: HList x -> HList (Maybe x)
+
+eq :: HList a -> Bool
+eq x = case x of
+ HCons ms -> True
+
+go (HCons x) = go x
+
+{- go :: HList alpha -> beta
+
+Under HCons
+ [G] alpha ~ Maybe x
+ [W] HList x ~ HList alpha
+==>
+ [W] x ~ alpha
+==>
+ [W] x ~ Maybe x
+-}
=====================================
testsuite/tests/gadt/T23298.stderr
=====================================
@@ -0,0 +1,12 @@
+ T23298.hs:14:16: error: [GHC-25897]
+ • Couldn't match type ‘x’ with ‘Maybe x’
+ Expected: HList x -> t
+ Actual: HList a -> t
+ ‘x’ is a rigid type variable bound by
+ a pattern with constructor:
+ HCons :: forall x. HList x -> HList (Maybe x),
+ in an equation for ‘go’
+ at T23298.hs:14:5-11
+ • In the expression: go x
+ In an equation for ‘go’: go (HCons x) = go x
+ • Relevant bindings include x :: HList x (bound at T23298.hs:14:11)
=====================================
testsuite/tests/gadt/all.T
=====================================
@@ -131,3 +131,4 @@ test('T19847a', normalise_version('base'), compile, ['-ddump-types'])
test('T19847b', normal, compile, [''])
test('T23022', normal, compile, ['-dcore-lint'])
test('T23023', normal, compile_fail, ['-O -dcore-lint']) # todo: move this test?
+test('T23298', normal, compile_fail, [''])
=====================================
testsuite/tests/simplCore/should_compile/T25976.hs
=====================================
@@ -0,0 +1,10 @@
+{-# LANGUAGE MagicHash #-}
+
+module T25976 where
+
+import GHC.PrimOps (tagToEnum#)
+
+-- Spoiler - it's all dead code since tagToEnum 3# is undefined
+main = case (tagToEnum# 4# :: Bool) of
+ True -> print "Dead Code"
+ False -> print "Dead Code"
=====================================
testsuite/tests/simplCore/should_compile/all.T
=====================================
@@ -541,3 +541,5 @@ test('T25883', normal, compile_grep_core, [''])
test('T25883b', normal, compile_grep_core, [''])
test('T25883c', normal, compile_grep_core, [''])
test('T25883d', [extra_files(['T25883d_import.hs'])], multimod_compile_filter, ['T25883d', '-O -ddump-simpl -dno-typeable-binds -dsuppress-all -dsuppress-uniques', r'grep -e "y ="'])
+
+test('T25976', [grep_errmsg('Dead Code')], compile, ['-O -ddump-simpl -dsuppress-uniques -dno-typeable-binds'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/2fd9a3da0a21c8d09a3ddf8865880b…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/2fd9a3da0a21c8d09a3ddf8865880b…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
Simon Peyton Jones pushed to branch wip/T20264 at Glasgow Haskell Compiler / GHC
Commits:
dde6593d by Simon Peyton Jones at 2025-04-22T23:42:54+01:00
Add IfaceExtTyVar
- - - - -
6 changed files:
- compiler/GHC/CoreToIface.hs
- compiler/GHC/Iface/Ext/Utils.hs
- compiler/GHC/Iface/Rename.hs
- compiler/GHC/Iface/Syntax.hs
- compiler/GHC/Iface/Type.hs
- compiler/GHC/IfaceToCore.hs
Changes:
=====================================
compiler/GHC/CoreToIface.hs
=====================================
@@ -183,7 +183,11 @@ toIfaceTypeX :: VarSet -> Type -> IfaceType
-- Synonyms are retained in the interface type
toIfaceTypeX fr (TyVarTy tv) -- See Note [Free TyVars and CoVars in IfaceType] in GHC.Iface.Type
| tv `elemVarSet` fr = IfaceFreeTyVar tv
+ | isExternalName nm = IfaceExtTyVar nm
| otherwise = IfaceTyVar (toIfaceTyVar tv)
+ where
+ nm = tyVarName tv
+
toIfaceTypeX fr ty@(AppTy {}) =
-- Flatten as many argument AppTys as possible, then turn them into an
-- IfaceAppArgs list.
=====================================
compiler/GHC/Iface/Ext/Utils.hs
=====================================
@@ -164,7 +164,7 @@ hieTypeToIface = foldType go
where
go (HTyVarTy n) = IfaceTyVar $ (mkIfLclName (occNameFS $ getOccName n))
go (HAppTy a b) = IfaceAppTy a (hieToIfaceArgs b)
- go (HLitTy l) = IfaceLitTy l
+ go (HLitTy l) = IfaceLitTy l
go (HForAllTy ((n,k),af) t) = let b = (mkIfLclName (occNameFS $ getOccName n), k)
in IfaceForAllTy (Bndr (IfaceTvBndr b) af) t
go (HFunTy w a b) = IfaceFunTy visArgTypeLike w a b
=====================================
compiler/GHC/Iface/Rename.hs
=====================================
@@ -718,7 +718,8 @@ rnIfaceIdDetails details
rnIfaceType :: Rename IfaceType
rnIfaceType (IfaceFreeTyVar n) = pure (IfaceFreeTyVar n)
-rnIfaceType (IfaceTyVar n) = pure (IfaceTyVar n)
+rnIfaceType (IfaceExtTyVar n) = pure (IfaceExtTyVar n)
+rnIfaceType (IfaceTyVar n) = pure (IfaceTyVar n)
rnIfaceType (IfaceAppTy t1 t2)
= IfaceAppTy <$> rnIfaceType t1 <*> rnIfaceAppArgs t2
rnIfaceType (IfaceLitTy l) = return (IfaceLitTy l)
=====================================
compiler/GHC/Iface/Syntax.hs
=====================================
@@ -2068,8 +2068,9 @@ freeNamesIfAppArgs (IA_Arg t _ ts) = freeNamesIfType t &&& freeNamesIfAppArgs ts
freeNamesIfAppArgs IA_Nil = emptyNameSet
freeNamesIfType :: IfaceType -> NameSet
-freeNamesIfType (IfaceFreeTyVar _) = emptyNameSet
-freeNamesIfType (IfaceTyVar _) = emptyNameSet
+freeNamesIfType (IfaceFreeTyVar {}) = emptyNameSet
+freeNamesIfType (IfaceTyVar {}) = emptyNameSet
+freeNamesIfType (IfaceExtTyVar {}) = emptyNameSet
freeNamesIfType (IfaceAppTy s t) = freeNamesIfType s &&& freeNamesIfAppArgs t
freeNamesIfType (IfaceTyConApp tc ts) = freeNamesIfTc tc &&& freeNamesIfAppArgs ts
freeNamesIfType (IfaceTupleTy _ _ ts) = freeNamesIfAppArgs ts
=====================================
compiler/GHC/Iface/Type.hs
=====================================
@@ -177,6 +177,7 @@ type IfaceKind = IfaceType
data IfaceType
= IfaceFreeTyVar TyVar -- See Note [Free TyVars and CoVars in IfaceType]
| IfaceTyVar IfLclName -- Type/coercion variable only, not tycon
+ | IfaceExtTyVar IfExtName -- Imported or top-level external tyvar
| IfaceLitTy IfaceTyLit
| IfaceAppTy IfaceType IfaceAppArgs
-- See Note [Suppressing invisible arguments] for
@@ -701,6 +702,7 @@ ifTypeIsVarFree :: IfaceType -> Bool
ifTypeIsVarFree ty = go ty
where
go (IfaceTyVar {}) = False
+ go (IfaceExtTyVar {}) = False
go (IfaceFreeTyVar {}) = False
go (IfaceAppTy fun args) = go fun && go_args args
go (IfaceFunTy _ w arg res) = go w && go arg && go res
@@ -723,6 +725,7 @@ visibleTypeVarOccurencies = go
(<>) = Set.union
go (IfaceTyVar var) = Set.singleton var
+ go (IfaceExtTyVar {}) = mempty
go (IfaceFreeTyVar {}) = mempty
go (IfaceAppTy fun args) = go fun <> go_args args
go (IfaceFunTy _ w arg res) = go w <> go arg <> go res
@@ -758,7 +761,8 @@ substIfaceType :: IfaceTySubst -> IfaceType -> IfaceType
substIfaceType env ty
= go ty
where
- go (IfaceFreeTyVar tv) = IfaceFreeTyVar tv
+ go ty@(IfaceFreeTyVar tv) = ty
+ go ty@(IfaceExtTyVar tv) = ty
go (IfaceTyVar tv) = substIfaceTyVar env tv
go (IfaceAppTy t ts) = IfaceAppTy (go t) (substIfaceAppArgs env ts)
go (IfaceFunTy af w t1 t2) = IfaceFunTy af (go w) (go t1) (go t2)
@@ -1143,8 +1147,9 @@ ppr_ty :: PprPrec -> IfaceType -> SDoc
ppr_ty ctxt_prec ty
| not (isIfaceRhoType ty) = ppr_sigma ShowForAllMust ctxt_prec ty
ppr_ty _ (IfaceForAllTy {}) = panic "ppr_ty" -- Covered by not.isIfaceRhoType
-ppr_ty _ (IfaceFreeTyVar tyvar) = ppr tyvar -- This is the main reason for IfaceFreeTyVar!
-ppr_ty _ (IfaceTyVar tyvar) = ppr tyvar -- See Note [Free TyVars and CoVars in IfaceType]
+ppr_ty _ (IfaceFreeTyVar tyvar) = ppr tyvar -- This is the main reason for IfaceFreeTyVar!
+ppr_ty _ (IfaceTyVar tyvar) = ppr tyvar -- See Note [Free TyVars and CoVars in IfaceType]
+ppr_ty _ (IfaceExtTyVar tyvar) = ppr tyvar
ppr_ty ctxt_prec (IfaceTyConApp tc tys) = pprTyTcApp ctxt_prec tc tys
ppr_ty ctxt_prec (IfaceTupleTy i p tys) = ppr_tuple ctxt_prec i p tys -- always fully saturated
ppr_ty _ (IfaceLitTy n) = pprIfaceTyLit n
@@ -1320,7 +1325,7 @@ defaultIfaceTyVarsOfKind def_rep def_mult ty = go emptyFsEnv True ty
= IfaceForAllTy (go_ifacebndr subs bndr) (go subs rank1 ty)
go subs _ ty@(IfaceTyVar tv) = case lookupFsEnv subs (ifLclNameFS tv) of
- Just s -> s
+ Just s -> s
Nothing -> ty
go _ _ ty@(IfaceFreeTyVar tv)
@@ -1343,6 +1348,8 @@ defaultIfaceTyVarsOfKind def_rep def_mult ty = go emptyFsEnv True ty
| otherwise
= ty
+ go _ _ ty@(IfaceExtTyVar {}) = ty
+
go subs _ (IfaceTyConApp tc tc_args)
= IfaceTyConApp tc (go_args subs tc_args)
@@ -2366,6 +2373,9 @@ putIfaceType bh (IfaceTupleTy s i tys)
= do { putByte bh 8; put_ bh s; put_ bh i; put_ bh tys }
putIfaceType bh (IfaceLitTy n)
= do { putByte bh 9; put_ bh n }
+putIfaceType bh (IfaceExtTyVar tv) = do
+ putByte bh 10
+ put_ bh tv
-- | Deserialises an 'IfaceType' from the given 'ReadBinHandle'.
--
@@ -2397,8 +2407,10 @@ getIfaceType bh = do
8 -> do { s <- get bh; i <- get bh; tys <- get bh
; return (IfaceTupleTy s i tys) }
- _ -> do n <- get bh
+ 9 -> do n <- get bh
return (IfaceLitTy n)
+ _ -> do n <- get bh
+ return (IfaceExtTyVar n)
instance Binary IfLclName where
put_ bh = put_ bh . ifLclNameFS
@@ -2586,6 +2598,7 @@ instance NFData IfaceType where
rnf = \case
IfaceFreeTyVar f1 -> f1 `seq` ()
IfaceTyVar f1 -> rnf f1
+ IfaceExtTyVar f1 -> rnf f1
IfaceLitTy f1 -> rnf f1
IfaceAppTy f1 f2 -> rnf f1 `seq` rnf f2
IfaceFunTy f1 f2 f3 f4 -> rnf f1 `seq` rnf f2 `seq` rnf f3 `seq` rnf f4
=====================================
compiler/GHC/IfaceToCore.hs
=====================================
@@ -1502,6 +1502,7 @@ tcIfaceType :: IfaceType -> IfL Type
tcIfaceType = go
where
go (IfaceTyVar n) = TyVarTy <$> tcIfaceTyVar n
+ go (IfaceExtTyVar n) = TyVarTy <$> tcIfaceExtTyVar n
go (IfaceFreeTyVar n) = pprPanic "tcIfaceType:IfaceFreeTyVar" (ppr n)
go (IfaceLitTy l) = LitTy <$> tcIfaceTyLit l
go (IfaceFunTy flag w t1 t2) = FunTy flag <$> tcIfaceType w <*> go t1 <*> go t2
@@ -2144,6 +2145,13 @@ tcIfaceGlobal name
-- the constructor (A and B) means that GHC will always typecheck
-- this expression *after* typechecking T.
+tcIfaceExtTyVar :: Name -> IfL TyVar
+tcIfaceExtTyVar name
+ = do { thing <- tcIfaceGlobal name
+ ; case thing of
+ ATyVar tv -> return tv
+ _ -> pprPanic "tcIfaceExtTyVar" (ppr thing) }
+
tcIfaceTyCon :: IfaceTyCon -> IfL TyCon
tcIfaceTyCon (IfaceTyCon name _info)
= do { thing <- tcIfaceGlobal name
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/dde6593d45bf3090cfc0ccdb1fe0169…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/dde6593d45bf3090cfc0ccdb1fe0169…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/T20264] Missing case in tyThingEntityInfo
by Simon Peyton Jones (@simonpj) 22 Apr '25
by Simon Peyton Jones (@simonpj) 22 Apr '25
22 Apr '25
Simon Peyton Jones pushed to branch wip/T20264 at Glasgow Haskell Compiler / GHC
Commits:
c7a75ca9 by Simon Peyton Jones at 2025-04-22T22:20:00+01:00
Missing case in tyThingEntityInfo
- - - - -
1 changed file:
- compiler/GHC/Iface/Ext/Types.hs
Changes:
=====================================
compiler/GHC/Iface/Ext/Types.hs
=====================================
@@ -867,11 +867,13 @@ idEntityInfo vid = S.fromList $ [EntityTypeVariable | isTyVar vid] <> [EntityFun
-- | Get the `EntityInfo` for a `TyThing`
tyThingEntityInfo :: TyThing -> S.Set EntityInfo
tyThingEntityInfo ty = case ty of
- AnId vid -> idEntityInfo vid
+ AnId vid -> idEntityInfo vid
+ ATyVar {} -> S.singleton EntityTypeVariable
AConLike con -> case con of
RealDataCon _ -> S.singleton EntityDataConstructor
PatSynCon _ -> S.singleton EntityPatternSynonym
- ATyCon tyCon -> S.fromList $ [EntityTypeSynonym | isTypeSynonymTyCon tyCon] <> [EntityTypeFamily | isFamilyTyCon tyCon]
+ ATyCon tyCon -> S.fromList $ [EntityTypeSynonym | isTypeSynonymTyCon tyCon]
+ <> [EntityTypeFamily | isFamilyTyCon tyCon]
<> [EntityTypeClass | isClassTyCon tyCon] <> [EntityTypeConstructor]
ACoAxiom _ -> S.empty
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/c7a75ca92dfa4b8bd73d289a8851e8c…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/c7a75ca92dfa4b8bd73d289a8851e8c…
You're receiving this email because of your account on gitlab.haskell.org.
1
0