module LLVM.DataLayout (
dataLayoutToString,
parseDataLayout
) where
import LLVM.Prelude
import Control.Monad.Trans.Except
import qualified Data.List as List
import qualified Data.Map as Map
import qualified Data.Set as Set
import Text.ParserCombinators.Parsec hiding (many)
import LLVM.AST.DataLayout
import LLVM.AST.AddrSpace
dataLayoutToString :: DataLayout -> String
dataLayoutToString dl =
let sAlignmentInfo :: AlignmentInfo -> String
sAlignmentInfo (AlignmentInfo abi pref) =
show abi ++ case pref of
Just pref | pref /= abi -> ":" ++ show pref
_ -> ""
sTriple :: (Word32, AlignmentInfo) -> String
sTriple (s, ai) = show s ++ ":" ++ sAlignmentInfo ai
atChar at = case at of
IntegerAlign -> "i"
VectorAlign -> "v"
FloatAlign -> "f"
manglingChar m = case m of
ELFMangling -> "e"
MIPSMangling -> "m"
MachOMangling -> "o"
WindowsCOFFMangling -> "w"
oneOpt f accessor = maybe [] ((:[]) . f) (accessor dl)
defDl = defaultDataLayout BigEndian
nonDef :: Eq a => (DataLayout -> [a]) -> [a]
nonDef f = (f dl) List.\\ (f defDl)
in
List.intercalate "-" (
[case endianness dl of BigEndian -> "E"; LittleEndian -> "e"]
++
(oneOpt (("m:" ++) . manglingChar) mangling)
++
[
"p" ++ (if a == 0 then "" else show a) ++ ":" ++ sTriple t
| (AddrSpace a, t) <- nonDef (Map.toList . pointerLayouts)
] ++ [
atChar at ++ sTriple (s, ai)
| ((at, s), ai) <- nonDef (Map.toList . typeLayouts)
] ++ [
"a:" ++ sAlignmentInfo ai | ai <- nonDef (pure . aggregateLayout)
] ++
(oneOpt (("n"++) . (List.intercalate ":") . (map show) . Set.toList) nativeSizes)
++
(oneOpt (("S"++) . show) stackAlignment)
)
parseDataLayout :: Endianness -> String -> Except String (Maybe DataLayout)
parseDataLayout _ "" = pure Nothing
parseDataLayout defaultEndianness s =
let
num :: Parser Word32
num = read <$> many1 digit
alignmentInfo :: Parser AlignmentInfo
alignmentInfo = do
abi <- num
pref <- optionMaybe $ char ':' *> num
pure $ AlignmentInfo abi pref
triple :: Parser (Word32, AlignmentInfo)
triple = do
s <- num
ai <- char ':' *> alignmentInfo
pure (s, ai)
parseSpec :: Parser (DataLayout -> DataLayout)
parseSpec = choice [
char 'e' *> pure (\dl -> dl { endianness = LittleEndian }),
char 'E' *> pure (\dl -> dl { endianness = BigEndian }),
do
m <- char 'm' *> char ':' *> choice [
char 'e' *> pure ELFMangling,
char 'm' *> pure MIPSMangling,
char 'o' *> pure MachOMangling,
char 'w' *> pure WindowsCOFFMangling
]
pure $ \dl -> dl { mangling = Just m },
do
n <- char 'S' *> num
pure $ \dl -> dl { stackAlignment = Just n },
do
a <- char 'p' *> (AddrSpace <$> option 0 (read <$> many1 digit))
t <- char ':' *> triple
pure $ \dl -> dl { pointerLayouts = Map.insert a t (pointerLayouts dl) },
do
void $ char 's' *> triple
pure id,
do
at <- choice [
char 'i' *> pure IntegerAlign,
char 'v' *> pure VectorAlign,
char 'f' *> pure FloatAlign
]
(sz, ai) <- triple
pure $ \dl -> dl { typeLayouts = Map.insert (at, sz) ai (typeLayouts dl) },
do
ai <- char 'a' *> char ':' *> alignmentInfo
pure $ \dl -> dl { aggregateLayout = ai },
do
ns <- char 'n' *> num `sepBy` (char ':')
pure $ \dl -> dl { nativeSizes = Just (Set.fromList ns) }
]
in
case parse (parseSpec `sepBy` (char '-')) "" s of
Left _ -> throwE $ "ill formed data layout: " ++ show s
Right fs -> pure . Just $ foldr ($) (defaultDataLayout defaultEndianness) fs