{-# LANGUAGE CPP, GeneralizedNewtypeDeriving #-}

--------------------------------------------------------------------------------
-- | The LLVM Type System.
--

module Llvm.Types where

#include "HsVersions.h"

import GhcPrelude

import Data.Char
import Data.Int
import Numeric

import DynFlags
import FastString
import Outputable
import Unique

-- from NCG
import PprBase

import GHC.Float

-- -----------------------------------------------------------------------------
-- * LLVM Basic Types and Variables
--

-- | A global mutable variable. Maybe defined or external
data LMGlobal = LMGlobal {
  LMGlobal -> LlvmVar
getGlobalVar :: LlvmVar,          -- ^ Returns the variable of the 'LMGlobal'
  LMGlobal -> Maybe LlvmStatic
getGlobalValue :: Maybe LlvmStatic -- ^ Return the value of the 'LMGlobal'
  }

-- | A String in LLVM
type LMString = FastString

-- | A type alias
type LlvmAlias = (LMString, LlvmType)

-- | Llvm Types
data LlvmType
  = LMInt Int             -- ^ An integer with a given width in bits.
  | LMFloat               -- ^ 32 bit floating point
  | LMDouble              -- ^ 64 bit floating point
  | LMFloat80             -- ^ 80 bit (x86 only) floating point
  | LMFloat128            -- ^ 128 bit floating point
  | LMPointer LlvmType    -- ^ A pointer to a 'LlvmType'
  | LMArray Int LlvmType  -- ^ An array of 'LlvmType'
  | LMVector Int LlvmType -- ^ A vector of 'LlvmType'
  | LMLabel               -- ^ A 'LlvmVar' can represent a label (address)
  | LMVoid                -- ^ Void type
  | LMStruct [LlvmType]   -- ^ Packed structure type
  | LMStructU [LlvmType]  -- ^ Unpacked structure type
  | LMAlias LlvmAlias     -- ^ A type alias
  | LMMetadata            -- ^ LLVM Metadata

  -- | Function type, used to create pointers to functions
  | LMFunction LlvmFunctionDecl
  deriving (LlvmType -> LlvmType -> Bool
(LlvmType -> LlvmType -> Bool)
-> (LlvmType -> LlvmType -> Bool) -> Eq LlvmType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmType -> LlvmType -> Bool
$c/= :: LlvmType -> LlvmType -> Bool
== :: LlvmType -> LlvmType -> Bool
$c== :: LlvmType -> LlvmType -> Bool
Eq)

instance Outputable LlvmType where
  ppr :: LlvmType -> SDoc
ppr (LMInt size :: Int
size     ) = Char -> SDoc
char 'i' SDoc -> SDoc -> SDoc
<> Int -> SDoc
forall a. Outputable a => a -> SDoc
ppr Int
size
  ppr (LlvmType
LMFloat        ) = String -> SDoc
text "float"
  ppr (LlvmType
LMDouble       ) = String -> SDoc
text "double"
  ppr (LlvmType
LMFloat80      ) = String -> SDoc
text "x86_fp80"
  ppr (LlvmType
LMFloat128     ) = String -> SDoc
text "fp128"
  ppr (LMPointer x :: LlvmType
x    ) = LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
x SDoc -> SDoc -> SDoc
<> Char -> SDoc
char '*'
  ppr (LMArray nr :: Int
nr tp :: LlvmType
tp  ) = Char -> SDoc
char '[' SDoc -> SDoc -> SDoc
<> Int -> SDoc
forall a. Outputable a => a -> SDoc
ppr Int
nr SDoc -> SDoc -> SDoc
<> String -> SDoc
text " x " SDoc -> SDoc -> SDoc
<> LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
tp SDoc -> SDoc -> SDoc
<> Char -> SDoc
char ']'
  ppr (LMVector nr :: Int
nr tp :: LlvmType
tp ) = Char -> SDoc
char '<' SDoc -> SDoc -> SDoc
<> Int -> SDoc
forall a. Outputable a => a -> SDoc
ppr Int
nr SDoc -> SDoc -> SDoc
<> String -> SDoc
text " x " SDoc -> SDoc -> SDoc
<> LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
tp SDoc -> SDoc -> SDoc
<> Char -> SDoc
char '>'
  ppr (LlvmType
LMLabel        ) = String -> SDoc
text "label"
  ppr (LlvmType
LMVoid         ) = String -> SDoc
text "void"
  ppr (LMStruct tys :: [LlvmType]
tys   ) = String -> SDoc
text "<{" SDoc -> SDoc -> SDoc
<> [LlvmType] -> SDoc
forall a. Outputable a => [a] -> SDoc
ppCommaJoin [LlvmType]
tys SDoc -> SDoc -> SDoc
<> String -> SDoc
text "}>"
  ppr (LMStructU tys :: [LlvmType]
tys  ) = String -> SDoc
text "{" SDoc -> SDoc -> SDoc
<> [LlvmType] -> SDoc
forall a. Outputable a => [a] -> SDoc
ppCommaJoin [LlvmType]
tys SDoc -> SDoc -> SDoc
<> String -> SDoc
text "}"
  ppr (LlvmType
LMMetadata     ) = String -> SDoc
text "metadata"

  ppr (LMFunction (LlvmFunctionDecl _ _ _ r :: LlvmType
r varg :: LlvmParameterListType
varg p :: [LlvmParameter]
p _))
    = LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
r SDoc -> SDoc -> SDoc
<+> SDoc
lparen SDoc -> SDoc -> SDoc
<> LlvmParameterListType -> [LlvmParameter] -> SDoc
ppParams LlvmParameterListType
varg [LlvmParameter]
p SDoc -> SDoc -> SDoc
<> SDoc
rparen

  ppr (LMAlias (s :: LMString
s,_)) = Char -> SDoc
char '%' SDoc -> SDoc -> SDoc
<> LMString -> SDoc
ftext LMString
s

ppParams :: LlvmParameterListType -> [LlvmParameter] -> SDoc
ppParams :: LlvmParameterListType -> [LlvmParameter] -> SDoc
ppParams varg :: LlvmParameterListType
varg p :: [LlvmParameter]
p
  = let varg' :: PtrString
varg' = case LlvmParameterListType
varg of
          VarArgs | [LlvmType] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [LlvmType]
args -> String -> PtrString
sLit "..."
                  | Bool
otherwise -> String -> PtrString
sLit ", ..."
          _otherwise :: LlvmParameterListType
_otherwise          -> String -> PtrString
sLit ""
        -- by default we don't print param attributes
        args :: [LlvmType]
args = (LlvmParameter -> LlvmType) -> [LlvmParameter] -> [LlvmType]
forall a b. (a -> b) -> [a] -> [b]
map LlvmParameter -> LlvmType
forall a b. (a, b) -> a
fst [LlvmParameter]
p
    in [LlvmType] -> SDoc
forall a. Outputable a => [a] -> SDoc
ppCommaJoin [LlvmType]
args SDoc -> SDoc -> SDoc
<> PtrString -> SDoc
ptext PtrString
varg'

-- | An LLVM section definition. If Nothing then let LLVM decide the section
type LMSection = Maybe LMString
type LMAlign = Maybe Int

data LMConst = Global      -- ^ Mutable global variable
             | Constant    -- ^ Constant global variable
             | Alias       -- ^ Alias of another variable
             deriving (LMConst -> LMConst -> Bool
(LMConst -> LMConst -> Bool)
-> (LMConst -> LMConst -> Bool) -> Eq LMConst
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LMConst -> LMConst -> Bool
$c/= :: LMConst -> LMConst -> Bool
== :: LMConst -> LMConst -> Bool
$c== :: LMConst -> LMConst -> Bool
Eq)

-- | LLVM Variables
data LlvmVar
  -- | Variables with a global scope.
  = LMGlobalVar LMString LlvmType LlvmLinkageType LMSection LMAlign LMConst
  -- | Variables local to a function or parameters.
  | LMLocalVar Unique LlvmType
  -- | Named local variables. Sometimes we need to be able to explicitly name
  -- variables (e.g for function arguments).
  | LMNLocalVar LMString LlvmType
  -- | A constant variable
  | LMLitVar LlvmLit
  deriving (LlvmVar -> LlvmVar -> Bool
(LlvmVar -> LlvmVar -> Bool)
-> (LlvmVar -> LlvmVar -> Bool) -> Eq LlvmVar
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmVar -> LlvmVar -> Bool
$c/= :: LlvmVar -> LlvmVar -> Bool
== :: LlvmVar -> LlvmVar -> Bool
$c== :: LlvmVar -> LlvmVar -> Bool
Eq)

instance Outputable LlvmVar where
  ppr :: LlvmVar -> SDoc
ppr (LMLitVar x :: LlvmLit
x)  = LlvmLit -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmLit
x
  ppr (LlvmVar
x         )  = LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr (LlvmVar -> LlvmType
getVarType LlvmVar
x) SDoc -> SDoc -> SDoc
<+> LlvmVar -> SDoc
ppName LlvmVar
x


-- | Llvm Literal Data.
--
-- These can be used inline in expressions.
data LlvmLit
  -- | Refers to an integer constant (i64 42).
  = LMIntLit Integer LlvmType
  -- | Floating point literal
  | LMFloatLit Double LlvmType
  -- | Literal NULL, only applicable to pointer types
  | LMNullLit LlvmType
  -- | Vector literal
  | LMVectorLit [LlvmLit]
  -- | Undefined value, random bit pattern. Useful for optimisations.
  | LMUndefLit LlvmType
  deriving (LlvmLit -> LlvmLit -> Bool
(LlvmLit -> LlvmLit -> Bool)
-> (LlvmLit -> LlvmLit -> Bool) -> Eq LlvmLit
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmLit -> LlvmLit -> Bool
$c/= :: LlvmLit -> LlvmLit -> Bool
== :: LlvmLit -> LlvmLit -> Bool
$c== :: LlvmLit -> LlvmLit -> Bool
Eq)

instance Outputable LlvmLit where
  ppr :: LlvmLit -> SDoc
ppr l :: LlvmLit
l@(LMVectorLit {}) = LlvmLit -> SDoc
ppLit LlvmLit
l
  ppr l :: LlvmLit
l                  = LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr (LlvmLit -> LlvmType
getLitType LlvmLit
l) SDoc -> SDoc -> SDoc
<+> LlvmLit -> SDoc
ppLit LlvmLit
l


-- | Llvm Static Data.
--
-- These represent the possible global level variables and constants.
data LlvmStatic
  = LMComment LMString                  -- ^ A comment in a static section
  | LMStaticLit LlvmLit                 -- ^ A static variant of a literal value
  | LMUninitType LlvmType               -- ^ For uninitialised data
  | LMStaticStr LMString LlvmType       -- ^ Defines a static 'LMString'
  | LMStaticArray [LlvmStatic] LlvmType -- ^ A static array
  | LMStaticStruc [LlvmStatic] LlvmType -- ^ A static structure type
  | LMStaticPointer LlvmVar             -- ^ A pointer to other data

  -- static expressions, could split out but leave
  -- for moment for ease of use. Not many of them.

  | LMTrunc LlvmStatic LlvmType        -- ^ Truncate
  | LMBitc LlvmStatic LlvmType         -- ^ Pointer to Pointer conversion
  | LMPtoI LlvmStatic LlvmType         -- ^ Pointer to Integer conversion
  | LMAdd LlvmStatic LlvmStatic        -- ^ Constant addition operation
  | LMSub LlvmStatic LlvmStatic        -- ^ Constant subtraction operation

instance Outputable LlvmStatic where
  ppr :: LlvmStatic -> SDoc
ppr (LMComment       s :: LMString
s) = String -> SDoc
text "; " SDoc -> SDoc -> SDoc
<> LMString -> SDoc
ftext LMString
s
  ppr (LMStaticLit   l :: LlvmLit
l  ) = LlvmLit -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmLit
l
  ppr (LMUninitType    t :: LlvmType
t) = LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
t SDoc -> SDoc -> SDoc
<> String -> SDoc
text " undef"
  ppr (LMStaticStr   s :: LMString
s t :: LlvmType
t) = LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
t SDoc -> SDoc -> SDoc
<> String -> SDoc
text " c\"" SDoc -> SDoc -> SDoc
<> LMString -> SDoc
ftext LMString
s SDoc -> SDoc -> SDoc
<> String -> SDoc
text "\\00\""
  ppr (LMStaticArray d :: [LlvmStatic]
d t :: LlvmType
t) = LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
t SDoc -> SDoc -> SDoc
<> String -> SDoc
text " [" SDoc -> SDoc -> SDoc
<> [LlvmStatic] -> SDoc
forall a. Outputable a => [a] -> SDoc
ppCommaJoin [LlvmStatic]
d SDoc -> SDoc -> SDoc
<> Char -> SDoc
char ']'
  ppr (LMStaticStruc d :: [LlvmStatic]
d t :: LlvmType
t) = LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
t SDoc -> SDoc -> SDoc
<> String -> SDoc
text "<{" SDoc -> SDoc -> SDoc
<> [LlvmStatic] -> SDoc
forall a. Outputable a => [a] -> SDoc
ppCommaJoin [LlvmStatic]
d SDoc -> SDoc -> SDoc
<> String -> SDoc
text "}>"
  ppr (LMStaticPointer v :: LlvmVar
v) = LlvmVar -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmVar
v
  ppr (LMTrunc v :: LlvmStatic
v t :: LlvmType
t)
      = LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
t SDoc -> SDoc -> SDoc
<> String -> SDoc
text " trunc (" SDoc -> SDoc -> SDoc
<> LlvmStatic -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmStatic
v SDoc -> SDoc -> SDoc
<> String -> SDoc
text " to " SDoc -> SDoc -> SDoc
<> LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
t SDoc -> SDoc -> SDoc
<> Char -> SDoc
char ')'
  ppr (LMBitc v :: LlvmStatic
v t :: LlvmType
t)
      = LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
t SDoc -> SDoc -> SDoc
<> String -> SDoc
text " bitcast (" SDoc -> SDoc -> SDoc
<> LlvmStatic -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmStatic
v SDoc -> SDoc -> SDoc
<> String -> SDoc
text " to " SDoc -> SDoc -> SDoc
<> LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
t SDoc -> SDoc -> SDoc
<> Char -> SDoc
char ')'
  ppr (LMPtoI v :: LlvmStatic
v t :: LlvmType
t)
      = LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
t SDoc -> SDoc -> SDoc
<> String -> SDoc
text " ptrtoint (" SDoc -> SDoc -> SDoc
<> LlvmStatic -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmStatic
v SDoc -> SDoc -> SDoc
<> String -> SDoc
text " to " SDoc -> SDoc -> SDoc
<> LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
t SDoc -> SDoc -> SDoc
<> Char -> SDoc
char ')'

  ppr (LMAdd s1 :: LlvmStatic
s1 s2 :: LlvmStatic
s2)
      = LlvmStatic
-> LlvmStatic -> PtrString -> PtrString -> String -> SDoc
pprStaticArith LlvmStatic
s1 LlvmStatic
s2 (String -> PtrString
sLit "add") (String -> PtrString
sLit "fadd") "LMAdd"
  ppr (LMSub s1 :: LlvmStatic
s1 s2 :: LlvmStatic
s2)
      = LlvmStatic
-> LlvmStatic -> PtrString -> PtrString -> String -> SDoc
pprStaticArith LlvmStatic
s1 LlvmStatic
s2 (String -> PtrString
sLit "sub") (String -> PtrString
sLit "fsub") "LMSub"


pprSpecialStatic :: LlvmStatic -> SDoc
pprSpecialStatic :: LlvmStatic -> SDoc
pprSpecialStatic (LMBitc v :: LlvmStatic
v t :: LlvmType
t) =
    LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr (LlvmType -> LlvmType
pLower LlvmType
t) SDoc -> SDoc -> SDoc
<> String -> SDoc
text ", bitcast (" SDoc -> SDoc -> SDoc
<> LlvmStatic -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmStatic
v SDoc -> SDoc -> SDoc
<> String -> SDoc
text " to " SDoc -> SDoc -> SDoc
<> LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
t
        SDoc -> SDoc -> SDoc
<> Char -> SDoc
char ')'
pprSpecialStatic stat :: LlvmStatic
stat = LlvmStatic -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmStatic
stat


pprStaticArith :: LlvmStatic -> LlvmStatic -> PtrString -> PtrString
                  -> String -> SDoc
pprStaticArith :: LlvmStatic
-> LlvmStatic -> PtrString -> PtrString -> String -> SDoc
pprStaticArith s1 :: LlvmStatic
s1 s2 :: LlvmStatic
s2 int_op :: PtrString
int_op float_op :: PtrString
float_op op_name :: String
op_name =
  let ty1 :: LlvmType
ty1 = LlvmStatic -> LlvmType
getStatType LlvmStatic
s1
      op :: PtrString
op  = if LlvmType -> Bool
isFloat LlvmType
ty1 then PtrString
float_op else PtrString
int_op
  in if LlvmType
ty1 LlvmType -> LlvmType -> Bool
forall a. Eq a => a -> a -> Bool
== LlvmStatic -> LlvmType
getStatType LlvmStatic
s2
     then LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
ty1 SDoc -> SDoc -> SDoc
<+> PtrString -> SDoc
ptext PtrString
op SDoc -> SDoc -> SDoc
<+> SDoc
lparen SDoc -> SDoc -> SDoc
<> LlvmStatic -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmStatic
s1 SDoc -> SDoc -> SDoc
<> SDoc
comma SDoc -> SDoc -> SDoc
<> LlvmStatic -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmStatic
s2 SDoc -> SDoc -> SDoc
<> SDoc
rparen
     else (DynFlags -> SDoc) -> SDoc
sdocWithDynFlags ((DynFlags -> SDoc) -> SDoc) -> (DynFlags -> SDoc) -> SDoc
forall a b. (a -> b) -> a -> b
$ \dflags :: DynFlags
dflags ->
            String -> SDoc
forall a. HasCallStack => String -> a
error (String -> SDoc) -> String -> SDoc
forall a b. (a -> b) -> a -> b
$ String
op_name String -> String -> String
forall a. [a] -> [a] -> [a]
++ " with different types! s1: "
                    String -> String -> String
forall a. [a] -> [a] -> [a]
++ DynFlags -> SDoc -> String
showSDoc DynFlags
dflags (LlvmStatic -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmStatic
s1) String -> String -> String
forall a. [a] -> [a] -> [a]
++ ", s2: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ DynFlags -> SDoc -> String
showSDoc DynFlags
dflags (LlvmStatic -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmStatic
s2)

-- -----------------------------------------------------------------------------
-- ** Operations on LLVM Basic Types and Variables
--

-- | Return the variable name or value of the 'LlvmVar'
-- in Llvm IR textual representation (e.g. @\@x@, @%y@ or @42@).
ppName :: LlvmVar -> SDoc
ppName :: LlvmVar -> SDoc
ppName v :: LlvmVar
v@(LMGlobalVar {}) = Char -> SDoc
char '@' SDoc -> SDoc -> SDoc
<> LlvmVar -> SDoc
ppPlainName LlvmVar
v
ppName v :: LlvmVar
v@(LMLocalVar  {}) = Char -> SDoc
char '%' SDoc -> SDoc -> SDoc
<> LlvmVar -> SDoc
ppPlainName LlvmVar
v
ppName v :: LlvmVar
v@(LMNLocalVar {}) = Char -> SDoc
char '%' SDoc -> SDoc -> SDoc
<> LlvmVar -> SDoc
ppPlainName LlvmVar
v
ppName v :: LlvmVar
v@(LMLitVar    {}) =             LlvmVar -> SDoc
ppPlainName LlvmVar
v

-- | Return the variable name or value of the 'LlvmVar'
-- in a plain textual representation (e.g. @x@, @y@ or @42@).
ppPlainName :: LlvmVar -> SDoc
ppPlainName :: LlvmVar -> SDoc
ppPlainName (LMGlobalVar x :: LMString
x _ _ _ _ _) = LMString -> SDoc
ftext LMString
x
ppPlainName (LMLocalVar  x :: Unique
x LMLabel  ) = String -> SDoc
text (Unique -> String
forall a. Show a => a -> String
show Unique
x)
ppPlainName (LMLocalVar  x :: Unique
x _        ) = String -> SDoc
text ('l' Char -> String -> String
forall a. a -> [a] -> [a]
: Unique -> String
forall a. Show a => a -> String
show Unique
x)
ppPlainName (LMNLocalVar x :: LMString
x _        ) = LMString -> SDoc
ftext LMString
x
ppPlainName (LMLitVar    x :: LlvmLit
x          ) = LlvmLit -> SDoc
ppLit LlvmLit
x

-- | Print a literal value. No type.
ppLit :: LlvmLit -> SDoc
ppLit :: LlvmLit -> SDoc
ppLit (LMIntLit i :: Integer
i (LMInt 32))  = Int32 -> SDoc
forall a. Outputable a => a -> SDoc
ppr (Integer -> Int32
forall a. Num a => Integer -> a
fromInteger Integer
i :: Int32)
ppLit (LMIntLit i :: Integer
i (LMInt 64))  = Int64 -> SDoc
forall a. Outputable a => a -> SDoc
ppr (Integer -> Int64
forall a. Num a => Integer -> a
fromInteger Integer
i :: Int64)
ppLit (LMIntLit   i :: Integer
i _       )  = Int -> SDoc
forall a. Outputable a => a -> SDoc
ppr ((Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
i)::Int)
ppLit (LMFloatLit r :: Double
r LMFloat )  = Float -> SDoc
ppFloat (Float -> SDoc) -> Float -> SDoc
forall a b. (a -> b) -> a -> b
$ Double -> Float
narrowFp Double
r
ppLit (LMFloatLit r :: Double
r LMDouble)  = Double -> SDoc
ppDouble Double
r
ppLit f :: LlvmLit
f@(LMFloatLit _ _)       = (DynFlags -> SDoc) -> SDoc
sdocWithDynFlags (\dflags :: DynFlags
dflags ->
                                   String -> SDoc
forall a. HasCallStack => String -> a
error (String -> SDoc) -> String -> SDoc
forall a b. (a -> b) -> a -> b
$ "Can't print this float literal!" String -> String -> String
forall a. [a] -> [a] -> [a]
++ DynFlags -> SDoc -> String
showSDoc DynFlags
dflags (LlvmLit -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmLit
f))
ppLit (LMVectorLit ls :: [LlvmLit]
ls  )       = Char -> SDoc
char '<' SDoc -> SDoc -> SDoc
<+> [LlvmLit] -> SDoc
forall a. Outputable a => [a] -> SDoc
ppCommaJoin [LlvmLit]
ls SDoc -> SDoc -> SDoc
<+> Char -> SDoc
char '>'
ppLit (LMNullLit _     )       = String -> SDoc
text "null"
-- Trac 11487 was an issue where we passed undef for some arguments
-- that were actually live. By chance the registers holding those
-- arguments usually happened to have the right values anyways, but
-- that was not guaranteed. To find such bugs reliably, we set the
-- flag below when validating, which replaces undef literals (at
-- common types) with values that are likely to cause a crash or test
-- failure.
ppLit (LMUndefLit t :: LlvmType
t    )       = (DynFlags -> SDoc) -> SDoc
sdocWithDynFlags DynFlags -> SDoc
f
  where f :: DynFlags -> SDoc
f dflags :: DynFlags
dflags
          | GeneralFlag -> DynFlags -> Bool
gopt GeneralFlag
Opt_LlvmFillUndefWithGarbage DynFlags
dflags,
            Just lit :: LlvmLit
lit <- LlvmType -> Maybe LlvmLit
garbageLit LlvmType
t   = LlvmLit -> SDoc
ppLit LlvmLit
lit
          | Bool
otherwise                  = String -> SDoc
text "undef"

garbageLit :: LlvmType -> Maybe LlvmLit
garbageLit :: LlvmType -> Maybe LlvmLit
garbageLit t :: LlvmType
t@(LMInt w :: Int
w)     = LlvmLit -> Maybe LlvmLit
forall a. a -> Maybe a
Just (Integer -> LlvmType -> LlvmLit
LMIntLit (0xbbbbbbbbbbbbbbb0 Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` (2Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^Int
w)) LlvmType
t)
  -- Use a value that looks like an untagged pointer, so we are more
  -- likely to try to enter it
garbageLit t :: LlvmType
t
  | LlvmType -> Bool
isFloat LlvmType
t              = LlvmLit -> Maybe LlvmLit
forall a. a -> Maybe a
Just (Double -> LlvmType -> LlvmLit
LMFloatLit 12345678.9 LlvmType
t)
garbageLit t :: LlvmType
t@(LMPointer _) = LlvmLit -> Maybe LlvmLit
forall a. a -> Maybe a
Just (LlvmType -> LlvmLit
LMNullLit LlvmType
t)
  -- Using null isn't totally ideal, since some functions may check for null.
  -- But producing another value is inconvenient since it needs a cast,
  -- and the knowledge for how to format casts is in PpLlvm.
garbageLit _               = Maybe LlvmLit
forall a. Maybe a
Nothing
  -- More cases could be added, but this should do for now.

-- | Return the 'LlvmType' of the 'LlvmVar'
getVarType :: LlvmVar -> LlvmType
getVarType :: LlvmVar -> LlvmType
getVarType (LMGlobalVar _ y :: LlvmType
y _ _ _ _) = LlvmType
y
getVarType (LMLocalVar  _ y :: LlvmType
y        ) = LlvmType
y
getVarType (LMNLocalVar _ y :: LlvmType
y        ) = LlvmType
y
getVarType (LMLitVar    l :: LlvmLit
l          ) = LlvmLit -> LlvmType
getLitType LlvmLit
l

-- | Return the 'LlvmType' of a 'LlvmLit'
getLitType :: LlvmLit -> LlvmType
getLitType :: LlvmLit -> LlvmType
getLitType (LMIntLit   _ t :: LlvmType
t) = LlvmType
t
getLitType (LMFloatLit _ t :: LlvmType
t) = LlvmType
t
getLitType (LMVectorLit [])  = String -> LlvmType
forall a. String -> a
panic "getLitType"
getLitType (LMVectorLit ls :: [LlvmLit]
ls)  = Int -> LlvmType -> LlvmType
LMVector ([LlvmLit] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [LlvmLit]
ls) (LlvmLit -> LlvmType
getLitType ([LlvmLit] -> LlvmLit
forall a. [a] -> a
head [LlvmLit]
ls))
getLitType (LMNullLit    t :: LlvmType
t) = LlvmType
t
getLitType (LMUndefLit   t :: LlvmType
t) = LlvmType
t

-- | Return the 'LlvmType' of the 'LlvmStatic'
getStatType :: LlvmStatic -> LlvmType
getStatType :: LlvmStatic -> LlvmType
getStatType (LMStaticLit   l :: LlvmLit
l  ) = LlvmLit -> LlvmType
getLitType LlvmLit
l
getStatType (LMUninitType    t :: LlvmType
t) = LlvmType
t
getStatType (LMStaticStr   _ t :: LlvmType
t) = LlvmType
t
getStatType (LMStaticArray _ t :: LlvmType
t) = LlvmType
t
getStatType (LMStaticStruc _ t :: LlvmType
t) = LlvmType
t
getStatType (LMStaticPointer v :: LlvmVar
v) = LlvmVar -> LlvmType
getVarType LlvmVar
v
getStatType (LMTrunc       _ t :: LlvmType
t) = LlvmType
t
getStatType (LMBitc        _ t :: LlvmType
t) = LlvmType
t
getStatType (LMPtoI        _ t :: LlvmType
t) = LlvmType
t
getStatType (LMAdd         t :: LlvmStatic
t _) = LlvmStatic -> LlvmType
getStatType LlvmStatic
t
getStatType (LMSub         t :: LlvmStatic
t _) = LlvmStatic -> LlvmType
getStatType LlvmStatic
t
getStatType (LMComment       _) = String -> LlvmType
forall a. HasCallStack => String -> a
error "Can't call getStatType on LMComment!"

-- | Return the 'LlvmLinkageType' for a 'LlvmVar'
getLink :: LlvmVar -> LlvmLinkageType
getLink :: LlvmVar -> LlvmLinkageType
getLink (LMGlobalVar _ _ l :: LlvmLinkageType
l _ _ _) = LlvmLinkageType
l
getLink _                         = LlvmLinkageType
Internal

-- | Add a pointer indirection to the supplied type. 'LMLabel' and 'LMVoid'
-- cannot be lifted.
pLift :: LlvmType -> LlvmType
pLift :: LlvmType -> LlvmType
pLift LMLabel    = String -> LlvmType
forall a. HasCallStack => String -> a
error "Labels are unliftable"
pLift LMVoid     = String -> LlvmType
forall a. HasCallStack => String -> a
error "Voids are unliftable"
pLift LMMetadata = String -> LlvmType
forall a. HasCallStack => String -> a
error "Metadatas are unliftable"
pLift x :: LlvmType
x          = LlvmType -> LlvmType
LMPointer LlvmType
x

-- | Lift a variable to 'LMPointer' type.
pVarLift :: LlvmVar -> LlvmVar
pVarLift :: LlvmVar -> LlvmVar
pVarLift (LMGlobalVar s :: LMString
s t :: LlvmType
t l :: LlvmLinkageType
l x :: LMSection
x a :: LMAlign
a c :: LMConst
c) = LMString
-> LlvmType
-> LlvmLinkageType
-> LMSection
-> LMAlign
-> LMConst
-> LlvmVar
LMGlobalVar LMString
s (LlvmType -> LlvmType
pLift LlvmType
t) LlvmLinkageType
l LMSection
x LMAlign
a LMConst
c
pVarLift (LMLocalVar  s :: Unique
s t :: LlvmType
t        ) = Unique -> LlvmType -> LlvmVar
LMLocalVar  Unique
s (LlvmType -> LlvmType
pLift LlvmType
t)
pVarLift (LMNLocalVar s :: LMString
s t :: LlvmType
t        ) = LMString -> LlvmType -> LlvmVar
LMNLocalVar LMString
s (LlvmType -> LlvmType
pLift LlvmType
t)
pVarLift (LMLitVar    _          ) = String -> LlvmVar
forall a. HasCallStack => String -> a
error (String -> LlvmVar) -> String -> LlvmVar
forall a b. (a -> b) -> a -> b
$ "Can't lower a literal type!"

-- | Remove the pointer indirection of the supplied type. Only 'LMPointer'
-- constructors can be lowered.
pLower :: LlvmType -> LlvmType
pLower :: LlvmType -> LlvmType
pLower (LMPointer x :: LlvmType
x) = LlvmType
x
pLower x :: LlvmType
x  = String -> SDoc -> LlvmType
forall a. HasCallStack => String -> SDoc -> a
pprPanic "llvmGen(pLower)"
            (SDoc -> LlvmType) -> SDoc -> LlvmType
forall a b. (a -> b) -> a -> b
$ LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
x SDoc -> SDoc -> SDoc
<+> String -> SDoc
text " is a unlowerable type, need a pointer"

-- | Lower a variable of 'LMPointer' type.
pVarLower :: LlvmVar -> LlvmVar
pVarLower :: LlvmVar -> LlvmVar
pVarLower (LMGlobalVar s :: LMString
s t :: LlvmType
t l :: LlvmLinkageType
l x :: LMSection
x a :: LMAlign
a c :: LMConst
c) = LMString
-> LlvmType
-> LlvmLinkageType
-> LMSection
-> LMAlign
-> LMConst
-> LlvmVar
LMGlobalVar LMString
s (LlvmType -> LlvmType
pLower LlvmType
t) LlvmLinkageType
l LMSection
x LMAlign
a LMConst
c
pVarLower (LMLocalVar  s :: Unique
s t :: LlvmType
t        ) = Unique -> LlvmType -> LlvmVar
LMLocalVar  Unique
s (LlvmType -> LlvmType
pLower LlvmType
t)
pVarLower (LMNLocalVar s :: LMString
s t :: LlvmType
t        ) = LMString -> LlvmType -> LlvmVar
LMNLocalVar LMString
s (LlvmType -> LlvmType
pLower LlvmType
t)
pVarLower (LMLitVar    _          ) = String -> LlvmVar
forall a. HasCallStack => String -> a
error (String -> LlvmVar) -> String -> LlvmVar
forall a b. (a -> b) -> a -> b
$ "Can't lower a literal type!"

-- | Test if the given 'LlvmType' is an integer
isInt :: LlvmType -> Bool
isInt :: LlvmType -> Bool
isInt (LMInt _) = Bool
True
isInt _         = Bool
False

-- | Test if the given 'LlvmType' is a floating point type
isFloat :: LlvmType -> Bool
isFloat :: LlvmType -> Bool
isFloat LMFloat    = Bool
True
isFloat LMDouble   = Bool
True
isFloat LMFloat80  = Bool
True
isFloat LMFloat128 = Bool
True
isFloat _          = Bool
False

-- | Test if the given 'LlvmType' is an 'LMPointer' construct
isPointer :: LlvmType -> Bool
isPointer :: LlvmType -> Bool
isPointer (LMPointer _) = Bool
True
isPointer _             = Bool
False

-- | Test if the given 'LlvmType' is an 'LMVector' construct
isVector :: LlvmType -> Bool
isVector :: LlvmType -> Bool
isVector (LMVector {}) = Bool
True
isVector _             = Bool
False

-- | Test if a 'LlvmVar' is global.
isGlobal :: LlvmVar -> Bool
isGlobal :: LlvmVar -> Bool
isGlobal (LMGlobalVar _ _ _ _ _ _) = Bool
True
isGlobal _                         = Bool
False

-- | Width in bits of an 'LlvmType', returns 0 if not applicable
llvmWidthInBits :: DynFlags -> LlvmType -> Int
llvmWidthInBits :: DynFlags -> LlvmType -> Int
llvmWidthInBits _      (LMInt n :: Int
n)       = Int
n
llvmWidthInBits _      (LlvmType
LMFloat)       = 32
llvmWidthInBits _      (LlvmType
LMDouble)      = 64
llvmWidthInBits _      (LlvmType
LMFloat80)     = 80
llvmWidthInBits _      (LlvmType
LMFloat128)    = 128
-- Could return either a pointer width here or the width of what
-- it points to. We will go with the former for now.
-- PMW: At least judging by the way LLVM outputs constants, pointers
--      should use the former, but arrays the latter.
llvmWidthInBits dflags :: DynFlags
dflags (LMPointer _)   = DynFlags -> LlvmType -> Int
llvmWidthInBits DynFlags
dflags (DynFlags -> LlvmType
llvmWord DynFlags
dflags)
llvmWidthInBits dflags :: DynFlags
dflags (LMArray n :: Int
n t :: LlvmType
t)   = Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
* DynFlags -> LlvmType -> Int
llvmWidthInBits DynFlags
dflags LlvmType
t
llvmWidthInBits dflags :: DynFlags
dflags (LMVector n :: Int
n ty :: LlvmType
ty) = Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
* DynFlags -> LlvmType -> Int
llvmWidthInBits DynFlags
dflags LlvmType
ty
llvmWidthInBits _      LMLabel         = 0
llvmWidthInBits _      LMVoid          = 0
llvmWidthInBits dflags :: DynFlags
dflags (LMStruct tys :: [LlvmType]
tys)  = [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ (LlvmType -> Int) -> [LlvmType] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (DynFlags -> LlvmType -> Int
llvmWidthInBits DynFlags
dflags) [LlvmType]
tys
llvmWidthInBits _      (LMStructU _)   =
    -- It's not trivial to calculate the bit width of the unpacked structs,
    -- since they will be aligned depending on the specified datalayout (
    -- http://llvm.org/docs/LangRef.html#data-layout ). One way we could support
    -- this could be to make the LlvmCodeGen.Ppr.moduleLayout be a data type
    -- that exposes the alignment information. However, currently the only place
    -- we use unpacked structs is LLVM intrinsics that return them (e.g.,
    -- llvm.sadd.with.overflow.*), so we don't actually need to compute their
    -- bit width.
    String -> Int
forall a. String -> a
panic "llvmWidthInBits: not implemented for LMStructU"
llvmWidthInBits _      (LMFunction  _) = 0
llvmWidthInBits dflags :: DynFlags
dflags (LMAlias (_,t :: LlvmType
t)) = DynFlags -> LlvmType -> Int
llvmWidthInBits DynFlags
dflags LlvmType
t
llvmWidthInBits _      LMMetadata      = String -> Int
forall a. String -> a
panic "llvmWidthInBits: Meta-data has no runtime representation!"


-- -----------------------------------------------------------------------------
-- ** Shortcut for Common Types
--

i128, i64, i32, i16, i8, i1, i8Ptr :: LlvmType
i128 :: LlvmType
i128  = Int -> LlvmType
LMInt 128
i64 :: LlvmType
i64   = Int -> LlvmType
LMInt  64
i32 :: LlvmType
i32   = Int -> LlvmType
LMInt  32
i16 :: LlvmType
i16   = Int -> LlvmType
LMInt  16
i8 :: LlvmType
i8    = Int -> LlvmType
LMInt   8
i1 :: LlvmType
i1    = Int -> LlvmType
LMInt   1
i8Ptr :: LlvmType
i8Ptr = LlvmType -> LlvmType
pLift LlvmType
i8

-- | The target architectures word size
llvmWord, llvmWordPtr :: DynFlags -> LlvmType
llvmWord :: DynFlags -> LlvmType
llvmWord    dflags :: DynFlags
dflags = Int -> LlvmType
LMInt (DynFlags -> Int
wORD_SIZE DynFlags
dflags Int -> Int -> Int
forall a. Num a => a -> a -> a
* 8)
llvmWordPtr :: DynFlags -> LlvmType
llvmWordPtr dflags :: DynFlags
dflags = LlvmType -> LlvmType
pLift (DynFlags -> LlvmType
llvmWord DynFlags
dflags)

-- -----------------------------------------------------------------------------
-- * LLVM Function Types
--

-- | An LLVM Function
data LlvmFunctionDecl = LlvmFunctionDecl {
        -- | Unique identifier of the function
        LlvmFunctionDecl -> LMString
decName       :: LMString,
        -- | LinkageType of the function
        LlvmFunctionDecl -> LlvmLinkageType
funcLinkage   :: LlvmLinkageType,
        -- | The calling convention of the function
        LlvmFunctionDecl -> LlvmCallConvention
funcCc        :: LlvmCallConvention,
        -- | Type of the returned value
        LlvmFunctionDecl -> LlvmType
decReturnType :: LlvmType,
        -- | Indicates if this function uses varargs
        LlvmFunctionDecl -> LlvmParameterListType
decVarargs    :: LlvmParameterListType,
        -- | Parameter types and attributes
        LlvmFunctionDecl -> [LlvmParameter]
decParams     :: [LlvmParameter],
        -- | Function align value, must be power of 2
        LlvmFunctionDecl -> LMAlign
funcAlign     :: LMAlign
  }
  deriving (LlvmFunctionDecl -> LlvmFunctionDecl -> Bool
(LlvmFunctionDecl -> LlvmFunctionDecl -> Bool)
-> (LlvmFunctionDecl -> LlvmFunctionDecl -> Bool)
-> Eq LlvmFunctionDecl
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmFunctionDecl -> LlvmFunctionDecl -> Bool
$c/= :: LlvmFunctionDecl -> LlvmFunctionDecl -> Bool
== :: LlvmFunctionDecl -> LlvmFunctionDecl -> Bool
$c== :: LlvmFunctionDecl -> LlvmFunctionDecl -> Bool
Eq)

instance Outputable LlvmFunctionDecl where
  ppr :: LlvmFunctionDecl -> SDoc
ppr (LlvmFunctionDecl n :: LMString
n l :: LlvmLinkageType
l c :: LlvmCallConvention
c r :: LlvmType
r varg :: LlvmParameterListType
varg p :: [LlvmParameter]
p a :: LMAlign
a)
    = let align :: SDoc
align = case LMAlign
a of
                       Just a' :: Int
a' -> String -> SDoc
text " align " SDoc -> SDoc -> SDoc
<> Int -> SDoc
forall a. Outputable a => a -> SDoc
ppr Int
a'
                       Nothing -> SDoc
empty
      in LlvmLinkageType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmLinkageType
l SDoc -> SDoc -> SDoc
<+> LlvmCallConvention -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmCallConvention
c SDoc -> SDoc -> SDoc
<+> LlvmType -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmType
r SDoc -> SDoc -> SDoc
<+> Char -> SDoc
char '@' SDoc -> SDoc -> SDoc
<> LMString -> SDoc
ftext LMString
n SDoc -> SDoc -> SDoc
<>
             SDoc
lparen SDoc -> SDoc -> SDoc
<> LlvmParameterListType -> [LlvmParameter] -> SDoc
ppParams LlvmParameterListType
varg [LlvmParameter]
p SDoc -> SDoc -> SDoc
<> SDoc
rparen SDoc -> SDoc -> SDoc
<> SDoc
align

type LlvmFunctionDecls = [LlvmFunctionDecl]

type LlvmParameter = (LlvmType, [LlvmParamAttr])

-- | LLVM Parameter Attributes.
--
-- Parameter attributes are used to communicate additional information about
-- the result or parameters of a function
data LlvmParamAttr
  -- | This indicates to the code generator that the parameter or return value
  -- should be zero-extended to a 32-bit value by the caller (for a parameter)
  -- or the callee (for a return value).
  = ZeroExt
  -- | This indicates to the code generator that the parameter or return value
  -- should be sign-extended to a 32-bit value by the caller (for a parameter)
  -- or the callee (for a return value).
  | SignExt
  -- | This indicates that this parameter or return value should be treated in
  -- a special target-dependent fashion during while emitting code for a
  -- function call or return (usually, by putting it in a register as opposed
  -- to memory).
  | InReg
  -- | This indicates that the pointer parameter should really be passed by
  -- value to the function.
  | ByVal
  -- | This indicates that the pointer parameter specifies the address of a
  -- structure that is the return value of the function in the source program.
  | SRet
  -- | This indicates that the pointer does not alias any global or any other
  -- parameter.
  | NoAlias
  -- | This indicates that the callee does not make any copies of the pointer
  -- that outlive the callee itself
  | NoCapture
  -- | This indicates that the pointer parameter can be excised using the
  -- trampoline intrinsics.
  | Nest
  deriving (LlvmParamAttr -> LlvmParamAttr -> Bool
(LlvmParamAttr -> LlvmParamAttr -> Bool)
-> (LlvmParamAttr -> LlvmParamAttr -> Bool) -> Eq LlvmParamAttr
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmParamAttr -> LlvmParamAttr -> Bool
$c/= :: LlvmParamAttr -> LlvmParamAttr -> Bool
== :: LlvmParamAttr -> LlvmParamAttr -> Bool
$c== :: LlvmParamAttr -> LlvmParamAttr -> Bool
Eq)

instance Outputable LlvmParamAttr where
  ppr :: LlvmParamAttr -> SDoc
ppr ZeroExt   = String -> SDoc
text "zeroext"
  ppr SignExt   = String -> SDoc
text "signext"
  ppr InReg     = String -> SDoc
text "inreg"
  ppr ByVal     = String -> SDoc
text "byval"
  ppr SRet      = String -> SDoc
text "sret"
  ppr NoAlias   = String -> SDoc
text "noalias"
  ppr NoCapture = String -> SDoc
text "nocapture"
  ppr Nest      = String -> SDoc
text "nest"

-- | Llvm Function Attributes.
--
-- Function attributes are set to communicate additional information about a
-- function. Function attributes are considered to be part of the function,
-- not of the function type, so functions with different parameter attributes
-- can have the same function type. Functions can have multiple attributes.
--
-- Descriptions taken from <http://llvm.org/docs/LangRef.html#fnattrs>
data LlvmFuncAttr
  -- | This attribute indicates that the inliner should attempt to inline this
  -- function into callers whenever possible, ignoring any active inlining
  -- size threshold for this caller.
  = AlwaysInline
  -- | This attribute indicates that the source code contained a hint that
  -- inlining this function is desirable (such as the \"inline\" keyword in
  -- C/C++). It is just a hint; it imposes no requirements on the inliner.
  | InlineHint
  -- | This attribute indicates that the inliner should never inline this
  -- function in any situation. This attribute may not be used together
  -- with the alwaysinline attribute.
  | NoInline
  -- | This attribute suggests that optimization passes and code generator
  -- passes make choices that keep the code size of this function low, and
  -- otherwise do optimizations specifically to reduce code size.
  | OptSize
  -- | This function attribute indicates that the function never returns
  -- normally. This produces undefined behavior at runtime if the function
  -- ever does dynamically return.
  | NoReturn
  -- | This function attribute indicates that the function never returns with
  -- an unwind or exceptional control flow. If the function does unwind, its
  -- runtime behavior is undefined.
  | NoUnwind
  -- | This attribute indicates that the function computes its result (or
  -- decides to unwind an exception) based strictly on its arguments, without
  -- dereferencing any pointer arguments or otherwise accessing any mutable
  -- state (e.g. memory, control registers, etc) visible to caller functions.
  -- It does not write through any pointer arguments (including byval
  -- arguments) and never changes any state visible to callers. This means
  -- that it cannot unwind exceptions by calling the C++ exception throwing
  -- methods, but could use the unwind instruction.
  | ReadNone
  -- | This attribute indicates that the function does not write through any
  -- pointer arguments (including byval arguments) or otherwise modify any
  -- state (e.g. memory, control registers, etc) visible to caller functions.
  -- It may dereference pointer arguments and read state that may be set in
  -- the caller. A readonly function always returns the same value (or unwinds
  -- an exception identically) when called with the same set of arguments and
  -- global state. It cannot unwind an exception by calling the C++ exception
  -- throwing methods, but may use the unwind instruction.
  | ReadOnly
  -- | This attribute indicates that the function should emit a stack smashing
  -- protector. It is in the form of a \"canary\"—a random value placed on the
  -- stack before the local variables that's checked upon return from the
  -- function to see if it has been overwritten. A heuristic is used to
  -- determine if a function needs stack protectors or not.
  --
  -- If a function that has an ssp attribute is inlined into a function that
  -- doesn't have an ssp attribute, then the resulting function will have an
  -- ssp attribute.
  | Ssp
  -- | This attribute indicates that the function should always emit a stack
  -- smashing protector. This overrides the ssp function attribute.
  --
  -- If a function that has an sspreq attribute is inlined into a function
  -- that doesn't have an sspreq attribute or which has an ssp attribute,
  -- then the resulting function will have an sspreq attribute.
  | SspReq
  -- | This attribute indicates that the code generator should not use a red
  -- zone, even if the target-specific ABI normally permits it.
  | NoRedZone
  -- | This attributes disables implicit floating point instructions.
  | NoImplicitFloat
  -- | This attribute disables prologue / epilogue emission for the function.
  -- This can have very system-specific consequences.
  | Naked
  deriving (LlvmFuncAttr -> LlvmFuncAttr -> Bool
(LlvmFuncAttr -> LlvmFuncAttr -> Bool)
-> (LlvmFuncAttr -> LlvmFuncAttr -> Bool) -> Eq LlvmFuncAttr
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmFuncAttr -> LlvmFuncAttr -> Bool
$c/= :: LlvmFuncAttr -> LlvmFuncAttr -> Bool
== :: LlvmFuncAttr -> LlvmFuncAttr -> Bool
$c== :: LlvmFuncAttr -> LlvmFuncAttr -> Bool
Eq)

instance Outputable LlvmFuncAttr where
  ppr :: LlvmFuncAttr -> SDoc
ppr AlwaysInline       = String -> SDoc
text "alwaysinline"
  ppr InlineHint         = String -> SDoc
text "inlinehint"
  ppr NoInline           = String -> SDoc
text "noinline"
  ppr OptSize            = String -> SDoc
text "optsize"
  ppr NoReturn           = String -> SDoc
text "noreturn"
  ppr NoUnwind           = String -> SDoc
text "nounwind"
  ppr ReadNone           = String -> SDoc
text "readnon"
  ppr ReadOnly           = String -> SDoc
text "readonly"
  ppr Ssp                = String -> SDoc
text "ssp"
  ppr SspReq             = String -> SDoc
text "ssqreq"
  ppr NoRedZone          = String -> SDoc
text "noredzone"
  ppr NoImplicitFloat    = String -> SDoc
text "noimplicitfloat"
  ppr Naked              = String -> SDoc
text "naked"


-- | Different types to call a function.
data LlvmCallType
  -- | Normal call, allocate a new stack frame.
  = StdCall
  -- | Tail call, perform the call in the current stack frame.
  | TailCall
  deriving (LlvmCallType -> LlvmCallType -> Bool
(LlvmCallType -> LlvmCallType -> Bool)
-> (LlvmCallType -> LlvmCallType -> Bool) -> Eq LlvmCallType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmCallType -> LlvmCallType -> Bool
$c/= :: LlvmCallType -> LlvmCallType -> Bool
== :: LlvmCallType -> LlvmCallType -> Bool
$c== :: LlvmCallType -> LlvmCallType -> Bool
Eq,Int -> LlvmCallType -> String -> String
[LlvmCallType] -> String -> String
LlvmCallType -> String
(Int -> LlvmCallType -> String -> String)
-> (LlvmCallType -> String)
-> ([LlvmCallType] -> String -> String)
-> Show LlvmCallType
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [LlvmCallType] -> String -> String
$cshowList :: [LlvmCallType] -> String -> String
show :: LlvmCallType -> String
$cshow :: LlvmCallType -> String
showsPrec :: Int -> LlvmCallType -> String -> String
$cshowsPrec :: Int -> LlvmCallType -> String -> String
Show)

-- | Different calling conventions a function can use.
data LlvmCallConvention
  -- | The C calling convention.
  -- This calling convention (the default if no other calling convention is
  -- specified) matches the target C calling conventions. This calling
  -- convention supports varargs function calls and tolerates some mismatch in
  -- the declared prototype and implemented declaration of the function (as
  -- does normal C).
  = CC_Ccc
  -- | This calling convention attempts to make calls as fast as possible
  -- (e.g. by passing things in registers). This calling convention allows
  -- the target to use whatever tricks it wants to produce fast code for the
  -- target, without having to conform to an externally specified ABI
  -- (Application Binary Interface). Implementations of this convention should
  -- allow arbitrary tail call optimization to be supported. This calling
  -- convention does not support varargs and requires the prototype of al
  -- callees to exactly match the prototype of the function definition.
  | CC_Fastcc
  -- | This calling convention attempts to make code in the caller as efficient
  -- as possible under the assumption that the call is not commonly executed.
  -- As such, these calls often preserve all registers so that the call does
  -- not break any live ranges in the caller side. This calling convention
  -- does not support varargs and requires the prototype of all callees to
  -- exactly match the prototype of the function definition.
  | CC_Coldcc
  -- | The GHC-specific 'registerised' calling convention.
  | CC_Ghc
  -- | Any calling convention may be specified by number, allowing
  -- target-specific calling conventions to be used. Target specific calling
  -- conventions start at 64.
  | CC_Ncc Int
  -- | X86 Specific 'StdCall' convention. LLVM includes a specific alias for it
  -- rather than just using CC_Ncc.
  | CC_X86_Stdcc
  deriving (LlvmCallConvention -> LlvmCallConvention -> Bool
(LlvmCallConvention -> LlvmCallConvention -> Bool)
-> (LlvmCallConvention -> LlvmCallConvention -> Bool)
-> Eq LlvmCallConvention
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmCallConvention -> LlvmCallConvention -> Bool
$c/= :: LlvmCallConvention -> LlvmCallConvention -> Bool
== :: LlvmCallConvention -> LlvmCallConvention -> Bool
$c== :: LlvmCallConvention -> LlvmCallConvention -> Bool
Eq)

instance Outputable LlvmCallConvention where
  ppr :: LlvmCallConvention -> SDoc
ppr CC_Ccc       = String -> SDoc
text "ccc"
  ppr CC_Fastcc    = String -> SDoc
text "fastcc"
  ppr CC_Coldcc    = String -> SDoc
text "coldcc"
  ppr CC_Ghc       = String -> SDoc
text "ghccc"
  ppr (CC_Ncc i :: Int
i)   = String -> SDoc
text "cc " SDoc -> SDoc -> SDoc
<> Int -> SDoc
forall a. Outputable a => a -> SDoc
ppr Int
i
  ppr CC_X86_Stdcc = String -> SDoc
text "x86_stdcallcc"


-- | Functions can have a fixed amount of parameters, or a variable amount.
data LlvmParameterListType
  -- Fixed amount of arguments.
  = FixedArgs
  -- Variable amount of arguments.
  | VarArgs
  deriving (LlvmParameterListType -> LlvmParameterListType -> Bool
(LlvmParameterListType -> LlvmParameterListType -> Bool)
-> (LlvmParameterListType -> LlvmParameterListType -> Bool)
-> Eq LlvmParameterListType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmParameterListType -> LlvmParameterListType -> Bool
$c/= :: LlvmParameterListType -> LlvmParameterListType -> Bool
== :: LlvmParameterListType -> LlvmParameterListType -> Bool
$c== :: LlvmParameterListType -> LlvmParameterListType -> Bool
Eq,Int -> LlvmParameterListType -> String -> String
[LlvmParameterListType] -> String -> String
LlvmParameterListType -> String
(Int -> LlvmParameterListType -> String -> String)
-> (LlvmParameterListType -> String)
-> ([LlvmParameterListType] -> String -> String)
-> Show LlvmParameterListType
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [LlvmParameterListType] -> String -> String
$cshowList :: [LlvmParameterListType] -> String -> String
show :: LlvmParameterListType -> String
$cshow :: LlvmParameterListType -> String
showsPrec :: Int -> LlvmParameterListType -> String -> String
$cshowsPrec :: Int -> LlvmParameterListType -> String -> String
Show)


-- | Linkage type of a symbol.
--
-- The description of the constructors is copied from the Llvm Assembly Language
-- Reference Manual <http://www.llvm.org/docs/LangRef.html#linkage>, because
-- they correspond to the Llvm linkage types.
data LlvmLinkageType
  -- | Global values with internal linkage are only directly accessible by
  -- objects in the current module. In particular, linking code into a module
  -- with an internal global value may cause the internal to be renamed as
  -- necessary to avoid collisions. Because the symbol is internal to the
  -- module, all references can be updated. This corresponds to the notion
  -- of the @static@ keyword in C.
  = Internal
  -- | Globals with @linkonce@ linkage are merged with other globals of the
  -- same name when linkage occurs. This is typically used to implement
  -- inline functions, templates, or other code which must be generated
  -- in each translation unit that uses it. Unreferenced linkonce globals are
  -- allowed to be discarded.
  | LinkOnce
  -- | @weak@ linkage is exactly the same as linkonce linkage, except that
  -- unreferenced weak globals may not be discarded. This is used for globals
  -- that may be emitted in multiple translation units, but that are not
  -- guaranteed to be emitted into every translation unit that uses them. One
  -- example of this are common globals in C, such as @int X;@ at global
  -- scope.
  | Weak
  -- | @appending@ linkage may only be applied to global variables of pointer
  -- to array type. When two global variables with appending linkage are
  -- linked together, the two global arrays are appended together. This is
  -- the Llvm, typesafe, equivalent of having the system linker append
  -- together @sections@ with identical names when .o files are linked.
  | Appending
  -- | The semantics of this linkage follow the ELF model: the symbol is weak
  -- until linked, if not linked, the symbol becomes null instead of being an
  -- undefined reference.
  | ExternWeak
  -- | The symbol participates in linkage and can be used to resolve external
  --  symbol references.
  | ExternallyVisible
  -- | Alias for 'ExternallyVisible' but with explicit textual form in LLVM
  --  assembly.
  | External
  -- | Symbol is private to the module and should not appear in the symbol table
  | Private
  deriving (LlvmLinkageType -> LlvmLinkageType -> Bool
(LlvmLinkageType -> LlvmLinkageType -> Bool)
-> (LlvmLinkageType -> LlvmLinkageType -> Bool)
-> Eq LlvmLinkageType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmLinkageType -> LlvmLinkageType -> Bool
$c/= :: LlvmLinkageType -> LlvmLinkageType -> Bool
== :: LlvmLinkageType -> LlvmLinkageType -> Bool
$c== :: LlvmLinkageType -> LlvmLinkageType -> Bool
Eq)

instance Outputable LlvmLinkageType where
  ppr :: LlvmLinkageType -> SDoc
ppr Internal          = String -> SDoc
text "internal"
  ppr LinkOnce          = String -> SDoc
text "linkonce"
  ppr Weak              = String -> SDoc
text "weak"
  ppr Appending         = String -> SDoc
text "appending"
  ppr ExternWeak        = String -> SDoc
text "extern_weak"
  -- ExternallyVisible does not have a textual representation, it is
  -- the linkage type a function resolves to if no other is specified
  -- in Llvm.
  ppr ExternallyVisible = SDoc
empty
  ppr External          = String -> SDoc
text "external"
  ppr Private           = String -> SDoc
text "private"

-- -----------------------------------------------------------------------------
-- * LLVM Operations
--

-- | Llvm binary operators machine operations.
data LlvmMachOp
  = LM_MO_Add  -- ^ add two integer, floating point or vector values.
  | LM_MO_Sub  -- ^ subtract two ...
  | LM_MO_Mul  -- ^ multiply ..
  | LM_MO_UDiv -- ^ unsigned integer or vector division.
  | LM_MO_SDiv -- ^ signed integer ..
  | LM_MO_URem -- ^ unsigned integer or vector remainder (mod)
  | LM_MO_SRem -- ^ signed ...

  | LM_MO_FAdd -- ^ add two floating point or vector values.
  | LM_MO_FSub -- ^ subtract two ...
  | LM_MO_FMul -- ^ multiply ...
  | LM_MO_FDiv -- ^ divide ...
  | LM_MO_FRem -- ^ remainder ...

  -- | Left shift
  | LM_MO_Shl
  -- | Logical shift right
  -- Shift right, filling with zero
  | LM_MO_LShr
  -- | Arithmetic shift right
  -- The most significant bits of the result will be equal to the sign bit of
  -- the left operand.
  | LM_MO_AShr

  | LM_MO_And -- ^ AND bitwise logical operation.
  | LM_MO_Or  -- ^ OR bitwise logical operation.
  | LM_MO_Xor -- ^ XOR bitwise logical operation.
  deriving (LlvmMachOp -> LlvmMachOp -> Bool
(LlvmMachOp -> LlvmMachOp -> Bool)
-> (LlvmMachOp -> LlvmMachOp -> Bool) -> Eq LlvmMachOp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmMachOp -> LlvmMachOp -> Bool
$c/= :: LlvmMachOp -> LlvmMachOp -> Bool
== :: LlvmMachOp -> LlvmMachOp -> Bool
$c== :: LlvmMachOp -> LlvmMachOp -> Bool
Eq)

instance Outputable LlvmMachOp where
  ppr :: LlvmMachOp -> SDoc
ppr LM_MO_Add  = String -> SDoc
text "add"
  ppr LM_MO_Sub  = String -> SDoc
text "sub"
  ppr LM_MO_Mul  = String -> SDoc
text "mul"
  ppr LM_MO_UDiv = String -> SDoc
text "udiv"
  ppr LM_MO_SDiv = String -> SDoc
text "sdiv"
  ppr LM_MO_URem = String -> SDoc
text "urem"
  ppr LM_MO_SRem = String -> SDoc
text "srem"
  ppr LM_MO_FAdd = String -> SDoc
text "fadd"
  ppr LM_MO_FSub = String -> SDoc
text "fsub"
  ppr LM_MO_FMul = String -> SDoc
text "fmul"
  ppr LM_MO_FDiv = String -> SDoc
text "fdiv"
  ppr LM_MO_FRem = String -> SDoc
text "frem"
  ppr LM_MO_Shl  = String -> SDoc
text "shl"
  ppr LM_MO_LShr = String -> SDoc
text "lshr"
  ppr LM_MO_AShr = String -> SDoc
text "ashr"
  ppr LM_MO_And  = String -> SDoc
text "and"
  ppr LM_MO_Or   = String -> SDoc
text "or"
  ppr LM_MO_Xor  = String -> SDoc
text "xor"


-- | Llvm compare operations.
data LlvmCmpOp
  = LM_CMP_Eq  -- ^ Equal (Signed and Unsigned)
  | LM_CMP_Ne  -- ^ Not equal (Signed and Unsigned)
  | LM_CMP_Ugt -- ^ Unsigned greater than
  | LM_CMP_Uge -- ^ Unsigned greater than or equal
  | LM_CMP_Ult -- ^ Unsigned less than
  | LM_CMP_Ule -- ^ Unsigned less than or equal
  | LM_CMP_Sgt -- ^ Signed greater than
  | LM_CMP_Sge -- ^ Signed greater than or equal
  | LM_CMP_Slt -- ^ Signed less than
  | LM_CMP_Sle -- ^ Signed less than or equal

  -- Float comparisons. GHC uses a mix of ordered and unordered float
  -- comparisons.
  | LM_CMP_Feq -- ^ Float equal
  | LM_CMP_Fne -- ^ Float not equal
  | LM_CMP_Fgt -- ^ Float greater than
  | LM_CMP_Fge -- ^ Float greater than or equal
  | LM_CMP_Flt -- ^ Float less than
  | LM_CMP_Fle -- ^ Float less than or equal
  deriving (LlvmCmpOp -> LlvmCmpOp -> Bool
(LlvmCmpOp -> LlvmCmpOp -> Bool)
-> (LlvmCmpOp -> LlvmCmpOp -> Bool) -> Eq LlvmCmpOp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmCmpOp -> LlvmCmpOp -> Bool
$c/= :: LlvmCmpOp -> LlvmCmpOp -> Bool
== :: LlvmCmpOp -> LlvmCmpOp -> Bool
$c== :: LlvmCmpOp -> LlvmCmpOp -> Bool
Eq)

instance Outputable LlvmCmpOp where
  ppr :: LlvmCmpOp -> SDoc
ppr LM_CMP_Eq  = String -> SDoc
text "eq"
  ppr LM_CMP_Ne  = String -> SDoc
text "ne"
  ppr LM_CMP_Ugt = String -> SDoc
text "ugt"
  ppr LM_CMP_Uge = String -> SDoc
text "uge"
  ppr LM_CMP_Ult = String -> SDoc
text "ult"
  ppr LM_CMP_Ule = String -> SDoc
text "ule"
  ppr LM_CMP_Sgt = String -> SDoc
text "sgt"
  ppr LM_CMP_Sge = String -> SDoc
text "sge"
  ppr LM_CMP_Slt = String -> SDoc
text "slt"
  ppr LM_CMP_Sle = String -> SDoc
text "sle"
  ppr LM_CMP_Feq = String -> SDoc
text "oeq"
  ppr LM_CMP_Fne = String -> SDoc
text "une"
  ppr LM_CMP_Fgt = String -> SDoc
text "ogt"
  ppr LM_CMP_Fge = String -> SDoc
text "oge"
  ppr LM_CMP_Flt = String -> SDoc
text "olt"
  ppr LM_CMP_Fle = String -> SDoc
text "ole"


-- | Llvm cast operations.
data LlvmCastOp
  = LM_Trunc    -- ^ Integer truncate
  | LM_Zext     -- ^ Integer extend (zero fill)
  | LM_Sext     -- ^ Integer extend (sign fill)
  | LM_Fptrunc  -- ^ Float truncate
  | LM_Fpext    -- ^ Float extend
  | LM_Fptoui   -- ^ Float to unsigned Integer
  | LM_Fptosi   -- ^ Float to signed Integer
  | LM_Uitofp   -- ^ Unsigned Integer to Float
  | LM_Sitofp   -- ^ Signed Int to Float
  | LM_Ptrtoint -- ^ Pointer to Integer
  | LM_Inttoptr -- ^ Integer to Pointer
  | LM_Bitcast  -- ^ Cast between types where no bit manipulation is needed
  deriving (LlvmCastOp -> LlvmCastOp -> Bool
(LlvmCastOp -> LlvmCastOp -> Bool)
-> (LlvmCastOp -> LlvmCastOp -> Bool) -> Eq LlvmCastOp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmCastOp -> LlvmCastOp -> Bool
$c/= :: LlvmCastOp -> LlvmCastOp -> Bool
== :: LlvmCastOp -> LlvmCastOp -> Bool
$c== :: LlvmCastOp -> LlvmCastOp -> Bool
Eq)

instance Outputable LlvmCastOp where
  ppr :: LlvmCastOp -> SDoc
ppr LM_Trunc    = String -> SDoc
text "trunc"
  ppr LM_Zext     = String -> SDoc
text "zext"
  ppr LM_Sext     = String -> SDoc
text "sext"
  ppr LM_Fptrunc  = String -> SDoc
text "fptrunc"
  ppr LM_Fpext    = String -> SDoc
text "fpext"
  ppr LM_Fptoui   = String -> SDoc
text "fptoui"
  ppr LM_Fptosi   = String -> SDoc
text "fptosi"
  ppr LM_Uitofp   = String -> SDoc
text "uitofp"
  ppr LM_Sitofp   = String -> SDoc
text "sitofp"
  ppr LM_Ptrtoint = String -> SDoc
text "ptrtoint"
  ppr LM_Inttoptr = String -> SDoc
text "inttoptr"
  ppr LM_Bitcast  = String -> SDoc
text "bitcast"


-- -----------------------------------------------------------------------------
-- * Floating point conversion
--

-- | Convert a Haskell Double to an LLVM hex encoded floating point form. In
-- Llvm float literals can be printed in a big-endian hexadecimal format,
-- regardless of underlying architecture.
--
-- See Note [LLVM Float Types].
ppDouble :: Double -> SDoc
ppDouble :: Double -> SDoc
ppDouble d :: Double
d
  = let bs :: [Int]
bs     = Double -> [Int]
doubleToBytes Double
d
        hex :: a -> String
hex d' :: a
d' = case a -> String -> String
forall a. (Integral a, Show a) => a -> String -> String
showHex a
d' "" of
                     []    -> String -> String
forall a. HasCallStack => String -> a
error "dToStr: too few hex digits for float"
                     [x :: Char
x]   -> ['0',Char
x]
                     [x :: Char
x,y :: Char
y] -> [Char
x,Char
y]
                     _     -> String -> String
forall a. HasCallStack => String -> a
error "dToStr: too many hex digits for float"

        str :: String
str  = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ [String] -> [String]
forall a. [a] -> [a]
fixEndian ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ (Int -> String) -> [Int] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Int -> String
forall a. (Integral a, Show a) => a -> String
hex [Int]
bs
    in  String -> SDoc
text "0x" SDoc -> SDoc -> SDoc
<> String -> SDoc
text String
str

-- Note [LLVM Float Types]
-- ~~~~~~~~~~~~~~~~~~~~~~~
-- We use 'ppDouble' for both printing Float and Double floating point types. This is
-- as LLVM expects all floating point constants (single & double) to be in IEEE
-- 754 Double precision format. However, for single precision numbers (Float)
-- they should be *representable* in IEEE 754 Single precision format. So the
-- easiest way to do this is to narrow and widen again.
-- (i.e., Double -> Float -> Double). We must be careful doing this that GHC
-- doesn't optimize that away.

-- Note [narrowFp & widenFp]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~
-- NOTE: we use float2Double & co directly as GHC likes to optimize away
-- successive calls of 'realToFrac', defeating the narrowing. (Bug #7600).
-- 'realToFrac' has inconsistent behaviour with optimisation as well that can
-- also cause issues, these methods don't.

narrowFp :: Double -> Float
{-# NOINLINE narrowFp #-}
narrowFp :: Double -> Float
narrowFp = Double -> Float
double2Float

widenFp :: Float -> Double
{-# NOINLINE widenFp #-}
widenFp :: Float -> Double
widenFp = Float -> Double
float2Double

ppFloat :: Float -> SDoc
ppFloat :: Float -> SDoc
ppFloat = Double -> SDoc
ppDouble (Double -> SDoc) -> (Float -> Double) -> Float -> SDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Float -> Double
widenFp

-- | Reverse or leave byte data alone to fix endianness on this target.
fixEndian :: [a] -> [a]
#if defined(WORDS_BIGENDIAN)
fixEndian = id
#else
fixEndian :: [a] -> [a]
fixEndian = [a] -> [a]
forall a. [a] -> [a]
reverse
#endif


--------------------------------------------------------------------------------
-- * Misc functions
--------------------------------------------------------------------------------

ppCommaJoin :: (Outputable a) => [a] -> SDoc
ppCommaJoin :: [a] -> SDoc
ppCommaJoin strs :: [a]
strs = [SDoc] -> SDoc
hsep ([SDoc] -> SDoc) -> [SDoc] -> SDoc
forall a b. (a -> b) -> a -> b
$ SDoc -> [SDoc] -> [SDoc]
punctuate SDoc
comma ((a -> SDoc) -> [a] -> [SDoc]
forall a b. (a -> b) -> [a] -> [b]
map a -> SDoc
forall a. Outputable a => a -> SDoc
ppr [a]
strs)

ppSpaceJoin :: (Outputable a) => [a] -> SDoc
ppSpaceJoin :: [a] -> SDoc
ppSpaceJoin strs :: [a]
strs = [SDoc] -> SDoc
hsep ((a -> SDoc) -> [a] -> [SDoc]
forall a b. (a -> b) -> [a] -> [b]
map a -> SDoc
forall a. Outputable a => a -> SDoc
ppr [a]
strs)