PageRenderTime 63ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

/compiler/llvmGen/LlvmCodeGen/Base.hs

https://bitbucket.org/carter/ghc
Haskell | 261 lines | 139 code | 56 blank | 66 comment | 0 complexity | 13cb34de87304383f5966d997f3ab69b MD5 | raw file
  1. -- ----------------------------------------------------------------------------
  2. -- | Base LLVM Code Generation module
  3. --
  4. -- Contains functions useful through out the code generator.
  5. --
  6. module LlvmCodeGen.Base (
  7. LlvmCmmDecl, LlvmBasicBlock,
  8. LlvmUnresData, LlvmData, UnresLabel, UnresStatic,
  9. LlvmVersion, defaultLlvmVersion, minSupportLlvmVersion,
  10. maxSupportLlvmVersion,
  11. LlvmEnv, initLlvmEnv, clearVars, varLookup, varInsert,
  12. funLookup, funInsert, getLlvmVer, setLlvmVer, getLlvmPlatform,
  13. getDflags, ghcInternalFunctions,
  14. cmmToLlvmType, widthToLlvmFloat, widthToLlvmInt, llvmFunTy,
  15. llvmFunSig, llvmStdFunAttrs, llvmFunAlign, llvmInfAlign,
  16. llvmPtrBits, mkLlvmFunc, tysToParams,
  17. strCLabel_llvm, genCmmLabelRef, genStringLabelRef
  18. ) where
  19. #include "HsVersions.h"
  20. import Llvm
  21. import LlvmCodeGen.Regs
  22. import CLabel
  23. import CgUtils ( activeStgRegs )
  24. import DynFlags
  25. import FastString
  26. import OldCmm
  27. import qualified Outputable as Outp
  28. import Platform
  29. import UniqFM
  30. import Unique
  31. -- ----------------------------------------------------------------------------
  32. -- * Some Data Types
  33. --
  34. type LlvmCmmDecl = GenCmmDecl [LlvmData] (Maybe CmmStatics) (ListGraph LlvmStatement)
  35. type LlvmBasicBlock = GenBasicBlock LlvmStatement
  36. -- | Unresolved code.
  37. -- Of the form: (data label, data type, unresolved data)
  38. type LlvmUnresData = (CLabel, Section, LlvmType, [UnresStatic])
  39. -- | Top level LLVM Data (globals and type aliases)
  40. type LlvmData = ([LMGlobal], [LlvmType])
  41. -- | An unresolved Label.
  42. --
  43. -- Labels are unresolved when we haven't yet determined if they are defined in
  44. -- the module we are currently compiling, or an external one.
  45. type UnresLabel = CmmLit
  46. type UnresStatic = Either UnresLabel LlvmStatic
  47. -- ----------------------------------------------------------------------------
  48. -- * Type translations
  49. --
  50. -- | Translate a basic CmmType to an LlvmType.
  51. cmmToLlvmType :: CmmType -> LlvmType
  52. cmmToLlvmType ty | isFloatType ty = widthToLlvmFloat $ typeWidth ty
  53. | otherwise = widthToLlvmInt $ typeWidth ty
  54. -- | Translate a Cmm Float Width to a LlvmType.
  55. widthToLlvmFloat :: Width -> LlvmType
  56. widthToLlvmFloat W32 = LMFloat
  57. widthToLlvmFloat W64 = LMDouble
  58. widthToLlvmFloat W80 = LMFloat80
  59. widthToLlvmFloat W128 = LMFloat128
  60. widthToLlvmFloat w = panic $ "widthToLlvmFloat: Bad float size: " ++ show w
  61. -- | Translate a Cmm Bit Width to a LlvmType.
  62. widthToLlvmInt :: Width -> LlvmType
  63. widthToLlvmInt w = LMInt $ widthInBits w
  64. -- | GHC Call Convention for LLVM
  65. llvmGhcCC :: DynFlags -> LlvmCallConvention
  66. llvmGhcCC dflags
  67. | platformUnregisterised (targetPlatform dflags) = CC_Ccc
  68. | otherwise = CC_Ncc 10
  69. -- | Llvm Function type for Cmm function
  70. llvmFunTy :: DynFlags -> LlvmType
  71. llvmFunTy dflags = LMFunction $ llvmFunSig' dflags (fsLit "a") ExternallyVisible
  72. -- | Llvm Function signature
  73. llvmFunSig :: LlvmEnv -> CLabel -> LlvmLinkageType -> LlvmFunctionDecl
  74. llvmFunSig env lbl link
  75. = llvmFunSig' (getDflags env) (strCLabel_llvm env lbl) link
  76. llvmFunSig' :: DynFlags -> LMString -> LlvmLinkageType -> LlvmFunctionDecl
  77. llvmFunSig' dflags lbl link
  78. = let toParams x | isPointer x = (x, [NoAlias, NoCapture])
  79. | otherwise = (x, [])
  80. in LlvmFunctionDecl lbl link (llvmGhcCC dflags) LMVoid FixedArgs
  81. (map (toParams . getVarType) (llvmFunArgs dflags))
  82. (llvmFunAlign dflags)
  83. -- | Create a Haskell function in LLVM.
  84. mkLlvmFunc :: LlvmEnv -> CLabel -> LlvmLinkageType -> LMSection -> LlvmBlocks
  85. -> LlvmFunction
  86. mkLlvmFunc env lbl link sec blks
  87. = let dflags = getDflags env
  88. funDec = llvmFunSig env lbl link
  89. funArgs = map (fsLit . getPlainName) (llvmFunArgs dflags)
  90. in LlvmFunction funDec funArgs llvmStdFunAttrs sec blks
  91. -- | Alignment to use for functions
  92. llvmFunAlign :: DynFlags -> LMAlign
  93. llvmFunAlign dflags = Just (wORD_SIZE dflags)
  94. -- | Alignment to use for into tables
  95. llvmInfAlign :: DynFlags -> LMAlign
  96. llvmInfAlign dflags = Just (wORD_SIZE dflags)
  97. -- | A Function's arguments
  98. llvmFunArgs :: DynFlags -> [LlvmVar]
  99. llvmFunArgs dflags = map (lmGlobalRegArg dflags) (activeStgRegs platform)
  100. where platform = targetPlatform dflags
  101. -- | Llvm standard fun attributes
  102. llvmStdFunAttrs :: [LlvmFuncAttr]
  103. llvmStdFunAttrs = [NoUnwind]
  104. -- | Convert a list of types to a list of function parameters
  105. -- (each with no parameter attributes)
  106. tysToParams :: [LlvmType] -> [LlvmParameter]
  107. tysToParams = map (\ty -> (ty, []))
  108. -- | Pointer width
  109. llvmPtrBits :: DynFlags -> Int
  110. llvmPtrBits dflags = widthInBits $ typeWidth $ gcWord dflags
  111. -- ----------------------------------------------------------------------------
  112. -- * Llvm Version
  113. --
  114. -- | LLVM Version Number
  115. type LlvmVersion = Int
  116. -- | The LLVM Version we assume if we don't know
  117. defaultLlvmVersion :: LlvmVersion
  118. defaultLlvmVersion = 30
  119. minSupportLlvmVersion :: LlvmVersion
  120. minSupportLlvmVersion = 28
  121. maxSupportLlvmVersion :: LlvmVersion
  122. maxSupportLlvmVersion = 31
  123. -- ----------------------------------------------------------------------------
  124. -- * Environment Handling
  125. --
  126. -- two maps, one for functions and one for local vars.
  127. newtype LlvmEnv = LlvmEnv (LlvmEnvMap, LlvmEnvMap, LlvmVersion, DynFlags)
  128. type LlvmEnvMap = UniqFM LlvmType
  129. -- | Get initial Llvm environment.
  130. initLlvmEnv :: DynFlags -> LlvmEnv
  131. initLlvmEnv dflags = LlvmEnv (initFuncs, emptyUFM, defaultLlvmVersion, dflags)
  132. where initFuncs = listToUFM $ [ (n, LMFunction ty) | (n, ty) <- ghcInternalFunctions dflags ]
  133. -- | Here we pre-initialise some functions that are used internally by GHC
  134. -- so as to make sure they have the most general type in the case that
  135. -- user code also uses these functions but with a different type than GHC
  136. -- internally. (Main offender is treating return type as 'void' instead of
  137. -- 'void *'. Fixes trac #5486.
  138. ghcInternalFunctions :: DynFlags -> [(LMString, LlvmFunctionDecl)]
  139. ghcInternalFunctions dflags =
  140. [ mk "memcpy" i8Ptr [i8Ptr, i8Ptr, llvmWord dflags]
  141. , mk "memmove" i8Ptr [i8Ptr, i8Ptr, llvmWord dflags]
  142. , mk "memset" i8Ptr [i8Ptr, llvmWord dflags, llvmWord dflags]
  143. , mk "newSpark" (llvmWord dflags) [i8Ptr, i8Ptr]
  144. ]
  145. where
  146. mk n ret args =
  147. let n' = fsLit n
  148. in (n', LlvmFunctionDecl n' ExternallyVisible CC_Ccc ret
  149. FixedArgs (tysToParams args) Nothing)
  150. -- | Clear variables from the environment.
  151. clearVars :: LlvmEnv -> LlvmEnv
  152. clearVars (LlvmEnv (e1, _, n, p)) = {-# SCC "llvm_env_clear" #-}
  153. LlvmEnv (e1, emptyUFM, n, p)
  154. -- | Insert local variables into the environment.
  155. varInsert :: Uniquable key => key -> LlvmType -> LlvmEnv -> LlvmEnv
  156. varInsert s t (LlvmEnv (e1, e2, n, p)) = {-# SCC "llvm_env_vinsert" #-}
  157. LlvmEnv (e1, addToUFM e2 s t, n, p)
  158. -- | Insert functions into the environment.
  159. funInsert :: Uniquable key => key -> LlvmType -> LlvmEnv -> LlvmEnv
  160. funInsert s t (LlvmEnv (e1, e2, n, p)) = {-# SCC "llvm_env_finsert" #-}
  161. LlvmEnv (addToUFM e1 s t, e2, n, p)
  162. -- | Lookup local variables in the environment.
  163. varLookup :: Uniquable key => key -> LlvmEnv -> Maybe LlvmType
  164. varLookup s (LlvmEnv (_, e2, _, _)) = {-# SCC "llvm_env_vlookup" #-}
  165. lookupUFM e2 s
  166. -- | Lookup functions in the environment.
  167. funLookup :: Uniquable key => key -> LlvmEnv -> Maybe LlvmType
  168. funLookup s (LlvmEnv (e1, _, _, _)) = {-# SCC "llvm_env_flookup" #-}
  169. lookupUFM e1 s
  170. -- | Get the LLVM version we are generating code for
  171. getLlvmVer :: LlvmEnv -> LlvmVersion
  172. getLlvmVer (LlvmEnv (_, _, n, _)) = n
  173. -- | Set the LLVM version we are generating code for
  174. setLlvmVer :: LlvmVersion -> LlvmEnv -> LlvmEnv
  175. setLlvmVer n (LlvmEnv (e1, e2, _, p)) = LlvmEnv (e1, e2, n, p)
  176. -- | Get the platform we are generating code for
  177. getLlvmPlatform :: LlvmEnv -> Platform
  178. getLlvmPlatform (LlvmEnv (_, _, _, d)) = targetPlatform d
  179. -- | Get the DynFlags for this compilation pass
  180. getDflags :: LlvmEnv -> DynFlags
  181. getDflags (LlvmEnv (_, _, _, d)) = d
  182. -- ----------------------------------------------------------------------------
  183. -- * Label handling
  184. --
  185. -- | Pretty print a 'CLabel'.
  186. strCLabel_llvm :: LlvmEnv -> CLabel -> LMString
  187. strCLabel_llvm env l = {-# SCC "llvm_strCLabel" #-}
  188. (fsLit . toString . pprCLabel (getLlvmPlatform env)) l
  189. where dflags = getDflags env
  190. style = Outp.mkCodeStyle Outp.CStyle
  191. toString doc = Outp.renderWithStyle dflags doc style
  192. -- | Create an external definition for a 'CLabel' defined in another module.
  193. genCmmLabelRef :: LlvmEnv -> CLabel -> LMGlobal
  194. genCmmLabelRef env = genStringLabelRef (getDflags env) . strCLabel_llvm env
  195. -- | As above ('genCmmLabelRef') but taking a 'LMString', not 'CLabel'.
  196. genStringLabelRef :: DynFlags -> LMString -> LMGlobal
  197. genStringLabelRef dflags cl
  198. = let ty = LMPointer $ LMArray 0 (llvmWord dflags)
  199. in (LMGlobalVar cl ty External Nothing Nothing False, Nothing)
  200. -- ----------------------------------------------------------------------------
  201. -- * Misc
  202. --
  203. -- | Error function
  204. panic :: String -> a
  205. panic s = Outp.panic $ "LlvmCodeGen.Base." ++ s