{-# OPTIONS_GHC -fno-warn-orphans #-} -- | Define the unparser for our LLVM IR module Data.LLVM.Internal.Printers ( printMetadata, printAsm, printType, printValue ) where import Data.GraphViz import Data.Int import Data.List ( intersperse ) import Data.Monoid import Data.Text ( Text, unpack ) import Data.Text.Lazy ( toStrict ) import Data.Text.Lazy.Builder import qualified Text.PrettyPrint as PP import Text.PrettyPrint.GenericPretty import Data.LLVM.Types.Attributes import Data.LLVM.Types.Identifiers import Data.LLVM.Types.Referential -- TODO List -- -- * Pretty up the DataLayout -- * Print out named type definitions -- * Make the function type printing as flexible as the official -- version showUntypedMDName :: Metadata -> Builder showUntypedMDName = fromString . ("!"++) . show . metaValueUniqueId showMDName :: Metadata -> Builder showMDName = fromString . ("metadata !"++) . show . metaValueUniqueId showMDString :: Text -> Builder showMDString t = mconcat [ fromString "metadata !\"" , fromText t , singleton '"' ] showBool :: Bool -> Builder showBool True = fromString "i1 true" showBool False = fromString "i1 false" maybeShowMDName :: Maybe Metadata -> Builder maybeShowMDName Nothing = fromString "null" maybeShowMDName (Just m) = showMDName m dbgTag :: Int -> Builder dbgTag i = fromShow (i + fromIntegral llvmDebugVersion) printMetadata :: Metadata -> Builder printMetadata md@MetaSourceLocation { } = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", fromShow (metaSourceRow md) , fromString ", i32 ", fromShow (metaSourceCol md) , fromString ", ", maybeShowMDName (metaSourceScope md) , fromString" null}" ] printMetadata md@MetaDWLexicalBlock { } = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", dbgTag 11 , fromString ", i32 ", fromShow (metaLexicalBlockRow md) , fromString ", i32 ", fromShow (metaLexicalBlockCol md) , fromString ", ", maybeShowMDName (metaLexicalBlockContext md) , fromString "}" ] printMetadata md@MetaDWCompileUnit {} = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", dbgTag 17 , fromString ", i32 ", fromShow (metaCompileUnitLanguage md) , fromString ", ", showMDString (metaCompileUnitSourceFile md) , fromString ", ", showMDString (metaCompileUnitCompileDir md) , fromString ", ", showMDString (metaCompileUnitProducer md) , fromString ", ", showBool (metaCompileUnitIsMain md) , fromString ", ", showBool (metaCompileUnitIsOpt md) , fromString ", i32 ", fromShow (metaCompileUnitVersion md) , fromString "}" ] printMetadata md@MetaDWFile {} = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", dbgTag 41 , fromString ", ", showMDString (metaFileSourceFile md) , fromString ", ", showMDString (metaFileSourceDir md) , fromString "}" ] printMetadata md@MetaDWVariable {} = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", dbgTag 52 , fromString ", ", maybeShowMDName (metaGlobalVarContext md) , fromString ", ", showMDString (metaGlobalVarName md) , fromString ", ", showMDString (metaGlobalVarDisplayName md) , fromString ", ", showMDString (metaGlobalVarLinkageName md) , fromString ", i32 ", fromShow (metaGlobalVarLine md) , fromString ", ", maybeShowMDName (metaGlobalVarType md) , fromString ", ", showBool (metaGlobalVarStatic md) , fromString ", ", showBool (metaGlobalVarNotExtern md) , fromString "}" ] printMetadata md@MetaDWSubprogram {} = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", dbgTag 46 , fromString ", ", maybeShowMDName (metaSubprogramContext md) , fromString ", ", showMDString (metaSubprogramName md) , fromString ", ", showMDString (metaSubprogramDisplayName md) , fromString ", ", showMDString (metaSubprogramLinkageName md) , fromString ", i32 ", fromShow (metaSubprogramLine md) , fromString ", ", maybeShowMDName (metaSubprogramType md) , fromString ", ", showBool (metaSubprogramStatic md) , fromString ", ", showBool (metaSubprogramNotExtern md) , fromString ", i32 ", fromShow (metaSubprogramVirtuality md) , fromString ", i32 ", fromShow (metaSubprogramVirtIndex md) , fromString ", ", maybeShowMDName (metaSubprogramBaseType md) , fromString ", ", showBool (metaSubprogramArtificial md) , fromString ", ", showBool (metaSubprogramOptimized md) , fromString "}" ] printMetadata md@MetaDWBaseType {} = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", dbgTag 36 , fromString ", ", maybeShowMDName (metaBaseTypeContext md) , fromString ", ", showMDString (metaBaseTypeName md) -- , fromString ", ", maybeShowMDName (metaBaseTypeFile md) , fromString ", i32 ", fromShow (metaBaseTypeLine md) , fromString ", i32 ", fromShow (metaBaseTypeSize md) , fromString ", i32 ", fromShow (metaBaseTypeAlign md) , fromString ", i64 ", fromShow (metaBaseTypeOffset md) , fromString ", i32 ", fromShow (metaBaseTypeFlags md) , fromString ", i32 ", fromShow (metaBaseTypeEncoding md) , fromString "}" ] printMetadata md@MetaDWDerivedType {} = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", fromShow (metaDerivedTypeTag md) , fromString ", ", maybeShowMDName (metaDerivedTypeContext md) , fromString ", ", showMDString (metaDerivedTypeName md) -- , fromString ", ", maybeShowMDName (metaDerivedTypeFile md) , fromString ", i32 ", fromShow (metaDerivedTypeLine md) , fromString ", i32 ", fromShow (metaDerivedTypeSize md) , fromString ", i32 ", fromShow (metaDerivedTypeAlign md) , fromString ", i64 ", fromShow (metaDerivedTypeOffset md) , fromString ", ", maybeShowMDName (metaDerivedTypeParent md) , fromString "}" ] printMetadata md@MetaDWCompositeType {} = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", fromShow (metaCompositeTypeTag md) , fromString ", ", maybeShowMDName (metaCompositeTypeContext md) , fromString ", ", showMDString (metaCompositeTypeName md) -- , fromString ", ", maybeShowMDName (metaCompositeTypeFile md) , fromString ", i32 ", fromShow (metaCompositeTypeLine md) , fromString ", i32 ", fromShow (metaCompositeTypeSize md) , fromString ", i32 ", fromShow (metaCompositeTypeAlign md) , fromString ", i64 ", fromShow (metaCompositeTypeOffset md) , fromString ", i32 ", fromShow (metaCompositeTypeFlags md) , fromString ", ", maybeShowMDName (metaCompositeTypeParent md) , fromString ", ", maybeShowMDName (metaCompositeTypeMembers md) , fromString ", i32 ", fromShow (metaCompositeTypeRuntime md) , fromString "}" ] printMetadata md@MetaDWSubrange {} = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", dbgTag 33 , fromString ", i32 ", fromShow (metaSubrangeLow md) , fromString ", i32 ", fromShow (metaSubrangeHigh md) , fromString "}" ] printMetadata md@MetaDWEnumerator {} = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", dbgTag 40 , fromString ", ", showMDString (metaEnumeratorName md) , fromString ", i32 ", fromShow (metaEnumeratorValue md) , fromString "}" ] printMetadata md@MetaDWLocal {} = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", fromShow (metaLocalTag md) , fromString ", ", maybeShowMDName (metaLocalContext md) , fromString ", ", showMDString (metaLocalName md) , fromString ", i32 ", fromShow (metaLocalLine md) , fromString ", ", maybeShowMDName (metaLocalType md) , fromString "}" ] printMetadata md@(MetadataList _ vals) = mconcat [ showUntypedMDName md, fromString " = metadata !{" , mconcat $ intersperse (fromString ", ") (map maybeShowMDName vals) , fromString "}" ] printMetadata md@MetaDWNamespace {} = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", dbgTag 57 , fromString ", ", showMDString (metaNamespaceName md) , fromString ", ", maybeShowMDName (metaNamespaceContext md) , fromString ", i32 ", fromShow (metaNamespaceLine md) , fromString "}" ] printMetadata md@MetaDWTemplateTypeParameter {} = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", dbgTag 0x2f , fromString ", ", showMDString (metaTemplateTypeParameterName md) , fromString ", i32 ", fromShow (metaTemplateTypeParameterLine md) , fromString ", i32 ", fromShow (metaTemplateTypeParameterCol md) , fromString ", ", maybeShowMDName (metaTemplateTypeParameterContext md) , fromString ", ", maybeShowMDName (metaTemplateTypeParameterType md) , fromString "}" ] printMetadata md@MetaDWTemplateValueParameter {} = mconcat [ showUntypedMDName md, fromString " = metadata !{i32 ", dbgTag 0x30 , fromString ", ", showMDString (metaTemplateValueParameterName md) , fromString ", i32 ", fromShow (metaTemplateValueParameterLine md) , fromString ", i32 ", fromShow (metaTemplateValueParameterCol md) , fromString ", ", maybeShowMDName (metaTemplateValueParameterContext md) , fromString ", ", maybeShowMDName (metaTemplateValueParameterType md) , fromString ", i64 ", fromShow (metaTemplateValueParameterValue md) , fromString "}" ] printMetadata md@(MetadataUnknown _ s) = mconcat [ showUntypedMDName md, fromString " = metadata ", fromText s ] -- Take all of the asm chunks, break their contents into lines, -- then wrap each of those lines in the 'module asm' wrapper. -- Combine them into a single string with newlines. printAsm :: Assembly -> Builder printAsm asm = mconcat asmLines where asmLines = map adorn (lines (show asm)) adorn s = mconcat [fromString "module asm \"", fromString s, fromString "\"\n"] -- When referencing a non-constant value during printing, just use -- this instead of printValue to avoid problems printing cyclic data. -- If the value doesn't have a name, just print it (it should be a -- constant). printConstOrName :: Value -> Builder printConstOrName v = case valueName v of Nothing -> mconcat [ printType (valueType v), singleton ' ', printValue v ] Just ident -> mconcat [ printType (valueType v), singleton ' ', fromShow ident ] printConstOrNameNoType :: Value -> Builder printConstOrNameNoType v = case valueName v of Nothing -> printValue v Just ident -> fromShow ident compose :: [Builder] -> Builder compose = mconcat . intersperse (singleton ' ') . filter (/= mempty) quote :: Builder -> Builder quote s = mconcat [ singleton '\\', s, singleton '\\' ] printValue :: Value -> Builder printValue v = case valueContent v of FunctionC f -> let retAttrS = unwords $ map show (functionRetAttrs f) argS = commaSep $ map (printValue . toValue) (functionParameters f) fAttrS = spaceSep $ map fromShow (functionAttrs f) bodyS = lineSep $ map (printValue . toValue) (functionBody f) vaTag = if functionIsVararg f then ", ..." else "" (TypeFunction rtype _ _) = functionType f name = functionName f in compose [ fromString "define", fromShow (functionLinkage f) , fromShow (functionVisibility f), fromShow (functionCC f) , fromString retAttrS, printType rtype, fromShow name, singleton '(' , argS, fromString vaTag, singleton ')', fAttrS , maybe mempty fromText (functionSection f) , printAlignment (functionAlign f) , maybe mempty fromShow (functionGCName f) , fromString "{\n", bodyS, singleton '}' ] ArgumentC a -> compose [ printType (argumentType a) , compose $ map fromShow (argumentParamAttrs a) , fromShow (argumentName a) ] BasicBlockC b -> let indent = (fromString " " `mappend`) dbgS = map (printDebugTag . valueMetadata) (basicBlockInstructions b) instS = map (printValue . toValue) (basicBlockInstructions b) instS' = zipWith mappend instS dbgS instS'' = mconcat $ intersperse (singleton '\n') $ map indent instS' identS = fromText $ identifierContent (basicBlockName b) label = case isAnonymousIdentifier (basicBlockName b) of True -> fromString ";