diff options
author | Ben Gamari <ben@smart-cactus.org> | 2022-02-08 19:04:41 -0500 |
---|---|---|
committer | Matthew Pickering <matthewtpickering@gmail.com> | 2022-04-01 10:34:39 +0100 |
commit | 5beeff46972b8b52e9f2572fff8b1ad9ace38cd8 (patch) | |
tree | f3fb4084554f8de4b2f9d8b0b6144cbc9ad1f342 /compiler/GHC/CmmToLlvm | |
parent | 6793a20fe0cd1f04dabad46b87e86018abf73e54 (diff) | |
download | haskell-5beeff46972b8b52e9f2572fff8b1ad9ace38cd8.tar.gz |
Refactor handling of global initializers
GHC uses global initializers for a number of things including
cost-center registration, info-table provenance registration, and setup
of foreign exports. Previously, the global initializer arrays which
referenced these initializers would live in the object file of the C
stub, which would then be merged into the main object file of the
module.
Unfortunately, this approach is no longer tenable with the move to
Clang/LLVM on Windows (see #21019). Specifically, lld's PE backend does
not support object merging (that is, the -r flag). Instead we are now
rather packaging a module's object files into a static library. However,
this is problematic in the case of initializers as there are no
references to the C stub object in the archive, meaning that the linker
may drop the object from the final link.
This patch refactors our handling of global initializers to instead
place initializer arrays within the object file of the module to which
they belong. We do this by introducing a Cmm data declaration containing
the initializer array in the module's Cmm stream. While the initializer
functions themselves remain in separate C stub objects, the reference
from the module's object ensures that they are not dropped from the
final link.
In service of #21068.
Diffstat (limited to 'compiler/GHC/CmmToLlvm')
-rw-r--r-- | compiler/GHC/CmmToLlvm/Data.hs | 45 |
1 files changed, 44 insertions, 1 deletions
diff --git a/compiler/GHC/CmmToLlvm/Data.hs b/compiler/GHC/CmmToLlvm/Data.hs index 0e5679887d..edab12a6ef 100644 --- a/compiler/GHC/CmmToLlvm/Data.hs +++ b/compiler/GHC/CmmToLlvm/Data.hs @@ -15,6 +15,7 @@ import GHC.CmmToLlvm.Config import GHC.Cmm.BlockId import GHC.Cmm.CLabel +import GHC.Cmm.InitFini import GHC.Cmm import GHC.Platform @@ -65,6 +66,14 @@ genLlvmData (_, CmmStaticsRaw alias [CmmStaticLit (CmmLabel lbl), CmmStaticLit i pure ([LMGlobal aliasDef $ Just orig], [tyAlias]) +-- See Note [Initializers and finalizers in Cmm] in GHC.Cmm.InitFini. +genLlvmData (sect, statics) + | Just (initOrFini, clbls) <- isInitOrFiniArray (CmmData sect statics) + = let var = case initOrFini of + IsInitArray -> fsLit "llvm.global_ctors" + IsFiniArray -> fsLit "llvm.global_dtors" + in genGlobalLabelArray var clbls + genLlvmData (sec, CmmStaticsRaw lbl xs) = do label <- strCLabel_llvm lbl static <- mapM genData xs @@ -88,6 +97,37 @@ genLlvmData (sec, CmmStaticsRaw lbl xs) = do return ([globDef], [tyAlias]) +-- | Produce an initializer or finalizer array declaration. +-- See Note [Initializers and finalizers in Cmm] in GHC.Cmm.InitFini for +-- details. +genGlobalLabelArray :: FastString -> [CLabel] -> LlvmM LlvmData +genGlobalLabelArray var_nm clbls = do + lbls <- mapM strCLabel_llvm clbls + decls <- mapM mkFunDecl lbls + let entries = map toArrayEntry lbls + static = LMStaticArray entries arr_ty + arr = LMGlobal arr_var (Just static) + return ([arr], decls) + where + mkFunDecl :: LMString -> LlvmM LlvmType + mkFunDecl fn_lbl = do + let fn_ty = mkFunTy fn_lbl + funInsert fn_lbl fn_ty + return (fn_ty) + + toArrayEntry :: LMString -> LlvmStatic + toArrayEntry fn_lbl = + let fn_var = LMGlobalVar fn_lbl (LMPointer $ mkFunTy fn_lbl) Internal Nothing Nothing Global + fn = LMStaticPointer fn_var + null = LMStaticLit (LMNullLit i8Ptr) + prio = LMStaticLit $ LMIntLit 0xffff i32 + in LMStaticStrucU [prio, fn, null] entry_ty + + arr_var = LMGlobalVar var_nm arr_ty Internal Nothing Nothing Global + mkFunTy lbl = LMFunction $ LlvmFunctionDecl lbl ExternallyVisible CC_Ccc LMVoid FixedArgs [] Nothing + entry_ty = LMStructU [i32, LMPointer $ mkFunTy $ fsLit "placeholder", LMPointer i8] + arr_ty = LMArray (length clbls) entry_ty + -- | Format the section type part of a Cmm Section llvmSectionType :: Platform -> SectionType -> FastString llvmSectionType p t = case t of @@ -106,7 +146,10 @@ llvmSectionType p t = case t of CString -> case platformOS p of OSMinGW32 -> fsLit ".rdata$str" _ -> fsLit ".rodata.str" - (OtherSection _) -> panic "llvmSectionType: unknown section type" + + InitArray -> panic "llvmSectionType: InitArray" + FiniArray -> panic "llvmSectionType: FiniArray" + OtherSection _ -> panic "llvmSectionType: unknown section type" -- | Format a Cmm Section into a LLVM section name llvmSection :: Section -> LlvmM LMSection |