module LlvmCodeGen.Data (
genLlvmData, resolveLlvmDatas, resolveLlvmData
) where
#include "HsVersions.h"
import Llvm
import LlvmCodeGen.Base
import BlockId
import CLabel
import OldCmm
import FastString
import qualified Outputable
import Data.List (foldl')
structStr :: LMString
structStr = fsLit "_struct"
genLlvmData :: LlvmEnv -> (Section, CmmStatics) -> LlvmUnresData
genLlvmData env (sec, Statics lbl xs) =
let static = map genData xs
label = strCLabel_llvm env lbl
types = map getStatTypes static
getStatTypes (Left x) = cmmToLlvmType $ cmmLitType x
getStatTypes (Right x) = getStatType x
strucTy = LMStruct types
alias = LMAlias ((label `appendFS` structStr), strucTy)
in (lbl, sec, alias, static)
resolveLlvmDatas :: LlvmEnv -> [LlvmUnresData] -> (LlvmEnv, [LlvmData])
resolveLlvmDatas env ldata
= foldl' res (env, []) ldata
where res (e, xs) ll =
let (e', nd) = resolveLlvmData e ll
in (e', nd:xs)
resolveLlvmData :: LlvmEnv -> LlvmUnresData -> (LlvmEnv, LlvmData)
resolveLlvmData env (lbl, sec, alias, unres) =
let (env', static, refs) = resDatas env unres ([], [])
struct = Just $ LMStaticStruc static alias
label = strCLabel_llvm env lbl
link = if (externallyVisibleCLabel lbl)
then ExternallyVisible else Internal
const = isSecConstant sec
glob = LMGlobalVar label alias link Nothing Nothing const
in (env', ((glob,struct):refs, [alias]))
isSecConstant :: Section -> Bool
isSecConstant Text = True
isSecConstant ReadOnlyData = True
isSecConstant RelocatableReadOnlyData = True
isSecConstant ReadOnlyData16 = True
isSecConstant Data = False
isSecConstant UninitialisedData = False
isSecConstant (OtherSection _) = False
resDatas :: LlvmEnv -> [UnresStatic] -> ([LlvmStatic], [LMGlobal])
-> (LlvmEnv, [LlvmStatic], [LMGlobal])
resDatas env [] (stats, glob)
= (env, stats, glob)
resDatas env (cmm:rest) (stats, globs)
= let (env', nstat, nglob) = resData env cmm
in resDatas env' rest (stats ++ [nstat], globs ++ nglob)
resData :: LlvmEnv -> UnresStatic -> (LlvmEnv, LlvmStatic, [LMGlobal])
resData env (Right stat) = (env, stat, [])
resData env (Left cmm@(CmmLabel l)) =
let label = strCLabel_llvm env l
ty = funLookup label env
lmty = cmmToLlvmType $ cmmLitType cmm
in case ty of
Nothing ->
let glob@(var, _) = genStringLabelRef label
env' = funInsert label (pLower $ getVarType var) env
ptr = LMStaticPointer var
in (env', LMPtoI ptr lmty, [glob])
Just ty' ->
let var = LMGlobalVar label (LMPointer ty')
ExternallyVisible Nothing Nothing False
ptr = LMStaticPointer var
in (env, LMPtoI ptr lmty, [])
resData env (Left (CmmLabelOff label off)) =
let (env', var, glob) = resData env (Left (CmmLabel label))
offset = LMStaticLit $ LMIntLit (toInteger off) llvmWord
in (env', LMAdd var offset, glob)
resData env (Left (CmmLabelDiffOff l1 l2 off)) =
let (env1, var1, glob1) = resData env (Left (CmmLabel l1))
(env2, var2, glob2) = resData env1 (Left (CmmLabel l2))
var = LMSub var1 var2
offset = LMStaticLit $ LMIntLit (toInteger off) llvmWord
in (env2, LMAdd var offset, glob1 ++ glob2)
resData _ _ = panic "resData: Non CLabel expr as left type!"
genData :: CmmStatic -> UnresStatic
genData (CmmString str) =
let v = map (\x -> LMStaticLit $ LMIntLit (fromIntegral x) i8) str
ve = v ++ [LMStaticLit $ LMIntLit 0 i8]
in Right $ LMStaticArray ve (LMArray (length ve) i8)
genData (CmmUninitialised bytes)
= Right $ LMUninitType (LMArray bytes i8)
genData (CmmStaticLit lit)
= genStaticLit lit
genStaticLit :: CmmLit -> UnresStatic
genStaticLit (CmmInt i w)
= Right $ LMStaticLit (LMIntLit i (LMInt $ widthInBits w))
genStaticLit (CmmFloat r w)
= Right $ LMStaticLit (LMFloatLit (fromRational r) (widthToLlvmFloat w))
genStaticLit c@(CmmLabel _ ) = Left $ c
genStaticLit c@(CmmLabelOff _ _) = Left $ c
genStaticLit c@(CmmLabelDiffOff _ _ _) = Left $ c
genStaticLit (CmmBlock b) = Left $ CmmLabel $ infoTblLbl b
genStaticLit (CmmHighStackMark)
= panic "genStaticLit: CmmHighStackMark unsupported!"
panic :: String -> a
panic s = Outputable.panic $ "LlvmCodeGen.Data." ++ s