[Git][ghc/ghc][wip/split-sections-scc] 16 commits: Remove unused known-key and name variables for generics
Cheng Shao pushed to branch wip/split-sections-scc at Glasgow Haskell Compiler / GHC Commits: 91edd292 by Wolfgang Jeltsch at 2025-12-19T03:18:19-05:00 Remove unused known-key and name variables for generics This removes the known-key and corresponding name variables for `K1`, `M1`, `R`, `D`, `C`, `S`, and `URec` from `GHC.Generics`, as they are apparently nowhere used in GHC’s source code. - - - - - 73ee7e38 by Wolfgang Jeltsch at 2025-12-19T03:19:02-05:00 Remove unused known keys and names for generics classes This removes the known-key and corresponding name variables for `Datatype`, `Constructor`, and `Selector` from `GHC.Generics`, as they are apparently nowhere used in GHC’s source code. - - - - - f69c5f14 by Cheng Shao at 2025-12-19T03:19:45-05:00 wasm: fix handling of ByteArray#/MutableByteArray# arguments in JSFFI imports This patch fixes the handling of ByteArray#/MutableByteArray# arguments in JSFFI imports, see the amended note and manual for explanation. Also adds a test to witness the fix. Co-authored-by: Codex <codex@openai.com> - - - - - 224446a2 by Cheng Shao at 2025-12-20T07:49:54-05:00 rts: workaround -Werror=maybe-uninitialized false positives In some cases gcc might report -Werror=maybe-uninitialized that we know are false positives, but need to workaround it to make validate builds with -Werror pass. - - - - - 251ec087 by Cheng Shao at 2025-12-20T07:49:54-05:00 hadrian: use -Og as C/C++ optimization level when debugging This commit enables -Og as optimization level when compiling the debug ways of rts. According to gcc documentation (https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-Og), -Og is a better choice than -O0 for producing debuggable code. It's also supported by clang as well, so it makes sense to use it as a default for debugging. Also add missing -g3 flag to C++ compilation flags in +debug_info flavour transformer. - - - - - fb586c67 by Cheng Shao at 2025-12-20T07:50:36-05:00 compiler: replace DList with OrdList This patch removes `DList` logic from the compiler and replaces it with `OrdList` which also supports O(1) concatenation and should be more memory efficient than the church-encoded `DList`. - - - - - 8149c987 by Cheng Shao at 2025-12-20T17:06:51-05:00 hadrian: add with_profiled_libs flavour transformer This patch adds a `with_profiled_libs` flavour transformer to hadrian which is the exact opposite of `no_profiled_libs`. It adds profiling ways to stage1+ rts/library ways, and doesn't alter other flavour settings. It is useful when needing to test profiling logic locally with a quick flavour. - - - - - 746b18cd by Cheng Shao at 2025-12-20T17:06:51-05:00 hadrian: fix missing profiled dynamic libraries in profiled_ghc This commit fixes the profiled_ghc flavour transformer to include profiled dynamic libraries as well, since they're supported by GHC since !12595. - - - - - 4dd7e3b9 by Cheng Shao at 2025-12-20T17:07:33-05:00 ci: set http.postBuffer to mitigate perf notes timeout on some runners This patch sets http.postBuffer to mitigate the timeout when fetching perf notes on some runners with slow internet connection. Fixes #26684. - - - - - bc36268a by Wolfgang Jeltsch at 2025-12-21T16:23:24-05:00 Remove unused known keys and names for type representations This removes the known-key and corresponding name variables for `TrName`, `TrNameD`, `TypeRep`, `KindRepTypeLitD`, `TypeLitSort`, and `mkTrType`, as they are apparently nowhere used in GHC’s source code. - - - - - ff5050e9 by Wolfgang Jeltsch at 2025-12-21T16:24:04-05:00 Remove unused known keys and names for natural operations This removes the known-key and corresponding name variables for `naturalAndNot`, `naturalLog2`, `naturalLogBaseWord`, `naturalLogBase`, `naturalPowMod`, `naturalSizeInBase`, `naturalToFloat`, and `naturalToDouble`, as they are apparently nowhere used in GHC’s source code. - - - - - 424388c2 by Wolfgang Jeltsch at 2025-12-21T16:24:45-05:00 Remove the unused known key and name for `Fingerprint` This removes the variables for the known key and the name of the `Fingerprint` data constructor, as they are apparently nowhere used in GHC’s source code. - - - - - a1ed86fe by Wolfgang Jeltsch at 2025-12-21T16:25:26-05:00 Remove the unused known key and name for `failIO` This removes the variables for the known key and the name of the `failIO` operation, as they are apparently nowhere used in GHC’s source code. - - - - - b8220daf by Wolfgang Jeltsch at 2025-12-21T16:26:07-05:00 Remove the unused known key and name for `liftM` This removes the variables for the known key and the name of the `liftM` operation, as they are apparently nowhere used in GHC’s source code. - - - - - eb0628b1 by Wolfgang Jeltsch at 2025-12-21T16:26:47-05:00 Fix the documentation of `hIsClosed` - - - - - 972a2c8e by Cheng Shao at 2025-12-22T09:34:14+01:00 WIP - - - - - 18 changed files: - .gitlab/ci.sh - compiler/GHC/Builtin/Names.hs - compiler/GHC/CmmToAsm.hs - compiler/GHC/HsToCore/Foreign/Wasm.hs - compiler/GHC/Parser/String.hs - compiler/GHC/StgToCmm/InfoTableProv.hs - docs/users_guide/wasm.rst - hadrian/doc/flavours.md - hadrian/src/Flavour.hs - hadrian/src/Settings/Packages.hs - libraries/ghc-internal/src/GHC/Internal/IO/Handle.hs - rts/linker/InitFini.c - rts/sm/Sanity.c - testsuite/tests/jsffi/all.T - + testsuite/tests/jsffi/bytearrayarg.hs - + testsuite/tests/jsffi/bytearrayarg.mjs - + testsuite/tests/jsffi/bytearrayarg.stdout - testsuite/tests/perf/should_run/all.T Changes: ===================================== .gitlab/ci.sh ===================================== @@ -265,6 +265,15 @@ function setup() { # testsuite driver! git config gc.auto 0 + # Some runners still choke at the perf note fetch step, which has to + # do with slow internet connection, see + # https://docs.gitlab.com/topics/git/troubleshooting_git/#error-stream-0-was-n... + # for the http.postBuffer mitigation. It might seem + # counter-intuitive that "post buffer" helps with fetching, but git + # indeed issues post requests when fetching over https, it's a + # bidirectional negotiation with the remote. + git config http.postBuffer 52428800 + info "=====================================================" info "Toolchain versions" info "=====================================================" ===================================== compiler/GHC/Builtin/Names.hs ===================================== @@ -222,12 +222,11 @@ basicKnownKeyNames -- Type representation types trModuleTyConName, trModuleDataConName, - trNameTyConName, trNameSDataConName, trNameDDataConName, + trNameSDataConName, trTyConTyConName, trTyConDataConName, -- Typeable typeableClassName, - typeRepTyConName, someTypeRepTyConName, someTypeRepDataConName, kindRepTyConName, @@ -237,13 +236,10 @@ basicKnownKeyNames kindRepFunDataConName, kindRepTYPEDataConName, kindRepTypeLitSDataConName, - kindRepTypeLitDDataConName, - typeLitSortTyConName, typeLitSymbolDataConName, typeLitNatDataConName, typeLitCharDataConName, typeRepIdName, - mkTrTypeName, mkTrConName, mkTrAppCheckedName, mkTrFunName, @@ -296,7 +292,7 @@ basicKnownKeyNames fmapName, -- Monad stuff - thenIOName, bindIOName, returnIOName, failIOName, bindMName, thenMName, + thenIOName, bindIOName, returnIOName, bindMName, thenMName, returnMName, joinMName, -- MonadFail @@ -409,26 +405,18 @@ basicKnownKeyNames naturalQuotName, naturalRemName, naturalAndName, - naturalAndNotName, naturalOrName, naturalXorName, naturalTestBitName, naturalBitName, naturalGcdName, naturalLcmName, - naturalLog2Name, - naturalLogBaseWordName, - naturalLogBaseName, - naturalPowModName, - naturalSizeInBaseName, bignatEqName, -- Float/Double integerToFloatName, integerToDoubleName, - naturalToFloatName, - naturalToDoubleName, rationalToFloatName, rationalToDoubleName, @@ -476,11 +464,9 @@ basicKnownKeyNames -- Generics , genClassName, gen1ClassName - , datatypeClassName, constructorClassName, selectorClassName -- Monad comprehensions , guardMName - , liftMName , mzipName -- GHCi Sandbox @@ -492,9 +478,6 @@ basicKnownKeyNames , staticPtrDataConName, staticPtrInfoDataConName , fromStaticPtrName - -- Fingerprint - , fingerprintDataConName - -- Custom type errors , errorMessageTypeErrorFamName , typeErrorTextDataConName @@ -517,12 +500,9 @@ basicKnownKeyNames genericTyConNames :: [Name] genericTyConNames = [ - v1TyConName, u1TyConName, par1TyConName, rec1TyConName, - k1TyConName, m1TyConName, sumTyConName, prodTyConName, - compTyConName, rTyConName, dTyConName, - cTyConName, sTyConName, rec0TyConName, - d1TyConName, c1TyConName, s1TyConName, - repTyConName, rep1TyConName, uRecTyConName, + v1TyConName, u1TyConName, par1TyConName, rec1TyConName, sumTyConName, + prodTyConName, compTyConName, rec0TyConName, d1TyConName, c1TyConName, + s1TyConName, repTyConName, rep1TyConName, uAddrTyConName, uCharTyConName, uDoubleTyConName, uFloatTyConName, uIntTyConName, uWordTyConName, prefixIDataConName, infixIDataConName, leftAssociativeDataConName, @@ -939,11 +919,8 @@ voidTyConName = tcQual gHC_INTERNAL_BASE (fsLit "Void") voidTyConKey -- Generics (types) v1TyConName, u1TyConName, par1TyConName, rec1TyConName, - k1TyConName, m1TyConName, sumTyConName, prodTyConName, - compTyConName, rTyConName, dTyConName, - cTyConName, sTyConName, rec0TyConName, - d1TyConName, c1TyConName, s1TyConName, - repTyConName, rep1TyConName, uRecTyConName, + sumTyConName, prodTyConName, compTyConName, rec0TyConName, d1TyConName, + c1TyConName, s1TyConName, repTyConName, rep1TyConName, uAddrTyConName, uCharTyConName, uDoubleTyConName, uFloatTyConName, uIntTyConName, uWordTyConName, prefixIDataConName, infixIDataConName, leftAssociativeDataConName, @@ -958,18 +935,11 @@ v1TyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "V1") v1TyConKey u1TyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "U1") u1TyConKey par1TyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "Par1") par1TyConKey rec1TyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "Rec1") rec1TyConKey -k1TyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "K1") k1TyConKey -m1TyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "M1") m1TyConKey sumTyConName = tcQual gHC_INTERNAL_GENERICS (fsLit ":+:") sumTyConKey prodTyConName = tcQual gHC_INTERNAL_GENERICS (fsLit ":*:") prodTyConKey compTyConName = tcQual gHC_INTERNAL_GENERICS (fsLit ":.:") compTyConKey -rTyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "R") rTyConKey -dTyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "D") dTyConKey -cTyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "C") cTyConKey -sTyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "S") sTyConKey - rec0TyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "Rec0") rec0TyConKey d1TyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "D1") d1TyConKey c1TyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "C1") c1TyConKey @@ -978,7 +948,6 @@ s1TyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "S1") s1TyConKey repTyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "Rep") repTyConKey rep1TyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "Rep1") rep1TyConKey -uRecTyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "URec") uRecTyConKey uAddrTyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "UAddr") uAddrTyConKey uCharTyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "UChar") uCharTyConKey uDoubleTyConName = tcQual gHC_INTERNAL_GENERICS (fsLit "UDouble") uDoubleTyConKey @@ -1169,18 +1138,12 @@ integerFromNaturalName , naturalQuotName , naturalRemName , naturalAndName - , naturalAndNotName , naturalOrName , naturalXorName , naturalTestBitName , naturalBitName , naturalGcdName , naturalLcmName - , naturalLog2Name - , naturalLogBaseWordName - , naturalLogBaseName - , naturalPowModName - , naturalSizeInBaseName , bignatEqName , bignatCompareName , bignatCompareWordName @@ -1209,18 +1172,12 @@ naturalQuotRemName = bnnVarQual "naturalQuotRem#" naturalQuotRe naturalQuotName = bnnVarQual "naturalQuot" naturalQuotIdKey naturalRemName = bnnVarQual "naturalRem" naturalRemIdKey naturalAndName = bnnVarQual "naturalAnd" naturalAndIdKey -naturalAndNotName = bnnVarQual "naturalAndNot" naturalAndNotIdKey naturalOrName = bnnVarQual "naturalOr" naturalOrIdKey naturalXorName = bnnVarQual "naturalXor" naturalXorIdKey naturalTestBitName = bnnVarQual "naturalTestBit#" naturalTestBitIdKey naturalBitName = bnnVarQual "naturalBit#" naturalBitIdKey naturalGcdName = bnnVarQual "naturalGcd" naturalGcdIdKey naturalLcmName = bnnVarQual "naturalLcm" naturalLcmIdKey -naturalLog2Name = bnnVarQual "naturalLog2#" naturalLog2IdKey -naturalLogBaseWordName = bnnVarQual "naturalLogBaseWord#" naturalLogBaseWordIdKey -naturalLogBaseName = bnnVarQual "naturalLogBase#" naturalLogBaseIdKey -naturalPowModName = bnnVarQual "naturalPowMod" naturalPowModIdKey -naturalSizeInBaseName = bnnVarQual "naturalSizeInBase#" naturalSizeInBaseIdKey integerFromNaturalName = bniVarQual "integerFromNatural" integerFromNaturalIdKey integerToNaturalClampName = bniVarQual "integerToNaturalClamp" integerToNaturalClampIdKey @@ -1291,12 +1248,9 @@ realFloatClassName = clsQual gHC_INTERNAL_FLOAT (fsLit "RealFloat") realFloatCla -- other GHC.Internal.Float functions integerToFloatName, integerToDoubleName, - naturalToFloatName, naturalToDoubleName, rationalToFloatName, rationalToDoubleName :: Name integerToFloatName = varQual gHC_INTERNAL_FLOAT (fsLit "integerToFloat#") integerToFloatIdKey integerToDoubleName = varQual gHC_INTERNAL_FLOAT (fsLit "integerToDouble#") integerToDoubleIdKey -naturalToFloatName = varQual gHC_INTERNAL_FLOAT (fsLit "naturalToFloat#") naturalToFloatIdKey -naturalToDoubleName = varQual gHC_INTERNAL_FLOAT (fsLit "naturalToDouble#") naturalToDoubleIdKey rationalToFloatName = varQual gHC_INTERNAL_FLOAT (fsLit "rationalToFloat") rationalToFloatIdKey rationalToDoubleName = varQual gHC_INTERNAL_FLOAT (fsLit "rationalToDouble") rationalToDoubleIdKey @@ -1307,17 +1261,13 @@ ixClassName = clsQual gHC_INTERNAL_IX (fsLit "Ix") ixClassKey -- Typeable representation types trModuleTyConName , trModuleDataConName - , trNameTyConName , trNameSDataConName - , trNameDDataConName , trTyConTyConName , trTyConDataConName :: Name trModuleTyConName = tcQual gHC_TYPES (fsLit "Module") trModuleTyConKey trModuleDataConName = dcQual gHC_TYPES (fsLit "Module") trModuleDataConKey -trNameTyConName = tcQual gHC_TYPES (fsLit "TrName") trNameTyConKey trNameSDataConName = dcQual gHC_TYPES (fsLit "TrNameS") trNameSDataConKey -trNameDDataConName = dcQual gHC_TYPES (fsLit "TrNameD") trNameDDataConKey trTyConTyConName = tcQual gHC_TYPES (fsLit "TyCon") trTyConTyConKey trTyConDataConName = dcQual gHC_TYPES (fsLit "TyCon") trTyConDataConKey @@ -1328,7 +1278,6 @@ kindRepTyConName , kindRepFunDataConName , kindRepTYPEDataConName , kindRepTypeLitSDataConName - , kindRepTypeLitDDataConName :: Name kindRepTyConName = tcQual gHC_TYPES (fsLit "KindRep") kindRepTyConKey kindRepTyConAppDataConName = dcQual gHC_TYPES (fsLit "KindRepTyConApp") kindRepTyConAppDataConKey @@ -1337,24 +1286,19 @@ kindRepAppDataConName = dcQual gHC_TYPES (fsLit "KindRepApp") kindR kindRepFunDataConName = dcQual gHC_TYPES (fsLit "KindRepFun") kindRepFunDataConKey kindRepTYPEDataConName = dcQual gHC_TYPES (fsLit "KindRepTYPE") kindRepTYPEDataConKey kindRepTypeLitSDataConName = dcQual gHC_TYPES (fsLit "KindRepTypeLitS") kindRepTypeLitSDataConKey -kindRepTypeLitDDataConName = dcQual gHC_TYPES (fsLit "KindRepTypeLitD") kindRepTypeLitDDataConKey -typeLitSortTyConName - , typeLitSymbolDataConName +typeLitSymbolDataConName , typeLitNatDataConName , typeLitCharDataConName :: Name -typeLitSortTyConName = tcQual gHC_TYPES (fsLit "TypeLitSort") typeLitSortTyConKey typeLitSymbolDataConName = dcQual gHC_TYPES (fsLit "TypeLitSymbol") typeLitSymbolDataConKey typeLitNatDataConName = dcQual gHC_TYPES (fsLit "TypeLitNat") typeLitNatDataConKey typeLitCharDataConName = dcQual gHC_TYPES (fsLit "TypeLitChar") typeLitCharDataConKey -- Class Typeable, and functions for constructing `Typeable` dictionaries typeableClassName - , typeRepTyConName , someTypeRepTyConName , someTypeRepDataConName - , mkTrTypeName , mkTrConName , mkTrAppCheckedName , mkTrFunName @@ -1365,11 +1309,9 @@ typeableClassName , trGhcPrimModuleName :: Name typeableClassName = clsQual gHC_INTERNAL_TYPEABLE_INTERNAL (fsLit "Typeable") typeableClassKey -typeRepTyConName = tcQual gHC_INTERNAL_TYPEABLE_INTERNAL (fsLit "TypeRep") typeRepTyConKey someTypeRepTyConName = tcQual gHC_INTERNAL_TYPEABLE_INTERNAL (fsLit "SomeTypeRep") someTypeRepTyConKey someTypeRepDataConName = dcQual gHC_INTERNAL_TYPEABLE_INTERNAL (fsLit "SomeTypeRep") someTypeRepDataConKey typeRepIdName = varQual gHC_INTERNAL_TYPEABLE_INTERNAL (fsLit "typeRep#") typeRepIdKey -mkTrTypeName = varQual gHC_INTERNAL_TYPEABLE_INTERNAL (fsLit "mkTrType") mkTrTypeKey mkTrConName = varQual gHC_INTERNAL_TYPEABLE_INTERNAL (fsLit "mkTrCon") mkTrConKey mkTrAppCheckedName = varQual gHC_INTERNAL_TYPEABLE_INTERNAL (fsLit "mkTrAppChecked") mkTrAppCheckedKey mkTrFunName = varQual gHC_INTERNAL_TYPEABLE_INTERNAL (fsLit "mkTrFun") mkTrFunKey @@ -1494,15 +1436,10 @@ readClassName :: Name readClassName = clsQual gHC_INTERNAL_READ (fsLit "Read") readClassKey -- Classes Generic and Generic1, Datatype, Constructor and Selector -genClassName, gen1ClassName, datatypeClassName, constructorClassName, - selectorClassName :: Name +genClassName, gen1ClassName :: Name genClassName = clsQual gHC_INTERNAL_GENERICS (fsLit "Generic") genClassKey gen1ClassName = clsQual gHC_INTERNAL_GENERICS (fsLit "Generic1") gen1ClassKey -datatypeClassName = clsQual gHC_INTERNAL_GENERICS (fsLit "Datatype") datatypeClassKey -constructorClassName = clsQual gHC_INTERNAL_GENERICS (fsLit "Constructor") constructorClassKey -selectorClassName = clsQual gHC_INTERNAL_GENERICS (fsLit "Selector") selectorClassKey - genericClassNames :: [Name] genericClassNames = [genClassName, gen1ClassName] @@ -1513,13 +1450,12 @@ ghciStepIoMName = varQual gHC_INTERNAL_GHCI (fsLit "ghciStepIO") ghciStepIoMClas -- IO things ioTyConName, ioDataConName, - thenIOName, bindIOName, returnIOName, failIOName :: Name + thenIOName, bindIOName, returnIOName :: Name ioTyConName = tcQual gHC_TYPES (fsLit "IO") ioTyConKey ioDataConName = dcQual gHC_TYPES (fsLit "IO") ioDataConKey thenIOName = varQual gHC_INTERNAL_BASE (fsLit "thenIO") thenIOIdKey bindIOName = varQual gHC_INTERNAL_BASE (fsLit "bindIO") bindIOIdKey returnIOName = varQual gHC_INTERNAL_BASE (fsLit "returnIO") returnIOIdKey -failIOName = varQual gHC_INTERNAL_IO (fsLit "failIO") failIOIdKey -- IO things printName :: Name @@ -1564,9 +1500,8 @@ choiceAName = varQual gHC_INTERNAL_ARROW (fsLit "|||") choiceAIdKey loopAName = varQual gHC_INTERNAL_ARROW (fsLit "loop") loopAIdKey -- Monad comprehensions -guardMName, liftMName, mzipName :: Name +guardMName, mzipName :: Name guardMName = varQual gHC_INTERNAL_MONAD (fsLit "guard") guardMIdKey -liftMName = varQual gHC_INTERNAL_MONAD (fsLit "liftM") liftMIdKey mzipName = varQual gHC_INTERNAL_CONTROL_MONAD_ZIP (fsLit "mzip") mzipIdKey @@ -1654,10 +1589,6 @@ fromStaticPtrName :: Name fromStaticPtrName = varQual gHC_INTERNAL_STATICPTR (fsLit "fromStaticPtr") fromStaticPtrClassOpKey -fingerprintDataConName :: Name -fingerprintDataConName = - dcQual gHC_INTERNAL_FINGERPRINT_TYPE (fsLit "Fingerprint") fingerprintDataConKey - constPtrConName :: Name constPtrConName = tcQual gHC_INTERNAL_FOREIGN_C_CONSTPTR (fsLit "ConstPtr") constPtrTyConKey @@ -1753,15 +1684,10 @@ applicativeClassKey = mkPreludeClassUnique 34 foldableClassKey = mkPreludeClassUnique 35 traversableClassKey = mkPreludeClassUnique 36 -genClassKey, gen1ClassKey, datatypeClassKey, constructorClassKey, - selectorClassKey :: Unique +genClassKey, gen1ClassKey :: Unique genClassKey = mkPreludeClassUnique 37 gen1ClassKey = mkPreludeClassUnique 38 -datatypeClassKey = mkPreludeClassUnique 39 -constructorClassKey = mkPreludeClassUnique 40 -selectorClassKey = mkPreludeClassUnique 41 - -- KnownNat: see Note [KnownNat & KnownSymbol and EvLit] in GHC.Tc.Instance.Class knownNatClassNameKey :: Unique knownNatClassNameKey = mkPreludeClassUnique 42 @@ -1940,21 +1866,16 @@ pluginTyConKey, frontendPluginTyConKey :: Unique pluginTyConKey = mkPreludeTyConUnique 102 frontendPluginTyConKey = mkPreludeTyConUnique 103 -trTyConTyConKey, trModuleTyConKey, trNameTyConKey, - kindRepTyConKey, typeLitSortTyConKey :: Unique +trTyConTyConKey, trModuleTyConKey, + kindRepTyConKey :: Unique trTyConTyConKey = mkPreludeTyConUnique 104 trModuleTyConKey = mkPreludeTyConUnique 105 -trNameTyConKey = mkPreludeTyConUnique 106 kindRepTyConKey = mkPreludeTyConUnique 107 -typeLitSortTyConKey = mkPreludeTyConUnique 108 -- Generics (Unique keys) v1TyConKey, u1TyConKey, par1TyConKey, rec1TyConKey, - k1TyConKey, m1TyConKey, sumTyConKey, prodTyConKey, - compTyConKey, rTyConKey, dTyConKey, - cTyConKey, sTyConKey, rec0TyConKey, - d1TyConKey, c1TyConKey, s1TyConKey, - repTyConKey, rep1TyConKey, uRecTyConKey, + sumTyConKey, prodTyConKey, compTyConKey, rec0TyConKey, + d1TyConKey, c1TyConKey, s1TyConKey, repTyConKey, rep1TyConKey, uAddrTyConKey, uCharTyConKey, uDoubleTyConKey, uFloatTyConKey, uIntTyConKey, uWordTyConKey :: Unique @@ -1962,18 +1883,11 @@ v1TyConKey = mkPreludeTyConUnique 135 u1TyConKey = mkPreludeTyConUnique 136 par1TyConKey = mkPreludeTyConUnique 137 rec1TyConKey = mkPreludeTyConUnique 138 -k1TyConKey = mkPreludeTyConUnique 139 -m1TyConKey = mkPreludeTyConUnique 140 sumTyConKey = mkPreludeTyConUnique 141 prodTyConKey = mkPreludeTyConUnique 142 compTyConKey = mkPreludeTyConUnique 143 -rTyConKey = mkPreludeTyConUnique 144 -dTyConKey = mkPreludeTyConUnique 146 -cTyConKey = mkPreludeTyConUnique 147 -sTyConKey = mkPreludeTyConUnique 148 - rec0TyConKey = mkPreludeTyConUnique 149 d1TyConKey = mkPreludeTyConUnique 151 c1TyConKey = mkPreludeTyConUnique 152 @@ -1982,7 +1896,6 @@ s1TyConKey = mkPreludeTyConUnique 153 repTyConKey = mkPreludeTyConUnique 155 rep1TyConKey = mkPreludeTyConUnique 156 -uRecTyConKey = mkPreludeTyConUnique 157 uAddrTyConKey = mkPreludeTyConUnique 158 uCharTyConKey = mkPreludeTyConUnique 159 uDoubleTyConKey = mkPreludeTyConUnique 160 @@ -2026,8 +1939,7 @@ callStackTyConKey :: Unique callStackTyConKey = mkPreludeTyConUnique 191 -- Typeables -typeRepTyConKey, someTypeRepTyConKey, someTypeRepDataConKey :: Unique -typeRepTyConKey = mkPreludeTyConUnique 192 +someTypeRepTyConKey, someTypeRepDataConKey :: Unique someTypeRepTyConKey = mkPreludeTyConUnique 193 someTypeRepDataConKey = mkPreludeTyConUnique 194 @@ -2159,19 +2071,15 @@ staticPtrDataConKey = mkPreludeDataConUnique 33 staticPtrInfoDataConKey :: Unique staticPtrInfoDataConKey = mkPreludeDataConUnique 34 -fingerprintDataConKey :: Unique -fingerprintDataConKey = mkPreludeDataConUnique 35 - srcLocDataConKey :: Unique srcLocDataConKey = mkPreludeDataConUnique 37 trTyConDataConKey, trModuleDataConKey, - trNameSDataConKey, trNameDDataConKey, + trNameSDataConKey, trGhcPrimModuleKey :: Unique trTyConDataConKey = mkPreludeDataConUnique 41 trModuleDataConKey = mkPreludeDataConUnique 43 trNameSDataConKey = mkPreludeDataConUnique 45 -trNameDDataConKey = mkPreludeDataConUnique 46 trGhcPrimModuleKey = mkPreludeDataConUnique 47 typeErrorTextDataConKey, @@ -2246,7 +2154,7 @@ vecElemDataConKeys = map mkPreludeDataConUnique [96..105] -- Typeable things kindRepTyConAppDataConKey, kindRepVarDataConKey, kindRepAppDataConKey, kindRepFunDataConKey, kindRepTYPEDataConKey, - kindRepTypeLitSDataConKey, kindRepTypeLitDDataConKey + kindRepTypeLitSDataConKey :: Unique kindRepTyConAppDataConKey = mkPreludeDataConUnique 106 kindRepVarDataConKey = mkPreludeDataConUnique 107 @@ -2254,7 +2162,6 @@ kindRepAppDataConKey = mkPreludeDataConUnique 108 kindRepFunDataConKey = mkPreludeDataConUnique 109 kindRepTYPEDataConKey = mkPreludeDataConUnique 110 kindRepTypeLitSDataConKey = mkPreludeDataConUnique 111 -kindRepTypeLitDDataConKey = mkPreludeDataConUnique 112 typeLitSymbolDataConKey, typeLitNatDataConKey, typeLitCharDataConKey :: Unique typeLitSymbolDataConKey = mkPreludeDataConUnique 113 @@ -2342,7 +2249,7 @@ cstringLengthIdKey = mkPreludeMiscIdUnique 28 concatIdKey, filterIdKey, zipIdKey, bindIOIdKey, returnIOIdKey, newStablePtrIdKey, - printIdKey, failIOIdKey, nullAddrIdKey, voidArgIdKey, + printIdKey, nullAddrIdKey, voidArgIdKey, otherwiseIdKey, assertIdKey :: Unique concatIdKey = mkPreludeMiscIdUnique 31 filterIdKey = mkPreludeMiscIdUnique 32 @@ -2351,7 +2258,6 @@ bindIOIdKey = mkPreludeMiscIdUnique 34 returnIOIdKey = mkPreludeMiscIdUnique 35 newStablePtrIdKey = mkPreludeMiscIdUnique 36 printIdKey = mkPreludeMiscIdUnique 37 -failIOIdKey = mkPreludeMiscIdUnique 38 nullAddrIdKey = mkPreludeMiscIdUnique 39 voidArgIdKey = mkPreludeMiscIdUnique 40 otherwiseIdKey = mkPreludeMiscIdUnique 43 @@ -2390,11 +2296,9 @@ considerAccessibleIdKey = mkPreludeMiscIdUnique 125 noinlineIdKey = mkPreludeMiscIdUnique 126 noinlineConstraintIdKey = mkPreludeMiscIdUnique 127 -integerToFloatIdKey, integerToDoubleIdKey, naturalToFloatIdKey, naturalToDoubleIdKey :: Unique +integerToFloatIdKey, integerToDoubleIdKey :: Unique integerToFloatIdKey = mkPreludeMiscIdUnique 128 integerToDoubleIdKey = mkPreludeMiscIdUnique 129 -naturalToFloatIdKey = mkPreludeMiscIdUnique 130 -naturalToDoubleIdKey = mkPreludeMiscIdUnique 131 rationalToFloatIdKey, rationalToDoubleIdKey :: Unique rationalToFloatIdKey = mkPreludeMiscIdUnique 132 @@ -2472,9 +2376,8 @@ toIntegerClassOpKey = mkPreludeMiscIdUnique 192 toRationalClassOpKey = mkPreludeMiscIdUnique 193 -- Monad comprehensions -guardMIdKey, liftMIdKey, mzipIdKey :: Unique +guardMIdKey, mzipIdKey :: Unique guardMIdKey = mkPreludeMiscIdUnique 194 -liftMIdKey = mkPreludeMiscIdUnique 195 mzipIdKey = mkPreludeMiscIdUnique 196 -- GHCi @@ -2497,7 +2400,6 @@ proxyHashKey = mkPreludeMiscIdUnique 502 -- Used to make `Typeable` dictionaries mkTyConKey - , mkTrTypeKey , mkTrConKey , mkTrAppCheckedKey , mkTrFunKey @@ -2507,7 +2409,6 @@ mkTyConKey , typeRepIdKey :: Unique mkTyConKey = mkPreludeMiscIdUnique 503 -mkTrTypeKey = mkPreludeMiscIdUnique 504 mkTrConKey = mkPreludeMiscIdUnique 505 mkTrAppCheckedKey = mkPreludeMiscIdUnique 506 typeNatTypeRepKey = mkPreludeMiscIdUnique 507 @@ -2620,18 +2521,12 @@ integerFromNaturalIdKey , naturalQuotIdKey , naturalRemIdKey , naturalAndIdKey - , naturalAndNotIdKey , naturalOrIdKey , naturalXorIdKey , naturalTestBitIdKey , naturalBitIdKey , naturalGcdIdKey , naturalLcmIdKey - , naturalLog2IdKey - , naturalLogBaseWordIdKey - , naturalLogBaseIdKey - , naturalPowModIdKey - , naturalSizeInBaseIdKey , bignatEqIdKey , bignatCompareIdKey , bignatCompareWordIdKey @@ -2686,18 +2581,12 @@ naturalQuotRemIdKey = mkPreludeMiscIdUnique 669 naturalQuotIdKey = mkPreludeMiscIdUnique 670 naturalRemIdKey = mkPreludeMiscIdUnique 671 naturalAndIdKey = mkPreludeMiscIdUnique 672 -naturalAndNotIdKey = mkPreludeMiscIdUnique 673 naturalOrIdKey = mkPreludeMiscIdUnique 674 naturalXorIdKey = mkPreludeMiscIdUnique 675 naturalTestBitIdKey = mkPreludeMiscIdUnique 676 naturalBitIdKey = mkPreludeMiscIdUnique 677 naturalGcdIdKey = mkPreludeMiscIdUnique 678 naturalLcmIdKey = mkPreludeMiscIdUnique 679 -naturalLog2IdKey = mkPreludeMiscIdUnique 680 -naturalLogBaseWordIdKey = mkPreludeMiscIdUnique 681 -naturalLogBaseIdKey = mkPreludeMiscIdUnique 682 -naturalPowModIdKey = mkPreludeMiscIdUnique 683 -naturalSizeInBaseIdKey = mkPreludeMiscIdUnique 684 bignatEqIdKey = mkPreludeMiscIdUnique 691 bignatCompareIdKey = mkPreludeMiscIdUnique 692 ===================================== compiler/GHC/CmmToAsm.hs ===================================== @@ -85,6 +85,7 @@ import GHC.CmmToAsm.BlockLayout as BlockLayout import GHC.Settings.Config import GHC.CmmToAsm.Instr import GHC.CmmToAsm.PIC +import GHC.CmmToAsm.Ppr (pprSectionHeader) import GHC.Platform.Reg import GHC.Platform.Reg.Class (RegClass) import GHC.CmmToAsm.Monad @@ -97,7 +98,9 @@ import GHC.Cmm.DebugBlock import GHC.Cmm.BlockId import GHC.StgToCmm.CgUtils ( fixStgRegisters ) import GHC.Cmm +import GHC.Cmm.Dataflow.Graph (entryLabel) import GHC.Cmm.Dataflow.Label +import GHC.Cmm.Dataflow.Block (foldBlockNodesF) import GHC.Cmm.GenericOpt import GHC.Cmm.CLabel @@ -123,13 +126,18 @@ import GHC.Data.Stream (liftIO) import qualified GHC.Data.Stream as Stream import GHC.Settings -import Data.List (sortBy) +import Data.List (sortBy, find) import Data.List.NonEmpty (groupAllWith, head) import Data.Maybe import Data.Ord ( comparing ) +import Data.Char (isSpace) import Control.Monad import System.IO -import System.Directory ( getCurrentDirectory ) +import System.Directory ( getCurrentDirectory, getTemporaryDirectory, removeFile ) +import qualified Data.Graph as Graph +import qualified Data.Map.Strict as Map +import qualified Data.Set as Set +import qualified Data.ByteString.Char8 as BS8 -------------------- nativeCodeGen :: forall a . Logger -> ToolSettings -> NCGConfig -> ModLocation -> Handle @@ -139,7 +147,13 @@ nativeCodeGen logger ts config modLoc h cmms = let platform = ncgPlatform config nCG' :: ( OutputableP Platform statics, Outputable jumpDest, Instruction instr) => NcgImpl statics instr jumpDest -> UniqDSMT IO a - nCG' ncgImpl = nativeCodeGen' logger config modLoc ncgImpl h cmms + nCG' ncgImpl + | shouldGroupSplitSections config + = nativeCodeGenGrouped logger config modLoc ncgImpl h cmms + | otherwise + = do + (a, _) <- nativeCodeGen' logger config modLoc ncgImpl False h cmms + return a in case platformArch platform of ArchX86 -> nCG' (X86.ncgX86 config) ArchX86_64 -> nCG' (X86.ncgX86_64 config) @@ -174,8 +188,257 @@ data NativeGenAcc statics instr , ngs_unwinds :: !(LabelMap [UnwindPoint]) -- ^ see Note [Unwinding information in the NCG] -- and Note [What is this unwinding business?] in "GHC.Cmm.DebugBlock". + , ngs_splitSecAcc :: !(Maybe SplitSecAcc) } +-- ----------------------------------------------------------------------------- +-- Split sections grouping + +data SplitNodeKey + = SplitNodeKey !SectionType !CLabel + +data SplitSecAcc = SplitSecAcc + { ssOwner :: !(Map.Map CLabel SplitNodeKey) + , ssNodeOrder :: !(Map.Map SplitNodeKey Int) + , ssNodes :: ![SplitNodeKey] -- ^ first-seen order + , ssNextId :: !Int + , ssPendingRefs :: !(Map.Map SplitNodeKey (Set.Set CLabel)) + } + +emptySplitSecAcc :: SplitSecAcc +emptySplitSecAcc = SplitSecAcc + { ssOwner = Map.empty + , ssNodeOrder = Map.empty + , ssNodes = [] + , ssNextId = 0 + , ssPendingRefs = Map.empty + } + +ensureSplitNode :: SplitNodeKey -> SplitSecAcc -> SplitSecAcc +ensureSplitNode node acc = + case Map.lookup node (ssNodeOrder acc) of + Just _ -> acc + Nothing -> + let newId = ssNextId acc + in acc { ssNodeOrder = Map.insert node newId (ssNodeOrder acc) + , ssNodes = ssNodes acc ++ [node] + , ssNextId = newId + 1 + } + +addSplitOwner :: CLabel -> SplitNodeKey -> SplitSecAcc -> SplitSecAcc +addSplitOwner lbl node acc = + let acc' = ensureSplitNode node acc + in acc' { ssOwner = Map.insert lbl node (ssOwner acc') } + +addSplitRefs :: SplitNodeKey -> Set.Set CLabel -> SplitSecAcc -> SplitSecAcc +addSplitRefs node refs acc = + let acc' = ensureSplitNode node acc + refs' = Map.findWithDefault Set.empty node (ssPendingRefs acc') + refs'' = refs `Set.union` refs' + in acc' { ssPendingRefs = Map.insert node refs'' (ssPendingRefs acc') } + +sectionTypeKey :: SectionType -> Int +sectionTypeKey t = case t of + Text -> 0 + Data -> 1 + ReadOnlyData -> 2 + RelocatableReadOnlyData -> 3 + UninitialisedData -> 4 + InitArray -> 5 + FiniArray -> 6 + CString -> 7 + IPE -> 8 + +instance Eq SplitNodeKey where + SplitNodeKey t1 l1 == SplitNodeKey t2 l2 = + sectionTypeKey t1 == sectionTypeKey t2 && l1 == l2 + +instance Ord SplitNodeKey where + compare (SplitNodeKey t1 l1) (SplitNodeKey t2 l2) = + compare (sectionTypeKey t1, l1) (sectionTypeKey t2, l2) + +shouldGroupSplitSections :: NCGConfig -> Bool +shouldGroupSplitSections config = + ncgSplitSections config && case platformOS (ncgPlatform config) of + OSDarwin -> False + OSAIX -> False + _ -> True + +labelsOfCmmLit :: CmmLit -> Set.Set CLabel +labelsOfCmmLit lit = case lit of + CmmLabel lbl -> Set.singleton lbl + CmmLabelOff lbl _ -> Set.singleton lbl + CmmLabelDiffOff lbl1 lbl2 _ _ -> Set.fromList [lbl1, lbl2] + _ -> Set.empty + +labelsOfCmmExpr :: CmmExpr -> Set.Set CLabel -> Set.Set CLabel +labelsOfCmmExpr expr acc = case expr of + CmmLit lit -> labelsOfCmmLit lit `Set.union` acc + _ -> acc + +collectStaticsLabels :: [CmmStatic] -> Set.Set CLabel +collectStaticsLabels = foldl' collect Set.empty + where + collect acc (CmmStaticLit lit) = labelsOfCmmLit lit `Set.union` acc + collect acc _ = acc + +collectGraphLabels :: CmmGraph -> Set.Set CLabel +collectGraphLabels graph = + foldl' collectBlock Set.empty (toBlockList graph) + where + collectBlock acc block = + foldBlockNodesF (\node a -> foldExpDeep labelsOfCmmExpr node a) block acc + +procSectionLabelRaw :: RawCmmDecl -> CLabel +procSectionLabelRaw (CmmProc infos entry _ graph) = + case mapLookup (g_entry graph) infos of + Just (CmmStaticsRaw info_lbl _) -> info_lbl + Nothing -> entry +procSectionLabelRaw _ = panic "procSectionLabelRaw: not a CmmProc" + +procSectionLabelNat :: NatCmmDecl statics instr -> CLabel +procSectionLabelNat (CmmProc infos entry _ (ListGraph blocks)) = + case find (\b -> blockLbl (blockId b) == entry) blocks of + Just b -> + case mapLookup (blockId b) infos of + Just (CmmStaticsRaw info_lbl _) -> info_lbl + Nothing -> entry + Nothing -> entry +procSectionLabelNat _ = panic "procSectionLabelNat: not a CmmProc" + +collectSplitSecRawDecl :: RawCmmDecl -> SplitSecAcc -> SplitSecAcc +collectSplitSecRawDecl decl acc = case decl of + CmmData (Section secTy suffix) (CmmStaticsRaw _ statics) -> + let node = SplitNodeKey secTy suffix + acc' = addSplitOwner suffix node acc + refs = collectStaticsLabels statics + in addSplitRefs node refs acc' + CmmProc infos entry _ graph -> + let procLbl = procSectionLabelRaw decl + procNode = SplitNodeKey Text procLbl + acc1 = addSplitOwner entry procNode acc + acc2 = addSplitOwner procLbl procNode acc1 + acc3 = foldl' (\a b -> addSplitOwner (blockLbl (entryLabel b)) procNode a) + acc2 (toBlockList graph) + infoStatics = mapElems infos + acc4 = foldl' (\a (CmmStaticsRaw info_lbl _) -> addSplitOwner info_lbl procNode a) + acc3 infoStatics + infoRefs = foldl' (\s (CmmStaticsRaw _ st) -> collectStaticsLabels st `Set.union` s) + Set.empty infoStatics + graphRefs = collectGraphLabels graph + refs = graphRefs `Set.union` infoRefs + in addSplitRefs procNode refs acc4 + +collectSplitSecJumpTables :: [NatCmmDecl statics instr] -> SplitSecAcc -> SplitSecAcc +collectSplitSecJumpTables decls acc = go Nothing acc decls + where + go _ acc' [] = acc' + go mProc acc' (d:ds) = case d of + CmmProc _ _ _ _ -> + let procLbl = procSectionLabelNat d + procNode = SplitNodeKey Text procLbl + acc'' = addSplitOwner procLbl procNode acc' + in go (Just procLbl) acc'' ds + CmmData (Section secTy suffix) _ -> + case mProc of + Nothing -> go mProc acc' ds + Just procLbl -> + let procNode = SplitNodeKey Text procLbl + tableNode = SplitNodeKey secTy suffix + acc1 = addSplitOwner suffix tableNode acc' + acc2 = addSplitRefs procNode (Set.singleton suffix) acc1 + acc3 = addSplitRefs tableNode (Set.singleton procLbl) acc2 + in go mProc acc3 ds + +splitSectionGroups :: SplitSecAcc -> Map.Map SplitNodeKey CLabel +splitSectionGroups acc = + let nodes = ssNodes acc + owner = ssOwner acc + refsMap = ssPendingRefs acc + nodeOrder node = Map.findWithDefault maxBound node (ssNodeOrder acc) + edgesFor node = + let refs = Map.findWithDefault Set.empty node refsMap + addRef s lbl = + case Map.lookup lbl owner of + Just node' -> Set.insert node' s + Nothing -> s + in Set.toList (Set.foldl' addRef Set.empty refs) + sccs = Graph.stronglyConnComp [ (node, node, edgesFor node) | node <- nodes ] + in foldl' (assignScc nodeOrder) Map.empty sccs + where + assignScc nodeOrder acc' scc = + let sccNodes = case scc of + Graph.AcyclicSCC n -> [n] + Graph.CyclicSCC ns -> ns + reps = foldl' (pickRep nodeOrder) Map.empty sccNodes + pickRep order repsAcc node@(SplitNodeKey secTy lbl) = + let secKey = sectionTypeKey secTy in + case Map.lookup secKey repsAcc of + Nothing -> Map.insert secKey lbl repsAcc + Just curLbl -> + if order node < order (SplitNodeKey secTy curLbl) + then Map.insert secKey lbl repsAcc + else repsAcc + addNode m node@(SplitNodeKey secTy _) = + case Map.lookup (sectionTypeKey secTy) reps of + Just repLbl -> Map.insert node repLbl m + Nothing -> m + in foldl' addNode acc' sccNodes + +splitSectionRewriteMap :: NCGConfig -> SplitSecAcc -> Map.Map BS8.ByteString BS8.ByteString +splitSectionRewriteMap config acc = + let ctx = ncgAsmContext config + groups = splitSectionGroups acc + lineFor secTy lbl = + BS8.pack $ showSDocOneLine ctx (pprSectionHeader config (Section secTy lbl)) + addEntry m (SplitNodeKey secTy oldLbl) newLbl = + let oldLine = lineFor secTy oldLbl + newLine = lineFor secTy newLbl + in if oldLine == newLine + then m + else case Map.lookup oldLine m of + Nothing -> Map.insert oldLine newLine m + Just _ -> m + in Map.foldlWithKey' addEntry Map.empty groups + +rewriteSplitSections :: Map.Map BS8.ByteString BS8.ByteString -> Handle -> Handle -> IO () +rewriteSplitSections mapping hIn hOut = loop + where + sectionPrefix = BS8.pack ".section " + loop = do + eof <- hIsEOF hIn + unless eof $ do + line <- BS8.hGetLine hIn + let (prefix, body) = BS8.span isSpace line + line' = + if BS8.isPrefixOf sectionPrefix body + then case Map.lookup body mapping of + Just newBody -> BS8.append prefix newBody + Nothing -> line + else line + BS8.hPut hOut line' + BS8.hPut hOut (BS8.singleton '\n') + loop + +nativeCodeGenGrouped :: (OutputableP Platform statics, Outputable jumpDest, Instruction instr) + => Logger + -> NCGConfig + -> ModLocation + -> NcgImpl statics instr jumpDest + -> Handle + -> CgStream RawCmmGroup a + -> UniqDSMT IO a +nativeCodeGenGrouped logger config modLoc ncgImpl h cmms = do + tmpDir <- liftIO getTemporaryDirectory + (tmpPath, tmpHandle) <- liftIO $ openBinaryTempFile tmpDir "ghc-split-sections" + (a, acc) <- nativeCodeGen' logger config modLoc ncgImpl True tmpHandle cmms + liftIO $ hClose tmpHandle + let mapping = splitSectionRewriteMap config acc + liftIO $ withBinaryFile tmpPath ReadMode $ \hIn -> + rewriteSplitSections mapping hIn h + liftIO $ removeFile tmpPath + return a + {- Note [Unwinding information in the NCG] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -205,19 +468,22 @@ nativeCodeGen' :: (OutputableP Platform statics, Outputable jumpDest, Instructio -> NCGConfig -> ModLocation -> NcgImpl statics instr jumpDest + -> Bool -> Handle -> CgStream RawCmmGroup a - -> UniqDSMT IO a -nativeCodeGen' logger config modLoc ncgImpl h cmms + -> UniqDSMT IO (a, SplitSecAcc) +nativeCodeGen' logger config modLoc ncgImpl collectSplit h cmms = do -- BufHandle is a performance hack. We could hide it inside -- Pretty if it weren't for the fact that we do lots of little -- printDocs here (in order to do codegen in constant space). bufh <- liftIO $ newBufHandle h - let ngs0 = NGS [] [] [] [] [] [] emptyUFM mapEmpty + let splitAcc = if collectSplit then Just emptySplitSecAcc else Nothing + let ngs0 = NGS [] [] [] [] [] [] emptyUFM mapEmpty splitAcc (ngs, a) <- cmmNativeGenStream logger config modLoc ncgImpl bufh cmms ngs0 _ <- finishNativeGen logger config modLoc bufh ngs - return a + let finalAcc = fromMaybe emptySplitSecAcc (ngs_splitSecAcc ngs) + return (a, finalAcc) finishNativeGen :: Instruction instr => Logger @@ -359,7 +625,11 @@ cmmNativeGens logger config ncgImpl h dbgMap = go return (ngs, us) go (cmm : cmms) ngs count us = do - let fileIds = ngs_dwarfFiles ngs + let ngs1 = case ngs_splitSecAcc ngs of + Nothing -> ngs + Just acc -> ngs { ngs_splitSecAcc = Just (collectSplitSecRawDecl cmm acc) } + + let fileIds = ngs_dwarfFiles ngs1 (us', fileIds', native, imports, colorStats, linearStats, unwinds, mcfg) <- {-# SCC "cmmNativeGen" #-} cmmNativeGen logger ncgImpl us fileIds dbgMap @@ -399,15 +669,17 @@ cmmNativeGens logger config ncgImpl h dbgMap = go then native : ngs_natives ngs else [] mCon = maybe id (:) - ngs' = ngs{ ngs_imports = imports : ngs_imports ngs - , ngs_natives = natives' - , ngs_colorStats = colorStats `mCon` ngs_colorStats ngs - , ngs_linearStats = linearStats `mCon` ngs_linearStats ngs - , ngs_labels = ngs_labels ngs ++ labels' - , ngs_dwarfFiles = fileIds' - , ngs_unwinds = ngs_unwinds ngs `mapUnion` unwinds - } - go cmms ngs' (count + 1) us' + ngs' = ngs1{ ngs_imports = imports : ngs_imports ngs1 + , ngs_natives = natives' + , ngs_colorStats = colorStats `mCon` ngs_colorStats ngs1 + , ngs_linearStats = linearStats `mCon` ngs_linearStats ngs1 + , ngs_labels = ngs_labels ngs1 ++ labels' + , ngs_dwarfFiles = fileIds' + , ngs_unwinds = ngs_unwinds ngs1 `mapUnion` unwinds + } + ngs'' = ngs' { ngs_splitSecAcc = + fmap (collectSplitSecJumpTables native) (ngs_splitSecAcc ngs') } + go cmms ngs'' (count + 1) us' -- see Note [pprNatCmmDeclS and pprNatCmmDeclH] in GHC.CmmToAsm.Monad ===================================== compiler/GHC/HsToCore/Foreign/Wasm.hs ===================================== @@ -224,6 +224,25 @@ especially since leaving all the boxing/unboxing business to C unifies the implementation of JSFFI imports and exports (rts_mkJSVal/rts_getJSVal). +We don't support unboxed FFI types like Int# etc. But we do support +one kind of unlifted FFI type for JSFFI import arguments: +ByteArray#/MutableByteArray#. The semantics is the same in C: the +pointer to the ByteArray# payload is passed instead of the ByteArray# +closure itself. This allows efficient zero-copy data exchange between +Haskell and JavaScript using unpinned ByteArray#, and the following +conditions must be met: + +- The JSFFI import itself must be a sync import marked as unsafe +- The JavaScript code must not re-enter Haskell when a ByteArray# is + passed as argument + +There's no magic in the handling of ByteArray#/MutableByteArray# +arguments. When generating C stub, we treat them like Ptr that points +to the payload, just without the rts_getPtr() unboxing call. After +lowering to C import, the backend takes care of adding the offset, see +add_shim in GHC.StgToCmm.Foreign and +Note [Unlifted boxed arguments to foreign calls]. + Now, each sync import calls a generated C function with a unique symbol. The C function uses rts_get* to unbox the arguments, call into JavaScript, then boxes the result with rts_mk* and returns it to @@ -517,8 +536,9 @@ importCStub sync cfun_name arg_tys res_ty js_src = CStub c_doc [] [] cfun_ret | res_ty `eqType` unitTy = cfun_call_import <> semi | otherwise = text "return" <+> cfun_call_import <> semi - cfun_make_arg arg_ty arg_val = - text ("rts_get" ++ ffiType arg_ty) <> parens arg_val + cfun_make_arg arg_ty arg_val + | isByteArrayPrimTy arg_ty = arg_val + | otherwise = text ("rts_get" ++ ffiType arg_ty) <> parens arg_val cfun_make_ret ret_val | res_ty `eqType` unitTy = ret_val | otherwise = @@ -543,7 +563,11 @@ importCStub sync cfun_name arg_tys res_ty js_src = CStub c_doc [] [] | res_ty `eqType` unitTy = text "void" | otherwise = text "HaskellObj" cfun_arg_list = - [text "HaskellObj" <+> char 'a' <> int n | n <- [1 .. length arg_tys]] + [ text (if isByteArrayPrimTy arg_ty then "HsPtr" else "HaskellObj") + <+> char 'a' + <> int n + | (arg_ty, n) <- zip arg_tys [1 ..] + ] cfun_args = case cfun_arg_list of [] -> text "void" _ -> hsep $ punctuate comma cfun_arg_list @@ -746,8 +770,18 @@ lookupGhcInternalTyCon m t = do n <- lookupOrig (mkGhcInternalModule m) (mkTcOcc t) dsLookupTyCon n +isByteArrayPrimTy :: Type -> Bool +isByteArrayPrimTy ty + | Just tc <- tyConAppTyCon_maybe ty, + tc == byteArrayPrimTyCon || tc == mutableByteArrayPrimTyCon = + True + | otherwise = + False + ffiType :: Type -> String -ffiType = occNameString . getOccName . fst . splitTyConApp +ffiType ty + | isByteArrayPrimTy ty = "Ptr" + | otherwise = occNameString $ getOccName $ tyConAppTyCon ty commonCDecls :: SDoc commonCDecls = ===================================== compiler/GHC/Parser/String.hs ===================================== @@ -19,6 +19,7 @@ import Data.Char (chr, ord) import qualified Data.Foldable1 as Foldable1 import qualified Data.List.NonEmpty as NonEmpty import Data.Maybe (listToMaybe, mapMaybe) +import GHC.Data.OrdList (fromOL, nilOL, snocOL) import GHC.Data.StringBuffer (StringBuffer) import qualified GHC.Data.StringBuffer as StringBuffer import GHC.Parser.CharClass ( @@ -167,16 +168,16 @@ collapseGaps = go [] -> panic "gap unexpectedly ended" resolveEscapes :: HasChar c => [c] -> Either (c, LexErr) [c] -resolveEscapes = go dlistEmpty +resolveEscapes = go nilOL where go !acc = \case - [] -> pure $ dlistToList acc + [] -> pure $ fromOL acc Char '\\' : Char '&' : cs -> go acc cs backslash@(Char '\\') : cs -> case resolveEscapeChar cs of - Right (esc, cs') -> go (acc `dlistSnoc` setChar esc backslash) cs' + Right (esc, cs') -> go (acc `snocOL` setChar esc backslash) cs' Left (c, e) -> Left (c, e) - c : cs -> go (acc `dlistSnoc` c) cs + c : cs -> go (acc `snocOL` c) cs -- ----------------------------------------------------------------------------- -- Escape characters @@ -420,17 +421,3 @@ It's more precisely defined with the following algorithm: * Lines with only whitespace characters 3. Calculate the longest prefix of whitespace shared by all lines in the remaining list -} - --- ----------------------------------------------------------------------------- --- DList - -newtype DList a = DList ([a] -> [a]) - -dlistEmpty :: DList a -dlistEmpty = DList id - -dlistToList :: DList a -> [a] -dlistToList (DList f) = f [] - -dlistSnoc :: DList a -> a -> DList a -dlistSnoc (DList f) x = DList (f . (x :)) ===================================== compiler/GHC/StgToCmm/InfoTableProv.hs ===================================== @@ -11,6 +11,7 @@ import GHC.IO (unsafePerformIO) #endif import Data.Char +import Data.Foldable import GHC.Prelude import GHC.Platform import GHC.Types.SrcLoc (pprUserRealSpan, srcSpanFile) @@ -18,6 +19,7 @@ import GHC.Types.Unique.DSM import GHC.Unit.Module import GHC.Utils.Outputable import GHC.Data.FastString (fastStringToShortText, unpackFS, LexicalFastString(..)) +import GHC.Data.OrdList (OrdList, nilOL, snocOL) import GHC.Cmm import GHC.Cmm.CLabel @@ -286,7 +288,7 @@ data CgInfoProvEnt = CgInfoProvEnt , ipeSrcSpan :: !StrTabOffset } -data StringTable = StringTable { stStrings :: DList ShortText +data StringTable = StringTable { stStrings :: !(OrdList ShortText) , stLength :: !Int , stLookup :: !(M.Map ShortText StrTabOffset) } @@ -295,7 +297,7 @@ type StrTabOffset = Word32 emptyStringTable :: StringTable emptyStringTable = - StringTable { stStrings = emptyDList + StringTable { stStrings = nilOL , stLength = 0 , stLookup = M.empty } @@ -303,7 +305,7 @@ emptyStringTable = getStringTableStrings :: StringTable -> BS.ByteString getStringTableStrings st = BSL.toStrict $ BSB.toLazyByteString - $ foldMap f $ dlistToList (stStrings st) + $ foldMap' f $ stStrings st where f x = BSB.shortByteString (ST.contents x) `mappend` BSB.word8 0 @@ -312,7 +314,7 @@ lookupStringTable str = state $ \st -> case M.lookup str (stLookup st) of Just off -> (off, st) Nothing -> - let !st' = st { stStrings = stStrings st `snoc` str + let !st' = st { stStrings = stStrings st `snocOL` str , stLength = stLength st + ST.byteLength str + 1 , stLookup = M.insert str res (stLookup st) } @@ -359,14 +361,3 @@ foreign import ccall unsafe "ZSTD_compressBound" defaultCompressionLevel :: Int defaultCompressionLevel = 3 - -newtype DList a = DList ([a] -> [a]) - -emptyDList :: DList a -emptyDList = DList id - -snoc :: DList a -> a -> DList a -snoc (DList f) x = DList (f . (x:)) - -dlistToList :: DList a -> [a] -dlistToList (DList f) = f [] ===================================== docs/users_guide/wasm.rst ===================================== @@ -265,7 +265,7 @@ backend’s JavaScript FFI, which we’ll now abbreviate as JSFFI. Marshalable types and ``JSVal`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -JSFFI supports all boxed marshalable foreign types in C FFI: +JSFFI supports all lifted marshalable foreign types in C FFI: - ``Bool`` - ``Char`` @@ -298,8 +298,14 @@ types in JSFFI. Some caveats to keep in mind: results in type errors, so keep this in mind. As for ``Int`` / ``Word``, they are 32-bit since the GHC wasm backend is based on ``wasm32`` . -- JSFFI doesn’t support unboxed foreign types like ``Int#``, - ``ByteArray#``, etc, even when ``UnliftedFFITypes`` is enabled. +- JSFFI doesn’t support unboxed foreign types like ``Int#``, even + when ``UnliftedFFITypes`` is enabled. The only supported unlifted + types are ``ByteArray#`` and ``MutableByteArray#``, they may only + be used as JSFFI import argument types, with the same semantics in + C FFI: the pointer to the payload is passed to JavaScript. Be + careful and avoid calling back into Haskell in such cases, + otherwise GC may occur and the pointer may be invalidated if it's + unpinned! In addition to the above types, JSFFI supports the ``JSVal`` type and its ``newtype``\ s as argument/result types. ``JSVal`` is defined in ===================================== hadrian/doc/flavours.md ===================================== @@ -249,10 +249,6 @@ The supported transformers are listed below: <tr> <td><code>profiled_ghc</code></td> <td>Build the GHC executable with cost-centre profiling support. - It is recommended that you use this in conjunction with `no_dynamic_ghc` since - GHC does not support loading of profiled libraries with the - dynamic linker. You should use a flavour that builds profiling libs and rts, - i.e. not <code>quick</code>. <br> This flag adds cost centres with the -fprof-late flag.</td> </tr> <tr> @@ -274,6 +270,10 @@ The supported transformers are listed below: <td><code>text_simdutf</code></td> <td>Enable building the <code>text</code> package with <code>simdutf</code> support.</td> </tr> + <tr> + <td><code>with_profiled_libs</code></td> + <td>Enables building of stage1+ libraries and the RTS in profiled build ways (the opposite of <code>no_profiled_libs</code>).</td> + </tr> <tr> <td><code>no_profiled_libs</code></td> <td>Disables building of libraries in profiled build ways.</td> ===================================== hadrian/src/Flavour.hs ===================================== @@ -15,6 +15,7 @@ module Flavour , enableProfiledGhc , disableDynamicGhcPrograms , disableDynamicLibs + , enableProfiledLibs , disableProfiledLibs , enableLinting , enableHaddock @@ -62,6 +63,7 @@ flavourTransformers = M.fromList , "no_dynamic_libs" =: disableDynamicLibs , "native_bignum" =: useNativeBignum , "text_simdutf" =: enableTextWithSIMDUTF + , "with_profiled_libs" =: enableProfiledLibs , "no_profiled_libs" =: disableProfiledLibs , "omit_pragmas" =: omitPragmas , "ipe" =: enableIPE @@ -169,6 +171,7 @@ enableDebugInfo :: Flavour -> Flavour enableDebugInfo = addArgs $ notStage0 ? mconcat [ builder (Ghc CompileHs) ? pure ["-g3"] , builder (Ghc CompileCWithGhc) ? pure ["-optc-g3"] + , builder (Ghc CompileCppWithGhc) ? pure ["-optcxx-g3"] , builder (Cc CompileC) ? arg "-g3" , builder (Cabal Setup) ? arg "--disable-library-stripping" , builder (Cabal Setup) ? arg "--disable-executable-stripping" @@ -307,29 +310,11 @@ enableUBSan = viaLlvmBackend :: Flavour -> Flavour viaLlvmBackend = addArgs $ notStage0 ? builder Ghc ? arg "-fllvm" --- | Build the GHC executable with profiling enabled in stages 2 and later. It --- is also recommended that you use this with @'dynamicGhcPrograms' = False@ --- since GHC does not support loading of profiled libraries with the --- dynamically-linker. +-- | Build the GHC executable with profiling enabled in stages 2 and +-- later. enableProfiledGhc :: Flavour -> Flavour enableProfiledGhc flavour = - enableLateCCS flavour - { rtsWays = do - ws <- rtsWays flavour - mconcat - [ pure ws - , buildingCompilerStage' (>= Stage2) ? pure (foldMap profiled_ways ws) - ] - , libraryWays = mconcat - [ libraryWays flavour - , buildingCompilerStage' (>= Stage2) ? pure (Set.singleton profiling) - ] - , ghcProfiled = (>= Stage2) - } - where - profiled_ways w - | wayUnit Dynamic w = Set.empty - | otherwise = Set.singleton (w <> profiling) + enableLateCCS $ enableProfiledLibs flavour { ghcProfiled = (>= Stage2) } -- | Disable 'dynamicGhcPrograms'. disableDynamicGhcPrograms :: Flavour -> Flavour @@ -346,6 +331,20 @@ disableDynamicLibs flavour = prune :: Ways -> Ways prune = fmap $ Set.filter (not . wayUnit Dynamic) +-- | Build libraries and the RTS in profiled ways (opposite of +-- 'disableProfiledLibs'). +enableProfiledLibs :: Flavour -> Flavour +enableProfiledLibs flavour = + flavour + { libraryWays = addProfilingWays $ libraryWays flavour, + rtsWays = addProfilingWays $ rtsWays flavour + } + where + addProfilingWays :: Ways -> Ways + addProfilingWays ways = do + ws <- ways + buildProfiled <- notStage0 + pure $ if buildProfiled then ws <> Set.map (<> profiling) ws else ws -- | Don't build libraries in profiled 'Way's. disableProfiledLibs :: Flavour -> Flavour ===================================== hadrian/src/Settings/Packages.hs ===================================== @@ -351,7 +351,7 @@ rtsPackageArgs = package rts ? do , Debug `wayUnit` way ? pure [ "-DDEBUG" , "-fno-omit-frame-pointer" , "-g3" - , "-O0" ] + , "-Og" ] -- Set the namespace for the rts fs functions , arg $ "-DFS_NAMESPACE=rts" ===================================== libraries/ghc-internal/src/GHC/Internal/IO/Handle.hs ===================================== @@ -480,7 +480,7 @@ hIsOpen handle = SemiClosedHandle -> return False _ -> return True --- | @'hIsOpen' hdl@ returns whether the handle is closed. +-- | @'hIsClosed' hdl@ returns whether the handle is closed. -- If the 'haType' of @hdl@ is 'ClosedHandle' this returns 'True' -- and 'False' otherwise. hIsClosed :: Handle -> IO Bool ===================================== rts/linker/InitFini.c ===================================== @@ -75,7 +75,7 @@ static void sortInitFiniList(struct InitFiniList **slist, enum SortOrder order) while (*last != NULL && (*last)->next != NULL) { struct InitFiniList *s0 = *last; struct InitFiniList *s1 = s0->next; - bool flip; + bool flip = false; switch (order) { case INCREASING: flip = s0->priority > s1->priority; break; case DECREASING: flip = s0->priority < s1->priority; break; ===================================== rts/sm/Sanity.c ===================================== @@ -692,7 +692,7 @@ checkCompactObjects(bdescr *bd) ASSERT((W_)str == (W_)block + sizeof(StgCompactNFDataBlock)); StgWord totalW = 0; - StgCompactNFDataBlock *last; + StgCompactNFDataBlock *last = block; for ( ; block ; block = block->next) { last = block; ASSERT(block->owner == str); ===================================== testsuite/tests/jsffi/all.T ===================================== @@ -25,4 +25,6 @@ test('jsffion', [], compile_and_run, ['-optl-Wl,--export=main']) test('jsffisleep', [], compile_and_run, ['-optl-Wl,--export=testWouldBlock,--export=testLazySleep,--export=testThreadDelay,--export=testInterruptingSleep']) +test('bytearrayarg', [], compile_and_run, ['-optl-Wl,--export=main']) + test('textconv', [], compile_and_run, ['-optl-Wl,--export=main']) ===================================== testsuite/tests/jsffi/bytearrayarg.hs ===================================== @@ -0,0 +1,39 @@ +{-# LANGUAGE MagicHash #-} +{-# LANGUAGE UnboxedTuples #-} +{-# LANGUAGE UnliftedFFITypes #-} + +module Test where + +import GHC.Exts +import GHC.IO +import GHC.Word (Word8(W8#)) + +foreign import javascript unsafe "(() => { const u8 = new Uint8Array(__exports.memory.buffer, $1, 4); return (u8[0] === 0x12 && u8[1] === 0x34 && u8[2] === 0x56 && u8[3] === 0x78) ? 1 : 0; })()" + js_check_mba :: MutableByteArray# RealWorld -> IO Int + +foreign import javascript unsafe "(() => { const u8 = new Uint8Array(__exports.memory.buffer, $1, 4); return (u8[0] === 0x12 && u8[1] === 0x34 && u8[2] === 0x56 && u8[3] === 0x78) ? 1 : 0; })()" + js_check_ba :: ByteArray# -> IO Int + +foreign export javascript "main" + main :: IO () + +main :: IO () +main = + IO $ \s0 -> + case newPinnedByteArray# 4# s0 of + (# s1, mba# #) -> + case (0x12 :: Word8) of { W8# b0# -> + case (0x34 :: Word8) of { W8# b1# -> + case (0x56 :: Word8) of { W8# b2# -> + case (0x78 :: Word8) of { W8# b3# -> + let s2 = writeWord8Array# mba# 0# b0# s1 + s3 = writeWord8Array# mba# 1# b1# s2 + s4 = writeWord8Array# mba# 2# b2# s3 + s5 = writeWord8Array# mba# 3# b3# s4 + in case unIO (js_check_mba mba#) s5 of + (# s6, ok_mba #) -> case unsafeFreezeByteArray# mba# s6 of + (# s7, ba# #) -> case unIO (js_check_ba ba#) s7 of + (# s8, ok_ba #) -> case unIO (print ok_mba) s8 of + (# s9, _ #) -> case unIO (print ok_ba) s9 of + (# s10, _ #) -> (# s10, () #) + }}}} ===================================== testsuite/tests/jsffi/bytearrayarg.mjs ===================================== @@ -0,0 +1,4 @@ +export default async (__exports) => { + await __exports.main(); + process.exit(); +} ===================================== testsuite/tests/jsffi/bytearrayarg.stdout ===================================== @@ -0,0 +1,2 @@ +1 +1 ===================================== testsuite/tests/perf/should_run/all.T ===================================== @@ -420,6 +420,7 @@ test('T17949', [collect_stats('bytes allocated', 1), only_ways(['normal'])], com test('ByteCodeAsm', [ extra_run_opts('"' + config.libdir + '"') , js_broken(22261) + , when(arch('wasm32'), run_timeout_multiplier(10)) , collect_stats('bytes allocated', 10), ], compile_and_run, View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/aea3ad2d6e58f4d56ee5318bff1ead2... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/aea3ad2d6e58f4d56ee5318bff1ead2... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
Cheng Shao (@TerrorJack)