summaryrefslogtreecommitdiff
path: root/compiler/cmm
diff options
context:
space:
mode:
authorSimon Marlow <simonmar@microsoft.com>2006-04-07 02:05:11 +0000
committerSimon Marlow <simonmar@microsoft.com>2006-04-07 02:05:11 +0000
commit0065d5ab628975892cea1ec7303f968c3338cbe1 (patch)
tree8e2afe0ab48ee33cf95009809d67c9649573ef92 /compiler/cmm
parent28a464a75e14cece5db40f2765a29348273ff2d2 (diff)
downloadhaskell-0065d5ab628975892cea1ec7303f968c3338cbe1.tar.gz
Reorganisation of the source tree
Most of the other users of the fptools build system have migrated to Cabal, and with the move to darcs we can now flatten the source tree without losing history, so here goes. The main change is that the ghc/ subdir is gone, and most of what it contained is now at the top level. The build system now makes no pretense at being multi-project, it is just the GHC build system. No doubt this will break many things, and there will be a period of instability while we fix the dependencies. A straightforward build should work, but I haven't yet fixed binary/source distributions. Changes to the Building Guide will follow, too.
Diffstat (limited to 'compiler/cmm')
-rw-r--r--compiler/cmm/CLabel.hs831
-rw-r--r--compiler/cmm/Cmm.hs322
-rw-r--r--compiler/cmm/CmmLex.x311
-rw-r--r--compiler/cmm/CmmLint.hs159
-rw-r--r--compiler/cmm/CmmOpt.hs507
-rw-r--r--compiler/cmm/CmmParse.y890
-rw-r--r--compiler/cmm/CmmUtils.hs177
-rw-r--r--compiler/cmm/MachOp.hs652
-rw-r--r--compiler/cmm/PprC.hs1028
-rw-r--r--compiler/cmm/PprCmm.hs462
10 files changed, 5339 insertions, 0 deletions
diff --git a/compiler/cmm/CLabel.hs b/compiler/cmm/CLabel.hs
new file mode 100644
index 0000000000..e42b92db5a
--- /dev/null
+++ b/compiler/cmm/CLabel.hs
@@ -0,0 +1,831 @@
+-----------------------------------------------------------------------------
+--
+-- Object-file symbols (called CLabel for histerical raisins).
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+module CLabel (
+ CLabel, -- abstract type
+
+ mkClosureLabel,
+ mkSRTLabel,
+ mkSRTDescLabel,
+ mkInfoTableLabel,
+ mkEntryLabel,
+ mkSlowEntryLabel,
+ mkConEntryLabel,
+ mkStaticConEntryLabel,
+ mkRednCountsLabel,
+ mkConInfoTableLabel,
+ mkStaticInfoTableLabel,
+ mkApEntryLabel,
+ mkApInfoTableLabel,
+ mkClosureTableLabel,
+
+ mkLocalClosureLabel,
+ mkLocalInfoTableLabel,
+ mkLocalEntryLabel,
+ mkLocalConEntryLabel,
+ mkLocalStaticConEntryLabel,
+ mkLocalConInfoTableLabel,
+ mkLocalStaticInfoTableLabel,
+ mkLocalClosureTableLabel,
+
+ mkReturnPtLabel,
+ mkReturnInfoLabel,
+ mkAltLabel,
+ mkDefaultLabel,
+ mkBitmapLabel,
+ mkStringLitLabel,
+
+ mkAsmTempLabel,
+
+ mkModuleInitLabel,
+ mkPlainModuleInitLabel,
+
+ mkSplitMarkerLabel,
+ mkDirty_MUT_VAR_Label,
+ mkUpdInfoLabel,
+ mkSeqInfoLabel,
+ mkIndStaticInfoLabel,
+ mkMainCapabilityLabel,
+ mkMAP_FROZEN_infoLabel,
+ mkMAP_DIRTY_infoLabel,
+ mkEMPTY_MVAR_infoLabel,
+
+ mkTopTickyCtrLabel,
+ mkCAFBlackHoleInfoTableLabel,
+ mkSECAFBlackHoleInfoTableLabel,
+ mkRtsPrimOpLabel,
+ mkRtsSlowTickyCtrLabel,
+
+ moduleRegdLabel,
+
+ mkSelectorInfoLabel,
+ mkSelectorEntryLabel,
+
+ mkRtsInfoLabel,
+ mkRtsEntryLabel,
+ mkRtsRetInfoLabel,
+ mkRtsRetLabel,
+ mkRtsCodeLabel,
+ mkRtsDataLabel,
+
+ mkRtsInfoLabelFS,
+ mkRtsEntryLabelFS,
+ mkRtsRetInfoLabelFS,
+ mkRtsRetLabelFS,
+ mkRtsCodeLabelFS,
+ mkRtsDataLabelFS,
+
+ mkRtsApFastLabel,
+
+ mkForeignLabel,
+
+ mkCCLabel, mkCCSLabel,
+
+ DynamicLinkerLabelInfo(..),
+ mkDynamicLinkerLabel,
+ dynamicLinkerLabelInfo,
+
+ mkPicBaseLabel,
+ mkDeadStripPreventer,
+
+ infoLblToEntryLbl, entryLblToInfoLbl,
+ needsCDecl, isAsmTemp, externallyVisibleCLabel,
+ CLabelType(..), labelType, labelDynamic,
+
+ pprCLabel
+ ) where
+
+
+#include "HsVersions.h"
+
+import Packages ( HomeModules )
+import StaticFlags ( opt_Static, opt_DoTickyProfiling )
+import Packages ( isHomeModule, isDllName )
+import DataCon ( ConTag )
+import Module ( moduleFS, Module )
+import Name ( Name, isExternalName )
+import Unique ( pprUnique, Unique )
+import PrimOp ( PrimOp )
+import Config ( cLeadingUnderscore )
+import CostCentre ( CostCentre, CostCentreStack )
+import Outputable
+import FastString
+
+-- -----------------------------------------------------------------------------
+-- The CLabel type
+
+{-
+CLabel is an abstract type that supports the following operations:
+
+ - Pretty printing
+
+ - In a C file, does it need to be declared before use? (i.e. is it
+ guaranteed to be already in scope in the places we need to refer to it?)
+
+ - If it needs to be declared, what type (code or data) should it be
+ declared to have?
+
+ - Is it visible outside this object file or not?
+
+ - Is it "dynamic" (see details below)
+
+ - Eq and Ord, so that we can make sets of CLabels (currently only
+ used in outputting C as far as I can tell, to avoid generating
+ more than one declaration for any given label).
+
+ - Converting an info table label into an entry label.
+-}
+
+data CLabel
+ = IdLabel -- A family of labels related to the
+ Name -- definition of a particular Id or Con
+ IdLabelInfo
+
+ | DynIdLabel -- like IdLabel, but in a separate package,
+ Name -- and might therefore need a dynamic
+ IdLabelInfo -- reference.
+
+ | CaseLabel -- A family of labels related to a particular
+ -- case expression.
+ {-# UNPACK #-} !Unique -- Unique says which case expression
+ CaseLabelInfo
+
+ | AsmTempLabel
+ {-# UNPACK #-} !Unique
+
+ | StringLitLabel
+ {-# UNPACK #-} !Unique
+
+ | ModuleInitLabel
+ Module -- the module name
+ String -- its "way"
+ Bool -- True <=> is in a different package
+ -- at some point we might want some kind of version number in
+ -- the module init label, to guard against compiling modules in
+ -- the wrong order. We can't use the interface file version however,
+ -- because we don't always recompile modules which depend on a module
+ -- whose version has changed.
+
+ | PlainModuleInitLabel -- without the vesrion & way info
+ Module
+ Bool -- True <=> is in a different package
+
+ | ModuleRegdLabel
+
+ | RtsLabel RtsLabelInfo
+
+ | ForeignLabel FastString -- a 'C' (or otherwise foreign) label
+ (Maybe Int) -- possible '@n' suffix for stdcall functions
+ -- When generating C, the '@n' suffix is omitted, but when
+ -- generating assembler we must add it to the label.
+ Bool -- True <=> is dynamic
+
+ | CC_Label CostCentre
+ | CCS_Label CostCentreStack
+
+ -- Dynamic Linking in the NCG:
+ -- generated and used inside the NCG only,
+ -- see module PositionIndependentCode for details.
+
+ | DynamicLinkerLabel DynamicLinkerLabelInfo CLabel
+ -- special variants of a label used for dynamic linking
+
+ | PicBaseLabel -- a label used as a base for PIC calculations
+ -- on some platforms.
+ -- It takes the form of a local numeric
+ -- assembler label '1'; it is pretty-printed
+ -- as 1b, referring to the previous definition
+ -- of 1: in the assembler source file.
+
+ | DeadStripPreventer CLabel
+ -- label before an info table to prevent excessive dead-stripping on darwin
+
+ deriving (Eq, Ord)
+
+data IdLabelInfo
+ = Closure -- Label for closure
+ | SRT -- Static reference table
+ | SRTDesc -- Static reference table descriptor
+ | InfoTable -- Info tables for closures; always read-only
+ | Entry -- entry point
+ | Slow -- slow entry point
+
+ | RednCounts -- Label of place to keep Ticky-ticky info for
+ -- this Id
+
+ | Bitmap -- A bitmap (function or case return)
+
+ | ConEntry -- constructor entry point
+ | ConInfoTable -- corresponding info table
+ | StaticConEntry -- static constructor entry point
+ | StaticInfoTable -- corresponding info table
+
+ | ClosureTable -- table of closures for Enum tycons
+
+ deriving (Eq, Ord)
+
+
+data CaseLabelInfo
+ = CaseReturnPt
+ | CaseReturnInfo
+ | CaseAlt ConTag
+ | CaseDefault
+ deriving (Eq, Ord)
+
+
+data RtsLabelInfo
+ = RtsSelectorInfoTable Bool{-updatable-} Int{-offset-} -- Selector thunks
+ | RtsSelectorEntry Bool{-updatable-} Int{-offset-}
+
+ | RtsApInfoTable Bool{-updatable-} Int{-arity-} -- AP thunks
+ | RtsApEntry Bool{-updatable-} Int{-arity-}
+
+ | RtsPrimOp PrimOp
+
+ | RtsInfo LitString -- misc rts info tables
+ | RtsEntry LitString -- misc rts entry points
+ | RtsRetInfo LitString -- misc rts ret info tables
+ | RtsRet LitString -- misc rts return points
+ | RtsData LitString -- misc rts data bits, eg CHARLIKE_closure
+ | RtsCode LitString -- misc rts code
+
+ | RtsInfoFS FastString -- misc rts info tables
+ | RtsEntryFS FastString -- misc rts entry points
+ | RtsRetInfoFS FastString -- misc rts ret info tables
+ | RtsRetFS FastString -- misc rts return points
+ | RtsDataFS FastString -- misc rts data bits, eg CHARLIKE_closure
+ | RtsCodeFS FastString -- misc rts code
+
+ | RtsApFast LitString -- _fast versions of generic apply
+
+ | RtsSlowTickyCtr String
+
+ deriving (Eq, Ord)
+ -- NOTE: Eq on LitString compares the pointer only, so this isn't
+ -- a real equality.
+
+data DynamicLinkerLabelInfo
+ = CodeStub -- MachO: Lfoo$stub, ELF: foo@plt
+ | SymbolPtr -- MachO: Lfoo$non_lazy_ptr, Windows: __imp_foo
+ | GotSymbolPtr -- ELF: foo@got
+ | GotSymbolOffset -- ELF: foo@gotoff
+
+ deriving (Eq, Ord)
+
+-- -----------------------------------------------------------------------------
+-- Constructing CLabels
+
+-- These are always local:
+mkSRTLabel name = IdLabel name SRT
+mkSRTDescLabel name = IdLabel name SRTDesc
+mkSlowEntryLabel name = IdLabel name Slow
+mkBitmapLabel name = IdLabel name Bitmap
+mkRednCountsLabel name = IdLabel name RednCounts
+
+-- These have local & (possibly) external variants:
+mkLocalClosureLabel name = IdLabel name Closure
+mkLocalInfoTableLabel name = IdLabel name InfoTable
+mkLocalEntryLabel name = IdLabel name Entry
+mkLocalClosureTableLabel name = IdLabel name ClosureTable
+
+mkClosureLabel hmods name
+ | isDllName hmods name = DynIdLabel name Closure
+ | otherwise = IdLabel name Closure
+
+mkInfoTableLabel hmods name
+ | isDllName hmods name = DynIdLabel name InfoTable
+ | otherwise = IdLabel name InfoTable
+
+mkEntryLabel hmods name
+ | isDllName hmods name = DynIdLabel name Entry
+ | otherwise = IdLabel name Entry
+
+mkClosureTableLabel hmods name
+ | isDllName hmods name = DynIdLabel name ClosureTable
+ | otherwise = IdLabel name ClosureTable
+
+mkLocalConInfoTableLabel con = IdLabel con ConInfoTable
+mkLocalConEntryLabel con = IdLabel con ConEntry
+mkLocalStaticInfoTableLabel con = IdLabel con StaticInfoTable
+mkLocalStaticConEntryLabel con = IdLabel con StaticConEntry
+
+mkConInfoTableLabel name False = IdLabel name ConInfoTable
+mkConInfoTableLabel name True = DynIdLabel name ConInfoTable
+
+mkStaticInfoTableLabel name False = IdLabel name StaticInfoTable
+mkStaticInfoTableLabel name True = DynIdLabel name StaticInfoTable
+
+mkConEntryLabel hmods name
+ | isDllName hmods name = DynIdLabel name ConEntry
+ | otherwise = IdLabel name ConEntry
+
+mkStaticConEntryLabel hmods name
+ | isDllName hmods name = DynIdLabel name StaticConEntry
+ | otherwise = IdLabel name StaticConEntry
+
+
+mkReturnPtLabel uniq = CaseLabel uniq CaseReturnPt
+mkReturnInfoLabel uniq = CaseLabel uniq CaseReturnInfo
+mkAltLabel uniq tag = CaseLabel uniq (CaseAlt tag)
+mkDefaultLabel uniq = CaseLabel uniq CaseDefault
+
+mkStringLitLabel = StringLitLabel
+mkAsmTempLabel = AsmTempLabel
+
+mkModuleInitLabel :: HomeModules -> Module -> String -> CLabel
+mkModuleInitLabel hmods mod way
+ = ModuleInitLabel mod way $! (not (isHomeModule hmods mod))
+
+mkPlainModuleInitLabel :: HomeModules -> Module -> CLabel
+mkPlainModuleInitLabel hmods mod
+ = PlainModuleInitLabel mod $! (not (isHomeModule hmods mod))
+
+ -- Some fixed runtime system labels
+
+mkSplitMarkerLabel = RtsLabel (RtsCode SLIT("__stg_split_marker"))
+mkDirty_MUT_VAR_Label = RtsLabel (RtsCode SLIT("dirty_MUT_VAR"))
+mkUpdInfoLabel = RtsLabel (RtsInfo SLIT("stg_upd_frame"))
+mkSeqInfoLabel = RtsLabel (RtsInfo SLIT("stg_seq_frame"))
+mkIndStaticInfoLabel = RtsLabel (RtsInfo SLIT("stg_IND_STATIC"))
+mkMainCapabilityLabel = RtsLabel (RtsData SLIT("MainCapability"))
+mkMAP_FROZEN_infoLabel = RtsLabel (RtsInfo SLIT("stg_MUT_ARR_PTRS_FROZEN0"))
+mkMAP_DIRTY_infoLabel = RtsLabel (RtsInfo SLIT("stg_MUT_ARR_PTRS_DIRTY"))
+mkEMPTY_MVAR_infoLabel = RtsLabel (RtsInfo SLIT("stg_EMPTY_MVAR"))
+
+mkTopTickyCtrLabel = RtsLabel (RtsData SLIT("top_ct"))
+mkCAFBlackHoleInfoTableLabel = RtsLabel (RtsInfo SLIT("stg_CAF_BLACKHOLE"))
+mkSECAFBlackHoleInfoTableLabel = if opt_DoTickyProfiling then
+ RtsLabel (RtsInfo SLIT("stg_SE_CAF_BLACKHOLE"))
+ else -- RTS won't have info table unless -ticky is on
+ panic "mkSECAFBlackHoleInfoTableLabel requires -ticky"
+mkRtsPrimOpLabel primop = RtsLabel (RtsPrimOp primop)
+
+moduleRegdLabel = ModuleRegdLabel
+
+mkSelectorInfoLabel upd off = RtsLabel (RtsSelectorInfoTable upd off)
+mkSelectorEntryLabel upd off = RtsLabel (RtsSelectorEntry upd off)
+
+mkApInfoTableLabel upd off = RtsLabel (RtsApInfoTable upd off)
+mkApEntryLabel upd off = RtsLabel (RtsApEntry upd off)
+
+ -- Foreign labels
+
+mkForeignLabel :: FastString -> Maybe Int -> Bool -> CLabel
+mkForeignLabel str mb_sz is_dynamic = ForeignLabel str mb_sz is_dynamic
+
+ -- Cost centres etc.
+
+mkCCLabel cc = CC_Label cc
+mkCCSLabel ccs = CCS_Label ccs
+
+mkRtsInfoLabel str = RtsLabel (RtsInfo str)
+mkRtsEntryLabel str = RtsLabel (RtsEntry str)
+mkRtsRetInfoLabel str = RtsLabel (RtsRetInfo str)
+mkRtsRetLabel str = RtsLabel (RtsRet str)
+mkRtsCodeLabel str = RtsLabel (RtsCode str)
+mkRtsDataLabel str = RtsLabel (RtsData str)
+
+mkRtsInfoLabelFS str = RtsLabel (RtsInfoFS str)
+mkRtsEntryLabelFS str = RtsLabel (RtsEntryFS str)
+mkRtsRetInfoLabelFS str = RtsLabel (RtsRetInfoFS str)
+mkRtsRetLabelFS str = RtsLabel (RtsRetFS str)
+mkRtsCodeLabelFS str = RtsLabel (RtsCodeFS str)
+mkRtsDataLabelFS str = RtsLabel (RtsDataFS str)
+
+mkRtsApFastLabel str = RtsLabel (RtsApFast str)
+
+mkRtsSlowTickyCtrLabel :: String -> CLabel
+mkRtsSlowTickyCtrLabel pat = RtsLabel (RtsSlowTickyCtr pat)
+
+ -- Dynamic linking
+
+mkDynamicLinkerLabel :: DynamicLinkerLabelInfo -> CLabel -> CLabel
+mkDynamicLinkerLabel = DynamicLinkerLabel
+
+dynamicLinkerLabelInfo :: CLabel -> Maybe (DynamicLinkerLabelInfo, CLabel)
+dynamicLinkerLabelInfo (DynamicLinkerLabel info lbl) = Just (info, lbl)
+dynamicLinkerLabelInfo _ = Nothing
+
+ -- Position independent code
+
+mkPicBaseLabel :: CLabel
+mkPicBaseLabel = PicBaseLabel
+
+mkDeadStripPreventer :: CLabel -> CLabel
+mkDeadStripPreventer lbl = DeadStripPreventer lbl
+
+-- -----------------------------------------------------------------------------
+-- Converting info labels to entry labels.
+
+infoLblToEntryLbl :: CLabel -> CLabel
+infoLblToEntryLbl (IdLabel n InfoTable) = IdLabel n Entry
+infoLblToEntryLbl (IdLabel n ConInfoTable) = IdLabel n ConEntry
+infoLblToEntryLbl (IdLabel n StaticInfoTable) = IdLabel n StaticConEntry
+infoLblToEntryLbl (DynIdLabel n InfoTable) = DynIdLabel n Entry
+infoLblToEntryLbl (DynIdLabel n ConInfoTable) = DynIdLabel n ConEntry
+infoLblToEntryLbl (DynIdLabel n StaticInfoTable) = DynIdLabel n StaticConEntry
+infoLblToEntryLbl (CaseLabel n CaseReturnInfo) = CaseLabel n CaseReturnPt
+infoLblToEntryLbl (RtsLabel (RtsInfo s)) = RtsLabel (RtsEntry s)
+infoLblToEntryLbl (RtsLabel (RtsRetInfo s)) = RtsLabel (RtsRet s)
+infoLblToEntryLbl (RtsLabel (RtsInfoFS s)) = RtsLabel (RtsEntryFS s)
+infoLblToEntryLbl (RtsLabel (RtsRetInfoFS s)) = RtsLabel (RtsRetFS s)
+infoLblToEntryLbl _ = panic "CLabel.infoLblToEntryLbl"
+
+entryLblToInfoLbl :: CLabel -> CLabel
+entryLblToInfoLbl (IdLabel n Entry) = IdLabel n InfoTable
+entryLblToInfoLbl (IdLabel n ConEntry) = IdLabel n ConInfoTable
+entryLblToInfoLbl (IdLabel n StaticConEntry) = IdLabel n StaticInfoTable
+entryLblToInfoLbl (DynIdLabel n Entry) = DynIdLabel n InfoTable
+entryLblToInfoLbl (DynIdLabel n ConEntry) = DynIdLabel n ConInfoTable
+entryLblToInfoLbl (DynIdLabel n StaticConEntry) = DynIdLabel n StaticInfoTable
+entryLblToInfoLbl (CaseLabel n CaseReturnPt) = CaseLabel n CaseReturnInfo
+entryLblToInfoLbl (RtsLabel (RtsEntry s)) = RtsLabel (RtsInfo s)
+entryLblToInfoLbl (RtsLabel (RtsRet s)) = RtsLabel (RtsRetInfo s)
+entryLblToInfoLbl (RtsLabel (RtsEntryFS s)) = RtsLabel (RtsInfoFS s)
+entryLblToInfoLbl (RtsLabel (RtsRetFS s)) = RtsLabel (RtsRetInfoFS s)
+entryLblToInfoLbl l = pprPanic "CLabel.entryLblToInfoLbl" (pprCLabel l)
+
+-- -----------------------------------------------------------------------------
+-- Does a CLabel need declaring before use or not?
+
+needsCDecl :: CLabel -> Bool
+ -- False <=> it's pre-declared; don't bother
+ -- don't bother declaring SRT & Bitmap labels, we always make sure
+ -- they are defined before use.
+needsCDecl (IdLabel _ SRT) = False
+needsCDecl (IdLabel _ SRTDesc) = False
+needsCDecl (IdLabel _ Bitmap) = False
+needsCDecl (IdLabel _ _) = True
+needsCDecl (DynIdLabel _ _) = True
+needsCDecl (CaseLabel _ _) = True
+needsCDecl (ModuleInitLabel _ _ _) = True
+needsCDecl (PlainModuleInitLabel _ _) = True
+needsCDecl ModuleRegdLabel = False
+
+needsCDecl (StringLitLabel _) = False
+needsCDecl (AsmTempLabel _) = False
+needsCDecl (RtsLabel _) = False
+needsCDecl (ForeignLabel _ _ _) = False
+needsCDecl (CC_Label _) = True
+needsCDecl (CCS_Label _) = True
+
+-- Whether the label is an assembler temporary:
+
+isAsmTemp :: CLabel -> Bool -- is a local temporary for native code generation
+isAsmTemp (AsmTempLabel _) = True
+isAsmTemp _ = False
+
+-- -----------------------------------------------------------------------------
+-- Is a CLabel visible outside this object file or not?
+
+-- From the point of view of the code generator, a name is
+-- externally visible if it has to be declared as exported
+-- in the .o file's symbol table; that is, made non-static.
+
+externallyVisibleCLabel :: CLabel -> Bool -- not C "static"
+externallyVisibleCLabel (CaseLabel _ _) = False
+externallyVisibleCLabel (StringLitLabel _) = False
+externallyVisibleCLabel (AsmTempLabel _) = False
+externallyVisibleCLabel (ModuleInitLabel _ _ _)= True
+externallyVisibleCLabel (PlainModuleInitLabel _ _)= True
+externallyVisibleCLabel ModuleRegdLabel = False
+externallyVisibleCLabel (RtsLabel _) = True
+externallyVisibleCLabel (ForeignLabel _ _ _) = True
+externallyVisibleCLabel (IdLabel name _) = isExternalName name
+externallyVisibleCLabel (DynIdLabel name _) = isExternalName name
+externallyVisibleCLabel (CC_Label _) = True
+externallyVisibleCLabel (CCS_Label _) = True
+externallyVisibleCLabel (DynamicLinkerLabel _ _) = False
+
+-- -----------------------------------------------------------------------------
+-- Finding the "type" of a CLabel
+
+-- For generating correct types in label declarations:
+
+data CLabelType
+ = CodeLabel
+ | DataLabel
+
+labelType :: CLabel -> CLabelType
+labelType (RtsLabel (RtsSelectorInfoTable _ _)) = DataLabel
+labelType (RtsLabel (RtsApInfoTable _ _)) = DataLabel
+labelType (RtsLabel (RtsData _)) = DataLabel
+labelType (RtsLabel (RtsCode _)) = CodeLabel
+labelType (RtsLabel (RtsInfo _)) = DataLabel
+labelType (RtsLabel (RtsEntry _)) = CodeLabel
+labelType (RtsLabel (RtsRetInfo _)) = DataLabel
+labelType (RtsLabel (RtsRet _)) = CodeLabel
+labelType (RtsLabel (RtsDataFS _)) = DataLabel
+labelType (RtsLabel (RtsCodeFS _)) = CodeLabel
+labelType (RtsLabel (RtsInfoFS _)) = DataLabel
+labelType (RtsLabel (RtsEntryFS _)) = CodeLabel
+labelType (RtsLabel (RtsRetInfoFS _)) = DataLabel
+labelType (RtsLabel (RtsRetFS _)) = CodeLabel
+labelType (RtsLabel (RtsApFast _)) = CodeLabel
+labelType (CaseLabel _ CaseReturnInfo) = DataLabel
+labelType (CaseLabel _ _) = CodeLabel
+labelType (ModuleInitLabel _ _ _) = CodeLabel
+labelType (PlainModuleInitLabel _ _) = CodeLabel
+
+labelType (IdLabel _ info) = idInfoLabelType info
+labelType (DynIdLabel _ info) = idInfoLabelType info
+labelType _ = DataLabel
+
+idInfoLabelType info =
+ case info of
+ InfoTable -> DataLabel
+ Closure -> DataLabel
+ Bitmap -> DataLabel
+ ConInfoTable -> DataLabel
+ StaticInfoTable -> DataLabel
+ ClosureTable -> DataLabel
+ _ -> CodeLabel
+
+
+-- -----------------------------------------------------------------------------
+-- Does a CLabel need dynamic linkage?
+
+-- When referring to data in code, we need to know whether
+-- that data resides in a DLL or not. [Win32 only.]
+-- @labelDynamic@ returns @True@ if the label is located
+-- in a DLL, be it a data reference or not.
+
+labelDynamic :: CLabel -> Bool
+labelDynamic lbl =
+ case lbl of
+ RtsLabel _ -> not opt_Static -- i.e., is the RTS in a DLL or not?
+ IdLabel n k -> False
+ DynIdLabel n k -> True
+#if mingw32_TARGET_OS
+ ForeignLabel _ _ d -> d
+#else
+ -- On Mac OS X and on ELF platforms, false positives are OK,
+ -- so we claim that all foreign imports come from dynamic libraries
+ ForeignLabel _ _ _ -> True
+#endif
+ ModuleInitLabel m _ dyn -> not opt_Static && dyn
+ PlainModuleInitLabel m dyn -> not opt_Static && dyn
+
+ -- Note that DynamicLinkerLabels do NOT require dynamic linking themselves.
+ _ -> False
+
+{-
+OLD?: These GRAN functions are needed for spitting out GRAN_FETCH() at the
+right places. It is used to detect when the abstractC statement of an
+CCodeBlock actually contains the code for a slow entry point. -- HWL
+
+We need at least @Eq@ for @CLabels@, because we want to avoid
+duplicate declarations in generating C (see @labelSeenTE@ in
+@PprAbsC@).
+-}
+
+-----------------------------------------------------------------------------
+-- Printing out CLabels.
+
+{-
+Convention:
+
+ <name>_<type>
+
+where <name> is <Module>_<name> for external names and <unique> for
+internal names. <type> is one of the following:
+
+ info Info table
+ srt Static reference table
+ srtd Static reference table descriptor
+ entry Entry code (function, closure)
+ slow Slow entry code (if any)
+ ret Direct return address
+ vtbl Vector table
+ <n>_alt Case alternative (tag n)
+ dflt Default case alternative
+ btm Large bitmap vector
+ closure Static closure
+ con_entry Dynamic Constructor entry code
+ con_info Dynamic Constructor info table
+ static_entry Static Constructor entry code
+ static_info Static Constructor info table
+ sel_info Selector info table
+ sel_entry Selector entry code
+ cc Cost centre
+ ccs Cost centre stack
+
+Many of these distinctions are only for documentation reasons. For
+example, _ret is only distinguished from _entry to make it easy to
+tell whether a code fragment is a return point or a closure/function
+entry.
+-}
+
+instance Outputable CLabel where
+ ppr = pprCLabel
+
+pprCLabel :: CLabel -> SDoc
+
+#if ! OMIT_NATIVE_CODEGEN
+pprCLabel (AsmTempLabel u)
+ = getPprStyle $ \ sty ->
+ if asmStyle sty then
+ ptext asmTempLabelPrefix <> pprUnique u
+ else
+ char '_' <> pprUnique u
+
+pprCLabel (DynamicLinkerLabel info lbl)
+ = pprDynamicLinkerAsmLabel info lbl
+
+pprCLabel PicBaseLabel
+ = ptext SLIT("1b")
+
+pprCLabel (DeadStripPreventer lbl)
+ = pprCLabel lbl <> ptext SLIT("_dsp")
+#endif
+
+pprCLabel lbl =
+#if ! OMIT_NATIVE_CODEGEN
+ getPprStyle $ \ sty ->
+ if asmStyle sty then
+ maybe_underscore (pprAsmCLbl lbl)
+ else
+#endif
+ pprCLbl lbl
+
+maybe_underscore doc
+ | underscorePrefix = pp_cSEP <> doc
+ | otherwise = doc
+
+#ifdef mingw32_TARGET_OS
+-- In asm mode, we need to put the suffix on a stdcall ForeignLabel.
+-- (The C compiler does this itself).
+pprAsmCLbl (ForeignLabel fs (Just sz) _)
+ = ftext fs <> char '@' <> int sz
+#endif
+pprAsmCLbl lbl
+ = pprCLbl lbl
+
+pprCLbl (StringLitLabel u)
+ = pprUnique u <> ptext SLIT("_str")
+
+pprCLbl (CaseLabel u CaseReturnPt)
+ = hcat [pprUnique u, ptext SLIT("_ret")]
+pprCLbl (CaseLabel u CaseReturnInfo)
+ = hcat [pprUnique u, ptext SLIT("_info")]
+pprCLbl (CaseLabel u (CaseAlt tag))
+ = hcat [pprUnique u, pp_cSEP, int tag, ptext SLIT("_alt")]
+pprCLbl (CaseLabel u CaseDefault)
+ = hcat [pprUnique u, ptext SLIT("_dflt")]
+
+pprCLbl (RtsLabel (RtsCode str)) = ptext str
+pprCLbl (RtsLabel (RtsData str)) = ptext str
+pprCLbl (RtsLabel (RtsCodeFS str)) = ftext str
+pprCLbl (RtsLabel (RtsDataFS str)) = ftext str
+
+pprCLbl (RtsLabel (RtsApFast str)) = ptext str <> ptext SLIT("_fast")
+
+pprCLbl (RtsLabel (RtsSelectorInfoTable upd_reqd offset))
+ = hcat [ptext SLIT("stg_sel_"), text (show offset),
+ ptext (if upd_reqd
+ then SLIT("_upd_info")
+ else SLIT("_noupd_info"))
+ ]
+
+pprCLbl (RtsLabel (RtsSelectorEntry upd_reqd offset))
+ = hcat [ptext SLIT("stg_sel_"), text (show offset),
+ ptext (if upd_reqd
+ then SLIT("_upd_entry")
+ else SLIT("_noupd_entry"))
+ ]
+
+pprCLbl (RtsLabel (RtsApInfoTable upd_reqd arity))
+ = hcat [ptext SLIT("stg_ap_"), text (show arity),
+ ptext (if upd_reqd
+ then SLIT("_upd_info")
+ else SLIT("_noupd_info"))
+ ]
+
+pprCLbl (RtsLabel (RtsApEntry upd_reqd arity))
+ = hcat [ptext SLIT("stg_ap_"), text (show arity),
+ ptext (if upd_reqd
+ then SLIT("_upd_entry")
+ else SLIT("_noupd_entry"))
+ ]
+
+pprCLbl (RtsLabel (RtsInfo fs))
+ = ptext fs <> ptext SLIT("_info")
+
+pprCLbl (RtsLabel (RtsEntry fs))
+ = ptext fs <> ptext SLIT("_entry")
+
+pprCLbl (RtsLabel (RtsRetInfo fs))
+ = ptext fs <> ptext SLIT("_info")
+
+pprCLbl (RtsLabel (RtsRet fs))
+ = ptext fs <> ptext SLIT("_ret")
+
+pprCLbl (RtsLabel (RtsInfoFS fs))
+ = ftext fs <> ptext SLIT("_info")
+
+pprCLbl (RtsLabel (RtsEntryFS fs))
+ = ftext fs <> ptext SLIT("_entry")
+
+pprCLbl (RtsLabel (RtsRetInfoFS fs))
+ = ftext fs <> ptext SLIT("_info")
+
+pprCLbl (RtsLabel (RtsRetFS fs))
+ = ftext fs <> ptext SLIT("_ret")
+
+pprCLbl (RtsLabel (RtsPrimOp primop))
+ = ppr primop <> ptext SLIT("_fast")
+
+pprCLbl (RtsLabel (RtsSlowTickyCtr pat))
+ = ptext SLIT("SLOW_CALL_") <> text pat <> ptext SLIT("_ctr")
+
+pprCLbl ModuleRegdLabel
+ = ptext SLIT("_module_registered")
+
+pprCLbl (ForeignLabel str _ _)
+ = ftext str
+
+pprCLbl (IdLabel name flavor) = ppr name <> ppIdFlavor flavor
+pprCLbl (DynIdLabel name flavor) = ppr name <> ppIdFlavor flavor
+
+pprCLbl (CC_Label cc) = ppr cc
+pprCLbl (CCS_Label ccs) = ppr ccs
+
+pprCLbl (ModuleInitLabel mod way _)
+ = ptext SLIT("__stginit_") <> ppr mod
+ <> char '_' <> text way
+pprCLbl (PlainModuleInitLabel mod _)
+ = ptext SLIT("__stginit_") <> ppr mod
+
+ppIdFlavor :: IdLabelInfo -> SDoc
+ppIdFlavor x = pp_cSEP <>
+ (case x of
+ Closure -> ptext SLIT("closure")
+ SRT -> ptext SLIT("srt")
+ SRTDesc -> ptext SLIT("srtd")
+ InfoTable -> ptext SLIT("info")
+ Entry -> ptext SLIT("entry")
+ Slow -> ptext SLIT("slow")
+ RednCounts -> ptext SLIT("ct")
+ Bitmap -> ptext SLIT("btm")
+ ConEntry -> ptext SLIT("con_entry")
+ ConInfoTable -> ptext SLIT("con_info")
+ StaticConEntry -> ptext SLIT("static_entry")
+ StaticInfoTable -> ptext SLIT("static_info")
+ ClosureTable -> ptext SLIT("closure_tbl")
+ )
+
+
+pp_cSEP = char '_'
+
+-- -----------------------------------------------------------------------------
+-- Machine-dependent knowledge about labels.
+
+underscorePrefix :: Bool -- leading underscore on assembler labels?
+underscorePrefix = (cLeadingUnderscore == "YES")
+
+asmTempLabelPrefix :: LitString -- for formatting labels
+asmTempLabelPrefix =
+#if alpha_TARGET_OS
+ {- The alpha assembler likes temporary labels to look like $L123
+ instead of L123. (Don't toss the L, because then Lf28
+ turns into $f28.)
+ -}
+ SLIT("$")
+#elif darwin_TARGET_OS
+ SLIT("L")
+#else
+ SLIT(".L")
+#endif
+
+pprDynamicLinkerAsmLabel :: DynamicLinkerLabelInfo -> CLabel -> SDoc
+
+#if darwin_TARGET_OS
+pprDynamicLinkerAsmLabel SymbolPtr lbl
+ = char 'L' <> pprCLabel lbl <> text "$non_lazy_ptr"
+pprDynamicLinkerAsmLabel CodeStub lbl
+ = char 'L' <> pprCLabel lbl <> text "$stub"
+#elif powerpc_TARGET_ARCH && linux_TARGET_OS
+pprDynamicLinkerAsmLabel CodeStub lbl
+ = pprCLabel lbl <> text "@plt"
+pprDynamicLinkerAsmLabel SymbolPtr lbl
+ = text ".LC_" <> pprCLabel lbl
+#elif linux_TARGET_OS
+pprDynamicLinkerAsmLabel CodeStub lbl
+ = pprCLabel lbl <> text "@plt"
+pprDynamicLinkerAsmLabel GotSymbolPtr lbl
+ = pprCLabel lbl <> text "@got"
+pprDynamicLinkerAsmLabel GotSymbolOffset lbl
+ = pprCLabel lbl <> text "@gotoff"
+pprDynamicLinkerAsmLabel SymbolPtr lbl
+ = text ".LC_" <> pprCLabel lbl
+#elif mingw32_TARGET_OS
+pprDynamicLinkerAsmLabel SymbolPtr lbl
+ = text "__imp_" <> pprCLabel lbl
+#endif
+pprDynamicLinkerAsmLabel _ _
+ = panic "pprDynamicLinkerAsmLabel"
diff --git a/compiler/cmm/Cmm.hs b/compiler/cmm/Cmm.hs
new file mode 100644
index 0000000000..13961c15d3
--- /dev/null
+++ b/compiler/cmm/Cmm.hs
@@ -0,0 +1,322 @@
+-----------------------------------------------------------------------------
+--
+-- Cmm data types
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+module Cmm (
+ GenCmm(..), Cmm,
+ GenCmmTop(..), CmmTop,
+ GenBasicBlock(..), CmmBasicBlock, blockId, blockStmts,
+ CmmStmt(..),
+ CmmCallTarget(..),
+ CmmStatic(..), Section(..),
+ CmmExpr(..), cmmExprRep,
+ CmmReg(..), cmmRegRep,
+ CmmLit(..), cmmLitRep,
+ LocalReg(..), localRegRep,
+ BlockId(..),
+ GlobalReg(..), globalRegRep,
+
+ node, nodeReg, spReg, hpReg,
+ ) where
+
+#include "HsVersions.h"
+
+import MachOp
+import CLabel ( CLabel )
+import ForeignCall ( CCallConv )
+import Unique ( Unique, Uniquable(..) )
+import FastString ( FastString )
+import DATA_WORD ( Word8 )
+
+-----------------------------------------------------------------------------
+-- Cmm, CmmTop, CmmBasicBlock
+-----------------------------------------------------------------------------
+
+-- A file is a list of top-level chunks. These may be arbitrarily
+-- re-orderd during code generation.
+
+-- GenCmm is abstracted over
+-- (a) the type of static data elements
+-- (b) the contents of a basic block.
+-- We expect there to be two main instances of this type:
+-- (a) Plain C--, i.e. populated with CmmLit and CmmExpr respectively,
+-- (b) Native code, populated with instructions
+--
+newtype GenCmm d i = Cmm [GenCmmTop d i]
+
+type Cmm = GenCmm CmmStatic CmmStmt
+
+-- A top-level chunk, abstracted over the type of the contents of
+-- the basic blocks (Cmm or instructions are the likely instantiations).
+data GenCmmTop d i
+ = CmmProc
+ [d] -- Info table, may be empty
+ CLabel -- Used to generate both info & entry labels
+ [LocalReg] -- Argument locals live on entry (C-- procedure params)
+ [GenBasicBlock i] -- Code, may be empty. The first block is
+ -- the entry point. The order is otherwise initially
+ -- unimportant, but at some point the code gen will
+ -- fix the order.
+
+ -- the BlockId of the first block does not give rise
+ -- to a label. To jump to the first block in a Proc,
+ -- use the appropriate CLabel.
+
+ -- some static data.
+ | CmmData Section [d] -- constant values only
+
+type CmmTop = GenCmmTop CmmStatic CmmStmt
+
+-- A basic block containing a single label, at the beginning.
+-- The list of basic blocks in a top-level code block may be re-ordered.
+-- Fall-through is not allowed: there must be an explicit jump at the
+-- end of each basic block, but the code generator might rearrange basic
+-- blocks in order to turn some jumps into fallthroughs.
+
+data GenBasicBlock i = BasicBlock BlockId [i]
+ -- ToDo: Julian suggests that we might need to annotate this type
+ -- with the out & in edges in the graph, i.e. two * [BlockId]. This
+ -- information can be derived from the contents, but it might be
+ -- helpful to cache it here.
+
+type CmmBasicBlock = GenBasicBlock CmmStmt
+
+blockId :: GenBasicBlock i -> BlockId
+-- The branch block id is that of the first block in
+-- the branch, which is that branch's entry point
+blockId (BasicBlock blk_id _ ) = blk_id
+
+blockStmts :: GenBasicBlock i -> [i]
+blockStmts (BasicBlock _ stmts) = stmts
+
+
+-----------------------------------------------------------------------------
+-- CmmStmt
+-- A "statement". Note that all branches are explicit: there are no
+-- control transfers to computed addresses, except when transfering
+-- control to a new function.
+-----------------------------------------------------------------------------
+
+data CmmStmt
+ = CmmNop
+ | CmmComment FastString
+
+ | CmmAssign CmmReg CmmExpr -- Assign to register
+
+ | CmmStore CmmExpr CmmExpr -- Assign to memory location. Size is
+ -- given by cmmExprRep of the rhs.
+
+ | CmmCall -- A foreign call, with
+ CmmCallTarget
+ [(CmmReg,MachHint)] -- zero or more results
+ [(CmmExpr,MachHint)] -- zero or more arguments
+ (Maybe [GlobalReg]) -- Global regs that may need to be saved
+ -- if they will be clobbered by the call.
+ -- Nothing <=> save *all* globals that
+ -- might be clobbered.
+
+ | CmmBranch BlockId -- branch to another BB in this fn
+
+ | CmmCondBranch CmmExpr BlockId -- conditional branch
+
+ | CmmSwitch CmmExpr [Maybe BlockId] -- Table branch
+ -- The scrutinee is zero-based;
+ -- zero -> first block
+ -- one -> second block etc
+ -- Undefined outside range, and when there's a Nothing
+
+ | CmmJump CmmExpr [LocalReg] -- Jump to another function, with these
+ -- parameters.
+
+-----------------------------------------------------------------------------
+-- CmmCallTarget
+--
+-- The target of a CmmCall.
+-----------------------------------------------------------------------------
+
+data CmmCallTarget
+ = CmmForeignCall -- Call to a foreign function
+ CmmExpr -- literal label <=> static call
+ -- other expression <=> dynamic call
+ CCallConv -- The calling convention
+
+ | CmmPrim -- Call to a "primitive" (eg. sin, cos)
+ CallishMachOp -- These might be implemented as inline
+ -- code by the backend.
+
+-----------------------------------------------------------------------------
+-- CmmExpr
+-- An expression. Expressions have no side effects.
+-----------------------------------------------------------------------------
+
+data CmmExpr
+ = CmmLit CmmLit -- Literal
+ | CmmLoad CmmExpr MachRep -- Read memory location
+ | CmmReg CmmReg -- Contents of register
+ | CmmMachOp MachOp [CmmExpr] -- Machine operation (+, -, *, etc.)
+ | CmmRegOff CmmReg Int
+ -- CmmRegOff reg i
+ -- ** is shorthand only, meaning **
+ -- CmmMachOp (MO_S_Add rep (CmmReg reg) (CmmLit (CmmInt i rep)))
+ -- where rep = cmmRegRep reg
+
+cmmExprRep :: CmmExpr -> MachRep
+cmmExprRep (CmmLit lit) = cmmLitRep lit
+cmmExprRep (CmmLoad _ rep) = rep
+cmmExprRep (CmmReg reg) = cmmRegRep reg
+cmmExprRep (CmmMachOp op _) = resultRepOfMachOp op
+cmmExprRep (CmmRegOff reg _) = cmmRegRep reg
+
+data CmmReg
+ = CmmLocal LocalReg
+ | CmmGlobal GlobalReg
+ deriving( Eq )
+
+cmmRegRep :: CmmReg -> MachRep
+cmmRegRep (CmmLocal reg) = localRegRep reg
+cmmRegRep (CmmGlobal reg) = globalRegRep reg
+
+data LocalReg
+ = LocalReg !Unique MachRep
+
+instance Eq LocalReg where
+ (LocalReg u1 _) == (LocalReg u2 _) = u1 == u2
+
+instance Uniquable LocalReg where
+ getUnique (LocalReg uniq _) = uniq
+
+localRegRep :: LocalReg -> MachRep
+localRegRep (LocalReg _ rep) = rep
+
+data CmmLit
+ = CmmInt Integer MachRep
+ -- Interpretation: the 2's complement representation of the value
+ -- is truncated to the specified size. This is easier than trying
+ -- to keep the value within range, because we don't know whether
+ -- it will be used as a signed or unsigned value (the MachRep doesn't
+ -- distinguish between signed & unsigned).
+ | CmmFloat Rational MachRep
+ | CmmLabel CLabel -- Address of label
+ | CmmLabelOff CLabel Int -- Address of label + byte offset
+
+ -- Due to limitations in the C backend, the following
+ -- MUST ONLY be used inside the info table indicated by label2
+ -- (label2 must be the info label), and label1 must be an
+ -- SRT, a slow entrypoint or a large bitmap (see the Mangler)
+ -- Don't use it at all unless tablesNextToCode.
+ -- It is also used inside the NCG during when generating
+ -- position-independent code.
+ | CmmLabelDiffOff CLabel CLabel Int -- label1 - label2 + offset
+
+cmmLitRep :: CmmLit -> MachRep
+cmmLitRep (CmmInt _ rep) = rep
+cmmLitRep (CmmFloat _ rep) = rep
+cmmLitRep (CmmLabel _) = wordRep
+cmmLitRep (CmmLabelOff _ _) = wordRep
+cmmLitRep (CmmLabelDiffOff _ _ _) = wordRep
+
+-----------------------------------------------------------------------------
+-- A local label.
+
+-- Local labels must be unique within a single compilation unit.
+
+newtype BlockId = BlockId Unique
+ deriving (Eq,Ord)
+
+instance Uniquable BlockId where
+ getUnique (BlockId u) = u
+
+-----------------------------------------------------------------------------
+-- Static Data
+-----------------------------------------------------------------------------
+
+data Section
+ = Text
+ | Data
+ | ReadOnlyData
+ | RelocatableReadOnlyData
+ | UninitialisedData
+ | ReadOnlyData16 -- .rodata.cst16 on x86_64, 16-byte aligned
+ | OtherSection String
+
+data CmmStatic
+ = CmmStaticLit CmmLit
+ -- a literal value, size given by cmmLitRep of the literal.
+ | CmmUninitialised Int
+ -- uninitialised data, N bytes long
+ | CmmAlign Int
+ -- align to next N-byte boundary (N must be a power of 2).
+ | CmmDataLabel CLabel
+ -- label the current position in this section.
+ | CmmString [Word8]
+ -- string of 8-bit values only, not zero terminated.
+
+-----------------------------------------------------------------------------
+-- Global STG registers
+-----------------------------------------------------------------------------
+
+data GlobalReg
+ -- Argument and return registers
+ = VanillaReg -- pointers, unboxed ints and chars
+ {-# UNPACK #-} !Int -- its number
+
+ | FloatReg -- single-precision floating-point registers
+ {-# UNPACK #-} !Int -- its number
+
+ | DoubleReg -- double-precision floating-point registers
+ {-# UNPACK #-} !Int -- its number
+
+ | LongReg -- long int registers (64-bit, really)
+ {-# UNPACK #-} !Int -- its number
+
+ -- STG registers
+ | Sp -- Stack ptr; points to last occupied stack location.
+ | SpLim -- Stack limit
+ | Hp -- Heap ptr; points to last occupied heap location.
+ | HpLim -- Heap limit register
+ | CurrentTSO -- pointer to current thread's TSO
+ | CurrentNursery -- pointer to allocation area
+ | HpAlloc -- allocation count for heap check failure
+
+ -- We keep the address of some commonly-called
+ -- functions in the register table, to keep code
+ -- size down:
+ | GCEnter1 -- stg_gc_enter_1
+ | GCFun -- stg_gc_fun
+
+ -- Base offset for the register table, used for accessing registers
+ -- which do not have real registers assigned to them. This register
+ -- will only appear after we have expanded GlobalReg into memory accesses
+ -- (where necessary) in the native code generator.
+ | BaseReg
+
+ -- Base Register for PIC (position-independent code) calculations
+ -- Only used inside the native code generator. It's exact meaning differs
+ -- from platform to platform (see module PositionIndependentCode).
+ | PicBaseReg
+
+ deriving( Eq
+#ifdef DEBUG
+ , Show
+#endif
+ )
+
+-- convenient aliases
+spReg, hpReg, nodeReg :: CmmReg
+spReg = CmmGlobal Sp
+hpReg = CmmGlobal Hp
+nodeReg = CmmGlobal node
+
+node :: GlobalReg
+node = VanillaReg 1
+
+globalRegRep :: GlobalReg -> MachRep
+globalRegRep (VanillaReg _) = wordRep
+globalRegRep (FloatReg _) = F32
+globalRegRep (DoubleReg _) = F64
+globalRegRep (LongReg _) = I64
+globalRegRep _ = wordRep
diff --git a/compiler/cmm/CmmLex.x b/compiler/cmm/CmmLex.x
new file mode 100644
index 0000000000..c2efd17710
--- /dev/null
+++ b/compiler/cmm/CmmLex.x
@@ -0,0 +1,311 @@
+-----------------------------------------------------------------------------
+-- (c) The University of Glasgow, 2004
+--
+-- Lexer for concrete Cmm. We try to stay close to the C-- spec, but there
+-- are a few minor differences:
+--
+-- * extra keywords for our macros, and float32/float64 types
+-- * global registers (Sp,Hp, etc.)
+--
+-----------------------------------------------------------------------------
+
+{
+module CmmLex (
+ CmmToken(..), cmmlex,
+ ) where
+
+#include "HsVersions.h"
+
+import Cmm
+import Lexer
+
+import SrcLoc
+import UniqFM
+import StringBuffer
+import FastString
+import Ctype
+import Util ( readRational )
+--import TRACE
+}
+
+$whitechar = [\ \t\n\r\f\v\xa0]
+$white_no_nl = $whitechar # \n
+
+$ascdigit = 0-9
+$unidigit = \x01
+$digit = [$ascdigit $unidigit]
+$octit = 0-7
+$hexit = [$digit A-F a-f]
+
+$unilarge = \x03
+$asclarge = [A-Z \xc0-\xd6 \xd8-\xde]
+$large = [$asclarge $unilarge]
+
+$unismall = \x04
+$ascsmall = [a-z \xdf-\xf6 \xf8-\xff]
+$small = [$ascsmall $unismall \_]
+
+$namebegin = [$large $small \_ \. \$ \@]
+$namechar = [$namebegin $digit]
+
+@decimal = $digit+
+@octal = $octit+
+@hexadecimal = $hexit+
+@exponent = [eE] [\-\+]? @decimal
+
+@floating_point = @decimal \. @decimal @exponent? | @decimal @exponent
+
+@escape = \\ ([abfnrt\\\'\"\?] | x @hexadecimal | @octal)
+@strchar = ($printable # [\"\\]) | @escape
+
+cmm :-
+
+$white_no_nl+ ;
+^\# pragma .* \n ; -- Apple GCC 3.3 CPP generates pragmas in its output
+
+^\# (line)? { begin line_prag }
+
+-- single-line line pragmas, of the form
+-- # <line> "<file>" <extra-stuff> \n
+<line_prag> $digit+ { setLine line_prag1 }
+<line_prag1> \" ($printable # \")* \" { setFile line_prag2 }
+<line_prag2> .* { pop }
+
+<0> {
+ \n ;
+
+ [\:\;\{\}\[\]\(\)\=\`\~\/\*\%\-\+\&\^\|\>\<\,\!] { special_char }
+
+ ".." { kw CmmT_DotDot }
+ "::" { kw CmmT_DoubleColon }
+ ">>" { kw CmmT_Shr }
+ "<<" { kw CmmT_Shl }
+ ">=" { kw CmmT_Ge }
+ "<=" { kw CmmT_Le }
+ "==" { kw CmmT_Eq }
+ "!=" { kw CmmT_Ne }
+ "&&" { kw CmmT_BoolAnd }
+ "||" { kw CmmT_BoolOr }
+
+ R@decimal { global_regN VanillaReg }
+ F@decimal { global_regN FloatReg }
+ D@decimal { global_regN DoubleReg }
+ L@decimal { global_regN LongReg }
+ Sp { global_reg Sp }
+ SpLim { global_reg SpLim }
+ Hp { global_reg Hp }
+ HpLim { global_reg HpLim }
+ CurrentTSO { global_reg CurrentTSO }
+ CurrentNursery { global_reg CurrentNursery }
+ HpAlloc { global_reg HpAlloc }
+ BaseReg { global_reg BaseReg }
+
+ $namebegin $namechar* { name }
+
+ 0 @octal { tok_octal }
+ @decimal { tok_decimal }
+ 0[xX] @hexadecimal { tok_hexadecimal }
+ @floating_point { strtoken tok_float }
+
+ \" @strchar* \" { strtoken tok_string }
+}
+
+{
+data CmmToken
+ = CmmT_SpecChar Char
+ | CmmT_DotDot
+ | CmmT_DoubleColon
+ | CmmT_Shr
+ | CmmT_Shl
+ | CmmT_Ge
+ | CmmT_Le
+ | CmmT_Eq
+ | CmmT_Ne
+ | CmmT_BoolAnd
+ | CmmT_BoolOr
+ | CmmT_CLOSURE
+ | CmmT_INFO_TABLE
+ | CmmT_INFO_TABLE_RET
+ | CmmT_INFO_TABLE_FUN
+ | CmmT_INFO_TABLE_CONSTR
+ | CmmT_INFO_TABLE_SELECTOR
+ | CmmT_else
+ | CmmT_export
+ | CmmT_section
+ | CmmT_align
+ | CmmT_goto
+ | CmmT_if
+ | CmmT_jump
+ | CmmT_foreign
+ | CmmT_import
+ | CmmT_switch
+ | CmmT_case
+ | CmmT_default
+ | CmmT_bits8
+ | CmmT_bits16
+ | CmmT_bits32
+ | CmmT_bits64
+ | CmmT_float32
+ | CmmT_float64
+ | CmmT_GlobalReg GlobalReg
+ | CmmT_Name FastString
+ | CmmT_String String
+ | CmmT_Int Integer
+ | CmmT_Float Rational
+ | CmmT_EOF
+#ifdef DEBUG
+ deriving (Show)
+#endif
+
+-- -----------------------------------------------------------------------------
+-- Lexer actions
+
+type Action = SrcSpan -> StringBuffer -> Int -> P (Located CmmToken)
+
+begin :: Int -> Action
+begin code _span _str _len = do pushLexState code; lexToken
+
+pop :: Action
+pop _span _buf _len = do popLexState; lexToken
+
+special_char :: Action
+special_char span buf len = return (L span (CmmT_SpecChar (currentChar buf)))
+
+kw :: CmmToken -> Action
+kw tok span buf len = return (L span tok)
+
+global_regN :: (Int -> GlobalReg) -> Action
+global_regN con span buf len
+ = return (L span (CmmT_GlobalReg (con (fromIntegral n))))
+ where buf' = stepOn buf
+ n = parseInteger buf' (len-1) 10 octDecDigit
+
+global_reg :: GlobalReg -> Action
+global_reg r span buf len = return (L span (CmmT_GlobalReg r))
+
+strtoken :: (String -> CmmToken) -> Action
+strtoken f span buf len =
+ return (L span $! (f $! lexemeToString buf len))
+
+name :: Action
+name span buf len =
+ case lookupUFM reservedWordsFM fs of
+ Just tok -> return (L span tok)
+ Nothing -> return (L span (CmmT_Name fs))
+ where
+ fs = lexemeToFastString buf len
+
+reservedWordsFM = listToUFM $
+ map (\(x, y) -> (mkFastString x, y)) [
+ ( "CLOSURE", CmmT_CLOSURE ),
+ ( "INFO_TABLE", CmmT_INFO_TABLE ),
+ ( "INFO_TABLE_RET", CmmT_INFO_TABLE_RET ),
+ ( "INFO_TABLE_FUN", CmmT_INFO_TABLE_FUN ),
+ ( "INFO_TABLE_CONSTR", CmmT_INFO_TABLE_CONSTR ),
+ ( "INFO_TABLE_SELECTOR",CmmT_INFO_TABLE_SELECTOR ),
+ ( "else", CmmT_else ),
+ ( "export", CmmT_export ),
+ ( "section", CmmT_section ),
+ ( "align", CmmT_align ),
+ ( "goto", CmmT_goto ),
+ ( "if", CmmT_if ),
+ ( "jump", CmmT_jump ),
+ ( "foreign", CmmT_foreign ),
+ ( "import", CmmT_import ),
+ ( "switch", CmmT_switch ),
+ ( "case", CmmT_case ),
+ ( "default", CmmT_default ),
+ ( "bits8", CmmT_bits8 ),
+ ( "bits16", CmmT_bits16 ),
+ ( "bits32", CmmT_bits32 ),
+ ( "bits64", CmmT_bits64 ),
+ ( "float32", CmmT_float32 ),
+ ( "float64", CmmT_float64 )
+ ]
+
+tok_decimal span buf len
+ = return (L span (CmmT_Int $! parseInteger buf len 10 octDecDigit))
+
+tok_octal span buf len
+ = return (L span (CmmT_Int $! parseInteger (offsetBytes 1 buf) (len-1) 8 octDecDigit))
+
+tok_hexadecimal span buf len
+ = return (L span (CmmT_Int $! parseInteger (offsetBytes 2 buf) (len-2) 16 hexDigit))
+
+tok_float str = CmmT_Float $! readRational str
+
+tok_string str = CmmT_String (read str)
+ -- urk, not quite right, but it'll do for now
+
+-- -----------------------------------------------------------------------------
+-- Line pragmas
+
+setLine :: Int -> Action
+setLine code span buf len = do
+ let line = parseInteger buf len 10 octDecDigit
+ setSrcLoc (mkSrcLoc (srcSpanFile span) (fromIntegral line - 1) 0)
+ -- subtract one: the line number refers to the *following* line
+ -- trace ("setLine " ++ show line) $ do
+ popLexState
+ pushLexState code
+ lexToken
+
+setFile :: Int -> Action
+setFile code span buf len = do
+ let file = lexemeToFastString (stepOn buf) (len-2)
+ setSrcLoc (mkSrcLoc file (srcSpanEndLine span) (srcSpanEndCol span))
+ popLexState
+ pushLexState code
+ lexToken
+
+-- -----------------------------------------------------------------------------
+-- This is the top-level function: called from the parser each time a
+-- new token is to be read from the input.
+
+cmmlex :: (Located CmmToken -> P a) -> P a
+cmmlex cont = do
+ tok@(L _ tok__) <- lexToken
+ --trace ("token: " ++ show tok__) $ do
+ cont tok
+
+lexToken :: P (Located CmmToken)
+lexToken = do
+ inp@(loc1,buf) <- getInput
+ sc <- getLexState
+ case alexScan inp sc of
+ AlexEOF -> do let span = mkSrcSpan loc1 loc1
+ setLastToken span 0
+ return (L span CmmT_EOF)
+ AlexError (loc2,_) -> do failLocMsgP loc1 loc2 "lexical error"
+ AlexSkip inp2 _ -> do
+ setInput inp2
+ lexToken
+ AlexToken inp2@(end,buf2) len t -> do
+ setInput inp2
+ let span = mkSrcSpan loc1 end
+ span `seq` setLastToken span len
+ t span buf len
+
+-- -----------------------------------------------------------------------------
+-- Monad stuff
+
+-- Stuff that Alex needs to know about our input type:
+type AlexInput = (SrcLoc,StringBuffer)
+
+alexInputPrevChar :: AlexInput -> Char
+alexInputPrevChar (_,s) = prevChar s '\n'
+
+alexGetChar :: AlexInput -> Maybe (Char,AlexInput)
+alexGetChar (loc,s)
+ | atEnd s = Nothing
+ | otherwise = c `seq` loc' `seq` s' `seq` Just (c, (loc', s'))
+ where c = currentChar s
+ loc' = advanceSrcLoc loc c
+ s' = stepOn s
+
+getInput :: P AlexInput
+getInput = P $ \s@PState{ loc=l, buffer=b } -> POk s (l,b)
+
+setInput :: AlexInput -> P ()
+setInput (l,b) = P $ \s -> POk s{ loc=l, buffer=b } ()
+}
diff --git a/compiler/cmm/CmmLint.hs b/compiler/cmm/CmmLint.hs
new file mode 100644
index 0000000000..fbfb14c165
--- /dev/null
+++ b/compiler/cmm/CmmLint.hs
@@ -0,0 +1,159 @@
+-----------------------------------------------------------------------------
+--
+-- CmmLint: checking the correctness of Cmm statements and expressions
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+module CmmLint (
+ cmmLint, cmmLintTop
+ ) where
+
+#include "HsVersions.h"
+
+import Cmm
+import CLabel ( pprCLabel )
+import MachOp
+import Outputable
+import PprCmm
+import Unique ( getUnique )
+import Constants ( wORD_SIZE )
+
+import Monad ( when )
+
+-- -----------------------------------------------------------------------------
+-- Exported entry points:
+
+cmmLint :: Cmm -> Maybe SDoc
+cmmLint (Cmm tops) = runCmmLint $ mapM_ lintCmmTop tops
+
+cmmLintTop :: CmmTop -> Maybe SDoc
+cmmLintTop top = runCmmLint $ lintCmmTop top
+
+runCmmLint :: CmmLint a -> Maybe SDoc
+runCmmLint l =
+ case unCL l of
+ Left err -> Just (ptext SLIT("Cmm lint error:") $$ nest 2 err)
+ Right _ -> Nothing
+
+lintCmmTop (CmmProc _info lbl _args blocks)
+ = addLintInfo (text "in proc " <> pprCLabel lbl) $
+ mapM_ lintCmmBlock blocks
+lintCmmTop _other
+ = return ()
+
+lintCmmBlock (BasicBlock id stmts)
+ = addLintInfo (text "in basic block " <> ppr (getUnique id)) $
+ mapM_ lintCmmStmt stmts
+
+-- -----------------------------------------------------------------------------
+-- lintCmmExpr
+
+-- Checks whether a CmmExpr is "type-correct", and check for obvious-looking
+-- byte/word mismatches.
+
+lintCmmExpr :: CmmExpr -> CmmLint MachRep
+lintCmmExpr (CmmLoad expr rep) = do
+ lintCmmExpr expr
+ when (machRepByteWidth rep >= wORD_SIZE) $
+ cmmCheckWordAddress expr
+ return rep
+lintCmmExpr expr@(CmmMachOp op args) = do
+ mapM_ lintCmmExpr args
+ if map cmmExprRep args == machOpArgReps op
+ then cmmCheckMachOp op args
+ else cmmLintMachOpErr expr
+lintCmmExpr (CmmRegOff reg offset)
+ = lintCmmExpr (CmmMachOp (MO_Add rep)
+ [CmmReg reg, CmmLit (CmmInt (fromIntegral offset) rep)])
+ where rep = cmmRegRep reg
+lintCmmExpr lit@(CmmLit (CmmInt _ rep))
+ | isFloatingRep rep
+ = cmmLintErr (text "integer literal with floating MachRep: " <> ppr lit)
+lintCmmExpr expr =
+ return (cmmExprRep expr)
+
+-- Check for some common byte/word mismatches (eg. Sp + 1)
+cmmCheckMachOp op args@[CmmReg reg, CmmLit (CmmInt i _)]
+ | isWordOffsetReg reg && isOffsetOp op && i `rem` fromIntegral wORD_SIZE /= 0
+ = cmmLintDubiousWordOffset (CmmMachOp op args)
+cmmCheckMachOp op [lit@(CmmLit (CmmInt i _)), reg@(CmmReg _)]
+ = cmmCheckMachOp op [reg, lit]
+cmmCheckMachOp op@(MO_U_Conv from to) args
+ | isFloatingRep from || isFloatingRep to
+ = cmmLintErr (text "unsigned conversion from/to floating rep: "
+ <> ppr (CmmMachOp op args))
+cmmCheckMachOp op args
+ = return (resultRepOfMachOp op)
+
+isWordOffsetReg (CmmGlobal Sp) = True
+isWordOffsetReg (CmmGlobal Hp) = True
+isWordOffsetReg _ = False
+
+isOffsetOp (MO_Add _) = True
+isOffsetOp (MO_Sub _) = True
+isOffsetOp _ = False
+
+-- This expression should be an address from which a word can be loaded:
+-- check for funny-looking sub-word offsets.
+cmmCheckWordAddress e@(CmmMachOp op [arg, CmmLit (CmmInt i _)])
+ | isOffsetOp op && i `rem` fromIntegral wORD_SIZE /= 0
+ = cmmLintDubiousWordOffset e
+cmmCheckWordAddress e@(CmmMachOp op [CmmLit (CmmInt i _), arg])
+ | isOffsetOp op && i `rem` fromIntegral wORD_SIZE /= 0
+ = cmmLintDubiousWordOffset e
+cmmCheckWordAddress _
+ = return ()
+
+
+lintCmmStmt :: CmmStmt -> CmmLint ()
+lintCmmStmt stmt@(CmmAssign reg expr) = do
+ erep <- lintCmmExpr expr
+ if (erep == cmmRegRep reg)
+ then return ()
+ else cmmLintAssignErr stmt
+lintCmmStmt (CmmStore l r) = do
+ lintCmmExpr l
+ lintCmmExpr r
+ return ()
+lintCmmStmt (CmmCall _target _res args _vols) = mapM_ (lintCmmExpr.fst) args
+lintCmmStmt (CmmCondBranch e _id) = lintCmmExpr e >> return ()
+lintCmmStmt (CmmSwitch e _branches) = lintCmmExpr e >> return ()
+lintCmmStmt (CmmJump e _args) = lintCmmExpr e >> return ()
+lintCmmStmt _other = return ()
+
+-- -----------------------------------------------------------------------------
+-- CmmLint monad
+
+-- just a basic error monad:
+
+newtype CmmLint a = CmmLint { unCL :: Either SDoc a }
+
+instance Monad CmmLint where
+ CmmLint m >>= k = CmmLint $ case m of
+ Left e -> Left e
+ Right a -> unCL (k a)
+ return a = CmmLint (Right a)
+
+cmmLintErr :: SDoc -> CmmLint a
+cmmLintErr msg = CmmLint (Left msg)
+
+addLintInfo :: SDoc -> CmmLint a -> CmmLint a
+addLintInfo info thing = CmmLint $
+ case unCL thing of
+ Left err -> Left (hang info 2 err)
+ Right a -> Right a
+
+cmmLintMachOpErr :: CmmExpr -> CmmLint a
+cmmLintMachOpErr expr = cmmLintErr (text "in MachOp application: " $$
+ nest 2 (pprExpr expr))
+
+cmmLintAssignErr :: CmmStmt -> CmmLint a
+cmmLintAssignErr stmt = cmmLintErr (text "in assignment: " $$
+ nest 2 (pprStmt stmt))
+
+cmmLintDubiousWordOffset :: CmmExpr -> CmmLint a
+cmmLintDubiousWordOffset expr
+ = cmmLintErr (text "offset is not a multiple of words: " $$
+ nest 2 (pprExpr expr))
diff --git a/compiler/cmm/CmmOpt.hs b/compiler/cmm/CmmOpt.hs
new file mode 100644
index 0000000000..c454ff4c6a
--- /dev/null
+++ b/compiler/cmm/CmmOpt.hs
@@ -0,0 +1,507 @@
+-----------------------------------------------------------------------------
+--
+-- Cmm optimisation
+--
+-- (c) The University of Glasgow 2006
+--
+-----------------------------------------------------------------------------
+
+module CmmOpt (
+ cmmMiniInline,
+ cmmMachOpFold,
+ cmmLoopifyForC,
+ ) where
+
+#include "HsVersions.h"
+
+import Cmm
+import CmmUtils ( hasNoGlobalRegs )
+import CLabel ( entryLblToInfoLbl )
+import MachOp
+import SMRep ( tablesNextToCode )
+
+import UniqFM
+import Unique ( Unique )
+import Panic ( panic )
+
+import Outputable
+
+import Bits
+import Word
+import Int
+import GLAEXTS
+
+
+-- -----------------------------------------------------------------------------
+-- The mini-inliner
+
+{-
+This pass inlines assignments to temporaries that are used just
+once. It works as follows:
+
+ - count uses of each temporary
+ - for each temporary that occurs just once:
+ - attempt to push it forward to the statement that uses it
+ - only push forward past assignments to other temporaries
+ (assumes that temporaries are single-assignment)
+ - if we reach the statement that uses it, inline the rhs
+ and delete the original assignment.
+
+Possible generalisations: here is an example from factorial
+
+Fac_zdwfac_entry:
+ cmG:
+ _smi = R2;
+ if (_smi != 0) goto cmK;
+ R1 = R3;
+ jump I64[Sp];
+ cmK:
+ _smn = _smi * R3;
+ R2 = _smi + (-1);
+ R3 = _smn;
+ jump Fac_zdwfac_info;
+
+We want to inline _smi and _smn. To inline _smn:
+
+ - we must be able to push forward past assignments to global regs.
+ We can do this if the rhs of the assignment we are pushing
+ forward doesn't refer to the global reg being assigned to; easy
+ to test.
+
+To inline _smi:
+
+ - It is a trivial replacement, reg for reg, but it occurs more than
+ once.
+ - We can inline trivial assignments even if the temporary occurs
+ more than once, as long as we don't eliminate the original assignment
+ (this doesn't help much on its own).
+ - We need to be able to propagate the assignment forward through jumps;
+ if we did this, we would find that it can be inlined safely in all
+ its occurrences.
+-}
+
+cmmMiniInline :: [CmmBasicBlock] -> [CmmBasicBlock]
+cmmMiniInline blocks = map do_inline blocks
+ where
+ blockUses (BasicBlock _ stmts)
+ = foldr (plusUFM_C (+)) emptyUFM (map getStmtUses stmts)
+
+ uses = foldr (plusUFM_C (+)) emptyUFM (map blockUses blocks)
+
+ do_inline (BasicBlock id stmts)
+ = BasicBlock id (cmmMiniInlineStmts uses stmts)
+
+
+cmmMiniInlineStmts :: UniqFM Int -> [CmmStmt] -> [CmmStmt]
+cmmMiniInlineStmts uses [] = []
+cmmMiniInlineStmts uses (stmt@(CmmAssign (CmmLocal (LocalReg u _)) expr) : stmts)
+ | Just 1 <- lookupUFM uses u,
+ Just stmts' <- lookForInline u expr stmts
+ =
+#ifdef NCG_DEBUG
+ trace ("nativeGen: inlining " ++ showSDoc (pprStmt stmt)) $
+#endif
+ cmmMiniInlineStmts uses stmts'
+
+cmmMiniInlineStmts uses (stmt:stmts)
+ = stmt : cmmMiniInlineStmts uses stmts
+
+
+-- Try to inline a temporary assignment. We can skip over assignments to
+-- other tempoararies, because we know that expressions aren't side-effecting
+-- and temporaries are single-assignment.
+lookForInline u expr (stmt@(CmmAssign (CmmLocal (LocalReg u' _)) rhs) : rest)
+ | u /= u'
+ = case lookupUFM (getExprUses rhs) u of
+ Just 1 -> Just (inlineStmt u expr stmt : rest)
+ _other -> case lookForInline u expr rest of
+ Nothing -> Nothing
+ Just stmts -> Just (stmt:stmts)
+
+lookForInline u expr (CmmNop : rest)
+ = lookForInline u expr rest
+
+lookForInline u expr (stmt:stmts)
+ = case lookupUFM (getStmtUses stmt) u of
+ Just 1 | ok_to_inline -> Just (inlineStmt u expr stmt : stmts)
+ _other -> Nothing
+ where
+ -- we don't inline into CmmCall if the expression refers to global
+ -- registers. This is a HACK to avoid global registers clashing with
+ -- C argument-passing registers, really the back-end ought to be able
+ -- to handle it properly, but currently neither PprC nor the NCG can
+ -- do it. See also CgForeignCall:load_args_into_temps.
+ ok_to_inline = case stmt of
+ CmmCall{} -> hasNoGlobalRegs expr
+ _ -> True
+
+-- -----------------------------------------------------------------------------
+-- Boring Cmm traversals for collecting usage info and substitutions.
+
+getStmtUses :: CmmStmt -> UniqFM Int
+getStmtUses (CmmAssign _ e) = getExprUses e
+getStmtUses (CmmStore e1 e2) = plusUFM_C (+) (getExprUses e1) (getExprUses e2)
+getStmtUses (CmmCall target _ es _)
+ = plusUFM_C (+) (uses target) (getExprsUses (map fst es))
+ where uses (CmmForeignCall e _) = getExprUses e
+ uses _ = emptyUFM
+getStmtUses (CmmCondBranch e _) = getExprUses e
+getStmtUses (CmmSwitch e _) = getExprUses e
+getStmtUses (CmmJump e _) = getExprUses e
+getStmtUses _ = emptyUFM
+
+getExprUses :: CmmExpr -> UniqFM Int
+getExprUses (CmmReg (CmmLocal (LocalReg u _))) = unitUFM u 1
+getExprUses (CmmRegOff (CmmLocal (LocalReg u _)) _) = unitUFM u 1
+getExprUses (CmmLoad e _) = getExprUses e
+getExprUses (CmmMachOp _ es) = getExprsUses es
+getExprUses _other = emptyUFM
+
+getExprsUses es = foldr (plusUFM_C (+)) emptyUFM (map getExprUses es)
+
+inlineStmt :: Unique -> CmmExpr -> CmmStmt -> CmmStmt
+inlineStmt u a (CmmAssign r e) = CmmAssign r (inlineExpr u a e)
+inlineStmt u a (CmmStore e1 e2) = CmmStore (inlineExpr u a e1) (inlineExpr u a e2)
+inlineStmt u a (CmmCall target regs es vols)
+ = CmmCall (infn target) regs es' vols
+ where infn (CmmForeignCall fn cconv) = CmmForeignCall fn cconv
+ infn (CmmPrim p) = CmmPrim p
+ es' = [ (inlineExpr u a e, hint) | (e,hint) <- es ]
+inlineStmt u a (CmmCondBranch e d) = CmmCondBranch (inlineExpr u a e) d
+inlineStmt u a (CmmSwitch e d) = CmmSwitch (inlineExpr u a e) d
+inlineStmt u a (CmmJump e d) = CmmJump (inlineExpr u a e) d
+inlineStmt u a other_stmt = other_stmt
+
+inlineExpr :: Unique -> CmmExpr -> CmmExpr -> CmmExpr
+inlineExpr u a e@(CmmReg (CmmLocal (LocalReg u' _)))
+ | u == u' = a
+ | otherwise = e
+inlineExpr u a e@(CmmRegOff (CmmLocal (LocalReg u' rep)) off)
+ | u == u' = CmmMachOp (MO_Add rep) [a, CmmLit (CmmInt (fromIntegral off) rep)]
+ | otherwise = e
+inlineExpr u a (CmmLoad e rep) = CmmLoad (inlineExpr u a e) rep
+inlineExpr u a (CmmMachOp op es) = CmmMachOp op (map (inlineExpr u a) es)
+inlineExpr u a other_expr = other_expr
+
+-- -----------------------------------------------------------------------------
+-- MachOp constant folder
+
+-- Now, try to constant-fold the MachOps. The arguments have already
+-- been optimized and folded.
+
+cmmMachOpFold
+ :: MachOp -- The operation from an CmmMachOp
+ -> [CmmExpr] -- The optimized arguments
+ -> CmmExpr
+
+cmmMachOpFold op arg@[CmmLit (CmmInt x rep)]
+ = case op of
+ MO_S_Neg r -> CmmLit (CmmInt (-x) rep)
+ MO_Not r -> CmmLit (CmmInt (complement x) rep)
+
+ -- these are interesting: we must first narrow to the
+ -- "from" type, in order to truncate to the correct size.
+ -- The final narrow/widen to the destination type
+ -- is implicit in the CmmLit.
+ MO_S_Conv from to
+ | isFloatingRep to -> CmmLit (CmmFloat (fromInteger x) to)
+ | otherwise -> CmmLit (CmmInt (narrowS from x) to)
+ MO_U_Conv from to -> CmmLit (CmmInt (narrowU from x) to)
+
+ _ -> panic "cmmMachOpFold: unknown unary op"
+
+
+-- Eliminate conversion NOPs
+cmmMachOpFold (MO_S_Conv rep1 rep2) [x] | rep1 == rep2 = x
+cmmMachOpFold (MO_U_Conv rep1 rep2) [x] | rep1 == rep2 = x
+
+-- Eliminate nested conversions where possible
+cmmMachOpFold conv_outer args@[CmmMachOp conv_inner [x]]
+ | Just (rep1,rep2,signed1) <- isIntConversion conv_inner,
+ Just (_, rep3,signed2) <- isIntConversion conv_outer
+ = case () of
+ -- widen then narrow to the same size is a nop
+ _ | rep1 < rep2 && rep1 == rep3 -> x
+ -- Widen then narrow to different size: collapse to single conversion
+ -- but remember to use the signedness from the widening, just in case
+ -- the final conversion is a widen.
+ | rep1 < rep2 && rep2 > rep3 ->
+ cmmMachOpFold (intconv signed1 rep1 rep3) [x]
+ -- Nested widenings: collapse if the signedness is the same
+ | rep1 < rep2 && rep2 < rep3 && signed1 == signed2 ->
+ cmmMachOpFold (intconv signed1 rep1 rep3) [x]
+ -- Nested narrowings: collapse
+ | rep1 > rep2 && rep2 > rep3 ->
+ cmmMachOpFold (MO_U_Conv rep1 rep3) [x]
+ | otherwise ->
+ CmmMachOp conv_outer args
+ where
+ isIntConversion (MO_U_Conv rep1 rep2)
+ | not (isFloatingRep rep1) && not (isFloatingRep rep2)
+ = Just (rep1,rep2,False)
+ isIntConversion (MO_S_Conv rep1 rep2)
+ | not (isFloatingRep rep1) && not (isFloatingRep rep2)
+ = Just (rep1,rep2,True)
+ isIntConversion _ = Nothing
+
+ intconv True = MO_S_Conv
+ intconv False = MO_U_Conv
+
+-- ToDo: a narrow of a load can be collapsed into a narrow load, right?
+-- but what if the architecture only supports word-sized loads, should
+-- we do the transformation anyway?
+
+cmmMachOpFold mop args@[CmmLit (CmmInt x xrep), CmmLit (CmmInt y _)]
+ = case mop of
+ -- for comparisons: don't forget to narrow the arguments before
+ -- comparing, since they might be out of range.
+ MO_Eq r -> CmmLit (CmmInt (if x_u == y_u then 1 else 0) wordRep)
+ MO_Ne r -> CmmLit (CmmInt (if x_u /= y_u then 1 else 0) wordRep)
+
+ MO_U_Gt r -> CmmLit (CmmInt (if x_u > y_u then 1 else 0) wordRep)
+ MO_U_Ge r -> CmmLit (CmmInt (if x_u >= y_u then 1 else 0) wordRep)
+ MO_U_Lt r -> CmmLit (CmmInt (if x_u < y_u then 1 else 0) wordRep)
+ MO_U_Le r -> CmmLit (CmmInt (if x_u <= y_u then 1 else 0) wordRep)
+
+ MO_S_Gt r -> CmmLit (CmmInt (if x_s > y_s then 1 else 0) wordRep)
+ MO_S_Ge r -> CmmLit (CmmInt (if x_s >= y_s then 1 else 0) wordRep)
+ MO_S_Lt r -> CmmLit (CmmInt (if x_s < y_s then 1 else 0) wordRep)
+ MO_S_Le r -> CmmLit (CmmInt (if x_s <= y_s then 1 else 0) wordRep)
+
+ MO_Add r -> CmmLit (CmmInt (x + y) r)
+ MO_Sub r -> CmmLit (CmmInt (x - y) r)
+ MO_Mul r -> CmmLit (CmmInt (x * y) r)
+ MO_S_Quot r | y /= 0 -> CmmLit (CmmInt (x `quot` y) r)
+ MO_S_Rem r | y /= 0 -> CmmLit (CmmInt (x `rem` y) r)
+
+ MO_And r -> CmmLit (CmmInt (x .&. y) r)
+ MO_Or r -> CmmLit (CmmInt (x .|. y) r)
+ MO_Xor r -> CmmLit (CmmInt (x `xor` y) r)
+
+ MO_Shl r -> CmmLit (CmmInt (x `shiftL` fromIntegral y) r)
+ MO_U_Shr r -> CmmLit (CmmInt (x_u `shiftR` fromIntegral y) r)
+ MO_S_Shr r -> CmmLit (CmmInt (x `shiftR` fromIntegral y) r)
+
+ other -> CmmMachOp mop args
+
+ where
+ x_u = narrowU xrep x
+ y_u = narrowU xrep y
+ x_s = narrowS xrep x
+ y_s = narrowS xrep y
+
+
+-- When possible, shift the constants to the right-hand side, so that we
+-- can match for strength reductions. Note that the code generator will
+-- also assume that constants have been shifted to the right when
+-- possible.
+
+cmmMachOpFold op [x@(CmmLit _), y]
+ | not (isLit y) && isCommutableMachOp op
+ = cmmMachOpFold op [y, x]
+
+-- Turn (a+b)+c into a+(b+c) where possible. Because literals are
+-- moved to the right, it is more likely that we will find
+-- opportunities for constant folding when the expression is
+-- right-associated.
+--
+-- ToDo: this appears to introduce a quadratic behaviour due to the
+-- nested cmmMachOpFold. Can we fix this?
+--
+-- Why do we check isLit arg1? If arg1 is a lit, it means that arg2
+-- is also a lit (otherwise arg1 would be on the right). If we
+-- put arg1 on the left of the rearranged expression, we'll get into a
+-- loop: (x1+x2)+x3 => x1+(x2+x3) => (x2+x3)+x1 => x2+(x3+x1) ...
+--
+cmmMachOpFold mop1 [CmmMachOp mop2 [arg1,arg2], arg3]
+ | mop1 == mop2 && isAssociativeMachOp mop1 && not (isLit arg1)
+ = cmmMachOpFold mop1 [arg1, cmmMachOpFold mop2 [arg2,arg3]]
+
+-- Make a RegOff if we can
+cmmMachOpFold (MO_Add _) [CmmReg reg, CmmLit (CmmInt n rep)]
+ = CmmRegOff reg (fromIntegral (narrowS rep n))
+cmmMachOpFold (MO_Add _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
+ = CmmRegOff reg (off + fromIntegral (narrowS rep n))
+cmmMachOpFold (MO_Sub _) [CmmReg reg, CmmLit (CmmInt n rep)]
+ = CmmRegOff reg (- fromIntegral (narrowS rep n))
+cmmMachOpFold (MO_Sub _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
+ = CmmRegOff reg (off - fromIntegral (narrowS rep n))
+
+-- Fold label(+/-)offset into a CmmLit where possible
+
+cmmMachOpFold (MO_Add _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
+ = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
+cmmMachOpFold (MO_Add _) [CmmLit (CmmInt i rep), CmmLit (CmmLabel lbl)]
+ = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
+cmmMachOpFold (MO_Sub _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
+ = CmmLit (CmmLabelOff lbl (fromIntegral (negate (narrowU rep i))))
+
+-- We can often do something with constants of 0 and 1 ...
+
+cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 0 _))]
+ = case mop of
+ MO_Add r -> x
+ MO_Sub r -> x
+ MO_Mul r -> y
+ MO_And r -> y
+ MO_Or r -> x
+ MO_Xor r -> x
+ MO_Shl r -> x
+ MO_S_Shr r -> x
+ MO_U_Shr r -> x
+ MO_Ne r | isComparisonExpr x -> x
+ MO_Eq r | Just x' <- maybeInvertConditionalExpr x -> x'
+ MO_U_Gt r | isComparisonExpr x -> x
+ MO_S_Gt r | isComparisonExpr x -> x
+ MO_U_Lt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordRep)
+ MO_S_Lt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordRep)
+ MO_U_Ge r | isComparisonExpr x -> CmmLit (CmmInt 1 wordRep)
+ MO_S_Ge r | isComparisonExpr x -> CmmLit (CmmInt 1 wordRep)
+ MO_U_Le r | Just x' <- maybeInvertConditionalExpr x -> x'
+ MO_S_Le r | Just x' <- maybeInvertConditionalExpr x -> x'
+ other -> CmmMachOp mop args
+
+cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 1 rep))]
+ = case mop of
+ MO_Mul r -> x
+ MO_S_Quot r -> x
+ MO_U_Quot r -> x
+ MO_S_Rem r -> CmmLit (CmmInt 0 rep)
+ MO_U_Rem r -> CmmLit (CmmInt 0 rep)
+ MO_Ne r | Just x' <- maybeInvertConditionalExpr x -> x'
+ MO_Eq r | isComparisonExpr x -> x
+ MO_U_Lt r | Just x' <- maybeInvertConditionalExpr x -> x'
+ MO_S_Lt r | Just x' <- maybeInvertConditionalExpr x -> x'
+ MO_U_Gt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordRep)
+ MO_S_Gt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordRep)
+ MO_U_Le r | isComparisonExpr x -> CmmLit (CmmInt 1 wordRep)
+ MO_S_Le r | isComparisonExpr x -> CmmLit (CmmInt 1 wordRep)
+ MO_U_Ge r | isComparisonExpr x -> x
+ MO_S_Ge r | isComparisonExpr x -> x
+ other -> CmmMachOp mop args
+
+-- Now look for multiplication/division by powers of 2 (integers).
+
+cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt n _))]
+ = case mop of
+ MO_Mul rep
+ -> case exactLog2 n of
+ Nothing -> unchanged
+ Just p -> CmmMachOp (MO_Shl rep) [x, CmmLit (CmmInt p rep)]
+ MO_S_Quot rep
+ -> case exactLog2 n of
+ Nothing -> unchanged
+ Just p -> CmmMachOp (MO_S_Shr rep) [x, CmmLit (CmmInt p rep)]
+ other
+ -> unchanged
+ where
+ unchanged = CmmMachOp mop args
+
+-- Anything else is just too hard.
+
+cmmMachOpFold mop args = CmmMachOp mop args
+
+-- -----------------------------------------------------------------------------
+-- exactLog2
+
+-- This algorithm for determining the $\log_2$ of exact powers of 2 comes
+-- from GCC. It requires bit manipulation primitives, and we use GHC
+-- extensions. Tough.
+--
+-- Used to be in MachInstrs --SDM.
+-- ToDo: remove use of unboxery --SDM.
+
+w2i x = word2Int# x
+i2w x = int2Word# x
+
+exactLog2 :: Integer -> Maybe Integer
+exactLog2 x
+ = if (x <= 0 || x >= 2147483648) then
+ Nothing
+ else
+ case fromInteger x of { I# x# ->
+ if (w2i ((i2w x#) `and#` (i2w (0# -# x#))) /=# x#) then
+ Nothing
+ else
+ Just (toInteger (I# (pow2 x#)))
+ }
+ where
+ pow2 x# | x# ==# 1# = 0#
+ | otherwise = 1# +# pow2 (w2i (i2w x# `shiftRL#` 1#))
+
+
+-- -----------------------------------------------------------------------------
+-- widening / narrowing
+
+narrowU :: MachRep -> Integer -> Integer
+narrowU I8 x = fromIntegral (fromIntegral x :: Word8)
+narrowU I16 x = fromIntegral (fromIntegral x :: Word16)
+narrowU I32 x = fromIntegral (fromIntegral x :: Word32)
+narrowU I64 x = fromIntegral (fromIntegral x :: Word64)
+narrowU _ _ = panic "narrowTo"
+
+narrowS :: MachRep -> Integer -> Integer
+narrowS I8 x = fromIntegral (fromIntegral x :: Int8)
+narrowS I16 x = fromIntegral (fromIntegral x :: Int16)
+narrowS I32 x = fromIntegral (fromIntegral x :: Int32)
+narrowS I64 x = fromIntegral (fromIntegral x :: Int64)
+narrowS _ _ = panic "narrowTo"
+
+-- -----------------------------------------------------------------------------
+-- Loopify for C
+
+{-
+ This is a simple pass that replaces tail-recursive functions like this:
+
+ fac() {
+ ...
+ jump fac();
+ }
+
+ with this:
+
+ fac() {
+ L:
+ ...
+ goto L;
+ }
+
+ the latter generates better C code, because the C compiler treats it
+ like a loop, and brings full loop optimisation to bear.
+
+ In my measurements this makes little or no difference to anything
+ except factorial, but what the hell.
+-}
+
+cmmLoopifyForC :: CmmTop -> CmmTop
+cmmLoopifyForC p@(CmmProc info entry_lbl [] blocks@(BasicBlock top_id _ : _))
+ | null info = p -- only if there's an info table, ignore case alts
+ | otherwise =
+-- pprTrace "jump_lbl" (ppr jump_lbl <+> ppr entry_lbl) $
+ CmmProc info entry_lbl [] blocks'
+ where blocks' = [ BasicBlock id (map do_stmt stmts)
+ | BasicBlock id stmts <- blocks ]
+
+ do_stmt (CmmJump (CmmLit (CmmLabel lbl)) _) | lbl == jump_lbl
+ = CmmBranch top_id
+ do_stmt stmt = stmt
+
+ jump_lbl | tablesNextToCode = entryLblToInfoLbl entry_lbl
+ | otherwise = entry_lbl
+
+cmmLoopifyForC top = top
+
+-- -----------------------------------------------------------------------------
+-- Utils
+
+isLit (CmmLit _) = True
+isLit _ = False
+
+isComparisonExpr :: CmmExpr -> Bool
+isComparisonExpr (CmmMachOp op _) = isComparisonMachOp op
+isComparisonExpr _other = False
+
+maybeInvertConditionalExpr :: CmmExpr -> Maybe CmmExpr
+maybeInvertConditionalExpr (CmmMachOp op args)
+ | Just op' <- maybeInvertComparison op = Just (CmmMachOp op' args)
+maybeInvertConditionalExpr _ = Nothing
diff --git a/compiler/cmm/CmmParse.y b/compiler/cmm/CmmParse.y
new file mode 100644
index 0000000000..73618bc35b
--- /dev/null
+++ b/compiler/cmm/CmmParse.y
@@ -0,0 +1,890 @@
+-----------------------------------------------------------------------------
+--
+-- (c) The University of Glasgow, 2004
+--
+-- Parser for concrete Cmm.
+--
+-----------------------------------------------------------------------------
+
+{
+module CmmParse ( parseCmmFile ) where
+
+import CgMonad
+import CgHeapery
+import CgUtils
+import CgProf
+import CgTicky
+import CgInfoTbls
+import CgForeignCall
+import CgTailCall ( pushUnboxedTuple )
+import CgStackery ( emitPushUpdateFrame )
+import ClosureInfo ( C_SRT(..) )
+import CgCallConv ( smallLiveness )
+import CgClosure ( emitBlackHoleCode )
+import CostCentre ( dontCareCCS )
+
+import Cmm
+import PprCmm
+import CmmUtils ( mkIntCLit )
+import CmmLex
+import CLabel
+import MachOp
+import SMRep ( fixedHdrSize, CgRep(..) )
+import Lexer
+
+import ForeignCall ( CCallConv(..), Safety(..) )
+import Literal ( mkMachInt )
+import Unique
+import UniqFM
+import SrcLoc
+import DynFlags ( DynFlags, DynFlag(..) )
+import Packages ( HomeModules )
+import StaticFlags ( opt_SccProfilingOn )
+import ErrUtils ( printError, dumpIfSet_dyn, showPass )
+import StringBuffer ( hGetStringBuffer )
+import FastString
+import Panic ( panic )
+import Constants ( wORD_SIZE )
+import Outputable
+
+import Monad ( when )
+import Data.Char ( ord )
+
+#include "HsVersions.h"
+}
+
+%token
+ ':' { L _ (CmmT_SpecChar ':') }
+ ';' { L _ (CmmT_SpecChar ';') }
+ '{' { L _ (CmmT_SpecChar '{') }
+ '}' { L _ (CmmT_SpecChar '}') }
+ '[' { L _ (CmmT_SpecChar '[') }
+ ']' { L _ (CmmT_SpecChar ']') }
+ '(' { L _ (CmmT_SpecChar '(') }
+ ')' { L _ (CmmT_SpecChar ')') }
+ '=' { L _ (CmmT_SpecChar '=') }
+ '`' { L _ (CmmT_SpecChar '`') }
+ '~' { L _ (CmmT_SpecChar '~') }
+ '/' { L _ (CmmT_SpecChar '/') }
+ '*' { L _ (CmmT_SpecChar '*') }
+ '%' { L _ (CmmT_SpecChar '%') }
+ '-' { L _ (CmmT_SpecChar '-') }
+ '+' { L _ (CmmT_SpecChar '+') }
+ '&' { L _ (CmmT_SpecChar '&') }
+ '^' { L _ (CmmT_SpecChar '^') }
+ '|' { L _ (CmmT_SpecChar '|') }
+ '>' { L _ (CmmT_SpecChar '>') }
+ '<' { L _ (CmmT_SpecChar '<') }
+ ',' { L _ (CmmT_SpecChar ',') }
+ '!' { L _ (CmmT_SpecChar '!') }
+
+ '..' { L _ (CmmT_DotDot) }
+ '::' { L _ (CmmT_DoubleColon) }
+ '>>' { L _ (CmmT_Shr) }
+ '<<' { L _ (CmmT_Shl) }
+ '>=' { L _ (CmmT_Ge) }
+ '<=' { L _ (CmmT_Le) }
+ '==' { L _ (CmmT_Eq) }
+ '!=' { L _ (CmmT_Ne) }
+ '&&' { L _ (CmmT_BoolAnd) }
+ '||' { L _ (CmmT_BoolOr) }
+
+ 'CLOSURE' { L _ (CmmT_CLOSURE) }
+ 'INFO_TABLE' { L _ (CmmT_INFO_TABLE) }
+ 'INFO_TABLE_RET'{ L _ (CmmT_INFO_TABLE_RET) }
+ 'INFO_TABLE_FUN'{ L _ (CmmT_INFO_TABLE_FUN) }
+ 'INFO_TABLE_CONSTR'{ L _ (CmmT_INFO_TABLE_CONSTR) }
+ 'INFO_TABLE_SELECTOR'{ L _ (CmmT_INFO_TABLE_SELECTOR) }
+ 'else' { L _ (CmmT_else) }
+ 'export' { L _ (CmmT_export) }
+ 'section' { L _ (CmmT_section) }
+ 'align' { L _ (CmmT_align) }
+ 'goto' { L _ (CmmT_goto) }
+ 'if' { L _ (CmmT_if) }
+ 'jump' { L _ (CmmT_jump) }
+ 'foreign' { L _ (CmmT_foreign) }
+ 'import' { L _ (CmmT_import) }
+ 'switch' { L _ (CmmT_switch) }
+ 'case' { L _ (CmmT_case) }
+ 'default' { L _ (CmmT_default) }
+ 'bits8' { L _ (CmmT_bits8) }
+ 'bits16' { L _ (CmmT_bits16) }
+ 'bits32' { L _ (CmmT_bits32) }
+ 'bits64' { L _ (CmmT_bits64) }
+ 'float32' { L _ (CmmT_float32) }
+ 'float64' { L _ (CmmT_float64) }
+
+ GLOBALREG { L _ (CmmT_GlobalReg $$) }
+ NAME { L _ (CmmT_Name $$) }
+ STRING { L _ (CmmT_String $$) }
+ INT { L _ (CmmT_Int $$) }
+ FLOAT { L _ (CmmT_Float $$) }
+
+%monad { P } { >>= } { return }
+%lexer { cmmlex } { L _ CmmT_EOF }
+%name cmmParse cmm
+%tokentype { Located CmmToken }
+
+-- C-- operator precedences, taken from the C-- spec
+%right '||' -- non-std extension, called %disjoin in C--
+%right '&&' -- non-std extension, called %conjoin in C--
+%right '!'
+%nonassoc '>=' '>' '<=' '<' '!=' '=='
+%left '|'
+%left '^'
+%left '&'
+%left '>>' '<<'
+%left '-' '+'
+%left '/' '*' '%'
+%right '~'
+
+%%
+
+cmm :: { ExtCode }
+ : {- empty -} { return () }
+ | cmmtop cmm { do $1; $2 }
+
+cmmtop :: { ExtCode }
+ : cmmproc { $1 }
+ | cmmdata { $1 }
+ | decl { $1 }
+ | 'CLOSURE' '(' NAME ',' NAME lits ')' ';'
+ { do lits <- sequence $6;
+ staticClosure $3 $5 (map getLit lits) }
+
+-- The only static closures in the RTS are dummy closures like
+-- stg_END_TSO_QUEUE_closure and stg_dummy_ret. We don't need
+-- to provide the full generality of static closures here.
+-- In particular:
+-- * CCS can always be CCS_DONT_CARE
+-- * closure is always extern
+-- * payload is always empty
+-- * we can derive closure and info table labels from a single NAME
+
+cmmdata :: { ExtCode }
+ : 'section' STRING '{' statics '}'
+ { do ss <- sequence $4;
+ code (emitData (section $2) (concat ss)) }
+
+statics :: { [ExtFCode [CmmStatic]] }
+ : {- empty -} { [] }
+ | static statics { $1 : $2 }
+
+-- Strings aren't used much in the RTS HC code, so it doesn't seem
+-- worth allowing inline strings. C-- doesn't allow them anyway.
+static :: { ExtFCode [CmmStatic] }
+ : NAME ':' { return [CmmDataLabel (mkRtsDataLabelFS $1)] }
+ | type expr ';' { do e <- $2;
+ return [CmmStaticLit (getLit e)] }
+ | type ';' { return [CmmUninitialised
+ (machRepByteWidth $1)] }
+ | 'bits8' '[' ']' STRING ';' { return [mkString $4] }
+ | 'bits8' '[' INT ']' ';' { return [CmmUninitialised
+ (fromIntegral $3)] }
+ | typenot8 '[' INT ']' ';' { return [CmmUninitialised
+ (machRepByteWidth $1 *
+ fromIntegral $3)] }
+ | 'align' INT ';' { return [CmmAlign (fromIntegral $2)] }
+ | 'CLOSURE' '(' NAME lits ')'
+ { do lits <- sequence $4;
+ return $ map CmmStaticLit $
+ mkStaticClosure (mkRtsInfoLabelFS $3)
+ dontCareCCS (map getLit lits) [] [] [] }
+ -- arrays of closures required for the CHARLIKE & INTLIKE arrays
+
+lits :: { [ExtFCode CmmExpr] }
+ : {- empty -} { [] }
+ | ',' expr lits { $2 : $3 }
+
+cmmproc :: { ExtCode }
+ : info '{' body '}'
+ { do (info_lbl, info1, info2) <- $1;
+ stmts <- getCgStmtsEC (loopDecls $3)
+ blks <- code (cgStmtsToBlocks stmts)
+ code (emitInfoTableAndCode info_lbl info1 info2 [] blks) }
+
+ | info ';'
+ { do (info_lbl, info1, info2) <- $1;
+ code (emitInfoTableAndCode info_lbl info1 info2 [] []) }
+
+ | NAME '{' body '}'
+ { do stmts <- getCgStmtsEC (loopDecls $3);
+ blks <- code (cgStmtsToBlocks stmts)
+ code (emitProc [] (mkRtsCodeLabelFS $1) [] blks) }
+
+info :: { ExtFCode (CLabel, [CmmLit],[CmmLit]) }
+ : 'INFO_TABLE' '(' NAME ',' INT ',' INT ',' INT ',' STRING ',' STRING ')'
+ -- ptrs, nptrs, closure type, description, type
+ { stdInfo $3 $5 $7 0 $9 $11 $13 }
+
+ | 'INFO_TABLE_FUN' '(' NAME ',' INT ',' INT ',' INT ',' STRING ',' STRING ',' INT ')'
+ -- ptrs, nptrs, closure type, description, type, fun type
+ { funInfo $3 $5 $7 $9 $11 $13 $15 }
+
+ | 'INFO_TABLE_CONSTR' '(' NAME ',' INT ',' INT ',' INT ',' INT ',' STRING ',' STRING ')'
+ -- ptrs, nptrs, tag, closure type, description, type
+ { stdInfo $3 $5 $7 $9 $11 $13 $15 }
+
+ | 'INFO_TABLE_SELECTOR' '(' NAME ',' INT ',' INT ',' STRING ',' STRING ')'
+ -- selector, closure type, description, type
+ { basicInfo $3 (mkIntCLit (fromIntegral $5)) 0 $7 $9 $11 }
+
+ | 'INFO_TABLE_RET' '(' NAME ',' INT ',' INT ',' INT maybe_vec ')'
+ { retInfo $3 $5 $7 $9 $10 }
+
+maybe_vec :: { [CmmLit] }
+ : {- empty -} { [] }
+ | ',' NAME maybe_vec { CmmLabel (mkRtsCodeLabelFS $2) : $3 }
+
+body :: { ExtCode }
+ : {- empty -} { return () }
+ | decl body { do $1; $2 }
+ | stmt body { do $1; $2 }
+
+decl :: { ExtCode }
+ : type names ';' { mapM_ (newLocal $1) $2 }
+ | 'import' names ';' { return () } -- ignore imports
+ | 'export' names ';' { return () } -- ignore exports
+
+names :: { [FastString] }
+ : NAME { [$1] }
+ | NAME ',' names { $1 : $3 }
+
+stmt :: { ExtCode }
+ : ';' { nopEC }
+
+ | block_id ':' { code (labelC $1) }
+
+ | lreg '=' expr ';'
+ { do reg <- $1; e <- $3; stmtEC (CmmAssign reg e) }
+ | type '[' expr ']' '=' expr ';'
+ { doStore $1 $3 $6 }
+ | 'foreign' STRING expr '(' hint_exprs0 ')' vols ';'
+ {% foreignCall $2 [] $3 $5 $7 }
+ | lreg '=' 'foreign' STRING expr '(' hint_exprs0 ')' vols ';'
+ {% let result = do r <- $1; return (r,NoHint) in
+ foreignCall $4 [result] $5 $7 $9 }
+ | STRING lreg '=' 'foreign' STRING expr '(' hint_exprs0 ')' vols ';'
+ {% do h <- parseHint $1;
+ let result = do r <- $2; return (r,h) in
+ foreignCall $5 [result] $6 $8 $10 }
+ -- stmt-level macros, stealing syntax from ordinary C-- function calls.
+ -- Perhaps we ought to use the %%-form?
+ | NAME '(' exprs0 ')' ';'
+ {% stmtMacro $1 $3 }
+ | 'switch' maybe_range expr '{' arms default '}'
+ { doSwitch $2 $3 $5 $6 }
+ | 'goto' block_id ';'
+ { stmtEC (CmmBranch $2) }
+ | 'jump' expr {-maybe_actuals-} ';'
+ { do e <- $2; stmtEC (CmmJump e []) }
+ | 'if' bool_expr '{' body '}' else
+ { ifThenElse $2 $4 $6 }
+
+bool_expr :: { ExtFCode BoolExpr }
+ : bool_op { $1 }
+ | expr { do e <- $1; return (BoolTest e) }
+
+bool_op :: { ExtFCode BoolExpr }
+ : bool_expr '&&' bool_expr { do e1 <- $1; e2 <- $3;
+ return (BoolAnd e1 e2) }
+ | bool_expr '||' bool_expr { do e1 <- $1; e2 <- $3;
+ return (BoolOr e1 e2) }
+ | '!' bool_expr { do e <- $2; return (BoolNot e) }
+ | '(' bool_op ')' { $2 }
+
+-- This is not C-- syntax. What to do?
+vols :: { Maybe [GlobalReg] }
+ : {- empty -} { Nothing }
+ | '[' ']' { Just [] }
+ | '[' globals ']' { Just $2 }
+
+globals :: { [GlobalReg] }
+ : GLOBALREG { [$1] }
+ | GLOBALREG ',' globals { $1 : $3 }
+
+maybe_range :: { Maybe (Int,Int) }
+ : '[' INT '..' INT ']' { Just (fromIntegral $2, fromIntegral $4) }
+ | {- empty -} { Nothing }
+
+arms :: { [([Int],ExtCode)] }
+ : {- empty -} { [] }
+ | arm arms { $1 : $2 }
+
+arm :: { ([Int],ExtCode) }
+ : 'case' ints ':' '{' body '}' { ($2, $5) }
+
+ints :: { [Int] }
+ : INT { [ fromIntegral $1 ] }
+ | INT ',' ints { fromIntegral $1 : $3 }
+
+default :: { Maybe ExtCode }
+ : 'default' ':' '{' body '}' { Just $4 }
+ -- taking a few liberties with the C-- syntax here; C-- doesn't have
+ -- 'default' branches
+ | {- empty -} { Nothing }
+
+else :: { ExtCode }
+ : {- empty -} { nopEC }
+ | 'else' '{' body '}' { $3 }
+
+-- we have to write this out longhand so that Happy's precedence rules
+-- can kick in.
+expr :: { ExtFCode CmmExpr }
+ : expr '/' expr { mkMachOp MO_U_Quot [$1,$3] }
+ | expr '*' expr { mkMachOp MO_Mul [$1,$3] }
+ | expr '%' expr { mkMachOp MO_U_Rem [$1,$3] }
+ | expr '-' expr { mkMachOp MO_Sub [$1,$3] }
+ | expr '+' expr { mkMachOp MO_Add [$1,$3] }
+ | expr '>>' expr { mkMachOp MO_U_Shr [$1,$3] }
+ | expr '<<' expr { mkMachOp MO_Shl [$1,$3] }
+ | expr '&' expr { mkMachOp MO_And [$1,$3] }
+ | expr '^' expr { mkMachOp MO_Xor [$1,$3] }
+ | expr '|' expr { mkMachOp MO_Or [$1,$3] }
+ | expr '>=' expr { mkMachOp MO_U_Ge [$1,$3] }
+ | expr '>' expr { mkMachOp MO_U_Gt [$1,$3] }
+ | expr '<=' expr { mkMachOp MO_U_Le [$1,$3] }
+ | expr '<' expr { mkMachOp MO_U_Lt [$1,$3] }
+ | expr '!=' expr { mkMachOp MO_Ne [$1,$3] }
+ | expr '==' expr { mkMachOp MO_Eq [$1,$3] }
+ | '~' expr { mkMachOp MO_Not [$2] }
+ | '-' expr { mkMachOp MO_S_Neg [$2] }
+ | expr0 '`' NAME '`' expr0 {% do { mo <- nameToMachOp $3 ;
+ return (mkMachOp mo [$1,$5]) } }
+ | expr0 { $1 }
+
+expr0 :: { ExtFCode CmmExpr }
+ : INT maybe_ty { return (CmmLit (CmmInt $1 $2)) }
+ | FLOAT maybe_ty { return (CmmLit (CmmFloat $1 $2)) }
+ | STRING { do s <- code (mkStringCLit $1);
+ return (CmmLit s) }
+ | reg { $1 }
+ | type '[' expr ']' { do e <- $3; return (CmmLoad e $1) }
+ | '%' NAME '(' exprs0 ')' {% exprOp $2 $4 }
+ | '(' expr ')' { $2 }
+
+
+-- leaving out the type of a literal gives you the native word size in C--
+maybe_ty :: { MachRep }
+ : {- empty -} { wordRep }
+ | '::' type { $2 }
+
+hint_exprs0 :: { [ExtFCode (CmmExpr, MachHint)] }
+ : {- empty -} { [] }
+ | hint_exprs { $1 }
+
+hint_exprs :: { [ExtFCode (CmmExpr, MachHint)] }
+ : hint_expr { [$1] }
+ | hint_expr ',' hint_exprs { $1 : $3 }
+
+hint_expr :: { ExtFCode (CmmExpr, MachHint) }
+ : expr { do e <- $1; return (e, inferHint e) }
+ | expr STRING {% do h <- parseHint $2;
+ return $ do
+ e <- $1; return (e,h) }
+
+exprs0 :: { [ExtFCode CmmExpr] }
+ : {- empty -} { [] }
+ | exprs { $1 }
+
+exprs :: { [ExtFCode CmmExpr] }
+ : expr { [ $1 ] }
+ | expr ',' exprs { $1 : $3 }
+
+reg :: { ExtFCode CmmExpr }
+ : NAME { lookupName $1 }
+ | GLOBALREG { return (CmmReg (CmmGlobal $1)) }
+
+lreg :: { ExtFCode CmmReg }
+ : NAME { do e <- lookupName $1;
+ return $
+ case e of
+ CmmReg r -> r
+ other -> pprPanic "CmmParse:" (ftext $1 <> text " not a register") }
+ | GLOBALREG { return (CmmGlobal $1) }
+
+block_id :: { BlockId }
+ : NAME { BlockId (newTagUnique (getUnique $1) 'L') }
+ -- TODO: ugh. The unique of a FastString has a null
+ -- tag, so we have to put our own tag on. We should
+ -- really make a new unique for every label, and keep
+ -- them in an environment.
+
+type :: { MachRep }
+ : 'bits8' { I8 }
+ | typenot8 { $1 }
+
+typenot8 :: { MachRep }
+ : 'bits16' { I16 }
+ | 'bits32' { I32 }
+ | 'bits64' { I64 }
+ | 'float32' { F32 }
+ | 'float64' { F64 }
+{
+section :: String -> Section
+section "text" = Text
+section "data" = Data
+section "rodata" = ReadOnlyData
+section "bss" = UninitialisedData
+section s = OtherSection s
+
+mkString :: String -> CmmStatic
+mkString s = CmmString (map (fromIntegral.ord) s)
+
+-- mkMachOp infers the type of the MachOp from the type of its first
+-- argument. We assume that this is correct: for MachOps that don't have
+-- symmetrical args (e.g. shift ops), the first arg determines the type of
+-- the op.
+mkMachOp :: (MachRep -> MachOp) -> [ExtFCode CmmExpr] -> ExtFCode CmmExpr
+mkMachOp fn args = do
+ arg_exprs <- sequence args
+ return (CmmMachOp (fn (cmmExprRep (head arg_exprs))) arg_exprs)
+
+getLit :: CmmExpr -> CmmLit
+getLit (CmmLit l) = l
+getLit (CmmMachOp (MO_S_Neg _) [CmmLit (CmmInt i r)]) = CmmInt (negate i) r
+getLit _ = panic "invalid literal" -- TODO messy failure
+
+nameToMachOp :: FastString -> P (MachRep -> MachOp)
+nameToMachOp name =
+ case lookupUFM machOps name of
+ Nothing -> fail ("unknown primitive " ++ unpackFS name)
+ Just m -> return m
+
+exprOp :: FastString -> [ExtFCode CmmExpr] -> P (ExtFCode CmmExpr)
+exprOp name args_code =
+ case lookupUFM exprMacros name of
+ Just f -> return $ do
+ args <- sequence args_code
+ return (f args)
+ Nothing -> do
+ mo <- nameToMachOp name
+ return $ mkMachOp mo args_code
+
+exprMacros :: UniqFM ([CmmExpr] -> CmmExpr)
+exprMacros = listToUFM [
+ ( FSLIT("ENTRY_CODE"), \ [x] -> entryCode x ),
+ ( FSLIT("INFO_PTR"), \ [x] -> closureInfoPtr x ),
+ ( FSLIT("STD_INFO"), \ [x] -> infoTable x ),
+ ( FSLIT("FUN_INFO"), \ [x] -> funInfoTable x ),
+ ( FSLIT("GET_ENTRY"), \ [x] -> entryCode (closureInfoPtr x) ),
+ ( FSLIT("GET_STD_INFO"), \ [x] -> infoTable (closureInfoPtr x) ),
+ ( FSLIT("GET_FUN_INFO"), \ [x] -> funInfoTable (closureInfoPtr x) ),
+ ( FSLIT("INFO_TYPE"), \ [x] -> infoTableClosureType x ),
+ ( FSLIT("INFO_PTRS"), \ [x] -> infoTablePtrs x ),
+ ( FSLIT("INFO_NPTRS"), \ [x] -> infoTableNonPtrs x ),
+ ( FSLIT("RET_VEC"), \ [info, conZ] -> retVec info conZ )
+ ]
+
+-- we understand a subset of C-- primitives:
+machOps = listToUFM $
+ map (\(x, y) -> (mkFastString x, y)) [
+ ( "add", MO_Add ),
+ ( "sub", MO_Sub ),
+ ( "eq", MO_Eq ),
+ ( "ne", MO_Ne ),
+ ( "mul", MO_Mul ),
+ ( "neg", MO_S_Neg ),
+ ( "quot", MO_S_Quot ),
+ ( "rem", MO_S_Rem ),
+ ( "divu", MO_U_Quot ),
+ ( "modu", MO_U_Rem ),
+
+ ( "ge", MO_S_Ge ),
+ ( "le", MO_S_Le ),
+ ( "gt", MO_S_Gt ),
+ ( "lt", MO_S_Lt ),
+
+ ( "geu", MO_U_Ge ),
+ ( "leu", MO_U_Le ),
+ ( "gtu", MO_U_Gt ),
+ ( "ltu", MO_U_Lt ),
+
+ ( "flt", MO_S_Lt ),
+ ( "fle", MO_S_Le ),
+ ( "feq", MO_Eq ),
+ ( "fne", MO_Ne ),
+ ( "fgt", MO_S_Gt ),
+ ( "fge", MO_S_Ge ),
+ ( "fneg", MO_S_Neg ),
+
+ ( "and", MO_And ),
+ ( "or", MO_Or ),
+ ( "xor", MO_Xor ),
+ ( "com", MO_Not ),
+ ( "shl", MO_Shl ),
+ ( "shrl", MO_U_Shr ),
+ ( "shra", MO_S_Shr ),
+
+ ( "lobits8", flip MO_U_Conv I8 ),
+ ( "lobits16", flip MO_U_Conv I16 ),
+ ( "lobits32", flip MO_U_Conv I32 ),
+ ( "lobits64", flip MO_U_Conv I64 ),
+ ( "sx16", flip MO_S_Conv I16 ),
+ ( "sx32", flip MO_S_Conv I32 ),
+ ( "sx64", flip MO_S_Conv I64 ),
+ ( "zx16", flip MO_U_Conv I16 ),
+ ( "zx32", flip MO_U_Conv I32 ),
+ ( "zx64", flip MO_U_Conv I64 ),
+ ( "f2f32", flip MO_S_Conv F32 ), -- TODO; rounding mode
+ ( "f2f64", flip MO_S_Conv F64 ), -- TODO; rounding mode
+ ( "f2i8", flip MO_S_Conv I8 ),
+ ( "f2i16", flip MO_S_Conv I8 ),
+ ( "f2i32", flip MO_S_Conv I8 ),
+ ( "f2i64", flip MO_S_Conv I8 ),
+ ( "i2f32", flip MO_S_Conv F32 ),
+ ( "i2f64", flip MO_S_Conv F64 )
+ ]
+
+parseHint :: String -> P MachHint
+parseHint "ptr" = return PtrHint
+parseHint "signed" = return SignedHint
+parseHint "float" = return FloatHint
+parseHint str = fail ("unrecognised hint: " ++ str)
+
+-- labels are always pointers, so we might as well infer the hint
+inferHint :: CmmExpr -> MachHint
+inferHint (CmmLit (CmmLabel _)) = PtrHint
+inferHint (CmmReg (CmmGlobal g)) | isPtrGlobalReg g = PtrHint
+inferHint _ = NoHint
+
+isPtrGlobalReg Sp = True
+isPtrGlobalReg SpLim = True
+isPtrGlobalReg Hp = True
+isPtrGlobalReg HpLim = True
+isPtrGlobalReg CurrentTSO = True
+isPtrGlobalReg CurrentNursery = True
+isPtrGlobalReg _ = False
+
+happyError :: P a
+happyError = srcParseFail
+
+-- -----------------------------------------------------------------------------
+-- Statement-level macros
+
+stmtMacro :: FastString -> [ExtFCode CmmExpr] -> P ExtCode
+stmtMacro fun args_code = do
+ case lookupUFM stmtMacros fun of
+ Nothing -> fail ("unknown macro: " ++ unpackFS fun)
+ Just fcode -> return $ do
+ args <- sequence args_code
+ code (fcode args)
+
+stmtMacros :: UniqFM ([CmmExpr] -> Code)
+stmtMacros = listToUFM [
+ ( FSLIT("CCS_ALLOC"), \[words,ccs] -> profAlloc words ccs ),
+ ( FSLIT("CLOSE_NURSERY"), \[] -> emitCloseNursery ),
+ ( FSLIT("ENTER_CCS_PAP_CL"), \[e] -> enterCostCentrePAP e ),
+ ( FSLIT("ENTER_CCS_THUNK"), \[e] -> enterCostCentreThunk e ),
+ ( FSLIT("HP_CHK_GEN"), \[words,liveness,reentry] ->
+ hpChkGen words liveness reentry ),
+ ( FSLIT("HP_CHK_NP_ASSIGN_SP0"), \[e,f] -> hpChkNodePointsAssignSp0 e f ),
+ ( FSLIT("LOAD_THREAD_STATE"), \[] -> emitLoadThreadState ),
+ ( FSLIT("LDV_ENTER"), \[e] -> ldvEnter e ),
+ ( FSLIT("LDV_RECORD_CREATE"), \[e] -> ldvRecordCreate e ),
+ ( FSLIT("OPEN_NURSERY"), \[] -> emitOpenNursery ),
+ ( FSLIT("PUSH_UPD_FRAME"), \[sp,e] -> emitPushUpdateFrame sp e ),
+ ( FSLIT("SAVE_THREAD_STATE"), \[] -> emitSaveThreadState ),
+ ( FSLIT("SET_HDR"), \[ptr,info,ccs] ->
+ emitSetDynHdr ptr info ccs ),
+ ( FSLIT("STK_CHK_GEN"), \[words,liveness,reentry] ->
+ stkChkGen words liveness reentry ),
+ ( FSLIT("STK_CHK_NP"), \[e] -> stkChkNodePoints e ),
+ ( FSLIT("TICK_ALLOC_PRIM"), \[hdr,goods,slop] ->
+ tickyAllocPrim hdr goods slop ),
+ ( FSLIT("TICK_ALLOC_PAP"), \[goods,slop] ->
+ tickyAllocPAP goods slop ),
+ ( FSLIT("TICK_ALLOC_UP_THK"), \[goods,slop] ->
+ tickyAllocThunk goods slop ),
+ ( FSLIT("UPD_BH_UPDATABLE"), \[] -> emitBlackHoleCode False ),
+ ( FSLIT("UPD_BH_SINGLE_ENTRY"), \[] -> emitBlackHoleCode True ),
+
+ ( FSLIT("RET_P"), \[a] -> emitRetUT [(PtrArg,a)]),
+ ( FSLIT("RET_N"), \[a] -> emitRetUT [(NonPtrArg,a)]),
+ ( FSLIT("RET_PP"), \[a,b] -> emitRetUT [(PtrArg,a),(PtrArg,b)]),
+ ( FSLIT("RET_NN"), \[a,b] -> emitRetUT [(NonPtrArg,a),(NonPtrArg,b)]),
+ ( FSLIT("RET_NP"), \[a,b] -> emitRetUT [(NonPtrArg,a),(PtrArg,b)]),
+ ( FSLIT("RET_PPP"), \[a,b,c] -> emitRetUT [(PtrArg,a),(PtrArg,b),(PtrArg,c)]),
+ ( FSLIT("RET_NNP"), \[a,b,c] -> emitRetUT [(NonPtrArg,a),(NonPtrArg,b),(PtrArg,c)]),
+ ( FSLIT("RET_NNNP"), \[a,b,c,d] -> emitRetUT [(NonPtrArg,a),(NonPtrArg,b),(NonPtrArg,c),(PtrArg,d)]),
+ ( FSLIT("RET_NPNP"), \[a,b,c,d] -> emitRetUT [(NonPtrArg,a),(PtrArg,b),(NonPtrArg,c),(PtrArg,d)])
+
+ ]
+
+-- -----------------------------------------------------------------------------
+-- Our extended FCode monad.
+
+-- We add a mapping from names to CmmExpr, to support local variable names in
+-- the concrete C-- code. The unique supply of the underlying FCode monad
+-- is used to grab a new unique for each local variable.
+
+-- In C--, a local variable can be declared anywhere within a proc,
+-- and it scopes from the beginning of the proc to the end. Hence, we have
+-- to collect declarations as we parse the proc, and feed the environment
+-- back in circularly (to avoid a two-pass algorithm).
+
+type Decls = [(FastString,CmmExpr)]
+type Env = UniqFM CmmExpr
+
+newtype ExtFCode a = EC { unEC :: Env -> Decls -> FCode (Decls, a) }
+
+type ExtCode = ExtFCode ()
+
+returnExtFC a = EC $ \e s -> return (s, a)
+thenExtFC (EC m) k = EC $ \e s -> do (s',r) <- m e s; unEC (k r) e s'
+
+instance Monad ExtFCode where
+ (>>=) = thenExtFC
+ return = returnExtFC
+
+-- This function takes the variable decarations and imports and makes
+-- an environment, which is looped back into the computation. In this
+-- way, we can have embedded declarations that scope over the whole
+-- procedure, and imports that scope over the entire module.
+loopDecls :: ExtFCode a -> ExtFCode a
+loopDecls (EC fcode) =
+ EC $ \e s -> fixC (\ ~(decls,a) -> fcode (addListToUFM e decls) [])
+
+getEnv :: ExtFCode Env
+getEnv = EC $ \e s -> return (s, e)
+
+addVarDecl :: FastString -> CmmExpr -> ExtCode
+addVarDecl var expr = EC $ \e s -> return ((var,expr):s, ())
+
+newLocal :: MachRep -> FastString -> ExtCode
+newLocal ty name = do
+ u <- code newUnique
+ addVarDecl name (CmmReg (CmmLocal (LocalReg u ty)))
+
+-- Unknown names are treated as if they had been 'import'ed.
+-- This saves us a lot of bother in the RTS sources, at the expense of
+-- deferring some errors to link time.
+lookupName :: FastString -> ExtFCode CmmExpr
+lookupName name = do
+ env <- getEnv
+ return $
+ case lookupUFM env name of
+ Nothing -> CmmLit (CmmLabel (mkRtsCodeLabelFS name))
+ Just e -> e
+
+-- Lifting FCode computations into the ExtFCode monad:
+code :: FCode a -> ExtFCode a
+code fc = EC $ \e s -> do r <- fc; return (s, r)
+
+code2 :: (FCode (Decls,b) -> FCode ((Decls,b),c))
+ -> ExtFCode b -> ExtFCode c
+code2 f (EC ec) = EC $ \e s -> do ((s',b),c) <- f (ec e s); return (s',c)
+
+nopEC = code nopC
+stmtEC stmt = code (stmtC stmt)
+stmtsEC stmts = code (stmtsC stmts)
+getCgStmtsEC = code2 getCgStmts'
+
+forkLabelledCodeEC ec = do
+ stmts <- getCgStmtsEC ec
+ code (forkCgStmts stmts)
+
+retInfo name size live_bits cl_type vector = do
+ let liveness = smallLiveness (fromIntegral size) (fromIntegral live_bits)
+ info_lbl = mkRtsRetInfoLabelFS name
+ (info1,info2) = mkRetInfoTable info_lbl liveness NoC_SRT
+ (fromIntegral cl_type) vector
+ return (info_lbl, info1, info2)
+
+stdInfo name ptrs nptrs srt_bitmap cl_type desc_str ty_str =
+ basicInfo name (packHalfWordsCLit ptrs nptrs)
+ srt_bitmap cl_type desc_str ty_str
+
+basicInfo name layout srt_bitmap cl_type desc_str ty_str = do
+ lit1 <- if opt_SccProfilingOn
+ then code $ mkStringCLit desc_str
+ else return (mkIntCLit 0)
+ lit2 <- if opt_SccProfilingOn
+ then code $ mkStringCLit ty_str
+ else return (mkIntCLit 0)
+ let info1 = mkStdInfoTable lit1 lit2 (fromIntegral cl_type)
+ (fromIntegral srt_bitmap)
+ layout
+ return (mkRtsInfoLabelFS name, info1, [])
+
+funInfo name ptrs nptrs cl_type desc_str ty_str fun_type = do
+ (label,info1,_) <- stdInfo name ptrs nptrs 0{-srt_bitmap-}
+ cl_type desc_str ty_str
+ let info2 = mkFunGenInfoExtraBits (fromIntegral fun_type) 0 zero zero zero
+ -- we leave most of the fields zero here. This is only used
+ -- to generate the BCO info table in the RTS at the moment.
+ return (label,info1,info2)
+ where
+ zero = mkIntCLit 0
+
+
+staticClosure :: FastString -> FastString -> [CmmLit] -> ExtCode
+staticClosure cl_label info payload
+ = code $ emitDataLits (mkRtsDataLabelFS cl_label) lits
+ where lits = mkStaticClosure (mkRtsInfoLabelFS info) dontCareCCS payload [] [] []
+
+foreignCall
+ :: String
+ -> [ExtFCode (CmmReg,MachHint)]
+ -> ExtFCode CmmExpr
+ -> [ExtFCode (CmmExpr,MachHint)]
+ -> Maybe [GlobalReg] -> P ExtCode
+foreignCall "C" results_code expr_code args_code vols
+ = return $ do
+ results <- sequence results_code
+ expr <- expr_code
+ args <- sequence args_code
+ code (emitForeignCall' PlayRisky results
+ (CmmForeignCall expr CCallConv) args vols)
+foreignCall conv _ _ _ _
+ = fail ("unknown calling convention: " ++ conv)
+
+doStore :: MachRep -> ExtFCode CmmExpr -> ExtFCode CmmExpr -> ExtCode
+doStore rep addr_code val_code
+ = do addr <- addr_code
+ val <- val_code
+ -- if the specified store type does not match the type of the expr
+ -- on the rhs, then we insert a coercion that will cause the type
+ -- mismatch to be flagged by cmm-lint. If we don't do this, then
+ -- the store will happen at the wrong type, and the error will not
+ -- be noticed.
+ let coerce_val
+ | cmmExprRep val /= rep = CmmMachOp (MO_U_Conv rep rep) [val]
+ | otherwise = val
+ stmtEC (CmmStore addr coerce_val)
+
+-- Return an unboxed tuple.
+emitRetUT :: [(CgRep,CmmExpr)] -> Code
+emitRetUT args = do
+ tickyUnboxedTupleReturn (length args) -- TICK
+ (sp, stmts) <- pushUnboxedTuple 0 args
+ emitStmts stmts
+ when (sp /= 0) $ stmtC (CmmAssign spReg (cmmRegOffW spReg (-sp)))
+ stmtC (CmmJump (entryCode (CmmLoad (cmmRegOffW spReg sp) wordRep)) [])
+
+-- -----------------------------------------------------------------------------
+-- If-then-else and boolean expressions
+
+data BoolExpr
+ = BoolExpr `BoolAnd` BoolExpr
+ | BoolExpr `BoolOr` BoolExpr
+ | BoolNot BoolExpr
+ | BoolTest CmmExpr
+
+-- ToDo: smart constructors which simplify the boolean expression.
+
+ifThenElse cond then_part else_part = do
+ then_id <- code newLabelC
+ join_id <- code newLabelC
+ c <- cond
+ emitCond c then_id
+ else_part
+ stmtEC (CmmBranch join_id)
+ code (labelC then_id)
+ then_part
+ -- fall through to join
+ code (labelC join_id)
+
+-- 'emitCond cond true_id' emits code to test whether the cond is true,
+-- branching to true_id if so, and falling through otherwise.
+emitCond (BoolTest e) then_id = do
+ stmtEC (CmmCondBranch e then_id)
+emitCond (BoolNot (BoolTest (CmmMachOp op args))) then_id
+ | Just op' <- maybeInvertComparison op
+ = emitCond (BoolTest (CmmMachOp op' args)) then_id
+emitCond (BoolNot e) then_id = do
+ else_id <- code newLabelC
+ emitCond e else_id
+ stmtEC (CmmBranch then_id)
+ code (labelC else_id)
+emitCond (e1 `BoolOr` e2) then_id = do
+ emitCond e1 then_id
+ emitCond e2 then_id
+emitCond (e1 `BoolAnd` e2) then_id = do
+ -- we'd like to invert one of the conditionals here to avoid an
+ -- extra branch instruction, but we can't use maybeInvertComparison
+ -- here because we can't look too closely at the expression since
+ -- we're in a loop.
+ and_id <- code newLabelC
+ else_id <- code newLabelC
+ emitCond e1 and_id
+ stmtEC (CmmBranch else_id)
+ code (labelC and_id)
+ emitCond e2 then_id
+ code (labelC else_id)
+
+
+-- -----------------------------------------------------------------------------
+-- Table jumps
+
+-- We use a simplified form of C-- switch statements for now. A
+-- switch statement always compiles to a table jump. Each arm can
+-- specify a list of values (not ranges), and there can be a single
+-- default branch. The range of the table is given either by the
+-- optional range on the switch (eg. switch [0..7] {...}), or by
+-- the minimum/maximum values from the branches.
+
+doSwitch :: Maybe (Int,Int) -> ExtFCode CmmExpr -> [([Int],ExtCode)]
+ -> Maybe ExtCode -> ExtCode
+doSwitch mb_range scrut arms deflt
+ = do
+ -- Compile code for the default branch
+ dflt_entry <-
+ case deflt of
+ Nothing -> return Nothing
+ Just e -> do b <- forkLabelledCodeEC e; return (Just b)
+
+ -- Compile each case branch
+ table_entries <- mapM emitArm arms
+
+ -- Construct the table
+ let
+ all_entries = concat table_entries
+ ixs = map fst all_entries
+ (min,max)
+ | Just (l,u) <- mb_range = (l,u)
+ | otherwise = (minimum ixs, maximum ixs)
+
+ entries = elems (accumArray (\_ a -> Just a) dflt_entry (min,max)
+ all_entries)
+ expr <- scrut
+ -- ToDo: check for out of range and jump to default if necessary
+ stmtEC (CmmSwitch expr entries)
+ where
+ emitArm :: ([Int],ExtCode) -> ExtFCode [(Int,BlockId)]
+ emitArm (ints,code) = do
+ blockid <- forkLabelledCodeEC code
+ return [ (i,blockid) | i <- ints ]
+
+
+-- -----------------------------------------------------------------------------
+-- Putting it all together
+
+-- The initial environment: we define some constants that the compiler
+-- knows about here.
+initEnv :: Env
+initEnv = listToUFM [
+ ( FSLIT("SIZEOF_StgHeader"),
+ CmmLit (CmmInt (fromIntegral (fixedHdrSize * wORD_SIZE)) wordRep) ),
+ ( FSLIT("SIZEOF_StgInfoTable"),
+ CmmLit (CmmInt (fromIntegral stdInfoTableSizeB) wordRep) )
+ ]
+
+parseCmmFile :: DynFlags -> HomeModules -> FilePath -> IO (Maybe Cmm)
+parseCmmFile dflags hmods filename = do
+ showPass dflags "ParseCmm"
+ buf <- hGetStringBuffer filename
+ let
+ init_loc = mkSrcLoc (mkFastString filename) 1 0
+ init_state = (mkPState buf init_loc dflags) { lex_state = [0] }
+ -- reset the lex_state: the Lexer monad leaves some stuff
+ -- in there we don't want.
+ case unP cmmParse init_state of
+ PFailed span err -> do printError span err; return Nothing
+ POk _ code -> do
+ cmm <- initC dflags hmods no_module (getCmm (unEC code initEnv [] >> return ()))
+ dumpIfSet_dyn dflags Opt_D_dump_cmm "Cmm" (pprCmms [cmm])
+ return (Just cmm)
+ where
+ no_module = panic "parseCmmFile: no module"
+}
diff --git a/compiler/cmm/CmmUtils.hs b/compiler/cmm/CmmUtils.hs
new file mode 100644
index 0000000000..a04935b279
--- /dev/null
+++ b/compiler/cmm/CmmUtils.hs
@@ -0,0 +1,177 @@
+-----------------------------------------------------------------------------
+--
+-- Cmm utilities.
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+module CmmUtils(
+ CmmStmts, noStmts, oneStmt, mkStmts, plusStmts, stmtList,
+ isNopStmt,
+
+ isTrivialCmmExpr, hasNoGlobalRegs,
+
+ cmmRegOff, cmmLabelOff, cmmOffset, cmmOffsetLit, cmmIndex,
+ cmmOffsetExpr, cmmIndexExpr, cmmLoadIndex,
+
+ mkIntCLit, zeroCLit,
+
+ mkLblExpr,
+ ) where
+
+#include "HsVersions.h"
+
+import CLabel ( CLabel )
+import Cmm
+import MachOp
+import OrdList
+import Outputable
+
+---------------------------------------------------
+--
+-- CmmStmts
+--
+---------------------------------------------------
+
+type CmmStmts = OrdList CmmStmt
+
+noStmts :: CmmStmts
+noStmts = nilOL
+
+oneStmt :: CmmStmt -> CmmStmts
+oneStmt = unitOL
+
+mkStmts :: [CmmStmt] -> CmmStmts
+mkStmts = toOL
+
+plusStmts :: CmmStmts -> CmmStmts -> CmmStmts
+plusStmts = appOL
+
+stmtList :: CmmStmts -> [CmmStmt]
+stmtList = fromOL
+
+
+---------------------------------------------------
+--
+-- CmmStmt
+--
+---------------------------------------------------
+
+isNopStmt :: CmmStmt -> Bool
+-- If isNopStmt returns True, the stmt is definitely a no-op;
+-- but it might be a no-op even if isNopStmt returns False
+isNopStmt CmmNop = True
+isNopStmt (CmmAssign r e) = cheapEqReg r e
+isNopStmt (CmmStore e1 (CmmLoad e2 _)) = cheapEqExpr e1 e2
+isNopStmt s = False
+
+cheapEqExpr :: CmmExpr -> CmmExpr -> Bool
+cheapEqExpr (CmmReg r) e = cheapEqReg r e
+cheapEqExpr (CmmRegOff r 0) e = cheapEqReg r e
+cheapEqExpr (CmmRegOff r n) (CmmRegOff r' n') = r==r' && n==n'
+cheapEqExpr e1 e2 = False
+
+cheapEqReg :: CmmReg -> CmmExpr -> Bool
+cheapEqReg r (CmmReg r') = r==r'
+cheapEqReg r (CmmRegOff r' 0) = r==r'
+cheapEqReg r e = False
+
+---------------------------------------------------
+--
+-- CmmExpr
+--
+---------------------------------------------------
+
+isTrivialCmmExpr :: CmmExpr -> Bool
+isTrivialCmmExpr (CmmLoad _ _) = False
+isTrivialCmmExpr (CmmMachOp _ _) = False
+isTrivialCmmExpr (CmmLit _) = True
+isTrivialCmmExpr (CmmReg _) = True
+isTrivialCmmExpr (CmmRegOff _ _) = True
+
+hasNoGlobalRegs :: CmmExpr -> Bool
+hasNoGlobalRegs (CmmLoad e _) = hasNoGlobalRegs e
+hasNoGlobalRegs (CmmMachOp _ es) = all hasNoGlobalRegs es
+hasNoGlobalRegs (CmmLit _) = True
+hasNoGlobalRegs (CmmReg (CmmLocal _)) = True
+hasNoGlobalRegs (CmmRegOff (CmmLocal _) _) = True
+hasNoGlobalRegs _ = False
+
+---------------------------------------------------
+--
+-- Expr Construction helpers
+--
+---------------------------------------------------
+
+cmmOffsetExpr :: CmmExpr -> CmmExpr -> CmmExpr
+-- assumes base and offset have the same MachRep
+cmmOffsetExpr e (CmmLit (CmmInt n _)) = cmmOffset e (fromInteger n)
+cmmOffsetExpr e byte_off = CmmMachOp (MO_Add (cmmExprRep e)) [e, byte_off]
+
+-- NB. Do *not* inspect the value of the offset in these smart constructors!!!
+--
+-- because the offset is sometimes involved in a loop in the code generator
+-- (we don't know the real Hp offset until we've generated code for the entire
+-- basic block, for example). So we cannot eliminate zero offsets at this
+-- stage; they're eliminated later instead (either during printing or
+-- a later optimisation step on Cmm).
+--
+cmmOffset :: CmmExpr -> Int -> CmmExpr
+cmmOffset (CmmReg reg) byte_off = cmmRegOff reg byte_off
+cmmOffset (CmmRegOff reg m) byte_off = cmmRegOff reg (m+byte_off)
+cmmOffset (CmmLit lit) byte_off = CmmLit (cmmOffsetLit lit byte_off)
+cmmOffset (CmmMachOp (MO_Add rep) [expr, CmmLit (CmmInt byte_off1 _rep)]) byte_off2
+ = CmmMachOp (MO_Add rep)
+ [expr, CmmLit (CmmInt (byte_off1 + toInteger byte_off2) rep)]
+cmmOffset expr byte_off
+ = CmmMachOp (MO_Add rep) [expr, CmmLit (CmmInt (toInteger byte_off) rep)]
+ where
+ rep = cmmExprRep expr
+
+-- Smart constructor for CmmRegOff. Same caveats as cmmOffset above.
+cmmRegOff :: CmmReg -> Int -> CmmExpr
+cmmRegOff reg byte_off = CmmRegOff reg byte_off
+
+cmmOffsetLit :: CmmLit -> Int -> CmmLit
+cmmOffsetLit (CmmLabel l) byte_off = cmmLabelOff l byte_off
+cmmOffsetLit (CmmLabelOff l m) byte_off = cmmLabelOff l (m+byte_off)
+cmmOffsetLit (CmmInt m rep) byte_off = CmmInt (m + fromIntegral byte_off) rep
+cmmOffsetLit other byte_off = pprPanic "cmmOffsetLit" (ppr byte_off)
+
+cmmLabelOff :: CLabel -> Int -> CmmLit
+-- Smart constructor for CmmLabelOff
+cmmLabelOff lbl 0 = CmmLabel lbl
+cmmLabelOff lbl byte_off = CmmLabelOff lbl byte_off
+
+-- | Useful for creating an index into an array, with a staticaly known offset.
+cmmIndex :: MachRep -> CmmExpr -> Int -> CmmExpr
+cmmIndex rep base idx = cmmOffset base (idx * machRepByteWidth rep)
+
+-- | Useful for creating an index into an array, with an unknown offset.
+cmmIndexExpr :: MachRep -> CmmExpr -> CmmExpr -> CmmExpr
+cmmIndexExpr rep base (CmmLit (CmmInt n _)) = cmmIndex rep base (fromInteger n)
+cmmIndexExpr rep base idx =
+ cmmOffsetExpr base byte_off
+ where
+ idx_rep = cmmExprRep idx
+ byte_off = CmmMachOp (MO_Shl idx_rep) [
+ idx, CmmLit (mkIntCLit (machRepLogWidth rep))]
+
+cmmLoadIndex :: MachRep -> CmmExpr -> Int -> CmmExpr
+cmmLoadIndex rep expr ix = CmmLoad (cmmIndex rep expr ix) rep
+
+---------------------------------------------------
+--
+-- Literal construction functions
+--
+---------------------------------------------------
+
+mkIntCLit :: Int -> CmmLit
+mkIntCLit i = CmmInt (toInteger i) wordRep
+
+zeroCLit :: CmmLit
+zeroCLit = CmmInt 0 wordRep
+
+mkLblExpr :: CLabel -> CmmExpr
+mkLblExpr lbl = CmmLit (CmmLabel lbl)
diff --git a/compiler/cmm/MachOp.hs b/compiler/cmm/MachOp.hs
new file mode 100644
index 0000000000..5bbff6de78
--- /dev/null
+++ b/compiler/cmm/MachOp.hs
@@ -0,0 +1,652 @@
+-----------------------------------------------------------------------------
+--
+-- (c) The University of Glasgow 2002-2004
+--
+-- Low-level machine operations, used in the Cmm datatype.
+--
+-----------------------------------------------------------------------------
+
+module MachOp (
+ MachRep(..),
+ machRepBitWidth,
+ machRepByteWidth,
+ machRepLogWidth,
+ isFloatingRep,
+
+ MachHint(..),
+
+ MachOp(..),
+ pprMachOp,
+ isCommutableMachOp,
+ isAssociativeMachOp,
+ isComparisonMachOp,
+ resultRepOfMachOp,
+ machOpArgReps,
+ maybeInvertComparison,
+
+ CallishMachOp(..),
+ pprCallishMachOp,
+
+ wordRep,
+ halfWordRep,
+ cIntRep, cLongRep,
+
+ mo_wordAdd,
+ mo_wordSub,
+ mo_wordEq,
+ mo_wordNe,
+ mo_wordMul,
+ mo_wordSQuot,
+ mo_wordSRem,
+ mo_wordSNeg,
+ mo_wordUQuot,
+ mo_wordURem,
+
+ mo_wordSGe,
+ mo_wordSLe,
+ mo_wordSGt,
+ mo_wordSLt,
+
+ mo_wordUGe,
+ mo_wordULe,
+ mo_wordUGt,
+ mo_wordULt,
+
+ mo_wordAnd,
+ mo_wordOr,
+ mo_wordXor,
+ mo_wordNot,
+ mo_wordShl,
+ mo_wordSShr,
+ mo_wordUShr,
+
+ mo_u_8To32,
+ mo_s_8To32,
+ mo_u_16To32,
+ mo_s_16To32,
+
+ mo_u_8ToWord,
+ mo_s_8ToWord,
+ mo_u_16ToWord,
+ mo_s_16ToWord,
+ mo_u_32ToWord,
+ mo_s_32ToWord,
+
+ mo_32To8,
+ mo_32To16,
+ mo_WordTo8,
+ mo_WordTo16,
+ mo_WordTo32,
+ ) where
+
+#include "HsVersions.h"
+
+import Constants
+import Outputable
+
+-- -----------------------------------------------------------------------------
+-- MachRep
+
+{- |
+A MachRep is the "representation" of a value in Cmm. It is used for
+resource allocation: eg. which kind of register a value should be
+stored in.
+
+The primary requirement is that there exists a function
+
+ cmmExprRep :: CmmExpr -> MachRep
+
+This means that:
+
+ - a register has an implicit MachRep
+ - a literal has an implicit MachRep
+ - an operation (MachOp) has an implicit result MachRep
+
+It also means that we can check that the arguments to a MachOp have
+the correct MachRep, i.e. we can do a kind of lint-style type checking
+on Cmm.
+-}
+
+data MachRep
+ = I8
+ | I16
+ | I32
+ | I64
+ | I128
+ | F32
+ | F64
+ | F80 -- extended double-precision, used in x86 native codegen only.
+ deriving (Eq, Ord, Show)
+
+mrStr I8 = SLIT("I8")
+mrStr I16 = SLIT("I16")
+mrStr I32 = SLIT("I32")
+mrStr I64 = SLIT("I64")
+mrStr I128 = SLIT("I128")
+mrStr F32 = SLIT("F32")
+mrStr F64 = SLIT("F64")
+mrStr F80 = SLIT("F80")
+
+instance Outputable MachRep where
+ ppr rep = ptext (mrStr rep)
+
+{-
+Implementation notes:
+
+It might suffice to keep just a width, without distinguishing between
+floating and integer types. However, keeping the distinction will
+help the native code generator to assign registers more easily.
+-}
+
+{-
+Should a MachRep include a signed vs. unsigned distinction?
+
+This is very much like a "hint" in C-- terminology: it isn't necessary
+in order to generate correct code, but it might be useful in that the
+compiler can generate better code if it has access to higher-level
+hints about data. This is important at call boundaries, because the
+definition of a function is not visible at all of its call sites, so
+the compiler cannot infer the hints.
+
+Here in Cmm, we're taking a slightly different approach. We include
+the int vs. float hint in the MachRep, because (a) the majority of
+platforms have a strong distinction between float and int registers,
+and (b) we don't want to do any heavyweight hint-inference in the
+native code backend in order to get good code. We're treating the
+hint more like a type: our Cmm is always completely consistent with
+respect to hints. All coercions between float and int are explicit.
+
+What about the signed vs. unsigned hint? This information might be
+useful if we want to keep sub-word-sized values in word-size
+registers, which we must do if we only have word-sized registers.
+
+On such a system, there are two straightforward conventions for
+representing sub-word-sized values:
+
+(a) Leave the upper bits undefined. Comparison operations must
+ sign- or zero-extend both operands before comparing them,
+ depending on whether the comparison is signed or unsigned.
+
+(b) Always keep the values sign- or zero-extended as appropriate.
+ Arithmetic operations must narrow the result to the appropriate
+ size.
+
+A clever compiler might not use either (a) or (b) exclusively, instead
+it would attempt to minimize the coercions by analysis: the same kind
+of analysis that propagates hints around. In Cmm we don't want to
+have to do this, so we plump for having richer types and keeping the
+type information consistent.
+
+If signed/unsigned hints are missing from MachRep, then the only
+choice we have is (a), because we don't know whether the result of an
+operation should be sign- or zero-extended.
+
+Many architectures have extending load operations, which work well
+with (b). To make use of them with (a), you need to know whether the
+value is going to be sign- or zero-extended by an enclosing comparison
+(for example), which involves knowing above the context. This is
+doable but more complex.
+
+Further complicating the issue is foreign calls: a foreign calling
+convention can specify that signed 8-bit quantities are passed as
+sign-extended 32 bit quantities, for example (this is the case on the
+PowerPC). So we *do* need sign information on foreign call arguments.
+
+Pros for adding signed vs. unsigned to MachRep:
+
+ - It would let us use convention (b) above, and get easier
+ code generation for extending loads.
+
+ - Less information required on foreign calls.
+
+ - MachOp type would be simpler
+
+Cons:
+
+ - More complexity
+
+ - What is the MachRep for a VanillaReg? Currently it is
+ always wordRep, but now we have to decide whether it is
+ signed or unsigned. The same VanillaReg can thus have
+ different MachReps in different parts of the program.
+
+ - Extra coercions cluttering up expressions.
+
+Currently for GHC, the foreign call point is moot, because we do our
+own promotion of sub-word-sized values to word-sized values. The Int8
+type is represnted by an Int# which is kept sign-extended at all times
+(this is slightly naughty, because we're making assumptions about the
+C calling convention rather early on in the compiler). However, given
+this, the cons outweigh the pros.
+
+-}
+
+
+machRepBitWidth :: MachRep -> Int
+machRepBitWidth I8 = 8
+machRepBitWidth I16 = 16
+machRepBitWidth I32 = 32
+machRepBitWidth I64 = 64
+machRepBitWidth I128 = 128
+machRepBitWidth F32 = 32
+machRepBitWidth F64 = 64
+machRepBitWidth F80 = 80
+
+machRepByteWidth :: MachRep -> Int
+machRepByteWidth I8 = 1
+machRepByteWidth I16 = 2
+machRepByteWidth I32 = 4
+machRepByteWidth I64 = 8
+machRepByteWidth I128 = 16
+machRepByteWidth F32 = 4
+machRepByteWidth F64 = 8
+machRepByteWidth F80 = 10
+
+-- log_2 of the width in bytes, useful for generating shifts.
+machRepLogWidth :: MachRep -> Int
+machRepLogWidth I8 = 0
+machRepLogWidth I16 = 1
+machRepLogWidth I32 = 2
+machRepLogWidth I64 = 3
+machRepLogWidth I128 = 4
+machRepLogWidth F32 = 2
+machRepLogWidth F64 = 3
+machRepLogWidth F80 = panic "machRepLogWidth: F80"
+
+isFloatingRep :: MachRep -> Bool
+isFloatingRep F32 = True
+isFloatingRep F64 = True
+isFloatingRep F80 = True
+isFloatingRep _ = False
+
+-- -----------------------------------------------------------------------------
+-- Hints
+
+{-
+A hint gives a little more information about a data value. Hints are
+used on the arguments to a foreign call, where the code generator needs
+to know some extra information on top of the MachRep of each argument in
+order to generate a correct call.
+-}
+
+data MachHint
+ = NoHint
+ | PtrHint
+ | SignedHint
+ | FloatHint
+ deriving Eq
+
+mhStr NoHint = SLIT("NoHint")
+mhStr PtrHint = SLIT("PtrHint")
+mhStr SignedHint = SLIT("SignedHint")
+mhStr FloatHint = SLIT("FloatHint")
+
+instance Outputable MachHint where
+ ppr hint = ptext (mhStr hint)
+
+-- -----------------------------------------------------------------------------
+-- MachOp
+
+{- |
+Machine-level primops; ones which we can reasonably delegate to the
+native code generators to handle. Basically contains C's primops
+and no others.
+
+Nomenclature: all ops indicate width and signedness, where
+appropriate. Widths: 8\/16\/32\/64 means the given size, obviously.
+Nat means the operation works on STG word sized objects.
+Signedness: S means signed, U means unsigned. For operations where
+signedness is irrelevant or makes no difference (for example
+integer add), the signedness component is omitted.
+
+An exception: NatP is a ptr-typed native word. From the point of
+view of the native code generators this distinction is irrelevant,
+but the C code generator sometimes needs this info to emit the
+right casts.
+-}
+
+data MachOp
+
+ -- Integer operations
+ = MO_Add MachRep
+ | MO_Sub MachRep
+ | MO_Eq MachRep
+ | MO_Ne MachRep
+ | MO_Mul MachRep -- low word of multiply
+ | MO_S_MulMayOflo MachRep -- nonzero if signed multiply overflows
+ | MO_S_Quot MachRep -- signed / (same semantics as IntQuotOp)
+ | MO_S_Rem MachRep -- signed % (same semantics as IntRemOp)
+ | MO_S_Neg MachRep -- unary -
+ | MO_U_MulMayOflo MachRep -- nonzero if unsigned multiply overflows
+ | MO_U_Quot MachRep -- unsigned / (same semantics as WordQuotOp)
+ | MO_U_Rem MachRep -- unsigned % (same semantics as WordRemOp)
+
+ -- Signed comparisons (floating-point comparisons also use these)
+ | MO_S_Ge MachRep
+ | MO_S_Le MachRep
+ | MO_S_Gt MachRep
+ | MO_S_Lt MachRep
+
+ -- Unsigned comparisons
+ | MO_U_Ge MachRep
+ | MO_U_Le MachRep
+ | MO_U_Gt MachRep
+ | MO_U_Lt MachRep
+
+ -- Bitwise operations. Not all of these may be supported at all sizes,
+ -- and only integral MachReps are valid.
+ | MO_And MachRep
+ | MO_Or MachRep
+ | MO_Xor MachRep
+ | MO_Not MachRep
+ | MO_Shl MachRep
+ | MO_U_Shr MachRep -- unsigned shift right
+ | MO_S_Shr MachRep -- signed shift right
+
+ -- Conversions. Some of these will be NOPs.
+ -- Floating-point conversions use the signed variant.
+ | MO_S_Conv MachRep{-from-} MachRep{-to-} -- signed conversion
+ | MO_U_Conv MachRep{-from-} MachRep{-to-} -- unsigned conversion
+
+ deriving (Eq, Show)
+
+pprMachOp :: MachOp -> SDoc
+pprMachOp mo = text (show mo)
+
+
+-- These MachOps tend to be implemented by foreign calls in some backends,
+-- so we separate them out. In Cmm, these can only occur in a
+-- statement position, in contrast to an ordinary MachOp which can occur
+-- anywhere in an expression.
+data CallishMachOp
+ = MO_F64_Pwr
+ | MO_F64_Sin
+ | MO_F64_Cos
+ | MO_F64_Tan
+ | MO_F64_Sinh
+ | MO_F64_Cosh
+ | MO_F64_Tanh
+ | MO_F64_Asin
+ | MO_F64_Acos
+ | MO_F64_Atan
+ | MO_F64_Log
+ | MO_F64_Exp
+ | MO_F64_Sqrt
+ | MO_F32_Pwr
+ | MO_F32_Sin
+ | MO_F32_Cos
+ | MO_F32_Tan
+ | MO_F32_Sinh
+ | MO_F32_Cosh
+ | MO_F32_Tanh
+ | MO_F32_Asin
+ | MO_F32_Acos
+ | MO_F32_Atan
+ | MO_F32_Log
+ | MO_F32_Exp
+ | MO_F32_Sqrt
+ deriving (Eq, Show)
+
+pprCallishMachOp :: CallishMachOp -> SDoc
+pprCallishMachOp mo = text (show mo)
+
+-- -----------------------------------------------------------------------------
+-- Some common MachReps
+
+-- A 'wordRep' is a machine word on the target architecture
+-- Specifically, it is the size of an Int#, Word#, Addr#
+-- and the unit of allocation on the stack and the heap
+-- Any pointer is also guaranteed to be a wordRep.
+
+wordRep | wORD_SIZE == 4 = I32
+ | wORD_SIZE == 8 = I64
+ | otherwise = panic "MachOp.wordRep: Unknown word size"
+
+halfWordRep | wORD_SIZE == 4 = I16
+ | wORD_SIZE == 8 = I32
+ | otherwise = panic "MachOp.halfWordRep: Unknown word size"
+
+mo_wordAdd = MO_Add wordRep
+mo_wordSub = MO_Sub wordRep
+mo_wordEq = MO_Eq wordRep
+mo_wordNe = MO_Ne wordRep
+mo_wordMul = MO_Mul wordRep
+mo_wordSQuot = MO_S_Quot wordRep
+mo_wordSRem = MO_S_Rem wordRep
+mo_wordSNeg = MO_S_Neg wordRep
+mo_wordUQuot = MO_U_Quot wordRep
+mo_wordURem = MO_U_Rem wordRep
+
+mo_wordSGe = MO_S_Ge wordRep
+mo_wordSLe = MO_S_Le wordRep
+mo_wordSGt = MO_S_Gt wordRep
+mo_wordSLt = MO_S_Lt wordRep
+
+mo_wordUGe = MO_U_Ge wordRep
+mo_wordULe = MO_U_Le wordRep
+mo_wordUGt = MO_U_Gt wordRep
+mo_wordULt = MO_U_Lt wordRep
+
+mo_wordAnd = MO_And wordRep
+mo_wordOr = MO_Or wordRep
+mo_wordXor = MO_Xor wordRep
+mo_wordNot = MO_Not wordRep
+mo_wordShl = MO_Shl wordRep
+mo_wordSShr = MO_S_Shr wordRep
+mo_wordUShr = MO_U_Shr wordRep
+
+mo_u_8To32 = MO_U_Conv I8 I32
+mo_s_8To32 = MO_S_Conv I8 I32
+mo_u_16To32 = MO_U_Conv I16 I32
+mo_s_16To32 = MO_S_Conv I16 I32
+
+mo_u_8ToWord = MO_U_Conv I8 wordRep
+mo_s_8ToWord = MO_S_Conv I8 wordRep
+mo_u_16ToWord = MO_U_Conv I16 wordRep
+mo_s_16ToWord = MO_S_Conv I16 wordRep
+mo_s_32ToWord = MO_S_Conv I32 wordRep
+mo_u_32ToWord = MO_U_Conv I32 wordRep
+
+mo_WordTo8 = MO_U_Conv wordRep I8
+mo_WordTo16 = MO_U_Conv wordRep I16
+mo_WordTo32 = MO_U_Conv wordRep I32
+
+mo_32To8 = MO_U_Conv I32 I8
+mo_32To16 = MO_U_Conv I32 I16
+
+-- cIntRep is the MachRep for a C-language 'int'
+#if SIZEOF_INT == 4
+cIntRep = I32
+#elif SIZEOF_INT == 8
+cIntRep = I64
+#endif
+
+#if SIZEOF_LONG == 4
+cLongRep = I32
+#elif SIZEOF_LONG == 8
+cLongRep = I64
+#endif
+
+-- ----------------------------------------------------------------------------
+-- isCommutableMachOp
+
+{- |
+Returns 'True' if the MachOp has commutable arguments. This is used
+in the platform-independent Cmm optimisations.
+
+If in doubt, return 'False'. This generates worse code on the
+native routes, but is otherwise harmless.
+-}
+isCommutableMachOp :: MachOp -> Bool
+isCommutableMachOp mop =
+ case mop of
+ MO_Add _ -> True
+ MO_Eq _ -> True
+ MO_Ne _ -> True
+ MO_Mul _ -> True
+ MO_S_MulMayOflo _ -> True
+ MO_U_MulMayOflo _ -> True
+ MO_And _ -> True
+ MO_Or _ -> True
+ MO_Xor _ -> True
+ _other -> False
+
+-- ----------------------------------------------------------------------------
+-- isAssociativeMachOp
+
+{- |
+Returns 'True' if the MachOp is associative (i.e. @(x+y)+z == x+(y+z)@)
+This is used in the platform-independent Cmm optimisations.
+
+If in doubt, return 'False'. This generates worse code on the
+native routes, but is otherwise harmless.
+-}
+isAssociativeMachOp :: MachOp -> Bool
+isAssociativeMachOp mop =
+ case mop of
+ MO_Add r -> not (isFloatingRep r)
+ MO_Mul r -> not (isFloatingRep r)
+ MO_And _ -> True
+ MO_Or _ -> True
+ MO_Xor _ -> True
+ _other -> False
+
+-- ----------------------------------------------------------------------------
+-- isComparisonMachOp
+
+{- |
+Returns 'True' if the MachOp is a comparison.
+
+If in doubt, return False. This generates worse code on the
+native routes, but is otherwise harmless.
+-}
+isComparisonMachOp :: MachOp -> Bool
+isComparisonMachOp mop =
+ case mop of
+ MO_Eq _ -> True
+ MO_Ne _ -> True
+ MO_S_Ge _ -> True
+ MO_S_Le _ -> True
+ MO_S_Gt _ -> True
+ MO_S_Lt _ -> True
+ MO_U_Ge _ -> True
+ MO_U_Le _ -> True
+ MO_U_Gt _ -> True
+ MO_U_Lt _ -> True
+ _other -> False
+
+-- -----------------------------------------------------------------------------
+-- Inverting conditions
+
+-- Sometimes it's useful to be able to invert the sense of a
+-- condition. Not all conditional tests are invertible: in
+-- particular, floating point conditionals cannot be inverted, because
+-- there exist floating-point values which return False for both senses
+-- of a condition (eg. !(NaN > NaN) && !(NaN /<= NaN)).
+
+maybeInvertComparison :: MachOp -> Maybe MachOp
+maybeInvertComparison op
+ = case op of
+ MO_Eq r | not (isFloatingRep r) -> Just (MO_Ne r)
+ MO_Ne r | not (isFloatingRep r) -> Just (MO_Eq r)
+ MO_U_Lt r | not (isFloatingRep r) -> Just (MO_U_Ge r)
+ MO_U_Gt r | not (isFloatingRep r) -> Just (MO_U_Le r)
+ MO_U_Le r | not (isFloatingRep r) -> Just (MO_U_Gt r)
+ MO_U_Ge r | not (isFloatingRep r) -> Just (MO_U_Lt r)
+ MO_S_Lt r | not (isFloatingRep r) -> Just (MO_S_Ge r)
+ MO_S_Gt r | not (isFloatingRep r) -> Just (MO_S_Le r)
+ MO_S_Le r | not (isFloatingRep r) -> Just (MO_S_Gt r)
+ MO_S_Ge r | not (isFloatingRep r) -> Just (MO_S_Lt r)
+ _other -> Nothing
+
+-- ----------------------------------------------------------------------------
+-- resultRepOfMachOp
+
+{- |
+Returns the MachRep of the result of a MachOp.
+-}
+resultRepOfMachOp :: MachOp -> MachRep
+resultRepOfMachOp mop =
+ case mop of
+ MO_Add r -> r
+ MO_Sub r -> r
+ MO_Eq r -> comparisonResultRep
+ MO_Ne r -> comparisonResultRep
+ MO_Mul r -> r
+ MO_S_MulMayOflo r -> r
+ MO_S_Quot r -> r
+ MO_S_Rem r -> r
+ MO_S_Neg r -> r
+ MO_U_MulMayOflo r -> r
+ MO_U_Quot r -> r
+ MO_U_Rem r -> r
+
+ MO_S_Ge r -> comparisonResultRep
+ MO_S_Le r -> comparisonResultRep
+ MO_S_Gt r -> comparisonResultRep
+ MO_S_Lt r -> comparisonResultRep
+
+ MO_U_Ge r -> comparisonResultRep
+ MO_U_Le r -> comparisonResultRep
+ MO_U_Gt r -> comparisonResultRep
+ MO_U_Lt r -> comparisonResultRep
+
+ MO_And r -> r
+ MO_Or r -> r
+ MO_Xor r -> r
+ MO_Not r -> r
+ MO_Shl r -> r
+ MO_U_Shr r -> r
+ MO_S_Shr r -> r
+
+ MO_S_Conv from to -> to
+ MO_U_Conv from to -> to
+
+
+comparisonResultRep = wordRep -- is it?
+
+
+-- -----------------------------------------------------------------------------
+-- machOpArgReps
+
+-- | This function is used for debugging only: we can check whether an
+-- application of a MachOp is "type-correct" by checking that the MachReps of
+-- its arguments are the same as the MachOp expects. This is used when
+-- linting a CmmExpr.
+
+machOpArgReps :: MachOp -> [MachRep]
+machOpArgReps op =
+ case op of
+ MO_Add r -> [r,r]
+ MO_Sub r -> [r,r]
+ MO_Eq r -> [r,r]
+ MO_Ne r -> [r,r]
+ MO_Mul r -> [r,r]
+ MO_S_MulMayOflo r -> [r,r]
+ MO_S_Quot r -> [r,r]
+ MO_S_Rem r -> [r,r]
+ MO_S_Neg r -> [r]
+ MO_U_MulMayOflo r -> [r,r]
+ MO_U_Quot r -> [r,r]
+ MO_U_Rem r -> [r,r]
+
+ MO_S_Ge r -> [r,r]
+ MO_S_Le r -> [r,r]
+ MO_S_Gt r -> [r,r]
+ MO_S_Lt r -> [r,r]
+
+ MO_U_Ge r -> [r,r]
+ MO_U_Le r -> [r,r]
+ MO_U_Gt r -> [r,r]
+ MO_U_Lt r -> [r,r]
+
+ MO_And r -> [r,r]
+ MO_Or r -> [r,r]
+ MO_Xor r -> [r,r]
+ MO_Not r -> [r]
+ MO_Shl r -> [r,wordRep]
+ MO_U_Shr r -> [r,wordRep]
+ MO_S_Shr r -> [r,wordRep]
+
+ MO_S_Conv from to -> [from]
+ MO_U_Conv from to -> [from]
diff --git a/compiler/cmm/PprC.hs b/compiler/cmm/PprC.hs
new file mode 100644
index 0000000000..a8d30668b7
--- /dev/null
+++ b/compiler/cmm/PprC.hs
@@ -0,0 +1,1028 @@
+-----------------------------------------------------------------------------
+--
+-- Pretty-printing of Cmm as C, suitable for feeding gcc
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+--
+-- Print Cmm as real C, for -fvia-C
+--
+-- This is simpler than the old PprAbsC, because Cmm is "macro-expanded"
+-- relative to the old AbstractC, and many oddities/decorations have
+-- disappeared from the data type.
+--
+
+-- ToDo: save/restore volatile registers around calls.
+
+module PprC (
+ writeCs,
+ pprStringInCStyle
+ ) where
+
+#include "HsVersions.h"
+
+-- Cmm stuff
+import Cmm
+import CLabel
+import MachOp
+import ForeignCall
+
+-- Utils
+import DynFlags ( DynFlags, DynFlag(..), dopt )
+import Unique ( getUnique )
+import UniqSet
+import FiniteMap
+import UniqFM ( eltsUFM )
+import FastString
+import Outputable
+import Constants
+import StaticFlags ( opt_Unregisterised )
+
+-- The rest
+import Data.List ( intersperse, groupBy )
+import Data.Bits ( shiftR )
+import Char ( ord, chr )
+import IO ( Handle )
+import DATA_BITS
+import Data.Word ( Word8 )
+
+#ifdef DEBUG
+import PprCmm () -- instances only
+-- import Debug.Trace
+#endif
+
+#if __GLASGOW_HASKELL__ >= 504
+import Data.Array.ST
+#endif
+import MONAD_ST
+
+-- --------------------------------------------------------------------------
+-- Top level
+
+pprCs :: DynFlags -> [Cmm] -> SDoc
+pprCs dflags cmms
+ = pprCode CStyle (vcat $ map (\c -> split_marker $$ pprC c) cmms)
+ where
+ split_marker
+ | dopt Opt_SplitObjs dflags = ptext SLIT("__STG_SPLIT_MARKER")
+ | otherwise = empty
+
+writeCs :: DynFlags -> Handle -> [Cmm] -> IO ()
+writeCs dflags handle cmms
+ = printForC handle (pprCs dflags cmms)
+
+-- --------------------------------------------------------------------------
+-- Now do some real work
+--
+-- for fun, we could call cmmToCmm over the tops...
+--
+
+pprC :: Cmm -> SDoc
+pprC (Cmm tops) = vcat $ intersperse (text "") $ map pprTop tops
+
+--
+-- top level procs
+--
+pprTop :: CmmTop -> SDoc
+pprTop (CmmProc info clbl _params blocks) =
+ (if not (null info)
+ then pprDataExterns info $$
+ pprWordArray (entryLblToInfoLbl clbl) info
+ else empty) $$
+ (case blocks of
+ [] -> empty
+ -- the first block doesn't get a label:
+ (BasicBlock _ stmts : rest) -> vcat [
+ text "",
+ extern_decls,
+ (if (externallyVisibleCLabel clbl)
+ then mkFN_ else mkIF_) (pprCLabel clbl) <+> lbrace,
+ nest 8 temp_decls,
+ nest 8 mkFB_,
+ nest 8 (vcat (map pprStmt stmts)) $$
+ vcat (map pprBBlock rest),
+ nest 8 mkFE_,
+ rbrace ]
+ )
+ where
+ (temp_decls, extern_decls) = pprTempAndExternDecls blocks
+
+
+-- Chunks of static data.
+
+-- We only handle (a) arrays of word-sized things and (b) strings.
+
+pprTop (CmmData _section _ds@[CmmDataLabel lbl, CmmString str]) =
+ hcat [
+ pprLocalness lbl, ptext SLIT("char "), pprCLabel lbl,
+ ptext SLIT("[] = "), pprStringInCStyle str, semi
+ ]
+
+pprTop (CmmData _section _ds@[CmmDataLabel lbl, CmmUninitialised size]) =
+ hcat [
+ pprLocalness lbl, ptext SLIT("char "), pprCLabel lbl,
+ brackets (int size), semi
+ ]
+
+pprTop top@(CmmData _section (CmmDataLabel lbl : lits)) =
+ pprDataExterns lits $$
+ pprWordArray lbl lits
+
+-- these shouldn't appear?
+pprTop (CmmData _ _) = panic "PprC.pprTop: can't handle this data"
+
+
+-- --------------------------------------------------------------------------
+-- BasicBlocks are self-contained entities: they always end in a jump.
+--
+-- Like nativeGen/AsmCodeGen, we could probably reorder blocks to turn
+-- as many jumps as possible into fall throughs.
+--
+
+pprBBlock :: CmmBasicBlock -> SDoc
+pprBBlock (BasicBlock lbl stmts) =
+ if null stmts then
+ pprTrace "pprC.pprBBlock: curious empty code block for"
+ (pprBlockId lbl) empty
+ else
+ nest 4 (pprBlockId lbl <> colon) $$
+ nest 8 (vcat (map pprStmt stmts))
+
+-- --------------------------------------------------------------------------
+-- Info tables. Just arrays of words.
+-- See codeGen/ClosureInfo, and nativeGen/PprMach
+
+pprWordArray :: CLabel -> [CmmStatic] -> SDoc
+pprWordArray lbl ds
+ = hcat [ pprLocalness lbl, ptext SLIT("StgWord")
+ , space, pprCLabel lbl, ptext SLIT("[] = {") ]
+ $$ nest 8 (commafy (pprStatics ds))
+ $$ ptext SLIT("};")
+
+--
+-- has to be static, if it isn't globally visible
+--
+pprLocalness :: CLabel -> SDoc
+pprLocalness lbl | not $ externallyVisibleCLabel lbl = ptext SLIT("static ")
+ | otherwise = empty
+
+-- --------------------------------------------------------------------------
+-- Statements.
+--
+
+pprStmt :: CmmStmt -> SDoc
+
+pprStmt stmt = case stmt of
+ CmmNop -> empty
+ CmmComment s -> (hang (ptext SLIT("/*")) 3 (ftext s)) $$ ptext SLIT("*/")
+
+ CmmAssign dest src -> pprAssign dest src
+
+ CmmStore dest src
+ | rep == I64 && wordRep /= I64
+ -> ptext SLIT("ASSIGN_Word64") <>
+ parens (mkP_ <> pprExpr1 dest <> comma <> pprExpr src) <> semi
+
+ | rep == F64 && wordRep /= I64
+ -> ptext SLIT("ASSIGN_DBL") <>
+ parens (mkP_ <> pprExpr1 dest <> comma <> pprExpr src) <> semi
+
+ | otherwise
+ -> hsep [ pprExpr (CmmLoad dest rep), equals, pprExpr src <> semi ]
+ where
+ rep = cmmExprRep src
+
+ CmmCall (CmmForeignCall fn cconv) results args volatile ->
+ -- Controversial: leave this out for now.
+ -- pprUndef fn $$
+
+ pprCall ppr_fn cconv results args volatile
+ where
+ ppr_fn = case fn of
+ CmmLit (CmmLabel lbl) -> pprCLabel lbl
+ _other -> parens (cCast (pprCFunType cconv results args) fn)
+ -- for a dynamic call, cast the expression to
+ -- a function of the right type (we hope).
+
+ -- we #undef a function before calling it: the FFI is supposed to be
+ -- an interface specifically to C, not to C+CPP. For one thing, this
+ -- makes the via-C route more compatible with the NCG. If macros
+ -- are being used for optimisation, then inline functions are probably
+ -- better anyway.
+ pprUndef (CmmLit (CmmLabel lbl)) =
+ ptext SLIT("#undef") <+> pprCLabel lbl
+ pprUndef _ = empty
+
+ CmmCall (CmmPrim op) results args volatile ->
+ pprCall ppr_fn CCallConv results args volatile
+ where
+ ppr_fn = pprCallishMachOp_for_C op
+
+ CmmBranch ident -> pprBranch ident
+ CmmCondBranch expr ident -> pprCondBranch expr ident
+ CmmJump lbl _params -> mkJMP_(pprExpr lbl) <> semi
+ CmmSwitch arg ids -> pprSwitch arg ids
+
+pprCFunType :: CCallConv -> [(CmmReg,MachHint)] -> [(CmmExpr,MachHint)] -> SDoc
+pprCFunType cconv ress args
+ = hcat [
+ res_type ress,
+ parens (text (ccallConvAttribute cconv) <> char '*'),
+ parens (commafy (map arg_type args))
+ ]
+ where
+ res_type [] = ptext SLIT("void")
+ res_type [(one,hint)] = machRepHintCType (cmmRegRep one) hint
+
+ arg_type (expr,hint) = machRepHintCType (cmmExprRep expr) hint
+
+-- ---------------------------------------------------------------------
+-- unconditional branches
+pprBranch :: BlockId -> SDoc
+pprBranch ident = ptext SLIT("goto") <+> pprBlockId ident <> semi
+
+
+-- ---------------------------------------------------------------------
+-- conditional branches to local labels
+pprCondBranch :: CmmExpr -> BlockId -> SDoc
+pprCondBranch expr ident
+ = hsep [ ptext SLIT("if") , parens(pprExpr expr) ,
+ ptext SLIT("goto") , (pprBlockId ident) <> semi ]
+
+
+-- ---------------------------------------------------------------------
+-- a local table branch
+--
+-- we find the fall-through cases
+--
+-- 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.
+--
+pprSwitch :: CmmExpr -> [ Maybe BlockId ] -> SDoc
+pprSwitch e maybe_ids
+ = let pairs = [ (ix, ident) | (ix,Just ident) <- zip [0..] maybe_ids ]
+ pairs2 = [ (map fst as, snd (head as)) | as <- groupBy sndEq pairs ]
+ in
+ (hang (ptext SLIT("switch") <+> parens ( pprExpr e ) <+> lbrace)
+ 4 (vcat ( map caseify pairs2 )))
+ $$ rbrace
+
+ where
+ sndEq (_,x) (_,y) = x == y
+
+ -- fall through case
+ caseify (ix:ixs, ident) = vcat (map do_fallthrough ixs) $$ final_branch ix
+ where
+ do_fallthrough ix =
+ hsep [ ptext SLIT("case") , pprHexVal ix wordRep <> colon ,
+ ptext SLIT("/* fall through */") ]
+
+ final_branch ix =
+ hsep [ ptext SLIT("case") , pprHexVal ix wordRep <> colon ,
+ ptext SLIT("goto") , (pprBlockId ident) <> semi ]
+
+-- ---------------------------------------------------------------------
+-- Expressions.
+--
+
+-- C Types: the invariant is that the C expression generated by
+--
+-- pprExpr e
+--
+-- has a type in C which is also given by
+--
+-- machRepCType (cmmExprRep e)
+--
+-- (similar invariants apply to the rest of the pretty printer).
+
+pprExpr :: CmmExpr -> SDoc
+pprExpr e = case e of
+ CmmLit lit -> pprLit lit
+
+ CmmLoad e I64 | wordRep /= I64
+ -> ptext SLIT("PK_Word64") <> parens (mkP_ <> pprExpr1 e)
+
+ CmmLoad e F64 | wordRep /= I64
+ -> ptext SLIT("PK_DBL") <> parens (mkP_ <> pprExpr1 e)
+
+ CmmLoad (CmmReg r) rep
+ | isPtrReg r && rep == wordRep
+ -> char '*' <> pprAsPtrReg r
+
+ CmmLoad (CmmRegOff r 0) rep
+ | isPtrReg r && rep == wordRep
+ -> char '*' <> pprAsPtrReg r
+
+ CmmLoad (CmmRegOff r off) rep
+ | isPtrReg r && rep == wordRep
+ -- ToDo: check that the offset is a word multiple?
+ -> pprAsPtrReg r <> brackets (ppr (off `shiftR` wordShift))
+
+ CmmLoad expr rep ->
+ -- the general case:
+ char '*' <> parens (cCast (machRepPtrCType rep) expr)
+
+ CmmReg reg -> pprCastReg reg
+ CmmRegOff reg 0 -> pprCastReg reg
+
+ CmmRegOff reg i
+ | i > 0 -> pprRegOff (char '+') i
+ | otherwise -> pprRegOff (char '-') (-i)
+ where
+ pprRegOff op i' = pprCastReg reg <> op <> int i'
+
+ CmmMachOp mop args -> pprMachOpApp mop args
+
+pprExpr1 :: CmmExpr -> SDoc
+pprExpr1 (CmmLit lit) = pprLit1 lit
+pprExpr1 e@(CmmReg _reg) = pprExpr e
+pprExpr1 other = parens (pprExpr other)
+
+-- --------------------------------------------------------------------------
+-- MachOp applications
+
+pprMachOpApp :: MachOp -> [CmmExpr] -> SDoc
+
+pprMachOpApp op args
+ | isMulMayOfloOp op
+ = ptext SLIT("mulIntMayOflo") <> parens (commafy (map pprExpr args))
+ where isMulMayOfloOp (MO_U_MulMayOflo _) = True
+ isMulMayOfloOp (MO_S_MulMayOflo _) = True
+ isMulMayOfloOp _ = False
+
+pprMachOpApp mop args
+ = case args of
+ -- dyadic
+ [x,y] -> pprArg x <+> pprMachOp_for_C mop <+> pprArg y
+
+ -- unary
+ [x] -> pprMachOp_for_C mop <> parens (pprArg x)
+
+ _ -> panic "PprC.pprMachOp : machop with wrong number of args"
+
+ where
+ pprArg e | signedOp mop = cCast (machRepSignedCType (cmmExprRep e)) e
+ | otherwise = pprExpr1 e
+
+-- --------------------------------------------------------------------------
+-- Literals
+
+pprLit :: CmmLit -> SDoc
+pprLit lit = case lit of
+ CmmInt i rep -> pprHexVal i rep
+ CmmFloat f rep -> parens (machRepCType rep) <> (rational f)
+ CmmLabel clbl -> mkW_ <> pprCLabelAddr clbl
+ CmmLabelOff clbl i -> mkW_ <> pprCLabelAddr clbl <> char '+' <> int i
+ CmmLabelDiffOff clbl1 clbl2 i
+ -- WARNING:
+ -- * the lit must occur in the info table clbl2
+ -- * clbl1 must be an SRT, a slow entry point or a large bitmap
+ -- The Mangler is expected to convert any reference to an SRT,
+ -- a slow entry point or a large bitmap
+ -- from an info table to an offset.
+ -> mkW_ <> pprCLabelAddr clbl1 <> char '+' <> int i
+
+pprCLabelAddr lbl = char '&' <> pprCLabel lbl
+
+pprLit1 :: CmmLit -> SDoc
+pprLit1 lit@(CmmLabelOff _ _) = parens (pprLit lit)
+pprLit1 lit@(CmmLabelDiffOff _ _ _) = parens (pprLit lit)
+pprLit1 lit@(CmmFloat _ _) = parens (pprLit lit)
+pprLit1 other = pprLit other
+
+-- ---------------------------------------------------------------------------
+-- Static data
+
+pprStatics :: [CmmStatic] -> [SDoc]
+pprStatics [] = []
+pprStatics (CmmStaticLit (CmmFloat f F32) : rest)
+ = pprLit1 (floatToWord f) : pprStatics rest
+pprStatics (CmmStaticLit (CmmFloat f F64) : rest)
+ = map pprLit1 (doubleToWords f) ++ pprStatics rest
+pprStatics (CmmStaticLit (CmmInt i I64) : rest)
+ | machRepByteWidth I32 == wORD_SIZE
+#ifdef WORDS_BIGENDIAN
+ = pprStatics (CmmStaticLit (CmmInt q I32) :
+ CmmStaticLit (CmmInt r I32) : rest)
+#else
+ = pprStatics (CmmStaticLit (CmmInt r I32) :
+ CmmStaticLit (CmmInt q I32) : rest)
+#endif
+ where r = i .&. 0xffffffff
+ q = i `shiftR` 32
+pprStatics (CmmStaticLit lit : rest)
+ = pprLit1 lit : pprStatics rest
+pprStatics (other : rest)
+ = pprPanic "pprWord" (pprStatic other)
+
+pprStatic :: CmmStatic -> SDoc
+pprStatic s = case s of
+
+ CmmStaticLit lit -> nest 4 (pprLit lit)
+ CmmAlign i -> nest 4 (ptext SLIT("/* align */") <+> int i)
+ CmmDataLabel clbl -> pprCLabel clbl <> colon
+ CmmUninitialised i -> nest 4 (mkC_ <> brackets (int i))
+
+ -- these should be inlined, like the old .hc
+ CmmString s' -> nest 4 (mkW_ <> parens(pprStringInCStyle s'))
+
+
+-- ---------------------------------------------------------------------------
+-- Block Ids
+
+pprBlockId :: BlockId -> SDoc
+pprBlockId b = char '_' <> ppr (getUnique b)
+
+-- --------------------------------------------------------------------------
+-- Print a MachOp in a way suitable for emitting via C.
+--
+
+pprMachOp_for_C :: MachOp -> SDoc
+
+pprMachOp_for_C mop = case mop of
+
+ -- Integer operations
+ MO_Add _ -> char '+'
+ MO_Sub _ -> char '-'
+ MO_Eq _ -> ptext SLIT("==")
+ MO_Ne _ -> ptext SLIT("!=")
+ MO_Mul _ -> char '*'
+
+ MO_S_Quot _ -> char '/'
+ MO_S_Rem _ -> char '%'
+ MO_S_Neg _ -> char '-'
+
+ MO_U_Quot _ -> char '/'
+ MO_U_Rem _ -> char '%'
+
+ -- Signed comparisons (floating-point comparisons also use these)
+ -- & Unsigned comparisons
+ MO_S_Ge _ -> ptext SLIT(">=")
+ MO_S_Le _ -> ptext SLIT("<=")
+ MO_S_Gt _ -> char '>'
+ MO_S_Lt _ -> char '<'
+
+ MO_U_Ge _ -> ptext SLIT(">=")
+ MO_U_Le _ -> ptext SLIT("<=")
+ MO_U_Gt _ -> char '>'
+ MO_U_Lt _ -> char '<'
+
+ -- Bitwise operations. Not all of these may be supported at all
+ -- sizes, and only integral MachReps are valid.
+ MO_And _ -> char '&'
+ MO_Or _ -> char '|'
+ MO_Xor _ -> char '^'
+ MO_Not _ -> char '~'
+ MO_Shl _ -> ptext SLIT("<<")
+ MO_U_Shr _ -> ptext SLIT(">>") -- unsigned shift right
+ MO_S_Shr _ -> ptext SLIT(">>") -- signed shift right
+
+-- Conversions. Some of these will be NOPs.
+-- Floating-point conversions use the signed variant.
+-- We won't know to generate (void*) casts here, but maybe from
+-- context elsewhere
+
+-- noop casts
+ MO_U_Conv I8 I8 -> empty
+ MO_U_Conv I16 I16 -> empty
+ MO_U_Conv I32 I32 -> empty
+ MO_U_Conv I64 I64 -> empty
+ MO_U_Conv I128 I128 -> empty
+ MO_S_Conv I8 I8 -> empty
+ MO_S_Conv I16 I16 -> empty
+ MO_S_Conv I32 I32 -> empty
+ MO_S_Conv I64 I64 -> empty
+ MO_S_Conv I128 I128 -> empty
+
+ MO_U_Conv _from to -> parens (machRepCType to)
+ MO_S_Conv _from to -> parens (machRepSignedCType to)
+
+ _ -> panic "PprC.pprMachOp_for_C: unknown machop"
+
+signedOp :: MachOp -> Bool
+signedOp (MO_S_Quot _) = True
+signedOp (MO_S_Rem _) = True
+signedOp (MO_S_Neg _) = True
+signedOp (MO_S_Ge _) = True
+signedOp (MO_S_Le _) = True
+signedOp (MO_S_Gt _) = True
+signedOp (MO_S_Lt _) = True
+signedOp (MO_S_Shr _) = True
+signedOp (MO_S_Conv _ _) = True
+signedOp _ = False
+
+-- ---------------------------------------------------------------------
+-- tend to be implemented by foreign calls
+
+pprCallishMachOp_for_C :: CallishMachOp -> SDoc
+
+pprCallishMachOp_for_C mop
+ = case mop of
+ MO_F64_Pwr -> ptext SLIT("pow")
+ MO_F64_Sin -> ptext SLIT("sin")
+ MO_F64_Cos -> ptext SLIT("cos")
+ MO_F64_Tan -> ptext SLIT("tan")
+ MO_F64_Sinh -> ptext SLIT("sinh")
+ MO_F64_Cosh -> ptext SLIT("cosh")
+ MO_F64_Tanh -> ptext SLIT("tanh")
+ MO_F64_Asin -> ptext SLIT("asin")
+ MO_F64_Acos -> ptext SLIT("acos")
+ MO_F64_Atan -> ptext SLIT("atan")
+ MO_F64_Log -> ptext SLIT("log")
+ MO_F64_Exp -> ptext SLIT("exp")
+ MO_F64_Sqrt -> ptext SLIT("sqrt")
+ MO_F32_Pwr -> ptext SLIT("powf")
+ MO_F32_Sin -> ptext SLIT("sinf")
+ MO_F32_Cos -> ptext SLIT("cosf")
+ MO_F32_Tan -> ptext SLIT("tanf")
+ MO_F32_Sinh -> ptext SLIT("sinhf")
+ MO_F32_Cosh -> ptext SLIT("coshf")
+ MO_F32_Tanh -> ptext SLIT("tanhf")
+ MO_F32_Asin -> ptext SLIT("asinf")
+ MO_F32_Acos -> ptext SLIT("acosf")
+ MO_F32_Atan -> ptext SLIT("atanf")
+ MO_F32_Log -> ptext SLIT("logf")
+ MO_F32_Exp -> ptext SLIT("expf")
+ MO_F32_Sqrt -> ptext SLIT("sqrtf")
+
+-- ---------------------------------------------------------------------
+-- Useful #defines
+--
+
+mkJMP_, mkFN_, mkIF_ :: SDoc -> SDoc
+
+mkJMP_ i = ptext SLIT("JMP_") <> parens i
+mkFN_ i = ptext SLIT("FN_") <> parens i -- externally visible function
+mkIF_ i = ptext SLIT("IF_") <> parens i -- locally visible
+
+
+mkFB_, mkFE_ :: SDoc
+mkFB_ = ptext SLIT("FB_") -- function code begin
+mkFE_ = ptext SLIT("FE_") -- function code end
+
+-- from includes/Stg.h
+--
+mkC_,mkW_,mkP_,mkPP_,mkI_,mkA_,mkD_,mkF_,mkB_,mkL_,mkLI_,mkLW_ :: SDoc
+
+mkC_ = ptext SLIT("(C_)") -- StgChar
+mkW_ = ptext SLIT("(W_)") -- StgWord
+mkP_ = ptext SLIT("(P_)") -- StgWord*
+mkPP_ = ptext SLIT("(PP_)") -- P_*
+mkI_ = ptext SLIT("(I_)") -- StgInt
+mkA_ = ptext SLIT("(A_)") -- StgAddr
+mkD_ = ptext SLIT("(D_)") -- const StgWord*
+mkF_ = ptext SLIT("(F_)") -- StgFunPtr
+mkB_ = ptext SLIT("(B_)") -- StgByteArray
+mkL_ = ptext SLIT("(L_)") -- StgClosurePtr
+
+mkLI_ = ptext SLIT("(LI_)") -- StgInt64
+mkLW_ = ptext SLIT("(LW_)") -- StgWord64
+
+
+-- ---------------------------------------------------------------------
+--
+-- Assignments
+--
+-- Generating assignments is what we're all about, here
+--
+pprAssign :: CmmReg -> CmmExpr -> SDoc
+
+-- dest is a reg, rhs is a reg
+pprAssign r1 (CmmReg r2)
+ | not (isStrangeTypeReg r1) && not (isStrangeTypeReg r2)
+ || isPtrReg r1 && isPtrReg r2
+ = hcat [ pprAsPtrReg r1, equals, pprAsPtrReg r2, semi ]
+
+-- dest is a reg, rhs is a CmmRegOff
+pprAssign r1 (CmmRegOff r2 off)
+ | not (isStrangeTypeReg r1) && not (isStrangeTypeReg r2)
+ || isPtrReg r1 && isPtrReg r2
+ = hcat [ pprAsPtrReg r1, equals, pprAsPtrReg r2, op, int off', semi ]
+ where
+ off1 | isPtrReg r2 = off `shiftR` wordShift
+ | otherwise = off
+
+ (op,off') | off >= 0 = (char '+', off1)
+ | otherwise = (char '-', -off1)
+
+-- dest is a reg, rhs is anything.
+-- We can't cast the lvalue, so we have to cast the rhs if necessary. Casting
+-- the lvalue elicits a warning from new GCC versions (3.4+).
+pprAssign r1 r2
+ | isPtrReg r1
+ = pprAsPtrReg r1 <> ptext SLIT(" = ") <> mkP_ <> pprExpr1 r2 <> semi
+ | Just ty <- strangeRegType r1
+ = pprReg r1 <> ptext SLIT(" = ") <> parens ty <> pprExpr1 r2 <> semi
+ | otherwise
+ = pprReg r1 <> ptext SLIT(" = ") <> pprExpr r2 <> semi
+
+-- ---------------------------------------------------------------------
+-- Registers
+
+pprCastReg reg
+ | isStrangeTypeReg reg = mkW_ <> pprReg reg
+ | otherwise = pprReg reg
+
+-- True if the register has type StgPtr in C, otherwise it has an
+-- integer type. We need to take care with pointer arithmetic on registers
+-- with type StgPtr.
+isPtrReg :: CmmReg -> Bool
+isPtrReg (CmmLocal _) = False
+isPtrReg (CmmGlobal r) = isPtrGlobalReg r
+
+isPtrGlobalReg :: GlobalReg -> Bool
+isPtrGlobalReg (VanillaReg n) = True
+isPtrGlobalReg Sp = True
+isPtrGlobalReg Hp = True
+isPtrGlobalReg HpLim = True
+isPtrGlobalReg SpLim = True
+isPtrGlobalReg _ = False
+
+-- True if in C this register doesn't have the type given by
+-- (machRepCType (cmmRegRep reg)), so it has to be cast.
+isStrangeTypeReg :: CmmReg -> Bool
+isStrangeTypeReg (CmmLocal _) = False
+isStrangeTypeReg (CmmGlobal g) = isStrangeTypeGlobal g
+
+isStrangeTypeGlobal :: GlobalReg -> Bool
+isStrangeTypeGlobal CurrentTSO = True
+isStrangeTypeGlobal CurrentNursery = True
+isStrangeTypeGlobal BaseReg = True
+isStrangeTypeGlobal r = isPtrGlobalReg r
+
+strangeRegType :: CmmReg -> Maybe SDoc
+strangeRegType (CmmGlobal CurrentTSO) = Just (ptext SLIT("struct StgTSO_ *"))
+strangeRegType (CmmGlobal CurrentNursery) = Just (ptext SLIT("struct bdescr_ *"))
+strangeRegType (CmmGlobal BaseReg) = Just (ptext SLIT("struct StgRegTable_ *"))
+strangeRegType _ = Nothing
+
+-- pprReg just prints the register name.
+--
+pprReg :: CmmReg -> SDoc
+pprReg r = case r of
+ CmmLocal local -> pprLocalReg local
+ CmmGlobal global -> pprGlobalReg global
+
+pprAsPtrReg :: CmmReg -> SDoc
+pprAsPtrReg (CmmGlobal (VanillaReg n)) = char 'R' <> int n <> ptext SLIT(".p")
+pprAsPtrReg other_reg = pprReg other_reg
+
+pprGlobalReg :: GlobalReg -> SDoc
+pprGlobalReg gr = case gr of
+ VanillaReg n -> char 'R' <> int n <> ptext SLIT(".w")
+ FloatReg n -> char 'F' <> int n
+ DoubleReg n -> char 'D' <> int n
+ LongReg n -> char 'L' <> int n
+ Sp -> ptext SLIT("Sp")
+ SpLim -> ptext SLIT("SpLim")
+ Hp -> ptext SLIT("Hp")
+ HpLim -> ptext SLIT("HpLim")
+ CurrentTSO -> ptext SLIT("CurrentTSO")
+ CurrentNursery -> ptext SLIT("CurrentNursery")
+ HpAlloc -> ptext SLIT("HpAlloc")
+ BaseReg -> ptext SLIT("BaseReg")
+ GCEnter1 -> ptext SLIT("stg_gc_enter_1")
+ GCFun -> ptext SLIT("stg_gc_fun")
+
+pprLocalReg :: LocalReg -> SDoc
+pprLocalReg (LocalReg uniq _rep) = char '_' <> ppr uniq
+
+-- -----------------------------------------------------------------------------
+-- Foreign Calls
+
+pprCall :: SDoc -> CCallConv -> [(CmmReg,MachHint)] -> [(CmmExpr,MachHint)]
+ -> Maybe [GlobalReg] -> SDoc
+
+pprCall ppr_fn cconv results args vols
+ | not (is_cish cconv)
+ = panic "pprCall: unknown calling convention"
+
+ | otherwise
+ = save vols $$
+ ptext SLIT("CALLER_SAVE_SYSTEM") $$
+#if x86_64_TARGET_ARCH
+ -- HACK around gcc optimisations.
+ -- x86_64 needs a __DISCARD__() here, to create a barrier between
+ -- putting the arguments into temporaries and passing the arguments
+ -- to the callee, because the argument expressions may refer to
+ -- machine registers that are also used for passing arguments in the
+ -- C calling convention.
+ (if (not opt_Unregisterised)
+ then ptext SLIT("__DISCARD__();")
+ else empty) $$
+#endif
+ ppr_assign results (ppr_fn <> parens (commafy (map pprArg args))) <> semi $$
+ ptext SLIT("CALLER_RESTORE_SYSTEM") $$
+ restore vols
+ where
+ ppr_assign [] rhs = rhs
+ ppr_assign [(reg@(CmmGlobal BaseReg), hint)] rhs
+ | Just ty <- strangeRegType reg
+ = ptext SLIT("ASSIGN_BaseReg") <> parens (parens ty <> rhs)
+ -- BaseReg is special, sometimes it isn't an lvalue and we
+ -- can't assign to it.
+ ppr_assign [(one,hint)] rhs
+ | Just ty <- strangeRegType one
+ = pprReg one <> ptext SLIT(" = ") <> parens ty <> rhs
+ | otherwise
+ = pprReg one <> ptext SLIT(" = ")
+ <> pprUnHint hint (cmmRegRep one) <> rhs
+ ppr_assign _other _rhs = panic "pprCall: multiple results"
+
+ pprArg (expr, PtrHint)
+ = cCast (ptext SLIT("void *")) expr
+ -- see comment by machRepHintCType below
+ pprArg (expr, SignedHint)
+ = cCast (machRepSignedCType (cmmExprRep expr)) expr
+ pprArg (expr, _other)
+ = pprExpr expr
+
+ pprUnHint PtrHint rep = parens (machRepCType rep)
+ pprUnHint SignedHint rep = parens (machRepCType rep)
+ pprUnHint _ _ = empty
+
+ save = save_restore SLIT("CALLER_SAVE")
+ restore = save_restore SLIT("CALLER_RESTORE")
+
+ -- Nothing says "I don't know what's live; save everything"
+ -- CALLER_SAVE_USER is defined in ghc/includes/Regs.h
+ save_restore txt Nothing = ptext txt <> ptext SLIT("_USER")
+ save_restore txt (Just these) = vcat (map saveRestoreGlobal these)
+ where saveRestoreGlobal r = ptext txt <> char '_' <> pprGlobalRegName r
+
+pprGlobalRegName :: GlobalReg -> SDoc
+pprGlobalRegName gr = case gr of
+ VanillaReg n -> char 'R' <> int n -- without the .w suffix
+ _ -> pprGlobalReg gr
+
+-- Currently we only have these two calling conventions, but this might
+-- change in the future...
+is_cish CCallConv = True
+is_cish StdCallConv = True
+
+-- ---------------------------------------------------------------------
+-- Find and print local and external declarations for a list of
+-- Cmm statements.
+--
+pprTempAndExternDecls :: [CmmBasicBlock] -> (SDoc{-temps-}, SDoc{-externs-})
+pprTempAndExternDecls stmts
+ = (vcat (map pprTempDecl (eltsUFM temps)),
+ vcat (map (pprExternDecl False{-ToDo-}) (keysFM lbls)))
+ where (temps, lbls) = runTE (mapM_ te_BB stmts)
+
+pprDataExterns :: [CmmStatic] -> SDoc
+pprDataExterns statics
+ = vcat (map (pprExternDecl False{-ToDo-}) (keysFM lbls))
+ where (_, lbls) = runTE (mapM_ te_Static statics)
+
+pprTempDecl :: LocalReg -> SDoc
+pprTempDecl l@(LocalReg _uniq rep)
+ = hcat [ machRepCType rep, space, pprLocalReg l, semi ]
+
+pprExternDecl :: Bool -> CLabel -> SDoc
+pprExternDecl in_srt lbl
+ -- do not print anything for "known external" things
+ | not (needsCDecl lbl) = empty
+ | otherwise =
+ hcat [ visibility, label_type (labelType lbl),
+ lparen, dyn_wrapper (pprCLabel lbl), text ");" ]
+ where
+ dyn_wrapper d
+ | in_srt && labelDynamic lbl = text "DLL_IMPORT_DATA_VAR" <> parens d
+ | otherwise = d
+
+ label_type CodeLabel = ptext SLIT("F_")
+ label_type DataLabel = ptext SLIT("I_")
+
+ visibility
+ | externallyVisibleCLabel lbl = char 'E'
+ | otherwise = char 'I'
+
+
+type TEState = (UniqSet LocalReg, FiniteMap CLabel ())
+newtype TE a = TE { unTE :: TEState -> (a, TEState) }
+
+instance Monad TE where
+ TE m >>= k = TE $ \s -> case m s of (a, s') -> unTE (k a) s'
+ return a = TE $ \s -> (a, s)
+
+te_lbl :: CLabel -> TE ()
+te_lbl lbl = TE $ \(temps,lbls) -> ((), (temps, addToFM lbls lbl ()))
+
+te_temp :: LocalReg -> TE ()
+te_temp r = TE $ \(temps,lbls) -> ((), (addOneToUniqSet temps r, lbls))
+
+runTE :: TE () -> TEState
+runTE (TE m) = snd (m (emptyUniqSet, emptyFM))
+
+te_Static :: CmmStatic -> TE ()
+te_Static (CmmStaticLit lit) = te_Lit lit
+te_Static _ = return ()
+
+te_BB :: CmmBasicBlock -> TE ()
+te_BB (BasicBlock _ ss) = mapM_ te_Stmt ss
+
+te_Lit :: CmmLit -> TE ()
+te_Lit (CmmLabel l) = te_lbl l
+te_Lit (CmmLabelOff l _) = te_lbl l
+te_Lit (CmmLabelDiffOff l1 l2 _) = te_lbl l1
+te_Lit _ = return ()
+
+te_Stmt :: CmmStmt -> TE ()
+te_Stmt (CmmAssign r e) = te_Reg r >> te_Expr e
+te_Stmt (CmmStore l r) = te_Expr l >> te_Expr r
+te_Stmt (CmmCall _ rs es _) = mapM_ (te_Reg.fst) rs >>
+ mapM_ (te_Expr.fst) es
+te_Stmt (CmmCondBranch e _) = te_Expr e
+te_Stmt (CmmSwitch e _) = te_Expr e
+te_Stmt (CmmJump e _) = te_Expr e
+te_Stmt _ = return ()
+
+te_Expr :: CmmExpr -> TE ()
+te_Expr (CmmLit lit) = te_Lit lit
+te_Expr (CmmLoad e _) = te_Expr e
+te_Expr (CmmReg r) = te_Reg r
+te_Expr (CmmMachOp _ es) = mapM_ te_Expr es
+te_Expr (CmmRegOff r _) = te_Reg r
+
+te_Reg :: CmmReg -> TE ()
+te_Reg (CmmLocal l) = te_temp l
+te_Reg _ = return ()
+
+
+-- ---------------------------------------------------------------------
+-- C types for MachReps
+
+cCast :: SDoc -> CmmExpr -> SDoc
+cCast ty expr = parens ty <> pprExpr1 expr
+
+-- This is for finding the types of foreign call arguments. For a pointer
+-- argument, we always cast the argument to (void *), to avoid warnings from
+-- the C compiler.
+machRepHintCType :: MachRep -> MachHint -> SDoc
+machRepHintCType rep PtrHint = ptext SLIT("void *")
+machRepHintCType rep SignedHint = machRepSignedCType rep
+machRepHintCType rep _other = machRepCType rep
+
+machRepPtrCType :: MachRep -> SDoc
+machRepPtrCType r | r == wordRep = ptext SLIT("P_")
+ | otherwise = machRepCType r <> char '*'
+
+machRepCType :: MachRep -> SDoc
+machRepCType r | r == wordRep = ptext SLIT("W_")
+ | otherwise = sized_type
+ where sized_type = case r of
+ I8 -> ptext SLIT("StgWord8")
+ I16 -> ptext SLIT("StgWord16")
+ I32 -> ptext SLIT("StgWord32")
+ I64 -> ptext SLIT("StgWord64")
+ F32 -> ptext SLIT("StgFloat") -- ToDo: correct?
+ F64 -> ptext SLIT("StgDouble")
+ _ -> panic "machRepCType"
+
+machRepSignedCType :: MachRep -> SDoc
+machRepSignedCType r | r == wordRep = ptext SLIT("I_")
+ | otherwise = sized_type
+ where sized_type = case r of
+ I8 -> ptext SLIT("StgInt8")
+ I16 -> ptext SLIT("StgInt16")
+ I32 -> ptext SLIT("StgInt32")
+ I64 -> ptext SLIT("StgInt64")
+ F32 -> ptext SLIT("StgFloat") -- ToDo: correct?
+ F64 -> ptext SLIT("StgDouble")
+ _ -> panic "machRepCType"
+
+-- ---------------------------------------------------------------------
+-- print strings as valid C strings
+
+pprStringInCStyle :: [Word8] -> SDoc
+pprStringInCStyle s = doubleQuotes (text (concatMap charToC s))
+
+charToC :: Word8 -> String
+charToC w =
+ case chr (fromIntegral w) of
+ '\"' -> "\\\""
+ '\'' -> "\\\'"
+ '\\' -> "\\\\"
+ c | c >= ' ' && c <= '~' -> [c]
+ | otherwise -> ['\\',
+ chr (ord '0' + ord c `div` 64),
+ chr (ord '0' + ord c `div` 8 `mod` 8),
+ chr (ord '0' + ord c `mod` 8)]
+
+-- ---------------------------------------------------------------------------
+-- Initialising static objects with floating-point numbers. We can't
+-- just emit the floating point number, because C will cast it to an int
+-- by rounding it. We want the actual bit-representation of the float.
+
+-- This is a hack to turn the floating point numbers into ints that we
+-- can safely initialise to static locations.
+
+big_doubles
+ | machRepByteWidth F64 == 2 * wORD_SIZE = True
+ | machRepByteWidth F64 == wORD_SIZE = False
+ | otherwise = panic "big_doubles"
+
+#if __GLASGOW_HASKELL__ >= 504
+newFloatArray :: (Int,Int) -> ST s (STUArray s Int Float)
+newFloatArray = newArray_
+
+newDoubleArray :: (Int,Int) -> ST s (STUArray s Int Double)
+newDoubleArray = newArray_
+
+castFloatToIntArray :: STUArray s Int Float -> ST s (STUArray s Int Int)
+castFloatToIntArray = castSTUArray
+
+castDoubleToIntArray :: STUArray s Int Double -> ST s (STUArray s Int Int)
+castDoubleToIntArray = castSTUArray
+
+writeFloatArray :: STUArray s Int Float -> Int -> Float -> ST s ()
+writeFloatArray = writeArray
+
+writeDoubleArray :: STUArray s Int Double -> Int -> Double -> ST s ()
+writeDoubleArray = writeArray
+
+readIntArray :: STUArray s Int Int -> Int -> ST s Int
+readIntArray = readArray
+
+#else
+
+castFloatToIntArray :: MutableByteArray s t -> ST s (MutableByteArray s t)
+castFloatToIntArray = return
+
+castDoubleToIntArray :: MutableByteArray s t -> ST s (MutableByteArray s t)
+castDoubleToIntArray = return
+
+#endif
+
+-- floats are always 1 word
+floatToWord :: Rational -> CmmLit
+floatToWord r
+ = runST (do
+ arr <- newFloatArray ((0::Int),0)
+ writeFloatArray arr 0 (fromRational r)
+ arr' <- castFloatToIntArray arr
+ i <- readIntArray arr' 0
+ return (CmmInt (toInteger i) wordRep)
+ )
+
+doubleToWords :: Rational -> [CmmLit]
+doubleToWords r
+ | big_doubles -- doubles are 2 words
+ = runST (do
+ arr <- newDoubleArray ((0::Int),1)
+ writeDoubleArray arr 0 (fromRational r)
+ arr' <- castDoubleToIntArray arr
+ i1 <- readIntArray arr' 0
+ i2 <- readIntArray arr' 1
+ return [ CmmInt (toInteger i1) wordRep
+ , CmmInt (toInteger i2) wordRep
+ ]
+ )
+ | otherwise -- doubles are 1 word
+ = runST (do
+ arr <- newDoubleArray ((0::Int),0)
+ writeDoubleArray arr 0 (fromRational r)
+ arr' <- castDoubleToIntArray arr
+ i <- readIntArray arr' 0
+ return [ CmmInt (toInteger i) wordRep ]
+ )
+
+-- ---------------------------------------------------------------------------
+-- Utils
+
+wordShift :: Int
+wordShift = machRepLogWidth wordRep
+
+commafy :: [SDoc] -> SDoc
+commafy xs = hsep $ punctuate comma xs
+
+-- Print in C hex format: 0x13fa
+pprHexVal :: Integer -> MachRep -> SDoc
+pprHexVal 0 _ = ptext SLIT("0x0")
+pprHexVal w rep
+ | w < 0 = parens (char '-' <> ptext SLIT("0x") <> go (-w) <> repsuffix rep)
+ | otherwise = ptext SLIT("0x") <> go w <> repsuffix rep
+ where
+ -- type suffix for literals:
+ -- Integer literals are unsigned in Cmm/C. We explicitly cast to
+ -- signed values for doing signed operations, but at all other
+ -- times values are unsigned. This also helps eliminate occasional
+ -- warnings about integer overflow from gcc.
+
+ -- on 32-bit platforms, add "ULL" to 64-bit literals
+ repsuffix I64 | wORD_SIZE == 4 = ptext SLIT("ULL")
+ -- on 64-bit platforms with 32-bit int, add "L" to 64-bit literals
+ repsuffix I64 | cINT_SIZE == 4 = ptext SLIT("UL")
+ repsuffix _ = char 'U'
+
+ go 0 = empty
+ go w' = go q <> dig
+ where
+ (q,r) = w' `quotRem` 16
+ dig | r < 10 = char (chr (fromInteger r + ord '0'))
+ | otherwise = char (chr (fromInteger r - 10 + ord 'a'))
+
diff --git a/compiler/cmm/PprCmm.hs b/compiler/cmm/PprCmm.hs
new file mode 100644
index 0000000000..6e8367d662
--- /dev/null
+++ b/compiler/cmm/PprCmm.hs
@@ -0,0 +1,462 @@
+----------------------------------------------------------------------------
+--
+-- Pretty-printing of Cmm as (a superset of) C--
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+--
+-- This is where we walk over Cmm emitting an external representation,
+-- suitable for parsing, in a syntax strongly reminiscent of C--. This
+-- is the "External Core" for the Cmm layer.
+--
+-- As such, this should be a well-defined syntax: we want it to look nice.
+-- Thus, we try wherever possible to use syntax defined in [1],
+-- "The C-- Reference Manual", http://www.cminusminus.org/. We differ
+-- slightly, in some cases. For one, we use I8 .. I64 for types, rather
+-- than C--'s bits8 .. bits64.
+--
+-- We try to ensure that all information available in the abstract
+-- syntax is reproduced, or reproducible, in the concrete syntax.
+-- Data that is not in printed out can be reconstructed according to
+-- conventions used in the pretty printer. There are at least two such
+-- cases:
+-- 1) if a value has wordRep type, the type is not appended in the
+-- output.
+-- 2) MachOps that operate over wordRep type are printed in a
+-- C-style, rather than as their internal MachRep name.
+--
+-- These conventions produce much more readable Cmm output.
+--
+-- A useful example pass over Cmm is in nativeGen/MachCodeGen.hs
+--
+
+module PprCmm (
+ writeCmms, pprCmms, pprCmm, pprStmt, pprExpr
+ ) where
+
+#include "HsVersions.h"
+
+import Cmm
+import CmmUtils ( isTrivialCmmExpr )
+import MachOp ( MachOp(..), pprMachOp, MachRep(..), wordRep )
+import CLabel ( pprCLabel, mkForeignLabel, entryLblToInfoLbl )
+
+import ForeignCall ( CCallConv(..) )
+import Unique ( getUnique )
+import Outputable
+import FastString ( mkFastString )
+
+import Data.List ( intersperse, groupBy )
+import IO ( Handle )
+import Maybe ( isJust )
+import Data.Char ( chr )
+
+pprCmms :: [Cmm] -> SDoc
+pprCmms cmms = pprCode CStyle (vcat (intersperse separator $ map ppr cmms))
+ where
+ separator = space $$ ptext SLIT("-------------------") $$ space
+
+writeCmms :: Handle -> [Cmm] -> IO ()
+writeCmms handle cmms = printForC handle (pprCmms cmms)
+
+-----------------------------------------------------------------------------
+
+instance Outputable Cmm where
+ ppr c = pprCmm c
+
+instance Outputable CmmTop where
+ ppr t = pprTop t
+
+instance Outputable CmmBasicBlock where
+ ppr b = pprBBlock b
+
+instance Outputable CmmStmt where
+ ppr s = pprStmt s
+
+instance Outputable CmmExpr where
+ ppr e = pprExpr e
+
+instance Outputable CmmReg where
+ ppr e = pprReg e
+
+instance Outputable GlobalReg where
+ ppr e = pprGlobalReg e
+
+-----------------------------------------------------------------------------
+
+pprCmm :: Cmm -> SDoc
+pprCmm (Cmm tops) = vcat $ intersperse (text "") $ map pprTop tops
+
+-- --------------------------------------------------------------------------
+-- Top level `procedure' blocks. The info tables, if not null, are
+-- printed in the style of C--'s 'stackdata' declaration, just inside
+-- the proc body, and are labelled with the procedure name ++ "_info".
+--
+pprTop :: CmmTop -> SDoc
+pprTop (CmmProc info lbl params blocks )
+
+ = vcat [ pprCLabel lbl <> parens (commafy $ map pprLocalReg params) <+> lbrace
+ , nest 8 $ pprInfo info lbl
+ , nest 4 $ vcat (map ppr blocks)
+ , rbrace ]
+
+ where
+ pprInfo [] _ = empty
+ pprInfo i label =
+ (hang (pprCLabel (entryLblToInfoLbl label) <+> lbrace )
+ 4 $ vcat (map pprStatic i))
+ $$ rbrace
+
+-- --------------------------------------------------------------------------
+-- We follow [1], 4.5
+--
+-- section "data" { ... }
+--
+pprTop (CmmData section ds) =
+ (hang (pprSection section <+> lbrace) 4 (vcat (map pprStatic ds)))
+ $$ rbrace
+
+
+-- --------------------------------------------------------------------------
+-- Basic blocks look like assembly blocks.
+-- lbl: stmt ; stmt ; ..
+pprBBlock :: CmmBasicBlock -> SDoc
+pprBBlock (BasicBlock ident stmts) =
+ hang (pprBlockId ident <> colon) 4 (vcat (map ppr stmts))
+
+-- --------------------------------------------------------------------------
+-- Statements. C-- usually, exceptions to this should be obvious.
+--
+pprStmt :: CmmStmt -> SDoc
+pprStmt stmt = case stmt of
+
+ -- ;
+ CmmNop -> semi
+
+ -- // text
+ CmmComment s -> text "//" <+> ftext s
+
+ -- reg = expr;
+ CmmAssign reg expr -> ppr reg <+> equals <+> ppr expr <> semi
+
+ -- rep[lv] = expr;
+ CmmStore lv expr -> rep <> brackets(ppr lv) <+> equals <+> ppr expr <> semi
+ where
+ rep = ppr ( cmmExprRep expr )
+
+ -- call "ccall" foo(x, y)[r1, r2];
+ -- ToDo ppr volatile
+ CmmCall (CmmForeignCall fn cconv) results args _volatile ->
+ hcat [ ptext SLIT("call"), space,
+ doubleQuotes(ppr cconv), space,
+ target fn, parens ( commafy $ map ppr args ),
+ (if null results
+ then empty
+ else brackets( commafy $ map ppr results)), semi ]
+ where
+ target (CmmLit lit) = pprLit lit
+ target fn' = parens (ppr fn')
+
+ CmmCall (CmmPrim op) results args volatile ->
+ pprStmt (CmmCall (CmmForeignCall (CmmLit lbl) CCallConv)
+ results args volatile)
+ where
+ lbl = CmmLabel (mkForeignLabel (mkFastString (show op)) Nothing False)
+
+ CmmBranch ident -> genBranch ident
+ CmmCondBranch expr ident -> genCondBranch expr ident
+ CmmJump expr params -> genJump expr params
+ CmmSwitch arg ids -> genSwitch arg ids
+
+-- --------------------------------------------------------------------------
+-- goto local label. [1], section 6.6
+--
+-- goto lbl;
+--
+genBranch :: BlockId -> SDoc
+genBranch ident =
+ ptext SLIT("goto") <+> pprBlockId ident <> semi
+
+-- --------------------------------------------------------------------------
+-- Conditional. [1], section 6.4
+--
+-- if (expr) { goto lbl; }
+--
+genCondBranch :: CmmExpr -> BlockId -> SDoc
+genCondBranch expr ident =
+ hsep [ ptext SLIT("if")
+ , parens(ppr expr)
+ , ptext SLIT("goto")
+ , pprBlockId ident <> semi ]
+
+-- --------------------------------------------------------------------------
+-- A tail call. [1], Section 6.9
+--
+-- jump foo(a, b, c);
+--
+genJump :: CmmExpr -> [LocalReg] -> SDoc
+genJump expr actuals =
+
+ hcat [ ptext SLIT("jump")
+ , space
+ , if isTrivialCmmExpr expr
+ then pprExpr expr
+ else case expr of
+ CmmLoad (CmmReg _) _ -> pprExpr expr
+ _ -> parens (pprExpr expr)
+ , pprActuals actuals
+ , semi ]
+
+ where
+ pprActuals [] = empty
+ pprActuals as = parens ( commafy $ map pprLocalReg as )
+
+-- --------------------------------------------------------------------------
+-- Tabled jump to local label
+--
+-- The syntax is from [1], section 6.5
+--
+-- switch [0 .. n] (expr) { case ... ; }
+--
+genSwitch :: CmmExpr -> [Maybe BlockId] -> SDoc
+genSwitch expr maybe_ids
+
+ = let pairs = groupBy snds (zip [0 .. ] maybe_ids )
+
+ in hang (hcat [ ptext SLIT("switch [0 .. ")
+ , int (length maybe_ids - 1)
+ , ptext SLIT("] ")
+ , if isTrivialCmmExpr expr
+ then pprExpr expr
+ else parens (pprExpr expr)
+ , ptext SLIT(" {")
+ ])
+ 4 (vcat ( map caseify pairs )) $$ rbrace
+
+ where
+ snds a b = (snd a) == (snd b)
+
+ caseify :: [(Int,Maybe BlockId)] -> SDoc
+ caseify ixs@((i,Nothing):_)
+ = ptext SLIT("/* impossible: ") <> hcat (intersperse comma (map (int.fst) ixs))
+ <> ptext SLIT(" */")
+ caseify as
+ = let (is,ids) = unzip as
+ in hsep [ ptext SLIT("case")
+ , hcat (punctuate comma (map int is))
+ , ptext SLIT(": goto")
+ , pprBlockId (head [ id | Just id <- ids]) <> semi ]
+
+-- --------------------------------------------------------------------------
+-- Expressions
+--
+
+pprExpr :: CmmExpr -> SDoc
+pprExpr e
+ = case e of
+ CmmRegOff reg i ->
+ pprExpr (CmmMachOp (MO_Add rep)
+ [CmmReg reg, CmmLit (CmmInt (fromIntegral i) rep)])
+ where rep = cmmRegRep reg
+ CmmLit lit -> pprLit lit
+ _other -> pprExpr1 e
+
+-- Here's the precedence table from CmmParse.y:
+-- %nonassoc '>=' '>' '<=' '<' '!=' '=='
+-- %left '|'
+-- %left '^'
+-- %left '&'
+-- %left '>>' '<<'
+-- %left '-' '+'
+-- %left '/' '*' '%'
+-- %right '~'
+
+-- We just cope with the common operators for now, the rest will get
+-- a default conservative behaviour.
+
+-- %nonassoc '>=' '>' '<=' '<' '!=' '=='
+pprExpr1 (CmmMachOp op [x,y]) | Just doc <- infixMachOp1 op
+ = pprExpr7 x <+> doc <+> pprExpr7 y
+pprExpr1 e = pprExpr7 e
+
+infixMachOp1 (MO_Eq _) = Just (ptext SLIT("=="))
+infixMachOp1 (MO_Ne _) = Just (ptext SLIT("!="))
+infixMachOp1 (MO_Shl _) = Just (ptext SLIT("<<"))
+infixMachOp1 (MO_U_Shr _) = Just (ptext SLIT(">>"))
+infixMachOp1 (MO_U_Ge _) = Just (ptext SLIT(">="))
+infixMachOp1 (MO_U_Le _) = Just (ptext SLIT("<="))
+infixMachOp1 (MO_U_Gt _) = Just (char '>')
+infixMachOp1 (MO_U_Lt _) = Just (char '<')
+infixMachOp1 _ = Nothing
+
+-- %left '-' '+'
+pprExpr7 (CmmMachOp op [x,y]) | Just doc <- infixMachOp7 op
+ = pprExpr7 x <+> doc <+> pprExpr8 y
+pprExpr7 e = pprExpr8 e
+
+infixMachOp7 (MO_Add _) = Just (char '+')
+infixMachOp7 (MO_Sub _) = Just (char '-')
+infixMachOp7 _ = Nothing
+
+-- %left '/' '*' '%'
+pprExpr8 (CmmMachOp op [x,y]) | Just doc <- infixMachOp8 op
+ = pprExpr8 x <+> doc <+> pprExpr9 y
+pprExpr8 e = pprExpr9 e
+
+infixMachOp8 (MO_U_Quot _) = Just (char '/')
+infixMachOp8 (MO_Mul _) = Just (char '*')
+infixMachOp8 (MO_U_Rem _) = Just (char '%')
+infixMachOp8 _ = Nothing
+
+pprExpr9 :: CmmExpr -> SDoc
+pprExpr9 e =
+ case e of
+ CmmLit lit -> pprLit1 lit
+ CmmLoad expr rep -> ppr rep <> brackets( ppr expr )
+ CmmReg reg -> ppr reg
+ CmmRegOff reg off -> parens (ppr reg <+> char '+' <+> int off)
+ CmmMachOp mop args -> genMachOp mop args
+
+genMachOp :: MachOp -> [CmmExpr] -> SDoc
+genMachOp mop args
+ | Just doc <- infixMachOp mop = case args of
+ -- dyadic
+ [x,y] -> pprExpr9 x <+> doc <+> pprExpr9 y
+
+ -- unary
+ [x] -> doc <> pprExpr9 x
+
+ _ -> pprTrace "PprCmm.genMachOp: machop with strange number of args"
+ (pprMachOp mop <+>
+ parens (hcat $ punctuate comma (map pprExpr args)))
+ empty
+
+ | isJust (infixMachOp1 mop)
+ || isJust (infixMachOp7 mop)
+ || isJust (infixMachOp8 mop) = parens (pprExpr (CmmMachOp mop args))
+
+ | otherwise = char '%' <> pprMachOp mop <> parens (commafy (map pprExpr args))
+
+--
+-- Unsigned ops on the word size of the machine get nice symbols.
+-- All else get dumped in their ugly format.
+--
+infixMachOp :: MachOp -> Maybe SDoc
+infixMachOp mop
+ = case mop of
+ MO_And _ -> Just $ char '&'
+ MO_Or _ -> Just $ char '|'
+ MO_Xor _ -> Just $ char '^'
+ MO_Not _ -> Just $ char '~'
+ MO_S_Neg _ -> Just $ char '-' -- there is no unsigned neg :)
+ _ -> Nothing
+
+-- --------------------------------------------------------------------------
+-- Literals.
+-- To minimise line noise we adopt the convention that if the literal
+-- has the natural machine word size, we do not append the type
+--
+pprLit :: CmmLit -> SDoc
+pprLit lit = case lit of
+ CmmInt i rep ->
+ hcat [ (if i < 0 then parens else id)(integer i)
+ , (if rep == wordRep
+ then empty
+ else space <> dcolon <+> ppr rep) ]
+
+ CmmFloat f rep -> hsep [ rational f, dcolon, ppr rep ]
+ CmmLabel clbl -> pprCLabel clbl
+ CmmLabelOff clbl i -> pprCLabel clbl <> ppr_offset i
+ CmmLabelDiffOff clbl1 clbl2 i -> pprCLabel clbl1 <> char '-'
+ <> pprCLabel clbl2 <> ppr_offset i
+
+pprLit1 lit@(CmmLabelOff clbl i) = parens (pprLit lit)
+pprLit1 lit = pprLit lit
+
+ppr_offset :: Int -> SDoc
+ppr_offset i
+ | i==0 = empty
+ | i>=0 = char '+' <> int i
+ | otherwise = char '-' <> int (-i)
+
+-- --------------------------------------------------------------------------
+-- Static data.
+-- Strings are printed as C strings, and we print them as I8[],
+-- following C--
+--
+pprStatic :: CmmStatic -> SDoc
+pprStatic s = case s of
+ CmmStaticLit lit -> nest 4 $ ptext SLIT("const") <+> pprLit lit <> semi
+ CmmUninitialised i -> nest 4 $ text "I8" <> brackets (int i)
+ CmmAlign i -> nest 4 $ text "align" <+> int i
+ CmmDataLabel clbl -> pprCLabel clbl <> colon
+ CmmString s' -> nest 4 $ text "I8[]" <+>
+ doubleQuotes (text (map (chr.fromIntegral) s'))
+
+-- --------------------------------------------------------------------------
+-- Registers, whether local (temps) or global
+--
+pprReg :: CmmReg -> SDoc
+pprReg r
+ = case r of
+ CmmLocal local -> pprLocalReg local
+ CmmGlobal global -> pprGlobalReg global
+
+--
+-- We only print the type of the local reg if it isn't wordRep
+--
+pprLocalReg :: LocalReg -> SDoc
+pprLocalReg (LocalReg uniq rep)
+ = hcat [ char '_', ppr uniq,
+ (if rep == wordRep
+ then empty else dcolon <> ppr rep) ]
+
+-- needs to be kept in syn with Cmm.hs.GlobalReg
+--
+pprGlobalReg :: GlobalReg -> SDoc
+pprGlobalReg gr
+ = case gr of
+ VanillaReg n -> char 'R' <> int n
+ FloatReg n -> char 'F' <> int n
+ DoubleReg n -> char 'D' <> int n
+ LongReg n -> char 'L' <> int n
+ Sp -> ptext SLIT("Sp")
+ SpLim -> ptext SLIT("SpLim")
+ Hp -> ptext SLIT("Hp")
+ HpLim -> ptext SLIT("HpLim")
+ CurrentTSO -> ptext SLIT("CurrentTSO")
+ CurrentNursery -> ptext SLIT("CurrentNursery")
+ HpAlloc -> ptext SLIT("HpAlloc")
+ GCEnter1 -> ptext SLIT("stg_gc_enter_1")
+ GCFun -> ptext SLIT("stg_gc_fun")
+ BaseReg -> ptext SLIT("BaseReg")
+ PicBaseReg -> ptext SLIT("PicBaseReg")
+
+-- --------------------------------------------------------------------------
+-- data sections
+--
+pprSection :: Section -> SDoc
+pprSection s = case s of
+ Text -> section <+> doubleQuotes (ptext SLIT("text"))
+ Data -> section <+> doubleQuotes (ptext SLIT("data"))
+ ReadOnlyData -> section <+> doubleQuotes (ptext SLIT("readonly"))
+ RelocatableReadOnlyData
+ -> section <+> doubleQuotes (ptext SLIT("relreadonly"))
+ UninitialisedData -> section <+> doubleQuotes (ptext SLIT("uninitialised"))
+ OtherSection s' -> section <+> doubleQuotes (text s')
+ where
+ section = ptext SLIT("section")
+
+-- --------------------------------------------------------------------------
+-- Basic block ids
+--
+pprBlockId :: BlockId -> SDoc
+pprBlockId b = ppr $ getUnique b
+
+-----------------------------------------------------------------------------
+
+commafy :: [SDoc] -> SDoc
+commafy xs = hsep $ punctuate comma xs
+