module LlvmCodeGen.Data (
genLlvmData, resolveLlvmDatas, resolveLlvmData
) where
#include "HsVersions.h"
import Llvm
import LlvmCodeGen.Base
import BlockId
import CLabel
import Cmm
import FastString
import qualified Outputable
import Data.Maybe
structStr :: LMString
structStr = fsLit "_struct"
genLlvmData :: (Section, [CmmStatic]) -> LlvmUnresData
genLlvmData (sec, CmmDataLabel lbl:xs) =
let static = map genData xs
label = strCLabel_llvm 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)
genLlvmData _ = panic "genLlvmData: CmmData section doesn't start with label!"
resolveLlvmDatas :: LlvmEnv -> [LlvmUnresData] -> [LlvmData]
-> (LlvmEnv, [LlvmData])
resolveLlvmDatas env [] ldata
= (env, ldata)
resolveLlvmDatas env (udata : rest) ldata
= let (env', ndata) = resolveLlvmData env udata
in resolveLlvmDatas env' rest (ldata ++ [ndata])
resolveLlvmData :: LlvmEnv -> LlvmUnresData -> (LlvmEnv, LlvmData)
resolveLlvmData env (lbl, sec, alias, unres) =
let (env', static, refs) = resDatas env unres ([], [])
refs' = catMaybes refs
struct = Just $ LMStaticStruc static alias
label = strCLabel_llvm lbl
link = if (externallyVisibleCLabel lbl)
then ExternallyVisible else Internal
const = isSecConstant sec
glob = LMGlobalVar label alias link Nothing Nothing const
in (env', (refs' ++ [(glob, struct)], [alias]))
isSecConstant :: Section -> Bool
isSecConstant Text = True
isSecConstant Data = False
isSecConstant ReadOnlyData = True
isSecConstant RelocatableReadOnlyData = True
isSecConstant UninitialisedData = False
isSecConstant ReadOnlyData16 = True
isSecConstant (OtherSection _) = False
resDatas :: LlvmEnv -> [UnresStatic] -> ([LlvmStatic], [Maybe LMGlobal])
-> (LlvmEnv, [LlvmStatic], [Maybe LMGlobal])
resDatas env [] (stat, glob)
= (env, stat, 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, [Maybe LMGlobal])
resData env (Right stat) = (env, stat, [Nothing])
resData env (Left cmm@(CmmLabel l)) =
let label = strCLabel_llvm 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, [Just glob])
Just ty' ->
let var = LMGlobalVar label (LMPointer ty')
ExternallyVisible Nothing Nothing False
ptr = LMStaticPointer var
in (env, LMPtoI ptr lmty, [Nothing])
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
genData (CmmAlign _)
= panic "genData: Can't handle CmmAlign!"
genData (CmmDataLabel _)
= panic "genData: Can't handle data labels not at top of data!"
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