Cheng Shao pushed to branch wip/ghci-no-simpl at Glasgow Haskell Compiler / GHC
Commits:
-
77deaa7a
by Cheng Shao at 2025-09-14T21:29:45-04:00
-
42a18960
by Cheng Shao at 2025-09-14T21:30:26-04:00
-
e6755b9f
by Cheng Shao at 2025-09-14T21:30:26-04:00
-
e5b1ac21
by Cheng Shao at 2025-09-16T18:43:32+02:00
-
f27a1ba9
by Cheng Shao at 2025-09-16T18:43:32+02:00
-
2287a923
by Cheng Shao at 2025-09-16T18:43:32+02:00
-
79f4f1d1
by Cheng Shao at 2025-09-16T18:57:46+02:00
9 changed files:
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Driver/Session/Inspect.hs
- compiler/GHC/Types/SrcLoc.hs
- hadrian/src/Rules/Gmp.hs
- testsuite/tests/interface-stability/ghc-prim-exports.stdout
- testsuite/tests/interface-stability/ghc-prim-exports.stdout-mingw32
- utils/genprimopcode/Main.hs
- + utils/genprimopcode/hie.yaml
- utils/jsffi/dyld.mjs
Changes:
... | ... | @@ -121,6 +121,7 @@ import GHC.Driver.Errors |
121 | 121 | import GHC.Driver.Messager
|
122 | 122 | import GHC.Driver.Errors.Types
|
123 | 123 | import GHC.Driver.CodeOutput
|
124 | +import GHC.Driver.Config
|
|
124 | 125 | import GHC.Driver.Config.Cmm.Parser (initCmmParserConfig)
|
125 | 126 | import GHC.Driver.Config.Core.Opt.Simplify ( initSimplifyExprOpts )
|
126 | 127 | import GHC.Driver.Config.Core.Lint ( endPassHscEnvIO )
|
... | ... | @@ -181,6 +182,7 @@ import GHC.Core.Utils ( exprType ) |
181 | 182 | import GHC.Core.ConLike
|
182 | 183 | import GHC.Core.Opt.Pipeline
|
183 | 184 | import GHC.Core.Opt.Pipeline.Types ( CoreToDo (..))
|
185 | +import GHC.Core.SimpleOpt
|
|
184 | 186 | import GHC.Core.TyCon
|
185 | 187 | import GHC.Core.InstEnv
|
186 | 188 | import GHC.Core.FamInstEnv
|
... | ... | @@ -253,6 +255,7 @@ import GHC.Types.TyThing |
253 | 255 | import GHC.Types.Unique.Supply (uniqFromTag)
|
254 | 256 | import GHC.Types.Unique.Set
|
255 | 257 | |
258 | +import GHC.Utils.Exception
|
|
256 | 259 | import GHC.Utils.Fingerprint ( Fingerprint )
|
257 | 260 | import GHC.Utils.Panic
|
258 | 261 | import GHC.Utils.Error
|
... | ... | @@ -2448,8 +2451,7 @@ hscParsedStmt hsc_env stmt = runInteractiveHsc hsc_env $ do |
2448 | 2451 | -- It's important NOT to have package 'interactive' as thisUnitId
|
2449 | 2452 | -- for linking, else we try to link 'main' and can't find it.
|
2450 | 2453 | -- Whereas the linker already knows to ignore 'interactive'
|
2451 | - let src_span = srcLocSpan interactiveSrcLoc
|
|
2452 | - (hval,_,_) <- liftIO $ hscCompileCoreExpr hsc_env src_span ds_expr
|
|
2454 | + (hval,_,_) <- liftIO $ hscCompileCoreExpr hsc_env interactiveSrcSpan ds_expr
|
|
2453 | 2455 | |
2454 | 2456 | return $ Just (ids, hval, fix_env)
|
2455 | 2457 | |
... | ... | @@ -2512,8 +2514,7 @@ hscParsedDecls hsc_env decls = runInteractiveHsc hsc_env $ do |
2512 | 2514 | (mkCgInteractiveGuts tidy_cg)
|
2513 | 2515 | iNTERACTIVELoc
|
2514 | 2516 | |
2515 | - let src_span = srcLocSpan interactiveSrcLoc
|
|
2516 | - _ <- liftIO $ loadDecls interp hsc_env src_span linkable
|
|
2517 | + _ <- liftIO $ loadDecls interp hsc_env interactiveSrcSpan linkable
|
|
2517 | 2518 | |
2518 | 2519 | {- Load static pointer table entries -}
|
2519 | 2520 | liftIO $ hscAddSptEntries hsc_env (cg_spt_entries tidy_cg)
|
... | ... | @@ -2710,17 +2711,44 @@ hscCompileCoreExpr hsc_env loc expr = |
2710 | 2711 | Just h -> h hsc_env loc expr
|
2711 | 2712 | |
2712 | 2713 | hscCompileCoreExpr' :: HscEnv -> SrcSpan -> CoreExpr -> IO (ForeignHValue, [Linkable], PkgsLoaded)
|
2713 | -hscCompileCoreExpr' hsc_env srcspan ds_expr = do
|
|
2714 | - {- Simplify it -}
|
|
2715 | - -- Question: should we call SimpleOpt.simpleOptExpr here instead?
|
|
2716 | - -- It is, well, simpler, and does less inlining etc.
|
|
2717 | - let dflags = hsc_dflags hsc_env
|
|
2714 | +hscCompileCoreExpr' hsc_env' srcspan ds_expr = do
|
|
2715 | + -- Use modified `dflags` and session that sets -O0 and do less work
|
|
2716 | + -- throughout the Core -> ByteCode pipeline, even if current session
|
|
2717 | + -- enables `-O1` or above. Unless user manually specified
|
|
2718 | + -- `-fno-unoptimized-core-for-interpreter`.
|
|
2719 | + let dflags' = hsc_dflags hsc_env'
|
|
2720 | + unopt = gopt Opt_UnoptimizedCoreForInterpreter dflags'
|
|
2721 | + dflags
|
|
2722 | + | unopt = updOptLevel 0 dflags'
|
|
2723 | + | otherwise = dflags'
|
|
2724 | + hsc_env
|
|
2725 | + | unopt = hsc_env' {hsc_dflags = dflags}
|
|
2726 | + | otherwise = hsc_env'
|
|
2718 | 2727 | let logger = hsc_logger hsc_env
|
2719 | - let ic = hsc_IC hsc_env
|
|
2720 | - let unit_env = hsc_unit_env hsc_env
|
|
2721 | - let simplify_expr_opts = initSimplifyExprOpts dflags ic
|
|
2722 | 2728 | |
2723 | - simpl_expr <- simplifyExpr logger (ue_eps unit_env) simplify_expr_opts ds_expr
|
|
2729 | + {- Simplify it -}
|
|
2730 | + simpl_expr <-
|
|
2731 | + if unopt
|
|
2732 | + then
|
|
2733 | + evaluate $
|
|
2734 | + -- When generating bytecode for ghci via `hscParsedStmt`, we
|
|
2735 | + -- still need to enable inlining! For `let foo = Foo ...`, the
|
|
2736 | + -- ghci debugger expects `:print foo` to show `foo = <Foo> ...`
|
|
2737 | + -- without forcing `foo` first, without inlining `foo`
|
|
2738 | + -- would remain a top-level thunk instead of a datacon
|
|
2739 | + -- closure. We can skip inlining for TH splices though.
|
|
2740 | + ( if srcspan == interactiveSrcSpan
|
|
2741 | + then simpleOptExpr
|
|
2742 | + else simpleOptExprNoInline
|
|
2743 | + )
|
|
2744 | + (initSimpleOpts dflags)
|
|
2745 | + ds_expr
|
|
2746 | + else
|
|
2747 | + simplifyExpr
|
|
2748 | + logger
|
|
2749 | + (ue_eps $ hsc_unit_env hsc_env)
|
|
2750 | + (initSimplifyExprOpts dflags $ hsc_IC hsc_env)
|
|
2751 | + ds_expr
|
|
2724 | 2752 | |
2725 | 2753 | -- Create a unique temporary binding
|
2726 | 2754 | --
|
... | ... | @@ -133,7 +133,7 @@ availsToGlobalRdrEnv hsc_env mod avails |
133 | 133 | imp_spec = ImpSpec { is_decl = decl, is_item = ImpAll}
|
134 | 134 | decl = ImpDeclSpec { is_mod = mod, is_as = moduleName mod,
|
135 | 135 | is_qual = False, is_isboot = NotBoot, is_pkg_qual = NoPkgQual,
|
136 | - is_dloc = srcLocSpan interactiveSrcLoc,
|
|
136 | + is_dloc = interactiveSrcSpan,
|
|
137 | 137 | is_level = NormalLevel }
|
138 | 138 | |
139 | 139 | getHomeModuleInfo :: HscEnv -> Module -> IO (Maybe ModuleInfo)
|
... | ... | @@ -198,4 +198,3 @@ modInfoSafe = minf_safe |
198 | 198 | |
199 | 199 | modInfoModBreaks :: ModuleInfo -> Maybe InternalModBreaks
|
200 | 200 | modInfoModBreaks = minf_modBreaks |
201 | - |
... | ... | @@ -19,8 +19,6 @@ module GHC.Types.SrcLoc ( |
19 | 19 | leftmostColumn,
|
20 | 20 | |
21 | 21 | noSrcLoc, -- "I'm sorry, I haven't a clue"
|
22 | - generatedSrcLoc, -- Code generated within the compiler
|
|
23 | - interactiveSrcLoc, -- Code from an interactive session
|
|
24 | 22 | |
25 | 23 | advanceSrcLoc,
|
26 | 24 | advanceBufPos,
|
... | ... | @@ -255,10 +253,8 @@ getBufPos (RealSrcLoc _ mbpos) = mbpos |
255 | 253 | getBufPos (UnhelpfulLoc _) = Strict.Nothing
|
256 | 254 | |
257 | 255 | -- | Built-in "bad" 'SrcLoc' values for particular locations
|
258 | -noSrcLoc, generatedSrcLoc, interactiveSrcLoc :: SrcLoc
|
|
256 | +noSrcLoc :: SrcLoc
|
|
259 | 257 | noSrcLoc = UnhelpfulLoc (fsLit "<no location info>")
|
260 | -generatedSrcLoc = UnhelpfulLoc (fsLit "<compiler-generated code>")
|
|
261 | -interactiveSrcLoc = UnhelpfulLoc (fsLit "<interactive>")
|
|
262 | 258 | |
263 | 259 | -- | Creates a "bad" 'SrcLoc' that has no detailed information about its location
|
264 | 260 | mkGeneralSrcLoc :: FastString -> SrcLoc
|
... | ... | @@ -12,7 +12,6 @@ import Utilities |
12 | 12 | import Hadrian.BuildPath
|
13 | 13 | import Hadrian.Expression
|
14 | 14 | import Settings.Builders.Common (cArgs, getStagedCCFlags)
|
15 | -import GHC.Platform.ArchOS
|
|
16 | 15 | |
17 | 16 | -- | Build in-tree GMP library objects (if GmpInTree flag is set) and return
|
18 | 17 | -- their paths.
|
... | ... | @@ -128,7 +127,10 @@ gmpRules = do |
128 | 127 | mconcat
|
129 | 128 | [ cArgs
|
130 | 129 | , getStagedCCFlags
|
131 | - , anyTargetArch [ArchWasm32] ? arg "-fvisibility=default"
|
|
130 | + -- gmp symbols are only used by bignum logic in
|
|
131 | + -- ghc-internal and shouldn't be exported by the
|
|
132 | + -- ghc-internal shared library.
|
|
133 | + , arg "-fvisibility=hidden"
|
|
132 | 134 | ]
|
133 | 135 | env <- sequence
|
134 | 136 | [ builderEnvironment "CC" $ Cc CompileC (stage ctx)
|
... | ... | @@ -3481,6 +3481,7 @@ module GHC.PrimopWrappers where |
3481 | 3481 | remWord8# :: GHC.Internal.Prim.Word8# -> GHC.Internal.Prim.Word8# -> GHC.Internal.Prim.Word8#
|
3482 | 3482 | resizeMutableByteArray# :: forall s. GHC.Internal.Prim.MutableByteArray# s -> GHC.Internal.Prim.Int# -> GHC.Internal.Prim.State# s -> (# GHC.Internal.Prim.State# s, GHC.Internal.Prim.MutableByteArray# s #)
|
3483 | 3483 | retry# :: forall a_levpoly. GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld -> (# GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld, a_levpoly #)
|
3484 | + seq :: forall a b_reppoly. a -> b_reppoly -> b_reppoly
|
|
3484 | 3485 | setAddrRange# :: GHC.Internal.Prim.Addr# -> GHC.Internal.Prim.Int# -> GHC.Internal.Prim.Int# -> GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld -> GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld
|
3485 | 3486 | setByteArray# :: forall s. GHC.Internal.Prim.MutableByteArray# s -> GHC.Internal.Prim.Int# -> GHC.Internal.Prim.Int# -> GHC.Internal.Prim.Int# -> GHC.Internal.Prim.State# s -> GHC.Internal.Prim.State# s
|
3486 | 3487 | setOtherThreadAllocationCounter# :: GHC.Internal.Prim.Int64# -> GHC.Internal.Prim.ThreadId# -> GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld -> GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld
|
... | ... | @@ -3484,6 +3484,7 @@ module GHC.PrimopWrappers where |
3484 | 3484 | remWord8# :: GHC.Internal.Prim.Word8# -> GHC.Internal.Prim.Word8# -> GHC.Internal.Prim.Word8#
|
3485 | 3485 | resizeMutableByteArray# :: forall s. GHC.Internal.Prim.MutableByteArray# s -> GHC.Internal.Prim.Int# -> GHC.Internal.Prim.State# s -> (# GHC.Internal.Prim.State# s, GHC.Internal.Prim.MutableByteArray# s #)
|
3486 | 3486 | retry# :: forall a_levpoly. GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld -> (# GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld, a_levpoly #)
|
3487 | + seq :: forall a b_reppoly. a -> b_reppoly -> b_reppoly
|
|
3487 | 3488 | setAddrRange# :: GHC.Internal.Prim.Addr# -> GHC.Internal.Prim.Int# -> GHC.Internal.Prim.Int# -> GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld -> GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld
|
3488 | 3489 | setByteArray# :: forall s. GHC.Internal.Prim.MutableByteArray# s -> GHC.Internal.Prim.Int# -> GHC.Internal.Prim.Int# -> GHC.Internal.Prim.Int# -> GHC.Internal.Prim.State# s -> GHC.Internal.Prim.State# s
|
3489 | 3490 | setOtherThreadAllocationCounter# :: GHC.Internal.Prim.Int64# -> GHC.Internal.Prim.ThreadId# -> GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld -> GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld
|
... | ... | @@ -510,7 +510,7 @@ gen_wrappers (Info _ entries) |
510 | 510 | want_wrapper :: Entry -> Bool
|
511 | 511 | want_wrapper entry =
|
512 | 512 | and
|
513 | - [ is_primop entry
|
|
513 | + [ (is_primop entry || is_seq_pseudoop entry)
|
|
514 | 514 | , not $ name entry `elem` magical_primops
|
515 | 515 | , not $ is_vector entry
|
516 | 516 | -- We currently don't generate wrappers for vector primops.
|
... | ... | @@ -520,6 +520,12 @@ gen_wrappers (Info _ entries) |
520 | 520 | -- suppose this choice can be revisited?
|
521 | 521 | ]
|
522 | 522 | |
523 | + -- We also want a wrapper for the `seq` pseudoop, since GHCi
|
|
524 | + -- expects to find a value binding in PrimopWrappers.
|
|
525 | + is_seq_pseudoop :: Entry -> Bool
|
|
526 | + is_seq_pseudoop (PseudoOpSpec { name = n }) = n == "seq"
|
|
527 | + is_seq_pseudoop _ = False
|
|
528 | + |
|
523 | 529 | magical_primops :: [String]
|
524 | 530 | magical_primops =
|
525 | 531 | [ "tagToEnum#"
|
1 | +cradle:
|
|
2 | + cabal: |
... | ... | @@ -291,7 +291,7 @@ const isNode = Boolean(globalThis?.process?.versions?.node); |
291 | 291 | // factor out browser-only/node-only logic into different modules. For
|
292 | 292 | // now, just make these global let bindings optionally initialized if
|
293 | 293 | // isNode and be careful to not use them in browser-only logic.
|
294 | -let fs, http, path, require, stream, util, wasi, ws, zlib;
|
|
294 | +let fs, http, path, require, stream, wasi, ws;
|
|
295 | 295 | |
296 | 296 | if (isNode) {
|
297 | 297 | require = (await import("node:module")).createRequire(import.meta.url);
|
... | ... | @@ -300,9 +300,7 @@ if (isNode) { |
300 | 300 | http = require("http");
|
301 | 301 | path = require("path");
|
302 | 302 | stream = require("stream");
|
303 | - util = require("util");
|
|
304 | 303 | wasi = require("wasi");
|
305 | - zlib = require("zlib");
|
|
306 | 304 | |
307 | 305 | // Optional npm dependencies loaded via NODE_PATH
|
308 | 306 | try {
|
... | ... | @@ -561,30 +559,8 @@ args.rpc.opened.then(() => main(args)); |
561 | 559 | }[path.extname(p)] || "application/octet-stream"
|
562 | 560 | );
|
563 | 561 | |
564 | - const buf = Buffer.from(await fs.promises.readFile(p));
|
|
565 | - const etag = `sha512-${Buffer.from(
|
|
566 | - await crypto.subtle.digest("SHA-512", buf)
|
|
567 | - ).toString("base64")}`;
|
|
568 | - |
|
569 | - res.setHeader("ETag", etag);
|
|
570 | - |
|
571 | - if (req.headers["if-none-match"] === etag) {
|
|
572 | - res.writeHead(304);
|
|
573 | - res.end();
|
|
574 | - return;
|
|
575 | - }
|
|
576 | - |
|
577 | - res.setHeader("Content-Encoding", "br");
|
|
578 | - |
|
579 | 562 | res.writeHead(200);
|
580 | - res.end(
|
|
581 | - await util.promisify(zlib.brotliCompress)(buf, {
|
|
582 | - params: {
|
|
583 | - [zlib.constants.BROTLI_PARAM_QUALITY]:
|
|
584 | - zlib.constants.BROTLI_MIN_QUALITY,
|
|
585 | - },
|
|
586 | - })
|
|
587 | - );
|
|
563 | + fs.createReadStream(p).pipe(res);
|
|
588 | 564 | return;
|
589 | 565 | }
|
590 | 566 |