ddc-core-llvm-0.4.2.1: DDC/Core/Llvm/Convert/Super.hs
{-# LANGUAGE TypeFamilies #-}
module DDC.Core.Llvm.Convert.Super
(convertSuper)
where
import DDC.Core.Llvm.Convert.Exp
import DDC.Core.Llvm.Convert.Type
import DDC.Core.Llvm.Convert.Context
import DDC.Core.Llvm.Convert.Base
import DDC.Llvm.Syntax
import DDC.Core.Salt.Platform
import DDC.Type.Predicates
import DDC.Base.Pretty hiding (align)
import qualified DDC.Core.Llvm.Metadata.Tbaa as Tbaa
import qualified DDC.Core.Salt as A
import qualified DDC.Core.Salt.Convert as A
import qualified DDC.Core.Exp.Generic.Compounds as A
import qualified DDC.Core.Module as C
import qualified DDC.Core.Exp as C
import qualified Data.Set as Set
import qualified Data.Sequence as Seq
import qualified Data.Foldable as Seq
-- | Convert a top-level supercombinator to a LLVM function.
-- Region variables are completely stripped out.
convertSuper
:: Context
-> A.Bind -- ^ Bind of the top-level super.
-> A.Exp -- ^ Super body.
-> ConvertM (Function, [MDecl])
convertSuper ctx (C.BName nSuper tSuper) x
| Just (asParam, xBody) <- A.takeXAbs x
= do
let pp = contextPlatform ctx
let mm = contextModule ctx
let kenv = contextKindEnv ctx
-- Collect names of exported values.
let nsExports = Set.fromList $ map fst $ C.moduleExportValues mm
-- Sanitise the super name so we can use it as a symbol
-- in the object code.
let Just nSuper' = A.seaNameOfSuper
(lookup nSuper (C.moduleImportValues mm))
(lookup nSuper (C.moduleExportValues mm))
nSuper
-- Add super parameters to the context.
(ctx', vsParamValue')
<- bindLocalAs ctx $ eraseWitBinds $ asParam
-- Add super meta-data to the context.
mdsup <- Tbaa.deriveMD (renderPlain nSuper') x
let ctx'' = ctx' { contextMDSuper = mdsup }
-- Convert function body to basic blocks.
label <- newUniqueLabel "entry"
blocks <- convertBody ctx'' ExpTop Seq.empty label Seq.empty xBody
-- Split off the argument and result types of the super.
(tsParam, tResult)
<- convertSuperType pp kenv tSuper
-- Make parameter binders.
let align = AlignBytes (platformAlignBytes pp)
-- Declaration of the super.
let decl
= FunctionDecl
{ declName = renderPlain nSuper'
-- Set internal linkage for non-exported functions so that they
-- they won't conflict with functions of the same name that
-- might be defined in other modules.
, declLinkage = if Set.member nSuper nsExports
then External
else Internal
-- ISSUE #266: Tailcall optimisation doesn't work for exported functions.
-- Using fast calls for non-exported functions enables the
-- LLVM tailcall optimisation. We can't enable this for exported
-- functions as well because we don't distinguish between DDC
-- generated functions and functions from the C libararies in
-- our import specifications. We need a proper FFI system so that
-- we can get tailcalls for exported functions as well.
, declCallConv = if Set.member nSuper nsExports
then CC_Ccc
else CC_Fastcc
, declReturnType = tResult
, declParamListType = FixedArgs
, declParams = [Param t [] | t <- tsParam]
, declAlign = align }
let Just ssParamValues
= sequence
$ map (\v -> case v of
(Var (NameLocal s) _) -> Just s
_ -> Nothing)
$ vsParamValue'
-- Build the function.
return ( Function
{ funDecl = decl
, funParams = ssParamValues
, funAttrs = []
, funSection = SectionAuto
, funBlocks = Seq.toList blocks }
, Tbaa.decls mdsup )
convertSuper _ b x
= throw $ ErrorInvalidSuper b x
---------------------------------------------------------------------------------------------------
-- | Erase witness bindings
eraseWitBinds :: [A.GAbs A.Name] -> [A.GAbs A.Name]
eraseWitBinds
= let
isBindWit (A.ALAM _) = False
isBindWit (A.ALam b)
= case b of
C.BName _ t | isWitnessType t -> True
_ -> False
in filter (not . isBindWit)