Add new LLVM code generator to GHC. (Version 2)
authorDavid Terei <davidterei@gmail.com>
Tue, 15 Jun 2010 09:47:14 +0000 (09:47 +0000)
committerDavid Terei <davidterei@gmail.com>
Tue, 15 Jun 2010 09:47:14 +0000 (09:47 +0000)
This was done as part of an honours thesis at UNSW, the paper describing the
work and results can be found at:

http://www.cse.unsw.edu.au/~pls/thesis/davidt-thesis.pdf

A Homepage for the backend can be found at:

http://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/Backends/LLVM

Quick summary of performance is that for the 'nofib' benchmark suite, runtimes
are within 5% slower than the NCG and generally better than the C code
generator.  For some code though, such as the DPH projects benchmark, the LLVM
code generator outperforms the NCG and C code generator by about a 25%
reduction in run times.

33 files changed:
compiler/cmm/Cmm.hs
compiler/cmm/CmmUtils.hs
compiler/codeGen/CgForeignCall.hs
compiler/codeGen/CgUtils.hs
compiler/ghc.cabal.in
compiler/ghc.mk
compiler/llvmGen/Llvm.hs [new file with mode: 0644]
compiler/llvmGen/Llvm/AbsSyn.hs [new file with mode: 0644]
compiler/llvmGen/Llvm/PpLlvm.hs [new file with mode: 0644]
compiler/llvmGen/Llvm/Types.hs [new file with mode: 0644]
compiler/llvmGen/LlvmCodeGen.hs [new file with mode: 0644]
compiler/llvmGen/LlvmCodeGen/Base.hs [new file with mode: 0644]
compiler/llvmGen/LlvmCodeGen/CodeGen.hs [new file with mode: 0644]
compiler/llvmGen/LlvmCodeGen/Data.hs [new file with mode: 0644]
compiler/llvmGen/LlvmCodeGen/Ppr.hs [new file with mode: 0644]
compiler/llvmGen/LlvmCodeGen/Regs.hs [new file with mode: 0644]
compiler/main/CodeOutput.lhs
compiler/main/DriverPhases.hs
compiler/main/DriverPipeline.hs
compiler/main/DynFlags.hs
compiler/main/SysTools.lhs
compiler/nativeGen/Alpha/Regs.hs
compiler/nativeGen/AsmCodeGen.lhs
compiler/nativeGen/PPC/CodeGen.hs
compiler/nativeGen/PPC/Regs.hs
compiler/nativeGen/SPARC/CodeGen/Base.hs
compiler/nativeGen/SPARC/Regs.hs
compiler/nativeGen/X86/CodeGen.hs
compiler/nativeGen/X86/Regs.hs
compiler/typecheck/TcForeign.lhs
driver/mangler/ghc-asm.lprl
mk/config.mk.in
rules/build-perl.mk

index c48269e..5c02622 100644 (file)
@@ -181,6 +181,7 @@ data ClosureTypeInfo
 
 data CmmReturnInfo = CmmMayReturn
                    | CmmNeverReturns
 
 data CmmReturnInfo = CmmMayReturn
                    | CmmNeverReturns
+    deriving ( Eq )
 
 -- TODO: These types may need refinement
 data ProfilingInfo = ProfilingInfo CmmLit CmmLit -- closure_type, closure_desc
 
 -- TODO: These types may need refinement
 data ProfilingInfo = ProfilingInfo CmmLit CmmLit -- closure_type, closure_desc
index e01d8f5..69320a2 100644 (file)
@@ -6,7 +6,7 @@
 --
 -----------------------------------------------------------------------------
 
 --
 -----------------------------------------------------------------------------
 
-module CmmUtils( 
+module CmmUtils(
        CmmStmts, noStmts, oneStmt, mkStmts, plusStmts, stmtList,
        isNopStmt,
 
        CmmStmts, noStmts, oneStmt, mkStmts, plusStmts, stmtList,
        isNopStmt,
 
index 901dd96..ce689c4 100644 (file)
@@ -122,9 +122,10 @@ emitForeignCall' safety results target args vols _srt ret
   | not (playSafe safety) = do
     temp_args <- load_args_into_temps args
     let (caller_save, caller_load) = callerSaveVolatileRegs vols
   | not (playSafe safety) = do
     temp_args <- load_args_into_temps args
     let (caller_save, caller_load) = callerSaveVolatileRegs vols
+    let caller_load' = if ret == CmmNeverReturns then [] else caller_load
     stmtsC caller_save
     stmtC (CmmCall target results temp_args CmmUnsafe ret)
     stmtsC caller_save
     stmtC (CmmCall target results temp_args CmmUnsafe ret)
-    stmtsC caller_load
+    stmtsC caller_load'
 
   | otherwise = do
     -- Both 'id' and 'new_base' are GCKindNonPtr because they're
 
   | otherwise = do
     -- Both 'id' and 'new_base' are GCKindNonPtr because they're
index f8b41a0..d22fee1 100644 (file)
@@ -26,6 +26,7 @@ module CgUtils (
        tagToClosure,
 
         callerSaveVolatileRegs, get_GlobalReg_addr,
        tagToClosure,
 
         callerSaveVolatileRegs, get_GlobalReg_addr,
+       activeStgRegs, fixStgRegisters,
 
        cmmAndWord, cmmOrWord, cmmNegate, cmmEqWord, cmmNeWord,
         cmmUGtWord,
 
        cmmAndWord, cmmOrWord, cmmNegate, cmmEqWord, cmmNeWord,
         cmmUGtWord,
@@ -423,33 +424,6 @@ callerSaveVolatileRegs vols = (caller_save, caller_load)
                        : next
        | otherwise = next
 
                        : next
        | otherwise = next
 
--- -----------------------------------------------------------------------------
--- Global registers
-
--- We map STG registers onto appropriate CmmExprs.  Either they map
--- to real machine registers or stored as offsets from BaseReg.  Given
--- a GlobalReg, get_GlobalReg_addr always produces the 
--- register table address for it.
--- (See also get_GlobalReg_reg_or_addr in MachRegs)
-
-get_GlobalReg_addr              :: GlobalReg -> CmmExpr
-get_GlobalReg_addr BaseReg = regTableOffset 0
-get_GlobalReg_addr mid     = get_Regtable_addr_from_offset 
-                               (globalRegType mid) (baseRegOffset mid)
-
--- Calculate a literal representing an offset into the register table.
--- Used when we don't have an actual BaseReg to offset from.
-regTableOffset n = 
-  CmmLit (CmmLabelOff mkMainCapabilityLabel (oFFSET_Capability_r + n))
-
-get_Regtable_addr_from_offset   :: CmmType -> Int -> CmmExpr
-get_Regtable_addr_from_offset rep offset =
-#ifdef REG_Base
-  CmmRegOff (CmmGlobal BaseReg) offset
-#else
-  regTableOffset offset
-#endif
-
 
 -- | Returns @True@ if this global register is stored in a caller-saves
 -- machine register.
 
 -- | Returns @True@ if this global register is stored in a caller-saves
 -- machine register.
@@ -1010,3 +984,181 @@ clHasCafRefs (ClosureInfo {closureSRT = srt}) =
   case srt of NoC_SRT -> NoCafRefs
               _       -> MayHaveCafRefs
 clHasCafRefs (ConInfo {}) = NoCafRefs
   case srt of NoC_SRT -> NoCafRefs
               _       -> MayHaveCafRefs
 clHasCafRefs (ConInfo {}) = NoCafRefs
+
+-- -----------------------------------------------------------------------------
+--
+-- STG/Cmm GlobalReg
+--
+-- -----------------------------------------------------------------------------
+
+-- | Here is where the STG register map is defined for each target arch.
+-- The order matters (for the llvm backend anyway)! We must make sure to
+-- maintain the order here with the order used in the LLVM calling conventions.
+-- Note that also, this isn't all registers, just the ones that are currently
+-- possbily mapped to real registers.
+activeStgRegs :: [GlobalReg]
+activeStgRegs = [
+#ifdef REG_Base
+    BaseReg
+#endif
+#ifdef REG_Sp
+    ,Sp
+#endif
+#ifdef REG_Hp
+    ,Hp
+#endif
+#ifdef REG_R1
+    ,VanillaReg 1 VGcPtr
+#endif
+#ifdef REG_R2
+    ,VanillaReg 2 VGcPtr
+#endif
+#ifdef REG_R3
+    ,VanillaReg 3 VGcPtr
+#endif
+#ifdef REG_R4
+    ,VanillaReg 4 VGcPtr
+#endif
+#ifdef REG_R5
+    ,VanillaReg 5 VGcPtr
+#endif
+#ifdef REG_R6
+    ,VanillaReg 6 VGcPtr
+#endif
+#ifdef REG_R7
+    ,VanillaReg 7 VGcPtr
+#endif
+#ifdef REG_R8
+    ,VanillaReg 8 VGcPtr
+#endif
+#ifdef REG_SpLim
+    ,SpLim
+#endif
+#ifdef REG_F1
+    ,FloatReg 1
+#endif
+#ifdef REG_F2
+    ,FloatReg 2
+#endif
+#ifdef REG_F3
+    ,FloatReg 3
+#endif
+#ifdef REG_F4
+    ,FloatReg 4
+#endif
+#ifdef REG_D1
+    ,DoubleReg 1
+#endif
+#ifdef REG_D2
+    ,DoubleReg 2
+#endif
+    ]
+  
+-- | We map STG registers onto appropriate CmmExprs.  Either they map
+-- to real machine registers or stored as offsets from BaseReg.  Given
+-- a GlobalReg, get_GlobalReg_addr always produces the 
+-- register table address for it.
+get_GlobalReg_addr :: GlobalReg -> CmmExpr
+get_GlobalReg_addr BaseReg = regTableOffset 0
+get_GlobalReg_addr mid     = get_Regtable_addr_from_offset 
+                               (globalRegType mid) (baseRegOffset mid)
+
+-- Calculate a literal representing an offset into the register table.
+-- Used when we don't have an actual BaseReg to offset from.
+regTableOffset n = 
+  CmmLit (CmmLabelOff mkMainCapabilityLabel (oFFSET_Capability_r + n))
+
+get_Regtable_addr_from_offset   :: CmmType -> Int -> CmmExpr
+get_Regtable_addr_from_offset rep offset =
+#ifdef REG_Base
+  CmmRegOff (CmmGlobal BaseReg) offset
+#else
+  regTableOffset offset
+#endif
+
+-- | Fixup global registers so that they assign to locations within the
+-- RegTable if they aren't pinned for the current target.
+fixStgRegisters :: RawCmmTop -> RawCmmTop
+fixStgRegisters top@(CmmData _ _) = top
+
+fixStgRegisters (CmmProc info lbl params (ListGraph blocks)) =
+  let blocks' = map fixStgRegBlock blocks
+  in CmmProc info lbl params $ ListGraph blocks'
+
+fixStgRegBlock :: CmmBasicBlock -> CmmBasicBlock
+fixStgRegBlock (BasicBlock id stmts) =
+  let stmts' = map fixStgRegStmt stmts
+  in BasicBlock id stmts'
+
+fixStgRegStmt :: CmmStmt -> CmmStmt
+fixStgRegStmt stmt
+  = case stmt of
+        CmmAssign (CmmGlobal reg) src ->
+            let src' = fixStgRegExpr src
+                baseAddr = get_GlobalReg_addr reg
+            in case reg `elem` activeStgRegs of
+                True  -> CmmAssign (CmmGlobal reg) src'
+                False -> CmmStore baseAddr src'   
+        
+        CmmAssign reg src ->
+            let src' = fixStgRegExpr src
+            in CmmAssign reg src'
+
+        CmmStore addr src -> CmmStore (fixStgRegExpr addr) (fixStgRegExpr src)
+
+        CmmCall target regs args srt returns ->
+            let target' = case target of
+                    CmmCallee e conv -> CmmCallee (fixStgRegExpr e) conv
+                    other            -> other
+                args' = map (\(CmmHinted arg hint) ->
+                                (CmmHinted (fixStgRegExpr arg) hint)) args
+            in CmmCall target' regs args' srt returns
+
+        CmmCondBranch test dest -> CmmCondBranch (fixStgRegExpr test) dest
+
+        CmmSwitch expr ids -> CmmSwitch (fixStgRegExpr expr) ids
+
+        CmmJump addr regs -> CmmJump (fixStgRegExpr addr) regs
+
+        -- CmmNop, CmmComment, CmmBranch, CmmReturn
+        _other -> stmt
+
+
+fixStgRegExpr :: CmmExpr ->  CmmExpr
+fixStgRegExpr expr
+  = case expr of
+        CmmLoad addr ty -> CmmLoad (fixStgRegExpr addr) ty
+
+        CmmMachOp mop args -> CmmMachOp mop args'
+            where args' = map fixStgRegExpr args
+
+        CmmReg (CmmGlobal reg) ->
+            -- Replace register leaves with appropriate StixTrees for
+            -- the given target.  MagicIds which map to a reg on this
+            -- arch are left unchanged.  For the rest, BaseReg is taken
+            -- to mean the address of the reg table in MainCapability,
+            -- and for all others we generate an indirection to its
+            -- location in the register table.
+            case reg `elem` activeStgRegs of
+                True  -> expr
+                False ->
+                    let baseAddr = get_GlobalReg_addr reg
+                    in case reg of
+                        BaseReg -> fixStgRegExpr baseAddr
+                        _other  -> fixStgRegExpr
+                                    (CmmLoad baseAddr (globalRegType reg))
+
+        CmmRegOff (CmmGlobal reg) offset ->
+            -- RegOf leaves are just a shorthand form. If the reg maps
+            -- to a real reg, we keep the shorthand, otherwise, we just
+            -- expand it and defer to the above code.
+            case reg `elem` activeStgRegs of
+                True  -> expr
+                False -> fixStgRegExpr (CmmMachOp (MO_Add wordWidth) [
+                                    CmmReg (CmmGlobal reg),
+                                    CmmLit (CmmInt (fromIntegral offset)
+                                                wordWidth)])
+
+        -- CmmLit, CmmReg (CmmLocal), CmmStackSlot
+        _other -> expr
+
index 448d27b..479e56d 100644 (file)
@@ -130,7 +130,9 @@ Library
         ghci
         hsSyn
         iface
         ghci
         hsSyn
         iface
+        llvmGen
         main
         main
+        nativeGen
         parser
         prelude
         profiling
         parser
         prelude
         profiling
@@ -153,6 +155,16 @@ Library
         Id
         IdInfo
         Literal
         Id
         IdInfo
         Literal
+        Llvm
+        Llvm.AbsSyn
+        Llvm.PpLlvm
+        Llvm.Types
+        LlvmCodeGen
+        LlvmCodeGen.Base
+        LlvmCodeGen.CodeGen
+        LlvmCodeGen.Data
+        LlvmCodeGen.Ppr
+        LlvmCodeGen.Regs
         MkId
         Module
         Name
         MkId
         Module
         Name
@@ -198,6 +210,7 @@ Library
         MkZipCfg
         MkZipCfgCmm
         OptimizationFuel
         MkZipCfg
         MkZipCfgCmm
         OptimizationFuel
+        PprBase
         PprC
         PprCmm
         PprCmmZ
         PprC
         PprCmm
         PprCmmZ
@@ -447,10 +460,9 @@ Library
         VectUtils
         Vectorise
 
         VectUtils
         Vectorise
 
+    -- We only need to expose more modules as some of the ncg code is used
+    -- by the LLVM backend so its always included
     if flag(ncg)
     if flag(ncg)
-        hs-source-dirs:
-            nativeGen
-
         Exposed-Modules:
             AsmCodeGen
             TargetReg
         Exposed-Modules:
             AsmCodeGen
             TargetReg
@@ -459,7 +471,6 @@ Library
             Size
             Reg
             RegClass
             Size
             Reg
             RegClass
-            PprBase
             PIC
             Platform
             Alpha.Regs
             PIC
             Platform
             Alpha.Regs
index 1c61494..9cbacf4 100644 (file)
@@ -43,6 +43,12 @@ compiler/stage2/package-data.mk : $(compiler_CONFIG_HS)
 compiler/stage3/package-data.mk : $(compiler_CONFIG_HS)
 endif
 
 compiler/stage3/package-data.mk : $(compiler_CONFIG_HS)
 endif
 
+ifeq "$(GhcEnableTablesNextToCode)" "NO"
+GhcWithLlvmCodeGen = YES
+else
+GhcWithLlvmCodeGen = NO
+endif
+
 $(compiler_CONFIG_HS) : mk/config.mk mk/project.mk
        "$(RM)" $(RM_OPTS) $@
        @echo "Creating $@ ... "
 $(compiler_CONFIG_HS) : mk/config.mk mk/project.mk
        "$(RM)" $(RM_OPTS) $@
        @echo "Creating $@ ... "
@@ -67,6 +73,8 @@ $(compiler_CONFIG_HS) : mk/config.mk mk/project.mk
        @echo "cGhcWithInterpreter   = \"$(GhcWithInterpreter)\"" >> $@
        @echo "cGhcWithNativeCodeGen :: String" >> $@
        @echo "cGhcWithNativeCodeGen = \"$(GhcWithNativeCodeGen)\"" >> $@
        @echo "cGhcWithInterpreter   = \"$(GhcWithInterpreter)\"" >> $@
        @echo "cGhcWithNativeCodeGen :: String" >> $@
        @echo "cGhcWithNativeCodeGen = \"$(GhcWithNativeCodeGen)\"" >> $@
+       @echo "cGhcWithLlvmCodeGen   :: String" >> $@
+       @echo "cGhcWithLlvmCodeGen   = \"$(GhcWithLlvmCodeGen)\"" >> $@
        @echo "cGhcWithSMP           :: String" >> $@
        @echo "cGhcWithSMP           = \"$(GhcWithSMP)\"" >> $@
        @echo "cGhcRTSWays           :: String" >> $@
        @echo "cGhcWithSMP           :: String" >> $@
        @echo "cGhcWithSMP           = \"$(GhcWithSMP)\"" >> $@
        @echo "cGhcRTSWays           :: String" >> $@
@@ -313,7 +321,7 @@ ifeq "$(GhcEnableTablesNextToCode) $(GhcUnregisterised)" "YES NO"
 # or not?
 # XXX This should logically be a CPP option, but there doesn't seem to
 # be a flag for that
 # or not?
 # XXX This should logically be a CPP option, but there doesn't seem to
 # be a flag for that
-compiler_stage2_CONFIGURE_OPTS += --ghc-option=-DGHCI_TABLES_NEXT_TO_CODE
+compiler_CONFIGURE_OPTS += --ghc-option=-DGHCI_TABLES_NEXT_TO_CODE
 endif
 
 # Should the debugger commands be enabled?
 endif
 
 # Should the debugger commands be enabled?
@@ -338,6 +346,8 @@ ifeq "$(HOSTPLATFORM)" "ia64-unknown-linux"
 # needed for generating proper relocation in large binaries: trac #856
 compiler_CONFIGURE_OPTS += --ld-option=-Wl,--relax
 endif
 # needed for generating proper relocation in large binaries: trac #856
 compiler_CONFIGURE_OPTS += --ld-option=-Wl,--relax
 endif
+else
+compiler_CONFIGURE_OPTS += --ghc-option=-DNO_REGS
 endif
 
 # We need to turn on profiling either if we have been asked to
 endif
 
 # We need to turn on profiling either if we have been asked to
diff --git a/compiler/llvmGen/Llvm.hs b/compiler/llvmGen/Llvm.hs
new file mode 100644 (file)
index 0000000..7a322bd
--- /dev/null
@@ -0,0 +1,52 @@
+-- ----------------------------------------------------------------------------
+-- | This module supplies bindings to generate Llvm IR from Haskell
+-- (<http://www.llvm.org/docs/LangRef.html>).
+--
+-- Note: this module is developed in a demand driven way. It is no complete
+-- LLVM binding library in Haskell, but enough to generate code for GHC.
+--
+-- This code is derived from code taken from the Essential Haskell Compiler
+-- (EHC) project (<http://www.cs.uu.nl/wiki/Ehc/WebHome>).
+--
+
+module Llvm (
+
+        -- * Modules, Functions and Blocks
+        LlvmModule(..),
+
+        LlvmFunction(..), LlvmFunctionDecl(..),
+        LlvmFunctions, LlvmFunctionDecls,
+        LlvmStatement(..), LlvmExpression(..),
+        LlvmBlocks, LlvmBlock(..), LlvmBlockId,
+
+        -- * Call Handling
+        LlvmCallConvention(..), LlvmCallType(..), LlvmParameterListType(..),
+        LlvmLinkageType(..), LlvmFuncAttr(..),
+
+        -- * Operations and Comparisons
+        LlvmCmpOp(..), LlvmMachOp(..), LlvmCastOp(..),
+
+        -- * Variables and Type System
+        LlvmVar(..), LlvmStatic(..), LlvmLit(..), LlvmType(..),
+        LMGlobal, LMString, LMConstant,
+
+        -- ** Some basic types
+        i64, i32, i16, i8, i1, llvmWord, llvmWordPtr,
+
+        -- ** Operations on the type system.
+        isGlobal, getLitType, getLit, getName, getPlainName, getVarType,
+        getStatType, getGlobalVar, getGlobalType, pVarLower, pLift, pLower,
+        isInt, isFloat, isPointer, llvmWidthInBits,
+
+        -- * Pretty Printing
+        ppLlvmModule, ppLlvmComments, ppLlvmComment, ppLlvmConstants,
+        ppLlvmConstant, ppLlvmGlobals, ppLlvmGlobal, ppLlvmFunctionDecls,
+        ppLlvmFunctionDecl, ppLlvmFunctions, ppLlvmFunction, ppLlvmType,
+        ppLlvmTypes, llvmSDoc
+
+    ) where
+
+import Llvm.AbsSyn
+import Llvm.PpLlvm
+import Llvm.Types
+
diff --git a/compiler/llvmGen/Llvm/AbsSyn.hs b/compiler/llvmGen/Llvm/AbsSyn.hs
new file mode 100644 (file)
index 0000000..1b8527b
--- /dev/null
@@ -0,0 +1,209 @@
+--------------------------------------------------------------------------------
+-- | The LLVM abstract syntax.
+--
+
+module Llvm.AbsSyn where
+
+import Llvm.Types
+
+import Unique
+
+-- | Block labels
+type LlvmBlockId = Unique
+
+-- | A block of LLVM code.
+data LlvmBlock = LlvmBlock {
+    -- | The code label for this block
+    blockLabel :: LlvmBlockId,
+
+    -- | A list of LlvmStatement's representing the code for this block.
+    -- This list must end with a control flow statement.
+    blockStmts :: [LlvmStatement]
+  }
+
+type LlvmBlocks = [LlvmBlock]
+
+-- | An LLVM Module. This is a top level contianer in LLVM.
+data LlvmModule = LlvmModule  {
+    -- | Comments to include at the start of the module.
+    modComments  :: [LMString],
+
+    -- | Constants to include in the module.
+    modConstants :: [LMConstant],
+
+    -- | Global variables to include in the module.
+    modGlobals   :: [LMGlobal],
+
+    -- | LLVM Functions used in this module but defined in other modules.
+    modFwdDecls  :: LlvmFunctionDecls,
+
+    -- | LLVM Functions defined in this module.
+    modFuncs     :: LlvmFunctions
+  }
+
+-- | An LLVM Function
+data LlvmFunction = LlvmFunction {
+    -- | The signature of this declared function.
+    funcDecl    :: LlvmFunctionDecl,
+
+    -- | The function attributes.
+    funcAttrs   :: [LlvmFuncAttr],
+
+    -- | The body of the functions.
+    funcBody    :: LlvmBlocks
+  }
+
+type LlvmFunctions  = [LlvmFunction]
+
+
+-- | Llvm Statements
+data LlvmStatement
+  {- |
+    Assign an expression to an variable:
+      * dest:   Variable to assign to
+      * source: Source expression
+  -}
+  = Assignment LlvmVar LlvmExpression
+
+  {- |
+    Always branch to the target label
+  -}
+  | Branch LlvmVar
+
+  {- |
+    Branch to label targetTrue if cond is true otherwise to label targetFalse
+      * cond:        condition that will be tested, must be of type i1
+      * targetTrue:  label to branch to if cond is true
+      * targetFalse: label to branch to if cond is false
+  -}
+  | BranchIf LlvmVar LlvmVar LlvmVar
+
+  {- |
+    Comment
+    Plain comment.
+  -}
+  | Comment [LMString]
+
+  {- |
+    Set a label on this position.
+      * name: Identifier of this label, unique for this module
+  -}
+  | MkLabel LlvmBlockId
+
+  {- |
+    Store variable value in pointer ptr. If value is of type t then ptr must
+    be of type t*.
+      * value: Variable/Constant to store.
+      * ptr:   Location to store the value in
+  -}
+  | Store LlvmVar LlvmVar
+
+  {- |
+    Mutliway branch
+      * scrutinee: Variable or constant which must be of integer type that is
+                   determines which arm is chosen.
+      * def:       The default label if there is no match in target.
+      * target:    A list of (value,label) where the value is an integer
+                   constant and label the corresponding label to jump to if the
+                   scrutinee matches the value.
+  -}
+  | Switch LlvmVar LlvmVar [(LlvmVar, LlvmVar)]
+
+  {- |
+    Return a result.
+      * result: The variable or constant to return
+  -}
+  | Return (Maybe LlvmVar)
+
+  {- |
+    An instruction for the optimizer that the code following is not reachable
+  -}
+  | Unreachable
+
+  {- |
+    Raise an expression to a statement (if don't want result or want to use
+    Llvm unamed values.
+  -}
+  | Expr LlvmExpression
+
+  deriving (Show, Eq)
+
+
+-- | Llvm Expressions
+data LlvmExpression
+  {- |
+    Allocate amount * sizeof(tp) bytes on the stack
+      * tp:     LlvmType to reserve room for
+      * amount: The nr of tp's which must be allocated
+  -}
+  = Alloca LlvmType Int
+
+  {- |
+    Perform the machine operator op on the operands left and right
+      * op:    operator
+      * left:  left operand
+      * right: right operand
+  -}
+  | LlvmOp LlvmMachOp LlvmVar LlvmVar
+
+  {- |
+    Perform a compare operation on the operands left and right
+      * op:    operator
+      * left:  left operand
+      * right: right operand
+  -}
+  | Compare LlvmCmpOp LlvmVar LlvmVar
+
+  {- |
+    Allocate amount * sizeof(tp) bytes on the heap
+      * tp:     LlvmType to reserve room for
+      * amount: The nr of tp's which must be allocated
+  -}
+  | Malloc LlvmType Int
+
+  {- |
+    Load the value at location ptr
+  -}
+  | Load LlvmVar
+
+  {- |
+    Navigate in an structure, selecting elements
+      * ptr:     Location of the structure
+      * indexes: A list of indexes to select the correct value. For example
+                 the first element of the third element of the structure ptr
+                 is selected with [3,1] (zero indexed)
+  -}
+  | GetElemPtr LlvmVar [Int]
+
+  {- |
+     Cast the variable from to the to type. This is an abstraction of three
+     cast operators in Llvm, inttoptr, prttoint and bitcast.
+       * cast: Cast type
+       * from: Variable to cast
+       * to:   type to cast to
+  -}
+  | Cast LlvmCastOp LlvmVar LlvmType
+
+  {- |
+    Call a function. The result is the value of the expression.
+      * tailJumps: CallType to signal if the function should be tail called
+      * fnptrval:  An LLVM value containing a pointer to a function to be
+                   invoked. Can be indirect. Should be LMFunction type.
+      * args:      Concrete arguments for the parameters
+      * attrs:     A list of function attributes for the call. Only NoReturn,
+                   NoUnwind, ReadOnly and ReadNone are valid here.
+  -}
+  | Call LlvmCallType LlvmVar [LlvmVar] [LlvmFuncAttr]
+
+  {- |
+    Merge variables from different basic blocks which are predecessors of this
+    basic block in a new variable of type tp.
+      * tp:         type of the merged variable, must match the types of the
+                    precessors variables.
+      * precessors: A list of variables and the basic block that they originate
+                    from.
+  -}
+  | Phi LlvmType [(LlvmVar,LlvmVar)]
+
+  deriving (Show, Eq)
+
diff --git a/compiler/llvmGen/Llvm/PpLlvm.hs b/compiler/llvmGen/Llvm/PpLlvm.hs
new file mode 100644 (file)
index 0000000..8d36511
--- /dev/null
@@ -0,0 +1,325 @@
+--------------------------------------------------------------------------------
+-- | Pretty print LLVM IR Code.
+--
+
+module Llvm.PpLlvm (
+
+    -- * Top level LLVM objects.
+    ppLlvmModule,
+    ppLlvmComments,
+    ppLlvmComment,
+    ppLlvmConstants,
+    ppLlvmConstant,
+    ppLlvmGlobals,
+    ppLlvmGlobal,
+    ppLlvmType,
+    ppLlvmTypes,
+    ppLlvmFunctionDecls,
+    ppLlvmFunctionDecl,
+    ppLlvmFunctions,
+    ppLlvmFunction,
+    llvmSDoc
+
+    ) where
+
+#include "HsVersions.h"
+
+import Llvm.AbsSyn
+import Llvm.Types
+
+import Data.List ( intersperse )
+import Pretty
+import qualified Outputable as Outp
+import Unique
+
+--------------------------------------------------------------------------------
+-- * Top Level Print functions
+--------------------------------------------------------------------------------
+
+-- | Print out a whole LLVM module.
+ppLlvmModule :: LlvmModule -> Doc
+ppLlvmModule (LlvmModule comments constants globals decls funcs)
+  = ppLlvmComments comments
+    $+$ empty
+    $+$ ppLlvmConstants constants
+    $+$ ppLlvmGlobals globals
+    $+$ empty
+    $+$ ppLlvmFunctionDecls decls
+    $+$ empty
+    $+$ ppLlvmFunctions funcs
+
+-- | Print out a multi-line comment, can be inside a function or on its own
+ppLlvmComments :: [LMString] -> Doc
+ppLlvmComments comments = vcat $ map ppLlvmComment comments
+
+-- | Print out a comment, can be inside a function or on its own
+ppLlvmComment :: LMString -> Doc
+ppLlvmComment com = semi <+> (ftext com)
+
+
+-- | Print out a list of global mutable variable definitions
+ppLlvmGlobals :: [LMGlobal] -> Doc
+ppLlvmGlobals ls = vcat $ map ppLlvmGlobal ls
+
+-- | Print out a global mutable variable definition
+ppLlvmGlobal :: LMGlobal -> Doc
+ppLlvmGlobal (var@(LMGlobalVar _ _ link), Nothing) =
+    ppAssignment var $ text (show link) <+> text "global" <+>
+        (text $ show (pLower $ getVarType var))
+
+ppLlvmGlobal (var@(LMGlobalVar _ _ link), (Just stat)) =
+    ppAssignment var $ text (show link) <+> text "global" <+> text (show stat)
+
+ppLlvmGlobal oth = error $ "Non Global var ppr as global! " ++ show oth
+
+
+-- | Print out a list global constant variable
+ppLlvmConstants :: [LMConstant] -> Doc
+ppLlvmConstants cons = vcat $ map ppLlvmConstant cons
+
+-- | Print out a global constant variable
+ppLlvmConstant :: LMConstant -> Doc
+ppLlvmConstant (dst@(LMGlobalVar _ _ link), src) =
+    ppAssignment dst $ text (show link) <+> text "constant" <+> text (show src)
+
+ppLlvmConstant c = error $ "Non global var as constant! " ++ show c
+
+
+-- | Print out a list of LLVM type aliases.
+ppLlvmTypes :: [LlvmType] -> Doc
+ppLlvmTypes tys = vcat $ map ppLlvmType tys
+
+-- | Print out an LLVM type alias.
+ppLlvmType :: LlvmType -> Doc
+
+ppLlvmType al@(LMAlias _ t)
+  = (text $ show al) <+> equals <+> (text "type") <+> (text $ show t)
+
+ppLlvmType (LMFunction t)
+  = ppLlvmFunctionDecl t
+
+ppLlvmType _ = empty
+
+
+-- | Print out a list of function definitions.
+ppLlvmFunctions :: LlvmFunctions -> Doc
+ppLlvmFunctions funcs = vcat $ map ppLlvmFunction funcs
+
+-- | Print out a function definition.
+ppLlvmFunction :: LlvmFunction -> Doc
+ppLlvmFunction (LlvmFunction dec attrs body) =
+    let attrDoc = ppSpaceJoin attrs
+    in (text "define") <+> (ppLlvmFuncDecSig dec)
+        <+> attrDoc
+        $+$ lbrace
+        $+$ ppLlvmBlocks body
+        $+$ rbrace
+
+
+-- | Print out a list of function declaration.
+ppLlvmFunctionDecls :: LlvmFunctionDecls -> Doc
+ppLlvmFunctionDecls decs = vcat $ map ppLlvmFunctionDecl decs
+
+-- | Print out a function declaration.
+-- Declarations define the function type but don't define the actual body of
+-- the function.
+ppLlvmFunctionDecl :: LlvmFunctionDecl -> Doc
+ppLlvmFunctionDecl dec = (text "declare") <+> ppLlvmFuncDecSig dec
+
+-- | Print out a functions type signature.
+-- This differs from [ppLlvmFunctionDecl] in that it is used for both function
+-- declarations and defined functions to print out the type.
+ppLlvmFuncDecSig :: LlvmFunctionDecl -> Doc
+ppLlvmFuncDecSig (LlvmFunctionDecl name link cc retTy argTy params)
+  = let linkTxt = show link
+        linkDoc   | linkTxt == "" = empty
+                  | otherwise     = (text linkTxt) <> space
+        ppParams = either ppCommaJoin ppCommaJoin params <>
+                    (case argTy of
+                        VarArgs -> (text ", ...")
+                        FixedArgs -> empty)
+  in linkDoc <> (text $ show cc) <+> (text $ show retTy)
+      <+> atsym <> (ftext name) <> lparen <+> ppParams <+> rparen
+
+
+-- | Print out a list of LLVM blocks.
+ppLlvmBlocks :: LlvmBlocks -> Doc
+ppLlvmBlocks blocks = vcat $ map ppLlvmBlock blocks
+
+-- | Print out an LLVM block.
+-- It must be part of a function definition.
+ppLlvmBlock :: LlvmBlock -> Doc
+ppLlvmBlock (LlvmBlock blockId stmts)
+  = ppLlvmStatement (MkLabel blockId)
+        $+$ nest 4 (vcat $ map  ppLlvmStatement stmts)
+
+
+-- | Print out an LLVM statement.
+ppLlvmStatement :: LlvmStatement -> Doc
+ppLlvmStatement stmt
+  = case stmt of
+        Assignment  dst expr      -> ppAssignment dst (ppLlvmExpression expr)
+        Branch      target        -> ppBranch target
+        BranchIf    cond ifT ifF  -> ppBranchIf cond ifT ifF
+        Comment     comments      -> ppLlvmComments comments
+        MkLabel     label         -> (llvmSDoc $ pprUnique label) <> colon
+        Store       value ptr     -> ppStore value ptr
+        Switch      scrut def tgs -> ppSwitch scrut def tgs
+        Return      result        -> ppReturn result
+        Expr        expr          -> ppLlvmExpression expr
+        Unreachable               -> text "unreachable"
+
+
+-- | Print out an LLVM expression.
+ppLlvmExpression :: LlvmExpression -> Doc
+ppLlvmExpression expr
+  = case expr of
+        Alloca     tp amount        -> ppAlloca tp amount
+        LlvmOp     op left right    -> ppMachOp op left right
+        Call       tp fp args attrs -> ppCall tp fp args attrs
+        Cast       op from to       -> ppCast op from to
+        Compare    op left right    -> ppCmpOp op left right
+        GetElemPtr ptr indexes      -> ppGetElementPtr ptr indexes
+        Load       ptr              -> ppLoad ptr
+        Malloc     tp amount        -> ppMalloc tp amount
+        Phi        tp precessors    -> ppPhi tp precessors
+
+
+--------------------------------------------------------------------------------
+-- * Individual print functions
+--------------------------------------------------------------------------------
+
+-- | Should always be a function pointer. So a global var of function type
+-- (since globals are always pointers) or a local var of pointer function type.
+ppCall :: LlvmCallType -> LlvmVar -> [LlvmVar] -> [LlvmFuncAttr] -> Doc
+ppCall ct fptr vals attrs = case fptr of
+                           --
+    -- if local var function pointer, unwrap
+    LMLocalVar _ (LMPointer (LMFunction d)) -> ppCall' d
+
+    -- should be function type otherwise
+    LMGlobalVar _ (LMFunction d) _          -> ppCall' d
+
+    -- not pointer or function, so error
+    _other -> error $ "ppCall called with non LMFunction type!\nMust be "
+                ++ " called with either global var of function type or "
+                ++ "local var of pointer function type."
+
+    where
+        ppCall' (LlvmFunctionDecl _ _ cc ret argTy params) =
+            let tc = if ct == TailCall then text "tail " else empty
+                ppValues = ppCommaJoin vals
+                ppArgTy = either ppCommaJoin (\x -> ppCommaJoin $ map getVarType x) params <>
+                           (case argTy of
+                               VarArgs -> (text ", ...")
+                               FixedArgs -> empty)
+                fnty = space <> lparen <> ppArgTy <> rparen <> (text "*")
+                attrDoc = ppSpaceJoin attrs
+            in  tc <> (text "call") <+> (text $ show cc) <+> (text $ show ret)
+                    <> fnty <+> (text $ getName fptr) <> lparen <+> ppValues
+                    <+> rparen <+> attrDoc
+
+
+ppMachOp :: LlvmMachOp -> LlvmVar -> LlvmVar -> Doc
+ppMachOp op left right =
+  (text $ show op) <+> (text $ show (getVarType left)) <+> (text $ getName left)
+        <> comma <+> (text $ getName right)
+
+
+ppCmpOp :: LlvmCmpOp -> LlvmVar -> LlvmVar -> Doc
+ppCmpOp op left right =
+  let cmpOp
+        | isInt (getVarType left) && isInt (getVarType right) = text "icmp"
+        | isFloat (getVarType left) && isFloat (getVarType right) = text "fcmp"
+        | otherwise = error ("can't compare different types, left = "
+                ++ (show $ getVarType left) ++ ", right = "
+                ++ (show $ getVarType right))
+  in cmpOp <+> (text $ show op) <+> (text $ show (getVarType left))
+        <+> (text $ getName left) <> comma <+> (text $ getName right)
+
+
+ppAssignment :: LlvmVar -> Doc -> Doc
+ppAssignment var expr = (text $ getName var) <+> equals <+> expr
+
+
+ppLoad :: LlvmVar -> Doc
+ppLoad var = (text "load") <+> (text $ show var)
+
+
+ppStore :: LlvmVar -> LlvmVar -> Doc
+ppStore val dst =
+  (text "store") <+> (text $ show val) <> comma <+> (text $ show dst)
+
+
+ppCast :: LlvmCastOp -> LlvmVar -> LlvmType -> Doc
+ppCast op from to =
+  let castOp = text $ show op
+  in castOp <+> (text $ show from) <+> (text "to") <+> (text $ show to)
+
+
+ppMalloc :: LlvmType -> Int -> Doc
+ppMalloc tp amount =
+  let amount' = LMLitVar $ LMIntLit (toInteger amount) i32
+  in (text "malloc") <+> (text $ show tp) <> comma <+> (text $ show amount')
+
+
+ppAlloca :: LlvmType -> Int -> Doc
+ppAlloca tp amount =
+  let amount' = LMLitVar $ LMIntLit (toInteger amount) i32
+  in (text "alloca") <+> (text $ show tp) <> comma <+> (text $ show amount')
+
+
+ppGetElementPtr :: LlvmVar -> [Int] -> Doc
+ppGetElementPtr ptr idx =
+  let indexes = hcat $ map ((comma <+> (text $ show i32) <+>) . text . show) idx
+  in (text "getelementptr") <+> (text $ show ptr) <> indexes
+
+
+ppReturn :: Maybe LlvmVar -> Doc
+ppReturn (Just var) = (text "ret") <+> (text $ show var)
+ppReturn Nothing    = (text "ret") <+> (text $ show LMVoid)
+
+
+ppBranch :: LlvmVar -> Doc
+ppBranch var = (text "br") <+> (text $ show var)
+
+
+ppBranchIf :: LlvmVar -> LlvmVar -> LlvmVar -> Doc
+ppBranchIf cond trueT falseT
+  = (text "br") <+> (text $ show cond) <> comma <+> (text $ show trueT) <> comma
+        <+> (text $ show falseT)
+
+
+ppPhi :: LlvmType -> [(LlvmVar,LlvmVar)] -> Doc
+ppPhi tp preds =
+  let ppPreds (val, label) = brackets $ (text $ getName val) <> comma
+        <+> (text $ getName label)
+  in (text "phi") <+> (text $ show tp)
+        <+> (hcat $ intersperse comma (map ppPreds preds))
+
+
+ppSwitch :: LlvmVar -> LlvmVar -> [(LlvmVar,LlvmVar)] -> Doc
+ppSwitch scrut dflt targets =
+  let ppTarget  (val, lab) = (text $ show val) <> comma <+> (text $ show lab)
+      ppTargets  xs        = brackets $ vcat (map ppTarget xs)
+  in (text "switch") <+> (text $ show scrut) <> comma <+> (text $ show dflt)
+        <+> (ppTargets targets)
+
+
+--------------------------------------------------------------------------------
+-- * Misc functions
+--------------------------------------------------------------------------------
+atsym :: Doc
+atsym = text "@"
+
+ppCommaJoin :: (Show a) => [a] -> Doc
+ppCommaJoin strs = hcat $ intersperse comma (map (text . show) strs)
+
+ppSpaceJoin :: (Show a) => [a] -> Doc
+ppSpaceJoin strs = hcat $ intersperse space (map (text . show) strs)
+
+-- | Convert SDoc to Doc
+llvmSDoc :: Outp.SDoc -> Doc
+llvmSDoc d
+       = Outp.withPprStyleDoc (Outp.mkCodeStyle Outp.CStyle) d
+
diff --git a/compiler/llvmGen/Llvm/Types.hs b/compiler/llvmGen/Llvm/Types.hs
new file mode 100644 (file)
index 0000000..a4080c4
--- /dev/null
@@ -0,0 +1,719 @@
+--------------------------------------------------------------------------------
+-- | The LLVM Type System.
+--
+
+module Llvm.Types where
+
+#include "HsVersions.h"
+#include "ghcconfig.h"
+
+import Data.Char
+import Numeric
+
+import Constants
+import FastString
+import Unique
+
+-- from NCG
+import PprBase
+
+-- -----------------------------------------------------------------------------
+-- * LLVM Basic Types and Variables
+--
+
+-- | A global mutable variable. Maybe defined or external
+type LMGlobal   = (LlvmVar, Maybe LlvmStatic)
+-- | A global constant variable
+type LMConstant = (LlvmVar, LlvmStatic)
+-- | A String in LLVM
+type LMString   = FastString
+
+
+-- | 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'
+  | LMLabel                   -- ^ A 'LlvmVar' can represent a label (address)
+  | LMVoid                    -- ^ Void type
+  | LMStruct [LlvmType]       -- ^ Structure type
+  | LMAlias LMString LlvmType -- ^ A type alias
+
+  -- | Function type, used to create pointers to functions
+  | LMFunction LlvmFunctionDecl
+  deriving (Eq)
+
+instance Show LlvmType where
+  show (LMInt size    ) = "i" ++ show size
+  show (LMFloat       ) = "float"
+  show (LMDouble      ) = "double"
+  show (LMFloat80     ) = "x86_fp80"
+  show (LMFloat128    ) = "fp128"
+  show (LMPointer x   ) = show x ++ "*"
+  show (LMArray nr tp ) = "[" ++ show nr ++ " x " ++ show tp ++ "]"
+  show (LMLabel       ) = "label"
+  show (LMVoid        ) = "void"
+  show (LMStruct tys  ) = "{" ++ (commaCat tys) ++ "}"
+
+  show (LMFunction (LlvmFunctionDecl _ _ _ r VarArgs p))
+        = (show r) ++ " (" ++ (either commaCat commaCat p) ++ ", ...)"
+  show (LMFunction (LlvmFunctionDecl _ _ _ r FixedArgs p))
+        = (show r) ++ " (" ++ (either commaCat commaCat p) ++ ")"
+
+  show (LMAlias s _   ) = "%" ++ unpackFS s
+
+
+-- | Llvm Variables
+data LlvmVar
+  -- | Variables with a global scope.
+  = LMGlobalVar LMString LlvmType LlvmLinkageType
+  -- | 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 (Eq)
+
+instance Show LlvmVar where
+  show (LMLitVar x) = show x
+  show (x         ) = show (getVarType x) ++ " " ++ getName 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 Rational LlvmType
+  deriving (Eq)
+
+instance Show LlvmLit where
+  show l = show (getLitType l) ++ " " ++ getLit 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.
+
+  | LMPtoI LlvmStatic LlvmType         -- ^ Pointer to Integer conversion
+  | LMAdd LlvmStatic LlvmStatic        -- ^ Constant addition operation
+  | LMSub LlvmStatic LlvmStatic        -- ^ Constant subtraction operation
+  deriving (Eq)
+
+instance Show LlvmStatic where
+  show (LMComment       s) = "; " ++ unpackFS s
+  show (LMStaticLit   l  ) = show l
+  show (LMUninitType    t) = show t ++ " undef"
+  show (LMStaticStr   s t) = show t ++ " c\"" ++ unpackFS s ++ "\\00\""
+
+  show (LMStaticArray d t)
+      = let struc = case d of
+              [] -> "[]"
+              ts -> "[" ++
+                      (show (head ts) ++ concat (map (\x -> "," ++ show x)
+                          (tail ts)))
+                      ++ "]"
+        in show t ++ " " ++ struc
+
+  show (LMStaticStruc d t)
+      = let struc = case d of
+              [] -> "{}"
+              ts -> "{" ++
+                      (show (head ts) ++ concat (map (\x -> "," ++ show x)
+                          (tail ts)))
+                      ++ "}"
+        in show t ++ " " ++ struc
+
+  show (LMStaticPointer v) = show v
+
+  show (LMPtoI v t)
+      = show t ++ " ptrtoint (" ++ show v ++ " to " ++ show t ++ ")"
+
+  show (LMAdd s1 s2)
+      = let ty1 = getStatType s1
+        in if ty1 == getStatType s2
+                then show ty1 ++ " add (" ++ show s1 ++ "," ++ show s2 ++ ")"
+                else error $ "LMAdd with different types! s1: "
+                        ++ show s1 ++ ", s2: " ++ show s2
+  show (LMSub s1 s2)
+      = let ty1 = getStatType s1
+        in if ty1 == getStatType s2
+                then show ty1 ++ " sub (" ++ show s1 ++ "," ++ show s2 ++ ")"
+                else error $ "LMSub with different types! s1: "
+                        ++ show s1 ++ ", s2: " ++ show s2
+
+
+-- | Concatenate an array together, separated by commas
+commaCat :: Show a => [a] -> String
+commaCat [] = ""
+commaCat x  = show (head x) ++ (concat $ map (\y -> "," ++ show y) (tail x))
+
+-- -----------------------------------------------------------------------------
+-- ** 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@).
+getName :: LlvmVar -> String
+getName v@(LMGlobalVar _ _ _ ) = "@" ++ getPlainName v
+getName v@(LMLocalVar  _ _   ) = "%" ++ getPlainName v
+getName v@(LMNLocalVar _ _   ) = "%" ++ getPlainName v
+getName v@(LMLitVar    _     ) = getPlainName v
+
+-- | Return the variable name or value of the 'LlvmVar'
+-- in a plain textual representation (e.g. @x@, @y@ or @42@).
+getPlainName :: LlvmVar -> String
+getPlainName (LMGlobalVar x _ _) = unpackFS x
+getPlainName (LMLocalVar  x _  ) = show x
+getPlainName (LMNLocalVar x _  ) = unpackFS x
+getPlainName (LMLitVar    x    ) = getLit x
+
+-- | Print a literal value. No type.
+getLit :: LlvmLit -> String
+getLit (LMIntLit i _)   = show ((fromInteger i)::Int)
+-- In Llvm float literals can be printed in a big-endian hexadecimal format,
+-- regardless of underlying architecture.
+getLit (LMFloatLit r LMFloat)  = fToStr $ fromRational r
+getLit (LMFloatLit r LMDouble) = dToStr $ fromRational r
+getLit l = error $ "getLit: Usupported LlvmLit type! " ++ show (getLitType l)
+
+-- | Return the 'LlvmType' of the 'LlvmVar'
+getVarType :: LlvmVar -> LlvmType
+getVarType (LMGlobalVar _ y _) = y
+getVarType (LMLocalVar  _ y  ) = y
+getVarType (LMNLocalVar _ y  ) = y
+getVarType (LMLitVar    l    ) = getLitType l
+
+-- | Return the 'LlvmType' of a 'LlvmLit'
+getLitType :: LlvmLit -> LlvmType
+getLitType (LMIntLit   _ t) = t
+getLitType (LMFloatLit _ t) = t
+
+-- | Return the 'LlvmType' of the 'LlvmStatic'
+getStatType :: LlvmStatic -> LlvmType
+getStatType (LMStaticLit   l  ) = getLitType l
+getStatType (LMUninitType    t) = t
+getStatType (LMStaticStr   _ t) = t
+getStatType (LMStaticArray _ t) = t
+getStatType (LMStaticStruc _ t) = t
+getStatType (LMStaticPointer v) = getVarType v
+getStatType (LMPtoI        _ t) = t
+getStatType (LMAdd         t _) = getStatType t
+getStatType (LMSub         t _) = getStatType t
+getStatType (LMComment       _) = error "Can't call getStatType on LMComment!"
+
+-- | Return the 'LlvmType' of the 'LMGlobal'
+getGlobalType :: LMGlobal -> LlvmType
+getGlobalType (v, _) = getVarType v
+
+-- | Return the 'LlvmVar' part of a 'LMGlobal'
+getGlobalVar :: LMGlobal -> LlvmVar
+getGlobalVar (v, _) = v
+
+-- | Return the 'LlvmLinkageType' for a 'LlvmVar'
+getLink :: LlvmVar -> LlvmLinkageType
+getLink (LMGlobalVar _ _ l) = l
+getLink _                   = ExternallyVisible
+
+-- | Add a pointer indirection to the supplied type. 'LMLabel' and 'LMVoid'
+-- cannot be lifted.
+pLift :: LlvmType -> LlvmType
+pLift (LMLabel) = error "Labels are unliftable"
+pLift (LMVoid)  = error "Voids are unliftable"
+pLift x         = LMPointer x
+
+-- | Remove the pointer indirection of the supplied type. Only 'LMPointer'
+-- constructors can be lowered.
+pLower :: LlvmType -> LlvmType
+pLower (LMPointer x) = x
+pLower x  = error $ show x ++ " is a unlowerable type, need a pointer"
+
+-- | Lower a variable of 'LMPointer' type.
+pVarLower :: LlvmVar -> LlvmVar
+pVarLower (LMGlobalVar s t l) = LMGlobalVar s (pLower t) l
+pVarLower (LMLocalVar  s t  ) = LMLocalVar  s (pLower t)
+pVarLower (LMNLocalVar s t  ) = LMNLocalVar s (pLower t)
+pVarLower (LMLitVar    _    ) = error $ "Can't lower a literal type!"
+
+-- | Test if the given 'LlvmType' is an integer
+isInt :: LlvmType -> Bool
+isInt (LMInt _) = True
+isInt _         = False
+
+-- | Test if the given 'LlvmType' is a floating point type
+isFloat :: LlvmType -> Bool
+isFloat LMFloat    = True
+isFloat LMDouble   = True
+isFloat LMFloat80  = True
+isFloat LMFloat128 = True
+isFloat _          = False
+
+-- | Test if the given 'LlvmType' is an 'LMPointer' construct
+isPointer :: LlvmType -> Bool
+isPointer (LMPointer _) = True
+isPointer _             = False
+
+-- | Test if a 'LlvmVar' is global.
+isGlobal :: LlvmVar -> Bool
+isGlobal (LMGlobalVar _ _ _) = True
+isGlobal _                   = False
+
+-- | Width in bits of an 'LlvmType', returns 0 if not applicable
+llvmWidthInBits :: LlvmType -> Int
+llvmWidthInBits (LMInt n)        = n
+llvmWidthInBits (LMFloat)        = 32
+llvmWidthInBits (LMDouble)       = 64
+llvmWidthInBits (LMFloat80)      = 80
+llvmWidthInBits (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.
+llvmWidthInBits (LMPointer _)    = llvmWidthInBits llvmWord
+llvmWidthInBits (LMArray _ _)    = llvmWidthInBits llvmWord
+llvmWidthInBits LMLabel          = 0
+llvmWidthInBits LMVoid           = 0
+llvmWidthInBits (LMStruct tys)   = sum $ map llvmWidthInBits tys
+llvmWidthInBits (LMFunction  _)  = 0
+llvmWidthInBits (LMAlias _ t)    = llvmWidthInBits t
+
+
+-- -----------------------------------------------------------------------------
+-- ** Shortcut for Common Types
+--
+
+i128, i64, i32, i16, i8, i1 :: LlvmType
+i128 = LMInt 128
+i64  = LMInt  64
+i32  = LMInt  32
+i16  = LMInt  16
+i8   = LMInt   8
+i1   = LMInt   1
+
+-- | The target architectures word size
+llvmWord :: LlvmType
+llvmWord = LMInt (wORD_SIZE * 8)
+
+-- | The target architectures pointer size
+llvmWordPtr :: LlvmType
+llvmWordPtr = pLift llvmWord
+
+
+-- -----------------------------------------------------------------------------
+-- * LLVM Function Types
+--
+
+-- | An LLVM Function
+data LlvmFunctionDecl = LlvmFunctionDecl {
+        -- | Unique identifier of the function.
+        decName       :: LMString,
+        -- | LinkageType of the function.
+        funcLinkage   :: LlvmLinkageType,
+        -- | The calling convention of the function.
+        funcCc        :: LlvmCallConvention,
+        -- | Type of the returned value
+        decReturnType :: LlvmType,
+        -- | Indicates if this function uses varargs
+        decVarargs    :: LlvmParameterListType,
+        -- | Signature of the parameters, can be just types or full vars
+        -- if parameter names are required.
+        decParams     :: Either [LlvmType] [LlvmVar]
+  }
+
+instance Show LlvmFunctionDecl where
+  show (LlvmFunctionDecl n l c r VarArgs p)
+        = (show l) ++ " " ++  (show c) ++ " " ++ (show r)
+            ++ " @" ++ unpackFS n ++ "(" ++ (either commaCat commaCat p) ++ ", ...)"
+  show (LlvmFunctionDecl n l c r FixedArgs p)
+        = (show l) ++ " " ++  (show c) ++ " " ++ (show r)
+            ++ " @" ++ unpackFS n ++ "(" ++ (either commaCat commaCat p) ++ ")"
+
+instance Eq LlvmFunctionDecl where
+  (LlvmFunctionDecl n1 l1 c1 r1 v1 p1) == (LlvmFunctionDecl n2 l2 c2 r2 v2 p2)
+        = (n1 == n2) && (l1 == l2) && (c1 == c2) && (r1 == r2)
+            && (v1 == v2) && (p1 == p2)
+
+type LlvmFunctionDecls = [LlvmFunctionDecl]
+
+
+-- | 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 (Eq)
+
+instance Show LlvmFuncAttr where
+  show AlwaysInline    = "alwaysinline"
+  show InlineHint      = "inlinehint"
+  show NoInline        = "noinline"
+  show OptSize         = "optsize"
+  show NoReturn        = "noreturn"
+  show NoUnwind        = "nounwind"
+  show ReadNone        = "readnon"
+  show ReadOnly        = "readonly"
+  show Ssp             = "ssp"
+  show SspReq          = "ssqreq"
+  show NoRedZone       = "noredzone"
+  show NoImplicitFloat = "noimplicitfloat"
+  show Naked           = "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 (Eq,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
+  -- | 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 (Eq)
+
+instance Show LlvmCallConvention where
+  show CC_Ccc       = "ccc"
+  show CC_Fastcc    = "fastcc"
+  show CC_Coldcc    = "coldcc"
+  show (CC_Ncc i)   = "cc " ++ (show i)
+  show CC_X86_Stdcc = "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 (Eq,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
+  deriving (Eq)
+
+instance Show LlvmLinkageType where
+  show Internal          = "internal"
+  show LinkOnce          = "linkonce"
+  show Weak              = "weak"
+  show Appending         = "appending"
+  show ExternWeak        = "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.
+  show ExternallyVisible = ""
+  show External          = "external"
+
+
+-- -----------------------------------------------------------------------------
+-- * 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_FDiv -- ^ floating point ..
+  | LM_MO_URem -- ^ unsigned integer or vector remainder (mod)
+  | LM_MO_SRem -- ^ signed ...
+  | LM_MO_FRem -- ^ floating point ...
+
+  -- | 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 (Eq)
+
+instance Show LlvmMachOp where
+  show LM_MO_Add  = "add"
+  show LM_MO_Sub  = "sub"
+  show LM_MO_Mul  = "mul"
+  show LM_MO_UDiv = "udiv"
+  show LM_MO_SDiv = "sdiv"
+  show LM_MO_FDiv = "fdiv"
+  show LM_MO_URem = "urem"
+  show LM_MO_SRem = "srem"
+  show LM_MO_FRem = "frem"
+  show LM_MO_Shl  = "shl"
+  show LM_MO_LShr = "lshr"
+  show LM_MO_AShr = "ashr"
+  show LM_MO_And  = "and"
+  show LM_MO_Or   = "or"
+  show LM_MO_Xor  = "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 (Eq)
+
+instance Show LlvmCmpOp where
+  show LM_CMP_Eq  = "eq"
+  show LM_CMP_Ne  = "ne"
+  show LM_CMP_Ugt = "ugt"
+  show LM_CMP_Uge = "uge"
+  show LM_CMP_Ult = "ult"
+  show LM_CMP_Ule = "ule"
+  show LM_CMP_Sgt = "sgt"
+  show LM_CMP_Sge = "sge"
+  show LM_CMP_Slt = "slt"
+  show LM_CMP_Sle = "sle"
+  show LM_CMP_Feq = "oeq"
+  show LM_CMP_Fne = "une"
+  show LM_CMP_Fgt = "ogt"
+  show LM_CMP_Fge = "oge"
+  show LM_CMP_Flt = "olt"
+  show LM_CMP_Fle = "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 (Eq)
+
+instance Show LlvmCastOp where
+  show LM_Trunc    = "trunc"
+  show LM_Zext     = "zext"
+  show LM_Sext     = "sext"
+  show LM_Fptrunc  = "fptrunc"
+  show LM_Fpext    = "fpext"
+  show LM_Fptoui   = "fptoui"
+  show LM_Fptosi   = "fptosi"
+  show LM_Uitofp   = "uitofp"
+  show LM_Sitofp   = "sitofp"
+  show LM_Ptrtoint = "ptrtoint"
+  show LM_Inttoptr = "inttoptr"
+  show LM_Bitcast  = "bitcast"
+
+
+-- -----------------------------------------------------------------------------
+-- * Floating point conversion
+--
+
+-- | Convert a Haskell Float to an LLVM hex encoded floating point form
+fToStr :: Float -> String
+fToStr f = dToStr $ realToFrac f
+
+-- | Convert a Haskell Double to an LLVM hex encoded floating point form
+dToStr :: Double -> String
+dToStr d =
+    let bs  = doubleToBytes d
+        hex d' = case showHex d' "" of
+                     []    -> error "dToStr: too few hex digits for float"
+                     [x]   -> ['0',x]
+                     [x,y] -> [x,y]
+                     _     -> error "dToStr: too many hex digits for float"
+
+        str' = concat . fixEndian . (map hex) $ bs
+        str = map toUpper str'
+    in  "0x" ++ str
+
+-- | Reverse or leave byte data alone to fix endianness on this
+-- target. LLVM generally wants things in Big-Endian form
+-- regardless of target architecture.
+fixEndian :: [a] -> [a]
+#ifdef WORDS_BIGENDIAN
+fixEndian = id
+#else
+fixEndian = reverse
+#endif
+
diff --git a/compiler/llvmGen/LlvmCodeGen.hs b/compiler/llvmGen/LlvmCodeGen.hs
new file mode 100644 (file)
index 0000000..e0485e7
--- /dev/null
@@ -0,0 +1,166 @@
+-- -----------------------------------------------------------------------------
+-- | This is the top-level module in the LLVM code generator.
+--
+
+module LlvmCodeGen ( llvmCodeGen ) where
+
+#include "HsVersions.h"
+
+import LlvmCodeGen.Base
+import LlvmCodeGen.CodeGen
+import LlvmCodeGen.Data
+import LlvmCodeGen.Ppr
+
+import Cmm
+import CgUtils ( fixStgRegisters )
+import PprCmm
+
+import BufWrite
+import DynFlags
+import ErrUtils
+import Outputable
+import qualified Pretty as Prt
+import UniqSupply
+
+import System.IO
+
+-- -----------------------------------------------------------------------------
+-- | Top-level of the llvm codegen
+--
+llvmCodeGen :: DynFlags -> Handle -> UniqSupply -> [RawCmm] -> IO ()
+llvmCodeGen dflags h us cmms
+  = do
+      let cmm = concat $ map extractRawCmm cmms
+
+      bufh <- newBufHandle h
+
+      Prt.bufLeftRender bufh $ pprLlvmHeader
+
+      env <- cmmDataLlvmGens dflags bufh cmm
+      cmmProcLlvmGens dflags bufh us env cmm
+
+      bFlush bufh
+
+      return  ()
+
+  where extractRawCmm (Cmm tops) = tops
+
+
+-- -----------------------------------------------------------------------------
+-- | Do llvm code generation on all these cmms data sections.
+--
+cmmDataLlvmGens
+      :: DynFlags
+      -> BufHandle
+      -> [RawCmmTop]
+      -> IO ( LlvmEnv )
+
+cmmDataLlvmGens _ _ []
+  = return ( initLlvmEnv )
+
+cmmDataLlvmGens dflags h cmm =
+    let exData (CmmData s d) = [(s,d)]
+        exData  _            = []
+
+        exProclbl (CmmProc _ l _ _) = [(strCLabel_llvm l)]
+        exProclbl  _                = []
+
+        cdata = concat $ map exData cmm
+        -- put the functions into the enviornment
+        cproc = concat $ map exProclbl cmm
+        env = foldl (\e l -> funInsert l llvmFunTy e) initLlvmEnv cproc
+    in cmmDataLlvmGens' dflags h env cdata []
+
+cmmDataLlvmGens'
+      :: DynFlags
+      -> BufHandle
+      -> LlvmEnv
+      -> [(Section, [CmmStatic])]
+      -> [LlvmUnresData]
+      -> IO ( LlvmEnv )
+
+cmmDataLlvmGens' dflags h env [] lmdata
+    = do
+        let (env', lmdata') = resolveLlvmDatas dflags env lmdata []
+        let lmdoc = Prt.vcat $ map (pprLlvmData dflags) lmdata'
+
+        dumpIfSet_dyn dflags Opt_D_dump_llvm "LLVM Code" $ docToSDoc lmdoc
+
+        Prt.bufLeftRender h lmdoc
+        return env'
+
+cmmDataLlvmGens' dflags h env (cmm:cmms) lmdata
+    = do
+        let lmdata'@(l, ty, _) = genLlvmData dflags cmm
+        let env' = funInsert (strCLabel_llvm l) ty env
+        cmmDataLlvmGens' dflags h env' cmms (lmdata ++ [lmdata'])
+
+
+-- -----------------------------------------------------------------------------
+-- | Do llvm code generation on all these cmms procs.
+--
+cmmProcLlvmGens
+      :: DynFlags
+      -> BufHandle
+      -> UniqSupply
+      -> LlvmEnv
+      -> [RawCmmTop]
+      -> IO ()
+
+cmmProcLlvmGens _ _ _ _ []
+    = return ()
+
+cmmProcLlvmGens dflags h us env (cmm : cmms)
+  = do
+      (us', env', llvm) <- cmmLlvmGen dflags us (clearVars env) cmm
+
+      Prt.bufLeftRender h $ Prt.vcat $ map (pprLlvmCmmTop dflags) llvm
+
+      cmmProcLlvmGens dflags h us' env' cmms
+
+
+-- | Complete llvm code generation phase for a single top-level chunk of Cmm.
+cmmLlvmGen
+      :: DynFlags
+      -> UniqSupply
+      -> LlvmEnv
+      -> RawCmmTop              -- ^ the cmm to generate code for
+      -> IO ( UniqSupply,
+              LlvmEnv,
+              [LlvmCmmTop] )   -- llvm code
+
+cmmLlvmGen dflags us env cmm
+  = do
+    -- rewrite assignments to global regs
+    let fixed_cmm = fixStgRegisters cmm
+
+    dumpIfSet_dyn dflags Opt_D_dump_opt_cmm "Optimised Cmm"
+        (pprCmm $ Cmm [fixed_cmm])
+
+    -- generate llvm code from cmm
+    let ((env', llvmBC), usGen) = initUs us $ genLlvmCode dflags env fixed_cmm
+
+    dumpIfSet_dyn dflags Opt_D_dump_llvm "LLVM Code"
+        (vcat $ map (docToSDoc . pprLlvmCmmTop dflags) llvmBC)
+
+    return (usGen, env', llvmBC)
+
+
+-- -----------------------------------------------------------------------------
+-- | Instruction selection
+--
+genLlvmCode
+    :: DynFlags
+    -> LlvmEnv
+    -> RawCmmTop
+    -> UniqSM (LlvmEnv, [LlvmCmmTop])
+
+genLlvmCode _ env (CmmData _ _)
+    = return (env, [])
+
+genLlvmCode _ env (CmmProc _ _ _ (ListGraph []))
+    = return (env, [])
+
+genLlvmCode _ env cp@(CmmProc _ _ _ _)
+    = genLlvmProc env cp
+
diff --git a/compiler/llvmGen/LlvmCodeGen/Base.hs b/compiler/llvmGen/LlvmCodeGen/Base.hs
new file mode 100644 (file)
index 0000000..36ffa18
--- /dev/null
@@ -0,0 +1,164 @@
+-- ----------------------------------------------------------------------------
+-- | Base LLVM Code Generation module
+--
+-- Contains functions useful through out the code generator.
+--
+
+module LlvmCodeGen.Base (
+
+        LlvmCmmTop, LlvmBasicBlock,
+        LlvmUnresData, LlvmData, UnresLabel, UnresStatic,
+
+        LlvmEnv, initLlvmEnv, clearVars, varLookup, varInsert,
+        funLookup, funInsert,
+
+        cmmToLlvmType, widthToLlvmFloat, widthToLlvmInt, llvmFunTy,
+        llvmFunSig, llvmStdFunAttrs, llvmPtrBits, llvmGhcCC,
+
+        strCLabel_llvm,
+        genCmmLabelRef, genStringLabelRef
+
+    ) where
+
+#include "HsVersions.h"
+
+import Llvm
+import LlvmCodeGen.Regs
+
+import CgUtils ( activeStgRegs )
+import CLabel
+import Cmm
+
+import FastString
+import qualified Outputable as Outp
+import Unique
+import UniqFM
+
+-- ----------------------------------------------------------------------------
+-- * Some Data Types
+--
+
+type LlvmCmmTop = GenCmmTop LlvmData [CmmStatic] (ListGraph LlvmStatement)
+type LlvmBasicBlock = GenBasicBlock LlvmStatement
+
+-- | Unresolved code.
+-- Of the form: (data label, data type, unresovled data)
+type LlvmUnresData = (CLabel, LlvmType, [UnresStatic])
+
+-- | Top level LLVM Data (globals and type aliases)
+type LlvmData = ([LMGlobal], [LlvmType])
+
+-- | An unresolved Label.
+--
+-- Labels are unresolved when we haven't yet determined if they are defined in
+-- the module we are currently compiling, or an external one.
+type UnresLabel = CmmLit
+type UnresStatic = Either UnresLabel LlvmStatic
+
+-- ----------------------------------------------------------------------------
+-- * Type translations
+--
+
+-- | Translate a basic CmmType to an LlvmType.
+cmmToLlvmType :: CmmType -> LlvmType
+cmmToLlvmType ty | isFloatType ty = widthToLlvmFloat $ typeWidth ty
+                 | otherwise      = widthToLlvmInt   $ typeWidth ty
+
+-- | Translate a Cmm Float Width to a LlvmType.
+widthToLlvmFloat :: Width -> LlvmType
+widthToLlvmFloat W32  = LMFloat
+widthToLlvmFloat W64  = LMDouble
+widthToLlvmFloat W80  = LMFloat80
+widthToLlvmFloat W128 = LMFloat128
+widthToLlvmFloat w    = panic $ "widthToLlvmFloat: Bad float size: " ++ show w
+
+-- | Translate a Cmm Bit Width to a LlvmType.
+widthToLlvmInt :: Width -> LlvmType
+widthToLlvmInt w = LMInt $ widthInBits w
+
+-- | GHC Call Convention for LLVM
+llvmGhcCC :: LlvmCallConvention
+llvmGhcCC = CC_Ncc 10
+
+-- | Llvm Function type for Cmm function
+llvmFunTy :: LlvmType
+llvmFunTy
+  = LMFunction $
+        LlvmFunctionDecl (fsLit "a") ExternallyVisible llvmGhcCC LMVoid FixedArgs
+            (Left $ map getVarType llvmFunArgs)
+
+-- | Llvm Function signature
+llvmFunSig :: CLabel -> LlvmLinkageType -> LlvmFunctionDecl
+llvmFunSig lbl link
+  = let n = strCLabel_llvm lbl
+    in LlvmFunctionDecl n link llvmGhcCC LMVoid FixedArgs
+        (Right llvmFunArgs)
+
+-- | A Function's arguments
+llvmFunArgs :: [LlvmVar]
+llvmFunArgs = map lmGlobalRegArg activeStgRegs
+
+-- | Llvm standard fun attributes
+llvmStdFunAttrs :: [LlvmFuncAttr]
+llvmStdFunAttrs = [NoUnwind]
+
+-- | Pointer width
+llvmPtrBits :: Int
+llvmPtrBits = widthInBits $ typeWidth gcWord
+
+
+-- ----------------------------------------------------------------------------
+-- * Environment Handling
+--
+
+type LlvmEnvMap = UniqFM LlvmType
+-- two maps, one for functions and one for local vars.
+type LlvmEnv = (LlvmEnvMap, LlvmEnvMap)
+
+-- | Get initial Llvm environment.
+initLlvmEnv :: LlvmEnv
+initLlvmEnv = (emptyUFM, emptyUFM)
+
+-- | Clear variables from the environment.
+clearVars :: LlvmEnv -> LlvmEnv
+clearVars (e1, _) = (e1, emptyUFM)
+
+-- | Insert functions into the environment.
+varInsert, funInsert :: Uniquable key => key -> LlvmType -> LlvmEnv -> LlvmEnv
+varInsert s t (e1, e2) = (e1, addToUFM e2 s t)
+funInsert s t (e1, e2) = (addToUFM e1 s t, e2)
+
+-- | Lookup functions in the environment.
+varLookup, funLookup :: Uniquable key => key -> LlvmEnv -> Maybe LlvmType
+varLookup s (_, e2) = lookupUFM e2 s
+funLookup s (e1, _) = lookupUFM e1 s
+
+
+-- ----------------------------------------------------------------------------
+-- * Label handling
+--
+
+-- | Pretty print a 'CLabel'.
+strCLabel_llvm :: CLabel -> LMString
+strCLabel_llvm l = (fsLit . show . llvmSDoc . pprCLabel) l
+
+-- | Create an external definition for a 'CLabel' defined in another module.
+genCmmLabelRef :: CLabel -> LMGlobal
+genCmmLabelRef cl =
+    let mcl = strCLabel_llvm cl
+    in (LMGlobalVar mcl (LMPointer (LMArray 0 llvmWord)) External, Nothing)
+
+-- | As above ('genCmmLabelRef') but taking a 'LMString', not 'CLabel'.
+genStringLabelRef :: LMString -> LMGlobal
+genStringLabelRef cl =
+    (LMGlobalVar cl (LMPointer (LMArray 0 llvmWord)) External, Nothing)
+
+
+-- ----------------------------------------------------------------------------
+-- * Misc
+--
+
+-- | Error function
+panic :: String -> a
+panic s = Outp.panic $ "LlvmCodeGen.Base." ++ s
+
diff --git a/compiler/llvmGen/LlvmCodeGen/CodeGen.hs b/compiler/llvmGen/LlvmCodeGen/CodeGen.hs
new file mode 100644 (file)
index 0000000..fb29f7a
--- /dev/null
@@ -0,0 +1,958 @@
+-- ----------------------------------------------------------------------------
+-- | Handle conversion of CmmProc to LLVM code.
+--
+
+module LlvmCodeGen.CodeGen ( genLlvmProc ) where
+
+#include "HsVersions.h"
+
+import Llvm
+import LlvmCodeGen.Base
+import LlvmCodeGen.Regs
+
+import BlockId
+import CgUtils ( activeStgRegs )
+import CLabel
+import Cmm
+import qualified PprCmm
+import OrdList
+
+import BasicTypes
+import FastString
+import ForeignCall
+import Outputable hiding ( panic, pprPanic )
+import qualified Outputable
+import UniqSupply
+import Unique
+import Util
+
+type LlvmStatements = OrdList LlvmStatement
+
+-- -----------------------------------------------------------------------------
+-- | Top-level of the llvm proc codegen
+--
+genLlvmProc :: LlvmEnv -> RawCmmTop -> UniqSM (LlvmEnv, [LlvmCmmTop])
+genLlvmProc env (CmmData _ _)
+  = return (env, [])
+
+genLlvmProc env (CmmProc _ _ _ (ListGraph []))
+  = return (env, [])
+
+genLlvmProc env (CmmProc info lbl params (ListGraph blocks))
+  = do
+        (env', lmblocks, lmdata) <- basicBlocksCodeGen env blocks ([], [])
+
+        let proc    = CmmProc info lbl params (ListGraph lmblocks)
+        let tops    = lmdata ++ [proc]
+
+        return (env', tops)
+
+
+-- -----------------------------------------------------------------------------
+-- * Block code generation
+--
+
+-- | Generate code for a list of blocks that make up a complete procedure.
+basicBlocksCodeGen :: LlvmEnv
+                   -> [CmmBasicBlock]
+                   -> ( [LlvmBasicBlock] , [LlvmCmmTop] )
+                   -> UniqSM (LlvmEnv, [LlvmBasicBlock] , [LlvmCmmTop] )
+basicBlocksCodeGen env ([]) (blocks, tops)
+  = do let (blocks', allocs) = mapAndUnzip dominateAllocs blocks
+       let allocs' = concat allocs
+       let ((BasicBlock id fstmts):rblocks) = blocks'
+       let fblocks = (BasicBlock id (funPrologue ++ allocs' ++ fstmts)):rblocks
+       return (env, fblocks, tops)
+
+basicBlocksCodeGen env (block:blocks) (lblocks', ltops')
+  = do (env', lb, lt) <- basicBlockCodeGen env block
+       let lblocks = lblocks' ++ lb
+       let ltops   = ltops' ++ lt
+       basicBlocksCodeGen env' blocks (lblocks, ltops)
+
+
+-- | Generate code for one block
+basicBlockCodeGen ::  LlvmEnv
+                  -> CmmBasicBlock
+                  -> UniqSM ( LlvmEnv, [LlvmBasicBlock], [LlvmCmmTop] )
+basicBlockCodeGen env (BasicBlock id stmts)
+  = do (env', instrs, top) <- stmtsToInstrs env stmts (nilOL, [])
+       return (env', [BasicBlock id (fromOL instrs)], top)
+
+
+-- | Allocations need to be extracted so they can be moved to the entry
+-- of a function to make sure they dominate all posible paths in the CFG.
+dominateAllocs :: LlvmBasicBlock -> (LlvmBasicBlock, [LlvmStatement])
+dominateAllocs (BasicBlock id stmts)
+  = (BasicBlock id allstmts, allallocs)
+    where
+        (allstmts, allallocs) = foldl split ([],[]) stmts
+        split (stmts', allocs) s@(Assignment _ (Alloca _ _))
+            = (stmts', allocs ++ [s])
+        split (stmts', allocs) other
+            = (stmts' ++ [other], allocs)
+
+
+-- -----------------------------------------------------------------------------
+-- * CmmStmt code generation
+--
+
+-- A statement conversion return data.
+--   * LlvmEnv: The new enviornment
+--   * LlvmStatements: The compiled llvm statements.
+--   * LlvmCmmTop: Any global data needed.
+type StmtData = (LlvmEnv, LlvmStatements, [LlvmCmmTop])
+
+
+-- | Convert a list of CmmStmt's to LlvmStatement's
+stmtsToInstrs :: LlvmEnv -> [CmmStmt] -> (LlvmStatements, [LlvmCmmTop])
+              -> UniqSM StmtData
+stmtsToInstrs env [] (llvm, top)
+  = return (env, llvm, top)
+
+stmtsToInstrs env (stmt : stmts) (llvm, top)
+   = do (env', instrs, tops) <- stmtToInstrs env stmt
+        stmtsToInstrs env' stmts (llvm `appOL` instrs, top ++ tops)
+
+
+-- | Convert a CmmStmt to a list of LlvmStatement's
+stmtToInstrs :: LlvmEnv -> CmmStmt
+             -> UniqSM StmtData
+stmtToInstrs env stmt = case stmt of
+
+    CmmNop               -> return (env, nilOL, [])
+    CmmComment _         -> return (env, nilOL, []) -- nuke comments
+--  CmmComment s         -> return (env, unitOL $ Comment (lines $ unpackFS s),
+--                                  [])
+
+    CmmAssign reg src    -> genAssign env reg src
+    CmmStore addr src    -> genStore env addr src
+
+    CmmBranch id         -> genBranch env id
+    CmmCondBranch arg id -> genCondBranch env arg id
+    CmmSwitch arg ids    -> genSwitch env arg ids
+
+    -- Foreign Call
+    CmmCall target res args _ ret
+        -> genCall env target res args ret
+
+    -- Tail call
+    CmmJump arg _ -> genJump env arg
+
+    -- CPS, only tail calls, no return's
+    -- Actually, there are a few return statements that occur because of hand
+    -- written cmm code.
+    CmmReturn _
+        -> return (env, unitOL $ Return Nothing, [])
+
+
+-- | Foreign Calls
+genCall :: LlvmEnv -> CmmCallTarget -> HintedCmmFormals -> HintedCmmActuals
+              -> CmmReturnInfo -> UniqSM StmtData
+
+-- Write barrier needs to be handled specially as it is implemented as an llvm
+-- intrinsic function.
+genCall env (CmmPrim MO_WriteBarrier) _ _ _ = do
+    let fname = fsLit "llvm.memory.barrier"
+    let funSig =
+            LlvmFunctionDecl
+                fname
+                ExternallyVisible
+                CC_Ccc
+                LMVoid
+                FixedArgs
+                (Left [i1, i1, i1, i1, i1])
+    let fty = LMFunction funSig
+
+    let fv   = LMGlobalVar fname fty (funcLinkage funSig)
+    let tops = case funLookup fname env of
+                    Just _  -> []
+                    Nothing -> [CmmData Data [([],[fty])]]
+
+    let args = [lmTrue, lmTrue, lmTrue, lmTrue, lmTrue]
+    let s1 = Expr $ Call StdCall fv args llvmStdFunAttrs
+    let env' = funInsert fname fty env
+
+    return (env', unitOL s1, tops)
+
+    where
+        lmTrue :: LlvmVar
+        lmTrue  = LMLitVar $ LMIntLit (-1) i1
+
+-- Handle all other foreign calls and prim ops.
+genCall env target res args ret = do
+
+    -- paramater types
+    let arg_type (CmmHinted _ AddrHint) = pLift i8
+        -- cast pointers to i8*. Llvm equivalent of void*
+        arg_type (CmmHinted expr _    ) = cmmToLlvmType $ cmmExprType expr
+
+    -- ret type
+    let ret_type ([]) = LMVoid
+        ret_type ([CmmHinted _ AddrHint]) = pLift i8
+        ret_type ([CmmHinted reg _])        = cmmToLlvmType $ localRegType reg
+        ret_type t = panic $ "genCall: Too many return values! Can only handle"
+                        ++ " 0 or 1, given " ++ show (length t) ++ "."
+
+    -- extract cmm call convention
+    let cconv = case target of
+            CmmCallee _ conv -> conv
+            CmmPrim   _      -> PrimCallConv
+
+    -- translate to llvm call convention
+    let lmconv = case cconv of
+#if i386_TARGET_ARCH || x86_64_TARGET_ARCH
+            StdCallConv  -> CC_X86_Stdcc
+#else
+            StdCallConv  -> CC_Ccc
+#endif
+            CCallConv    -> CC_Ccc
+            PrimCallConv -> CC_Ccc
+            CmmCallConv  -> panic "CmmCallConv not supported here!"
+
+    {-
+        Some of the possibilities here are a worry with the use of a custom
+        calling convention for passing STG args. In practice the more
+        dangerous combinations (e.g StdCall + llvmGhcCC) don't occur.
+
+        The native code generator only handles StdCall and CCallConv.
+    -}
+
+    -- call attributes
+    let fnAttrs | ret == CmmNeverReturns = NoReturn : llvmStdFunAttrs
+                | otherwise              = llvmStdFunAttrs
+
+    -- fun type
+    let ccTy  = StdCall -- tail calls should be done through CmmJump
+    let retTy = ret_type res
+    let argTy = Left $ map arg_type args
+    let funTy name = LMFunction $
+            LlvmFunctionDecl name ExternallyVisible lmconv retTy FixedArgs argTy
+
+    -- get paramter values
+    (env1, argVars, stmts1, top1) <- arg_vars env args ([], nilOL, [])
+
+    -- get the return register
+    let ret_reg ([CmmHinted reg hint]) = (reg, hint)
+        ret_reg t = panic $ "genCall: Bad number of registers! Can only handle"
+                        ++ " 1, given " ++ show (length t) ++ "."
+
+    -- deal with call types
+    let getFunPtr :: CmmCallTarget -> UniqSM ExprData
+        getFunPtr targ = case targ of
+            CmmCallee (CmmLit (CmmLabel lbl)) _ -> do
+                let name = strCLabel_llvm lbl
+                case funLookup name env1 of
+                    Just ty'@(LMFunction sig) -> do
+                        -- Function in module in right form
+                        let fun = LMGlobalVar name ty' (funcLinkage sig)
+                        return (env1, fun, nilOL, [])
+
+                    Just _ -> do
+                        -- label in module but not function pointer, convert
+                        let fty@(LMFunction sig) = funTy name
+                        let fun = LMGlobalVar name fty (funcLinkage sig)
+                        (v1, s1) <- doExpr (pLift fty)
+                                        $ Cast LM_Bitcast fun (pLift fty)
+                        return  (env1, v1, unitOL s1, [])
+
+                    Nothing -> do
+                        -- label not in module, create external reference
+                        let fty@(LMFunction sig) = funTy name
+                        let fun = LMGlobalVar name fty (funcLinkage sig)
+                        let top = CmmData Data [([],[fty])]
+                        let env' = funInsert name fty env1
+                        return (env', fun, nilOL, [top])
+
+            CmmCallee expr _ -> do
+                (env', v1, stmts, top) <- exprToVar env1 expr
+                let fty = funTy $ fsLit "dynamic"
+                let cast = case getVarType v1 of
+                     ty | isPointer ty -> LM_Bitcast
+                     ty | isInt ty     -> LM_Inttoptr
+
+                     ty -> panic $ "genCall: Expr is of bad type for function"
+                                ++ " call! (" ++ show (ty) ++ ")"
+
+                (v2,s1) <- doExpr (pLift fty) $ Cast cast v1 (pLift fty)
+                return (env', v2, stmts `snocOL` s1, top)
+
+            CmmPrim mop -> do
+                let name = cmmPrimOpFunctions mop
+                let lbl  = mkForeignLabel name Nothing
+                                            ForeignLabelInExternalPackage IsFunction
+                getFunPtr $ CmmCallee (CmmLit (CmmLabel lbl)) CCallConv
+
+    (env2, fptr, stmts2, top2) <- getFunPtr target
+
+    let retStmt | ccTy == TailCall       = unitOL $ Return Nothing
+                | ret == CmmNeverReturns = unitOL $ Unreachable
+                | otherwise              = nilOL
+
+    -- make the actual call
+    case retTy of
+        LMVoid -> do
+            let s1 = Expr $ Call ccTy fptr argVars fnAttrs
+            let allStmts = stmts1 `appOL` stmts2 `snocOL` s1 `appOL` retStmt
+            return (env2, allStmts, top1 ++ top2)
+
+        _ -> do
+            let (creg, _) = ret_reg res
+            let (env3, vreg, stmts3, top3) = getCmmReg env2 (CmmLocal creg)
+            let allStmts = stmts1 `appOL` stmts2 `appOL` stmts3
+            (v1, s1) <- doExpr retTy $ Call ccTy fptr argVars fnAttrs
+            if retTy == pLower (getVarType vreg)
+                then do
+                    let s2 = Store v1 vreg
+                    return (env3, allStmts `snocOL` s1 `snocOL` s2
+                            `appOL` retStmt, top1 ++ top2 ++ top3)
+                else do
+                    let ty = pLower $ getVarType vreg
+                    let op = case ty of
+                            vt | isPointer vt -> LM_Bitcast
+                               | isInt     vt -> LM_Ptrtoint
+                               | otherwise    ->
+                                   panic $ "genCall: CmmReg bad match for"
+                                        ++ " returned type!"
+
+                    (v2, s2) <- doExpr ty $ Cast op v1 ty
+                    let s3 = Store v2 vreg
+                    return (env3, allStmts `snocOL` s1 `snocOL` s2 `snocOL` s3
+                            `appOL` retStmt, top1 ++ top2 ++ top3)
+
+
+-- | Conversion of call arguments.
+arg_vars :: LlvmEnv
+         -> HintedCmmActuals
+         -> ([LlvmVar], LlvmStatements, [LlvmCmmTop])
+         -> UniqSM (LlvmEnv, [LlvmVar], LlvmStatements, [LlvmCmmTop])
+
+arg_vars env [] (vars, stmts, tops)
+  = return (env, vars, stmts, tops)
+
+arg_vars env (CmmHinted e AddrHint:rest) (vars, stmts, tops)
+  = do (env', v1, stmts', top') <- exprToVar env e
+       let op = case getVarType v1 of
+               ty | isPointer ty -> LM_Bitcast
+               ty | isInt ty     -> LM_Inttoptr
+
+               a  -> panic $ "genCall: Can't cast llvmType to i8*! ("
+                           ++ show a ++ ")"
+
+       (v2, s1) <- doExpr (pLift i8) $ Cast op v1 (pLift i8)
+       arg_vars env' rest (vars ++ [v2], stmts `appOL` stmts' `snocOL` s1, tops ++ top')
+
+arg_vars env (CmmHinted e _:rest) (vars, stmts, tops)
+  = do (env', v1, stmts', top') <- exprToVar env e
+       arg_vars env' rest (vars ++ [v1], stmts `appOL` stmts', tops ++ top')
+
+-- | Decide what C function to use to implement a CallishMachOp
+cmmPrimOpFunctions :: CallishMachOp -> FastString
+cmmPrimOpFunctions mop
+ = case mop of
+    MO_F32_Exp    -> fsLit "expf"
+    MO_F32_Log    -> fsLit "logf"
+    MO_F32_Sqrt   -> fsLit "sqrtf"
+    MO_F32_Pwr    -> fsLit "powf"
+
+    MO_F32_Sin    -> fsLit "sinf"
+    MO_F32_Cos    -> fsLit "cosf"
+    MO_F32_Tan    -> fsLit "tanf"
+
+    MO_F32_Asin   -> fsLit "asinf"
+    MO_F32_Acos   -> fsLit "acosf"
+    MO_F32_Atan   -> fsLit "atanf"
+
+    MO_F32_Sinh   -> fsLit "sinhf"
+    MO_F32_Cosh   -> fsLit "coshf"
+    MO_F32_Tanh   -> fsLit "tanhf"
+
+    MO_F64_Exp    -> fsLit "exp"
+    MO_F64_Log    -> fsLit "log"
+    MO_F64_Sqrt   -> fsLit "sqrt"
+    MO_F64_Pwr    -> fsLit "pow"
+
+    MO_F64_Sin    -> fsLit "sin"
+    MO_F64_Cos    -> fsLit "cos"
+    MO_F64_Tan    -> fsLit "tan"
+
+    MO_F64_Asin   -> fsLit "asin"
+    MO_F64_Acos   -> fsLit "acos"
+    MO_F64_Atan   -> fsLit "atan"
+
+    MO_F64_Sinh   -> fsLit "sinh"
+    MO_F64_Cosh   -> fsLit "cosh"
+    MO_F64_Tanh   -> fsLit "tanh"
+
+    a -> panic $ "cmmPrimOpFunctions: Unknown callish op! (" ++ show a ++ ")"
+
+
+-- | Tail function calls
+genJump :: LlvmEnv -> CmmExpr -> UniqSM StmtData
+
+-- Call to known function
+genJump env (CmmLit (CmmLabel lbl)) = do
+    (env', vf, stmts, top) <- getHsFunc env lbl
+    (stgRegs, stgStmts) <- funEpilogue
+    let s1  = Expr $ Call TailCall vf stgRegs llvmStdFunAttrs
+    let s2  = Return Nothing
+    return (env', stmts `appOL` stgStmts `snocOL` s1 `snocOL` s2, top)
+
+
+-- Call to unknown function / address
+genJump env expr = do
+    let fty = llvmFunTy
+    (env', vf, stmts, top) <- exprToVar env expr
+
+    let cast = case getVarType vf of
+         ty | isPointer ty -> LM_Bitcast
+         ty | isInt ty     -> LM_Inttoptr
+
+         ty -> panic $ "genJump: Expr is of bad type for function call! ("
+                     ++ show (ty) ++ ")"
+
+    (v1, s1) <- doExpr (pLift fty) $ Cast cast vf (pLift fty)
+    (stgRegs, stgStmts) <- funEpilogue
+    let s2 = Expr $ Call TailCall v1 stgRegs llvmStdFunAttrs
+    let s3 = Return Nothing
+    return (env', stmts `snocOL` s1 `appOL` stgStmts `snocOL` s2 `snocOL` s3,
+            top)
+
+
+-- | CmmAssign operation
+--
+-- We use stack allocated variables for CmmReg. The optimiser will replace
+-- these with registers when possible.
+genAssign :: LlvmEnv -> CmmReg -> CmmExpr -> UniqSM StmtData
+genAssign env reg val = do
+    let (env1, vreg, stmts1, top1) = getCmmReg env reg
+    (env2, vval, stmts2, top2) <- exprToVar env1 val
+    let s1 = Store vval vreg
+    return (env2, stmts1 `appOL` stmts2 `snocOL` s1, top1 ++ top2)
+
+
+-- | CmmStore operation
+genStore :: LlvmEnv -> CmmExpr -> CmmExpr -> UniqSM StmtData
+genStore env addr val = do
+    (env1, vaddr, stmts1, top1) <- exprToVar env addr
+    (env2, vval,  stmts2, top2) <- exprToVar env1 val
+    if getVarType vaddr == llvmWord
+        then do
+            let vty = pLift $ getVarType vval
+            (vptr, s1) <- doExpr vty $ Cast LM_Inttoptr vaddr vty
+            let s2 = Store vval vptr
+            return (env2, stmts1 `appOL` stmts2 `snocOL` s1 `snocOL` s2,
+                    top1 ++ top2)
+
+        else
+            panic $ "genStore: ptr not of word size! (" ++ show vaddr ++ ")"
+
+
+-- | Unconditional branch
+genBranch :: LlvmEnv -> BlockId -> UniqSM StmtData
+genBranch env id =
+    let label = blockIdToLlvm id
+    in return (env, unitOL $ Branch label, [])
+
+
+-- | Conditional branch
+genCondBranch :: LlvmEnv -> CmmExpr -> BlockId -> UniqSM StmtData
+genCondBranch env cond idT = do
+    idF <- getUniqueUs
+    let labelT = blockIdToLlvm idT
+    let labelF = LMLocalVar idF LMLabel
+    (env', vc, stmts, top) <- exprToVarOpt env i1Option cond
+    if getVarType vc == i1
+        then do
+            let s1 = BranchIf vc labelT labelF
+            let s2 = MkLabel idF
+            return $ (env', stmts `snocOL` s1 `snocOL` s2, top)
+        else
+            panic $ "genCondBranch: Cond expr not bool! (" ++ show vc ++ ")"
+
+
+-- | Switch branch
+--
+-- N.B. we remove Nothing's from the list of branches, as they are 'undefined'.
+-- However, they may be defined one day, so we better document this behaviour.
+genSwitch :: LlvmEnv -> CmmExpr -> [Maybe BlockId] -> UniqSM StmtData
+genSwitch env cond maybe_ids = do
+    (env', vc, stmts, top) <- exprToVar env cond
+    let ty = getVarType vc
+
+    let pairs = [ (ix, id) | (ix,Just id) <- zip ([0..]::[Integer]) maybe_ids ]
+    let labels = map (\(ix, b) -> (mkIntLit ix ty, blockIdToLlvm b)) pairs
+    -- out of range is undefied, so lets just branch to first label
+    let (_, defLbl) = head labels
+
+    let s1 = Switch vc defLbl labels
+    return $ (env', stmts `snocOL` s1, top)
+
+
+-- -----------------------------------------------------------------------------
+-- * CmmExpr code generation
+--
+
+-- | An expression conversion return data:
+--   * LlvmEnv: The new enviornment
+--   * LlvmVar: The var holding the result of the expression
+--   * LlvmStatements: Any statements needed to evaluate the expression
+--   * LlvmCmmTop: Any global data needed for this expression
+type ExprData = (LlvmEnv, LlvmVar, LlvmStatements, [LlvmCmmTop])
+
+-- | Values which can be passed to 'exprToVar' to configure its
+-- behaviour in certain circumstances.
+data EOption = EOption {
+        -- | The expected LlvmType for the returned variable.
+        --
+        -- Currently just used for determining if a comparison should return
+        -- a boolean (i1) or a int (i32/i64).
+        eoExpectedType :: Maybe LlvmType
+  }
+
+i1Option :: EOption
+i1Option = EOption (Just i1)
+
+wordOption :: EOption
+wordOption = EOption (Just llvmWord)
+
+
+-- | Convert a CmmExpr to a list of LlvmStatements with the result of the
+-- expression being stored in the returned LlvmVar.
+exprToVar :: LlvmEnv -> CmmExpr -> UniqSM ExprData
+exprToVar env = exprToVarOpt env wordOption
+
+exprToVarOpt :: LlvmEnv -> EOption -> CmmExpr -> UniqSM ExprData
+exprToVarOpt env opt e = case e of
+
+    CmmLit lit
+        -> genLit env lit
+
+    CmmLoad e' ty
+        -> genCmmLoad env e' ty
+
+    -- Cmmreg in expression is the value, so must load. If you want actual
+    -- reg pointer, call getCmmReg directly.
+    CmmReg r -> do
+        let (env', vreg, stmts, top) = getCmmReg env r
+        (v1, s1) <- doExpr (pLower $ getVarType vreg) $ Load vreg
+        return (env', v1, stmts `snocOL` s1 , top)
+
+    CmmMachOp op exprs
+        -> genMachOp env opt op exprs
+
+    CmmRegOff r i
+        -> exprToVar env $ expandCmmReg (r, i)
+
+    CmmStackSlot _ _
+        -> panic "exprToVar: CmmStackSlot not supported!"
+
+
+-- | Handle CmmMachOp expressions
+genMachOp :: LlvmEnv -> EOption -> MachOp -> [CmmExpr] -> UniqSM ExprData
+
+-- Unary Machop
+genMachOp env _ op [x] = case op of
+
+    MO_Not w ->
+        let all1 = mkIntLit (-1::Int) (widthToLlvmInt w)
+        in negate (widthToLlvmInt w) all1 LM_MO_Xor
+
+    MO_S_Neg w ->
+        let all0 = mkIntLit (0::Int) (widthToLlvmInt w)
+        in negate (widthToLlvmInt w) all0 LM_MO_Sub
+
+    MO_F_Neg w ->
+        let all0 = LMLitVar $ LMFloatLit 0 (widthToLlvmFloat w)
+        in negate (widthToLlvmFloat w) all0 LM_MO_Sub
+
+    MO_SF_Conv _ w -> fiConv (widthToLlvmFloat w) LM_Sitofp
+    MO_FS_Conv _ w -> fiConv (widthToLlvmInt w) LM_Fptosi
+
+    MO_SS_Conv from to
+        -> sameConv from (widthToLlvmInt to) LM_Trunc LM_Sext
+
+    MO_UU_Conv from to
+        -> sameConv from (widthToLlvmInt to) LM_Trunc LM_Zext
+
+    MO_FF_Conv from to
+        -> sameConv from (widthToLlvmFloat to) LM_Fptrunc LM_Fpext
+
+    a -> panic $ "genMachOp: unmatched unary CmmMachOp! (" ++ show a ++ ")"
+
+    where
+        negate ty v2 negOp = do
+            (env', vx, stmts, top) <- exprToVar env x
+            (v1, s1) <- doExpr ty $ LlvmOp negOp v2 vx
+            return (env', v1, stmts `snocOL` s1, top)
+
+        fiConv ty convOp = do
+            (env', vx, stmts, top) <- exprToVar env x
+            (v1, s1) <- doExpr ty $ Cast convOp vx ty
+            return (env', v1, stmts `snocOL` s1, top)
+
+        sameConv from ty reduce expand = do
+            x'@(env', vx, stmts, top) <- exprToVar env x
+            let sameConv' op = do
+                (v1, s1) <- doExpr ty $ Cast op vx ty
+                return (env', v1, stmts `snocOL` s1, top)
+            let toWidth = llvmWidthInBits ty
+            -- LLVM doesn't like trying to convert to same width, so
+            -- need to check for that as we do get cmm code doing it.
+            case widthInBits from  of
+                 w | w < toWidth -> sameConv' expand
+                 w | w > toWidth -> sameConv' reduce
+                 _w              -> return x'
+
+
+-- Binary MachOp
+genMachOp env opt op [x, y] = case op of
+
+    MO_Eq _   -> genBinComp opt LM_CMP_Eq
+    MO_Ne _   -> genBinComp opt LM_CMP_Ne
+
+    MO_S_Gt _ -> genBinComp opt LM_CMP_Sgt
+    MO_S_Ge _ -> genBinComp opt LM_CMP_Sge
+    MO_S_Lt _ -> genBinComp opt LM_CMP_Slt
+    MO_S_Le _ -> genBinComp opt LM_CMP_Sle
+
+    MO_U_Gt _ -> genBinComp opt LM_CMP_Ugt
+    MO_U_Ge _ -> genBinComp opt LM_CMP_Uge
+    MO_U_Lt _ -> genBinComp opt LM_CMP_Ult
+    MO_U_Le _ -> genBinComp opt LM_CMP_Ule
+
+    MO_Add _ -> genBinMach LM_MO_Add
+    MO_Sub _ -> genBinMach LM_MO_Sub
+    MO_Mul _ -> genBinMach LM_MO_Mul
+
+    MO_U_MulMayOflo _ -> panic "genMachOp: MO_U_MulMayOflo unsupported!"
+
+    MO_S_MulMayOflo w -> isSMulOK w x y
+
+    MO_S_Quot _ -> genBinMach LM_MO_SDiv
+    MO_S_Rem  _ -> genBinMach LM_MO_SRem
+
+    MO_U_Quot _ -> genBinMach LM_MO_UDiv
+    MO_U_Rem  _ -> genBinMach LM_MO_URem
+
+    MO_F_Eq _ -> genBinComp opt LM_CMP_Feq
+    MO_F_Ne _ -> genBinComp opt LM_CMP_Fne
+    MO_F_Gt _ -> genBinComp opt LM_CMP_Fgt
+    MO_F_Ge _ -> genBinComp opt LM_CMP_Fge
+    MO_F_Lt _ -> genBinComp opt LM_CMP_Flt
+    MO_F_Le _ -> genBinComp opt LM_CMP_Fle
+
+    MO_F_Add  _ -> genBinMach LM_MO_Add
+    MO_F_Sub  _ -> genBinMach LM_MO_Sub
+    MO_F_Mul  _ -> genBinMach LM_MO_Mul
+    MO_F_Quot _ -> genBinMach LM_MO_FDiv
+
+    MO_And _   -> genBinMach LM_MO_And
+    MO_Or  _   -> genBinMach LM_MO_Or
+    MO_Xor _   -> genBinMach LM_MO_Xor
+    MO_Shl _   -> genBinMach LM_MO_Shl
+    MO_U_Shr _ -> genBinMach LM_MO_LShr
+    MO_S_Shr _ -> genBinMach LM_MO_AShr
+
+    a -> panic $ "genMachOp: unmatched binary CmmMachOp! (" ++ show a ++ ")"
+
+    where
+        binLlvmOp ty binOp = do
+            (env1, vx, stmts1, top1) <- exprToVar env x
+            (env2, vy, stmts2, top2) <- exprToVar env1 y
+            if getVarType vx == getVarType vy
+                then do
+                    (v1, s1) <- doExpr (ty vx) $ binOp vx vy
+                    return (env2, v1, stmts1 `appOL` stmts2 `snocOL` s1,
+                            top1 ++ top2)
+
+                else do
+                    -- XXX: Error. Continue anyway so we can debug the generated
+                    -- ll file.
+                    let cmmToStr = (lines . show . llvmSDoc . PprCmm.pprExpr)
+                    let dx = Comment $ map fsLit $ cmmToStr x
+                    let dy = Comment $ map fsLit $ cmmToStr y
+                    (v1, s1) <- doExpr (ty vx) $ binOp vx vy
+                    let allStmts = stmts1 `appOL` stmts2 `snocOL` dx
+                                    `snocOL` dy `snocOL` s1
+                    return (env2, v1, allStmts, top1 ++ top2)
+
+                    -- let o = case binOp vx vy of
+                    --         Compare op _ _ -> show op
+                    --         LlvmOp  op _ _ -> show op
+                    --         _              -> "unknown"
+                    -- panic $ "genMachOp: comparison between different types ("
+                    --         ++ o ++ " "++ show vx ++ ", " ++ show vy ++ ")"
+                    --         ++ "\ne1: " ++ (show.llvmSDoc.PprCmm.pprExpr $ x)
+                    --         ++ "\ne2: " ++ (show.llvmSDoc.PprCmm.pprExpr $ y)
+
+        -- | Need to use EOption here as Cmm expects word size results from
+        -- comparisons while llvm return i1. Need to extend to llvmWord type
+        -- if expected
+        genBinComp opt cmp = do
+            ed@(env', v1, stmts, top) <- binLlvmOp (\_ -> i1) $ Compare cmp
+
+            if getVarType v1 == i1
+                then
+                    case eoExpectedType opt of
+                         Nothing ->
+                             return ed
+
+                         Just t | t == i1 ->
+                                    return ed
+
+                                | isInt t -> do
+                                    (v2, s1) <- doExpr t $ Cast LM_Zext v1 t
+                                    return (env', v2, stmts `snocOL` s1, top)
+
+                                | otherwise ->
+                                    panic $ "genBinComp: Can't case i1 compare"
+                                        ++ "res to non int type " ++ show (t)
+                else
+                    panic $ "genBinComp: Compare returned type other then i1! "
+                        ++ (show $ getVarType v1)
+
+        genBinMach op = binLlvmOp getVarType (LlvmOp op)
+
+        -- | Detect if overflow will occur in signed multiply of the two
+        -- CmmExpr's. This is the LLVM assembly equivalent of the NCG
+        -- implementation. Its much longer due to type information/safety.
+        -- This should actually compile to only about 3 asm instructions.
+        isSMulOK :: Width -> CmmExpr -> CmmExpr -> UniqSM ExprData
+        isSMulOK _ x y = do
+            (env1, vx, stmts1, top1) <- exprToVar env x
+            (env2, vy, stmts2, top2) <- exprToVar env1 y
+
+            let word  = getVarType vx
+            let word2 = LMInt $ 2 * (llvmWidthInBits $ getVarType vx)
+            let shift = llvmWidthInBits word
+            let shift1 = mkIntLit (shift - 1) llvmWord
+            let shift2 = mkIntLit shift llvmWord
+
+            if isInt word
+                then do
+                    (x1, s1)     <- doExpr word2 $ Cast LM_Sext vx word2
+                    (y1, s2)     <- doExpr word2 $ Cast LM_Sext vy word2
+                    (r1, s3)     <- doExpr word2 $ LlvmOp LM_MO_Mul x1 y1
+                    (rlow1, s4)  <- doExpr word $ Cast LM_Trunc r1 word
+                    (rlow2, s5)  <- doExpr word $ LlvmOp LM_MO_AShr rlow1 shift1
+                    (rhigh1, s6) <- doExpr word2 $ LlvmOp LM_MO_AShr r1 shift2
+                    (rhigh2, s7) <- doExpr word $ Cast LM_Trunc rhigh1 word
+                    (dst, s8)    <- doExpr word $ LlvmOp LM_MO_Sub rlow2 rhigh2
+                    let stmts = (unitOL s1) `snocOL` s2 `snocOL` s3 `snocOL` s4
+                            `snocOL` s5 `snocOL` s6 `snocOL` s7 `snocOL` s8
+                    return (env2, dst, stmts1 `appOL` stmts2 `appOL` stmts,
+                        top1 ++ top2)
+
+                else
+                    panic $ "isSMulOK: Not bit type! (" ++ show word ++ ")"
+
+
+-- More then two expression, invalid!
+genMachOp _ _ _ _ = panic "genMachOp: More then 2 expressions in MachOp!"
+
+
+-- | Handle CmmLoad expression
+genCmmLoad :: LlvmEnv -> CmmExpr -> CmmType -> UniqSM ExprData
+genCmmLoad env e ty = do
+    (env', iptr, stmts, tops) <- exprToVar env e
+    let ety = getVarType iptr
+    case (isInt ety) of
+         True | llvmPtrBits == llvmWidthInBits ety ->  do
+                    let pty = LMPointer $ cmmToLlvmType ty
+                    (ptr, cast)  <- doExpr pty $ Cast LM_Inttoptr iptr pty
+                    (dvar, load) <- doExpr (cmmToLlvmType ty) $ Load ptr
+                    return (env', dvar, stmts `snocOL` cast `snocOL` load, tops)
+
+              | otherwise
+                -> pprPanic
+                        ("exprToVar: can't cast to pointer as int not of "
+                            ++ "pointer size!")
+                        (PprCmm.pprExpr e <+> text (
+                            "Size of Ptr: " ++ show llvmPtrBits ++
+                            ", Size of var: " ++ show (llvmWidthInBits ety) ++
+                            ", Var: " ++ show iptr))
+
+         False -> panic "exprToVar: CmmLoad expression is not of type int!"
+
+
+-- | Handle CmmReg expression
+--
+-- We allocate CmmReg on the stack. This avoids having to map a CmmReg to an
+-- equivalent SSA form and avoids having to deal with Phi node insertion.
+-- This is also the approach recommended by llvm developers.
+getCmmReg :: LlvmEnv -> CmmReg -> ExprData
+getCmmReg env r@(CmmLocal (LocalReg un _))
+  = let exists = varLookup un env
+
+        (newv, stmts) = allocReg r
+        nenv = varInsert un (pLower $ getVarType newv) env
+    in case exists of
+            Just ety -> (env, (LMLocalVar un $ pLift ety), nilOL, [])
+            Nothing  -> (nenv, newv, stmts, [])
+
+getCmmReg env (CmmGlobal g) = (env, lmGlobalRegVar g, nilOL, [])
+
+
+-- | Allocate a CmmReg on the stack
+allocReg :: CmmReg -> (LlvmVar, LlvmStatements)
+allocReg (CmmLocal (LocalReg un ty))
+  = let ty' = cmmToLlvmType ty
+        var = LMLocalVar un (LMPointer ty')
+        alc = Alloca ty' 1
+    in (var, unitOL $ Assignment var alc)
+
+allocReg _ = panic $ "allocReg: Global reg encountered! Global registers should"
+                    ++ " have been handled elsewhere!"
+
+
+-- | Generate code for a literal
+genLit :: LlvmEnv -> CmmLit -> UniqSM ExprData
+genLit env (CmmInt i w)
+  = return (env, mkIntLit i (LMInt $ widthInBits w), nilOL, [])
+
+genLit env (CmmFloat r w)
+  = return (env, LMLitVar $ LMFloatLit r (widthToLlvmFloat w), nilOL, [])
+
+genLit env cmm@(CmmLabel l)
+  = let label = strCLabel_llvm l
+        ty = funLookup label env
+        lmty = cmmToLlvmType $ cmmLitType cmm
+    in case ty of
+            -- Make generic external label defenition and then pointer to it
+            Nothing -> do
+                let glob@(var, _) = genStringLabelRef label
+                let ldata = [CmmData Data [([glob], [])]]
+                let env' = funInsert label (pLower $ getVarType var) env
+                (v1, s1) <- doExpr lmty $ Cast LM_Ptrtoint var llvmWord
+                return (env', v1, unitOL s1, ldata)
+            -- Referenced data exists in this module, retrieve type and make
+            -- pointer to it.
+            Just ty' -> do
+                let var = LMGlobalVar label (LMPointer ty') ExternallyVisible
+                (v1, s1) <- doExpr lmty $ Cast LM_Ptrtoint var llvmWord
+                return (env, v1, unitOL s1, [])
+
+genLit env (CmmLabelOff label off) = do
+    (env', vlbl, stmts, stat) <- genLit env (CmmLabel label)
+    let voff = mkIntLit off llvmWord
+    (v1, s1) <- doExpr (getVarType vlbl) $ LlvmOp LM_MO_Add vlbl voff
+    return (env', v1, stmts `snocOL` s1, stat)
+
+genLit env (CmmLabelDiffOff l1 l2 off) = do
+    (env1, vl1, stmts1, stat1) <- genLit env (CmmLabel l1)
+    (env2, vl2, stmts2, stat2) <- genLit env1 (CmmLabel l2)
+    let voff = mkIntLit off llvmWord
+    let ty1 = getVarType vl1
+    let ty2 = getVarType vl2
+    if (isInt ty1) && (isInt ty2)
+       && (llvmWidthInBits ty1 == llvmWidthInBits ty2)
+
+       then do
+            (v1, s1) <- doExpr (getVarType vl1) $ LlvmOp LM_MO_Sub vl1 vl2
+            (v2, s2) <- doExpr (getVarType v1 ) $ LlvmOp LM_MO_Add v1 voff
+            return (env2, v2, stmts1 `appOL` stmts2 `snocOL` s1 `snocOL` s2,
+                        stat1 ++ stat2)
+
+        else
+            panic "genLit: CmmLabelDiffOff encountered with different label ty!"
+
+genLit env (CmmBlock b)
+  = genLit env (CmmLabel $ infoTblLbl b)
+
+genLit _ CmmHighStackMark
+  = panic "genStaticLit - CmmHighStackMark unsupported!"
+
+
+-- -----------------------------------------------------------------------------
+-- * Misc
+--
+
+-- | Function prologue. Load STG arguments into variables for function.
+funPrologue :: [LlvmStatement]
+funPrologue = concat $ map getReg activeStgRegs
+    where getReg rr =
+            let reg = lmGlobalRegVar rr
+                arg = lmGlobalRegArg rr
+                alloc = Assignment reg $ Alloca (pLower $ getVarType reg) 1
+                store = Store arg reg
+            in [alloc, store]
+
+
+-- | Function epilogue. Load STG variables to use as argument for call.
+funEpilogue :: UniqSM ([LlvmVar], LlvmStatements)
+funEpilogue = do
+    let loadExpr r = do
+        (v,s) <- doExpr (pLower $ getVarType r) $ Load r
+        return (v, unitOL s)
+    loads <- mapM (loadExpr . lmGlobalRegVar) activeStgRegs
+    let (vars, stmts) = unzip loads
+    return (vars, concatOL stmts)
+
+
+-- | Get a function pointer to the CLabel specified.
+--
+-- This is for Haskell functions, function type is assumed, so doesn't work
+-- with foreign functions.
+getHsFunc :: LlvmEnv -> CLabel -> UniqSM ExprData
+getHsFunc env lbl
+  = let fname = strCLabel_llvm lbl
+        ty    = funLookup fname env
+    in case ty of
+        Just ty'@(LMFunction sig) -> do
+        -- Function in module in right form
+            let fun = LMGlobalVar fname ty' (funcLinkage sig)
+            return (env, fun, nilOL, [])
+        Just ty' -> do
+        -- label in module but not function pointer, convert
+            let fun = LMGlobalVar fname (pLift ty') ExternallyVisible
+            (v1, s1) <- doExpr (pLift llvmFunTy) $ Cast LM_Bitcast fun (pLift llvmFunTy)
+            return (env, v1, unitOL s1, [])
+        Nothing  -> do
+        -- label not in module, create external reference
+            let ty' = LMFunction $ llvmFunSig lbl ExternallyVisible
+            let fun = LMGlobalVar fname ty' ExternallyVisible
+            let top = CmmData Data [([],[ty'])]
+            let env' = funInsert fname ty' env
+            return (env', fun, nilOL, [top])
+
+
+-- | Create a new local var
+mkLocalVar :: LlvmType -> UniqSM LlvmVar
+mkLocalVar ty = do
+    un <- getUniqueUs
+    return $ LMLocalVar un ty
+
+
+-- | Execute an expression, assigning result to a var
+doExpr :: LlvmType -> LlvmExpression -> UniqSM (LlvmVar, LlvmStatement)
+doExpr ty expr = do
+    v <- mkLocalVar ty
+    return (v, Assignment v expr)
+
+
+-- | Expand CmmRegOff
+expandCmmReg :: (CmmReg, Int) -> CmmExpr
+expandCmmReg (reg, off)
+  = let width = typeWidth (cmmRegType reg)
+        voff  = CmmLit $ CmmInt (fromIntegral off) width
+    in CmmMachOp (MO_Add width) [CmmReg reg, voff]
+
+
+-- | Convert a block id into a appropriate Llvm label
+blockIdToLlvm :: BlockId -> LlvmVar
+blockIdToLlvm bid = LMLocalVar (getUnique bid) LMLabel
+
+
+-- | Create Llvm int Literal
+mkIntLit :: Integral a => a -> LlvmType -> LlvmVar
+mkIntLit i ty = LMLitVar $ LMIntLit (toInteger i) ty
+
+
+-- | Error functions
+panic :: String -> a
+panic s = Outputable.panic $ "LlvmCodeGen.CodeGen." ++ s
+
+pprPanic :: String -> SDoc -> a
+pprPanic s d = Outputable.pprPanic ("LlvmCodeGen.CodeGen." ++ s) d
+
diff --git a/compiler/llvmGen/LlvmCodeGen/Data.hs b/compiler/llvmGen/LlvmCodeGen/Data.hs
new file mode 100644 (file)
index 0000000..a5b82aa
--- /dev/null
@@ -0,0 +1,190 @@
+-- ----------------------------------------------------------------------------
+-- | Handle conversion of CmmData to LLVM code.
+--
+
+module LlvmCodeGen.Data (
+        genLlvmData, resolveLlvmDatas, resolveLlvmData
+    ) where
+
+#include "HsVersions.h"
+
+import Llvm
+import LlvmCodeGen.Base
+
+import BlockId
+import CLabel
+import Cmm
+
+import DynFlags
+import FastString
+import qualified Outputable
+
+import Data.Maybe
+
+
+-- ----------------------------------------------------------------------------
+-- * Constants
+--
+
+-- | The string appended to a variable name to create its structure type alias
+structStr :: LMString
+structStr = fsLit "_struct"
+
+-- ----------------------------------------------------------------------------
+-- * Top level
+--
+
+-- | Pass a CmmStatic section to an equivalent Llvm code. Can't
+-- complete this completely though as we need to pass all CmmStatic
+-- sections before all references can be resolved. This last step is
+-- done by 'resolveLlvmData'.
+genLlvmData :: DynFlags -> (Section, [CmmStatic]) -> LlvmUnresData
+genLlvmData _ ( _ , (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, alias, static)
+
+genLlvmData _ _ = panic "genLlvmData: CmmData section doesn't start with label!"
+
+resolveLlvmDatas :: DynFlags -> LlvmEnv -> [LlvmUnresData] -> [LlvmData]
+                 -> (LlvmEnv, [LlvmData])
+resolveLlvmDatas _ env [] ldata
+  = (env, ldata)
+
+resolveLlvmDatas dflags env (udata : rest) ldata
+  = let (env', ndata) = resolveLlvmData dflags env udata
+    in resolveLlvmDatas dflags env' rest (ldata ++ [ndata])
+
+-- | Fix up CLabel references now that we should have passed all CmmData.
+resolveLlvmData :: DynFlags -> LlvmEnv -> LlvmUnresData -> (LlvmEnv, LlvmData)
+resolveLlvmData _ env (lbl, 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
+        glob           = LMGlobalVar label alias link
+    in (env', (refs' ++ [(glob, struct)], [alias]))
+
+
+-- ----------------------------------------------------------------------------
+-- ** Resolve Data/CLabel references
+--
+
+-- | Resolve data list
+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)
+
+-- | Resolve an individual static label if it needs to be.
+--
+-- We check the 'LlvmEnv' to see if the reference has been defined in this
+-- module. If it has we can retrieve its type and make a pointer, otherwise
+-- we introduce a generic external defenition for the referenced label and
+-- then make a pointer.
+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
+            -- Make generic external label defenition and then pointer to it
+            Nothing ->
+                let glob@(var, _) = genStringLabelRef label
+                    env' =  funInsert label (pLower $ getVarType var) env
+                    ptr  = LMStaticPointer var
+                in  (env', LMPtoI ptr lmty, [Just glob])
+            -- Referenced data exists in this module, retrieve type and make
+            -- pointer to it.
+            Just ty' ->
+                let var = LMGlobalVar label (LMPointer ty') ExternallyVisible
+                    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!"
+
+-- ----------------------------------------------------------------------------
+-- * Generate static data
+--
+
+-- | Handle static data
+-- Don't handle 'CmmAlign' or a 'CmmDataLabel'.
+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!"
+
+
+-- | Generate Llvm code for a static literal.
+--
+-- Will either generate the code or leave it unresolved if it is a 'CLabel'
+-- which isn't yet known.
+genStaticLit :: CmmLit -> UnresStatic
+genStaticLit (CmmInt i w)
+    = Right $ LMStaticLit (LMIntLit i (LMInt $ widthInBits w))
+
+genStaticLit (CmmFloat r w)
+    = Right $ LMStaticLit (LMFloatLit r (widthToLlvmFloat w))
+
+-- Leave unresolved, will fix later
+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!"
+
+
+-- -----------------------------------------------------------------------------
+-- * Misc
+--
+
+-- | Error Function
+panic :: String -> a
+panic s = Outputable.panic $ "LlvmCodeGen.Data." ++ s
+
diff --git a/compiler/llvmGen/LlvmCodeGen/Ppr.hs b/compiler/llvmGen/LlvmCodeGen/Ppr.hs
new file mode 100644 (file)
index 0000000..bccc336
--- /dev/null
@@ -0,0 +1,91 @@
+-- ----------------------------------------------------------------------------
+-- | Pretty print helpers for the LLVM Code generator.
+--
+
+module LlvmCodeGen.Ppr (
+        pprLlvmHeader, pprLlvmCmmTop, pprLlvmData
+    ) where
+
+#include "HsVersions.h"
+
+import Llvm
+import LlvmCodeGen.Base
+import LlvmCodeGen.Data
+
+import CLabel
+import Cmm
+
+import DynFlags
+import Pretty
+import Unique
+
+-- ----------------------------------------------------------------------------
+-- * Top level
+--
+
+-- | LLVM module layout description for the host target
+moduleLayout :: Doc
+moduleLayout = 
+#ifdef i386_TARGET_ARCH
+
+#ifdef darwin_TARGET_OS
+    (text "target datalayout = \"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128\"")
+    $+$ (text "target triple = \"i386-apple-darwin9.8\"")
+#else
+    (text "target datalayout = \"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32\"")
+    $+$ (text "target triple = \"i386-linux-gnu\"")
+#endif
+
+#else
+
+#ifdef x86_64_TARGET_ARCH 
+    (text "target datalayout = \"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128\"")
+    $+$ (text "target triple = \"x86_64-linux-gnu\"")
+
+#else /* Not i386 */
+    -- FIX: Other targets
+    empty
+#endif
+
+#endif
+
+-- | Header code for LLVM modules
+pprLlvmHeader :: Doc
+pprLlvmHeader = moduleLayout
+
+-- | Pretty print LLVM code
+pprLlvmCmmTop :: DynFlags -> LlvmCmmTop -> Doc
+pprLlvmCmmTop dflags (CmmData _ lmdata)
+  = vcat $ map (pprLlvmData dflags) lmdata
+
+pprLlvmCmmTop dflags (CmmProc info lbl _ (ListGraph blocks))
+  = (
+        let static = CmmDataLabel (entryLblToInfoLbl lbl) : info
+        in if not (null info)
+            then pprCmmStatic dflags static
+            else empty
+    ) $+$ (
+        let link = if (externallyVisibleCLabel lbl)
+                        then ExternallyVisible else Internal
+            funDec = llvmFunSig lbl link
+            lmblocks = map (\(BasicBlock id stmts) -> LlvmBlock (getUnique id) stmts) blocks
+            fun = LlvmFunction funDec [NoUnwind] lmblocks
+        in ppLlvmFunction fun
+    )
+
+
+-- | Pretty print LLVM data code
+pprLlvmData :: DynFlags -> LlvmData -> Doc
+pprLlvmData _ (globals, types ) =
+    let globals' = ppLlvmGlobals globals
+        types'   = ppLlvmTypes types
+    in types' $+$ globals'
+
+
+-- | Pretty print CmmStatic
+pprCmmStatic :: DynFlags -> [CmmStatic] -> Doc
+pprCmmStatic dflags stat
+  = let unres = genLlvmData dflags (Data,stat)
+        (_, ldata) = resolveLlvmData dflags initLlvmEnv unres
+    in pprLlvmData dflags ldata
+
diff --git a/compiler/llvmGen/LlvmCodeGen/Regs.hs b/compiler/llvmGen/LlvmCodeGen/Regs.hs
new file mode 100644 (file)
index 0000000..b731a86
--- /dev/null
@@ -0,0 +1,54 @@
+-- ----------------------------------------------------------------------------
+-- | Deal with Cmm registers
+--
+
+module LlvmCodeGen.Regs (
+        lmGlobalRegArg, lmGlobalRegVar
+    ) where
+
+#include "HsVersions.h"
+
+import Llvm
+
+import CmmExpr
+import Outputable ( panic )
+import FastString
+
+-- | Get the LlvmVar function variable storing the real register
+lmGlobalRegVar :: GlobalReg -> LlvmVar
+lmGlobalRegVar = lmGlobalReg "_Var"
+
+-- | Get the LlvmVar function argument storing the real register
+lmGlobalRegArg :: GlobalReg -> LlvmVar
+lmGlobalRegArg = (pVarLower . lmGlobalReg "_Arg")
+
+{- Need to make sure the names here can't conflict with the unique generated
+   names. Uniques generated names containing only base62 chars. So using say
+    the '_' char guarantees this.
+-}
+lmGlobalReg :: String -> GlobalReg -> LlvmVar
+lmGlobalReg suf reg
+  = case reg of
+        BaseReg        -> wordGlobal $ "Base" ++ suf
+        Sp             -> wordGlobal $ "Sp" ++ suf
+        Hp             -> wordGlobal $ "Hp" ++ suf
+        VanillaReg 1 _ -> wordGlobal $ "R1" ++ suf
+        VanillaReg 2 _ -> wordGlobal $ "R2" ++ suf
+        VanillaReg 3 _ -> wordGlobal $ "R3" ++ suf
+        VanillaReg 4 _ -> wordGlobal $ "R4" ++ suf
+        VanillaReg 5 _ -> wordGlobal $ "R5" ++ suf
+        VanillaReg 6 _ -> wordGlobal $ "R6" ++ suf
+        SpLim          -> wordGlobal $ "SpLim" ++ suf
+        FloatReg 1     -> floatGlobal $"F1" ++ suf
+        FloatReg 2     -> floatGlobal $"F2" ++ suf
+        FloatReg 3     -> floatGlobal $"F3" ++ suf
+        FloatReg 4     -> floatGlobal $"F4" ++ suf
+        DoubleReg 1    -> doubleGlobal $ "D1" ++ suf
+        DoubleReg 2    -> doubleGlobal $ "D2" ++ suf
+        _other         -> panic $ "LlvmCodeGen.Reg: GlobalReg (" ++ (show reg)
+                                ++ ") not supported!"
+    where
+        wordGlobal   name = LMNLocalVar (fsLit name) llvmWordPtr
+        floatGlobal  name = LMNLocalVar (fsLit name) $ pLift LMFloat
+        doubleGlobal name = LMNLocalVar (fsLit name) $ pLift LMDouble
+
index 83f23cf..40f4f11 100644 (file)
@@ -9,10 +9,14 @@ module CodeOutput( codeOutput, outputForeignStubs ) where
 #include "HsVersions.h"
 
 #ifndef OMIT_NATIVE_CODEGEN
 #include "HsVersions.h"
 
 #ifndef OMIT_NATIVE_CODEGEN
-import UniqSupply      ( mkSplitUniqSupply )
 import AsmCodeGen      ( nativeCodeGen )
 #endif
 
 import AsmCodeGen      ( nativeCodeGen )
 #endif
 
+import UniqSupply      ( mkSplitUniqSupply )
+#ifndef GHCI_TABLES_NEXT_TO_CODE
+import qualified LlvmCodeGen ( llvmCodeGen )
+#endif
+
 #ifdef JAVA
 import JavaGen         ( javaGen )
 import qualified PrintJava
 #ifdef JAVA
 import JavaGen         ( javaGen )
 import qualified PrintJava
@@ -81,6 +85,7 @@ codeOutput dflags this_mod location foreign_stubs pkg_deps flat_abstractC
              HscInterpreted -> return ();
              HscAsm         -> outputAsm dflags filenm flat_abstractC;
              HscC           -> outputC dflags filenm flat_abstractC pkg_deps;
              HscInterpreted -> return ();
              HscAsm         -> outputAsm dflags filenm flat_abstractC;
              HscC           -> outputC dflags filenm flat_abstractC pkg_deps;
+             HscLlvm        -> outputLlvm dflags filenm flat_abstractC;
              HscJava        -> 
 #ifdef JAVA
                               outputJava dflags filenm mod_name tycons core_binds;
              HscJava        -> 
 #ifdef JAVA
                               outputJava dflags filenm mod_name tycons core_binds;
@@ -168,6 +173,30 @@ outputAsm _ _ _
 
 %************************************************************************
 %*                                                                     *
 
 %************************************************************************
 %*                                                                     *
+\subsection{LLVM}
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+outputLlvm :: DynFlags -> FilePath -> [RawCmm] -> IO ()
+
+#ifndef GHCI_TABLES_NEXT_TO_CODE
+outputLlvm dflags filenm flat_absC
+  = do ncg_uniqs <- mkSplitUniqSupply 'n'
+       doOutput filenm $ \f -> 
+                LlvmCodeGen.llvmCodeGen dflags f ncg_uniqs flat_absC
+#else
+outputLlvm _ _ _
+  = pprPanic "This compiler was built with the LLVM backend disabled"
+            (text ("This is because the TABLES_NEXT_TO_CODE optimisation is"
+         ++ " enabled, which the LLVM backend doesn't support right now.")
+         $+$ text "Use -fasm instead")
+#endif
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
 \subsection{Java}
 %*                                                                     *
 %************************************************************************
 \subsection{Java}
 %*                                                                     *
 %************************************************************************
index eb64134..398da79 100644 (file)
@@ -80,6 +80,9 @@ data Phase
         | SplitMangle   -- after mangler if splitting
         | SplitAs
         | As
         | SplitMangle   -- after mangler if splitting
         | SplitAs
         | As
+       | LlvmAs        -- LLVM assembly to bitcode file
+       | LlvmOpt       -- Run LLVM opt tool over llvm assembly
+       | LlvmLlc       -- LLVM bitcode to native assembly
         | CmmCpp        -- pre-process Cmm source
         | Cmm           -- parse & compile Cmm code
 
         | CmmCpp        -- pre-process Cmm source
         | Cmm           -- parse & compile Cmm code
 
@@ -109,6 +112,9 @@ eqPhase Mangle      Mangle      = True
 eqPhase SplitMangle SplitMangle = True
 eqPhase SplitAs     SplitAs     = True
 eqPhase As          As          = True
 eqPhase SplitMangle SplitMangle = True
 eqPhase SplitAs     SplitAs     = True
 eqPhase As          As          = True
+eqPhase LlvmAs     LlvmAs      = True
+eqPhase LlvmOpt            LlvmOpt     = True
+eqPhase LlvmLlc            LlvmLlc     = True
 eqPhase CmmCpp      CmmCpp      = True
 eqPhase Cmm         Cmm         = True
 eqPhase StopLn      StopLn      = True
 eqPhase CmmCpp      CmmCpp      = True
 eqPhase Cmm         Cmm         = True
 eqPhase StopLn      StopLn      = True
@@ -133,6 +139,9 @@ nextPhase HCc           = Mangle
 nextPhase Mangle        = SplitMangle
 nextPhase SplitMangle   = As
 nextPhase As            = SplitAs
 nextPhase Mangle        = SplitMangle
 nextPhase SplitMangle   = As
 nextPhase As            = SplitAs
+nextPhase LlvmAs       = LlvmOpt
+nextPhase LlvmOpt      = LlvmLlc
+nextPhase LlvmLlc      = As
 nextPhase SplitAs       = StopLn
 nextPhase Ccpp          = As
 nextPhase Cc            = As
 nextPhase SplitAs       = StopLn
 nextPhase Ccpp          = As
 nextPhase Cc            = As
@@ -160,6 +169,9 @@ startPhase "raw_s"    = Mangle
 startPhase "split_s"  = SplitMangle
 startPhase "s"        = As
 startPhase "S"        = As
 startPhase "split_s"  = SplitMangle
 startPhase "s"        = As
 startPhase "S"        = As
+startPhase "ll"       = LlvmAs
+startPhase "bc"       = LlvmOpt
+startPhase "opt_bc"   = LlvmLlc
 startPhase "o"        = StopLn
 startPhase "cmm"      = CmmCpp
 startPhase "cmmcpp"   = Cmm
 startPhase "o"        = StopLn
 startPhase "cmm"      = CmmCpp
 startPhase "cmmcpp"   = Cmm
@@ -184,6 +196,9 @@ phaseInputExt Cc                  = "c"
 phaseInputExt Mangle              = "raw_s"
 phaseInputExt SplitMangle         = "split_s"   -- not really generated
 phaseInputExt As                  = "s"
 phaseInputExt Mangle              = "raw_s"
 phaseInputExt SplitMangle         = "split_s"   -- not really generated
 phaseInputExt As                  = "s"
+phaseInputExt LlvmAs             = "ll"
+phaseInputExt LlvmOpt            = "bc"
+phaseInputExt LlvmLlc            = "opt_bc"
 phaseInputExt SplitAs             = "split_s"   -- not really generated
 phaseInputExt CmmCpp              = "cmm"
 phaseInputExt Cmm                 = "cmmcpp"
 phaseInputExt SplitAs             = "split_s"   -- not really generated
 phaseInputExt CmmCpp              = "cmm"
 phaseInputExt Cmm                 = "cmmcpp"
@@ -195,7 +210,7 @@ haskellish_src_suffixes, haskellish_suffixes, cish_suffixes,
 haskellish_src_suffixes      = haskellish_user_src_suffixes ++
                                [ "hspp", "hscpp", "hcr", "cmm" ]
 haskellish_suffixes          = haskellish_src_suffixes ++ ["hc", "raw_s"]
 haskellish_src_suffixes      = haskellish_user_src_suffixes ++
                                [ "hspp", "hscpp", "hcr", "cmm" ]
 haskellish_suffixes          = haskellish_src_suffixes ++ ["hc", "raw_s"]
-cish_suffixes                = [ "c", "cpp", "C", "cc", "cxx", "s", "S" ]
+cish_suffixes                = [ "c", "cpp", "C", "cc", "cxx", "s", "S", "ll", "bc", "opt_bc" ]
 extcoreish_suffixes          = [ "hcr" ]
 -- Will not be deleted as temp files:
 haskellish_user_src_suffixes = [ "hs", "lhs", "hs-boot", "lhs-boot" ]
 extcoreish_suffixes          = [ "hcr" ]
 -- Will not be deleted as temp files:
 haskellish_user_src_suffixes = [ "hs", "lhs", "hs-boot", "lhs-boot" ]
index c6d3d0a..7274f2a 100644 (file)
@@ -605,6 +605,7 @@ getOutputFilename stop_phase output basename
                 keep_hc    = dopt Opt_KeepHcFiles dflags
                 keep_raw_s = dopt Opt_KeepRawSFiles dflags
                 keep_s     = dopt Opt_KeepSFiles dflags
                 keep_hc    = dopt Opt_KeepHcFiles dflags
                 keep_raw_s = dopt Opt_KeepRawSFiles dflags
                 keep_s     = dopt Opt_KeepSFiles dflags
+               keep_bc    = dopt Opt_KeepLlvmFiles dflags
 
                 myPhaseInputExt HCc    = hcsuf
                 myPhaseInputExt StopLn = osuf
 
                 myPhaseInputExt HCc    = hcsuf
                 myPhaseInputExt StopLn = osuf
@@ -615,11 +616,13 @@ getOutputFilename stop_phase output basename
                 -- sometimes, we keep output from intermediate stages
                 keep_this_output =
                      case next_phase of
                 -- sometimes, we keep output from intermediate stages
                 keep_this_output =
                      case next_phase of
-                             StopLn              -> True
-                             Mangle | keep_raw_s -> True
-                             As     | keep_s     -> True
-                             HCc    | keep_hc    -> True
-                             _other              -> False
+                             StopLn               -> True
+                             Mangle  | keep_raw_s -> True
+                             As      | keep_s     -> True
+                            LlvmAs  | keep_bc    -> True
+                            LlvmOpt | keep_bc    -> True
+                             HCc     | keep_hc    -> True
+                             _other               -> False
 
                 suffix = myPhaseInputExt next_phase
 
 
                 suffix = myPhaseInputExt next_phase
 
@@ -1232,6 +1235,77 @@ runPhase SplitAs _stop hsc_env _basename _suff _input_fn get_output_fn maybe_loc
 
         return (StopLn, dflags, maybe_loc, output_fn)
 
 
         return (StopLn, dflags, maybe_loc, output_fn)
 
+
+-----------------------------------------------------------------------------
+-- LlvmAs phase
+
+runPhase LlvmAs _stop hsc_env _basename _suff input_fn get_output_fn maybe_loc
+  = liftIO $ do
+       let dflags  = hsc_dflags hsc_env
+       let la_opts = getOpts dflags opt_la
+
+       output_fn <- get_output_fn dflags LlvmOpt maybe_loc
+
+       SysTools.runLlvmAs dflags
+                      (map SysTools.Option la_opts
+                      ++ [ SysTools.FileOption "" input_fn,
+                           SysTools.Option "-o", SysTools.FileOption "" output_fn])
+
+       return (LlvmOpt, dflags, maybe_loc, output_fn)
+
+
+-----------------------------------------------------------------------------
+-- LlvmOpt phase
+
+runPhase LlvmOpt _stop hsc_env _basename _suff input_fn get_output_fn maybe_loc
+  = liftIO $ do
+       let dflags  = hsc_dflags hsc_env
+       let lo_opts = getOpts dflags opt_lo
+       let opt_lvl = max 0 (min 2 $ optLevel dflags)
+
+    -- only run if > 0 OR opt options given by user
+       if opt_lvl /= 0 || lo_opts /= []
+               then do
+                       output_fn <- get_output_fn dflags LlvmLlc maybe_loc
+
+                       SysTools.runLlvmOpt dflags
+                                      (map SysTools.Option lo_opts
+                                      ++ [ SysTools.FileOption "" input_fn,
+                                           SysTools.Option (llvmOpts !! opt_lvl),
+                                           SysTools.Option "-o",
+                                           SysTools.FileOption "" output_fn])
+
+                       return (LlvmLlc, dflags, maybe_loc, output_fn)
+
+               else
+                       return (LlvmLlc, dflags, maybe_loc, input_fn)
+  where 
+               llvmOpts = ["-O1", "-O2", "-O3"]
+
+
+-----------------------------------------------------------------------------
+-- LlvmLlc phase
+
+runPhase LlvmLlc _stop hsc_env _basename _suff input_fn get_output_fn maybe_loc
+  = liftIO $ do
+       let dflags  = hsc_dflags hsc_env
+       let lc_opts = getOpts dflags opt_lc
+       let opt_lvl = max 0 (min 2 $ optLevel dflags)
+
+       output_fn <- get_output_fn dflags As maybe_loc
+
+       SysTools.runLlvmLlc dflags
+                      (map SysTools.Option lc_opts
+                      ++ [ -- SysTools.Option "-tailcallopt",
+                    SysTools.Option (llvmOpts !! opt_lvl),
+                    SysTools.FileOption "" input_fn,
+                           SysTools.Option "-o", SysTools.FileOption "" output_fn])
+
+       return (As, dflags, maybe_loc, output_fn)
+  where
+               llvmOpts = ["", "-O2", "-O3"]
+
+
 -- warning suppression
 runPhase other _stop _dflags _basename _suff _input_fn _get_output_fn _maybe_loc =
    panic ("runPhase: don't know how to run phase " ++ show other)
 -- warning suppression
 runPhase other _stop _dflags _basename _suff _input_fn _get_output_fn _maybe_loc =
    panic ("runPhase: don't know how to run phase " ++ show other)
@@ -1832,6 +1906,7 @@ hscNextPhase dflags _ hsc_lang =
         HscC -> HCc
         HscAsm | dopt Opt_SplitObjs dflags -> SplitMangle
                | otherwise -> As
         HscC -> HCc
         HscAsm | dopt Opt_SplitObjs dflags -> SplitMangle
                | otherwise -> As
+        HscLlvm        -> LlvmAs
         HscNothing     -> StopLn
         HscInterpreted -> StopLn
         _other         -> StopLn
         HscNothing     -> StopLn
         HscInterpreted -> StopLn
         _other         -> StopLn
index 1f83d29..70b1355 100644 (file)
@@ -107,6 +107,8 @@ data DynFlag
    | Opt_D_dump_asm_conflicts
    | Opt_D_dump_asm_stats
    | Opt_D_dump_asm_expanded
    | Opt_D_dump_asm_conflicts
    | Opt_D_dump_asm_stats
    | Opt_D_dump_asm_expanded
+   | Opt_D_dump_llvm
+   | Opt_D_dump_llvm_opt
    | Opt_D_dump_cpranal
    | Opt_D_dump_deriv
    | Opt_D_dump_ds
    | Opt_D_dump_cpranal
    | Opt_D_dump_deriv
    | Opt_D_dump_ds
@@ -332,6 +334,7 @@ data DynFlag
    | Opt_KeepRawSFiles
    | Opt_KeepTmpFiles
    | Opt_KeepRawTokenStream
    | Opt_KeepRawSFiles
    | Opt_KeepTmpFiles
    | Opt_KeepRawTokenStream
+   | Opt_KeepLlvmFiles
 
    deriving (Eq, Show)
 
 
    deriving (Eq, Show)
 
@@ -420,6 +423,9 @@ data DynFlags = DynFlags {
   opt_a                 :: [String],
   opt_l                 :: [String],
   opt_windres           :: [String],
   opt_a                 :: [String],
   opt_l                 :: [String],
   opt_windres           :: [String],
+  opt_la                :: [String], -- LLVM: llvm-as assembler
+  opt_lo                :: [String], -- LLVM: llvm optimiser
+  opt_lc                :: [String], -- LLVM: llc static compiler
 
   -- commands for particular phases
   pgm_L                 :: String,
 
   -- commands for particular phases
   pgm_L                 :: String,
@@ -434,6 +440,9 @@ data DynFlags = DynFlags {
   pgm_T                 :: String,
   pgm_sysman            :: String,
   pgm_windres           :: String,
   pgm_T                 :: String,
   pgm_sysman            :: String,
   pgm_windres           :: String,
+  pgm_la                :: (String,[Option]), -- LLVM: llvm-as assembler
+  pgm_lo                :: (String,[Option]), -- LLVM: opt llvm optimiser
+  pgm_lc                :: (String,[Option]), -- LLVM: llc static compiler
 
   --  For ghc -M
   depMakefile           :: FilePath,
 
   --  For ghc -M
   depMakefile           :: FilePath,
@@ -498,6 +507,7 @@ wayNames = map wayName . ways
 data HscTarget
   = HscC           -- ^ Generate C code.
   | HscAsm         -- ^ Generate assembly using the native code generator.
 data HscTarget
   = HscC           -- ^ Generate C code.
   | HscAsm         -- ^ Generate assembly using the native code generator.
+  | HscLlvm        -- ^ Generate assembly using the llvm code generator.
   | HscJava        -- ^ Generate Java bytecode.
   | HscInterpreted -- ^ Generate bytecode.  (Requires 'LinkInMemory')
   | HscNothing     -- ^ Don't generate any code.  See notes above.
   | HscJava        -- ^ Generate Java bytecode.
   | HscInterpreted -- ^ Generate bytecode.  (Requires 'LinkInMemory')
   | HscNothing     -- ^ Don't generate any code.  See notes above.
@@ -507,6 +517,7 @@ data HscTarget
 isObjectTarget :: HscTarget -> Bool
 isObjectTarget HscC     = True
 isObjectTarget HscAsm   = True
 isObjectTarget :: HscTarget -> Bool
 isObjectTarget HscC     = True
 isObjectTarget HscAsm   = True
+isObjectTarget HscLlvm  = True
 isObjectTarget _        = False
 
 -- | The 'GhcMode' tells us whether we're doing multi-module
 isObjectTarget _        = False
 
 -- | The 'GhcMode' tells us whether we're doing multi-module
@@ -656,6 +667,9 @@ defaultDynFlags =
         opt_m                   = [],
         opt_l                   = [],
         opt_windres             = [],
         opt_m                   = [],
         opt_l                   = [],
         opt_windres             = [],
+        opt_la                  = [],
+        opt_lo                  = [],
+        opt_lc                  = [],
 
         extraPkgConfs           = [],
         packageFlags            = [],
 
         extraPkgConfs           = [],
         packageFlags            = [],
@@ -682,6 +696,9 @@ defaultDynFlags =
         pgm_T                   = panic "defaultDynFlags: No pgm_T",
         pgm_sysman              = panic "defaultDynFlags: No pgm_sysman",
         pgm_windres             = panic "defaultDynFlags: No pgm_windres",
         pgm_T                   = panic "defaultDynFlags: No pgm_T",
         pgm_sysman              = panic "defaultDynFlags: No pgm_sysman",
         pgm_windres             = panic "defaultDynFlags: No pgm_windres",
+        pgm_la                  = panic "defaultDynFlags: No pgm_la",
+        pgm_lo                  = panic "defaultDynFlags: No pgm_lo",
+        pgm_lc                  = panic "defaultDynFlags: No pgm_lc",
         -- end of initSysTools values
         -- ghc -M values
         depMakefile       = "Makefile",
         -- end of initSysTools values
         -- ghc -M values
         depMakefile       = "Makefile",
@@ -770,8 +787,9 @@ getVerbFlag dflags
 setObjectDir, setHiDir, setStubDir, setOutputDir, setDylibInstallName,
          setObjectSuf, setHiSuf, setHcSuf, parseDynLibLoaderMode,
          setPgmP, setPgmL, setPgmF, setPgmc, setPgmm, setPgms, setPgma, setPgml, setPgmdll, setPgmwindres,
 setObjectDir, setHiDir, setStubDir, setOutputDir, setDylibInstallName,
          setObjectSuf, setHiSuf, setHcSuf, parseDynLibLoaderMode,
          setPgmP, setPgmL, setPgmF, setPgmc, setPgmm, setPgms, setPgma, setPgml, setPgmdll, setPgmwindres,
-         addOptL, addOptP, addOptF, addOptc, addOptm, addOpta, addOptl, addOptwindres,
-         addCmdlineFramework, addHaddockOpts
+         setPgmla, setPgmlo, setPgmlc,
+         addOptL, addOptP, addOptF, addOptc, addOptm, addOpta, addOptl, addOptwindres, addOptla, addOptlo,
+         addOptlc, addCmdlineFramework, addHaddockOpts
    :: String -> DynFlags -> DynFlags
 setOutputFile, setOutputHi, setDumpPrefixForce
    :: Maybe String -> DynFlags -> DynFlags
    :: String -> DynFlags -> DynFlags
 setOutputFile, setOutputHi, setDumpPrefixForce
    :: Maybe String -> DynFlags -> DynFlags
@@ -815,6 +833,9 @@ setPgma   f d = d{ pgm_a   = (f,[])}
 setPgml   f d = d{ pgm_l   = (f,[])}
 setPgmdll f d = d{ pgm_dll = (f,[])}
 setPgmwindres f d = d{ pgm_windres = f}
 setPgml   f d = d{ pgm_l   = (f,[])}
 setPgmdll f d = d{ pgm_dll = (f,[])}
 setPgmwindres f d = d{ pgm_windres = f}
+setPgmla  f d = d{ pgm_la  = (f,[])}
+setPgmlo  f d = d{ pgm_lo  = (f,[])}
+setPgmlc  f d = d{ pgm_lc  = (f,[])}
 
 addOptL   f d = d{ opt_L   = f : opt_L d}
 addOptP   f d = d{ opt_P   = f : opt_P d}
 
 addOptL   f d = d{ opt_L   = f : opt_L d}
 addOptP   f d = d{ opt_P   = f : opt_P d}
@@ -824,6 +845,9 @@ addOptm   f d = d{ opt_m   = f : opt_m d}
 addOpta   f d = d{ opt_a   = f : opt_a d}
 addOptl   f d = d{ opt_l   = f : opt_l d}
 addOptwindres f d = d{ opt_windres = f : opt_windres d}
 addOpta   f d = d{ opt_a   = f : opt_a d}
 addOptl   f d = d{ opt_l   = f : opt_l d}
 addOptwindres f d = d{ opt_windres = f : opt_windres d}
+addOptla  f d = d{ opt_la  = f : opt_la d}
+addOptlo  f d = d{ opt_lo  = f : opt_lo d}
+addOptlc  f d = d{ opt_lc  = f : opt_lc d}
 
 setDepMakefile :: FilePath -> DynFlags -> DynFlags
 setDepMakefile f d = d { depMakefile = deOptDep f }
 
 setDepMakefile :: FilePath -> DynFlags -> DynFlags
 setDepMakefile f d = d { depMakefile = deOptDep f }
@@ -1018,6 +1042,11 @@ dynamic_flags = [
   , Flag "v"              (OptIntSuffix setVerbosity) Supported
 
         ------- Specific phases  --------------------------------------------
   , Flag "v"              (OptIntSuffix setVerbosity) Supported
 
         ------- Specific phases  --------------------------------------------
+    -- need to appear before -pgmL to be parsed as LLVM flags.
+  , Flag "pgmla"         (HasArg (upd . setPgmla)) Supported
+  , Flag "pgmlo"         (HasArg (upd . setPgmlo)) Supported
+  , Flag "pgmlc"         (HasArg (upd . setPgmlc)) Supported
+
   , Flag "pgmL"           (HasArg (upd . setPgmL)) Supported
   , Flag "pgmP"           (HasArg (upd . setPgmP)) Supported
   , Flag "pgmF"           (HasArg (upd . setPgmF)) Supported
   , Flag "pgmL"           (HasArg (upd . setPgmL)) Supported
   , Flag "pgmP"           (HasArg (upd . setPgmP)) Supported
   , Flag "pgmF"           (HasArg (upd . setPgmF)) Supported
@@ -1029,6 +1058,11 @@ dynamic_flags = [
   , Flag "pgmdll"         (HasArg (upd . setPgmdll)) Supported
   , Flag "pgmwindres"     (HasArg (upd . setPgmwindres)) Supported
 
   , Flag "pgmdll"         (HasArg (upd . setPgmdll)) Supported
   , Flag "pgmwindres"     (HasArg (upd . setPgmwindres)) Supported
 
+    -- need to appear before -optl/-opta to be parsed as LLVM flags.
+  , Flag "optla"          (HasArg (upd . addOptla)) Supported
+  , Flag "optlo"          (HasArg (upd . addOptlo)) Supported
+  , Flag "optlc"          (HasArg (upd . addOptlc)) Supported
+
   , Flag "optL"           (HasArg (upd . addOptL)) Supported
   , Flag "optP"           (HasArg (upd . addOptP)) Supported
   , Flag "optF"           (HasArg (upd . addOptF)) Supported
   , Flag "optL"           (HasArg (upd . addOptL)) Supported
   , Flag "optP"           (HasArg (upd . addOptP)) Supported
   , Flag "optF"           (HasArg (upd . addOptF)) Supported
@@ -1102,6 +1136,8 @@ dynamic_flags = [
   , Flag "keep-s-files"     (NoArg (setDynFlag Opt_KeepSFiles)) Supported
   , Flag "keep-raw-s-file"  (NoArg (setDynFlag Opt_KeepRawSFiles)) Supported
   , Flag "keep-raw-s-files" (NoArg (setDynFlag Opt_KeepRawSFiles)) Supported
   , Flag "keep-s-files"     (NoArg (setDynFlag Opt_KeepSFiles)) Supported
   , Flag "keep-raw-s-file"  (NoArg (setDynFlag Opt_KeepRawSFiles)) Supported
   , Flag "keep-raw-s-files" (NoArg (setDynFlag Opt_KeepRawSFiles)) Supported
+  , Flag "keep-llvm-file"   (NoArg (setDynFlag Opt_KeepLlvmFiles)) Supported
+  , Flag "keep-llvm-files"  (NoArg (setDynFlag Opt_KeepLlvmFiles)) Supported
      -- This only makes sense as plural
   , Flag "keep-tmp-files"   (NoArg (setDynFlag Opt_KeepTmpFiles)) Supported
 
      -- This only makes sense as plural
   , Flag "keep-tmp-files"   (NoArg (setDynFlag Opt_KeepTmpFiles)) Supported
 
@@ -1162,6 +1198,11 @@ dynamic_flags = [
          Supported
   , Flag "ddump-asm-expanded"      (setDumpFlag Opt_D_dump_asm_expanded)
          Supported
          Supported
   , Flag "ddump-asm-expanded"      (setDumpFlag Opt_D_dump_asm_expanded)
          Supported
+  , Flag "ddump-llvm"              (NoArg (do { setObjTarget HscLlvm
+                                              ; setDumpFlag' Opt_D_dump_llvm}))
+         Supported
+  , Flag "ddump-opt-llvm"          (setDumpFlag Opt_D_dump_llvm_opt)
+         Supported
   , Flag "ddump-cpranal"           (setDumpFlag Opt_D_dump_cpranal)
          Supported
   , Flag "ddump-deriv"             (setDumpFlag Opt_D_dump_deriv)
   , Flag "ddump-cpranal"           (setDumpFlag Opt_D_dump_cpranal)
          Supported
   , Flag "ddump-deriv"             (setDumpFlag Opt_D_dump_deriv)
@@ -1384,6 +1425,7 @@ dynamic_flags = [
   , Flag "fasm"             (NoArg (setObjTarget HscAsm)) Supported
   , Flag "fvia-c"           (NoArg (setObjTarget HscC)) Supported
   , Flag "fvia-C"           (NoArg (setObjTarget HscC)) Supported
   , Flag "fasm"             (NoArg (setObjTarget HscAsm)) Supported
   , Flag "fvia-c"           (NoArg (setObjTarget HscC)) Supported
   , Flag "fvia-C"           (NoArg (setObjTarget HscC)) Supported
+  , Flag "fllvm"            (NoArg (setObjTarget HscLlvm)) Supported
 
   , Flag "fno-code"         (NoArg (do upd $ \d -> d{ ghcLink=NoLink }
                                        setTarget HscNothing))
 
   , Flag "fno-code"         (NoArg (do upd $ \d -> d{ ghcLink=NoLink }
                                        setTarget HscNothing))
@@ -1787,9 +1829,12 @@ unSetDynFlag f = upd (\dfs -> dopt_unset dfs f)
 
 --------------------------
 setDumpFlag :: DynFlag -> OptKind DynP
 
 --------------------------
 setDumpFlag :: DynFlag -> OptKind DynP
-setDumpFlag dump_flag
-  = NoArg (do { setDynFlag dump_flag
-              ; when want_recomp forceRecompile })
+setDumpFlag dump_flag = NoArg (setDumpFlag' dump_flag)
+
+setDumpFlag' :: DynFlag -> DynP ()
+setDumpFlag' dump_flag
+  = do { setDynFlag dump_flag
+              ; when want_recomp forceRecompile }
   where
        -- Certain dumpy-things are really interested in what's going
         -- on during recompilation checking, so in those cases we
   where
        -- Certain dumpy-things are really interested in what's going
         -- on during recompilation checking, so in those cases we
@@ -2185,6 +2230,7 @@ compilerInfo = [("Project name",                String cProjectName),
                 ("Have interpreter",            String cGhcWithInterpreter),
                 ("Object splitting",            String cSplitObjs),
                 ("Have native code generator",  String cGhcWithNativeCodeGen),
                 ("Have interpreter",            String cGhcWithInterpreter),
                 ("Object splitting",            String cSplitObjs),
                 ("Have native code generator",  String cGhcWithNativeCodeGen),
+                ("Have llvm code generator",    String cGhcWithLlvmCodeGen),
                 ("Support SMP",                 String cGhcWithSMP),
                 ("Unregisterised",              String cGhcUnregisterised),
                 ("Tables next to code",         String cGhcEnableTablesNextToCode),
                 ("Support SMP",                 String cGhcWithSMP),
                 ("Unregisterised",              String cGhcUnregisterised),
                 ("Tables next to code",         String cGhcEnableTablesNextToCode),
index c479a66..29889db 100644 (file)
@@ -18,6 +18,9 @@ module SysTools (
         runAs, runLink,          -- [Option] -> IO ()
         runMkDLL,
         runWindres,
         runAs, runLink,          -- [Option] -> IO ()
         runMkDLL,
         runWindres,
+        runLlvmAs,
+        runLlvmOpt,
+        runLlvmLlc,
 
         touch,                  -- String -> String -> IO ()
         copy,
 
         touch,                  -- String -> String -> IO ()
         copy,
@@ -219,6 +222,11 @@ initSysTools mbMinusB dflags0
         ; let   as_prog  = gcc_prog
                 ld_prog  = gcc_prog
 
         ; let   as_prog  = gcc_prog
                 ld_prog  = gcc_prog
 
+        -- figure out llvm location. (TODO: Acutally implement).
+        ; let la_prog = "llvm-as"
+              lc_prog = "llc"
+              lo_prog = "opt"
+
         ; return dflags1{
                         ghcUsagePath = ghc_usage_msg_path,
                         ghciUsagePath = ghci_usage_msg_path,
         ; return dflags1{
                         ghcUsagePath = ghc_usage_msg_path,
                         ghciUsagePath = ghci_usage_msg_path,
@@ -235,7 +243,10 @@ initSysTools mbMinusB dflags0
                         pgm_dll = (mkdll_prog,mkdll_args),
                         pgm_T   = touch_path,
                         pgm_sysman = top_dir ++ "/ghc/rts/parallel/SysMan",
                         pgm_dll = (mkdll_prog,mkdll_args),
                         pgm_T   = touch_path,
                         pgm_sysman = top_dir ++ "/ghc/rts/parallel/SysMan",
-                        pgm_windres = windres_path
+                        pgm_windres = windres_path,
+                        pgm_la  = (la_prog,[]),
+                        pgm_lo  = (lo_prog,[]),
+                        pgm_lc  = (lc_prog,[])
                         -- Hans: this isn't right in general, but you can
                         -- elaborate it in the same way as the others
                 }
                         -- Hans: this isn't right in general, but you can
                         -- elaborate it in the same way as the others
                 }
@@ -381,6 +392,21 @@ runAs dflags args = do
   mb_env <- getGccEnv args1
   runSomethingFiltered dflags id "Assembler" p args1 mb_env
 
   mb_env <- getGccEnv args1
   runSomethingFiltered dflags id "Assembler" p args1 mb_env
 
+runLlvmAs :: DynFlags -> [Option] -> IO ()
+runLlvmAs dflags args = do
+  let (p,args0) = pgm_la dflags
+  runSomething dflags "LLVM Assembler" p (args0++args)
+
+runLlvmOpt :: DynFlags -> [Option] -> IO ()
+runLlvmOpt dflags args = do
+  let (p,args0) = pgm_lo dflags
+  runSomething dflags "LLVM Optimiser" p (args0++args)
+
+runLlvmLlc :: DynFlags -> [Option] -> IO ()
+runLlvmLlc dflags args = do
+  let (p,args0) = pgm_lc dflags
+  runSomething dflags "LLVM Compiler" p (args0++args)
+
 runLink :: DynFlags -> [Option] -> IO ()
 runLink dflags args = do
   let (p,args0) = pgm_l dflags
 runLink :: DynFlags -> [Option] -> IO ()
 runLink dflags args = do
   let (p,args0) = pgm_l dflags
index 2d85c5f..ee49050 100644 (file)
@@ -27,7 +27,6 @@ import RegsBase
 
 import BlockId
 import Cmm
 
 import BlockId
 import Cmm
-import CgUtils          ( get_GlobalReg_addr )
 import CLabel           ( CLabel, mkMainCapabilityLabel )
 import Pretty
 import Outputable      ( Outputable(..), pprPanic, panic )
 import CLabel           ( CLabel, mkMainCapabilityLabel )
 import Pretty
 import Outputable      ( Outputable(..), pprPanic, panic )
index d79fbb6..d73cb89 100644 (file)
@@ -73,6 +73,7 @@ import RegClass
 import NCGMonad
 
 import BlockId
 import NCGMonad
 
 import BlockId
+import CgUtils         ( fixStgRegisters )
 import Cmm
 import CmmOpt          ( cmmMiniInline, cmmMachOpFold )
 import PprCmm
 import Cmm
 import CmmOpt          ( cmmMiniInline, cmmMachOpFold )
 import PprCmm
@@ -278,9 +279,9 @@ cmmNativeGen dflags us cmm count
  = do
 
        -- rewrite assignments to global regs
  = do
 
        -- rewrite assignments to global regs
-       let (fixed_cmm, usFix)  =
-               {-# SCC "fixAssignsTop" #-}
-               initUs us $ fixAssignsTop cmm
+       let fixed_cmm =
+               {-# SCC "fixStgRegisters" #-}
+               fixStgRegisters cmm
 
        -- cmm to cmm optimisations
        let (opt_cmm, imports) =
 
        -- cmm to cmm optimisations
        let (opt_cmm, imports) =
@@ -294,13 +295,12 @@ cmmNativeGen dflags us cmm count
        -- generate native code from cmm
        let ((native, lastMinuteImports), usGen) =
                {-# SCC "genMachCode" #-}
        -- generate native code from cmm
        let ((native, lastMinuteImports), usGen) =
                {-# SCC "genMachCode" #-}
-               initUs usFix $ genMachCode dflags opt_cmm
+               initUs us $ genMachCode dflags opt_cmm
 
        dumpIfSet_dyn dflags
                Opt_D_dump_asm_native "Native code"
                (vcat $ map (docToSDoc . pprNatCmmTop) native)
 
 
        dumpIfSet_dyn dflags
                Opt_D_dump_asm_native "Native code"
                (vcat $ map (docToSDoc . pprNatCmmTop) native)
 
-
        -- tag instructions with register liveness information
        let (withLiveness, usLive) =
                {-# SCC "regLiveness" #-}
        -- tag instructions with register liveness information
        let (withLiveness, usLive) =
                {-# SCC "regLiveness" #-}
@@ -309,7 +309,6 @@ cmmNativeGen dflags us cmm count
        dumpIfSet_dyn dflags
                Opt_D_dump_asm_liveness "Liveness annotations added"
                (vcat $ map ppr withLiveness)
        dumpIfSet_dyn dflags
                Opt_D_dump_asm_liveness "Liveness annotations added"
                (vcat $ map ppr withLiveness)
-
                
        -- allocate registers
        (alloced, usAlloc, ppr_raStatsColor, ppr_raStatsLinear) <-
                
        -- allocate registers
        (alloced, usAlloc, ppr_raStatsColor, ppr_raStatsLinear) <-
@@ -323,7 +322,6 @@ cmmNativeGen dflags us cmm count
                                emptyUFM
                        $ allocatableRegs
 
                                emptyUFM
                        $ allocatableRegs
 
-
                -- do the graph coloring register allocation
                let ((alloced, regAllocStats), usAlloc)
                        = {-# SCC "RegAlloc" #-}
                -- do the graph coloring register allocation
                let ((alloced, regAllocStats), usAlloc)
                        = {-# SCC "RegAlloc" #-}
@@ -697,44 +695,6 @@ genMachCode dflags cmm_top
           else pprPanic "genMachCode: nonzero final delta" (int final_delta)
     }
 
           else pprPanic "genMachCode: nonzero final delta" (int final_delta)
     }
 
--- -----------------------------------------------------------------------------
--- Fixup assignments to global registers so that they assign to 
--- locations within the RegTable, if appropriate.
-
--- Note that we currently don't fixup reads here: they're done by
--- the generic optimiser below, to avoid having two separate passes
--- over the Cmm.
-
-fixAssignsTop :: RawCmmTop -> UniqSM RawCmmTop
-fixAssignsTop top@(CmmData _ _) = returnUs top
-fixAssignsTop (CmmProc info lbl params (ListGraph blocks)) =
-  mapUs fixAssignsBlock blocks `thenUs` \ blocks' ->
-  returnUs (CmmProc info lbl params (ListGraph blocks'))
-
-fixAssignsBlock :: CmmBasicBlock -> UniqSM CmmBasicBlock
-fixAssignsBlock (BasicBlock id stmts) =
-  fixAssigns stmts `thenUs` \ stmts' ->
-  returnUs (BasicBlock id stmts')
-
-fixAssigns :: [CmmStmt] -> UniqSM [CmmStmt]
-fixAssigns stmts =
-  mapUs fixAssign stmts `thenUs` \ stmtss ->
-  returnUs (concat stmtss)
-
-fixAssign :: CmmStmt -> UniqSM [CmmStmt]
-fixAssign (CmmAssign (CmmGlobal reg) src)
-  | Left  realreg <- reg_or_addr
-  = returnUs [CmmAssign (CmmGlobal reg) src]
-  | Right baseRegAddr <- reg_or_addr
-  = returnUs [CmmStore baseRegAddr src]
-           -- Replace register leaves with appropriate StixTrees for
-           -- the given target. GlobalRegs which map to a reg on this
-           -- arch are left unchanged.  Assigning to BaseReg is always
-           -- illegal, so we check for that.
-  where
-       reg_or_addr = get_GlobalReg_reg_or_addr reg
-
-fixAssign other_stmt = returnUs [other_stmt]
 
 -- -----------------------------------------------------------------------------
 -- Generic Cmm optimiser
 
 -- -----------------------------------------------------------------------------
 -- Generic Cmm optimiser
@@ -745,10 +705,7 @@ Here we do:
   (a) Constant folding
   (b) Simple inlining: a temporary which is assigned to and then
       used, once, can be shorted.
   (a) Constant folding
   (b) Simple inlining: a temporary which is assigned to and then
       used, once, can be shorted.
-  (c) Replacement of references to GlobalRegs which do not have
-      machine registers by the appropriate memory load (eg.
-      Hp ==>  *(BaseReg + 34) ).
-  (d) Position independent code and dynamic linking
+  (c) Position independent code and dynamic linking
         (i)  introduce the appropriate indirections
              and position independent refs
         (ii) compile a list of imported symbols
         (i)  introduce the appropriate indirections
              and position independent refs
         (ii) compile a list of imported symbols
@@ -883,42 +840,8 @@ cmmExprConFold referenceKind expr
              CmmLit (CmmLabel (mkCmmCodeLabel rtsPackageId (fsLit "__stg_gc_fun")))
 #endif
 
              CmmLit (CmmLabel (mkCmmCodeLabel rtsPackageId (fsLit "__stg_gc_fun")))
 #endif
 
-        CmmReg (CmmGlobal mid)
-           -- Replace register leaves with appropriate StixTrees for
-           -- the given target.  MagicIds which map to a reg on this
-           -- arch are left unchanged.  For the rest, BaseReg is taken
-           -- to mean the address of the reg table in MainCapability,
-           -- and for all others we generate an indirection to its
-           -- location in the register table.
-           -> case get_GlobalReg_reg_or_addr mid of
-                 Left  realreg -> return expr
-                 Right baseRegAddr 
-                    -> case mid of 
-                          BaseReg -> cmmExprConFold DataReference baseRegAddr
-                          other   -> cmmExprConFold DataReference
-                                        (CmmLoad baseRegAddr (globalRegType mid))
-          -- eliminate zero offsets
-       CmmRegOff reg 0
-          -> cmmExprConFold referenceKind (CmmReg reg)
-
-        CmmRegOff (CmmGlobal mid) offset
-           -- RegOf leaves are just a shorthand form. If the reg maps
-           -- to a real reg, we keep the shorthand, otherwise, we just
-           -- expand it and defer to the above code. 
-           -> case get_GlobalReg_reg_or_addr mid of
-                Left  realreg -> return expr
-                Right baseRegAddr
-                   -> cmmExprConFold DataReference (CmmMachOp (MO_Add wordWidth) [
-                                        CmmReg (CmmGlobal mid),
-                                        CmmLit (CmmInt (fromIntegral offset)
-                                                       wordWidth)])
         other
            -> return other
 
         other
            -> return other
 
--- -----------------------------------------------------------------------------
--- Utils
-
-bind f x = x $! f
-
 \end{code}
 
 \end{code}
 
index a1b55ce..8a4228b 100644 (file)
@@ -180,12 +180,12 @@ getRegisterReg (CmmLocal (LocalReg u pk))
   = RegVirtual $ mkVirtualReg u (cmmTypeSize pk)
 
 getRegisterReg (CmmGlobal mid)
   = RegVirtual $ mkVirtualReg u (cmmTypeSize pk)
 
 getRegisterReg (CmmGlobal mid)
-  = case get_GlobalReg_reg_or_addr mid of
-       Left reg -> reg
-       _other -> pprPanic "getRegisterReg-memory" (ppr $ CmmGlobal mid)
-          -- By this stage, the only MagicIds remaining should be the
-          -- ones which map to a real machine register on this
-          -- platform.  Hence ...
+  = case globalRegMaybe mid of
+        Just reg -> reg
+        Nothing  -> pprPanic "getRegisterReg-memory" (ppr $ CmmGlobal mid)
+        -- By this stage, the only MagicIds remaining should be the
+        -- ones which map to a real machine register on this
+        -- platform.  Hence ...
 
 
 {-
 
 
 {-
index d649d84..e00dd7e 100644 (file)
@@ -40,7 +40,6 @@ module PPC.Regs (
        -- horrow show
        freeReg,
        globalRegMaybe,
        -- horrow show
        freeReg,
        globalRegMaybe,
-       get_GlobalReg_reg_or_addr,
        allocatableRegs
 
 )
        allocatableRegs
 
 )
@@ -55,7 +54,6 @@ import Reg
 import RegClass
 import Size
 
 import RegClass
 import Size
 
-import CgUtils          ( get_GlobalReg_addr )
 import BlockId
 import Cmm
 import CLabel           ( CLabel )
 import BlockId
 import Cmm
 import CLabel           ( CLabel )
@@ -595,20 +593,6 @@ globalRegMaybe _   = panic "PPC.Regs.globalRegMaybe: not defined"
 #endif /* powerpc_TARGET_ARCH */
 
 
 #endif /* powerpc_TARGET_ARCH */
 
 
--- We map STG registers onto appropriate CmmExprs.  Either they map
--- to real machine registers or stored as offsets from BaseReg.  Given
--- a GlobalReg, get_GlobalReg_reg_or_addr produces either the real
--- register it is in, on this platform, or a CmmExpr denoting the
--- address in the register table holding it.
--- (See also get_GlobalReg_addr in CgUtils.)
-
-get_GlobalReg_reg_or_addr :: GlobalReg -> Either Reg CmmExpr
-get_GlobalReg_reg_or_addr mid
-   = case globalRegMaybe mid of
-        Just rr -> Left rr
-        Nothing -> Right (get_GlobalReg_addr mid)
-
-
 -- allocatableRegs is allMachRegNos with the fixed-use regs removed.
 -- i.e., these are the regs for which we are prepared to allow the
 -- register allocator to attempt to map VRegs to.
 -- allocatableRegs is allMachRegNos with the fixed-use regs removed.
 -- i.e., these are the regs for which we are prepared to allow the
 -- register allocator to attempt to map VRegs to.
index 54bbf9b..c85d806 100644 (file)
@@ -18,6 +18,7 @@ import SPARC.Instr
 import SPARC.Cond
 import SPARC.AddrMode
 import SPARC.Regs
 import SPARC.Cond
 import SPARC.AddrMode
 import SPARC.Regs
+import SPARC.RegPlate
 import Size
 import Reg
 
 import Size
 import Reg
 
@@ -95,11 +96,11 @@ getRegisterReg (CmmLocal (LocalReg u pk))
        = RegVirtual $ mkVirtualReg u (cmmTypeSize pk)
 
 getRegisterReg (CmmGlobal mid)
        = RegVirtual $ mkVirtualReg u (cmmTypeSize pk)
 
 getRegisterReg (CmmGlobal mid)
-  = case get_GlobalReg_reg_or_addr mid of
-       Left rr -> RegReal rr
-
-       _       -> pprPanic "SPARC.CodeGen.Base.getRegisterReg: global is in memory" 
-                                       (ppr $ CmmGlobal mid)
+  = case globalRegMaybe mid of
+        Just reg -> RegReal reg
+        Nothing  -> pprPanic
+                        "SPARC.CodeGen.Base.getRegisterReg: global is in memory"
+                        (ppr $ CmmGlobal mid)
 
 
 -- Expand CmmRegOff.  ToDo: should we do it this way around, or convert
 
 
 -- Expand CmmRegOff.  ToDo: should we do it this way around, or convert
index cd19138..98151ec 100644 (file)
@@ -18,7 +18,6 @@ module SPARC.Regs (
 
        -- allocatable
        allocatableRegs,
 
        -- allocatable
        allocatableRegs,
-       get_GlobalReg_reg_or_addr,
 
        -- args
        argRegs, 
 
        -- args
        argRegs, 
@@ -38,9 +37,7 @@ import Reg
 import RegClass
 import Size
 
 import RegClass
 import Size
 
-import Cmm
 import PprCmm          ()
 import PprCmm          ()
-import CgUtils          ( get_GlobalReg_addr )
 
 import Unique
 import Outputable
 
 import Unique
 import Outputable
@@ -214,21 +211,6 @@ allocatableRegs
      in        filter isFree allRealRegs
 
 
      in        filter isFree allRealRegs
 
 
-
--- We map STG registers onto appropriate CmmExprs.  Either they map
--- to real machine registers or stored as offsets from BaseReg.  Given
--- a GlobalReg, get_GlobalReg_reg_or_addr produces either the real
--- register it is in, on this platform, or a CmmExpr denoting the
--- address in the register table holding it.
--- (See also get_GlobalReg_addr in CgUtils.)
-
-get_GlobalReg_reg_or_addr :: GlobalReg -> Either RealReg CmmExpr
-get_GlobalReg_reg_or_addr mid
-   = case globalRegMaybe mid of
-        Just rr -> Left  rr
-        Nothing -> Right (get_GlobalReg_addr mid)
-
-
 -- | The registers to place arguments for function calls, 
 --     for some number of arguments.
 --
 -- | The registers to place arguments for function calls, 
 --     for some number of arguments.
 --
index 2698406..89a26a9 100644 (file)
@@ -226,12 +226,12 @@ getRegisterReg use_sse2 (CmmLocal (LocalReg u pk))
        else RegVirtual (mkVirtualReg u sz)
 
 getRegisterReg _ (CmmGlobal mid)
        else RegVirtual (mkVirtualReg u sz)
 
 getRegisterReg _ (CmmGlobal mid)
-  = case get_GlobalReg_reg_or_addr mid of
-       Left reg -> RegReal $ reg
-       _other -> pprPanic "getRegisterReg-memory" (ppr $ CmmGlobal mid)
-          -- By this stage, the only MagicIds remaining should be the
-          -- ones which map to a real machine register on this
-          -- platform.  Hence ...
+  = case globalRegMaybe mid of
+        Just reg -> RegReal $ reg
+        Nothing  -> pprPanic "getRegisterReg-memory" (ppr $ CmmGlobal mid)
+        -- By this stage, the only MagicIds remaining should be the
+        -- ones which map to a real machine register on this
+        -- platform.  Hence ...
 
 
 -- | Memory addressing modes passed up the tree.
 
 
 -- | Memory addressing modes passed up the tree.
index a04e854..b9a23a6 100644 (file)
@@ -40,7 +40,6 @@ module X86.Regs (
        freeReg,
        globalRegMaybe,
        
        freeReg,
        globalRegMaybe,
        
-       get_GlobalReg_reg_or_addr,
        allocatableRegs
 )
 
        allocatableRegs
 )
 
@@ -54,7 +53,6 @@ where
 import Reg
 import RegClass
 
 import Reg
 import RegClass
 
-import CgUtils          ( get_GlobalReg_addr )
 import BlockId
 import Cmm
 import CLabel           ( CLabel )
 import BlockId
 import Cmm
 import CLabel           ( CLabel )
@@ -662,20 +660,6 @@ callClobberedRegs  = panic "X86.Regs.globalRegMaybe: not defined"
 
 #endif
 
 
 #endif
 
--- We map STG registers onto appropriate CmmExprs.  Either they map
--- to real machine registers or stored as offsets from BaseReg.  Given
--- a GlobalReg, get_GlobalReg_reg_or_addr produces either the real
--- register it is in, on this platform, or a CmmExpr denoting the
--- address in the register table holding it.
--- (See also get_GlobalReg_addr in CgUtils.)
-
-get_GlobalReg_reg_or_addr :: GlobalReg -> Either RealReg CmmExpr
-get_GlobalReg_reg_or_addr mid
-   = case globalRegMaybe mid of
-        Just rr -> Left rr
-        Nothing -> Right (get_GlobalReg_addr mid)
-
-
 -- allocatableRegs is allMachRegNos with the fixed-use regs removed.
 -- i.e., these are the regs for which we are prepared to allow the
 -- register allocator to attempt to map VRegs to.
 -- allocatableRegs is allMachRegNos with the fixed-use regs removed.
 -- i.e., these are the regs for which we are prepared to allow the
 -- register allocator to attempt to map VRegs to.
index fdb7ce5..935127c 100644 (file)
@@ -94,7 +94,7 @@ tcCheckFIType :: Type -> [Type] -> Type -> ForeignImport -> TcM ForeignImport
 
 tcCheckFIType sig_ty arg_tys res_ty idecl@(CImport _ safety _ (CLabel _))
   = ASSERT( null arg_tys )
 
 tcCheckFIType sig_ty arg_tys res_ty idecl@(CImport _ safety _ (CLabel _))
   = ASSERT( null arg_tys )
-    do { checkCg checkCOrAsmOrInterp
+    do { checkCg checkCOrAsmOrLlvmOrInterp
        ; checkSafety safety
        ; check (isFFILabelTy res_ty) (illegalForeignTyErr empty sig_ty)
        ; return idecl }             -- NB check res_ty not sig_ty!
        ; checkSafety safety
        ; check (isFFILabelTy res_ty) (illegalForeignTyErr empty sig_ty)
        ; return idecl }             -- NB check res_ty not sig_ty!
@@ -106,7 +106,7 @@ tcCheckFIType sig_ty arg_tys res_ty idecl@(CImport cconv safety _ CWrapper) = do
        -- valid foreign type.  For legacy reasons ft -> IO (Ptr ft) as well
        -- as ft -> IO Addr is accepted, too.  The use of the latter two forms
        -- is DEPRECATED, though.
        -- valid foreign type.  For legacy reasons ft -> IO (Ptr ft) as well
        -- as ft -> IO Addr is accepted, too.  The use of the latter two forms
        -- is DEPRECATED, though.
-    checkCg checkCOrAsmOrInterp
+    checkCg checkCOrAsmOrLlvmOrInterp
     checkCConv cconv
     checkSafety safety
     case arg_tys of
     checkCConv cconv
     checkSafety safety
     case arg_tys of
@@ -121,7 +121,7 @@ tcCheckFIType sig_ty arg_tys res_ty idecl@(CImport cconv safety _ CWrapper) = do
 
 tcCheckFIType sig_ty arg_tys res_ty idecl@(CImport cconv safety _ (CFunction target))
   | isDynamicTarget target = do -- Foreign import dynamic
 
 tcCheckFIType sig_ty arg_tys res_ty idecl@(CImport cconv safety _ (CFunction target))
   | isDynamicTarget target = do -- Foreign import dynamic
-      checkCg checkCOrAsmOrInterp
+      checkCg checkCOrAsmOrLlvmOrInterp
       checkCConv cconv
       checkSafety safety
       case arg_tys of           -- The first arg must be Ptr, FunPtr, or Addr
       checkCConv cconv
       checkSafety safety
       case arg_tys of           -- The first arg must be Ptr, FunPtr, or Addr
@@ -139,7 +139,7 @@ tcCheckFIType sig_ty arg_tys res_ty idecl@(CImport cconv safety _ (CFunction tar
       dflags <- getDOpts
       check (dopt Opt_GHCForeignImportPrim dflags)
             (text "Use -XGHCForeignImportPrim to allow `foreign import prim'.")
       dflags <- getDOpts
       check (dopt Opt_GHCForeignImportPrim dflags)
             (text "Use -XGHCForeignImportPrim to allow `foreign import prim'.")
-      checkCg (checkCOrAsmOrDotNetOrInterp)
+      checkCg (checkCOrAsmOrLlvmOrDotNetOrInterp)
       checkCTarget target
       check (playSafe safety)
             (text "The safe/unsafe annotation should not be used with `foreign import prim'.")
       checkCTarget target
       check (playSafe safety)
             (text "The safe/unsafe annotation should not be used with `foreign import prim'.")
@@ -148,7 +148,7 @@ tcCheckFIType sig_ty arg_tys res_ty idecl@(CImport cconv safety _ (CFunction tar
       checkForeignRes nonIOok (isFFIPrimResultTy dflags) res_ty
       return idecl
   | otherwise = do              -- Normal foreign import
       checkForeignRes nonIOok (isFFIPrimResultTy dflags) res_ty
       return idecl
   | otherwise = do              -- Normal foreign import
-      checkCg (checkCOrAsmOrDotNetOrInterp)
+      checkCg (checkCOrAsmOrLlvmOrDotNetOrInterp)
       checkCConv cconv
       checkSafety safety
       checkCTarget target
       checkCConv cconv
       checkSafety safety
       checkCTarget target
@@ -163,7 +163,7 @@ tcCheckFIType sig_ty arg_tys res_ty idecl@(CImport cconv safety _ (CFunction tar
 -- that the C identifier is valid for C
 checkCTarget :: CCallTarget -> TcM ()
 checkCTarget (StaticTarget str _) = do
 -- that the C identifier is valid for C
 checkCTarget :: CCallTarget -> TcM ()
 checkCTarget (StaticTarget str _) = do
-    checkCg checkCOrAsmOrDotNetOrInterp
+    checkCg checkCOrAsmOrLlvmOrDotNetOrInterp
     check (isCLabelString str) (badCName str)
 
 checkCTarget DynamicTarget = panic "checkCTarget DynamicTarget"
     check (isCLabelString str) (badCName str)
 
 checkCTarget DynamicTarget = panic "checkCTarget DynamicTarget"
@@ -247,7 +247,7 @@ tcFExport d = pprPanic "tcFExport" (ppr d)
 \begin{code}
 tcCheckFEType :: Type -> ForeignExport -> TcM ()
 tcCheckFEType sig_ty (CExport (CExportStatic str cconv)) = do
 \begin{code}
 tcCheckFEType :: Type -> ForeignExport -> TcM ()
 tcCheckFEType sig_ty (CExport (CExportStatic str cconv)) = do
-    checkCg checkCOrAsm
+    checkCg checkCOrAsmOrLlvm
     check (isCLabelString str) (badCName str)
     checkCConv cconv
     checkForeignArgs isFFIExternalTy arg_tys
     check (isCLabelString str) (badCName str)
     checkCConv cconv
     checkForeignArgs isFFIExternalTy arg_tys
@@ -297,25 +297,28 @@ checkForeignRes non_io_result_ok pred_res_ty ty
 \end{code}
 
 \begin{code}
 \end{code}
 
 \begin{code}
-checkCOrAsm :: HscTarget -> Maybe SDoc
-checkCOrAsm HscC   = Nothing
-checkCOrAsm HscAsm = Nothing
-checkCOrAsm _
-   = Just (text "requires via-C or native code generation (-fvia-C)")
-
-checkCOrAsmOrInterp :: HscTarget -> Maybe SDoc
-checkCOrAsmOrInterp HscC           = Nothing
-checkCOrAsmOrInterp HscAsm         = Nothing
-checkCOrAsmOrInterp HscInterpreted = Nothing
-checkCOrAsmOrInterp _
-   = Just (text "requires interpreted, C or native code generation")
-
-checkCOrAsmOrDotNetOrInterp :: HscTarget -> Maybe SDoc
-checkCOrAsmOrDotNetOrInterp HscC           = Nothing
-checkCOrAsmOrDotNetOrInterp HscAsm         = Nothing
-checkCOrAsmOrDotNetOrInterp HscInterpreted = Nothing
-checkCOrAsmOrDotNetOrInterp _
-   = Just (text "requires interpreted, C or native code generation")
+checkCOrAsmOrLlvm :: HscTarget -> Maybe SDoc
+checkCOrAsmOrLlvm HscC    = Nothing
+checkCOrAsmOrLlvm HscAsm  = Nothing
+checkCOrAsmOrLlvm HscLlvm = Nothing
+checkCOrAsmOrLlvm _
+   = Just (text "requires via-C, llvm (-fllvm) or native code generation (-fvia-C)")
+
+checkCOrAsmOrLlvmOrInterp :: HscTarget -> Maybe SDoc
+checkCOrAsmOrLlvmOrInterp HscC           = Nothing
+checkCOrAsmOrLlvmOrInterp HscAsm         = Nothing
+checkCOrAsmOrLlvmOrInterp HscLlvm        = Nothing
+checkCOrAsmOrLlvmOrInterp HscInterpreted = Nothing
+checkCOrAsmOrLlvmOrInterp _
+   = Just (text "requires interpreted, C, Llvm or native code generation")
+
+checkCOrAsmOrLlvmOrDotNetOrInterp :: HscTarget -> Maybe SDoc
+checkCOrAsmOrLlvmOrDotNetOrInterp HscC           = Nothing
+checkCOrAsmOrLlvmOrDotNetOrInterp HscAsm         = Nothing
+checkCOrAsmOrLlvmOrDotNetOrInterp HscLlvm        = Nothing
+checkCOrAsmOrLlvmOrDotNetOrInterp HscInterpreted = Nothing
+checkCOrAsmOrLlvmOrDotNetOrInterp _
+   = Just (text "requires interpreted, C, Llvm or native code generation")
 
 checkCg :: (HscTarget -> Maybe SDoc) -> TcM ()
 checkCg check = do
 
 checkCg :: (HscTarget -> Maybe SDoc) -> TcM ()
 checkCg check = do
index 1ff78a4..a354caa 100644 (file)
@@ -1445,7 +1445,8 @@ sub mangle_asm {
 
                # If this is an entry point with an info table,
                 # eliminate the entry symbol and all directives involving it.
 
                # If this is an entry point with an info table,
                 # eliminate the entry symbol and all directives involving it.
-               if (defined($infochk{$symb}) && $TargetPlatform !~ /^ia64-/m) {
+               if (defined($infochk{$symb}) && $TargetPlatform !~ /^ia64-/m
+                               && $TABLES_NEXT_TO_CODE ~~ "YES") {
                        @o = ();
                        foreach $l (split(/\n/m,$c)) {
                            next if $l =~ /^.*$symb_(entry|ret)${T_POST_LBL}/m;
                        @o = ();
                        foreach $l (split(/\n/m,$c)) {
                            next if $l =~ /^.*$symb_(entry|ret)${T_POST_LBL}/m;
@@ -1880,7 +1881,8 @@ sub rev_tbl {
     # use vars '$discard1';   # Unused?
     local($symb, $tbl, $discard1) = @_;
 
     # use vars '$discard1';   # Unused?
     local($symb, $tbl, $discard1) = @_;
 
-    return ($tbl) if ($TargetPlatform =~ /^ia64-/m);
+    return ($tbl) if ($TargetPlatform =~ /^ia64-/m
+                      || $TABLES_NEXT_TO_CODE ~~ "NO");
 
     local($before) = '';
     local($label) = '';
 
     local($before) = '';
     local($label) = '';
index 40f1ea7..e1a124c 100644 (file)
@@ -139,6 +139,9 @@ GhcWithNativeCodeGen=$(strip\
     $(if $(filter YESYESNO,\
                  $(OsSupportsNCG)$(ArchSupportsNCG)$(GhcUnregisterised)),YES,NO))
 
     $(if $(filter YESYESNO,\
                  $(OsSupportsNCG)$(ArchSupportsNCG)$(GhcUnregisterised)),YES,NO))
 
+# Build a compiler with the llvm code generator backend
+GhcWithLlvmCodeGen=NO
+
 HaveLibDL = @HaveLibDL@
 
 # ArchSupportsSMP should be set iff there is support for that arch in
 HaveLibDL = @HaveLibDL@
 
 # ArchSupportsSMP should be set iff there is support for that arch in
index cfa71cc..5ee1d23 100644 (file)
@@ -45,6 +45,7 @@ $1/$2/$$($1_$2_PROG): $1/$2/$$($1_$2_PROG).prl
        "$$(RM)" $$(RM_OPTS) $$@
        echo '#!$$(PERL)'                                  >> $$@
        echo '$$$$TARGETPLATFORM  = "$$(TARGETPLATFORM)";' >> $$@
        "$$(RM)" $$(RM_OPTS) $$@
        echo '#!$$(PERL)'                                  >> $$@
        echo '$$$$TARGETPLATFORM  = "$$(TARGETPLATFORM)";' >> $$@
+       echo '$$$$TABLES_NEXT_TO_CODE  = "$(GhcEnableTablesNextToCode)";' >> $$@
        cat $$<                                            >> $$@
 
 $$($1_$2_INPLACE): $1/$2/$$($1_$2_PROG) | $$$$(dir $$$$@)/.
        cat $$<                                            >> $$@
 
 $$($1_$2_INPLACE): $1/$2/$$($1_$2_PROG) | $$$$(dir $$$$@)/.