[project @ 2004-08-13 13:04:50 by simonmar]
authorsimonmar <unknown>
Fri, 13 Aug 2004 13:11:23 +0000 (13:11 +0000)
committersimonmar <unknown>
Fri, 13 Aug 2004 13:11:23 +0000 (13:11 +0000)
Merge backend-hacking-branch onto HEAD.  Yay!

218 files changed:
ghc/compiler/HsVersions.h
ghc/compiler/Makefile
ghc/compiler/NOTES
ghc/compiler/absCSyn/AbsCSyn.lhs [deleted file]
ghc/compiler/absCSyn/AbsCUtils.lhs [deleted file]
ghc/compiler/absCSyn/CLabel.lhs [deleted file]
ghc/compiler/absCSyn/CStrings.lhs [deleted file]
ghc/compiler/absCSyn/Costs.lhs [deleted file]
ghc/compiler/absCSyn/MachOp.hs [deleted file]
ghc/compiler/absCSyn/PprAbsC.lhs [deleted file]
ghc/compiler/basicTypes/Id.lhs
ghc/compiler/basicTypes/Literal.lhs
ghc/compiler/basicTypes/Name.lhs
ghc/compiler/basicTypes/Unique.lhs
ghc/compiler/cmm/CLabel.hs [new file with mode: 0644]
ghc/compiler/cmm/Cmm.hs [new file with mode: 0644]
ghc/compiler/cmm/CmmLex.x [new file with mode: 0644]
ghc/compiler/cmm/CmmLint.hs [new file with mode: 0644]
ghc/compiler/cmm/CmmParse.y [new file with mode: 0644]
ghc/compiler/cmm/CmmUtils.hs [new file with mode: 0644]
ghc/compiler/cmm/MachOp.hs [new file with mode: 0644]
ghc/compiler/cmm/PprC.hs [new file with mode: 0644]
ghc/compiler/cmm/PprCmm.hs [new file with mode: 0644]
ghc/compiler/codeGen/CgBindery.lhs
ghc/compiler/codeGen/CgCallConv.hs [new file with mode: 0644]
ghc/compiler/codeGen/CgCase.lhs
ghc/compiler/codeGen/CgClosure.lhs
ghc/compiler/codeGen/CgCon.lhs
ghc/compiler/codeGen/CgConTbls.lhs [deleted file]
ghc/compiler/codeGen/CgExpr.lhs
ghc/compiler/codeGen/CgForeignCall.hs [new file with mode: 0644]
ghc/compiler/codeGen/CgHeapery.lhs
ghc/compiler/codeGen/CgInfoTbls.hs [new file with mode: 0644]
ghc/compiler/codeGen/CgLetNoEscape.lhs
ghc/compiler/codeGen/CgMonad.lhs
ghc/compiler/codeGen/CgParallel.hs [new file with mode: 0644]
ghc/compiler/codeGen/CgPrimOp.hs [new file with mode: 0644]
ghc/compiler/codeGen/CgProf.hs [new file with mode: 0644]
ghc/compiler/codeGen/CgRetConv.hi-boot [deleted file]
ghc/compiler/codeGen/CgRetConv.lhs [deleted file]
ghc/compiler/codeGen/CgStackery.lhs
ghc/compiler/codeGen/CgTailCall.lhs
ghc/compiler/codeGen/CgTicky.hs [new file with mode: 0644]
ghc/compiler/codeGen/CgUpdate.lhs [deleted file]
ghc/compiler/codeGen/CgUsages.lhs [deleted file]
ghc/compiler/codeGen/CgUtils.hs [new file with mode: 0644]
ghc/compiler/codeGen/ClosureInfo.lhs
ghc/compiler/codeGen/CodeGen.lhs
ghc/compiler/codeGen/SMRep.lhs
ghc/compiler/compMan/CompManager.lhs
ghc/compiler/deSugar/DsCCall.lhs
ghc/compiler/deSugar/DsForeign.lhs
ghc/compiler/ghci/ByteCodeAsm.lhs
ghc/compiler/ghci/ByteCodeFFI.lhs
ghc/compiler/ghci/ByteCodeGen.lhs
ghc/compiler/ghci/ByteCodeInstr.lhs
ghc/compiler/ghci/ByteCodeItbls.lhs
ghc/compiler/ghci/InteractiveUI.hs
ghc/compiler/ghci/Linker.lhs
ghc/compiler/hsSyn/HsDecls.lhs
ghc/compiler/main/CmdLineOpts.lhs
ghc/compiler/main/CodeOutput.lhs
ghc/compiler/main/Constants.lhs
ghc/compiler/main/DriverFlags.hs
ghc/compiler/main/DriverPhases.hs
ghc/compiler/main/DriverPipeline.hs
ghc/compiler/main/DriverState.hs
ghc/compiler/main/DriverUtil.hs
ghc/compiler/main/ErrUtils.lhs
ghc/compiler/main/HscMain.lhs
ghc/compiler/main/Main.hs
ghc/compiler/main/SysTools.lhs
ghc/compiler/nativeGen/AbsCStixGen.lhs [deleted file]
ghc/compiler/nativeGen/AsmCodeGen.lhs
ghc/compiler/nativeGen/AsmRegAlloc.lhs [deleted file]
ghc/compiler/nativeGen/MachCode.lhs [deleted file]
ghc/compiler/nativeGen/MachCodeGen.hs [new file with mode: 0644]
ghc/compiler/nativeGen/MachInstrs.hs [new file with mode: 0644]
ghc/compiler/nativeGen/MachMisc.hi-boot [deleted file]
ghc/compiler/nativeGen/MachMisc.hi-boot-5 [deleted file]
ghc/compiler/nativeGen/MachMisc.hi-boot-6 [deleted file]
ghc/compiler/nativeGen/MachMisc.lhs [deleted file]
ghc/compiler/nativeGen/MachRegs.lhs
ghc/compiler/nativeGen/NCG.h
ghc/compiler/nativeGen/NCGMonad.hs [new file with mode: 0644]
ghc/compiler/nativeGen/NOTES
ghc/compiler/nativeGen/PprMach.hs [moved from ghc/compiler/nativeGen/PprMach.lhs with 77% similarity]
ghc/compiler/nativeGen/RegAllocInfo.hs [moved from ghc/compiler/nativeGen/RegAllocInfo.lhs with 58% similarity]
ghc/compiler/nativeGen/RegisterAlloc.hs [new file with mode: 0644]
ghc/compiler/nativeGen/Stix.hi-boot [deleted file]
ghc/compiler/nativeGen/Stix.lhs [deleted file]
ghc/compiler/nativeGen/StixMacro.lhs [deleted file]
ghc/compiler/nativeGen/StixPrim.hi-boot [deleted file]
ghc/compiler/nativeGen/StixPrim.hi-boot-5 [deleted file]
ghc/compiler/nativeGen/StixPrim.hi-boot-6 [deleted file]
ghc/compiler/nativeGen/StixPrim.lhs [deleted file]
ghc/compiler/parser/Ctype.lhs
ghc/compiler/parser/Lexer.x
ghc/compiler/parser/Parser.y.pp
ghc/compiler/parser/RdrHsSyn.lhs
ghc/compiler/prelude/ForeignCall.lhs
ghc/compiler/prelude/PrimOp.lhs
ghc/compiler/prelude/PrimRep.lhs [deleted file]
ghc/compiler/prelude/TysPrim.lhs
ghc/compiler/profiling/CostCentre.lhs
ghc/compiler/typecheck/TcForeign.lhs
ghc/compiler/typecheck/TcHsSyn.lhs
ghc/compiler/typecheck/TcRnTypes.lhs
ghc/compiler/types/TyCon.lhs
ghc/compiler/types/Type.lhs
ghc/compiler/utils/FastString.lhs
ghc/compiler/utils/OrdList.lhs
ghc/compiler/utils/Panic.lhs
ghc/compiler/utils/StringBuffer.lhs
ghc/compiler/utils/Util.lhs
ghc/docs/comm/genesis/modules.html
ghc/docs/comm/rts-libs/coding-style.html
ghc/driver/mangler/ghc-asm.lprl
ghc/includes/Block.h
ghc/includes/CCall.h [deleted file]
ghc/includes/ClosureMacros.h
ghc/includes/Closures.h
ghc/includes/Cmm.h [new file with mode: 0644]
ghc/includes/Constants.h
ghc/includes/Derived.h [deleted file]
ghc/includes/DietHEP.h [deleted file]
ghc/includes/HsFFI.h
ghc/includes/InfoMacros.h [deleted file]
ghc/includes/InfoTables.h
ghc/includes/Liveness.h [new file with mode: 0644]
ghc/includes/MachDeps.h
ghc/includes/MachRegs.h
ghc/includes/Makefile
ghc/includes/PosixSource.h [deleted file]
ghc/includes/PrimOps.h [deleted file]
ghc/includes/README [new file with mode: 0644]
ghc/includes/Regs.h
ghc/includes/Rts.h
ghc/includes/RtsAPI.h
ghc/includes/RtsConfig.h [new file with mode: 0644]
ghc/includes/RtsExternal.h [new file with mode: 0644]
ghc/includes/RtsFlags.h
ghc/includes/Stable.h
ghc/includes/Stg.h
ghc/includes/StgFun.h
ghc/includes/StgLdvProf.h
ghc/includes/StgMacros.h [deleted file]
ghc/includes/StgMiscClosures.h
ghc/includes/StgProf.h
ghc/includes/StgStorage.h [deleted file]
ghc/includes/StgTicky.h
ghc/includes/StgTypes.h
ghc/includes/Storage.h [moved from ghc/rts/Storage.h with 54% similarity]
ghc/includes/TSO.h
ghc/includes/TailCalls.h
ghc/includes/Updates.h
ghc/includes/mkDerivedConstants.c
ghc/includes/mkNativeHdr.c [deleted file]
ghc/rts/Apply.cmm [new file with mode: 0644]
ghc/rts/Apply.h
ghc/rts/Apply.hc [deleted file]
ghc/rts/AutoApply.h [new file with mode: 0644]
ghc/rts/Capability.h
ghc/rts/Disassembler.c
ghc/rts/Exception.cmm [new file with mode: 0644]
ghc/rts/Exception.h
ghc/rts/Exception.hc [deleted file]
ghc/rts/FrontPanel.c
ghc/rts/GC.c
ghc/rts/GCCompact.c
ghc/rts/HeapStackCheck.cmm [new file with mode: 0644]
ghc/rts/HeapStackCheck.hc [deleted file]
ghc/rts/Interpreter.c
ghc/rts/LdvProfile.c
ghc/rts/Linker.c
ghc/rts/MBlock.h
ghc/rts/Main.c
ghc/rts/Makefile
ghc/rts/Prelude.h
ghc/rts/PrimOps.cmm [new file with mode: 0644]
ghc/rts/PrimOps.hc [deleted file]
ghc/rts/Printer.c
ghc/rts/ProfHeap.c
ghc/rts/Profiling.c
ghc/rts/Profiling.h
ghc/rts/RetainerProfile.c
ghc/rts/RetainerProfile.h
ghc/rts/RtsFlags.c
ghc/rts/RtsStartup.c
ghc/rts/RtsUtils.h
ghc/rts/Sanity.c
ghc/rts/Schedule.c
ghc/rts/Schedule.h
ghc/rts/Signals.c
ghc/rts/Stable.c
ghc/rts/StablePriv.h [deleted file]
ghc/rts/Stats.c
ghc/rts/StgCRun.c
ghc/rts/StgMiscClosures.cmm [new file with mode: 0644]
ghc/rts/StgMiscClosures.hc [deleted file]
ghc/rts/StgRun.h
ghc/rts/StgStartup.cmm [moved from ghc/rts/StgStartup.hc with 53% similarity]
ghc/rts/StgStartup.h [deleted file]
ghc/rts/StgStdThunks.cmm [new file with mode: 0644]
ghc/rts/StgStdThunks.hc [deleted file]
ghc/rts/Storage.c
ghc/rts/StoragePriv.h [deleted file]
ghc/rts/Ticky.c
ghc/rts/Updates.cmm [moved from ghc/rts/Updates.hc with 55% similarity]
ghc/rts/Weak.c
ghc/rts/Weak.h
ghc/rts/package.conf.in
ghc/utils/genapply/GenApply.hs
ghc/utils/ghc-pkg/Main.hs
ghc/utils/hp2ps/Main.h
ghc/utils/hsc2hs/Main.hs
ghc/utils/prof/cgprof/cgprof.c
ghc/utils/prof/cgprof/main.c

index 1ba51b5..0bd9c14 100644 (file)
@@ -66,10 +66,10 @@ name = Util.global (value) :: IORef (ty); \
 #define WARN( e, msg ) (warnPprTrace (e) __FILE__ __LINE__ (msg))
 #define ASSERTM(e) ASSERT(e) do
 #else
-#define ASSERT(e)
-#define ASSERT2(e,msg)
+#define ASSERT(e)      if False then error "ASSERT"  else
+#define ASSERT2(e,msg) if False then error "ASSERT2" else
 #define ASSERTM(e)
-#define WARN(e,msg)
+#define WARN(e,msg)    if False then error "WARN"    else
 #endif
 
 -- temporary usage assertion control KSW 2000-10
index b040e58..ee40fc1 100644 (file)
@@ -232,8 +232,8 @@ CLEAN_FILES += $(CONFIG_HS)
 
 ALL_DIRS = \
   utils basicTypes types hsSyn prelude rename typecheck deSugar coreSyn \
-  specialise simplCore stranal stgSyn simplStg codeGen absCSyn main \
-  profiling parser cprAnalysis compMan ndpFlatten cbits iface
+  specialise simplCore stranal stgSyn simplStg codeGen main \
+  profiling parser cprAnalysis compMan ndpFlatten cbits iface cmm
 
 # Make sure we include Config.hs even if it doesn't exist yet...
 ALL_SRCS += $(CONFIG_HS)
@@ -410,9 +410,6 @@ ifeq "$(HOSTPLATFORM)" "i386-unknown-mingw32"
 main/SysTools_HC_OPTS          += '-\#include <windows.h>' '-\#include <process.h>'
 endif
 
-# Required due to use of Concurrent.myThreadId
-utils/Panic_HC_OPTS += -fvia-C
-
 parser/Lexer_HC_OPTS += -funbox-strict-fields
 
 # ghc_strlen percolates through so many modules that it is easier to get its
@@ -553,8 +550,6 @@ endif
 # typecheck/TcTyDecls_HC_OPTS += -auto-all
 # typecheck/TcType_HC_OPTS += -auto-all
 # typecheck/TcUnify_HC_OPTS += -auto-all
-# 
-# absCSyn/PprAbsC_HC_OPTS += -auto-all
 
 coreSyn/CorePrep_HC_OPTS += -auto-all
 
index 4c2b702..8607f90 100644 (file)
@@ -1,5 +1,47 @@
-* Can a scoped type variable denote a type scheme?
+       New back end thoughts
 
+-----------------------------------------------------------------------------
+Codegen notes
+
+* jumps to ImpossibleBranch should be removed.
+
+* Profiling:
+       - when updating a closure with an indirection to a function,
+         we should make a permanent indirection.
+
+       - check that we're bumping the scc count appropriately
+
+* check perf & binary sizes against the HEAD
+
+-----------------------------------------------------------------------------
+C backend notes
+
+* use STGCALL macros for foreign calls (doesn't look like volatile regs
+  are handled properly at the mo).
+
+-----------------------------------------------------------------------------
+Cmm parser notes
+
+* switches
+
+* need to cater for unexported procedures/info tables?
+
+* We should be able to get rid of entry labels, use info labels only.
+  - we need a %ENTRY_LBL(info_lbl) macro, so that instead of
+     JMP_(foo_entry) we can write jump %ENTRY_LBL(foo_info).
+
+-----------------------------------------------------------------------------
+
+* Move arg-descr from LFInfo to ClosureInfo? 
+  But: only needed for functions
+
+* Move all of CgClosure.link_caf into NewCaf, and newDynCaf
+
+* If the case binder is dead, and the constr is nullary,
+  do we need to assign to Node?
+
+
+-------------------------
 * Relation between separate type sigs and pattern type sigs
 f :: forall a. a->a
 f :: b->b = e   -- No: monomorphic
diff --git a/ghc/compiler/absCSyn/AbsCSyn.lhs b/ghc/compiler/absCSyn/AbsCSyn.lhs
deleted file mode 100644 (file)
index 3c8a470..0000000
+++ /dev/null
@@ -1,540 +0,0 @@
-%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
-%
-% $Id: AbsCSyn.lhs,v 1.56 2003/11/17 14:47:53 simonmar Exp $
-%
-\section[AbstractC]{Abstract C: the last stop before machine code}
-
-This ``Abstract C'' data type describes the raw Spineless Tagless
-machine model at a C-ish level; it is ``abstract'' in that it only
-includes C-like structures that we happen to need.  The conversion of
-programs from @StgSyntax@ (basically a functional language) to
-@AbstractC@ (basically imperative C) is the heart of code generation.
-From @AbstractC@, one may convert to real C (for portability) or to
-raw assembler/machine code.
-
-\begin{code}
-module AbsCSyn where   -- export everything
-
-#include "HsVersions.h"
-
-import {-# SOURCE #-} ClosureInfo ( ClosureInfo )
-
-import CLabel
-import Constants       ( mAX_Vanilla_REG, mAX_Float_REG,
-                         mAX_Double_REG, spRelToInt )
-import CostCentre       ( CostCentre, CostCentreStack )
-import Literal         ( mkMachInt, Literal(..) )
-import ForeignCall     ( CCallSpec )
-import PrimRep         ( PrimRep(..) )
-import MachOp          ( MachOp(..) )
-import Unique           ( Unique )
-import StgSyn          ( StgOp )
-import TyCon           ( TyCon )
-import Bitmap          ( Bitmap, mAX_SMALL_BITMAP_SIZE )
-import SMRep           ( StgWord, StgHalfWord )
-import FastTypes
-import FastString
-\end{code}
-
-@AbstractC@ is a list of Abstract~C statements, but the data structure
-is tree-ish, for easier and more efficient putting-together.
-\begin{code}
-data AbstractC
-  = AbsCNop
-  | AbsCStmts          AbstractC AbstractC
-
-  -- and the individual stmts...
-\end{code}
-
-A note on @CAssign@: In general, the type associated with an assignment
-is the type of the lhs.  However, when the lhs is a pointer to mixed
-types (e.g. SpB relative), the type of the assignment is the type of
-the rhs for float types, or the generic StgWord for all other types.
-(In particular, a CharRep on the rhs is promoted to IntRep when
-stored in a mixed type location.)
-
-\begin{code}
-  | CAssign
-       !CAddrMode      -- target
-       !CAddrMode      -- source
-
-  | CJump
-       CAddrMode       -- Put this in the program counter
-                       -- eg `CJump (CReg (VanillaReg PtrRep 1))' puts Ret1 in PC
-                       -- Enter can be done by:
-                       --        CJump (CVal NodeRel zeroOff)
-
-  | CFallThrough
-       CAddrMode       -- Fall through into this routine
-                       -- (for the benefit of the native code generators)
-                       -- Equivalent to CJump in C land
-
-  | CReturn            -- Perform a return
-       CAddrMode       -- Address of a RET_<blah> info table
-       ReturnInfo      -- Whether it's a direct or vectored return
-
-  | CSwitch !CAddrMode
-       [(Literal, AbstractC)]  -- alternatives
-       AbstractC               -- default; if there is no real Abstract C in here
-                               -- (e.g., all comments; see function "nonemptyAbsC"),
-                               -- then that means the default _cannot_ occur.
-                               -- If there is only one alternative & no default code,
-                               -- then there is no need to check the tag.
-                               -- Therefore, e.g.:
-                               --  CSwitch m [(tag,code)] AbsCNop == code
-
-  | CCodeBlock CLabel AbstractC
-                       -- A labelled block of code; this "statement" is not
-                       -- executed; rather, the labelled code will be hoisted
-                       -- out to the top level (out of line) & it can be
-                       -- jumped to.
-
-  | CInitHdr           -- to initialise the header of a closure (both fixed/var parts)
-       ClosureInfo
-       CAddrMode       -- address of the info ptr
-       !CAddrMode      -- cost centre to place in closure
-                       --   CReg CurCostCentre or CC_HDR(R1.p{-Node-})
-       Int             -- size of closure, for profiling
-
-  -- NEW CASES FOR EXPANDED PRIMOPS
-
-  | CMachOpStmt                        -- Machine-level operation
-       CAddrMode               -- result
-       MachOp
-       [CAddrMode]             -- Arguments
-        (Maybe [MagicId])      -- list of regs which need to be preserved
-       -- across the primop.  This is allowed to be Nothing only if
-       -- machOpIsDefinitelyInline returns True.  And that in turn may
-       -- only return True if we are absolutely sure that the mach op
-       -- can be done inline on all platforms.  
-
-  | CSequential                -- Do the nested AbstractCs sequentially.
-       [AbstractC]     -- In particular, as far as the AbsCUtils.doSimultaneously
-                       -- is concerned, these stmts are to be treated as atomic
-                       -- and are not to be reordered.
-
-  -- end of NEW CASES FOR EXPANDED PRIMOPS
-
-  | COpStmt
-       [CAddrMode]     -- Results
-       StgOp
-       [CAddrMode]     -- Arguments
-       [MagicId]       -- Potentially volatile/live registers
-                       -- (to save/restore around the call/op)
-
-       -- INVARIANT: When a PrimOp which can cause GC is used, the
-       -- only live data is tidily on the STG stacks or in the STG
-       -- registers (the code generator ensures this).
-       --
-       -- Why this?  Because if the arguments were arbitrary
-       -- addressing modes, they might be things like (Hp+6) which
-       -- will get utterly spongled by GC.
-
-  | CSimultaneous      -- Perform simultaneously all the statements
-       AbstractC       -- in the nested AbstractC.  They are only
-                       -- allowed to be CAssigns, COpStmts and AbsCNops, so the
-                       -- "simultaneous" part just concerns making
-                       -- sure that permutations work.
-                       -- For example { a := b, b := a }
-                       --      needs to go via (at least one) temporary
-
-  | CCheck             -- heap or stack checks, or both.  
-       CCheckMacro     -- These might include some code to fill in tags 
-       [CAddrMode]     -- on the stack, so we can't use CMacroStmt below.
-       AbstractC
-
-  | CRetDirect                 -- Direct return
-        !Unique                        -- for making labels
-       AbstractC               -- return code
-       C_SRT                   -- SRT info
-       Liveness                -- stack liveness at the return point
-
-  -- see the notes about these next few; they follow below...
-  | CMacroStmt         CStmtMacro      [CAddrMode]
-  | CCallProfCtrMacro  FastString      [CAddrMode]
-  | CCallProfCCMacro   FastString      [CAddrMode]
-
-    {- The presence of this constructor is a makeshift solution;
-       it being used to work around a gcc-related problem of
-       handling typedefs within statement blocks (or, rather,
-       the inability to do so.)
-       
-       The AbstractC flattener takes care of lifting out these
-       typedefs if needs be (i.e., when generating .hc code and
-       compiling 'foreign import dynamic's)
-    -}
-  | CCallTypedef Bool {- True => use "typedef"; False => use "extern"-}
-                CCallSpec Unique [CAddrMode] [CAddrMode]
-
-  -- *** the next three [or so...] are DATA (those above are CODE) ***
-
-  | CStaticClosure
-       CLabel                  -- The closure's label
-       ClosureInfo             -- Todo: maybe info_lbl & closure_lbl instead?
-       CAddrMode               -- cost centre identifier to place in closure
-       [CAddrMode]             -- free vars; ptrs, then non-ptrs.
-
-  | CSRT CLabel [CLabel]       -- SRT declarations: basically an array of 
-                               -- pointers to static closures.
-  
-  | CBitmap Liveness           -- A "large" bitmap to be emitted
-
-  | CSRTDesc                   -- A "large" SRT descriptor (one that doesn't
-                               -- fit into the half-word bitmap in the itbl).
-       !CLabel                 -- Label for this SRT descriptor
-       !CLabel                 -- Pointer to the SRT
-       !Int                    -- Offset within the SRT
-       !Int                    -- Length
-       !Bitmap                 -- Bitmap
-
-  | CClosureInfoAndCode
-       ClosureInfo             -- Explains placement and layout of closure
-       AbstractC               -- Entry point code
-
-  | CRetVector                 -- A labelled block of static data
-       CLabel
-       [CAddrMode]
-       C_SRT                   -- SRT info
-       Liveness                -- stack liveness at the return point
-
-  | CClosureTbl                -- table of constructors for enumerated types
-       TyCon                   -- which TyCon this table is for
-
-  | CModuleInitBlock           -- module initialisation block
-       CLabel                  -- "plain" label for init block
-       CLabel                  -- label for init block (with ver + way info)
-       AbstractC               -- initialisation code
-
-  | CCostCentreDecl            -- A cost centre *declaration*
-       Bool                    -- True  <=> local => full declaration
-                               -- False <=> extern; just say so
-       CostCentre
-
-  | CCostCentreStackDecl       -- A cost centre stack *declaration*
-       CostCentreStack         -- this is the declaration for a
-                               -- pre-defined singleton CCS (see 
-                               -- CostCentre.lhs)
-
-  | CSplitMarker               -- Split into separate object modules here
-
--- C_SRT is what StgSyn.SRT gets translated to... 
--- we add a label for the table, and expect only the 'offset/length' form
-
-data C_SRT = NoC_SRT
-          | C_SRT !CLabel !Int{-offset-} !StgHalfWord{-bitmap or escape-}
-
-needsSRT :: C_SRT -> Bool
-needsSRT NoC_SRT       = False
-needsSRT (C_SRT _ _ _) = True
-\end{code}
-
-About @CMacroStmt@, etc.: notionally, they all just call some
-arbitrary C~macro or routine, passing the @CAddrModes@ as arguments.
-However, we distinguish between various flavours of these things,
-mostly just to keep things somewhat less wild and wooly.
-
-\begin{description}
-\item[@CMacroStmt@:]
-Some {\em essential} bits of the STG execution model are done with C
-macros.  An example is @STK_CHK@, which checks for stack-space
-overflow.  This enumeration type lists all such macros:
-\begin{code}
-data CStmtMacro
-  = UPD_CAF                            -- update CAF closure with indirection
-  | UPD_BH_UPDATABLE                   -- eager backholing
-  | UPD_BH_SINGLE_ENTRY                        -- more eager blackholing
-  | PUSH_UPD_FRAME                     -- push update frame
-  | SET_TAG                            -- set TagReg if it exists
-      -- dataToTag# primop -- *only* used in unregisterised builds.
-      -- (see AbsCUtils.dsCOpStmt)
-  | DATA_TO_TAGZH
-
-  | REGISTER_FOREIGN_EXPORT            -- register a foreign exported fun
-  | REGISTER_IMPORT                    -- register an imported module
-  | REGISTER_DIMPORT                    -- register an imported module from
-                                        -- another DLL
-
-  | GRAN_FETCH                 -- for GrAnSim only  -- HWL
-  | GRAN_RESCHEDULE            -- for GrAnSim only  -- HWL
-  | GRAN_FETCH_AND_RESCHEDULE  -- for GrAnSim only  -- HWL
-  | THREAD_CONTEXT_SWITCH      -- for GrAnSim only  -- HWL
-  | GRAN_YIELD                 -- for GrAnSim only  -- HWL 
-\end{code}
-
-Heap/Stack checks.  There are far too many of these.
-
-\begin{code}
-data CCheckMacro
-
-  = HP_CHK_NP                          -- heap/stack checks when
-  | STK_CHK_NP                         -- node points to the closure
-  | HP_STK_CHK_NP
-
-  | HP_CHK_FUN                         -- heap/stack checks when
-  | STK_CHK_FUN                                -- node doesn't point
-  | HP_STK_CHK_FUN
-                                       -- case alternative heap checks:
-
-  | HP_CHK_NOREGS                      --   no registers live
-  | HP_CHK_UNPT_R1                     --   R1 is boxed/unlifted
-  | HP_CHK_UNBX_R1                     --   R1 is unboxed
-  | HP_CHK_F1                          --   FloatReg1 (only) is live 
-  | HP_CHK_D1                          --   DblReg1   (only) is live
-  | HP_CHK_L1                          --   LngReg1   (only) is live
-
-  | HP_CHK_UNBX_TUPLE                  -- unboxed tuple heap check
-\end{code}
-
-\item[@CCallProfCtrMacro@:]
-The @String@ names a macro that, if \tr{#define}d, will bump one/some
-of the STG-event profiling counters.
-
-\item[@CCallProfCCMacro@:]
-The @String@ names a macro that, if \tr{#define}d, will perform some
-cost-centre-profiling-related action.
-\end{description}
-
-%************************************************************************
-%*                                                                     *
-\subsection[CAddrMode]{C addressing modes}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-data CAddrMode
-  = CVal  RegRelative PrimRep
-                       -- On RHS of assign: Contents of Magic[n]
-                       -- On LHS of assign: location Magic[n]
-                       -- (ie at addr Magic+n)
-
-  | CAddr RegRelative
-                       -- On RHS of assign: Address of Magic[n]; ie Magic+n
-                       --      n=0 gets the Magic location itself
-                       --      (NB: n=0 case superceded by CReg)
-                       -- On LHS of assign: only sensible if n=0,
-                       --      which gives the magic location itself
-                       --      (NB: superceded by CReg)
-
-             -- JRS 2002-02-05: CAddr is really scummy and should be fixed.
-             -- The effect is that the semantics of CAddr depend on what the
-             -- contained RegRelative is; it is decidely non-orthogonal.
-
-  | CReg MagicId       -- To replace (CAddr MagicId 0)
-
-  | CTemp !Unique !PrimRep     -- Temporary locations
-       -- ``Temporaries'' correspond to local variables in C, and registers in
-       -- native code.
-
-  | CLbl    CLabel     -- Labels in the runtime system, etc.
-           PrimRep     -- the kind is so we can generate accurate C decls
-
-  | CCharLike CAddrMode        -- The address of a static char-like closure for
-                       -- the specified character.  It is guaranteed to be in
-                       -- the range mIN_CHARLIKE..mAX_CHARLIKE
-
-  | CIntLike CAddrMode -- The address of a static int-like closure for the
-                       -- specified small integer.  It is guaranteed to be in
-                       -- the range mIN_INTLIKE..mAX_INTLIKE
-
-  | CLit    Literal
-
-  | CJoinPoint         -- This is used as the amode of a let-no-escape-bound
-                       -- variable.
-       VirtualSpOffset   -- Sp value after any volatile free vars
-                         -- of the rhs have been saved on stack.
-                         -- Just before the code for the thing is jumped to,
-                         -- Sp will be set to this value,
-                         -- and then any stack-passed args pushed,
-                         -- then the code for this thing will be entered
-  | CMacroExpr
-       !PrimRep        -- the kind of the result
-       CExprMacro      -- the macro to generate a value
-       [CAddrMode]     -- and its arguments
-\end{code}
-
-Various C macros for values which are dependent on the back-end layout.
-
-\begin{code}
-
-data CExprMacro
-  = ENTRY_CODE
-  | ARG_TAG                            -- stack argument tagging
-  | GET_TAG                            -- get current constructor tag
-  | CCS_HDR
-  | BYTE_ARR_CTS               -- used when passing a ByteArray# to a ccall
-  | PTRS_ARR_CTS               -- similarly for an Array#
-  | ForeignObj_CLOSURE_DATA    -- and again for a ForeignObj#
-\end{code}
-
-Convenience functions:
-
-\begin{code}
-mkIntCLit :: Int -> CAddrMode
-mkIntCLit i = CLit (mkMachInt (toInteger i))
-
-mkWordCLit :: StgWord -> CAddrMode
-mkWordCLit wd = CLit (MachWord (fromIntegral wd))
-
-mkCString :: FastString -> CAddrMode
-mkCString s = CLit (MachStr s)
-
-mkCCostCentre :: CostCentre -> CAddrMode
-mkCCostCentre cc = CLbl (mkCC_Label cc) DataPtrRep
-
-mkCCostCentreStack :: CostCentreStack -> CAddrMode
-mkCCostCentreStack ccs = CLbl (mkCCS_Label ccs) DataPtrRep
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[RegRelative]{@RegRelatives@: ???}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-data RegRelative
-  = HpRel      FastInt -- }
-  | SpRel      FastInt -- }- offsets in StgWords
-  | NodeRel    FastInt -- }
-  | CIndex     CAddrMode CAddrMode PrimRep     -- pointer arithmetic :-)
-                                               -- CIndex a b k === (k*)a[b]
-
-data ReturnInfo
-  = DirectReturn                       -- Jump directly, if possible
-  | StaticVectoredReturn Int           -- Fixed tag, starting at zero
-  | DynamicVectoredReturn CAddrMode    -- Dynamic tag given by amode, starting at zero
-
-hpRel :: VirtualHeapOffset     -- virtual offset of Hp
-      -> VirtualHeapOffset     -- virtual offset of The Thing
-      -> RegRelative           -- integer offset
-hpRel hp off = HpRel (iUnbox (hp - off))
-
-spRel :: VirtualSpOffset       -- virtual offset of Sp
-      -> VirtualSpOffset       -- virtual offset of The Thing
-      -> RegRelative           -- integer offset
-spRel sp off = SpRel (iUnbox (spRelToInt sp off))
-
-nodeRel :: VirtualHeapOffset
-        -> RegRelative
-nodeRel off = NodeRel (iUnbox off)
-
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[Liveness]{Liveness Masks}
-%*                                                                     *
-%************************************************************************
-
-We represent liveness bitmaps as a BitSet (whose internal
-representation really is a bitmap).  These are pinned onto case return
-vectors to indicate the state of the stack for the garbage collector.
-
-In the compiled program, liveness bitmaps that fit inside a single
-word (StgWord) are stored as a single word, while larger bitmaps are
-stored as a pointer to an array of words. 
-
-\begin{code}
-data Liveness = Liveness CLabel !Int Bitmap
-
-maybeLargeBitmap :: Liveness -> AbstractC
-maybeLargeBitmap liveness@(Liveness _ size _)
-  | size <= mAX_SMALL_BITMAP_SIZE = AbsCNop
-  | otherwise                     = CBitmap liveness
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[HeapOffset]{@Heap Offsets@}
-%*                                                                     *
-%************************************************************************
-
-This used to be a grotesquely complicated datatype in an attempt to
-hide the details of header sizes from the compiler itself.  Now these
-constants are imported from the RTS, and we deal in real Ints.
-
-\begin{code}
-type HeapOffset = Int                  -- ToDo: remove
-
-type VirtualHeapOffset = HeapOffset
-type VirtualSpOffset   = Int
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[MagicId]{@MagicIds@: registers and such}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-data MagicId
-  = BaseReg    -- mentioned only in nativeGen
-
-  -- Argument and return registers
-  | VanillaReg         -- pointers, unboxed ints and chars
-       PrimRep
-       FastInt -- its number (1 .. mAX_Vanilla_REG)
-
-  | FloatReg           -- single-precision floating-point registers
-       FastInt -- its number (1 .. mAX_Float_REG)
-
-  | DoubleReg          -- double-precision floating-point registers
-       FastInt -- its number (1 .. mAX_Double_REG)
-
-  -- 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
-  | CurCostCentre      -- current cost centre register.
-  | VoidReg            -- see "VoidPrim" type; just a placeholder; 
-                       --   no actual register
-  | LongReg            -- long int registers (64-bit, really)
-       PrimRep         -- Int64Rep or Word64Rep
-       FastInt -- its number (1 .. mAX_Long_REG)
-
-  | CurrentTSO         -- pointer to current thread's TSO
-  | CurrentNursery     -- pointer to allocation area
-  | HpAlloc            -- allocation count for heap check failure
-
-
-node   = VanillaReg PtrRep     (_ILIT 1) -- A convenient alias for Node
-tagreg  = VanillaReg WordRep    (_ILIT 2) -- A convenient alias for TagReg
-
-nodeReg = CReg node
-\end{code}
-
-We need magical @Eq@ because @VanillaReg@s come in multiple flavors.
-
-\begin{code}
-instance Eq MagicId where
-    reg1 == reg2 = tag reg1 ==# tag reg2
-     where
-       tag BaseReg          = (_ILIT(0) :: FastInt)
-       tag Sp               = _ILIT(1)
-       tag SpLim            = _ILIT(3)
-       tag Hp               = _ILIT(4)
-       tag HpLim            = _ILIT(5)
-       tag CurCostCentre    = _ILIT(6)
-       tag VoidReg          = _ILIT(7)
-
-       tag (VanillaReg _ i) = _ILIT(8) +# i
-
-       tag (FloatReg i)  = _ILIT(8) +# maxv +# i
-       tag (DoubleReg i) = _ILIT(8) +# maxv +# maxf +# i
-       tag (LongReg _ i) = _ILIT(8) +# maxv +# maxf +# maxd +# i
-
-        maxv = iUnbox mAX_Vanilla_REG
-        maxf = iUnbox mAX_Float_REG
-        maxd = iUnbox mAX_Double_REG
-\end{code}
-
-Returns True for any register that {\em potentially} dies across
-C calls (or anything near equivalent).  We just say @True@ and
-let the (machine-specific) registering macros sort things out...
-
-\begin{code}
-isVolatileReg :: MagicId -> Bool
-isVolatileReg any = True
-\end{code}
diff --git a/ghc/compiler/absCSyn/AbsCUtils.lhs b/ghc/compiler/absCSyn/AbsCUtils.lhs
deleted file mode 100644 (file)
index fef7bf5..0000000
+++ /dev/null
@@ -1,1315 +0,0 @@
-%
-% (c) The GRASP/AQUA Project, Glasgow University, 1993-1998
-%
-\section[AbsCUtils]{Help functions for Abstract~C datatype}
-
-\begin{code}
-module AbsCUtils (
-       nonemptyAbsC,
-       mkAbstractCs, mkAbsCStmts,
-       mkAlgAltsCSwitch,
-       magicIdPrimRep,
-       getAmodeRep,
-       mixedTypeLocn, mixedPtrLocn,
-       flattenAbsC,
-       mkAbsCStmtList,
-       shimFCallArg
-       -- printing/forcing stuff comes from PprAbsC
-    ) where
-
-#include "HsVersions.h"
-#include "../includes/config.h"
-
-import AbsCSyn
-import Type            ( tyConAppTyCon, repType )
-import TysPrim         ( foreignObjPrimTyCon, arrayPrimTyCon, 
-                         byteArrayPrimTyCon, mutableByteArrayPrimTyCon,
-                         mutableArrayPrimTyCon )
-import CLabel          ( mkMAP_FROZEN_infoLabel )
-import Digraph         ( stronglyConnComp, SCC(..) )
-import DataCon         ( fIRST_TAG, dataConTag )
-import Literal         ( literalPrimRep, mkMachWord, mkMachInt )
-import PrimRep         ( getPrimRepSize, PrimRep(..) )
-import PrimOp          ( PrimOp(..) )
-import MachOp          ( MachOp(..), isDefinitelyInlineMachOp )
-import Unique          ( Unique{-instance Eq-} )
-import UniqSupply      ( uniqFromSupply, uniqsFromSupply, splitUniqSupply, 
-                         UniqSupply )
-import CmdLineOpts      ( opt_EmitCExternDecls, opt_Unregisterised )
-import ForeignCall     ( ForeignCall(..), CCallSpec(..), isDynamicTarget )
-import StgSyn          ( StgOp(..), stgArgType )
-import CoreSyn         ( AltCon(..) )
-import SMRep           ( arrPtrsHdrSize, arrWordsHdrSize, fixedHdrSize )
-import Outputable
-import Panic           ( panic )
-import FastTypes
-import Constants       ( wORD_SIZE, wORD_SIZE_IN_BITS )
-
-infixr 9 `thenFlt`
-\end{code}
-
-Check if there is any real code in some Abstract~C.  If so, return it
-(@Just ...@); otherwise, return @Nothing@.  Don't be too strict!
-
-It returns the "reduced" code in the Just part so that the work of
-discarding AbsCNops isn't lost, and so that if the caller uses
-the reduced version there's less danger of a big tree of AbsCNops getting
-materialised and causing a space leak.
-
-\begin{code}
-nonemptyAbsC :: AbstractC -> Maybe AbstractC
-nonemptyAbsC  AbsCNop          = Nothing
-nonemptyAbsC (AbsCStmts s1 s2) = case (nonemptyAbsC s1) of
-                                   Nothing -> nonemptyAbsC s2
-                                   Just x  -> Just (AbsCStmts x s2)
-nonemptyAbsC s@(CSimultaneous c) = case (nonemptyAbsC c) of
-                                   Nothing -> Nothing
-                                   Just x  -> Just s
-nonemptyAbsC other             = Just other
-\end{code}
-
-\begin{code}
-mkAbstractCs :: [AbstractC] -> AbstractC
-mkAbstractCs [] = AbsCNop
-mkAbstractCs cs = foldr1 mkAbsCStmts cs
-
--- for fiddling around w/ killing off AbsCNops ... (ToDo)
-mkAbsCStmts :: AbstractC -> AbstractC -> AbstractC
-mkAbsCStmts AbsCNop c = c
-mkAbsCStmts c AbsCNop = c
-mkAbsCStmts c1 c2     = c1 `AbsCStmts` c2
-
-{- Discarded SLPJ June 95; it calls nonemptyAbsC too much!
-  = case (case (nonemptyAbsC abc2) of
-           Nothing -> AbsCNop
-           Just d2 -> d2)      of { abc2b ->
-
-    case (nonemptyAbsC abc1) of {
-      Nothing -> abc2b;
-      Just d1 -> AbsCStmts d1 abc2b
-    } }
--}
-\end{code}
-
-Get the sho' 'nuff statements out of an @AbstractC@.
-\begin{code}
-mkAbsCStmtList :: AbstractC -> [AbstractC]
-
-mkAbsCStmtList absC = mkAbsCStmtList' absC []
-
--- Optimised a la foldr/build!
-
-mkAbsCStmtList'  AbsCNop r = r
-
-mkAbsCStmtList' (AbsCStmts s1 s2) r
-  = mkAbsCStmtList' s1 (mkAbsCStmtList' s2 r)
-
-mkAbsCStmtList' s@(CSimultaneous c) r
-  = if null (mkAbsCStmtList c) then r else s : r
-
-mkAbsCStmtList' other r = other : r
-\end{code}
-
-\begin{code}
-mkAlgAltsCSwitch :: CAddrMode -> [(AltCon, AbstractC)] -> AbstractC
-
-mkAlgAltsCSwitch scrutinee ((_,first_alt) : rest_alts)
- = CSwitch scrutinee (adjust rest_alts) first_alt
- where
-   -- We use the first alt as the default.  Either it *is* the DEFAULT,
-   -- (which is always first if present), or the case is exhaustive,
-   -- in which case we can use the first as the default anyway
-
-   -- Adjust the tags in the switch to start at zero.
-   -- This is the convention used by primitive ops which return algebraic
-   -- data types.  Why?         Because for two-constructor types, zero is faster
-   -- to create and distinguish from 1 than are 1 and 2.
-
-   -- We also need to convert to Literals to keep the CSwitch happy
-   adjust tagged_alts
-     = [ (mkMachWord (toInteger (dataConTag dc - fIRST_TAG)), abs_c)
-       | (DataAlt dc, abs_c) <- tagged_alts ]
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsubsection[AbsCUtils-kinds-from-MagicIds]{Kinds from MagicIds}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-magicIdPrimRep BaseReg             = PtrRep
-magicIdPrimRep (VanillaReg kind _) = kind
-magicIdPrimRep (FloatReg _)        = FloatRep
-magicIdPrimRep (DoubleReg _)       = DoubleRep
-magicIdPrimRep (LongReg kind _)            = kind
-magicIdPrimRep Sp                  = PtrRep
-magicIdPrimRep SpLim               = PtrRep
-magicIdPrimRep Hp                  = PtrRep
-magicIdPrimRep HpLim               = PtrRep
-magicIdPrimRep CurCostCentre       = CostCentreRep
-magicIdPrimRep VoidReg             = VoidRep
-magicIdPrimRep CurrentTSO          = PtrRep
-magicIdPrimRep CurrentNursery      = PtrRep
-magicIdPrimRep HpAlloc              = WordRep
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[AbsCUtils-amode-kinds]{Finding @PrimitiveKinds@ of amodes}
-%*                                                                     *
-%************************************************************************
-
-See also the return conventions for unboxed things; currently living
-in @CgCon@ (next to the constructor return conventions).
-
-ToDo: tiny tweaking may be in order
-\begin{code}
-getAmodeRep :: CAddrMode -> PrimRep
-
-getAmodeRep (CVal _ kind)                  = kind
-getAmodeRep (CAddr _)                      = PtrRep
-getAmodeRep (CReg magic_id)                = magicIdPrimRep magic_id
-getAmodeRep (CTemp uniq kind)              = kind
-getAmodeRep (CLbl _ kind)                  = kind
-getAmodeRep (CCharLike _)                  = PtrRep
-getAmodeRep (CIntLike _)                   = PtrRep
-getAmodeRep (CLit lit)                     = literalPrimRep lit
-getAmodeRep (CMacroExpr kind _ _)          = kind
-getAmodeRep (CJoinPoint _)                 = panic "getAmodeRep:CJoinPoint"
-\end{code}
-
-@mixedTypeLocn@ tells whether an amode identifies an ``StgWord''
-location; that is, one which can contain values of various types.
-
-\begin{code}
-mixedTypeLocn :: CAddrMode -> Bool
-
-mixedTypeLocn (CVal (NodeRel _) _)     = True
-mixedTypeLocn (CVal (SpRel _)   _)     = True
-mixedTypeLocn (CVal (HpRel _)  _)      = True
-mixedTypeLocn other                    = False -- All the rest
-\end{code}
-
-@mixedPtrLocn@ tells whether an amode identifies a
-location which can contain values of various pointer types.
-
-\begin{code}
-mixedPtrLocn :: CAddrMode -> Bool
-
-mixedPtrLocn (CVal (SpRel _)  _)       = True
-mixedPtrLocn other                     = False -- All the rest
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[AbsCUtils-flattening]{Flatten Abstract~C}
-%*                                                                     *
-%************************************************************************
-
-The following bits take ``raw'' Abstract~C, which may have all sorts of
-nesting, and flattens it into one long @AbsCStmtList@.  Mainly,
-@CClosureInfos@ and code for switches are pulled out to the top level.
-
-The various functions herein tend to produce
-\begin{enumerate}
-\item
-A {\em flattened} \tr{<something>} of interest for ``here'', and
-\item
-Some {\em unflattened} Abstract~C statements to be carried up to the
-top-level.  The only real reason (now) that it is unflattened is
-because it means the recursive flattening can be done in just one
-place rather than having to remember lots of places.
-\end{enumerate}
-
-Care is taken to reduce the occurrence of forward references, while still
-keeping laziness a much as possible.  Essentially, this means that:
-\begin{itemize}
-\item
-{\em All} the top-level C statements resulting from flattening a
-particular AbsC statement (whether the latter is nested or not) appear
-before {\em any} of the code for a subsequent AbsC statement;
-\item
-but stuff nested within any AbsC statement comes
-out before the code for the statement itself.
-\end{itemize}
-
-The ``stuff to be carried up'' always includes a label: a
-@CStaticClosure@, @CRetDirect@, @CFlatRetVector@, or
-@CCodeBlock@.  The latter turns into a C function, and is never
-actually produced by the code generator.  Rather it always starts life
-as a @CCodeBlock@ addressing mode; when such an addr mode is
-flattened, the ``tops'' stuff is a @CCodeBlock@.
-
-\begin{code}
-flattenAbsC :: UniqSupply -> AbstractC -> AbstractC
-
-flattenAbsC us abs_C
-  = case (initFlt us (flatAbsC abs_C)) of { (here, tops) ->
-    here `mkAbsCStmts` tops }
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsubsection{Flattening monadery}
-%*                                                                     *
-%************************************************************************
-
-The flattener is monadised.  It's just a @UniqueSupply@.
-
-\begin{code}
-type FlatM result =  UniqSupply -> result
-
-initFlt :: UniqSupply -> FlatM a -> a
-
-initFlt init_us m = m init_us
-
-{-# INLINE thenFlt #-}
-{-# INLINE returnFlt #-}
-
-thenFlt :: FlatM a -> (a -> FlatM b) -> FlatM b
-
-thenFlt expr cont us
-  = case (splitUniqSupply us)   of { (s1, s2) ->
-    case (expr s1)             of { result ->
-    cont result s2 }}
-
-returnFlt :: a -> FlatM a
-returnFlt result us = result
-
-mapFlt :: (a -> FlatM b) -> [a] -> FlatM [b]
-
-mapFlt f []     = returnFlt []
-mapFlt f (x:xs)
-  = f x         `thenFlt` \ r  ->
-    mapFlt f xs `thenFlt` \ rs ->
-    returnFlt (r:rs)
-
-mapAndUnzipFlt  :: (a -> FlatM (b,c))   -> [a] -> FlatM ([b],[c])
-
-mapAndUnzipFlt f [] = returnFlt ([],[])
-mapAndUnzipFlt f (x:xs)
-  = f x                        `thenFlt` \ (r1,  r2)  ->
-    mapAndUnzipFlt f xs        `thenFlt` \ (rs1, rs2) ->
-    returnFlt (r1:rs1, r2:rs2)
-
-getUniqFlt :: FlatM Unique
-getUniqFlt us = uniqFromSupply us
-
-getUniqsFlt :: FlatM [Unique]
-getUniqsFlt us = uniqsFromSupply us
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsubsection{Flattening the top level}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-flatAbsC :: AbstractC
-        -> FlatM (AbstractC,   -- Stuff to put inline          [Both are fully
-                  AbstractC)   -- Stuff to put at top level     flattened]
-
-flatAbsC AbsCNop = returnFlt (AbsCNop, AbsCNop)
-
-flatAbsC (AbsCStmts s1 s2)
-  = flatAbsC s1        `thenFlt` \ (inline_s1, top_s1) ->
-    flatAbsC s2        `thenFlt` \ (inline_s2, top_s2) ->
-    returnFlt (mkAbsCStmts inline_s1 inline_s2,
-              mkAbsCStmts top_s1    top_s2)
-
-flatAbsC (CClosureInfoAndCode cl_info entry)
-  = flatAbsC entry             `thenFlt` \ (entry_heres, entry_tops) ->
-    returnFlt (AbsCNop, mkAbstractCs [entry_tops, 
-       CClosureInfoAndCode cl_info entry_heres]
-    )
-
-flatAbsC (CCodeBlock lbl abs_C)
-  = flatAbsC abs_C         `thenFlt` \ (absC_heres, absC_tops) ->
-    returnFlt (AbsCNop, absC_tops `mkAbsCStmts` CCodeBlock lbl absC_heres)
-
-flatAbsC (CRetDirect uniq slow_code srt liveness)
-  = flatAbsC slow_code         `thenFlt` \ (heres, tops) ->
-    returnFlt (AbsCNop, 
-               mkAbstractCs [ tops, CRetDirect uniq heres srt liveness ])
-
-flatAbsC (CSwitch discrim alts deflt)
-  = mapAndUnzipFlt flat_alt alts `thenFlt` \ (flat_alts, flat_alts_tops) ->
-    flatAbsC deflt              `thenFlt` \ (flat_def_alt, def_tops) ->
-    returnFlt (
-      CSwitch discrim flat_alts flat_def_alt,
-      mkAbstractCs (def_tops : flat_alts_tops)
-    )
-  where
-    flat_alt (tag, absC)
-      = flatAbsC absC  `thenFlt` \ (alt_heres, alt_tops) ->
-       returnFlt ( (tag, alt_heres), alt_tops )
-
-flatAbsC stmt@(COpStmt results (StgFCallOp (CCall ccall@(CCallSpec target _ _)) uniq) args _)
-  |  is_dynamic                       -- Emit a typedef if its a dynamic call
-     || (opt_EmitCExternDecls) -- or we want extern decls
-  = returnFlt (stmt, CCallTypedef is_dynamic ccall uniq results args)
-  where
-    is_dynamic = isDynamicTarget target
-
-flatAbsC stmt@(CSimultaneous abs_c)
-  = flatAbsC abs_c             `thenFlt` \ (stmts_here, tops) ->
-    doSimultaneously stmts_here        `thenFlt` \ new_stmts_here ->
-    returnFlt (new_stmts_here, tops)
-
-flatAbsC stmt@(CCheck macro amodes code)
-  = flatAbsC code              `thenFlt` \ (code_here, code_tops) ->
-    returnFlt (CCheck macro amodes code_here, code_tops)
-
--- the TICKY_CTR macro always needs to be hoisted out to the top level. 
--- This is a HACK.
-flatAbsC stmt@(CCallProfCtrMacro str amodes)
-  | str == FSLIT("TICK_CTR")   = returnFlt (AbsCNop, stmt)
-  | otherwise                  = returnFlt (stmt, AbsCNop)
-
--- Some statements need no flattening at all:
-flatAbsC stmt@(CMacroStmt macro amodes)         = returnFlt (stmt, AbsCNop)
-flatAbsC stmt@(CCallProfCCMacro str amodes)     = returnFlt (stmt, AbsCNop)
-flatAbsC stmt@(CAssign dest source)             = returnFlt (stmt, AbsCNop)
-flatAbsC stmt@(CJump target)                    = returnFlt (stmt, AbsCNop)
-flatAbsC stmt@(CFallThrough target)             = returnFlt (stmt, AbsCNop)
-flatAbsC stmt@(CReturn target return_info)      = returnFlt (stmt, AbsCNop)
-flatAbsC stmt@(CInitHdr a b cc sz)              = returnFlt (stmt, AbsCNop)
-flatAbsC stmt@(CMachOpStmt res mop args m_vols)  = returnFlt (stmt, AbsCNop)
-flatAbsC stmt@(COpStmt results (StgFCallOp _ _) args vol_regs) 
-                                                 = returnFlt (stmt, AbsCNop)
-flatAbsC stmt@(COpStmt results (StgPrimOp op) args vol_regs) 
-   = dscCOpStmt (filter non_void_amode results) op 
-                (filter non_void_amode args) vol_regs  
-                               `thenFlt` \ simpl ->
-     case simpl of
-        COpStmt _ _ _ _ -> panic "flatAbsC - dscCOpStmt"   -- make sure we don't loop!
-        other           -> flatAbsC other
-     {-
-        A gruesome hack for printing the names of inline primops when they
-        are used. 
-                                  oink other
-     where
-        oink xxx 
-            = getUniqFlt `thenFlt` \ uu ->
-              flatAbsC (CSequential [moo uu (showSDoc (ppr op)), xxx])
-
-        moo uu op_str
-           = COpStmt 
-                []
-                (StgFCallOp
-                    (CCall (CCallSpec (CasmTarget (mkFastString (mktxt op_str))) 
-                                      defaultCCallConv (PlaySafe False)))
-                    uu
-                )
-                [CReg VoidReg]
-                []
-        mktxt op_str
-            = " asm(\"pushal;\"); printf(\"%%s\\n\",\"" ++ op_str ++ "\"); asm(\"popal\"); "
-     -}
-
-flatAbsC (CSequential abcs)
-  = mapAndUnzipFlt flatAbsC abcs `thenFlt` \ (inlines, tops) ->
-    returnFlt (CSequential inlines, foldr AbsCStmts AbsCNop tops)
-
-
--- Some statements only make sense at the top level, so we always float
--- them.  This probably isn't necessary.
-flatAbsC stmt@(CStaticClosure _ _ _ _)                 = returnFlt (AbsCNop, stmt)
-flatAbsC stmt@(CClosureTbl _)                  = returnFlt (AbsCNop, stmt)
-flatAbsC stmt@(CSRT _ _)                       = returnFlt (AbsCNop, stmt)
-flatAbsC stmt@(CSRTDesc _ _ _ _ _)             = returnFlt (AbsCNop, stmt)
-flatAbsC stmt@(CBitmap _)                      = returnFlt (AbsCNop, stmt)
-flatAbsC stmt@(CCostCentreDecl _ _)            = returnFlt (AbsCNop, stmt)
-flatAbsC stmt@(CCostCentreStackDecl _)         = returnFlt (AbsCNop, stmt)
-flatAbsC stmt@(CSplitMarker)                   = returnFlt (AbsCNop, stmt)
-flatAbsC stmt@(CRetVector _ _ _ _)              = returnFlt (AbsCNop, stmt)
-flatAbsC stmt@(CModuleInitBlock _ _ _)          = returnFlt (AbsCNop, stmt)
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[flat-simultaneous]{Doing things simultaneously}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-doSimultaneously :: AbstractC -> FlatM AbstractC
-\end{code}
-
-Generate code to perform the @CAssign@s and @COpStmt@s in the
-input simultaneously, using temporary variables when necessary.
-
-We use the strongly-connected component algorithm, in which
-       * the vertices are the statements
-       * an edge goes from s1 to s2 iff
-               s1 assigns to something s2 uses
-         that is, if s1 should *follow* s2 in the final order
-
-\begin{code}
-type CVertex = (Int, AbstractC)  -- Give each vertex a unique number,
-                                -- for fast comparison
-
-doSimultaneously abs_c
-  = let
-       enlisted = en_list abs_c
-    in
-    case enlisted of -- it's often just one stmt
-      []  -> returnFlt AbsCNop
-      [x] -> returnFlt x
-      _   -> doSimultaneously1 (zip [(1::Int)..] enlisted)
-
--- en_list puts all the assignments in a list, filtering out Nops and
--- assignments which do nothing
-en_list AbsCNop                                      = []
-en_list (AbsCStmts a1 a2)                    = en_list a1 ++ en_list a2
-en_list (CAssign am1 am2) | sameAmode am1 am2 = []
-en_list other                                = [other]
-
-sameAmode :: CAddrMode -> CAddrMode -> Bool
--- ToDo: Move this function, or make CAddrMode an instance of Eq
--- At the moment we put in just enough to catch the cases we want:
---     the second (destination) argument is always a CVal.
-sameAmode (CReg r1)                 (CReg r2)               = r1 == r2
-sameAmode (CVal (SpRel r1) _) (CVal (SpRel r2) _)           = r1 ==# r2
-sameAmode other1                    other2                  = False
-
-doSimultaneously1 :: [CVertex] -> FlatM AbstractC
-doSimultaneously1 vertices
-  = let
-       edges = [ (vertex, key1, edges_from stmt1)
-               | vertex@(key1, stmt1) <- vertices
-               ]
-       edges_from stmt1 = [ key2 | (key2, stmt2) <- vertices, 
-                                   stmt1 `should_follow` stmt2
-                          ]
-       components = stronglyConnComp edges
-
-       -- do_components deal with one strongly-connected component
-               -- Not cyclic, or singleton?  Just do it
-       do_component (AcyclicSCC (n,abs_c))  = returnFlt abs_c
-       do_component (CyclicSCC [(n,abs_c)]) = returnFlt abs_c
-
-               -- Cyclic?  Then go via temporaries.  Pick one to
-               -- break the loop and try again with the rest.
-       do_component (CyclicSCC ((n,first_stmt) : rest))
-         = doSimultaneously1 rest      `thenFlt` \ abs_cs ->
-           go_via_temps first_stmt     `thenFlt` \ (to_temps, from_temps) ->
-           returnFlt (mkAbstractCs [to_temps, abs_cs, from_temps])
-
-       go_via_temps (CAssign dest src)
-         = getUniqFlt                  `thenFlt` \ uniq ->
-           let
-               the_temp = CTemp uniq (getAmodeRep dest)
-           in
-           returnFlt (CAssign the_temp src, CAssign dest the_temp)
-
-       go_via_temps (COpStmt dests op srcs vol_regs)
-         = getUniqsFlt                 `thenFlt` \ uniqs ->
-           let
-               the_temps = zipWith (\ u d -> CTemp u (getAmodeRep d)) uniqs dests
-           in
-           returnFlt (COpStmt the_temps op srcs vol_regs,
-                      mkAbstractCs (zipWith CAssign dests the_temps))
-    in
-    mapFlt do_component components `thenFlt` \ abs_cs ->
-    returnFlt (mkAbstractCs abs_cs)
-
-  where
-    should_follow :: AbstractC -> AbstractC -> Bool
-    (CAssign dest1 _) `should_follow` (CAssign _ src2)
-      = dest1 `conflictsWith` src2
-    (COpStmt dests1 _ _ _) `should_follow` (CAssign _ src2)
-      = or [dest1 `conflictsWith` src2 | dest1 <- dests1]
-    (CAssign dest1 _)`should_follow` (COpStmt _ _ srcs2 _)
-      = or [dest1 `conflictsWith` src2 | src2 <- srcs2]
-    (COpStmt dests1 _ _ _) `should_follow` (COpStmt _ _ srcs2 _)
-      = or [dest1 `conflictsWith` src2 | dest1 <- dests1, src2 <- srcs2]
-\end{code}
-
-@conflictsWith@ tells whether an assignment to its first argument will
-screw up an access to its second.
-
-\begin{code}
-conflictsWith :: CAddrMode -> CAddrMode -> Bool
-(CReg reg1)       `conflictsWith` (CReg reg2)          = reg1 == reg2
-(CReg reg)        `conflictsWith` (CVal reg_rel _)     = reg `regConflictsWithRR` reg_rel
-(CReg reg)        `conflictsWith` (CAddr reg_rel)      = reg `regConflictsWithRR` reg_rel
-(CTemp u1 _)      `conflictsWith` (CTemp u2 _)         = u1 == u2
-(CVal reg_rel1 k1) `conflictsWith` (CVal reg_rel2 k2)
-  = rrConflictsWithRR (getPrimRepSize k1) (getPrimRepSize k2) reg_rel1 reg_rel2
-
-other1           `conflictsWith` other2                = False
--- CAddr and literals are impossible on the LHS of an assignment
-
-regConflictsWithRR :: MagicId -> RegRelative -> Bool
-
-regConflictsWithRR (VanillaReg k n) (NodeRel _)        | n ==# (_ILIT 1)    = True
-regConflictsWithRR Sp  (SpRel _)       = True
-regConflictsWithRR Hp  (HpRel _)       = True
-regConflictsWithRR _   _               = False
-
-rrConflictsWithRR :: Int -> Int                        -- Sizes of two things
-                 -> RegRelative -> RegRelative -- The two amodes
-                 -> Bool
-
-rrConflictsWithRR s1b s2b rr1 rr2 = rr rr1 rr2
-  where
-    s1 = iUnbox s1b
-    s2 = iUnbox s2b
-
-    rr (SpRel o1)    (SpRel o2)
-       | s1 ==# (_ILIT 0) || s2 ==# (_ILIT 0) = False -- No conflict if either is size zero
-       | s1 ==# (_ILIT 1)  && s2 ==# (_ILIT 1) = o1 ==# o2
-       | otherwise          = (o1 +# s1) >=# o2  &&
-                              (o2 +# s2) >=# o1
-
-    rr (NodeRel o1)     (NodeRel o2)
-       | s1 ==# (_ILIT 0) || s2 ==# (_ILIT 0) = False -- No conflict if either is size zero
-       | s1 ==# (_ILIT 1) && s2 ==# (_ILIT 1) = o1 ==# o2
-       | otherwise          = True             -- Give up
-
-    rr (HpRel _)        (HpRel _)    = True    -- Give up (ToDo)
-
-    rr other1           other2       = False
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[flat-primops]{Translating COpStmts to CMachOpStmts}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-
--- We begin with some helper functions.  The main Dude here is
--- dscCOpStmt, defined a little further down.
-
-------------------------------------------------------------------------------
-
--- Assumes no volatiles
--- Creates
---     res = arg >> (bits-per-word / 2)   when little-endian
--- or
---     res = arg & ((1 << (bits-per-word / 2)) - 1) when big-endian
---
--- In other words, if arg had been stored in memory, makes res the 
--- halfword of arg which would have had the higher address.  This is
--- why it needs to take into account endianness.
---
-mkHalfWord_HIADDR res arg
-   = mkTemp WordRep                    `thenFlt` \ t_hw_mask1 ->
-     mkTemp WordRep                    `thenFlt` \ t_hw_mask2 ->
-     let 
-        hw_shift = mkIntCLit (wORD_SIZE_IN_BITS `quot` 2)
-
-#        if WORDS_BIGENDIAN
-         a_hw_mask1
-            = CMachOpStmt t_hw_mask1
-                          MO_Nat_Shl [CLit (mkMachWord 1), hw_shift] Nothing
-         a_hw_mask2
-            = CMachOpStmt t_hw_mask2
-                          MO_Nat_Sub [t_hw_mask1, CLit (mkMachWord 1)] Nothing
-         final
-            = CSequential [ a_hw_mask1, a_hw_mask2,
-                 CMachOpStmt res MO_Nat_And [arg, t_hw_mask2] Nothing
-              ]
-#        else
-         final = CMachOpStmt res MO_Nat_Shr [arg, hw_shift] Nothing
-#        endif
-     in
-         returnFlt final
-
-
-mkTemp :: PrimRep -> FlatM CAddrMode
-mkTemp rep 
-   = getUniqFlt `thenFlt` \ uniq -> returnFlt (CTemp uniq rep)
-
-mkTemps = mapFlt mkTemp
-
--- Sigh.  This is done in 3 seperate places.  Should be
--- commoned up (here, in pprAbsC of COpStmt, and presumably
--- somewhere in the NCG).
-non_void_amode amode 
-   = case getAmodeRep amode of
-        VoidRep -> False
-        k       -> True
-
--- Helpers for translating various minor variants of array indexing.
-
-mkDerefOff :: PrimRep -> CAddrMode -> Int -> CAddrMode
-mkDerefOff rep base off
-   = CVal (CIndex base (CLit (mkMachInt (toInteger off))) rep) rep
-
-mkNoDerefOff :: PrimRep -> CAddrMode -> Int -> CAddrMode
-mkNoDerefOff rep base off
-   = CAddr (CIndex base (CLit (mkMachInt (toInteger off))) rep)
-
-
--- Generates an address as follows
---    base + sizeof(machine_word)*offw + sizeof(rep)*idx
-mk_OSBI_addr :: Int -> PrimRep -> CAddrMode -> CAddrMode -> RegRelative
-mk_OSBI_addr offw rep base idx
-   = CIndex (CAddr (CIndex base idx rep)) 
-            (CLit (mkMachWord (fromIntegral offw))) 
-            PtrRep
-
-mk_OSBI_ref :: Int -> PrimRep -> CAddrMode -> CAddrMode -> CAddrMode
-mk_OSBI_ref offw rep base idx
-   = CVal (mk_OSBI_addr offw rep base idx) rep
-
-
-doIndexOffForeignObjOp maybe_post_read_cast rep res addr idx
-   = mkBasicIndexedRead 0 maybe_post_read_cast rep res (mkDerefOff WordRep addr fixedHdrSize) idx
-
-doIndexOffAddrOp maybe_post_read_cast rep res addr idx
-   = mkBasicIndexedRead 0 maybe_post_read_cast rep res addr idx
-
-doIndexByteArrayOp maybe_post_read_cast rep res addr idx
-   = mkBasicIndexedRead arrWordsHdrSize maybe_post_read_cast rep res addr idx
-
-doReadPtrArrayOp res addr idx
-   = mkBasicIndexedRead arrPtrsHdrSize Nothing PtrRep res addr idx
-
-
-doWriteOffAddrOp maybe_pre_write_cast rep addr idx val
-   = mkBasicIndexedWrite 0 maybe_pre_write_cast rep addr idx val
-
-doWriteByteArrayOp maybe_pre_write_cast rep addr idx val
-   = mkBasicIndexedWrite arrWordsHdrSize maybe_pre_write_cast rep addr idx val
-
-doWritePtrArrayOp addr idx val
-   = mkBasicIndexedWrite arrPtrsHdrSize Nothing PtrRep addr idx val
-
-
-
-mkBasicIndexedRead offw Nothing read_rep res base idx
-   = returnFlt (
-        CAssign res (mk_OSBI_ref offw read_rep base idx)
-     )
-mkBasicIndexedRead offw (Just cast_to_mop) read_rep res base idx
-   = mkTemp read_rep                   `thenFlt` \ tmp ->
-     (returnFlt . CSequential) [
-        CAssign tmp (mk_OSBI_ref offw read_rep base idx),
-        CMachOpStmt res cast_to_mop [tmp] Nothing
-     ]
-
-mkBasicIndexedWrite offw Nothing write_rep base idx val
-   = returnFlt (
-        CAssign (mk_OSBI_ref offw write_rep base idx) val
-     )
-mkBasicIndexedWrite offw (Just cast_to_mop) write_rep base idx val
-   = mkTemp write_rep                  `thenFlt` \ tmp ->
-     (returnFlt . CSequential) [
-        CMachOpStmt tmp cast_to_mop [val] Nothing,
-        CAssign (mk_OSBI_ref offw write_rep base idx) tmp
-     ]
-
-
--- Simple dyadic op but one for which we need to cast first arg to
--- be sure of correctness
-translateOp_dyadic_cast1 mop res cast_arg1_to arg1 arg2 vols
-   = mkTemp cast_arg1_to               `thenFlt` \ arg1casted ->
-     (returnFlt . CSequential) [
-        CAssign arg1casted arg1,
-        CMachOpStmt res mop [arg1casted,arg2]
-           (if isDefinitelyInlineMachOp mop then Nothing else Just vols)
-     ]
-
--- IA64 mangler doesn't place tables next to code
-tablesNextToCode :: Bool
-#ifdef ia64_TARGET_ARCH
-tablesNextToCode = False
-#else
-tablesNextToCode = not opt_Unregisterised
-#endif
-
-------------------------------------------------------------------------------
-
--- This is the main top-level desugarer PrimOps into MachOps.  First we
--- handle various awkward cases specially.  The remaining easy cases are
--- then handled by translateOp, defined below.
-
-
-dscCOpStmt :: [CAddrMode]      -- Results
-           -> PrimOp
-           -> [CAddrMode]      -- Arguments
-           -> [MagicId]                -- Potentially volatile/live registers
-                               -- (to save/restore around the op)
-           -> FlatM AbstractC
-
-
-dscCOpStmt [res_r,res_c] IntAddCOp [aa,bb] vols
-{- 
-   With some bit-twiddling, we can define int{Add,Sub}Czh portably in
-   C, and without needing any comparisons.  This may not be the
-   fastest way to do it - if you have better code, please send it! --SDM
-  
-   Return : r = a + b,  c = 0 if no overflow, 1 on overflow.
-  
-   We currently don't make use of the r value if c is != 0 (i.e. 
-   overflow), we just convert to big integers and try again.  This
-   could be improved by making r and c the correct values for
-   plugging into a new J#.  
-   
-   { r = ((I_)(a)) + ((I_)(b));                                        \
-     c = ((StgWord)(~(((I_)(a))^((I_)(b))) & (((I_)(a))^r)))   \
-         >> (BITS_IN (I_) - 1);                                        \
-   } 
-   Wading through the mass of bracketry, it seems to reduce to:
-   c = ( (~(a^b)) & (a^r) ) >>unsigned (BITS_IN(I_)-1)
-
-   SSA-form:
-   t1 = a^b
-   t2 = ~t1
-   t3 = a^r
-   t4 = t2 & t3
-   c  = t4 >>unsigned BITS_IN(I_)-1
--}
-   = mkTemps [IntRep,IntRep,IntRep,IntRep]     `thenFlt` \ [t1,t2,t3,t4] ->
-     let bpw1 = mkIntCLit (wORD_SIZE_IN_BITS - 1) in
-     (returnFlt . CSequential) [
-        CMachOpStmt res_r MO_Nat_Add [aa,bb] Nothing,
-        CMachOpStmt t1 MO_Nat_Xor [aa,bb] Nothing,
-        CMachOpStmt t2 MO_Nat_Not [t1] Nothing,
-        CMachOpStmt t3 MO_Nat_Xor [aa,res_r] Nothing,
-        CMachOpStmt t4 MO_Nat_And [t2,t3] Nothing,
-        CMachOpStmt res_c MO_Nat_Shr [t4, bpw1] Nothing
-     ]
-
-
-dscCOpStmt [res_r,res_c] IntSubCOp [aa,bb] vols
-{- Similarly:
-   #define subIntCzh(r,c,a,b)                                  \
-   { r = ((I_)(a)) - ((I_)(b));                                        \
-     c = ((StgWord)((((I_)(a))^((I_)(b))) & (((I_)(a))^r)))    \
-         >> (BITS_IN (I_) - 1);                                        \
-   }
-
-   c =  ((a^b) & (a^r)) >>unsigned (BITS_IN(I_)-1)
-
-   t1 = a^b
-   t2 = a^r
-   t3 = t1 & t2
-   c  = t3 >>unsigned BITS_IN(I_)-1
--}
-   = mkTemps [IntRep,IntRep,IntRep]            `thenFlt` \ [t1,t2,t3] ->
-     let bpw1 = mkIntCLit (wORD_SIZE_IN_BITS - 1) in
-     (returnFlt . CSequential) [
-        CMachOpStmt res_r MO_Nat_Sub [aa,bb] Nothing,
-        CMachOpStmt t1 MO_Nat_Xor [aa,bb] Nothing,
-        CMachOpStmt t2 MO_Nat_Xor [aa,res_r] Nothing,
-        CMachOpStmt t3 MO_Nat_And [t1,t2] Nothing,
-        CMachOpStmt res_c MO_Nat_Shr [t3, bpw1] Nothing
-     ]
-
-
--- #define parzh(r,node) r = 1
-dscCOpStmt [res] ParOp [arg] vols
-   = returnFlt
-        (CAssign res (CLit (mkMachInt 1)))
-
--- #define readMutVarzh(r,a)    r=(P_)(((StgMutVar *)(a))->var)
-dscCOpStmt [res] ReadMutVarOp [mutv] vols
-   = returnFlt
-        (CAssign res (mkDerefOff PtrRep mutv fixedHdrSize))
-
--- #define writeMutVarzh(a,v)       (P_)(((StgMutVar *)(a))->var)=(v)
-dscCOpStmt [] WriteMutVarOp [mutv,var] vols
-   = returnFlt
-        (CAssign (mkDerefOff PtrRep mutv fixedHdrSize) var)
-
-
--- #define ForeignObj_CLOSURE_DATA(c)  (((StgForeignObj *)c)->data)
--- #define foreignObjToAddrzh(r,fo)    r=ForeignObj_CLOSURE_DATA(fo)
-dscCOpStmt [res] ForeignObjToAddrOp [fo] vols
-   = returnFlt
-        (CAssign res (mkDerefOff PtrRep fo fixedHdrSize))
-
--- #define writeForeignObjzh(res,datum) \
---    (ForeignObj_CLOSURE_DATA(res) = (P_)(datum))
-dscCOpStmt [] WriteForeignObjOp [fo,addr] vols
-   = returnFlt
-        (CAssign (mkDerefOff PtrRep fo fixedHdrSize) addr)
-
-
--- #define sizzeofByteArrayzh(r,a) \
---     r = (((StgArrWords *)(a))->words * sizeof(W_))
-dscCOpStmt [res] SizeofByteArrayOp [arg] vols
-   = mkTemp WordRep                    `thenFlt` \ w ->
-     (returnFlt . CSequential) [
-        CAssign w (mkDerefOff WordRep arg fixedHdrSize),
-        CMachOpStmt w MO_NatU_Mul [w, mkIntCLit wORD_SIZE] (Just vols),
-        CAssign res w
-     ]
-
--- #define sizzeofMutableByteArrayzh(r,a) \
---      r = (((StgArrWords *)(a))->words * sizeof(W_))
-dscCOpStmt [res] SizeofMutableByteArrayOp [arg] vols
-   = dscCOpStmt [res] SizeofByteArrayOp [arg] vols
-
-
--- #define touchzh(o)                  /* nothing */
-dscCOpStmt [] TouchOp [arg] vols
-   = returnFlt AbsCNop
-
--- #define byteArrayContentszh(r,a) r = BYTE_ARR_CTS(a)
-dscCOpStmt [res] ByteArrayContents_Char [arg] vols
-   = mkTemp PtrRep                     `thenFlt` \ ptr ->
-     (returnFlt . CSequential) [
-         CMachOpStmt ptr MO_NatU_to_NatP [arg] Nothing,
-         CAssign ptr (mkNoDerefOff WordRep ptr arrWordsHdrSize),
-         CAssign res ptr
-     ]
-
--- #define stableNameToIntzh(r,s)   (r = ((StgStableName *)s)->sn)
-dscCOpStmt [res] StableNameToIntOp [arg] vols
-   = returnFlt 
-        (CAssign res (mkDerefOff WordRep arg fixedHdrSize))
-
--- #define eqStableNamezh(r,sn1,sn2)                                   \
---    (r = (((StgStableName *)sn1)->sn == ((StgStableName *)sn2)->sn))
-dscCOpStmt [res] EqStableNameOp [arg1,arg2] vols
-   = mkTemps [WordRep, WordRep]        `thenFlt` \ [sn1,sn2] ->
-     (returnFlt . CSequential) [
-        CAssign sn1 (mkDerefOff WordRep arg1 fixedHdrSize),
-        CAssign sn2 (mkDerefOff WordRep arg2 fixedHdrSize),
-        CMachOpStmt res MO_Nat_Eq [sn1,sn2] Nothing
-     ]
-
-dscCOpStmt [res] ReallyUnsafePtrEqualityOp [arg1,arg2] vols
-   = mkTemps [WordRep, WordRep]        `thenFlt` \ [w1,w2] ->
-     (returnFlt . CSequential) [
-       CMachOpStmt w1 MO_NatP_to_NatU [arg1] Nothing,
-       CMachOpStmt w2 MO_NatP_to_NatU [arg2] Nothing,
-        CMachOpStmt res MO_Nat_Eq [w1,w2] Nothing{- because it's inline? -}
-     ]
-
--- #define addrToHValuezh(r,a) r=(P_)a
-dscCOpStmt [res] AddrToHValueOp [arg] vols
-   = returnFlt 
-        (CAssign res arg)
-
--- #define dataToTagzh(r,a)  r=(GET_TAG(((StgClosure *)a)->header.info))
--- 
---   In the unregisterised case, we don't attempt to compute the location
---   of the tag halfword, just a macro. For this build, fixing on layout
---   info has only got drawbacks.
---
---   Should this arrangement deeply offend you for some reason, code which
---   computes the offset can be found below also.
---      -- sof 3/02
--- 
-dscCOpStmt [res] DataToTagOp [arg] vols
-   | not tablesNextToCode
-   = returnFlt (CMacroStmt DATA_TO_TAGZH [res,arg])
-   | otherwise
-   = mkTemps [PtrRep, WordRep]         `thenFlt` \ [t_infoptr, t_theword] ->
-     mkHalfWord_HIADDR res t_theword   `thenFlt` \ select_ops ->
-     (returnFlt . CSequential) [
-        CAssign t_infoptr (mkDerefOff PtrRep arg 0),
-        {-
-          Get at the tag within the info table; two cases to consider:
-          
-             - reversed info tables next to the entry point code;
-               one word above the end of the info table (which is
-               what t_infoptr is really pointing to).
-             - info tables with their entry points stored somewhere else,
-               which is how the unregisterised (nee TABLES_NEXT_TO_CODE)
-               world operates.
-               
-               The t_infoptr points to the start of the info table, so add
-               the length of the info table & subtract one word.
-        -}
-        CAssign t_theword (mkDerefOff WordRep t_infoptr (-1)),
-{- UNUSED - see above comment.
-                                    (if opt_Unregisterised then 
-                                        (fixedItblSize - 1)
-                                     else (-1))),
--}
-        select_ops
-     ]
-
-
-{- Freezing arrays-of-ptrs requires changing an info table, for the
-   benefit of the generational collector.  It needs to scavenge mutable
-   objects, even if they are in old space.  When they become immutable,
-   they can be removed from this scavenge list.         -}
-
--- #define unsafeFreezzeArrayzh(r,a)                                   \
---     {                                                               \
---        SET_INFO((StgClosure *)a,&stg_MUT_ARR_PTRS_FROZEN_info);        \
---     r = a;                                                          \
---     }
-dscCOpStmt [res] UnsafeFreezeArrayOp [arg] vols
-   = (returnFlt . CSequential) [
-        CAssign (mkDerefOff PtrRep arg 0) (CLbl mkMAP_FROZEN_infoLabel PtrRep),
-        CAssign res arg
-     ]
-
--- #define unsafeFreezzeByteArrayzh(r,a)       r=(a)
-dscCOpStmt [res] UnsafeFreezeByteArrayOp [arg] vols
-   = returnFlt
-        (CAssign res arg)
-
--- This ought to be trivial, but it's difficult to insert the casts
--- required to keep the C compiler happy.
-dscCOpStmt [r] AddrRemOp [a1,a2] vols 
-   = mkTemp WordRep                    `thenFlt` \ a1casted ->
-     (returnFlt . CSequential) [
-        CMachOpStmt a1casted MO_NatP_to_NatU [a1] Nothing,
-        CMachOpStmt r MO_NatU_Rem [a1casted,a2] Nothing
-     ]
-
--- not handled by translateOp because they need casts
-dscCOpStmt [r] SllOp [a1,a2] vols 
-   = translateOp_dyadic_cast1 MO_Nat_Shl r WordRep a1 a2 vols
-dscCOpStmt [r] SrlOp [a1,a2] vols 
-   = translateOp_dyadic_cast1 MO_Nat_Shr r WordRep a1 a2 vols
-
-dscCOpStmt [r] ISllOp [a1,a2] vols 
-   = translateOp_dyadic_cast1 MO_Nat_Shl r IntRep a1 a2 vols
-dscCOpStmt [r] ISrlOp [a1,a2] vols 
-   = translateOp_dyadic_cast1 MO_Nat_Shr r IntRep a1 a2 vols
-dscCOpStmt [r] ISraOp [a1,a2] vols 
-   = translateOp_dyadic_cast1 MO_Nat_Sar r IntRep a1 a2 vols
-
--- Reading/writing pointer arrays
-
-dscCOpStmt [r] ReadArrayOp  [obj,ix]   vols  = doReadPtrArrayOp r obj ix
-dscCOpStmt [r] IndexArrayOp [obj,ix]   vols  = doReadPtrArrayOp r obj ix
-dscCOpStmt []  WriteArrayOp [obj,ix,v] vols  = doWritePtrArrayOp obj ix v
-
--- IndexXXXoffForeignObj
-
-dscCOpStmt [r] IndexOffForeignObjOp_Char      [a,i] vols = doIndexOffForeignObjOp (Just MO_8U_to_32U) Word8Rep r a i
-dscCOpStmt [r] IndexOffForeignObjOp_WideChar  [a,i] vols = doIndexOffForeignObjOp Nothing Word32Rep r a i
-dscCOpStmt [r] IndexOffForeignObjOp_Int       [a,i] vols = doIndexOffForeignObjOp Nothing IntRep r a i
-dscCOpStmt [r] IndexOffForeignObjOp_Word      [a,i] vols = doIndexOffForeignObjOp Nothing WordRep r a i
-dscCOpStmt [r] IndexOffForeignObjOp_Addr      [a,i] vols = doIndexOffForeignObjOp Nothing AddrRep r a i
-dscCOpStmt [r] IndexOffForeignObjOp_Float     [a,i] vols = doIndexOffForeignObjOp Nothing FloatRep r a i
-dscCOpStmt [r] IndexOffForeignObjOp_Double    [a,i] vols = doIndexOffForeignObjOp Nothing DoubleRep r a i
-dscCOpStmt [r] IndexOffForeignObjOp_StablePtr [a,i] vols = doIndexOffForeignObjOp Nothing StablePtrRep r a i
-
-dscCOpStmt [r] IndexOffForeignObjOp_Int8      [a,i] vols = doIndexOffForeignObjOp Nothing Int8Rep  r a i
-dscCOpStmt [r] IndexOffForeignObjOp_Int16     [a,i] vols = doIndexOffForeignObjOp Nothing Int16Rep r a i
-dscCOpStmt [r] IndexOffForeignObjOp_Int32     [a,i] vols = doIndexOffForeignObjOp Nothing Int32Rep r a i
-dscCOpStmt [r] IndexOffForeignObjOp_Int64     [a,i] vols = doIndexOffForeignObjOp Nothing Int64Rep r a i
-
-dscCOpStmt [r] IndexOffForeignObjOp_Word8     [a,i] vols = doIndexOffForeignObjOp Nothing Word8Rep  r a i
-dscCOpStmt [r] IndexOffForeignObjOp_Word16    [a,i] vols = doIndexOffForeignObjOp Nothing Word16Rep r a i
-dscCOpStmt [r] IndexOffForeignObjOp_Word32    [a,i] vols = doIndexOffForeignObjOp Nothing Word32Rep r a i
-dscCOpStmt [r] IndexOffForeignObjOp_Word64    [a,i] vols = doIndexOffForeignObjOp Nothing Word64Rep r a i
-
--- IndexXXXoffAddr
-
-dscCOpStmt [r] IndexOffAddrOp_Char      [a,i] vols = doIndexOffAddrOp (Just MO_8U_to_32U) Word8Rep r a i
-dscCOpStmt [r] IndexOffAddrOp_WideChar  [a,i] vols = doIndexOffAddrOp Nothing Word32Rep r a i
-dscCOpStmt [r] IndexOffAddrOp_Int       [a,i] vols = doIndexOffAddrOp Nothing IntRep r a i
-dscCOpStmt [r] IndexOffAddrOp_Word      [a,i] vols = doIndexOffAddrOp Nothing WordRep r a i
-dscCOpStmt [r] IndexOffAddrOp_Addr      [a,i] vols = doIndexOffAddrOp Nothing AddrRep r a i
-dscCOpStmt [r] IndexOffAddrOp_Float     [a,i] vols = doIndexOffAddrOp Nothing FloatRep r a i
-dscCOpStmt [r] IndexOffAddrOp_Double    [a,i] vols = doIndexOffAddrOp Nothing DoubleRep r a i
-dscCOpStmt [r] IndexOffAddrOp_StablePtr [a,i] vols = doIndexOffAddrOp Nothing StablePtrRep r a i
-
-dscCOpStmt [r] IndexOffAddrOp_Int8      [a,i] vols = doIndexOffAddrOp Nothing Int8Rep  r a i
-dscCOpStmt [r] IndexOffAddrOp_Int16     [a,i] vols = doIndexOffAddrOp Nothing Int16Rep r a i
-dscCOpStmt [r] IndexOffAddrOp_Int32     [a,i] vols = doIndexOffAddrOp Nothing Int32Rep r a i
-dscCOpStmt [r] IndexOffAddrOp_Int64     [a,i] vols = doIndexOffAddrOp Nothing Int64Rep r a i
-
-dscCOpStmt [r] IndexOffAddrOp_Word8     [a,i] vols = doIndexOffAddrOp Nothing Word8Rep  r a i
-dscCOpStmt [r] IndexOffAddrOp_Word16    [a,i] vols = doIndexOffAddrOp Nothing Word16Rep r a i
-dscCOpStmt [r] IndexOffAddrOp_Word32    [a,i] vols = doIndexOffAddrOp Nothing Word32Rep r a i
-dscCOpStmt [r] IndexOffAddrOp_Word64    [a,i] vols = doIndexOffAddrOp Nothing Word64Rep r a i
-
--- ReadXXXoffAddr, which are identical, for our purposes, to IndexXXXoffAddr.
-
-dscCOpStmt [r] ReadOffAddrOp_Char      [a,i] vols = doIndexOffAddrOp (Just MO_8U_to_32U) Word8Rep r a i
-dscCOpStmt [r] ReadOffAddrOp_WideChar  [a,i] vols = doIndexOffAddrOp Nothing Word32Rep r a i
-dscCOpStmt [r] ReadOffAddrOp_Int       [a,i] vols = doIndexOffAddrOp Nothing IntRep r a i
-dscCOpStmt [r] ReadOffAddrOp_Word      [a,i] vols = doIndexOffAddrOp Nothing WordRep r a i
-dscCOpStmt [r] ReadOffAddrOp_Addr      [a,i] vols = doIndexOffAddrOp Nothing AddrRep r a i
-dscCOpStmt [r] ReadOffAddrOp_Float     [a,i] vols = doIndexOffAddrOp Nothing FloatRep r a i
-dscCOpStmt [r] ReadOffAddrOp_Double    [a,i] vols = doIndexOffAddrOp Nothing DoubleRep r a i
-dscCOpStmt [r] ReadOffAddrOp_StablePtr [a,i] vols = doIndexOffAddrOp Nothing StablePtrRep r a i
-
-dscCOpStmt [r] ReadOffAddrOp_Int8      [a,i] vols = doIndexOffAddrOp Nothing Int8Rep  r a i
-dscCOpStmt [r] ReadOffAddrOp_Int16     [a,i] vols = doIndexOffAddrOp Nothing Int16Rep r a i
-dscCOpStmt [r] ReadOffAddrOp_Int32     [a,i] vols = doIndexOffAddrOp Nothing Int32Rep r a i
-dscCOpStmt [r] ReadOffAddrOp_Int64     [a,i] vols = doIndexOffAddrOp Nothing Int64Rep r a i
-
-dscCOpStmt [r] ReadOffAddrOp_Word8     [a,i] vols = doIndexOffAddrOp Nothing Word8Rep  r a i
-dscCOpStmt [r] ReadOffAddrOp_Word16    [a,i] vols = doIndexOffAddrOp Nothing Word16Rep r a i
-dscCOpStmt [r] ReadOffAddrOp_Word32    [a,i] vols = doIndexOffAddrOp Nothing Word32Rep r a i
-dscCOpStmt [r] ReadOffAddrOp_Word64    [a,i] vols = doIndexOffAddrOp Nothing Word64Rep r a i
-
--- IndexXXXArray
-
-dscCOpStmt [r] IndexByteArrayOp_Char      [a,i] vols = doIndexByteArrayOp (Just MO_8U_to_32U) Word8Rep r a i
-dscCOpStmt [r] IndexByteArrayOp_WideChar  [a,i] vols = doIndexByteArrayOp Nothing Word32Rep r a i
-dscCOpStmt [r] IndexByteArrayOp_Int       [a,i] vols = doIndexByteArrayOp Nothing IntRep r a i
-dscCOpStmt [r] IndexByteArrayOp_Word      [a,i] vols = doIndexByteArrayOp Nothing WordRep r a i
-dscCOpStmt [r] IndexByteArrayOp_Addr      [a,i] vols = doIndexByteArrayOp Nothing AddrRep r a i
-dscCOpStmt [r] IndexByteArrayOp_Float     [a,i] vols = doIndexByteArrayOp Nothing FloatRep r a i
-dscCOpStmt [r] IndexByteArrayOp_Double    [a,i] vols = doIndexByteArrayOp Nothing DoubleRep r a i
-dscCOpStmt [r] IndexByteArrayOp_StablePtr [a,i] vols = doIndexByteArrayOp Nothing StablePtrRep r a i
-
-dscCOpStmt [r] IndexByteArrayOp_Int8      [a,i] vols = doIndexByteArrayOp Nothing Int8Rep  r a i
-dscCOpStmt [r] IndexByteArrayOp_Int16     [a,i] vols = doIndexByteArrayOp Nothing Int16Rep  r a i
-dscCOpStmt [r] IndexByteArrayOp_Int32     [a,i] vols = doIndexByteArrayOp Nothing Int32Rep  r a i
-dscCOpStmt [r] IndexByteArrayOp_Int64     [a,i] vols = doIndexByteArrayOp Nothing Int64Rep  r a i
-
-dscCOpStmt [r] IndexByteArrayOp_Word8     [a,i] vols = doIndexByteArrayOp Nothing Word8Rep  r a i
-dscCOpStmt [r] IndexByteArrayOp_Word16    [a,i] vols = doIndexByteArrayOp Nothing Word16Rep  r a i
-dscCOpStmt [r] IndexByteArrayOp_Word32    [a,i] vols = doIndexByteArrayOp Nothing Word32Rep  r a i
-dscCOpStmt [r] IndexByteArrayOp_Word64    [a,i] vols = doIndexByteArrayOp Nothing Word64Rep  r a i
-
--- ReadXXXArray, identical to IndexXXXArray.
-
-dscCOpStmt [r] ReadByteArrayOp_Char       [a,i] vols = doIndexByteArrayOp (Just MO_8U_to_32U) Word8Rep r a i
-dscCOpStmt [r] ReadByteArrayOp_WideChar   [a,i] vols = doIndexByteArrayOp Nothing Word32Rep r a i
-dscCOpStmt [r] ReadByteArrayOp_Int        [a,i] vols = doIndexByteArrayOp Nothing IntRep r a i
-dscCOpStmt [r] ReadByteArrayOp_Word       [a,i] vols = doIndexByteArrayOp Nothing WordRep r a i
-dscCOpStmt [r] ReadByteArrayOp_Addr       [a,i] vols = doIndexByteArrayOp Nothing AddrRep r a i
-dscCOpStmt [r] ReadByteArrayOp_Float      [a,i] vols = doIndexByteArrayOp Nothing FloatRep r a i
-dscCOpStmt [r] ReadByteArrayOp_Double     [a,i] vols = doIndexByteArrayOp Nothing DoubleRep r a i
-dscCOpStmt [r] ReadByteArrayOp_StablePtr  [a,i] vols = doIndexByteArrayOp Nothing StablePtrRep r a i
-
-dscCOpStmt [r] ReadByteArrayOp_Int8       [a,i] vols = doIndexByteArrayOp Nothing Int8Rep  r a i
-dscCOpStmt [r] ReadByteArrayOp_Int16      [a,i] vols = doIndexByteArrayOp Nothing Int16Rep  r a i
-dscCOpStmt [r] ReadByteArrayOp_Int32      [a,i] vols = doIndexByteArrayOp Nothing Int32Rep  r a i
-dscCOpStmt [r] ReadByteArrayOp_Int64      [a,i] vols = doIndexByteArrayOp Nothing Int64Rep  r a i
-
-dscCOpStmt [r] ReadByteArrayOp_Word8      [a,i] vols = doIndexByteArrayOp Nothing Word8Rep  r a i
-dscCOpStmt [r] ReadByteArrayOp_Word16     [a,i] vols = doIndexByteArrayOp Nothing Word16Rep  r a i
-dscCOpStmt [r] ReadByteArrayOp_Word32     [a,i] vols = doIndexByteArrayOp Nothing Word32Rep  r a i
-dscCOpStmt [r] ReadByteArrayOp_Word64     [a,i] vols = doIndexByteArrayOp Nothing Word64Rep  r a i
-
--- WriteXXXoffAddr
-
-dscCOpStmt [] WriteOffAddrOp_Char       [a,i,x] vols = doWriteOffAddrOp (Just MO_32U_to_8U) Word8Rep a i x
-dscCOpStmt [] WriteOffAddrOp_WideChar   [a,i,x] vols = doWriteOffAddrOp Nothing Word32Rep a i x
-dscCOpStmt [] WriteOffAddrOp_Int        [a,i,x] vols = doWriteOffAddrOp Nothing IntRep a i x
-dscCOpStmt [] WriteOffAddrOp_Word       [a,i,x] vols = doWriteOffAddrOp Nothing WordRep a i x
-dscCOpStmt [] WriteOffAddrOp_Addr       [a,i,x] vols = doWriteOffAddrOp Nothing AddrRep a i x
-dscCOpStmt [] WriteOffAddrOp_Float      [a,i,x] vols = doWriteOffAddrOp Nothing FloatRep a i x
-dscCOpStmt [] WriteOffAddrOp_ForeignObj [a,i,x] vols = doWriteOffAddrOp Nothing PtrRep a i x
-dscCOpStmt [] WriteOffAddrOp_Double     [a,i,x] vols = doWriteOffAddrOp Nothing DoubleRep a i x
-dscCOpStmt [] WriteOffAddrOp_StablePtr  [a,i,x] vols = doWriteOffAddrOp Nothing StablePtrRep a i x
-
-dscCOpStmt [] WriteOffAddrOp_Int8       [a,i,x] vols = doWriteOffAddrOp Nothing Int8Rep  a i x
-dscCOpStmt [] WriteOffAddrOp_Int16      [a,i,x] vols = doWriteOffAddrOp Nothing Int16Rep a i x
-dscCOpStmt [] WriteOffAddrOp_Int32      [a,i,x] vols = doWriteOffAddrOp Nothing Int32Rep a i x
-dscCOpStmt [] WriteOffAddrOp_Int64      [a,i,x] vols = doWriteOffAddrOp Nothing Int64Rep a i x
-
-dscCOpStmt [] WriteOffAddrOp_Word8      [a,i,x] vols = doWriteOffAddrOp Nothing Word8Rep  a i x
-dscCOpStmt [] WriteOffAddrOp_Word16     [a,i,x] vols = doWriteOffAddrOp Nothing Word16Rep a i x
-dscCOpStmt [] WriteOffAddrOp_Word32     [a,i,x] vols = doWriteOffAddrOp Nothing Word32Rep a i x
-dscCOpStmt [] WriteOffAddrOp_Word64     [a,i,x] vols = doWriteOffAddrOp Nothing Word64Rep a i x
-
--- WriteXXXArray
-
-dscCOpStmt [] WriteByteArrayOp_Char      [a,i,x] vols = doWriteByteArrayOp (Just MO_32U_to_8U) Word8Rep a i x
-dscCOpStmt [] WriteByteArrayOp_WideChar  [a,i,x] vols = doWriteByteArrayOp Nothing Word32Rep a i x
-dscCOpStmt [] WriteByteArrayOp_Int       [a,i,x] vols = doWriteByteArrayOp Nothing IntRep a i x
-dscCOpStmt [] WriteByteArrayOp_Word      [a,i,x] vols = doWriteByteArrayOp Nothing WordRep a i x
-dscCOpStmt [] WriteByteArrayOp_Addr      [a,i,x] vols = doWriteByteArrayOp Nothing AddrRep a i x
-dscCOpStmt [] WriteByteArrayOp_Float     [a,i,x] vols = doWriteByteArrayOp Nothing FloatRep a i x
-dscCOpStmt [] WriteByteArrayOp_Double    [a,i,x] vols = doWriteByteArrayOp Nothing DoubleRep a i x
-dscCOpStmt [] WriteByteArrayOp_StablePtr [a,i,x] vols = doWriteByteArrayOp Nothing StablePtrRep a i x
-
-dscCOpStmt [] WriteByteArrayOp_Int8      [a,i,x] vols = doWriteByteArrayOp Nothing Int8Rep  a i x
-dscCOpStmt [] WriteByteArrayOp_Int16     [a,i,x] vols = doWriteByteArrayOp Nothing Int16Rep  a i x
-dscCOpStmt [] WriteByteArrayOp_Int32     [a,i,x] vols = doWriteByteArrayOp Nothing Int32Rep  a i x
-dscCOpStmt [] WriteByteArrayOp_Int64     [a,i,x] vols = doWriteByteArrayOp Nothing Int64Rep  a i x
-
-dscCOpStmt [] WriteByteArrayOp_Word8     [a,i,x] vols = doWriteByteArrayOp Nothing Word8Rep  a i x
-dscCOpStmt [] WriteByteArrayOp_Word16    [a,i,x] vols = doWriteByteArrayOp Nothing Word16Rep  a i x
-dscCOpStmt [] WriteByteArrayOp_Word32    [a,i,x] vols = doWriteByteArrayOp Nothing Word32Rep  a i x
-dscCOpStmt [] WriteByteArrayOp_Word64    [a,i,x] vols = doWriteByteArrayOp Nothing Word64Rep  a i x
-
-
--- Handle all others as simply as possible.
-dscCOpStmt ress op args vols
-   = case translateOp ress op args of
-        Nothing 
-           -> pprPanic "dscCOpStmt: can't translate PrimOp" (ppr op)
-        Just (maybe_res, mop, args)
-           -> returnFlt (
-                 CMachOpStmt maybe_res mop args 
-                    (if isDefinitelyInlineMachOp mop then Nothing else Just vols)
-              )
-
--- Native word signless ops
-
-translateOp [r] IntAddOp       [a1,a2] = Just (r, MO_Nat_Add,        [a1,a2])
-translateOp [r] IntSubOp       [a1,a2] = Just (r, MO_Nat_Sub,        [a1,a2])
-translateOp [r] WordAddOp      [a1,a2] = Just (r, MO_Nat_Add,        [a1,a2])
-translateOp [r] WordSubOp      [a1,a2] = Just (r, MO_Nat_Sub,        [a1,a2])
-translateOp [r] AddrAddOp      [a1,a2] = Just (r, MO_Nat_Add,        [a1,a2])
-translateOp [r] AddrSubOp      [a1,a2] = Just (r, MO_Nat_Sub,        [a1,a2])
-
-translateOp [r] IntEqOp        [a1,a2] = Just (r, MO_Nat_Eq,         [a1,a2])
-translateOp [r] IntNeOp        [a1,a2] = Just (r, MO_Nat_Ne,         [a1,a2])
-translateOp [r] WordEqOp       [a1,a2] = Just (r, MO_Nat_Eq,         [a1,a2])
-translateOp [r] WordNeOp       [a1,a2] = Just (r, MO_Nat_Ne,         [a1,a2])
-translateOp [r] AddrEqOp       [a1,a2] = Just (r, MO_Nat_Eq,         [a1,a2])
-translateOp [r] AddrNeOp       [a1,a2] = Just (r, MO_Nat_Ne,         [a1,a2])
-
-translateOp [r] AndOp          [a1,a2] = Just (r, MO_Nat_And,        [a1,a2])
-translateOp [r] OrOp           [a1,a2] = Just (r, MO_Nat_Or,         [a1,a2])
-translateOp [r] XorOp          [a1,a2] = Just (r, MO_Nat_Xor,        [a1,a2])
-translateOp [r] NotOp          [a1]    = Just (r, MO_Nat_Not,        [a1])
-
--- Native word signed ops
-
-translateOp [r] IntMulOp       [a1,a2] = Just (r, MO_NatS_Mul,       [a1,a2])
-translateOp [r] IntMulMayOfloOp [a1,a2] = Just (r, MO_NatS_MulMayOflo, [a1,a2])
-translateOp [r] IntQuotOp      [a1,a2] = Just (r, MO_NatS_Quot,      [a1,a2])
-translateOp [r] IntRemOp       [a1,a2] = Just (r, MO_NatS_Rem,       [a1,a2])
-translateOp [r] IntNegOp       [a1]    = Just (r, MO_NatS_Neg,       [a1])
-
-translateOp [r] IntGeOp        [a1,a2] = Just (r, MO_NatS_Ge,        [a1,a2])
-translateOp [r] IntLeOp        [a1,a2] = Just (r, MO_NatS_Le,        [a1,a2])
-translateOp [r] IntGtOp        [a1,a2] = Just (r, MO_NatS_Gt,        [a1,a2])
-translateOp [r] IntLtOp        [a1,a2] = Just (r, MO_NatS_Lt,        [a1,a2])
-
-
--- Native word unsigned ops
-
-translateOp [r] WordGeOp       [a1,a2] = Just (r, MO_NatU_Ge,        [a1,a2])
-translateOp [r] WordLeOp       [a1,a2] = Just (r, MO_NatU_Le,        [a1,a2])
-translateOp [r] WordGtOp       [a1,a2] = Just (r, MO_NatU_Gt,        [a1,a2])
-translateOp [r] WordLtOp       [a1,a2] = Just (r, MO_NatU_Lt,        [a1,a2])
-
-translateOp [r] WordMulOp      [a1,a2] = Just (r, MO_NatU_Mul,       [a1,a2])
-translateOp [r] WordQuotOp     [a1,a2] = Just (r, MO_NatU_Quot,      [a1,a2])
-translateOp [r] WordRemOp      [a1,a2] = Just (r, MO_NatU_Rem,       [a1,a2])
-
-translateOp [r] AddrGeOp       [a1,a2] = Just (r, MO_NatU_Ge,        [a1,a2])
-translateOp [r] AddrLeOp       [a1,a2] = Just (r, MO_NatU_Le,        [a1,a2])
-translateOp [r] AddrGtOp       [a1,a2] = Just (r, MO_NatU_Gt,        [a1,a2])
-translateOp [r] AddrLtOp       [a1,a2] = Just (r, MO_NatU_Lt,        [a1,a2])
-
--- 32-bit unsigned ops
-
-translateOp [r] CharEqOp       [a1,a2] = Just (r, MO_32U_Eq,        [a1,a2])
-translateOp [r] CharNeOp       [a1,a2] = Just (r, MO_32U_Ne,        [a1,a2])
-translateOp [r] CharGeOp       [a1,a2] = Just (r, MO_32U_Ge,        [a1,a2])
-translateOp [r] CharLeOp       [a1,a2] = Just (r, MO_32U_Le,        [a1,a2])
-translateOp [r] CharGtOp       [a1,a2] = Just (r, MO_32U_Gt,        [a1,a2])
-translateOp [r] CharLtOp       [a1,a2] = Just (r, MO_32U_Lt,        [a1,a2])
-
--- Double ops
-
-translateOp [r] DoubleEqOp     [a1,a2] = Just (r, MO_Dbl_Eq,      [a1,a2])
-translateOp [r] DoubleNeOp     [a1,a2] = Just (r, MO_Dbl_Ne,      [a1,a2])
-translateOp [r] DoubleGeOp     [a1,a2] = Just (r, MO_Dbl_Ge,      [a1,a2])
-translateOp [r] DoubleLeOp     [a1,a2] = Just (r, MO_Dbl_Le,      [a1,a2])
-translateOp [r] DoubleGtOp     [a1,a2] = Just (r, MO_Dbl_Gt,      [a1,a2])
-translateOp [r] DoubleLtOp     [a1,a2] = Just (r, MO_Dbl_Lt,      [a1,a2])
-
-translateOp [r] DoubleAddOp    [a1,a2] = Just (r, MO_Dbl_Add,    [a1,a2])
-translateOp [r] DoubleSubOp    [a1,a2] = Just (r, MO_Dbl_Sub,    [a1,a2])
-translateOp [r] DoubleMulOp    [a1,a2] = Just (r, MO_Dbl_Mul,    [a1,a2])
-translateOp [r] DoubleDivOp    [a1,a2] = Just (r, MO_Dbl_Div,    [a1,a2])
-translateOp [r] DoublePowerOp  [a1,a2] = Just (r, MO_Dbl_Pwr,    [a1,a2])
-
-translateOp [r] DoubleSinOp    [a1]    = Just (r, MO_Dbl_Sin,    [a1])
-translateOp [r] DoubleCosOp    [a1]    = Just (r, MO_Dbl_Cos,    [a1])
-translateOp [r] DoubleTanOp    [a1]    = Just (r, MO_Dbl_Tan,    [a1])
-translateOp [r] DoubleSinhOp   [a1]    = Just (r, MO_Dbl_Sinh,   [a1])
-translateOp [r] DoubleCoshOp   [a1]    = Just (r, MO_Dbl_Cosh,   [a1])
-translateOp [r] DoubleTanhOp   [a1]    = Just (r, MO_Dbl_Tanh,   [a1])
-translateOp [r] DoubleAsinOp   [a1]    = Just (r, MO_Dbl_Asin,    [a1])
-translateOp [r] DoubleAcosOp   [a1]    = Just (r, MO_Dbl_Acos,    [a1])
-translateOp [r] DoubleAtanOp   [a1]    = Just (r, MO_Dbl_Atan,    [a1])
-translateOp [r] DoubleLogOp    [a1]    = Just (r, MO_Dbl_Log,    [a1])
-translateOp [r] DoubleExpOp    [a1]    = Just (r, MO_Dbl_Exp,    [a1])
-translateOp [r] DoubleSqrtOp   [a1]    = Just (r, MO_Dbl_Sqrt,    [a1])
-translateOp [r] DoubleNegOp    [a1]    = Just (r, MO_Dbl_Neg,    [a1])
-
--- Float ops
-
-translateOp [r] FloatEqOp     [a1,a2] = Just (r, MO_Flt_Eq,      [a1,a2])
-translateOp [r] FloatNeOp     [a1,a2] = Just (r, MO_Flt_Ne,      [a1,a2])
-translateOp [r] FloatGeOp     [a1,a2] = Just (r, MO_Flt_Ge,      [a1,a2])
-translateOp [r] FloatLeOp     [a1,a2] = Just (r, MO_Flt_Le,      [a1,a2])
-translateOp [r] FloatGtOp     [a1,a2] = Just (r, MO_Flt_Gt,      [a1,a2])
-translateOp [r] FloatLtOp     [a1,a2] = Just (r, MO_Flt_Lt,      [a1,a2])
-
-translateOp [r] FloatAddOp    [a1,a2] = Just (r, MO_Flt_Add,    [a1,a2])
-translateOp [r] FloatSubOp    [a1,a2] = Just (r, MO_Flt_Sub,    [a1,a2])
-translateOp [r] FloatMulOp    [a1,a2] = Just (r, MO_Flt_Mul,    [a1,a2])
-translateOp [r] FloatDivOp    [a1,a2] = Just (r, MO_Flt_Div,    [a1,a2])
-translateOp [r] FloatPowerOp  [a1,a2] = Just (r, MO_Flt_Pwr,    [a1,a2])
-
-translateOp [r] FloatSinOp    [a1]    = Just (r, MO_Flt_Sin,    [a1])
-translateOp [r] FloatCosOp    [a1]    = Just (r, MO_Flt_Cos,    [a1])
-translateOp [r] FloatTanOp    [a1]    = Just (r, MO_Flt_Tan,    [a1])
-translateOp [r] FloatSinhOp   [a1]    = Just (r, MO_Flt_Sinh,   [a1])
-translateOp [r] FloatCoshOp   [a1]    = Just (r, MO_Flt_Cosh,   [a1])
-translateOp [r] FloatTanhOp   [a1]    = Just (r, MO_Flt_Tanh,   [a1])
-translateOp [r] FloatAsinOp   [a1]    = Just (r, MO_Flt_Asin,    [a1])
-translateOp [r] FloatAcosOp   [a1]    = Just (r, MO_Flt_Acos,    [a1])
-translateOp [r] FloatAtanOp   [a1]    = Just (r, MO_Flt_Atan,    [a1])
-translateOp [r] FloatLogOp    [a1]    = Just (r, MO_Flt_Log,    [a1])
-translateOp [r] FloatExpOp    [a1]    = Just (r, MO_Flt_Exp,    [a1])
-translateOp [r] FloatSqrtOp   [a1]    = Just (r, MO_Flt_Sqrt,    [a1])
-translateOp [r] FloatNegOp    [a1]    = Just (r, MO_Flt_Neg,    [a1])
-
--- Conversions
-
-translateOp [r] Int2DoubleOp   [a1]   = Just (r, MO_NatS_to_Dbl,   [a1])
-translateOp [r] Double2IntOp   [a1]   = Just (r, MO_Dbl_to_NatS,   [a1])
-
-translateOp [r] Int2FloatOp    [a1]   = Just (r, MO_NatS_to_Flt,   [a1])
-translateOp [r] Float2IntOp    [a1]   = Just (r, MO_Flt_to_NatS,   [a1])
-
-translateOp [r] Float2DoubleOp [a1]   = Just (r, MO_Flt_to_Dbl,    [a1])
-translateOp [r] Double2FloatOp [a1]   = Just (r, MO_Dbl_to_Flt,    [a1])
-
-translateOp [r] Int2WordOp     [a1]   = Just (r, MO_NatS_to_NatU,  [a1])
-translateOp [r] Word2IntOp     [a1]   = Just (r, MO_NatU_to_NatS,  [a1])
-
-translateOp [r] Int2AddrOp     [a1]   = Just (r, MO_NatS_to_NatP,  [a1])
-translateOp [r] Addr2IntOp     [a1]   = Just (r, MO_NatP_to_NatS,  [a1])
-
-translateOp [r] OrdOp          [a1]   = Just (r, MO_32U_to_NatS,   [a1])
-translateOp [r] ChrOp          [a1]   = Just (r, MO_NatS_to_32U,   [a1])
-
-translateOp [r] Narrow8IntOp   [a1]   = Just (r, MO_8S_to_NatS,    [a1])
-translateOp [r] Narrow16IntOp  [a1]   = Just (r, MO_16S_to_NatS,   [a1])
-translateOp [r] Narrow32IntOp  [a1]   = Just (r, MO_32S_to_NatS,   [a1])
-
-translateOp [r] Narrow8WordOp   [a1]  = Just (r, MO_8U_to_NatU,    [a1])
-translateOp [r] Narrow16WordOp  [a1]  = Just (r, MO_16U_to_NatU,   [a1])
-translateOp [r] Narrow32WordOp  [a1]  = Just (r, MO_32U_to_NatU,   [a1])
-
--- Word comparisons masquerading as more exotic things.
-
-translateOp [r] SameMutVarOp   [a1,a2]  = Just (r, MO_Nat_Eq,    [a1,a2])
-translateOp [r] SameMVarOp     [a1,a2]  = Just (r, MO_Nat_Eq,    [a1,a2])
-translateOp [r] SameMutableArrayOp  [a1,a2]  = Just (r, MO_Nat_Eq,    [a1,a2])
-translateOp [r] SameMutableByteArrayOp [a1,a2]  = Just (r, MO_Nat_Eq,    [a1,a2])
-translateOp [r] EqForeignObj [a1,a2]  = Just (r, MO_Nat_Eq,    [a1,a2])
-translateOp [r] EqStablePtrOp [a1,a2]  = Just (r, MO_Nat_Eq,    [a1,a2])
-
-translateOp _ _ _ = Nothing
-\end{code}
-
-
-\begin{code}
-shimFCallArg arg amode
-  | tycon == foreignObjPrimTyCon
-       = CMacroExpr AddrRep ForeignObj_CLOSURE_DATA [amode]
-  | tycon == arrayPrimTyCon || tycon == mutableArrayPrimTyCon
-       = CMacroExpr PtrRep PTRS_ARR_CTS [amode]
-  | tycon == byteArrayPrimTyCon || tycon == mutableByteArrayPrimTyCon
-       = CMacroExpr AddrRep BYTE_ARR_CTS [amode]
-  | otherwise = amode
-  where        
-       -- should be a tycon app, since this is a foreign call
-       tycon = tyConAppTyCon (repType (stgArgType arg))
-\end{code}
diff --git a/ghc/compiler/absCSyn/CLabel.lhs b/ghc/compiler/absCSyn/CLabel.lhs
deleted file mode 100644 (file)
index f2b3ff9..0000000
+++ /dev/null
@@ -1,596 +0,0 @@
-%
-% (c) The University of Glasgow, 1992-2002
-%
-\section[CLabel]{@CLabel@: Information to make C Labels}
-
-\begin{code}
-module CLabel (
-       CLabel, -- abstract type
-
-       mkClosureLabel,
-       mkSRTLabel,
-       mkSRTDescLabel,
-       mkInfoTableLabel,
-       mkEntryLabel,
-       mkSlowEntryLabel,
-       mkConEntryLabel,
-       mkStaticConEntryLabel,
-       mkRednCountsLabel,
-       mkConInfoTableLabel,
-       mkStaticInfoTableLabel,
-       mkApEntryLabel,
-       mkApInfoTableLabel,
-
-       mkReturnPtLabel,
-       mkReturnInfoLabel,
-       mkVecTblLabel,
-       mkAltLabel,
-       mkDefaultLabel,
-       mkBitmapLabel,
-
-       mkClosureTblLabel,
-
-       mkAsmTempLabel,
-
-       mkModuleInitLabel,
-       mkPlainModuleInitLabel,
-
-       mkErrorStdEntryLabel,
-
-       mkStgUpdatePAPLabel,
-       mkSplitMarkerLabel,
-       mkUpdInfoLabel,
-       mkSeqInfoLabel,
-       mkIndInfoLabel,
-       mkIndStaticInfoLabel,
-       mkRtsGCEntryLabel,
-        mkMainCapabilityLabel,
-       mkCharlikeClosureLabel,
-       mkIntlikeClosureLabel,
-       mkMAP_FROZEN_infoLabel,
-        mkEMPTY_MVAR_infoLabel,
-
-       mkTopTickyCtrLabel,
-       mkBlackHoleInfoTableLabel,
-       mkBlackHoleBQInfoTableLabel,
-        mkCAFBlackHoleInfoTableLabel,
-        mkSECAFBlackHoleInfoTableLabel,
-       mkRtsPrimOpLabel,
-
-       moduleRegdLabel,
-
-       mkSelectorInfoLabel,
-       mkSelectorEntryLabel,
-
-       mkRtsApplyInfoLabel,
-       mkRtsApplyEntryLabel,
-
-       mkForeignLabel,
-
-       mkCC_Label, mkCCS_Label,
-       
-       needsCDecl, isAsmTemp, externallyVisibleCLabel,
-
-       CLabelType(..), labelType, labelDynamic,
-
-       pprCLabel
-    ) where
-
-
-#include "HsVersions.h"
-
-#if ! OMIT_NATIVE_CODEGEN
-import {-# SOURCE #-} MachMisc ( underscorePrefix, fmtAsmLbl )
-#endif
-
-import CmdLineOpts      ( opt_Static, opt_DoTickyProfiling )
-import CStrings                ( pp_cSEP )
-import DataCon         ( ConTag )
-import Module          ( moduleName, moduleNameFS, 
-                         Module, isHomeModule )
-import Name            ( Name, getName, isDllName, isExternalName )
-import TyCon           ( TyCon )
-import Unique          ( pprUnique, Unique )
-import PrimOp          ( PrimOp )
-import CostCentre      ( CostCentre, CostCentreStack )
-import Outputable
-import FastString
-\end{code}
-
-things we want to find out:
-
-* should the labelled things be declared "static" (visible only in this file)?
-
-* should it be declared "const" (read-only text space)?
-
-* does it need declarations at all? (v common Prelude things are pre-declared)
-
-* what type does it have? (for generating accurate enough C declarations
-  so that the C compiler won't complain).
-
-\begin{code}
-data CLabel
-  = IdLabel                    -- A family of labels related to the
-       Name                    -- definition of a particular Id
-       IdLabelInfo
-
-  | DataConLabel               -- Ditto data constructors
-       Name
-       DataConLabelInfo
-
-  | CaseLabel                  -- A family of labels related to a particular case expression
-       Unique                  -- Unique says which case expression
-       CaseLabelInfo
-
-  | TyConLabel TyCon           -- currently only one kind of TyconLabel,
-                               -- a 'Closure Table'.
-
-  | AsmTempLabel    Unique
-
-  | ModuleInitLabel 
-       Module                  -- the module name
-       String                  -- its "way"
-       -- 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 Module         -- without the vesrion & way info
-
-  | RtsLabel       RtsLabelInfo
-
-  | ForeignLabel FastString Bool  -- a 'C' (or otherwise foreign) label
-                                  -- Bool <=> is dynamic
-
-  | CC_Label CostCentre
-  | CCS_Label CostCentreStack
-
-  deriving (Eq, Ord)
-\end{code}
-
-\begin{code}
-data IdLabelInfo
-  = Closure            -- Label for (static???) closure
-  | SRT                 -- Static reference table
-  | SRTDesc             -- Static reference table descriptor
-  | InfoTbl            -- Info tables for closures; always read-only
-  | Entry              -- entry point
-  | Slow               -- slow entry point
-
-                       -- Ticky-ticky counting
-  | RednCounts         -- Label of place to keep reduction-count info for 
-                       -- this Id
-
-  | Bitmap             -- A bitmap (function or case return)
-
-  deriving (Eq, Ord)
-
-data DataConLabelInfo
-  = ConEntry           -- the only kind of entry pt for constructors
-  | ConInfoTbl         -- corresponding info table
-  | StaticConEntry     -- static constructor entry point
-  | StaticInfoTbl      -- corresponding info table
-  deriving (Eq, Ord)
-
-data CaseLabelInfo
-  = CaseReturnPt
-  | CaseReturnInfo
-  | CaseVecTbl
-  | CaseAlt ConTag
-  | CaseDefault
-  deriving (Eq, Ord)
-
-data RtsLabelInfo
-  = RtsShouldNeverHappenCode
-
-  | RtsBlackHoleInfoTbl LitString  -- black hole with info table name
-
-  | RtsUpdInfo                 -- upd_frame_info
-  | RtsSeqInfo                 -- seq_frame_info
-  | RtsGCEntryLabel String     -- a heap check fail handler, eg  stg_chk_2
-  | RtsMainCapability           -- MainCapability
-  | Rts_Closure String         -- misc rts closures, eg CHARLIKE_closure
-  | Rts_Info String            -- misc rts itbls, eg MUT_ARR_PTRS_FROZEN_info
-  | Rts_Code String            -- misc rts code
-
-  | RtsSelectorInfoTbl Bool{-updatable-} Int{-offset-} -- Selector thunks
-  | RtsSelectorEntry   Bool{-updatable-} Int{-offset-}
-
-  | RtsApInfoTbl Bool{-updatable-} Int{-arity-}                -- AP thunks
-  | RtsApEntry   Bool{-updatable-} Int{-arity-}
-
-  | RtsPrimOp PrimOp
-
-  | RtsTopTickyCtr
-
-  | RtsModuleRegd
-
-  | RtsApplyInfoLabel  LitString
-  | RtsApplyEntryLabel LitString
-
-  deriving (Eq, Ord)
-
--- Label Type: for generating C declarations.
-
-data CLabelType
-  = RetInfoTblType
-  | InfoTblType
-  | ClosureType
-  | VecTblType
-  | ClosureTblType
-  | CodeType
-  | DataType
-\end{code}
-
-\begin{code}
-mkClosureLabel         id              = IdLabel id  Closure
-mkSRTLabel             id              = IdLabel id  SRT
-mkSRTDescLabel         id              = IdLabel id  SRTDesc
-mkInfoTableLabel       id              = IdLabel id  InfoTbl
-mkEntryLabel           id              = IdLabel id  Entry
-mkSlowEntryLabel       id              = IdLabel id  Slow
-mkBitmapLabel          id              = IdLabel id  Bitmap
-mkRednCountsLabel      id              = IdLabel id  RednCounts
-
-mkStaticInfoTableLabel  con            = DataConLabel con StaticInfoTbl
-mkConInfoTableLabel     con            = DataConLabel con ConInfoTbl
-mkConEntryLabel                con             = DataConLabel con ConEntry
-mkStaticConEntryLabel  con             = DataConLabel con StaticConEntry
-
-
-mkReturnPtLabel uniq           = CaseLabel uniq CaseReturnPt
-mkReturnInfoLabel uniq         = CaseLabel uniq CaseReturnInfo
-mkVecTblLabel   uniq           = CaseLabel uniq CaseVecTbl
-mkAltLabel      uniq tag       = CaseLabel uniq (CaseAlt tag)
-mkDefaultLabel  uniq           = CaseLabel uniq CaseDefault
-
-
-mkClosureTblLabel tycon                = TyConLabel tycon
-
-mkAsmTempLabel                         = AsmTempLabel
-
-mkModuleInitLabel              = ModuleInitLabel
-mkPlainModuleInitLabel         = PlainModuleInitLabel
-
-       -- Some fixed runtime system labels
-
-mkErrorStdEntryLabel           = RtsLabel RtsShouldNeverHappenCode
-mkStgUpdatePAPLabel            = RtsLabel (Rts_Code "stg_update_PAP")
-mkSplitMarkerLabel             = RtsLabel (Rts_Code "__stg_split_marker")
-mkUpdInfoLabel                 = RtsLabel RtsUpdInfo
-mkSeqInfoLabel                 = RtsLabel RtsSeqInfo
-mkIndInfoLabel                 = RtsLabel (Rts_Info "stg_IND_info")
-mkIndStaticInfoLabel           = RtsLabel (Rts_Info "stg_IND_STATIC_info")
-mkRtsGCEntryLabel str          = RtsLabel (RtsGCEntryLabel str)
-mkMainCapabilityLabel          = RtsLabel RtsMainCapability
-mkCharlikeClosureLabel         = RtsLabel (Rts_Closure "stg_CHARLIKE_closure")
-mkIntlikeClosureLabel          = RtsLabel (Rts_Closure "stg_INTLIKE_closure")
-mkMAP_FROZEN_infoLabel         = RtsLabel (Rts_Info "stg_MUT_ARR_PTRS_FROZEN_info")
-mkEMPTY_MVAR_infoLabel         = RtsLabel (Rts_Info "stg_EMPTY_MVAR_info")
-
-mkTopTickyCtrLabel             = RtsLabel RtsTopTickyCtr
-mkBlackHoleInfoTableLabel      = RtsLabel (RtsBlackHoleInfoTbl SLIT("stg_BLACKHOLE_info"))
-mkBlackHoleBQInfoTableLabel    = RtsLabel (RtsBlackHoleInfoTbl SLIT("stg_BLACKHOLE_BQ_info"))
-mkCAFBlackHoleInfoTableLabel   = RtsLabel (RtsBlackHoleInfoTbl SLIT("stg_CAF_BLACKHOLE_info"))
-mkSECAFBlackHoleInfoTableLabel = if opt_DoTickyProfiling then
-                                    RtsLabel (RtsBlackHoleInfoTbl SLIT("stg_SE_CAF_BLACKHOLE_info"))
-                                  else  -- RTS won't have info table unless -ticky is on
-                                    panic "mkSECAFBlackHoleInfoTableLabel requires -ticky"
-mkRtsPrimOpLabel primop                = RtsLabel (RtsPrimOp primop)
-
-moduleRegdLabel                        = RtsLabel RtsModuleRegd
-
-mkSelectorInfoLabel  upd off   = RtsLabel (RtsSelectorInfoTbl upd off)
-mkSelectorEntryLabel upd off   = RtsLabel (RtsSelectorEntry   upd off)
-
-mkApInfoTableLabel  upd off    = RtsLabel (RtsApInfoTbl upd off)
-mkApEntryLabel upd off         = RtsLabel (RtsApEntry   upd off)
-
-       -- Foreign labels
-
-mkForeignLabel :: FastString -> Bool -> CLabel
-mkForeignLabel str is_dynamic  = ForeignLabel str is_dynamic
-
-       -- Cost centres etc.
-
-mkCC_Label     cc              = CC_Label cc
-mkCCS_Label    ccs             = CCS_Label ccs
-
--- Std RTS application routines
-
-mkRtsApplyInfoLabel  = RtsLabel . RtsApplyInfoLabel
-mkRtsApplyEntryLabel = RtsLabel . RtsApplyEntryLabel
-\end{code}
-
-\begin{code}
-needsCDecl :: CLabel -> Bool   -- False <=> it's pre-declared; don't bother
-isAsmTemp  :: CLabel -> Bool    -- is a local temporary for native code generation
-externallyVisibleCLabel :: CLabel -> Bool -- not C "static"
-\end{code}
-
-@needsCDecl@ is @True@ unless the thing is a deeply-@PreludeCore@-ish
-object.  {\em Also:} No need to spit out labels for things generated
-by the flattener (in @AbsCUtils@)---it is careful to ensure references
-to them are always backwards.  These are return-point and vector-table
-labels.
-
-Declarations for (non-prelude) @Id@-based things are needed because of
-mutual recursion.
-
-Declarations for direct return points are needed, because they may be
-let-no-escapes, which can be recursive.
-
-\begin{code}
-  -- 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 (CaseLabel _ CaseReturnPt)  = True
-needsCDecl (DataConLabel _ _)          = True
-needsCDecl (TyConLabel _)              = True
-needsCDecl (ModuleInitLabel _ _)       = True
-needsCDecl (PlainModuleInitLabel _)    = True
-
-needsCDecl (CaseLabel _ _)             = False
-needsCDecl (AsmTempLabel _)            = False
-needsCDecl (RtsLabel _)                        = False
-needsCDecl (ForeignLabel _ _)          = False
-needsCDecl (CC_Label _)                        = False
-needsCDecl (CCS_Label _)               = False
-\end{code}
-
-Whether the label is an assembler temporary:
-
-\begin{code}
-isAsmTemp (AsmTempLabel _) = True
-isAsmTemp _               = False
-\end{code}
-
-C ``static'' 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.
-
-\begin{code}
-externallyVisibleCLabel (DataConLabel _ _) = True
-externallyVisibleCLabel (TyConLabel tc)    = True
-externallyVisibleCLabel (CaseLabel _ _)           = False
-externallyVisibleCLabel (AsmTempLabel _)   = False
-externallyVisibleCLabel (ModuleInitLabel _ _)= True
-externallyVisibleCLabel (PlainModuleInitLabel _)= True
-externallyVisibleCLabel (RtsLabel RtsModuleRegd) = False --hack
-externallyVisibleCLabel (RtsLabel _)      = True
-externallyVisibleCLabel (ForeignLabel _ _) = True
-externallyVisibleCLabel (IdLabel id _)     = isExternalName id
-externallyVisibleCLabel (CC_Label _)      = False -- not strictly true
-externallyVisibleCLabel (CCS_Label _)     = False -- not strictly true
-\end{code}
-
-For generating correct types in label declarations, and also for
-deciding whether the C compiler would like us to use '&' before the
-label to get its address:
-
-\begin{code}
-labelType :: CLabel -> CLabelType
-labelType (RtsLabel (RtsBlackHoleInfoTbl _))  = InfoTblType
-labelType (RtsLabel (RtsSelectorInfoTbl _ _)) = InfoTblType
-labelType (RtsLabel (RtsApInfoTbl _ _))       = InfoTblType
-labelType (RtsLabel RtsUpdInfo)              = RetInfoTblType
-labelType (RtsLabel RtsSeqInfo)              = RetInfoTblType
-labelType (RtsLabel RtsTopTickyCtr)          = CodeType -- XXX
-labelType (RtsLabel (Rts_Info _))             = InfoTblType
-labelType (RtsLabel (RtsApplyInfoLabel _))    = RetInfoTblType
-labelType (RtsLabel (RtsApplyEntryLabel _))   = CodeType
-labelType (CaseLabel _ CaseReturnInfo)        = RetInfoTblType
-labelType (CaseLabel _ CaseReturnPt)         = CodeType
-labelType (CaseLabel _ CaseVecTbl)            = VecTblType
-labelType (TyConLabel _)                     = ClosureTblType
-labelType (ModuleInitLabel _ _)               = CodeType
-labelType (PlainModuleInitLabel _)            = CodeType
-labelType (CC_Label _)                       = CodeType -- hack
-labelType (CCS_Label _)                              = CodeType -- hack
-
-labelType (IdLabel _ info) = 
-  case info of
-    InfoTbl   -> InfoTblType
-    Closure   -> ClosureType
-    Bitmap    -> DataType
-    _        -> CodeType
-
-labelType (DataConLabel _ info) = 
-  case info of
-     ConInfoTbl    -> InfoTblType
-     StaticInfoTbl -> InfoTblType
-     _            -> CodeType
-
-labelType _        = DataType
-\end{code}
-
-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.
-
-\begin{code}
-labelDynamic :: CLabel -> Bool
-labelDynamic lbl = 
-  case lbl of
-   -- The special case for RtsShouldNeverHappenCode is because the associated address is
-   -- NULL, i.e. not a DLL entry point
-   RtsLabel RtsShouldNeverHappenCode -> False
-   RtsLabel _               -> not opt_Static  -- i.e., is the RTS in a DLL or not?
-   IdLabel n k       -> isDllName n
-   DataConLabel n k  -> isDllName n
-   TyConLabel tc     -> isDllName (getName tc)
-   ForeignLabel _ d  -> d
-   ModuleInitLabel m _  -> (not opt_Static) && (not (isHomeModule m))
-   PlainModuleInitLabel m -> (not opt_Static) && (not (isHomeModule m))
-   _                -> False
-\end{code}
-
-
-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
-        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
-
-\begin{code}
-pprCLabel :: CLabel -> SDoc
-
-#if ! OMIT_NATIVE_CODEGEN
-pprCLabel (AsmTempLabel u)
-  = text (fmtAsmLbl (show u))
-#endif
-
-pprCLabel lbl = 
-#if ! OMIT_NATIVE_CODEGEN
-    getPprStyle $ \ sty ->
-    if asmStyle sty && underscorePrefix then
-       pp_cSEP <> pprCLbl lbl
-    else
-#endif
-       pprCLbl lbl
-
-pprCLbl (CaseLabel u CaseReturnPt)
-  = hcat [pprUnique u, pp_cSEP, ptext SLIT("ret")]
-pprCLbl (CaseLabel u CaseReturnInfo)
-  = hcat [pprUnique u, pp_cSEP, ptext SLIT("info")]
-pprCLbl (CaseLabel u CaseVecTbl)
-  = hcat [pprUnique u, pp_cSEP, ptext SLIT("vtbl")]
-pprCLbl (CaseLabel u (CaseAlt tag))
-  = hcat [pprUnique u, pp_cSEP, int tag, pp_cSEP, ptext SLIT("alt")]
-pprCLbl (CaseLabel u CaseDefault)
-  = hcat [pprUnique u, pp_cSEP, ptext SLIT("dflt")]
-
-pprCLbl (RtsLabel RtsShouldNeverHappenCode) = ptext SLIT("NULL")
--- used to be stg_error_entry but Windows can't have DLL entry points as static
--- initialisers, and besides, this ShouldNeverHappen, right?
-
-pprCLbl (RtsLabel RtsUpdInfo)            = ptext SLIT("stg_upd_frame_info")
-pprCLbl (RtsLabel RtsSeqInfo)            = ptext SLIT("stg_seq_frame_info")
-pprCLbl (RtsLabel RtsMainCapability)     = ptext SLIT("MainCapability")
-pprCLbl (RtsLabel (RtsGCEntryLabel str)) = text str
-pprCLbl (RtsLabel (Rts_Closure str))     = text str
-pprCLbl (RtsLabel (Rts_Info str))        = text str
-pprCLbl (RtsLabel (Rts_Code str))        = text str
-
-pprCLbl (RtsLabel RtsTopTickyCtr) = ptext SLIT("top_ct")
-
-pprCLbl (RtsLabel (RtsBlackHoleInfoTbl info)) = ptext info
-
-pprCLbl (RtsLabel (RtsSelectorInfoTbl 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 (RtsApInfoTbl 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 (RtsApplyInfoLabel  fs))
-  = ptext SLIT("stg_ap_") <> ptext fs <> ptext SLIT("_info")
-
-pprCLbl (RtsLabel (RtsApplyEntryLabel fs))
-  = ptext SLIT("stg_ap_") <> ptext fs <> ptext SLIT("_ret")
-
-pprCLbl (RtsLabel (RtsPrimOp primop)) 
-  = ppr primop <> ptext SLIT("_fast")
-
-pprCLbl (RtsLabel RtsModuleRegd)
-  = ptext SLIT("module_registered")
-
-pprCLbl (ForeignLabel str _)
-  = ftext str
-
-pprCLbl (TyConLabel tc)
-  = hcat [ppr tc, pp_cSEP, ptext SLIT("closure_tbl")]
-
-pprCLbl (IdLabel      id  flavor) = ppr id <> ppIdFlavor flavor
-pprCLbl (DataConLabel con flavor) = ppr con <> ppConFlavor flavor
-
-pprCLbl (CC_Label cc)          = ppr cc
-pprCLbl (CCS_Label ccs)        = ppr ccs
-
-pprCLbl (ModuleInitLabel mod way)      
-   = ptext SLIT("__stginit_") <> ftext (moduleNameFS (moduleName mod))
-       <> char '_' <> text way
-pprCLbl (PlainModuleInitLabel mod)     
-   = ptext SLIT("__stginit_") <> ftext (moduleNameFS (moduleName mod))
-
-ppIdFlavor :: IdLabelInfo -> SDoc
-
-ppIdFlavor x = pp_cSEP <>
-              (case x of
-                      Closure          -> ptext SLIT("closure")
-                      SRT              -> ptext SLIT("srt")
-                      SRTDesc          -> ptext SLIT("srtd")
-                      InfoTbl          -> ptext SLIT("info")
-                      Entry            -> ptext SLIT("entry")
-                      Slow             -> ptext SLIT("slow")
-                      RednCounts       -> ptext SLIT("ct")
-                      Bitmap           -> ptext SLIT("btm")
-                     )
-
-ppConFlavor x = pp_cSEP <>
-               (case x of
-                      ConEntry         -> ptext SLIT("con_entry")
-                      ConInfoTbl       -> ptext SLIT("con_info")
-                      StaticConEntry   -> ptext SLIT("static_entry")
-                      StaticInfoTbl    -> ptext SLIT("static_info")
-               )
-\end{code}
diff --git a/ghc/compiler/absCSyn/CStrings.lhs b/ghc/compiler/absCSyn/CStrings.lhs
deleted file mode 100644 (file)
index f25e6c2..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-This module deals with printing C string literals 
-
-\begin{code}
-module CStrings(
-       CLabelString, isCLabelString, pprCLabelString,
-
-       pp_cSEP,
-
-       pprFSInCStyle, pprStringInCStyle
-  ) where
-
-#include "HsVersions.h"
-
-import Char    ( ord, chr, isAlphaNum )
-import FastString
-import Outputable
-\end{code}
-
-
-\begin{code}
-type CLabelString = FastString         -- A C label, completely unencoded
-
-pprCLabelString :: CLabelString -> SDoc
-pprCLabelString lbl = ftext lbl
-
-isCLabelString :: CLabelString -> Bool -- Checks to see if this is a valid C label
-isCLabelString lbl 
-  = all ok (unpackFS lbl)
-  where
-    ok c = isAlphaNum c || c == '_' || c == '.'
-       -- The '.' appears in e.g. "foo.so" in the 
-       -- module part of a ExtName.  Maybe it should be separate
-
-pp_cSEP = char '_'
-\end{code}
-
-\begin{code}
-pprFSInCStyle :: FastString -> SDoc
--- Assumes it contains only characters '\0'..'\xFF'!
-pprFSInCStyle fs = pprStringInCStyle (unpackFS fs)
-
-pprStringInCStyle :: String -> SDoc
-pprStringInCStyle s = doubleQuotes (text (concatMap charToC s))
-
-charToC :: Char -> String
-charToC '\"' = "\\\""
-charToC '\'' = "\\\'"
-charToC '\\' = "\\\\"
-charToC c | c >= ' ' && c <= '~' = [c]
-          | c > '\xFF' = panic ("charToC "++show 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)]
-\end{code}
diff --git a/ghc/compiler/absCSyn/Costs.lhs b/ghc/compiler/absCSyn/Costs.lhs
deleted file mode 100644 (file)
index 17ea6d5..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
-%
-% $Id: Costs.lhs,v 1.33 2003/07/28 16:05:30 simonmar Exp $
-%
-% Only needed in a GranSim setup -- HWL
-% ---------------------------------------------------------------------------
-
-\section[Costs]{Evaluating the costs of computing some abstract C code}
-
-This module   provides all necessary  functions for   computing for a given
-abstract~C Program the costs of executing that program. This is done by the
-exported function:
-
-\begin{quote}
- {\verb type CostRes = (Int, Int, Int, Int, Int)}
- {\verb costs :: AbstractC -> CostRes }
-\end{quote}
-
-The meaning of the result tuple is:
-\begin{itemize}
- \item The first component ({\tt i}) counts the number of integer,
-   arithmetic and bit-manipulating instructions.
- \item The second component ({\tt b}) counts the number of branches (direct
-   branches as well as indirect ones).
- \item The third component ({\tt l}) counts the number of load instructions.
- \item The fourth component ({\tt s}) counts the number of store
-   instructions.
- \item The fifth component ({\tt f}) counts the number of floating point
-   instructions.
-\end{itemize}
-
-This function is needed in GranSim for costing pieces of abstract C.
-
-These are first suggestions for scaling the costs. But, this scaling should
-be done in the RTS rather than the compiler (this really should be
-tunable!):
-
-\begin{pseudocode}
-
-#define LOAD_COSTS             2
-#define STORE_COSTS            2
-#define INT_ARITHM_COSTS       1
-#define GMP_ARITHM_COSTS       3 {- any clue for GMP costs ? -}
-#define FLOAT_ARITHM_COSTS     3 {- any clue for float costs ? -}
-#define BRANCH_COSTS           2
-
-\end{pseudocode}
-
-\begin{code}
-#define ACCUM_COSTS(i,b,l,s,f) (i+b+l+s+f)
-
-#define NUM_REGS               10 {- PprAbsCSyn.lhs -}       {- runtime/c-as-asm/CallWrap_C.lc -}
-#define RESTORE_COSTS          (Cost (0, 0, NUM_REGS, 0, 0)  :: CostRes)
-#define SAVE_COSTS             (Cost (0, 0, 0, NUM_REGS, 0)  :: CostRes)
-#define CCALL_COSTS_GUESS      (Cost (50, 0, 0, 0, 0)        :: CostRes)
-
-module Costs( costs,
-             addrModeCosts, CostRes(Cost), nullCosts, Side(..)
-    ) where
-
-#include "HsVersions.h"
-
-import AbsCSyn
-import StgSyn          ( StgOp(..) )
-import PrimOp          ( primOpNeedsWrapper, PrimOp(..) )
-import Panic           ( trace )
-
--- --------------------------------------------------------------------------
-data CostRes = Cost (Int, Int, Int, Int, Int)
-              deriving (Show)
-
-nullCosts    = Cost (0, 0, 0, 0, 0) :: CostRes
-initHdrCosts = Cost (2, 0, 0, 1, 0) :: CostRes
-
-instance Eq CostRes where
- (==) t1 t2 = i && b && l && s && f
-            where (i,b,l,s,f) = binOp' (==) t1 t2
-
-instance Num CostRes where
- (+) = binOp (+)
- (-) = binOp (-)
- (*) = binOp (*)
- negate         = mapOp negate
- abs    = mapOp abs
- signum         = mapOp signum
- fromInteger _ = error "fromInteger not defined"
-
-mapOp :: (Int -> Int) -> CostRes -> CostRes
-mapOp g ( Cost (i, b, l, s, f) )  = Cost (g i, g b, g l, g s, g f)
-
-binOp :: (Int -> Int -> Int) -> CostRes -> CostRes -> CostRes
-binOp o ( Cost (i1, b1, l1, s1, f1) ) ( Cost  (i2, b2, l2, s2, f2) )  =
-       ( Cost (i1 `o` i2, b1 `o` b2, l1 `o` l2, s1 `o` s2, f1 `o` f2) )
-
-binOp' :: (Int -> Int -> a) -> CostRes -> CostRes -> (a,a,a,a,a)
-binOp' o ( Cost (i1, b1, l1, s1, f1) ) ( Cost  (i2, b2, l2, s2, f2) )  =
-        (i1 `o` i2, b1 `o` b2, l1 `o` l2, s1 `o` s2, f1 `o` f2)
-
--- --------------------------------------------------------------------------
-
-data Side = Lhs | Rhs
-           deriving (Eq)
-
--- --------------------------------------------------------------------------
-
-costs :: AbstractC -> CostRes
-
-costs absC =
-  case absC of
-   AbsCNop                     ->  nullCosts
-
-   AbsCStmts absC1 absC2       -> costs absC1 + costs absC2
-
-   CAssign (CReg _) (CReg _)   -> Cost (1,0,0,0,0)   -- typ.: mov %reg1,%reg2
-
-   CAssign (CReg _) (CTemp _ _) -> Cost (1,0,0,0,0)
-
-   CAssign (CReg _) source_m   -> addrModeCosts source_m Rhs
-
-   CAssign target_m source_m   -> addrModeCosts target_m Lhs +
-                                  addrModeCosts source_m Rhs
-
-   CJump (CLbl _  _)           -> Cost (0,1,0,0,0)  -- no ld for call necessary
-
-   CJump mode                  -> addrModeCosts mode Rhs +
-                                  Cost (0,1,0,0,0)
-
-   CFallThrough mode  -> addrModeCosts mode Rhs +              -- chu' 0.24
-                        Cost (0,1,0,0,0)
-
-   CReturn mode info  -> case info of
-                         DirectReturn -> addrModeCosts mode Rhs +
-                                         Cost (0,1,0,0,0)
-
-                           -- i.e. ld address to reg and call reg
-
-                         DynamicVectoredReturn mode' ->
-                                       addrModeCosts mode Rhs +
-                                       addrModeCosts mode' Rhs +
-                                       Cost (0,1,1,0,0)
-
-                           {- generates code like this:
-                               JMP_(<mode>)[RVREL(<mode'>)];
-                              i.e. 1 possb ld for mode'
-                                   1 ld for RVREL
-                                   1 possb ld for mode
-                                   1 call                              -}
-
-                         StaticVectoredReturn _ -> addrModeCosts mode Rhs +
-                                                 Cost (0,1,1,0,0)
-
-                           -- as above with mode' fixed to CLit
-                           -- typically 2 ld + 1 call; 1st ld due
-                           -- to CVal as mode
-
-   CSwitch mode alts absC     -> nullCosts
-                                {- for handling costs of all branches of
-                                   a CSwitch see PprAbsC.
-                                   Basically:
-                                    Costs for branch =
-                                       Costs before CSwitch +
-                                       addrModeCosts of head +
-                                       Costs for 1 cond branch +
-                                       Costs for body of branch
-                                -}
-
-   CCodeBlock _ absC         -> costs absC
-
-   CInitHdr cl_info reg_rel cost_centre _ -> initHdrCosts
-
-                       {- This is more fancy but superflous: The addr modes
-                          are fixed and so the costs are const!
-
-                       argCosts + initHdrCosts
-                       where argCosts = addrModeCosts (CAddr reg_rel) Rhs +
-                                        addrModeCosts base_lbl +    -- CLbl!
-                                        3*addrModeCosts (mkIntCLit 1{- any val -})
-                       -}
-                       {- this extends to something like
-                           SET_SPEC_HDR(...)
-                          For costing the args of this macro
-                          see PprAbsC.lhs where args are inserted -}
-
-   COpStmt modes_res op modes_args _ ->
-       {-
-          let
-               n = length modes_res
-          in
-               (0, 0, n, n, 0) +
-               primOpCosts primOp +
-               if primOpNeedsWrapper primOp then SAVE_COSTS + RESTORE_COSTS
-                                            else nullCosts
-          -- ^^HWL
-       -}
-       foldl (+) nullCosts [addrModeCosts mode Lhs | mode <- modes_res]  +
-       foldl (+) nullCosts [addrModeCosts mode Rhs | mode <- modes_args]  +
-       opCosts op
-
-   CSimultaneous absC       -> costs absC
-
-   CCheck _ amodes code             -> Cost (2, 1, 0, 0, 0) -- ToDo: refine this by 
-                                                     -- looking at the first arg 
-
-   CRetDirect _ _ _ _       -> nullCosts
-
-   CMacroStmt  macro modes  -> stmtMacroCosts macro modes
-
-   CCallProfCtrMacro   _ _   -> nullCosts
-                                 {- we don't count profiling in GrAnSim -}
-
-   CCallProfCCMacro    _ _   -> nullCosts
-                                 {- we don't count profiling in GrAnSim -}
-
-  -- *** the next three [or so...] are DATA (those above are CODE) ***
-  -- as they are data rather than code they all have nullCosts        -- HWL
-
-   CCallTypedef _ _ _ _ _    -> nullCosts
-
-   CStaticClosure _ _ _ _    -> nullCosts
-
-   CSRT _ _                  -> nullCosts
-
-   CBitmap _                 -> nullCosts
-
-   CClosureInfoAndCode _ _   -> nullCosts
-
-   CRetVector _ _ _ _        -> nullCosts
-
-   CClosureTbl _             -> nullCosts
-
-   CCostCentreDecl _ _      -> nullCosts
-
-   CCostCentreStackDecl _    -> nullCosts
-
-   CSplitMarker                     -> nullCosts
-
-   _ -> trace ("Costs.costs") nullCosts
-
-
--- ---------------------------------------------------------------------------
-
-addrModeCosts :: CAddrMode -> Side -> CostRes
-
--- addrModeCosts _ _ = nullCosts
-
-addrModeCosts addr_mode side =
-  let
-    lhs = side == Lhs
-  in
-  case addr_mode of
-    CVal _ _ -> if lhs then Cost (0, 0, 0, 1, 0)
-                      else Cost (0, 0, 1, 0, 0)
-
-    CAddr (CIndex _ n _ ) -> Cost (1, 0, 1, 0, 0) -- does pointer arithmetic
-
-    CAddr _ -> nullCosts
-
-    CReg _  -> nullCosts        {- loading from, storing to reg is free ! -}
-                                {- for costing CReg->Creg ops see special -}
-                                {- case in costs fct -}
-
-    CTemp _ _  -> nullCosts    {- if lhs then Cost (0, 0, 0, 1, 0)
-                                         else Cost (0, 0, 1, 0, 0)  -}
-       -- ``Temporaries'' correspond to local variables in C, and registers in
-       -- native code.
-       -- I assume they can be somewhat optimized by gcc -- HWL
-
-    CLbl _ _   -> if lhs then Cost (0, 0, 0, 1, 0)
-                        else Cost (2, 0, 0, 0, 0)
-                 -- Rhs: typically: sethi %hi(lbl),%tmp_reg
-                 --                 or    %tmp_reg,%lo(lbl),%target_reg
-
-    -- Check the following 3 (checked form CLit on)
-
-    CCharLike mode -> if lhs then Cost (0, 0, 0, 1, 0)
-                            else Cost (0, 0, 1, 0, 0)
-
-    CIntLike mode  -> if lhs then Cost (0, 0, 0, 1, 0)
-                            else Cost (0, 0, 1, 0, 0)
-
-    CLit    _     -> if lhs then nullCosts            -- should never occur
-                            else Cost (1, 0, 0, 0, 0) -- typ.: mov lit,%reg
-
-    CJoinPoint _         -> if lhs then Cost (0, 0, 0, 1, 0)
-                                   else Cost (0, 0, 1, 0, 0)
-
-    CMacroExpr _ macro mode_list -> exprMacroCosts side macro mode_list
-
--- ---------------------------------------------------------------------------
-
-exprMacroCosts :: Side -> CExprMacro -> [CAddrMode] -> CostRes
-
-exprMacroCosts side macro mode_list =
-  let
-    arg_costs = foldl (+) nullCosts
-                     (map (\ x -> addrModeCosts x Rhs) mode_list)
-  in
-  arg_costs +
-  case macro of
-    ENTRY_CODE -> nullCosts -- nothing 
-    ARG_TAG -> nullCosts -- nothing
-    GET_TAG -> Cost (0, 0, 1, 0, 0)  -- indirect load
-
--- ---------------------------------------------------------------------------
-
-stmtMacroCosts :: CStmtMacro -> [CAddrMode] -> CostRes
-
-stmtMacroCosts macro modes =
-  case macro of
-    UPD_CAF              ->  Cost (7, 0, 1, 3, 0)       {- SMupdate.lh  -}
-    UPD_BH_UPDATABLE     ->  Cost (3, 0, 0, 1, 0)       {- SMupdate.lh  -}
-    UPD_BH_SINGLE_ENTRY          ->  Cost (3, 0, 0, 1, 0)       {- SMupdate.lh  -}
-    PUSH_UPD_FRAME       ->  Cost (3, 0, 0, 4, 0)       {- Updates.h    -}
-    SET_TAG              ->  nullCosts             {- COptRegs.lh -}
-    GRAN_FETCH                 ->  nullCosts     {- GrAnSim bookkeeping -}
-    GRAN_RESCHEDULE            ->  nullCosts     {- GrAnSim bookkeeping -}
-    GRAN_FETCH_AND_RESCHEDULE  ->  nullCosts     {- GrAnSim bookkeeping -}
-    GRAN_YIELD                 ->  nullCosts     {- GrAnSim bookkeeping -- added SOF -}
-    THREAD_CONTEXT_SWITCH      ->  nullCosts     {- GrAnSim bookkeeping -}
-    _ -> trace ("Costs.stmtMacroCosts") nullCosts
-
--- ---------------------------------------------------------------------------
-
-floatOps :: [PrimOp]
-floatOps =
-  [   FloatGtOp         , FloatGeOp  , FloatEqOp  , FloatNeOp  , FloatLtOp  , FloatLeOp
-    , DoubleGtOp , DoubleGeOp , DoubleEqOp , DoubleNeOp , DoubleLtOp , DoubleLeOp
-    , FloatAddOp , FloatSubOp , FloatMulOp , FloatDivOp , FloatNegOp
-    , Float2IntOp , Int2FloatOp
-    , FloatExpOp   , FloatLogOp          , FloatSqrtOp
-    , FloatSinOp   , FloatCosOp          , FloatTanOp
-    , FloatAsinOp  , FloatAcosOp  , FloatAtanOp
-    , FloatSinhOp  , FloatCoshOp  , FloatTanhOp
-    , FloatPowerOp
-    , DoubleAddOp , DoubleSubOp , DoubleMulOp , DoubleDivOp , DoubleNegOp
-    , Double2IntOp , Int2DoubleOp
-    , Double2FloatOp , Float2DoubleOp
-    , DoubleExpOp   , DoubleLogOp   , DoubleSqrtOp
-    , DoubleSinOp   , DoubleCosOp   , DoubleTanOp
-    , DoubleAsinOp  , DoubleAcosOp  , DoubleAtanOp
-    , DoubleSinhOp  , DoubleCoshOp  , DoubleTanhOp
-    , DoublePowerOp
-    , FloatDecodeOp
-    , DoubleDecodeOp
-  ]
-
-gmpOps :: [PrimOp]
-gmpOps =
-  [   IntegerAddOp , IntegerSubOp , IntegerMulOp
-    , IntegerQuotRemOp , IntegerDivModOp
-    , IntegerCmpOp
-    , Integer2IntOp  , Int2IntegerOp
-  ]
-
-
-umul_costs = Cost (21,4,0,0,0)    -- due to spy counts
-rem_costs =  Cost (30,15,0,0,0)           -- due to spy counts
-div_costs =  Cost (30,15,0,0,0)           -- due to spy counts
-
-
-
--- ---------------------------------------------------------------------------
-
-opCosts :: StgOp -> CostRes
-
-opCosts (StgFCallOp _ _) = SAVE_COSTS + RESTORE_COSTS          
-       -- Don't guess costs of ccall proper
-        -- for exact costing use a GRAN_EXEC in the C code
-
-opCosts (StgPrimOp primop)
-  = primOpCosts primop +
-    if primOpNeedsWrapper primop then SAVE_COSTS + RESTORE_COSTS
-                                else nullCosts
-
-primOpCosts :: PrimOp -> CostRes
-
--- Usually 3 mov instructions are needed to get args and res in right place.
-primOpCosts IntMulOp  = Cost (3, 1, 0, 0, 0)  + umul_costs
-primOpCosts IntQuotOp = Cost (3, 1, 0, 0, 0)  + div_costs
-primOpCosts IntRemOp  = Cost (3, 1, 0, 0, 0)  + rem_costs
-primOpCosts IntNegOp  = Cost (1, 1, 0, 0, 0) -- translates into 1 sub
-
-primOpCosts FloatGtOp  = Cost (2, 0, 0, 0, 2) -- expensive f-comp
-primOpCosts FloatGeOp  = Cost (2, 0, 0, 0, 2) -- expensive f-comp
-primOpCosts FloatEqOp  = Cost (0, 0, 0, 0, 2) -- cheap f-comp
-primOpCosts FloatNeOp  = Cost (0, 0, 0, 0, 2) -- cheap f-comp
-primOpCosts FloatLtOp  = Cost (2, 0, 0, 0, 2) -- expensive f-comp
-primOpCosts FloatLeOp  = Cost (2, 0, 0, 0, 2) -- expensive f-comp
-primOpCosts DoubleGtOp = Cost (2, 0, 0, 0, 2) -- expensive f-comp
-primOpCosts DoubleGeOp = Cost (2, 0, 0, 0, 2) -- expensive f-comp
-primOpCosts DoubleEqOp = Cost (0, 0, 0, 0, 2) -- cheap f-comp
-primOpCosts DoubleNeOp = Cost (0, 0, 0, 0, 2) -- cheap f-comp
-primOpCosts DoubleLtOp = Cost (2, 0, 0, 0, 2) -- expensive f-comp
-primOpCosts DoubleLeOp = Cost (2, 0, 0, 0, 2) -- expensive f-comp
-
-primOpCosts FloatExpOp   = Cost (2, 1, 4, 4, 3)
-primOpCosts FloatLogOp   = Cost (2, 1, 4, 4, 3)
-primOpCosts FloatSqrtOp          = Cost (2, 1, 4, 4, 3)
-primOpCosts FloatSinOp   = Cost (2, 1, 4, 4, 3)
-primOpCosts FloatCosOp   = Cost (2, 1, 4, 4, 3)
-primOpCosts FloatTanOp   = Cost (2, 1, 4, 4, 3)
-primOpCosts FloatAsinOp          = Cost (2, 1, 4, 4, 3)
-primOpCosts FloatAcosOp          = Cost (2, 1, 4, 4, 3)
-primOpCosts FloatAtanOp          = Cost (2, 1, 4, 4, 3)
-primOpCosts FloatSinhOp          = Cost (2, 1, 4, 4, 3)
-primOpCosts FloatCoshOp          = Cost (2, 1, 4, 4, 3)
-primOpCosts FloatTanhOp          = Cost (2, 1, 4, 4, 3)
---primOpCosts FloatAsinhOp  = Cost (2, 1, 4, 4, 3)
---primOpCosts FloatAcoshOp  = Cost (2, 1, 4, 4, 3)
---primOpCosts FloatAtanhOp  = Cost (2, 1, 4, 4, 3)
-primOpCosts FloatPowerOp  = Cost (2, 1, 4, 4, 3)
-
-{- There should be special handling of the Array PrimOps in here   HWL -}
-
-primOpCosts primOp
-  | primOp `elem` floatOps = Cost (0, 0, 0, 0, 1)  :: CostRes
-  | primOp `elem` gmpOps   = Cost (30, 5, 10, 10, 0) :: CostRes  -- GUESS; check it
-  | otherwise             = Cost (1, 0, 0, 0, 0)
-
-\end{code}
diff --git a/ghc/compiler/absCSyn/MachOp.hs b/ghc/compiler/absCSyn/MachOp.hs
deleted file mode 100644 (file)
index 087a403..0000000
+++ /dev/null
@@ -1,460 +0,0 @@
-
-module MachOp  ( MachOp(..), pprMachOp,
-                 isDefinitelyInlineMachOp, 
-                 isCommutableMachOp,
-                 isComparisonMachOp,
-                  resultRepOfMachOp
-                 )
-where
-
-#include "HsVersions.h"
-
-import PrimRep         ( PrimRep(..) )
-import Outputable
-
-
-{- 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
-
-  -- OPS at the native word size
-  = MO_Nat_Add         -- +
-  | MO_Nat_Sub         -- -
-  | MO_Nat_Eq
-  | MO_Nat_Ne
-
-  | MO_NatS_Ge
-  | MO_NatS_Le
-  | MO_NatS_Gt
-  | MO_NatS_Lt
-
-  | MO_NatU_Ge
-  | MO_NatU_Le
-  | MO_NatU_Gt
-  | MO_NatU_Lt
-
-  | MO_NatS_Mul                -- low word of signed *
-  | MO_NatS_MulMayOflo -- nonzero if high word of signed * might contain useful info
-  | MO_NatS_Quot       -- signed / (same semantics as IntQuotOp)
-  | MO_NatS_Rem                -- signed % (same semantics as IntRemOp)
-  | MO_NatS_Neg                -- unary -
-
-  | MO_NatU_Mul                -- low word of unsigned *
-  | MO_NatU_Quot       -- unsigned / (same semantics as WordQuotOp)
-  | MO_NatU_Rem                -- unsigned % (same semantics as WordRemOp)
-
-  | MO_Nat_And
-  | MO_Nat_Or
-  | MO_Nat_Xor
-  | MO_Nat_Not
-  | MO_Nat_Shl
-  | MO_Nat_Shr
-  | MO_Nat_Sar
-
-  -- OPS at 32 bits regardless of word size
-  | MO_32U_Eq
-  | MO_32U_Ne
-  | MO_32U_Ge
-  | MO_32U_Le
-  | MO_32U_Gt
-  | MO_32U_Lt
-
-  -- IEEE754 Double ops
-  | MO_Dbl_Eq
-  | MO_Dbl_Ne
-  | MO_Dbl_Ge
-  | MO_Dbl_Le
-  | MO_Dbl_Gt
-  | MO_Dbl_Lt
-
-  | MO_Dbl_Add
-  | MO_Dbl_Sub
-  | MO_Dbl_Mul
-  | MO_Dbl_Div
-  | MO_Dbl_Pwr
-
-  | MO_Dbl_Sin
-  | MO_Dbl_Cos
-  | MO_Dbl_Tan
-  | MO_Dbl_Sinh
-  | MO_Dbl_Cosh
-  | MO_Dbl_Tanh
-  | MO_Dbl_Asin
-  | MO_Dbl_Acos
-  | MO_Dbl_Atan
-  | MO_Dbl_Log
-  | MO_Dbl_Exp
-  | MO_Dbl_Sqrt
-  | MO_Dbl_Neg
-
-  -- IEEE754 Float ops
-  | MO_Flt_Add
-  | MO_Flt_Sub
-  | MO_Flt_Mul
-  | MO_Flt_Div
-  | MO_Flt_Pwr
-
-  | MO_Flt_Eq
-  | MO_Flt_Ne
-  | MO_Flt_Ge
-  | MO_Flt_Le
-  | MO_Flt_Gt
-  | MO_Flt_Lt
-
-  | MO_Flt_Sin
-  | MO_Flt_Cos
-  | MO_Flt_Tan
-  | MO_Flt_Sinh
-  | MO_Flt_Cosh
-  | MO_Flt_Tanh
-  | MO_Flt_Asin
-  | MO_Flt_Acos
-  | MO_Flt_Atan
-  | MO_Flt_Log
-  | MO_Flt_Exp
-  | MO_Flt_Neg
-  | MO_Flt_Sqrt
-
-  -- Conversions.  Some of these are NOPs, in which case they
-  -- are here usually to placate the C code generator.
-  | MO_32U_to_NatS
-  | MO_NatS_to_32U
-
-  | MO_NatS_to_Dbl
-  | MO_Dbl_to_NatS
-
-  | MO_NatS_to_Flt
-  | MO_Flt_to_NatS
-
-  | MO_NatS_to_NatU
-  | MO_NatU_to_NatS
-
-  | MO_NatS_to_NatP
-  | MO_NatP_to_NatS
-  | MO_NatU_to_NatP
-  | MO_NatP_to_NatU
-
-  | MO_Dbl_to_Flt
-  | MO_Flt_to_Dbl
-
-  | MO_8S_to_NatS
-  | MO_16S_to_NatS
-  | MO_32S_to_NatS
-  | MO_8U_to_NatU
-  | MO_16U_to_NatU
-  | MO_32U_to_NatU
-
-  | MO_8U_to_32U       -- zero extend
-  | MO_32U_to_8U       -- mask out all but lowest byte
-
-    deriving Eq
-
-
-
--- Almost, but not quite == text . derived show
-pprMachOp :: MachOp -> SDoc
-
-pprMachOp MO_Nat_Add       = text "MO_Nat_Add"
-pprMachOp MO_Nat_Sub       = text "MO_Nat_Sub"
-pprMachOp MO_Nat_Eq        = text "MO_Nat_Eq"
-pprMachOp MO_Nat_Ne        = text "MO_Nat_Ne"
-
-pprMachOp MO_NatS_Ge       = text "MO_NatS_Ge"
-pprMachOp MO_NatS_Le       = text "MO_NatS_Le"
-pprMachOp MO_NatS_Gt       = text "MO_NatS_Gt"
-pprMachOp MO_NatS_Lt       = text "MO_NatS_Lt"
-
-pprMachOp MO_NatU_Ge       = text "MO_NatU_Ge"
-pprMachOp MO_NatU_Le       = text "MO_NatU_Le"
-pprMachOp MO_NatU_Gt       = text "MO_NatU_Gt"
-pprMachOp MO_NatU_Lt       = text "MO_NatU_Lt"
-
-pprMachOp MO_NatS_Mul      = text "MO_NatS_Mul"
-pprMachOp MO_NatS_MulMayOflo = text "MO_NatS_MulMayOflo"
-pprMachOp MO_NatS_Quot     = text "MO_NatS_Quot"
-pprMachOp MO_NatS_Rem      = text "MO_NatS_Rem"
-pprMachOp MO_NatS_Neg      = text "MO_NatS_Neg"
-
-pprMachOp MO_NatU_Mul      = text "MO_NatU_Mul"
-pprMachOp MO_NatU_Quot     = text "MO_NatU_Quot"
-pprMachOp MO_NatU_Rem      = text "MO_NatU_Rem"
-
-pprMachOp MO_Nat_And       = text "MO_Nat_And"
-pprMachOp MO_Nat_Or        = text "MO_Nat_Or"
-pprMachOp MO_Nat_Xor       = text "MO_Nat_Xor"
-pprMachOp MO_Nat_Not       = text "MO_Nat_Not"
-pprMachOp MO_Nat_Shl       = text "MO_Nat_Shl"
-pprMachOp MO_Nat_Shr       = text "MO_Nat_Shr"
-pprMachOp MO_Nat_Sar       = text "MO_Nat_Sar"
-
-pprMachOp MO_32U_Eq        = text "MO_32U_Eq"
-pprMachOp MO_32U_Ne        = text "MO_32U_Ne"
-pprMachOp MO_32U_Ge        = text "MO_32U_Ge"
-pprMachOp MO_32U_Le        = text "MO_32U_Le"
-pprMachOp MO_32U_Gt        = text "MO_32U_Gt"
-pprMachOp MO_32U_Lt        = text "MO_32U_Lt"
-
-pprMachOp MO_Dbl_Eq        = text "MO_Dbl_Eq"
-pprMachOp MO_Dbl_Ne        = text "MO_Dbl_Ne"
-pprMachOp MO_Dbl_Ge        = text "MO_Dbl_Ge"
-pprMachOp MO_Dbl_Le        = text "MO_Dbl_Le"
-pprMachOp MO_Dbl_Gt        = text "MO_Dbl_Gt"
-pprMachOp MO_Dbl_Lt        = text "MO_Dbl_Lt"
-
-pprMachOp MO_Dbl_Add       = text "MO_Dbl_Add"
-pprMachOp MO_Dbl_Sub       = text "MO_Dbl_Sub"
-pprMachOp MO_Dbl_Mul       = text "MO_Dbl_Mul"
-pprMachOp MO_Dbl_Div       = text "MO_Dbl_Div"
-pprMachOp MO_Dbl_Pwr       = text "MO_Dbl_Pwr"
-
-pprMachOp MO_Dbl_Sin       = text "MO_Dbl_Sin"
-pprMachOp MO_Dbl_Cos       = text "MO_Dbl_Cos"
-pprMachOp MO_Dbl_Tan       = text "MO_Dbl_Tan"
-pprMachOp MO_Dbl_Sinh      = text "MO_Dbl_Sinh"
-pprMachOp MO_Dbl_Cosh      = text "MO_Dbl_Cosh"
-pprMachOp MO_Dbl_Tanh      = text "MO_Dbl_Tanh"
-pprMachOp MO_Dbl_Asin      = text "MO_Dbl_Asin"
-pprMachOp MO_Dbl_Acos      = text "MO_Dbl_Acos"
-pprMachOp MO_Dbl_Atan      = text "MO_Dbl_Atan"
-pprMachOp MO_Dbl_Log       = text "MO_Dbl_Log"
-pprMachOp MO_Dbl_Exp       = text "MO_Dbl_Exp"
-pprMachOp MO_Dbl_Sqrt      = text "MO_Dbl_Sqrt"
-pprMachOp MO_Dbl_Neg       = text "MO_Dbl_Neg"
-
-pprMachOp MO_Flt_Add       = text "MO_Flt_Add"
-pprMachOp MO_Flt_Sub       = text "MO_Flt_Sub"
-pprMachOp MO_Flt_Mul       = text "MO_Flt_Mul"
-pprMachOp MO_Flt_Div       = text "MO_Flt_Div"
-pprMachOp MO_Flt_Pwr       = text "MO_Flt_Pwr"
-
-pprMachOp MO_Flt_Eq        = text "MO_Flt_Eq"
-pprMachOp MO_Flt_Ne        = text "MO_Flt_Ne"
-pprMachOp MO_Flt_Ge        = text "MO_Flt_Ge"
-pprMachOp MO_Flt_Le        = text "MO_Flt_Le"
-pprMachOp MO_Flt_Gt        = text "MO_Flt_Gt"
-pprMachOp MO_Flt_Lt        = text "MO_Flt_Lt"
-
-pprMachOp MO_Flt_Sin       = text "MO_Flt_Sin"
-pprMachOp MO_Flt_Cos       = text "MO_Flt_Cos"
-pprMachOp MO_Flt_Tan       = text "MO_Flt_Tan"
-pprMachOp MO_Flt_Sinh      = text "MO_Flt_Sinh"
-pprMachOp MO_Flt_Cosh      = text "MO_Flt_Cosh"
-pprMachOp MO_Flt_Tanh      = text "MO_Flt_Tanh"
-pprMachOp MO_Flt_Asin      = text "MO_Flt_Asin"
-pprMachOp MO_Flt_Acos      = text "MO_Flt_Acos"
-pprMachOp MO_Flt_Atan      = text "MO_Flt_Atan"
-pprMachOp MO_Flt_Log       = text "MO_Flt_Log"
-pprMachOp MO_Flt_Exp       = text "MO_Flt_Exp"
-pprMachOp MO_Flt_Sqrt      = text "MO_Flt_Sqrt"
-pprMachOp MO_Flt_Neg       = text "MO_Flt_Neg"
-
-pprMachOp MO_32U_to_NatS   = text "MO_32U_to_NatS"
-pprMachOp MO_NatS_to_32U   = text "MO_NatS_to_32U"
-
-pprMachOp MO_NatS_to_Dbl   = text "MO_NatS_to_Dbl"
-pprMachOp MO_Dbl_to_NatS   = text "MO_Dbl_to_NatS"
-
-pprMachOp MO_NatS_to_Flt   = text "MO_NatS_to_Flt"
-pprMachOp MO_Flt_to_NatS   = text "MO_Flt_to_NatS"
-
-pprMachOp MO_NatS_to_NatU  = text "MO_NatS_to_NatU"
-pprMachOp MO_NatU_to_NatS  = text "MO_NatU_to_NatS"
-
-pprMachOp MO_NatS_to_NatP  = text "MO_NatS_to_NatP"
-pprMachOp MO_NatP_to_NatS  = text "MO_NatP_to_NatS"
-pprMachOp MO_NatU_to_NatP  = text "MO_NatU_to_NatP"
-pprMachOp MO_NatP_to_NatU  = text "MO_NatP_to_NatU"
-
-pprMachOp MO_Dbl_to_Flt    = text "MO_Dbl_to_Flt"
-pprMachOp MO_Flt_to_Dbl    = text "MO_Flt_to_Dbl"
-
-pprMachOp MO_8S_to_NatS    = text "MO_8S_to_NatS"
-pprMachOp MO_16S_to_NatS   = text "MO_16S_to_NatS"
-pprMachOp MO_32S_to_NatS   = text "MO_32S_to_NatS"
-
-pprMachOp MO_8U_to_NatU    = text "MO_8U_to_NatU"
-pprMachOp MO_16U_to_NatU   = text "MO_16U_to_NatU"
-pprMachOp MO_32U_to_NatU   = text "MO_32U_to_NatU"
-
-pprMachOp MO_8U_to_32U     = text "MO_8U_to_32U"
-pprMachOp MO_32U_to_8U     = text "MO_32U_to_8U"
-
-
-
--- Non-exported helper enumeration:
-data MO_Prop 
-   = MO_Commutable 
-   | MO_DefinitelyInline 
-   | MO_Comparison
-     deriving Eq
-
-comm   = MO_Commutable
-inline = MO_DefinitelyInline
-comp   = MO_Comparison
-
-
--- If in doubt, return False.  This generates worse code on the
--- via-C route, but has no effect on the native code routes.
--- Remember that claims about definitely inline have to be true
--- regardless of what the C compiler does, so we need to be 
--- careful about boundary cases like sqrt which are sometimes
--- implemented in software and sometimes in hardware.
-isDefinitelyInlineMachOp :: MachOp -> Bool
-isDefinitelyInlineMachOp mop = inline `elem` snd (machOpProps mop)
-
--- If in doubt, return False.  This generates worse code on the
--- native routes, but is otherwise harmless.
-isCommutableMachOp :: MachOp -> Bool
-isCommutableMachOp mop = comm `elem` snd (machOpProps mop)
-
--- If in doubt, return False.  This generates worse code on the
--- native routes, but is otherwise harmless.
-isComparisonMachOp :: MachOp -> Bool
-isComparisonMachOp mop = comp `elem` snd (machOpProps mop)
-
--- Find the PrimRep for the returned value of the MachOp.
-resultRepOfMachOp :: MachOp -> PrimRep
-resultRepOfMachOp mop = fst (machOpProps mop)
-
--- This bit does the real work.
-machOpProps :: MachOp -> (PrimRep, [MO_Prop])
-
-machOpProps MO_Nat_Add       = (IntRep, [inline, comm])
-machOpProps MO_Nat_Sub       = (IntRep, [inline])
-machOpProps MO_Nat_Eq        = (IntRep, [inline, comp, comm])
-machOpProps MO_Nat_Ne        = (IntRep, [inline, comp, comm])
-
-machOpProps MO_NatS_Ge       = (IntRep, [inline, comp])
-machOpProps MO_NatS_Le       = (IntRep, [inline, comp])
-machOpProps MO_NatS_Gt       = (IntRep, [inline, comp])
-machOpProps MO_NatS_Lt       = (IntRep, [inline, comp])
-
-machOpProps MO_NatU_Ge       = (IntRep, [inline, comp])
-machOpProps MO_NatU_Le       = (IntRep, [inline, comp])
-machOpProps MO_NatU_Gt       = (IntRep, [inline, comp])
-machOpProps MO_NatU_Lt       = (IntRep, [inline, comp])
-
-machOpProps MO_NatS_Mul      = (IntRep, [inline, comm])
-machOpProps MO_NatS_MulMayOflo = (IntRep, [inline, comm])
-machOpProps MO_NatS_Quot     = (IntRep, [inline])
-machOpProps MO_NatS_Rem      = (IntRep, [inline])
-machOpProps MO_NatS_Neg      = (IntRep, [inline])
-
-machOpProps MO_NatU_Mul      = (WordRep, [inline, comm])
-machOpProps MO_NatU_Quot     = (WordRep, [inline])
-machOpProps MO_NatU_Rem      = (WordRep, [inline])
-
-machOpProps MO_Nat_And       = (IntRep, [inline, comm])
-machOpProps MO_Nat_Or        = (IntRep, [inline, comm])
-machOpProps MO_Nat_Xor       = (IntRep, [inline, comm])
-machOpProps MO_Nat_Not       = (IntRep, [inline])
-machOpProps MO_Nat_Shl       = (IntRep, [inline])
-machOpProps MO_Nat_Shr       = (IntRep, [inline])
-machOpProps MO_Nat_Sar       = (IntRep, [inline])
-
-machOpProps MO_32U_Eq        = (IntRep, [inline, comp, comm])
-machOpProps MO_32U_Ne        = (IntRep, [inline, comp, comm])
-machOpProps MO_32U_Ge        = (IntRep, [inline, comp])
-machOpProps MO_32U_Le        = (IntRep, [inline, comp])
-machOpProps MO_32U_Gt        = (IntRep, [inline, comp])
-machOpProps MO_32U_Lt        = (IntRep, [inline, comp])
-
-machOpProps MO_Dbl_Eq        = (IntRep, [inline, comp, comm])
-machOpProps MO_Dbl_Ne        = (IntRep, [inline, comp, comm])
-machOpProps MO_Dbl_Ge        = (IntRep, [inline, comp])
-machOpProps MO_Dbl_Le        = (IntRep, [inline, comp])
-machOpProps MO_Dbl_Gt        = (IntRep, [inline, comp])
-machOpProps MO_Dbl_Lt        = (IntRep, [inline, comp])
-
-machOpProps MO_Dbl_Add       = (DoubleRep, [inline, comm])
-machOpProps MO_Dbl_Sub       = (DoubleRep, [inline])
-machOpProps MO_Dbl_Mul       = (DoubleRep, [inline, comm])
-machOpProps MO_Dbl_Div       = (DoubleRep, [inline])
-machOpProps MO_Dbl_Pwr       = (DoubleRep, [])
-
-machOpProps MO_Dbl_Sin       = (DoubleRep, [])
-machOpProps MO_Dbl_Cos       = (DoubleRep, [])
-machOpProps MO_Dbl_Tan       = (DoubleRep, [])
-machOpProps MO_Dbl_Sinh      = (DoubleRep, [])
-machOpProps MO_Dbl_Cosh      = (DoubleRep, [])
-machOpProps MO_Dbl_Tanh      = (DoubleRep, [])
-machOpProps MO_Dbl_Asin      = (DoubleRep, [])
-machOpProps MO_Dbl_Acos      = (DoubleRep, [])
-machOpProps MO_Dbl_Atan      = (DoubleRep, [])
-machOpProps MO_Dbl_Log       = (DoubleRep, [])
-machOpProps MO_Dbl_Exp       = (DoubleRep, [])
-machOpProps MO_Dbl_Sqrt      = (DoubleRep, [])
-machOpProps MO_Dbl_Neg       = (DoubleRep, [inline])
-
-machOpProps MO_Flt_Add       = (FloatRep, [inline, comm])
-machOpProps MO_Flt_Sub       = (FloatRep, [inline])
-machOpProps MO_Flt_Mul       = (FloatRep, [inline, comm])
-machOpProps MO_Flt_Div       = (FloatRep, [inline])
-machOpProps MO_Flt_Pwr       = (FloatRep, [])
-
-machOpProps MO_Flt_Eq        = (IntRep, [inline, comp, comm])
-machOpProps MO_Flt_Ne        = (IntRep, [inline, comp, comm])
-machOpProps MO_Flt_Ge        = (IntRep, [inline, comp])
-machOpProps MO_Flt_Le        = (IntRep, [inline, comp])
-machOpProps MO_Flt_Gt        = (IntRep, [inline, comp])
-machOpProps MO_Flt_Lt        = (IntRep, [inline, comp])
-
-machOpProps MO_Flt_Sin       = (FloatRep, [])
-machOpProps MO_Flt_Cos       = (FloatRep, [])
-machOpProps MO_Flt_Tan       = (FloatRep, [])
-machOpProps MO_Flt_Sinh      = (FloatRep, [])
-machOpProps MO_Flt_Cosh      = (FloatRep, [])
-machOpProps MO_Flt_Tanh      = (FloatRep, [])
-machOpProps MO_Flt_Asin      = (FloatRep, [])
-machOpProps MO_Flt_Acos      = (FloatRep, [])
-machOpProps MO_Flt_Atan      = (FloatRep, [])
-machOpProps MO_Flt_Log       = (FloatRep, [])
-machOpProps MO_Flt_Exp       = (FloatRep, [])
-machOpProps MO_Flt_Sqrt      = (FloatRep, [])
-machOpProps MO_Flt_Neg       = (FloatRep, [inline])
-
-machOpProps MO_32U_to_NatS   = (IntRep, [inline])
-machOpProps MO_NatS_to_32U   = (Word32Rep, [inline])
-
-machOpProps MO_NatS_to_Dbl   = (DoubleRep, [inline])
-machOpProps MO_Dbl_to_NatS   = (IntRep, [inline])
-
-machOpProps MO_NatS_to_Flt   = (FloatRep, [inline])
-machOpProps MO_Flt_to_NatS   = (IntRep, [inline])
-
-machOpProps MO_NatS_to_NatU  = (WordRep, [inline])
-machOpProps MO_NatU_to_NatS  = (IntRep, [inline])
-
-machOpProps MO_NatS_to_NatP  = (PtrRep, [inline])
-machOpProps MO_NatP_to_NatS  = (IntRep, [inline])
-machOpProps MO_NatU_to_NatP  = (PtrRep, [inline])
-machOpProps MO_NatP_to_NatU  = (WordRep, [inline])
-
-machOpProps MO_Dbl_to_Flt    = (FloatRep, [inline])
-machOpProps MO_Flt_to_Dbl    = (DoubleRep, [inline])
-
-machOpProps MO_8S_to_NatS    = (IntRep, [inline])
-machOpProps MO_16S_to_NatS   = (IntRep, [inline])
-machOpProps MO_32S_to_NatS   = (IntRep, [inline])
-
-machOpProps MO_8U_to_NatU    = (WordRep, [inline])
-machOpProps MO_16U_to_NatU   = (WordRep, [inline])
-machOpProps MO_32U_to_NatU   = (WordRep, [inline])
-
-machOpProps MO_8U_to_32U     = (Word32Rep, [inline])
-machOpProps MO_32U_to_8U     = (Word8Rep, [inline])
diff --git a/ghc/compiler/absCSyn/PprAbsC.lhs b/ghc/compiler/absCSyn/PprAbsC.lhs
deleted file mode 100644 (file)
index 76b1f43..0000000
+++ /dev/null
@@ -1,1804 +0,0 @@
-%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
-%
-%************************************************************************
-%*                                                                     *
-\section[PprAbsC]{Pretty-printing Abstract~C}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-module PprAbsC (
-       writeRealC,
-       dumpRealC,
-       pprAmode,
-       pprMagicId
-    ) where
-
-#include "HsVersions.h"
-
-import IO      ( Handle )
-
-import PrimRep 
-import AbsCSyn
-import ClosureInfo
-import AbsCUtils       ( getAmodeRep, nonemptyAbsC,
-                         mixedPtrLocn, mixedTypeLocn
-                       )
-
-import ForeignCall     ( CCallSpec(..), CCallTarget(..), playSafe,
-                         playThreadSafe, ccallConvAttribute,
-                         ForeignCall(..), DNCallSpec(..),
-                         DNType(..), DNKind(..) )
-import CLabel          ( externallyVisibleCLabel,
-                         needsCDecl, pprCLabel, mkClosureLabel,
-                         mkReturnInfoLabel, mkReturnPtLabel, mkClosureTblLabel,
-                         CLabel, CLabelType(..), labelType, labelDynamic
-                       )
-
-import CmdLineOpts     ( opt_SccProfilingOn, opt_GranMacros )
-import CostCentre      ( pprCostCentreDecl, pprCostCentreStackDecl )
-
-import Costs           ( costs, addrModeCosts, CostRes(..), Side(..) )
-import CStrings                ( pprCLabelString )
-import FiniteMap       ( addToFM, emptyFM, lookupFM, FiniteMap )
-import Literal         ( Literal(..) )
-import TyCon           ( tyConDataCons )
-import Name            ( NamedThing(..) )
-import Maybes          ( catMaybes )
-import PrimOp          ( primOpNeedsWrapper )
-import MachOp          ( MachOp(..) )
-import PrimRep         ( isFloatingRep, PrimRep(..), getPrimRepSize )
-import Unique          ( pprUnique, Unique{-instance NamedThing-} )
-import UniqSet         ( emptyUniqSet, elementOfUniqSet,
-                         addOneToUniqSet, UniqSet
-                       )
-import StgSyn          ( StgOp(..) )
-import Outputable
-import FastString
-import Util            ( lengthExceeds )
-
-#if __GLASGOW_HASKELL__ >= 504
-import Data.Array.ST
-#endif
-
-#ifdef DEBUG
-import Util            ( listLengthCmp )
-#endif
-
-import Maybe           ( isJust )
-import GLAEXTS
-import MONAD_ST
-
-infixr 9 `thenTE`
-\end{code}
-
-For spitting out the costs of an abstract~C expression, @writeRealC@
-now not only prints the C~code of the @absC@ arg but also adds a macro
-call to a cost evaluation function @GRAN_EXEC@. For that,
-@pprAbsC@ has a new ``costs'' argument.  %% HWL
-
-\begin{code}
-{-
-writeRealC :: Handle -> AbstractC -> IO ()
-writeRealC handle absC
-     -- avoid holding on to the whole of absC in the !Gransim case.
-     if opt_GranMacros
-       then printForCFast fp (pprAbsC absC (costs absC))
-       else printForCFast fp (pprAbsC absC (panic "costs"))
-            --printForC handle (pprAbsC absC (panic "costs"))
-dumpRealC :: AbstractC -> SDoc
-dumpRealC absC = pprAbsC absC (costs absC)
--}
-
-writeRealC :: Handle -> AbstractC -> IO ()
---writeRealC handle absC = 
--- _scc_ "writeRealC" 
--- printDoc LeftMode handle (pprAbsC absC (costs absC))
-
-writeRealC handle absC
- | opt_GranMacros = _scc_ "writeRealC" printForC handle $ 
-                                      pprCode CStyle (pprAbsC absC (costs absC))
- | otherwise     = _scc_ "writeRealC" printForC handle $
-                                      pprCode CStyle (pprAbsC absC (panic "costs"))
-
-dumpRealC :: AbstractC -> SDoc
-dumpRealC absC
- | opt_GranMacros = pprCode CStyle (pprAbsC absC (costs absC))
- | otherwise     = pprCode CStyle (pprAbsC absC (panic "costs"))
-
-\end{code}
-
-This emits the macro,  which is used in GrAnSim  to compute the total costs
-from a cost 5 tuple. %%  HWL
-
-\begin{code}
-emitMacro :: CostRes -> SDoc
-
-emitMacro _ | not opt_GranMacros = empty
-
-emitMacro (Cost (i,b,l,s,f))
-  = hcat [ ptext SLIT("GRAN_EXEC"), char '(',
-                          int i, comma, int b, comma, int l, comma,
-                         int s, comma, int f, pp_paren_semi ]
-
-pp_paren_semi = text ");"
-\end{code}
-
-New type: Now pprAbsC also takes the costs for evaluating the Abstract C
-code as an argument (that's needed when spitting out the GRAN_EXEC macro
-which must be done before the return i.e. inside absC code)   HWL
-
-\begin{code}
-pprAbsC :: AbstractC -> CostRes -> SDoc
-pprAbsC AbsCNop _ = empty
-pprAbsC (AbsCStmts s1 s2) c = ($$) (pprAbsC s1 c) (pprAbsC s2 c)
-
-pprAbsC (CAssign dest src) _ = pprAssign (getAmodeRep dest) dest src
-
-pprAbsC (CJump target) c
-  = ($$) (hcat [emitMacro c {-WDP:, text "/* <--++  CJump */"-} ])
-            (hcat [ text jmp_lit, pprAmode target, pp_paren_semi ])
-
-pprAbsC (CFallThrough target) c
-  = ($$) (hcat [emitMacro c {-WDP:, text "/* <--++  CFallThrough */"-} ])
-            (hcat [ text jmp_lit, pprAmode target, pp_paren_semi ])
-
--- --------------------------------------------------------------------------
--- Spit out GRAN_EXEC macro immediately before the return                 HWL
-
-pprAbsC (CReturn am return_info)  c
-  = ($$) (hcat [emitMacro c {-WDP:, text "/* <----  CReturn */"-} ])
-            (hcat [text jmp_lit, target, pp_paren_semi ])
-  where
-   target = case return_info of
-       DirectReturn -> hcat [ptext SLIT("ENTRY_CODE"), lparen,
-                             pprAmode am, rparen]
-       DynamicVectoredReturn am' -> mk_vector (pprAmode am')
-       StaticVectoredReturn n -> mk_vector (int n)     -- Always positive
-   mk_vector x = hcat [ptext SLIT("RET_VEC"), char '(', pprAmode am, comma,
-                      x, rparen ]
-
-pprAbsC (CSplitMarker) _ = ptext SLIT("__STG_SPLIT_MARKER")
-
--- we optimise various degenerate cases of CSwitches.
-
--- --------------------------------------------------------------------------
--- Assume: CSwitch is also end of basic block
---         costs function yields nullCosts for whole switch
---         ==> inherited costs c are those of basic block up to switch
---         ==> inherit c + costs for the corresponding branch
---                                                                       HWL
--- --------------------------------------------------------------------------
-
-pprAbsC (CSwitch discrim [] deflt) c
-  = pprAbsC deflt (c + costs deflt)
-    -- Empty alternative list => no costs for discrim as nothing cond. here HWL
-
-pprAbsC (CSwitch discrim [(tag,alt_code)] deflt) c -- only one alt
-  = case (nonemptyAbsC deflt) of
-      Nothing ->               -- one alt and no default
-                pprAbsC alt_code (c + costs alt_code)
-                -- Nothing conditional in here either  HWL
-
-      Just dc ->               -- make it an "if"
-                do_if_stmt discrim tag alt_code dc c
-
--- What problem is the re-ordering trying to solve ?
-pprAbsC (CSwitch discrim [(tag1@(MachInt i1), alt_code1),
-                         (tag2@(MachInt i2), alt_code2)] deflt) c
-  | empty_deflt && ((i1 == 0 && i2 == 1) || (i1 == 1 && i2 == 0))
-  = if (i1 == 0) then
-       do_if_stmt discrim tag1 alt_code1 alt_code2 c
-    else
-       do_if_stmt discrim tag2 alt_code2 alt_code1 c
-  where
-    empty_deflt = not (isJust (nonemptyAbsC deflt))
-
-pprAbsC (CSwitch discrim alts deflt) c -- general case
-  | isFloatingRep (getAmodeRep discrim)
-    = pprAbsC (foldr ( \ a -> CSwitch discrim [a]) deflt alts) c
-  | otherwise
-    = vcat [
-       hcat [text "switch (", pp_discrim, text ") {"],
-       nest 2 (vcat (map ppr_alt alts)),
-       (case (nonemptyAbsC deflt) of
-          Nothing -> empty
-          Just dc ->
-           nest 2 (vcat [ptext SLIT("default:"),
-                                 pprAbsC dc (c + switch_head_cost
-                                                   + costs dc),
-                                 ptext SLIT("break;")])),
-       char '}' ]
-  where
-    pp_discrim
-      = pprAmode discrim
-
-    ppr_alt (lit, absC)
-      = vcat [ hcat [ptext SLIT("case "), pprBasicLit lit, char ':'],
-                  nest 2 (($$) (pprAbsC absC (c + switch_head_cost + costs absC))
-                                      (ptext SLIT("break;"))) ]
-
-    -- Costs for addressing header of switch and cond. branching        -- HWL
-    switch_head_cost = addrModeCosts discrim Rhs + (Cost (0, 1, 0, 0, 0))
-
-pprAbsC stmt@(COpStmt results (StgFCallOp fcall uniq) args vol_regs) _
-  = pprFCall fcall uniq args results vol_regs
-
-pprAbsC stmt@(COpStmt results (StgPrimOp op) args vol_regs) _
-  = let
-       non_void_args = grab_non_void_amodes args
-       non_void_results = grab_non_void_amodes results
-       -- if just one result, we print in the obvious "assignment" style;
-       -- if 0 or many results, we emit a macro call, w/ the results
-       -- followed by the arguments.  The macro presumably knows which
-       -- are which :-)
-
-       the_op = ppr_op_call non_void_results non_void_args
-               -- liveness mask is *in* the non_void_args
-    in
-    if primOpNeedsWrapper op then
-       case (ppr_vol_regs vol_regs) of { (pp_saves, pp_restores) ->
-       vcat [  pp_saves,
-               the_op,
-               pp_restores
-            ]
-       }
-    else
-       the_op
-  where
-    ppr_op_call results args
-      = hcat [ ppr op, lparen,
-       hcat (punctuate comma (map ppr_op_result results)),
-       if null results || null args then empty else comma,
-       hcat (punctuate comma (map pprAmode args)),
-       pp_paren_semi ]
-
-    ppr_op_result r = ppr_amode r
-      -- primop macros do their own casting of result;
-      -- hence we can toss the provided cast...
-
--- NEW CASES FOR EXPANDED PRIMOPS
-
-pprAbsC stmt@(CMachOpStmt res mop [arg1,arg2] maybe_vols) _
-  = let prefix_fn = mop `elem` [MO_Dbl_Pwr, MO_Flt_Pwr, MO_NatS_MulMayOflo]
-    in
-    case ppr_maybe_vol_regs maybe_vols of {(saves,restores) ->
-    saves $$
-    hcat (
-       [ppr_amode res, equals]
-       ++ (if prefix_fn 
-           then [pprMachOp_for_C mop, parens (pprAmode arg1 <> comma <> pprAmode arg2)]
-           else [pprAmode arg1, pprMachOp_for_C mop, pprAmode arg2])
-       ++ [semi]
-    )
-    $$ restores
-    }
-
-pprAbsC stmt@(CMachOpStmt res mop [arg1] maybe_vols) _
-  = case ppr_maybe_vol_regs maybe_vols of {(saves,restores) ->
-    saves $$
-    hcat [ppr_amode res, equals, 
-          pprMachOp_for_C mop, parens (pprAmode arg1),
-          semi]
-    $$ restores
-    }
-
-pprAbsC stmt@(CSequential stuff) c
-  = vcat (map (flip pprAbsC c) stuff)
-
--- end of NEW CASES FOR EXPANDED PRIMOPS
-
-pprAbsC stmt@(CSRT lbl closures) c
-  = case (pprTempAndExternDecls stmt) of { (_, pp_exts) ->
-         pp_exts
-      $$ ptext SLIT("SRT") <> lparen <> pprCLabel lbl <> rparen
-      $$ nest 2 (hcat (punctuate comma (map pp_closure_lbl closures)))
-         <> ptext SLIT("};")
-  }
-
-pprAbsC stmt@(CBitmap liveness@(Liveness lbl size mask)) c
-  = pprWordArray lbl (mkWordCLit (fromIntegral size) : bitmapAddrModes mask)
-
-pprAbsC stmt@(CSRTDesc desc_lbl srt_lbl off len bitmap) c
-  = pprWordArray desc_lbl (
-       CAddr (CIndex (CLbl srt_lbl DataPtrRep) (mkIntCLit off) WordRep) :
-       mkWordCLit (fromIntegral len) :
-       bitmapAddrModes bitmap
-     )
-
-pprAbsC (CSimultaneous abs_c) c
-  = hcat [ptext SLIT("{{"), pprAbsC abs_c c, ptext SLIT("}}")]
-
-pprAbsC (CCheck macro as code) c
-  = hcat [ptext (cCheckMacroText macro), lparen,
-       hcat (punctuate comma (map ppr_amode as)), comma,
-       pprAbsC code c, pp_paren_semi
-    ]
-pprAbsC (CMacroStmt macro as) _
-  = hcat [ptext (cStmtMacroText macro), lparen,
-       hcat (punctuate comma (map ppr_amode as)),pp_paren_semi] -- no casting
-pprAbsC (CCallProfCtrMacro op as) _
-  = hcat [ftext op, lparen,
-       hcat (punctuate comma (map ppr_amode as)),pp_paren_semi]
-pprAbsC (CCallProfCCMacro op as) _
-  = hcat [ftext op, lparen,
-       hcat (punctuate comma (map ppr_amode as)),pp_paren_semi]
-pprAbsC stmt@(CCallTypedef is_tdef (CCallSpec op_str cconv _) uniq results args) _
-  =  hsep [ ptext (if is_tdef then SLIT("typedef") else SLIT("extern"))
-         , ccall_res_ty
-         , fun_nm
-         , parens (hsep (punctuate comma ccall_decl_ty_args))
-         ] <> semi
-    where
-    {-
-      In the non-casm case, to ensure that we're entering the given external
-      entry point using the correct calling convention, we have to do the following:
-
-       - When entering via a function pointer (the `dynamic' case) using the specified
-         calling convention, we emit a typedefn declaration attributed with the
-         calling convention to use together with the result and parameter types we're
-         assuming. Coerce the function pointer to this type and go.
-
-        - to enter the function at a given code label, we emit an extern declaration
-         for the label here, stating the calling convention together with result and
-          argument types we're assuming. 
-
-          The C compiler will hopefully use this extern declaration to good effect,
-          reporting any discrepancies between our extern decl and any other that
-         may be in scope.
-    
-         Re: calling convention, notice that gcc (2.8.1 and egcs-1.0.2) will for
-         the external function `foo' use the calling convention of the first `foo'
-         prototype it encounters (nor does it complain about conflicting attribute
-         declarations). The consequence of this is that you cannot override the
-         calling convention of `foo' using an extern declaration (you'd have to use
-         a typedef), but why you would want to do such a thing in the first place
-         is totally beyond me.
-         
-         ToDo: petition the gcc folks to add code to warn about conflicting attribute
-         declarations.
-
-    -}
-
-     fun_nm
-       | is_tdef   = parens (text (ccallConvAttribute cconv) <+> char '*' <> ccall_fun_ty)
-       | otherwise = text (ccallConvAttribute cconv) <+> ccall_fun_ty
-
-     ccall_fun_ty = 
-        case op_str of
-         DynamicTarget  -> ptext SLIT("_ccall_fun_ty") <> ppr uniq
-         StaticTarget x -> pprCLabelString x
-
-     ccall_res_ty = 
-       case non_void_results of
-          []       -> ptext SLIT("void")
-         [amode]  -> ppr (getAmodeRep amode)
-         _        -> panic "pprAbsC{CCallTypedef}: ccall_res_ty"
-
-     ccall_decl_ty_args 
-       | is_tdef   = tail ccall_arg_tys
-       | otherwise = ccall_arg_tys
-
-     ccall_arg_tys      = map (ppr . getAmodeRep) non_void_args
-
-      -- the first argument will be the "I/O world" token (a VoidRep)
-      -- all others should be non-void
-     non_void_args =
-       let nvas = init args
-       in ASSERT (all non_void nvas) nvas
-
-      -- there will usually be two results: a (void) state which we
-      -- should ignore and a (possibly void) result.
-     non_void_results =
-       let nvrs = grab_non_void_amodes results
-       in ASSERT (listLengthCmp nvrs 1 /= GT) nvrs
-
-pprAbsC (CCodeBlock lbl abs_C) _
-  = if not (isJust(nonemptyAbsC abs_C)) then
-       pprTrace "pprAbsC: curious empty code block for" (pprCLabel lbl) empty
-    else
-    case (pprTempAndExternDecls abs_C) of { (pp_temps, pp_exts) ->
-    vcat [
-        empty,
-       pp_exts, 
-       hcat [text (if (externallyVisibleCLabel lbl)
-                         then "FN_("   -- abbreviations to save on output
-                         else "IF_("),
-                  pprCLabel lbl, text ") {"],
-
-       pp_temps,
-
-       nest 8 (ptext SLIT("FB_")),
-       nest 8 (pprAbsC abs_C (costs abs_C)),
-       nest 8 (ptext SLIT("FE_")),
-       char '}',
-        char ' ' ]
-    }
-
-
-pprAbsC (CInitHdr cl_info amode cost_centre size) _
-  = hcat [ ptext SLIT("SET_HDR_"), char '(',
-               ppr_amode amode, comma,
-               pprCLabelAddr info_lbl, comma,
-               if_profiling (pprAmode cost_centre), comma,
-               if_profiling (int size),
-               pp_paren_semi ]
-  where
-    info_lbl   = infoTableLabelFromCI cl_info
-
-
-pprAbsC stmt@(CStaticClosure closure_lbl cl_info cost_centre amodes) _
-  = case (pprTempAndExternDecls stmt) of { (_, pp_exts) ->
-    vcat [
-       pp_exts,
-       hcat [
-               ptext SLIT("SET_STATIC_HDR"), char '(',
-               pprCLabel closure_lbl,                          comma,
-               pprCLabel info_lbl,                             comma,
-               if_profiling (pprAmode cost_centre),            comma,
-               ppLocalness closure_lbl,                        comma,
-               ppLocalnessMacro True{-include dyn-} info_lbl,
-               char ')'
-               ],
-       nest 2 (ppr_payload amodes),
-       ptext SLIT("};") ]
-    }
-  where
-    info_lbl    = infoTableLabelFromCI cl_info
-
-    ppr_payload [] = empty
-    ppr_payload ls = 
-       comma <+> 
-         (braces $ hsep $ punctuate comma $
-          map (text "(L_)" <>) (foldr ppr_item [] ls))
-
-    ppr_item item rest
-      | rep == VoidRep   = rest
-      | rep == FloatRep  = ppr_amode (floatToWord item) : rest
-      | rep == DoubleRep = map ppr_amode (doubleToWords item) ++ rest
-      | otherwise       = ppr_amode item : rest
-      where 
-       rep  = getAmodeRep item
-
-pprAbsC stmt@(CClosureInfoAndCode cl_info entry) _
-  =  pprWordArray info_lbl (mkInfoTable cl_info)
-  $$ let stuff = CCodeBlock entry_lbl entry in
-     pprAbsC stuff (costs stuff)
-  where
-       entry_lbl = entryLabelFromCI cl_info
-       info_lbl  = infoTableLabelFromCI cl_info
-
-pprAbsC stmt@(CClosureTbl tycon) _
-  = vcat (
-       ptext SLIT("CLOSURE_TBL") <> 
-          lparen <> pprCLabel (mkClosureTblLabel tycon) <> rparen :
-       punctuate comma (
-          map (pp_closure_lbl . mkClosureLabel . getName) (tyConDataCons tycon)
-       )
-   ) $$ ptext SLIT("};")
-
-pprAbsC stmt@(CRetDirect uniq code srt liveness) _
-  =  pprWordArray info_lbl (mkRetInfoTable entry_lbl srt liveness)
-  $$ let stuff = CCodeBlock entry_lbl code in
-     pprAbsC stuff (costs stuff)
-  where
-     info_lbl  = mkReturnInfoLabel uniq
-     entry_lbl = mkReturnPtLabel uniq
-
-pprAbsC stmt@(CRetVector lbl amodes srt liveness) _
-  = pprWordArray lbl (mkVecInfoTable amodes srt liveness)
-
-pprAbsC stmt@(CModuleInitBlock plain_lbl lbl code) _
-  = vcat [
-       ptext SLIT("START_MOD_INIT") <> 
-           parens (pprCLabel plain_lbl <> comma <> pprCLabel lbl),
-       case (pprTempAndExternDecls stmt) of { (_, pp_exts) -> pp_exts },
-       pprAbsC code (costs code),
-       hcat [ptext SLIT("END_MOD_INIT"), lparen, rparen]
-    ]
-
-pprAbsC (CCostCentreDecl is_local cc) _ = pprCostCentreDecl is_local cc
-pprAbsC (CCostCentreStackDecl ccs)    _ = pprCostCentreStackDecl ccs
-\end{code}
-
-Info tables... just arrays of words (the translation is done in
-ClosureInfo).
-
-\begin{code}
-pprWordArray lbl amodes
-  = (case snd (initTE (ppr_decls_Amodes amodes)) of
-       Just pp -> pp
-       Nothing -> empty)
-  $$ hcat [ ppLocalness lbl, ptext SLIT("StgWord "), 
-           pprCLabel lbl, ptext SLIT("[] = {") ]
-  $$ hcat (punctuate comma (map (castToWord.pprAmode) amodes))
-  $$ ptext SLIT("};")
-
-castToWord s = text "(W_)(" <> s <> char ')'
-\end{code}
-
-\begin{code}
--- Print a CMachOp in a way suitable for emitting via C.
-pprMachOp_for_C MO_Nat_Add       = char '+'
-pprMachOp_for_C MO_Nat_Sub       = char '-'
-pprMachOp_for_C MO_Nat_Eq        = text "==" 
-pprMachOp_for_C MO_Nat_Ne        = text "!="
-
-pprMachOp_for_C MO_NatS_Ge       = text ">="
-pprMachOp_for_C MO_NatS_Le       = text "<="
-pprMachOp_for_C MO_NatS_Gt       = text ">"
-pprMachOp_for_C MO_NatS_Lt       = text "<"
-
-pprMachOp_for_C MO_NatU_Ge       = text ">="
-pprMachOp_for_C MO_NatU_Le       = text "<="
-pprMachOp_for_C MO_NatU_Gt       = text ">"
-pprMachOp_for_C MO_NatU_Lt       = text "<"
-
-pprMachOp_for_C MO_NatS_Mul      = char '*'
-pprMachOp_for_C MO_NatS_MulMayOflo = text "mulIntMayOflo"
-pprMachOp_for_C MO_NatS_Quot     = char '/'
-pprMachOp_for_C MO_NatS_Rem      = char '%'
-pprMachOp_for_C MO_NatS_Neg      = char '-'
-
-pprMachOp_for_C MO_NatU_Mul      = char '*'
-pprMachOp_for_C MO_NatU_Quot     = char '/'
-pprMachOp_for_C MO_NatU_Rem      = char '%'
-
-pprMachOp_for_C MO_Nat_And       = text "&"
-pprMachOp_for_C MO_Nat_Or        = text "|"
-pprMachOp_for_C MO_Nat_Xor       = text "^"
-pprMachOp_for_C MO_Nat_Not       = text "~"
-pprMachOp_for_C MO_Nat_Shl       = text "<<"
-pprMachOp_for_C MO_Nat_Shr       = text ">>"
-pprMachOp_for_C MO_Nat_Sar       = text ">>"
-
-pprMachOp_for_C MO_32U_Eq        = text "=="
-pprMachOp_for_C MO_32U_Ne        = text "!="
-pprMachOp_for_C MO_32U_Ge        = text ">="
-pprMachOp_for_C MO_32U_Le        = text "<="
-pprMachOp_for_C MO_32U_Gt        = text ">"
-pprMachOp_for_C MO_32U_Lt        = text "<"
-
-pprMachOp_for_C MO_Dbl_Eq        = text "=="
-pprMachOp_for_C MO_Dbl_Ne        = text "!="
-pprMachOp_for_C MO_Dbl_Ge        = text ">="
-pprMachOp_for_C MO_Dbl_Le        = text "<="
-pprMachOp_for_C MO_Dbl_Gt        = text ">"
-pprMachOp_for_C MO_Dbl_Lt        = text "<"
-
-pprMachOp_for_C MO_Dbl_Add       = text "+"
-pprMachOp_for_C MO_Dbl_Sub       = text "-"
-pprMachOp_for_C MO_Dbl_Mul       = text "*"
-pprMachOp_for_C MO_Dbl_Div       = text "/"
-pprMachOp_for_C MO_Dbl_Pwr       = text "pow"
-
-pprMachOp_for_C MO_Dbl_Sin       = text "sin"
-pprMachOp_for_C MO_Dbl_Cos       = text "cos"
-pprMachOp_for_C MO_Dbl_Tan       = text "tan"
-pprMachOp_for_C MO_Dbl_Sinh      = text "sinh"
-pprMachOp_for_C MO_Dbl_Cosh      = text "cosh"
-pprMachOp_for_C MO_Dbl_Tanh      = text "tanh"
-pprMachOp_for_C MO_Dbl_Asin      = text "asin"
-pprMachOp_for_C MO_Dbl_Acos      = text "acos"
-pprMachOp_for_C MO_Dbl_Atan      = text "atan"
-pprMachOp_for_C MO_Dbl_Log       = text "log"
-pprMachOp_for_C MO_Dbl_Exp       = text "exp"
-pprMachOp_for_C MO_Dbl_Sqrt      = text "sqrt"
-pprMachOp_for_C MO_Dbl_Neg       = text "-"
-
-pprMachOp_for_C MO_Flt_Add       = text "+"
-pprMachOp_for_C MO_Flt_Sub       = text "-"
-pprMachOp_for_C MO_Flt_Mul       = text "*"
-pprMachOp_for_C MO_Flt_Div       = text "/"
-pprMachOp_for_C MO_Flt_Pwr       = text "pow"
-
-pprMachOp_for_C MO_Flt_Eq        = text "=="
-pprMachOp_for_C MO_Flt_Ne        = text "!="
-pprMachOp_for_C MO_Flt_Ge        = text ">="
-pprMachOp_for_C MO_Flt_Le        = text "<="
-pprMachOp_for_C MO_Flt_Gt        = text ">"
-pprMachOp_for_C MO_Flt_Lt        = text "<"
-
-pprMachOp_for_C MO_Flt_Sin       = text "sin"
-pprMachOp_for_C MO_Flt_Cos       = text "cos"
-pprMachOp_for_C MO_Flt_Tan       = text "tan"
-pprMachOp_for_C MO_Flt_Sinh      = text "sinh"
-pprMachOp_for_C MO_Flt_Cosh      = text "cosh"
-pprMachOp_for_C MO_Flt_Tanh      = text "tanh"
-pprMachOp_for_C MO_Flt_Asin      = text "asin"
-pprMachOp_for_C MO_Flt_Acos      = text "acos"
-pprMachOp_for_C MO_Flt_Atan      = text "atan"
-pprMachOp_for_C MO_Flt_Log       = text "log"
-pprMachOp_for_C MO_Flt_Exp       = text "exp"
-pprMachOp_for_C MO_Flt_Sqrt      = text "sqrt"
-pprMachOp_for_C MO_Flt_Neg       = text "-"
-
-pprMachOp_for_C MO_32U_to_NatS   = text "(StgInt)"
-pprMachOp_for_C MO_NatS_to_32U   = text "(StgWord32)"
-
-pprMachOp_for_C MO_NatS_to_Dbl   = text "(StgDouble)"
-pprMachOp_for_C MO_Dbl_to_NatS   = text "(StgInt)"
-
-pprMachOp_for_C MO_NatS_to_Flt   = text "(StgFloat)"
-pprMachOp_for_C MO_Flt_to_NatS   = text "(StgInt)"
-
-pprMachOp_for_C MO_NatS_to_NatU  = text "(StgWord)"
-pprMachOp_for_C MO_NatU_to_NatS  = text "(StgInt)"
-
-pprMachOp_for_C MO_NatS_to_NatP  = text "(void*)"
-pprMachOp_for_C MO_NatP_to_NatS  = text "(StgInt)"
-pprMachOp_for_C MO_NatU_to_NatP  = text "(void*)"
-pprMachOp_for_C MO_NatP_to_NatU  = text "(StgWord)"
-
-pprMachOp_for_C MO_Dbl_to_Flt    = text "(StgFloat)"
-pprMachOp_for_C MO_Flt_to_Dbl    = text "(StgDouble)"
-
-pprMachOp_for_C MO_8S_to_NatS    = text "(StgInt8)(StgInt)"
-pprMachOp_for_C MO_16S_to_NatS   = text "(StgInt16)(StgInt)"
-pprMachOp_for_C MO_32S_to_NatS   = text "(StgInt32)(StgInt)"
-
-pprMachOp_for_C MO_8U_to_NatU    = text "(StgWord8)(StgWord)"
-pprMachOp_for_C MO_16U_to_NatU   = text "(StgWord16)(StgWord)"
-pprMachOp_for_C MO_32U_to_NatU   = text "(StgWord32)(StgWord)"
-
-pprMachOp_for_C MO_8U_to_32U     = text "(StgWord32)"
-pprMachOp_for_C MO_32U_to_8U     = text "(StgWord8)"
-
-
-ppLocalness lbl
-  = if (externallyVisibleCLabel lbl) 
-               then empty 
-               else ptext SLIT("static ")
-
--- Horrible macros for declaring the types and locality of labels (see
--- StgMacros.h).
-
-ppLocalnessMacro include_dyn_prefix clabel =
-     hcat [
-        visiblity_prefix,
-       dyn_prefix,
-        case label_type of
-         ClosureType        -> ptext SLIT("C_")
-         CodeType           -> ptext SLIT("F_")
-         InfoTblType        -> ptext SLIT("I_")
-         RetInfoTblType     -> ptext SLIT("RI_")
-         ClosureTblType     -> ptext SLIT("CP_")
-         DataType           -> ptext SLIT("D_")
-     ]
-  where
-   is_visible = externallyVisibleCLabel clabel
-   label_type = labelType clabel
-
-   visiblity_prefix
-     | is_visible = char 'E'
-     | otherwise  = char 'I'
-
-   dyn_prefix
-     | include_dyn_prefix && labelDynamic clabel = char 'D'
-     | otherwise                                = empty
-
-\end{code}
-
-\begin{code}
-jmp_lit = "JMP_("
-
-grab_non_void_amodes amodes
-  = filter non_void amodes
-
-non_void amode
-  = case (getAmodeRep amode) of
-      VoidRep -> False
-      k        -> True
-\end{code}
-
-\begin{code}
-ppr_maybe_vol_regs :: Maybe [MagicId] -> (SDoc, SDoc)
-ppr_maybe_vol_regs Nothing
-   = (empty, empty)
-ppr_maybe_vol_regs (Just vrs)
-   = case ppr_vol_regs vrs of
-        (saves, restores) 
-           -> (pp_basic_saves $$ saves,
-               pp_basic_restores $$ restores)
-
-ppr_vol_regs :: [MagicId] -> (SDoc, SDoc)
-
-ppr_vol_regs [] = (empty, empty)
-ppr_vol_regs (VoidReg:rs) = ppr_vol_regs rs
-ppr_vol_regs (r:rs)
-  = let pp_reg = case r of
-                   VanillaReg pk n -> pprVanillaReg n
-                   _ -> pprMagicId r
-       (more_saves, more_restores) = ppr_vol_regs rs
-    in
-    (($$) ((<>) (ptext SLIT("CALLER_SAVE_"))    pp_reg) more_saves,
-     ($$) ((<>) (ptext SLIT("CALLER_RESTORE_")) pp_reg) more_restores)
-
--- pp_basic_{saves,restores}: The BaseReg, Sp, Hp and
--- HpLim (see StgRegs.lh) may need to be saved/restored around CCalls,
--- depending on the platform.  (The "volatile regs" stuff handles all
--- other registers.)  Just be *sure* BaseReg is OK before trying to do
--- anything else. The correct sequence of saves&restores are
--- encoded by the CALLER_*_SYSTEM macros.
-pp_basic_saves    = ptext SLIT("CALLER_SAVE_SYSTEM")
-pp_basic_restores = ptext SLIT("CALLER_RESTORE_SYSTEM")
-\end{code}
-
-\begin{code}
-pp_closure_lbl lbl
-      | labelDynamic lbl = text "DLL_SRT_ENTRY" <> parens (pprCLabel lbl)
-      | otherwise       = char '&' <> pprCLabel lbl
-\end{code}
-
-\begin{code}
-if_profiling pretty
-  = if  opt_SccProfilingOn
-    then pretty
-    else char '0' -- leave it out!
--- ---------------------------------------------------------------------------
--- Changes for GrAnSim:
---  draw costs for computation in head of if into both branches;
---  as no abstractC data structure is given for the head, one is constructed
---  guessing unknown values and fed into the costs function
--- ---------------------------------------------------------------------------
-
-do_if_stmt discrim tag alt_code deflt c
-   = let
-       cond = hcat [ pprAmode discrim
-                  , ptext SLIT(" == ")
-                  , tcast
-                  , pprAmode (CLit tag)
-                  ]
-       -- to be absolutely sure that none of the 
-       -- conversion rules hit, e.g.,
-       --
-       --     minInt is different to (int)minInt
-        --
-       -- in C (when minInt is a number not a constant
-       --  expression which evaluates to it.)
-       -- 
-       tcast = case tag of
-                  MachInt _  -> ptext SLIT("(I_)")
-                  _          -> empty
-     in
-     ppr_if_stmt cond
-                alt_code deflt
-                (addrModeCosts discrim Rhs) c
-
-ppr_if_stmt pp_pred then_part else_part discrim_costs c
-  = vcat [
-      hcat [text "if (", pp_pred, text ") {"],
-      nest 8 (pprAbsC then_part        (c + discrim_costs +
-                                       (Cost (0, 2, 0, 0, 0)) +
-                                       costs then_part)),
-      (case nonemptyAbsC else_part of Nothing -> empty; Just _ -> text "} else {"),
-      nest 8 (pprAbsC else_part  (c + discrim_costs +
-                                       (Cost (0, 1, 0, 0, 0)) +
-                                       costs else_part)),
-      char '}' ]
-    {- Total costs = inherited costs (before if) + costs for accessing discrim
-                    + costs for cond branch ( = (0, 1, 0, 0, 0) )
-                    + costs for that alternative
-    -}
-\end{code}
-
-Historical note: this used to be two separate cases -- one for `ccall'
-and one for `casm'.  To get round a potential limitation to only 10
-arguments, the numbering of arguments in @process_casm@ was beefed up a
-bit. ADR
-
-Some rough notes on generating code for @CCallOp@:
-
-1) Evaluate all arguments and stuff them into registers. (done elsewhere)
-2) Save any essential registers (heap, stack, etc).
-
-   ToDo: If stable pointers are in use, these must be saved in a place
-   where the runtime system can get at them so that the Stg world can
-   be restarted during the call.
-
-3) Save any temporary registers that are currently in use.
-4) Do the call, putting result into a local variable
-5) Restore essential registers
-6) Restore temporaries
-
-   (This happens after restoration of essential registers because we
-   might need the @Base@ register to access all the others correctly.)
-
-   Otherwise, copy local variable into result register.
-
-8) If ccall (not casm), declare the function being called as extern so
-   that C knows if it returns anything other than an int.
-
-\begin{pseudocode}
-{ ResultType _ccall_result;
-  basic_saves;
-  saves;
-  _ccall_result = f( args );
-  basic_restores;
-  restores;
-
-  return_reg = _ccall_result;
-}
-\end{pseudocode}
-
-Amendment to the above: if we can GC, we have to:
-
-* make sure we save all our registers away where the garbage collector
-  can get at them.
-* be sure that there are no live registers or we're in trouble.
-  (This can cause problems if you try something foolish like passing
-   an array or a foreign obj to a _ccall_GC_ thing.)
-* increment/decrement the @inCCallGC@ counter before/after the call so
-  that the runtime check that PerformGC is being used sensibly will work.
-
-\begin{code}
-pprFCall call uniq args results vol_regs
-  = case call of
-      CCall (CCallSpec target _cconv safety) ->
-        vcat [ char '{',
-               declare_local_vars,   -- local var for *result*
-               vcat local_arg_decls,
-               makeCall target safety 
-                        (process_casm local_vars pp_non_void_args (call_str target)),
-               assign_results,
-             char '}'
-            ]
-      DNCall (DNCallSpec isStatic kind assem nm argTys resTy) ->
-         let
-         resultVar = "_ccall_result"
-         hasAssemArg = isStatic || kind == DNConstructor
-         invokeOp  = 
-           case kind of
-             DNMethod 
-               | isStatic  -> "DN_invokeStatic"
-               | otherwise -> "DN_invokeMethod"
-             DNField
-               | isStatic ->
-                  if resTy == DNUnit 
-                   then "DN_setStatic"
-                   else "DN_getStatic"
-                | otherwise ->
-                  if resTy == DNUnit 
-                   then "DN_setField"
-                   else "DN_getField"
-             DNConstructor -> "DN_createObject"
-
-         (methArrDecl, methArrInit, methArrName, methArrLen) 
-           | null argTys = (empty, empty, text "NULL", text "0")
-           | otherwise   = 
-             ( text "DotnetArg __meth_args[" <> int (length argTys) <> text "];"
-             , vcat (zipWith3 (\ idx arg argTy -> 
-                                text "__meth_args[" <> int idx <> text "].arg." <> text (toDotnetArgField argTy) <> equals <> ppr_amode arg <> semi $$
-                                text "__meth_args[" <> int idx <> text "].arg_type=" <> text (toDotnetTy argTy) <> semi)
-                              [0..]
-                              non_void_args
-                              argTys)
-             , text "__meth_args"
-             , int (length non_void_args)
-             )
-        in
-         vcat [ char '{',
-                 declare_local_vars,
-                 vcat local_arg_decls,
-                 vcat [ methArrDecl
-                      , methArrInit
-                      , text "_ccall_result1 =" <+> text invokeOp <> parens (
-                         hcat (punctuate comma $
-                                    (if hasAssemArg then
-                                       ((if null assem then 
-                                           text "NULL" 
-                                        else 
-                                           doubleQuotes (text assem)):)
-                                     else
-                                        id) $
-                                    [ doubleQuotes $ text nm
-                                    , methArrName
-                                    , methArrLen
-                                    , text (toDotnetTy resTy)
-                                    , text "(void*)&" <> text resultVar 
-                                    ])) <> semi
-                       ],
-                 assign_results,
-               char '}'
-              ]
-  where
-    (pp_saves, pp_restores) = ppr_vol_regs vol_regs
-    
-    makeCall target safety theCall = 
-        vcat [ pp_save_context,        theCall, pp_restore_context ]
-     where
-      (pp_save_context, pp_restore_context)
-       | playSafe safety = ( text "{ I_" <+> ppr_uniq_token <> 
-                               text "; SUSPEND_THREAD" <> parens thread_macro_args <> semi
-                           , text "RESUME_THREAD" <> parens thread_macro_args <> text ";}"
-                           )
-       | otherwise = ( pp_basic_saves $$ pp_saves,
-                       pp_basic_restores $$ pp_restores)
-          where
-           thread_macro_args = ppr_uniq_token <> comma <+> 
-                               text "rts" <> ppr (playThreadSafe safety)
-           ppr_uniq_token = text "tok_" <> ppr uniq
-
-
-    non_void_args = 
-       let nvas = init args
-       in ASSERT2 ( all non_void nvas, ppr call <+> hsep (map pprAmode args) )
-       nvas
-    -- the last argument will be the "I/O world" token (a VoidRep)
-    -- all others should be non-void
-
-    non_void_results =
-       let nvrs = grab_non_void_amodes results
-       in ASSERT (forDotnet || listLengthCmp nvrs 1 /= GT) nvrs
-    -- there will usually be two results: a (void) state which we
-    -- should ignore and a (possibly void) result.
-
-    (local_arg_decls, pp_non_void_args)
-      = unzip [ ppr_casm_arg a i | (a,i) <- non_void_args `zip` [1..] ]
-
-    (declare_local_vars, local_vars, assign_results)
-      = ppr_casm_results non_void_results forDotnet
-
-    forDotnet
-      = case call of
-          DNCall{} -> True
-         _ -> False
-
-    call_str tgt 
-      = case tgt of
-         StaticTarget fn -> mk_ccall_str (pprCLabelString fn) ccall_args
-         DynamicTarget   -> mk_ccall_str dyn_fun              (tail ccall_args)
-
-    ccall_args = zipWith (\ _ i -> char '%' <> int i) non_void_args [0..]
-    dyn_fun    = parens (parens (ptext SLIT("_ccall_fun_ty") <> ppr uniq) <> text "%0")
-                                                
-
-    -- Remainder only used for ccall
-    mk_ccall_str fun_name ccall_fun_args = showSDoc
-       (hcat [
-               if null non_void_results
-                 then empty
-                 else text "%r = ",
-               lparen, fun_name, lparen,
-                 hcat (punctuate comma ccall_fun_args),
-               text "));"
-       ])
-
-toDotnetTy :: DNType -> String
-toDotnetTy x = 
-  case x of 
-    DNByte -> "Dotnet_Byte"
-    DNBool -> "Dotnet_Bool"
-    DNChar -> "Dotnet_Char"
-    DNDouble -> "Dotnet_Double"
-    DNFloat  -> "Dotnet_Float"
-    DNInt    -> "Dotnet_Int"
-    DNInt8   -> "Dotnet_Int8"
-    DNInt16  -> "Dotnet_Int16"
-    DNInt32  -> "Dotnet_Int32"
-    DNInt64  -> "Dotnet_Int64"
-    DNWord8  -> "Dotnet_Word8"
-    DNWord16 -> "Dotnet_Word16"
-    DNWord32 -> "Dotnet_Word32"
-    DNWord64 -> "Dotnet_Word64"
-    DNPtr    -> "Dotnet_Ptr"
-    DNUnit   -> "Dotnet_Unit"
-    DNObject -> "Dotnet_Object"
-    DNString -> "Dotnet_String"
-
-toDotnetArgField :: DNType -> String
-toDotnetArgField x = 
-  case x of 
-    DNByte -> "arg_byte"
-    DNBool -> "arg_bool"
-    DNChar -> "arg_char"
-    DNDouble -> "arg_double"
-    DNFloat  -> "arg_float"
-    DNInt    -> "arg_int"
-    DNInt8   -> "arg_int8"
-    DNInt16  -> "arg_int16"
-    DNInt32  -> "arg_int32"
-    DNInt64  -> "arg_int64"
-    DNWord8  -> "arg_word8"
-    DNWord16 -> "arg_word16"
-    DNWord32 -> "arg_word32"
-    DNWord64 -> "arg_word64"
-    DNPtr    -> "arg_ptr"
-    DNUnit   -> "arg_ptr" -- can't happen
-    DNObject -> "arg_obj"
-    DNString -> "arg_str"
-
-ppr_casm_arg :: CAddrMode -> Int -> (SDoc, SDoc)
-    -- (a) decl and assignment, (b) local var to be used later
-
-ppr_casm_arg amode a_num
-  = let
-       a_kind   = getAmodeRep amode
-       pp_amode = pprAmode amode
-       pp_kind  = pprPrimKind a_kind
-
-       local_var  = (<>) (ptext SLIT("_ccall_arg")) (int a_num)
-
-       declare_local_var
-         = hcat [ pp_kind, space, local_var, equals, pp_amode, semi ]
-    in
-    (declare_local_var, local_var)
-\end{code}
-
-For l-values, the critical questions are:
-
-1) Are there any results at all?
-
-   We only allow zero or one results.
-
-\begin{code}
-ppr_casm_results
-       :: [CAddrMode]  -- list of results (length <= 1)
-       -> Bool         -- True => multiple results OK.
-       ->
-       ( SDoc,         -- declaration of any local vars
-         [SDoc],       -- list of result vars (same length as results)
-         SDoc )        -- assignment (if any) of results in local var to registers
-
-ppr_casm_results [] _
-  = (empty, [], empty)         -- no results
-
-ppr_casm_results (r:rs) multiResultsOK
-  | not multiResultsOK && not (null rs) = panic "ppr_casm_results: ccall/casm with many results"
-  | otherwise
-  = foldr (\ (a,b,c) (as,bs,cs) -> (a $$ as, b ++ bs, c $$ cs))
-         (empty,[],empty)
-         (zipWith pprRes (r:rs) ("" : map show [(1::Int)..]))
-    where
-      pprRes r suf = (declare_local_var, [local_var], assign_result)
-       where
-       result_reg = ppr_amode r
-       r_kind     = getAmodeRep r
-
-       local_var  = ptext SLIT("_ccall_result") <> text suf
-
-       (result_type, assign_result)
-         = (pprPrimKind r_kind,
-            hcat [ result_reg, equals, local_var, semi ])
-
-       declare_local_var = hcat [ result_type, space, local_var, semi ]
-
-\end{code}
-
-
-Note the sneaky way _the_ result is represented by a list so that we
-can complain if it's used twice.
-
-ToDo: Any chance of giving line numbers when process-casm fails?
-      Or maybe we should do a check _much earlier_ in compiler. ADR
-
-\begin{code}
-process_casm :: [SDoc]         -- results (length <= 1)
-            -> [SDoc]          -- arguments
-            -> String          -- format string (with embedded %'s)
-            -> SDoc            -- code being generated
-
-process_casm results args string = process results args string
- where
-  process []    _ "" = empty
-  process (_:_) _ "" = error ("process_casm: non-void result not assigned while processing _casm_ \"" ++ 
-                             string ++ 
-                             "\"\n(Try changing result type to IO ()\n")
-
-  process ress args ('%':cs)
-    = case cs of
-       [] ->
-           error ("process_casm: lonely % while processing _casm_ \"" ++ string ++ "\".\n")
-
-       ('%':css) ->
-           char '%' <> process ress args css
-
-       ('r':css)  ->
-         case ress of
-           []  -> error ("process_casm: no result to match %r while processing _casm_ \"" ++ string ++ "\".\nTry deleting %r or changing result type from PrimIO ()\n")
-           [r] -> r <> (process [] args css)
-           _   -> panic ("process_casm: casm with many results while processing _casm_ \"" ++ string ++ "\".\n")
-
-       other ->
-         let
-               read_int :: ReadS Int
-               read_int = reads
-         in
-         case (read_int other) of
-           [(num,css)] ->
-                 if num >= 0 && args `lengthExceeds` num
-                 then parens (args !! num) <> process ress args css
-                 else error ("process_casm: no such arg #:"++(show num)++" while processing \"" ++ string ++ "\".\n")
-           _ -> error ("process_casm: not %<num> while processing _casm_ \"" ++ string ++ "\".\n")
-
-  process ress args (other_c:cs)
-    = char other_c <> process ress args cs
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[a2r-assignments]{Assignments}
-%*                                                                     *
-%************************************************************************
-
-Printing assignments is a little tricky because of type coercion.
-
-First of all, the kind of the thing being assigned can be gotten from
-the destination addressing mode.  (It should be the same as the kind
-of the source addressing mode.)  If the kind of the assignment is of
-@VoidRep@, then don't generate any code at all.
-
-\begin{code}
-pprAssign :: PrimRep -> CAddrMode -> CAddrMode -> SDoc
-
-pprAssign VoidRep dest src = empty
-\end{code}
-
-Special treatment for floats and doubles, to avoid unwanted conversions.
-
-\begin{code}
-pprAssign FloatRep dest@(CVal reg_rel _) src
-  = hcat [ ptext SLIT("ASSIGN_FLT((W_*)"), parens (ppr_amode (CAddr reg_rel)), comma, pprAmode src, pp_paren_semi ]
-
-pprAssign DoubleRep dest@(CVal reg_rel _) src
-  = hcat [ ptext SLIT("ASSIGN_DBL((W_*)"), parens (ppr_amode (CAddr reg_rel)), comma, pprAmode src, pp_paren_semi ]
-
-pprAssign Int64Rep dest@(CVal reg_rel _) src
-  = hcat [ ptext SLIT("ASSIGN_Int64((W_*)"), parens (ppr_amode (CAddr reg_rel)), comma, pprAmode src, pp_paren_semi ]
-pprAssign Word64Rep dest@(CVal reg_rel _) src
-  = hcat [ ptext SLIT("ASSIGN_Word64((W_*)"), parens (ppr_amode (CAddr reg_rel)), comma, pprAmode src, pp_paren_semi ]
-\end{code}
-
-Lastly, the question is: will the C compiler think the types of the
-two sides of the assignment match?
-
-       We assume that the types will match if neither side is a
-       @CVal@ addressing mode for any register which can point into
-       the heap or stack.
-
-Why?  Because the heap and stack are used to store miscellaneous
-things, whereas the temporaries, registers, etc., are only used for
-things of fixed type.
-
-\begin{code}
-pprAssign kind (CReg (VanillaReg _ dest)) (CReg (VanillaReg _ src))
-  = hcat [ pprVanillaReg dest, equals,
-               pprVanillaReg src, semi ]
-
-pprAssign kind dest src
-  | mixedTypeLocn dest
-    -- Add in a cast to StgWord (a.k.a. W_) iff the destination is mixed
-  = hcat [ ppr_amode dest, equals,
-               text "(W_)(",   -- Here is the cast
-               ppr_amode src, pp_paren_semi ]
-
-pprAssign kind dest src
-  | mixedPtrLocn dest && getAmodeRep src /= PtrRep
-    -- Add in a cast to StgPtr (a.k.a. P_) iff the destination is mixed
-  = hcat [ ppr_amode dest, equals,
-               text "(P_)(",   -- Here is the cast
-               ppr_amode src, pp_paren_semi ]
-
-pprAssign kind other_dest src
-  = hcat [ ppr_amode other_dest, equals,
-               pprAmode  src, semi ]
-\end{code}
-
-
-%************************************************************************
-%*                                                                     *
-\subsection[a2r-CAddrModes]{Addressing modes}
-%*                                                                     *
-%************************************************************************
-
-@pprAmode@ is used to print r-values (which may need casts), whereas
-@ppr_amode@ is used for l-values {\em and} as a help function for
-@pprAmode@.
-
-\begin{code}
-pprAmode, ppr_amode :: CAddrMode -> SDoc
-\end{code}
-
-For reasons discussed above under assignments, @CVal@ modes need
-to be treated carefully.  First come special cases for floats and doubles,
-similar to those in @pprAssign@:
-
-(NB: @PK_FLT@ and @PK_DBL@ require the {\em address} of the value in
-question.)
-
-\begin{code}
-pprAmode (CVal reg_rel FloatRep)
-  = hcat [ text "PK_FLT((W_*)", parens (ppr_amode (CAddr reg_rel)), rparen ]
-pprAmode (CVal reg_rel DoubleRep)
-  = hcat [ text "PK_DBL((W_*)", parens (ppr_amode (CAddr reg_rel)), rparen ]
-pprAmode (CVal reg_rel Int64Rep)
-  = hcat [ text "PK_Int64((W_*)", parens (ppr_amode (CAddr reg_rel)), rparen ]
-pprAmode (CVal reg_rel Word64Rep)
-  = hcat [ text "PK_Word64((W_*)", parens (ppr_amode (CAddr reg_rel)), rparen ]
-\end{code}
-
-Next comes the case where there is some other cast need, and the
-no-cast case:
-
-\begin{code}
-pprAmode amode
-  | mixedTypeLocn amode
-  = parens (hcat [ pprPrimKind (getAmodeRep amode), ptext SLIT(")("),
-               ppr_amode amode ])
-  | otherwise  -- No cast needed
-  = ppr_amode amode
-\end{code}
-
-When we have an indirection through a CIndex, we have to be careful to
-get the type casts right.  
-
-this amode:
-
-       CVal (CIndex kind1 base offset) kind2
-
-means (in C speak): 
-       
-       *(kind2 *)((kind1 *)base + offset)
-
-That is, the indexing is done in units of kind1, but the resulting
-amode has kind2.
-
-\begin{code}
-ppr_amode (CVal reg_rel@(CIndex _ _ _) kind)
-  = case (pprRegRelative False{-no sign wanted-} reg_rel) of
-       (pp_reg, Nothing)     -> panic "ppr_amode: CIndex"
-       (pp_reg, Just offset) -> 
-          hcat [ char '*', parens (pprPrimKind kind <> char '*'),
-                 parens (pp_reg <> char '+' <> offset) ]
-\end{code}
-
-Now the rest of the cases for ``workhorse'' @ppr_amode@:
-
-\begin{code}
-ppr_amode (CVal reg_rel _)
-  = case (pprRegRelative False{-no sign wanted-} reg_rel) of
-       (pp_reg, Nothing)     -> (<>)  (char '*') pp_reg
-       (pp_reg, Just offset) -> hcat [ pp_reg, brackets offset ]
-
-ppr_amode (CAddr reg_rel)
-  = case (pprRegRelative True{-sign wanted-} reg_rel) of
-       (pp_reg, Nothing)     -> pp_reg
-       (pp_reg, Just offset) -> pp_reg <> offset
-
-ppr_amode (CReg magic_id) = pprMagicId magic_id
-
-ppr_amode (CTemp uniq kind) = char '_' <> pprUnique uniq <> char '_'
-
-ppr_amode (CLbl lbl kind) = pprCLabelAddr lbl 
-
-ppr_amode (CCharLike ch)
-  = hcat [ptext SLIT("CHARLIKE_CLOSURE"), char '(', pprAmode ch, rparen ]
-ppr_amode (CIntLike int)
-  = hcat [ptext SLIT("INTLIKE_CLOSURE"), char '(', pprAmode int, rparen ]
-
-ppr_amode (CLit lit) = pprBasicLit lit
-
-ppr_amode (CJoinPoint _)
-  = panic "ppr_amode: CJoinPoint"
-
-ppr_amode (CMacroExpr pk macro as)
-  = parens (ptext (cExprMacroText macro) <> 
-           parens (hcat (punctuate comma (map pprAmode as))))
-\end{code}
-
-\begin{code}
-cExprMacroText ENTRY_CODE              = SLIT("ENTRY_CODE")
-cExprMacroText ARG_TAG                 = SLIT("ARG_TAG")
-cExprMacroText GET_TAG                 = SLIT("GET_TAG")
-cExprMacroText CCS_HDR                 = SLIT("CCS_HDR")
-cExprMacroText BYTE_ARR_CTS            = SLIT("BYTE_ARR_CTS")
-cExprMacroText PTRS_ARR_CTS            = SLIT("PTRS_ARR_CTS")
-cExprMacroText ForeignObj_CLOSURE_DATA  = SLIT("ForeignObj_CLOSURE_DATA")
-
-cStmtMacroText UPD_CAF                 = SLIT("UPD_CAF")
-cStmtMacroText UPD_BH_UPDATABLE                = SLIT("UPD_BH_UPDATABLE")
-cStmtMacroText UPD_BH_SINGLE_ENTRY     = SLIT("UPD_BH_SINGLE_ENTRY")
-cStmtMacroText PUSH_UPD_FRAME          = SLIT("PUSH_UPD_FRAME")
-cStmtMacroText SET_TAG                 = SLIT("SET_TAG")
-cStmtMacroText DATA_TO_TAGZH            = SLIT("dataToTagzh")
-cStmtMacroText REGISTER_FOREIGN_EXPORT = SLIT("REGISTER_FOREIGN_EXPORT")
-cStmtMacroText REGISTER_IMPORT         = SLIT("REGISTER_IMPORT")
-cStmtMacroText REGISTER_DIMPORT                = SLIT("REGISTER_DIMPORT")
-cStmtMacroText GRAN_FETCH              = SLIT("GRAN_FETCH")
-cStmtMacroText GRAN_RESCHEDULE         = SLIT("GRAN_RESCHEDULE")
-cStmtMacroText GRAN_FETCH_AND_RESCHEDULE= SLIT("GRAN_FETCH_AND_RESCHEDULE")
-cStmtMacroText THREAD_CONTEXT_SWITCH           = SLIT("THREAD_CONTEXT_SWITCH")
-cStmtMacroText GRAN_YIELD              = SLIT("GRAN_YIELD")
-
-cCheckMacroText        HP_CHK_NP               = SLIT("HP_CHK_NP")
-cCheckMacroText        STK_CHK_NP              = SLIT("STK_CHK_NP")
-cCheckMacroText        HP_STK_CHK_NP           = SLIT("HP_STK_CHK_NP")
-cCheckMacroText        HP_CHK_FUN              = SLIT("HP_CHK_FUN")
-cCheckMacroText        STK_CHK_FUN             = SLIT("STK_CHK_FUN")
-cCheckMacroText        HP_STK_CHK_FUN          = SLIT("HP_STK_CHK_FUN")
-cCheckMacroText        HP_CHK_NOREGS           = SLIT("HP_CHK_NOREGS")
-cCheckMacroText        HP_CHK_UNPT_R1          = SLIT("HP_CHK_UNPT_R1")
-cCheckMacroText        HP_CHK_UNBX_R1          = SLIT("HP_CHK_UNBX_R1")
-cCheckMacroText        HP_CHK_F1               = SLIT("HP_CHK_F1")
-cCheckMacroText        HP_CHK_D1               = SLIT("HP_CHK_D1")
-cCheckMacroText        HP_CHK_L1               = SLIT("HP_CHK_L1")
-cCheckMacroText        HP_CHK_UNBX_TUPLE       = SLIT("HP_CHK_UNBX_TUPLE")
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[ppr-liveness-masks]{Liveness Masks}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-bitmapAddrModes [] = [mkWordCLit 0]
-bitmapAddrModes xs = map mkWordCLit xs
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[a2r-MagicIds]{Magic ids}
-%*                                                                     *
-%************************************************************************
-
-@pprRegRelative@ returns a pair of the @Doc@ for the register
-(some casting may be required), and a @Maybe Doc@ for the offset
-(zero offset gives a @Nothing@).
-
-\begin{code}
-addPlusSign :: Bool -> SDoc -> SDoc
-addPlusSign False p = p
-addPlusSign True  p = (<>) (char '+') p
-
-pprSignedInt :: Bool -> Int -> Maybe SDoc      -- Nothing => 0
-pprSignedInt sign_wanted n
- = if n == 0 then Nothing else
-   if n > 0  then Just (addPlusSign sign_wanted (int n))
-   else          Just (int n)
-
-pprRegRelative :: Bool         -- True <=> Print leading plus sign (if +ve)
-              -> RegRelative
-              -> (SDoc, Maybe SDoc)
-
-pprRegRelative sign_wanted (SpRel off)
-  = (pprMagicId Sp, pprSignedInt sign_wanted (I# off))
-
-pprRegRelative sign_wanted r@(HpRel o)
-  = let pp_Hp   = pprMagicId Hp; off = I# o
-    in
-    if off == 0 then
-       (pp_Hp, Nothing)
-    else
-       (pp_Hp, Just ((<>) (char '-') (int off)))
-
-pprRegRelative sign_wanted (NodeRel o)
-  = let pp_Node = pprMagicId node; off = I# o
-    in
-    if off == 0 then
-       (pp_Node, Nothing)
-    else
-       (pp_Node, Just (addPlusSign sign_wanted (int off)))
-
-pprRegRelative sign_wanted (CIndex base offset kind)
-  = ( hcat [text "((", pprPrimKind kind, text " *)(", ppr_amode base, text "))"]
-    , Just (hcat [if sign_wanted then char '+' else empty,
-           text "(I_)(", ppr_amode offset, ptext SLIT(")")])
-    )
-\end{code}
-
-@pprMagicId@ just prints the register name.  @VanillaReg@ registers are
-represented by a discriminated union (@StgUnion@), so we use the @PrimRep@
-to select the union tag.
-
-\begin{code}
-pprMagicId :: MagicId -> SDoc
-
-pprMagicId BaseReg                 = ptext SLIT("BaseReg")
-pprMagicId (VanillaReg pk n)
-                                   = hcat [ pprVanillaReg n, char '.',
-                                                 pprUnionTag pk ]
-pprMagicId (FloatReg  n)            = ptext SLIT("F") <> int (I# n)
-pprMagicId (DoubleReg n)           = ptext SLIT("D") <> int (I# n)
-pprMagicId (LongReg _ n)           = ptext SLIT("L") <> int (I# n)
-pprMagicId Sp                      = ptext SLIT("Sp")
-pprMagicId SpLim                   = ptext SLIT("SpLim")
-pprMagicId Hp                      = ptext SLIT("Hp")
-pprMagicId HpLim                   = ptext SLIT("HpLim")
-pprMagicId CurCostCentre           = ptext SLIT("CCCS")
-pprMagicId VoidReg                 = ptext SLIT("VoidReg")
-
-pprVanillaReg :: Int# -> SDoc
-pprVanillaReg n = char 'R' <> int (I# n)
-
-pprUnionTag :: PrimRep -> SDoc
-
-pprUnionTag PtrRep             = char 'p'
-pprUnionTag CodePtrRep         = ptext SLIT("fp")
-pprUnionTag DataPtrRep         = char 'd'
-pprUnionTag RetRep             = char 'p'
-pprUnionTag CostCentreRep      = panic "pprUnionTag:CostCentre?"
-
-pprUnionTag CharRep            = char 'c'
-pprUnionTag Int8Rep            = ptext SLIT("i8")
-pprUnionTag IntRep             = char 'i'
-pprUnionTag WordRep            = char 'w'
-pprUnionTag Int32Rep           = char 'i'
-pprUnionTag Word32Rep          = char 'w'
-pprUnionTag AddrRep            = char 'a'
-pprUnionTag FloatRep           = char 'f'
-pprUnionTag DoubleRep          = panic "pprUnionTag:Double?"
-
-pprUnionTag StablePtrRep       = char 'p'
-
-pprUnionTag _                   = panic "pprUnionTag:Odd kind"
-\end{code}
-
-
-Find and print local and external declarations for a list of
-Abstract~C statements.
-\begin{code}
-pprTempAndExternDecls :: AbstractC -> (SDoc{-temps-}, SDoc{-externs-})
-pprTempAndExternDecls AbsCNop = (empty, empty)
-
-pprTempAndExternDecls (AbsCStmts stmt1 stmt2)
-  = initTE (ppr_decls_AbsC stmt1       `thenTE` \ (t_p1, e_p1) ->
-           ppr_decls_AbsC stmt2        `thenTE` \ (t_p2, e_p2) ->
-           case (catMaybes [t_p1, t_p2])        of { real_temps ->
-           case (catMaybes [e_p1, e_p2])        of { real_exts ->
-           returnTE (vcat real_temps, vcat real_exts) }}
-          )
-
-pprTempAndExternDecls other_stmt
-  = initTE (ppr_decls_AbsC other_stmt `thenTE` \ (maybe_t, maybe_e) ->
-           returnTE (
-               case maybe_t of
-                 Nothing -> empty
-                 Just pp -> pp,
-
-               case maybe_e of
-                 Nothing -> empty
-                 Just pp -> pp )
-          )
-
-pprBasicLit :: Literal -> SDoc
-pprPrimKind :: PrimRep -> SDoc
-
-pprBasicLit  lit = ppr lit
-pprPrimKind  k   = ppr k
-\end{code}
-
-
-%************************************************************************
-%*                                                                     *
-\subsection[a2r-monad]{Monadery}
-%*                                                                     *
-%************************************************************************
-
-We need some monadery to keep track of temps and externs we have already
-printed.  This info must be threaded right through the Abstract~C, so
-it's most convenient to hide it in this monad.
-
-WDP 95/02: Switched from \tr{([Unique], [CLabel])} to
-\tr{(UniqSet, CLabelSet)}.  Allegedly for efficiency.
-
-\begin{code}
-type CLabelSet = FiniteMap CLabel (){-any type will do-}
-emptyCLabelSet = emptyFM
-x `elementOfCLabelSet` labs
-  = case (lookupFM labs x) of { Just _ -> True; Nothing -> False }
-
-addToCLabelSet set x = addToFM set x ()
-
-type TEenv = (UniqSet Unique, CLabelSet)
-
-type TeM result =  TEenv -> (TEenv, result)
-
-initTE :: TeM a -> a
-initTE sa
-  = case sa (emptyUniqSet, emptyCLabelSet) of { (_, result) ->
-    result }
-
-{-# INLINE thenTE #-}
-{-# INLINE returnTE #-}
-
-thenTE :: TeM a -> (a -> TeM b) -> TeM b
-thenTE a b u
-  = case a u       of { (u_1, result_of_a) ->
-    b result_of_a u_1 }
-
-mapTE :: (a -> TeM b) -> [a] -> TeM [b]
-mapTE f []     = returnTE []
-mapTE f (x:xs)
-  = f x                `thenTE` \ r  ->
-    mapTE f xs `thenTE` \ rs ->
-    returnTE (r : rs)
-
-returnTE :: a -> TeM a
-returnTE result env = (env, result)
-
--- these next two check whether the thing is already
--- recorded, and THEN THEY RECORD IT
--- (subsequent calls will return False for the same uniq/label)
-
-tempSeenTE :: Unique -> TeM Bool
-tempSeenTE uniq env@(seen_uniqs, seen_labels)
-  = if (uniq `elementOfUniqSet` seen_uniqs)
-    then (env, True)
-    else ((addOneToUniqSet seen_uniqs uniq,
-         seen_labels),
-         False)
-
-labelSeenTE :: CLabel -> TeM Bool
-labelSeenTE lbl env@(seen_uniqs, seen_labels)
-  = if (lbl `elementOfCLabelSet` seen_labels)
-    then (env, True)
-    else ((seen_uniqs,
-         addToCLabelSet seen_labels lbl),
-         False)
-\end{code}
-
-\begin{code}
-pprTempDecl :: Unique -> PrimRep -> SDoc
-pprTempDecl uniq kind
-  = hcat [ pprPrimKind kind, space, char '_', pprUnique uniq, ptext SLIT("_;") ]
-
-pprExternDecl :: Bool -> CLabel -> SDoc
-pprExternDecl in_srt clabel
-  | not (needsCDecl clabel) = empty -- do not print anything for "known external" things
-  | otherwise              = 
-       hcat [ ppLocalnessMacro (not in_srt) clabel, 
-              lparen, dyn_wrapper (pprCLabel clabel), pp_paren_semi ]
- where
-  dyn_wrapper d
-    | in_srt && labelDynamic clabel = text "DLL_IMPORT_DATA_VAR" <> parens d
-    | otherwise                            = d
-
-\end{code}
-
-\begin{code}
-ppr_decls_AbsC :: AbstractC -> TeM (Maybe SDoc{-temps-}, Maybe SDoc{-externs-})
-
-ppr_decls_AbsC AbsCNop         = returnTE (Nothing, Nothing)
-
-ppr_decls_AbsC (AbsCStmts stmts_1 stmts_2)
-  = ppr_decls_AbsC stmts_1  `thenTE` \ p1 ->
-    ppr_decls_AbsC stmts_2  `thenTE` \ p2 ->
-    returnTE (maybe_vcat [p1, p2])
-
-ppr_decls_AbsC (CSplitMarker) = returnTE (Nothing, Nothing)
-
-ppr_decls_AbsC (CAssign dest source)
-  = ppr_decls_Amode dest    `thenTE` \ p1 ->
-    ppr_decls_Amode source  `thenTE` \ p2 ->
-    returnTE (maybe_vcat [p1, p2])
-
-ppr_decls_AbsC (CJump target) = ppr_decls_Amode target
-
-ppr_decls_AbsC (CFallThrough target) = ppr_decls_Amode target
-
-ppr_decls_AbsC (CReturn target _) = ppr_decls_Amode target
-
-ppr_decls_AbsC (CSwitch discrim alts deflt)
-  = ppr_decls_Amode discrim    `thenTE` \ pdisc ->
-    mapTE ppr_alt_stuff alts   `thenTE` \ palts  ->
-    ppr_decls_AbsC deflt       `thenTE` \ pdeflt ->
-    returnTE (maybe_vcat (pdisc:pdeflt:palts))
-  where
-    ppr_alt_stuff (_, absC) = ppr_decls_AbsC absC
-
-ppr_decls_AbsC (CCodeBlock lbl absC)
-  = ppr_decls_AbsC absC
-
-ppr_decls_AbsC (CInitHdr cl_info reg_rel cost_centre _)
-       -- ToDo: strictly speaking, should chk "cost_centre" amode
-  = labelSeenTE info_lbl     `thenTE` \  label_seen ->
-    returnTE (Nothing,
-             if label_seen then
-                 Nothing
-             else
-                 Just (pprExternDecl False{-not in an SRT decl-} info_lbl))
-  where
-    info_lbl = infoTableLabelFromCI cl_info
-
-ppr_decls_AbsC (CMachOpStmt res        _ args _) = ppr_decls_Amodes (res : args)
-ppr_decls_AbsC (COpStmt        results _ args _) = ppr_decls_Amodes (results ++ args)
-
-ppr_decls_AbsC (CSimultaneous abc)       = ppr_decls_AbsC abc
-
-ppr_decls_AbsC (CSequential abcs) 
-  = mapTE ppr_decls_AbsC abcs  `thenTE` \ t_and_e_s ->
-    returnTE (maybe_vcat t_and_e_s)
-
-ppr_decls_AbsC (CCheck             _ amodes code) = 
-     ppr_decls_Amodes amodes `thenTE` \p1 ->
-     ppr_decls_AbsC code     `thenTE` \p2 ->
-     returnTE (maybe_vcat [p1,p2])
-
-ppr_decls_AbsC (CMacroStmt         _ amodes)   = ppr_decls_Amodes amodes
-
-ppr_decls_AbsC (CCallProfCtrMacro   _ amodes)  = ppr_decls_Amodes [] -- *****!!!
-  -- you get some nasty re-decls of stdio.h if you compile
-  -- the prelude while looking inside those amodes;
-  -- no real reason to, anyway.
-ppr_decls_AbsC (CCallProfCCMacro    _ amodes)  = ppr_decls_Amodes amodes
-
-ppr_decls_AbsC (CStaticClosure _ closure_info cost_centre amodes)
-       -- ToDo: strictly speaking, should chk "cost_centre" amode
-  = ppr_decls_Amodes amodes
-
-ppr_decls_AbsC (CClosureInfoAndCode cl_info entry)
-  = ppr_decls_Amodes [entry_lbl]               `thenTE` \ p1 ->
-    ppr_decls_AbsC entry                       `thenTE` \ p2 ->
-    returnTE (maybe_vcat [p1, p2])
-  where
-    entry_lbl = CLbl (entryLabelFromCI cl_info) CodePtrRep
-
-ppr_decls_AbsC (CSRT _ closure_lbls)
-  = mapTE labelSeenTE closure_lbls             `thenTE` \ seen ->
-    returnTE (Nothing, 
-             if and seen then Nothing
-               else Just (vcat [ pprExternDecl True{-in SRT decl-} l
-                               | (l,False) <- zip closure_lbls seen ]))
-
-ppr_decls_AbsC (CRetDirect     _ code _ _)   = ppr_decls_AbsC code
-ppr_decls_AbsC (CRetVector _ amodes _ _)     = ppr_decls_Amodes amodes
-ppr_decls_AbsC (CModuleInitBlock _ _ code)   = ppr_decls_AbsC code
-
-ppr_decls_AbsC (_) = returnTE (Nothing, Nothing)
-\end{code}
-
-\begin{code}
-ppr_decls_Amode :: CAddrMode -> TeM (Maybe SDoc, Maybe SDoc)
-ppr_decls_Amode (CVal  (CIndex base offset _) _) = ppr_decls_Amodes [base,offset]
-ppr_decls_Amode (CAddr (CIndex base offset _))   = ppr_decls_Amodes [base,offset]
-ppr_decls_Amode (CVal _ _)     = returnTE (Nothing, Nothing)
-ppr_decls_Amode (CAddr _)      = returnTE (Nothing, Nothing)
-ppr_decls_Amode (CReg _)       = returnTE (Nothing, Nothing)
-ppr_decls_Amode (CLit _)       = returnTE (Nothing, Nothing)
-
--- CIntLike must be a literal -- no decls
-ppr_decls_Amode (CIntLike int) = returnTE (Nothing, Nothing)
-
--- CCharLike too
-ppr_decls_Amode (CCharLike char) = returnTE (Nothing, Nothing)
-
--- now, the only place where we actually print temps/externs...
-ppr_decls_Amode (CTemp uniq kind)
-  = case kind of
-      VoidRep -> returnTE (Nothing, Nothing)
-      other ->
-       tempSeenTE uniq `thenTE` \ temp_seen ->
-       returnTE
-         (if temp_seen then Nothing else Just (pprTempDecl uniq kind), Nothing)
-
-ppr_decls_Amode (CLbl lbl VoidRep)
-  = returnTE (Nothing, Nothing)
-
-ppr_decls_Amode (CLbl lbl kind)
-  = labelSeenTE lbl `thenTE` \ label_seen ->
-    returnTE (Nothing,
-             if label_seen then Nothing else Just (pprExternDecl False{-not in an SRT decl-} lbl))
-
-ppr_decls_Amode (CMacroExpr _ _ amodes)
-  = ppr_decls_Amodes amodes
-
-ppr_decls_Amode other = returnTE (Nothing, Nothing)
-
-
-maybe_vcat :: [(Maybe SDoc, Maybe SDoc)] -> (Maybe SDoc, Maybe SDoc)
-maybe_vcat ps
-  = case (unzip ps)    of { (ts, es) ->
-    case (catMaybes ts)        of { real_ts  ->
-    case (catMaybes es)        of { real_es  ->
-    (if (null real_ts) then Nothing else Just (vcat real_ts),
-     if (null real_es) then Nothing else Just (vcat real_es))
-    } } }
-\end{code}
-
-\begin{code}
-ppr_decls_Amodes :: [CAddrMode] -> TeM (Maybe SDoc, Maybe SDoc)
-ppr_decls_Amodes amodes
-  = mapTE ppr_decls_Amode amodes `thenTE` \ ps ->
-    returnTE ( maybe_vcat ps )
-\end{code}
-
-Print out a C Label where you want the *address* of the label, not the
-object it refers to.  The distinction is important when the label may
-refer to a C structure (info tables and closures, for instance).
-
-When just generating a declaration for the label, use pprCLabel.
-
-\begin{code}
-pprCLabelAddr :: CLabel -> SDoc
-pprCLabelAddr clabel =
-  case labelType clabel of
-     InfoTblType    -> addr_of_label
-     RetInfoTblType -> addr_of_label
-     ClosureType    -> addr_of_label
-     VecTblType     -> addr_of_label
-     DataType      -> addr_of_label
-
-     _              -> pp_label
-  where
-    addr_of_label = ptext SLIT("(P_)&") <> pp_label
-    pp_label = pprCLabel clabel
-\end{code}
-
------------------------------------------------------------------------------
-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.
-
-\begin{code}
-big_doubles = (getPrimRepSize DoubleRep) /= 1
-
-#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 :: CAddrMode -> CAddrMode
-floatToWord (CLit (MachFloat r))
-  = runST (do
-       arr <- newFloatArray ((0::Int),0)
-       writeFloatArray arr 0 (fromRational r)
-       arr' <- castFloatToIntArray arr
-       i <- readIntArray arr' 0
-       return (CLit (MachInt (toInteger i)))
-    )
-
-doubleToWords :: CAddrMode -> [CAddrMode]
-doubleToWords (CLit (MachDouble 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 [ CLit (MachInt (toInteger i1))
-              , CLit (MachInt (toInteger i2))
-              ]
-    )
-  | 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 [ CLit (MachInt (toInteger i)) ]
-    )
-\end{code}
index 8761762..4b7f131 100644 (file)
@@ -15,7 +15,7 @@ module Id (
 
        -- Taking an Id apart
        idName, idType, idUnique, idInfo,
-       idPrimRep, isId, globalIdDetails,
+       isId, globalIdDetails, idPrimRep,
        recordSelectorFieldLabel,
 
        -- Modifying an Id
@@ -90,7 +90,8 @@ import Var            ( Id, DictId,
                          globalIdDetails
                        )
 import qualified Var   ( mkLocalId, mkGlobalId, mkSpecPragmaId, mkExportedLocalId )
-import Type            ( Type, typePrimRep, addFreeTyVars, seqType, splitTyConApp_maybe )
+import Type            ( Type, typePrimRep, addFreeTyVars, seqType, 
+                         splitTyConApp_maybe, PrimRep )
 import TysPrim         ( statePrimTyCon )
 import IdInfo 
 
@@ -105,7 +106,6 @@ import Name         ( Name, OccName, nameIsLocalOrFrom,
                        ) 
 import Module          ( Module )
 import OccName         ( EncodedFS, mkWorkerOcc )
-import PrimRep         ( PrimRep )
 import FieldLabel      ( FieldLabel )
 import Maybes          ( orElse )
 import SrcLoc          ( SrcLoc )
index 35d9ba0..01b21b1 100644 (file)
@@ -10,7 +10,7 @@ module Literal
        , mkMachInt64, mkMachWord64
        , litSize
        , litIsDupable, litIsTrivial
-       , literalType, literalPrimRep
+       , literalType, 
        , hashLiteral
 
        , inIntRange, inWordRange, tARGET_MAX_INT, inCharRange
@@ -29,10 +29,7 @@ module Literal
 import TysPrim         ( charPrimTy, addrPrimTy, floatPrimTy, doublePrimTy,
                          intPrimTy, wordPrimTy, int64PrimTy, word64PrimTy
                        )
-import PrimRep         ( PrimRep(..) )
 import Type            ( Type )
-import CStrings                ( pprFSInCStyle )
-
 import Outputable
 import FastTypes
 import FastString
@@ -298,31 +295,16 @@ litSize _other          = 1
        ~~~~~
 \begin{code}
 literalType :: Literal -> Type
-literalType (MachChar _)         = charPrimTy
-literalType (MachStr  _)         = addrPrimTy
-literalType (MachNullAddr)       = addrPrimTy
-literalType (MachInt  _)         = intPrimTy
-literalType (MachWord  _)        = wordPrimTy
-literalType (MachInt64  _)       = int64PrimTy
-literalType (MachWord64  _)      = word64PrimTy
-literalType (MachFloat _)        = floatPrimTy
-literalType (MachDouble _)       = doublePrimTy
-literalType (MachLabel _ _)      = addrPrimTy
-\end{code}
-
-\begin{code}
-literalPrimRep :: Literal -> PrimRep
-
-literalPrimRep (MachChar _)      = CharRep
-literalPrimRep (MachStr _)       = AddrRep  -- specifically: "char *"
-literalPrimRep (MachNullAddr)    = AddrRep
-literalPrimRep (MachInt _)       = IntRep
-literalPrimRep (MachWord _)      = WordRep
-literalPrimRep (MachInt64 _)     = Int64Rep
-literalPrimRep (MachWord64 _)    = Word64Rep
-literalPrimRep (MachFloat _)     = FloatRep
-literalPrimRep (MachDouble _)    = DoubleRep
-literalPrimRep (MachLabel _ _)   = AddrRep
+literalType MachNullAddr    = addrPrimTy
+literalType (MachChar _)    = charPrimTy
+literalType (MachStr  _)    = addrPrimTy
+literalType (MachInt  _)    = intPrimTy
+literalType (MachWord  _)   = wordPrimTy
+literalType (MachInt64  _)  = int64PrimTy
+literalType (MachWord64  _) = word64PrimTy
+literalType (MachFloat _)   = floatPrimTy
+literalType (MachDouble _)  = doublePrimTy
+literalType (MachLabel _ _) = addrPrimTy
 \end{code}
 
 
@@ -360,71 +342,24 @@ litTag (MachLabel   _ _)   = _ILIT(10)
   exceptions: MachFloat gets an initial keyword prefix.
 
 \begin{code}
-pprLit lit
-  = getPprStyle $ \ sty ->
-    let
-      code_style  = codeStyle  sty
-    in
-    case lit of
-      MachChar ch | code_style -> hcat [ptext SLIT("(C_)"), text (show (ord ch))]
-                 | otherwise  -> pprHsChar ch
-
-      MachStr s | code_style -> pprFSInCStyle s
-               | otherwise  -> pprHsString s
-      -- Warning: printing MachStr in code_style assumes it contains
-      -- only characters '\0'..'\xFF'!
-
-      MachInt i | code_style && i == tARGET_MIN_INT -> parens (integer (i+1) <> text "-1")
-                               -- Avoid a problem whereby gcc interprets
-                               -- the constant minInt as unsigned.
-               | otherwise -> pprIntVal i
-
-      MachInt64 i | code_style -> pprIntVal i          -- Same problem with gcc???
-                 | otherwise -> ptext SLIT("__int64") <+> integer i
-
-      MachWord w | code_style -> pprHexVal w
-                | otherwise  -> ptext SLIT("__word") <+> integer w
-
-      MachWord64 w | code_style -> pprHexVal w
-                  | otherwise  -> ptext SLIT("__word64") <+> integer w
-
-      MachFloat f | code_style -> ptext SLIT("(StgFloat)") <> code_rational f
-                  | otherwise  -> ptext SLIT("__float") <+> rational f
-
-      MachDouble d | code_style -> code_rational d
-                  | otherwise  -> rational d
-
-      MachNullAddr | code_style -> ptext SLIT("(void*)0")
-                  | otherwise  -> ptext SLIT("__NULL")
-
-      MachLabel l mb
-         | code_style -> ptext SLIT("(&") <> ftext l <> char ')'
-        | otherwise  -> ptext SLIT("__label") <+> 
-            case mb of
-              Nothing -> pprHsString l
-              Just x  -> doubleQuotes (text (unpackFS l ++ '@':show x))
-
--- negative floating literals in code style need parentheses to avoid
--- interacting with surrounding syntax.
-code_rational d | d < 0     = parens (rational d)
-                | otherwise = rational d
+pprLit (MachChar ch)   = pprHsChar ch
+pprLit (MachStr s)     = pprHsString s
+pprLit (MachInt i)     = pprIntVal i
+pprLit (MachInt64 i)   = ptext SLIT("__int64") <+> integer i
+pprLit (MachWord w)    = ptext SLIT("__word") <+> integer w
+pprLit (MachWord64 w)  = ptext SLIT("__word64") <+> integer w
+pprLit (MachFloat f)   = ptext SLIT("__float") <+> rational f
+pprLit (MachDouble d)  = rational d
+pprLit (MachNullAddr)  = ptext SLIT("__NULL")
+pprLit (MachLabel l mb) = ptext SLIT("__label") <+> 
+                            case mb of
+                              Nothing -> pprHsString l
+                              Just x  -> doubleQuotes (text (unpackFS l ++ '@':show x))
 
 pprIntVal :: Integer -> SDoc
 -- Print negative integers with parens to be sure it's unambiguous
 pprIntVal i | i < 0     = parens (integer i)
            | otherwise = integer i
-               
-pprHexVal :: Integer -> SDoc
--- Print in C hex format: 0x13fa 
-pprHexVal 0 = ptext SLIT("0x0")
-pprHexVal w = ptext SLIT("0x") <> go w
-           where
-             go 0 = empty
-             go w = go quot <> dig
-                  where
-                    (quot,rem) = w `quotRem` 16
-                    dig | rem < 10  = char (chr (fromInteger rem + ord '0'))
-                        | otherwise = char (chr (fromInteger rem - 10 + ord 'a'))
 \end{code}
 
 
index 2b55d01..702b07f 100644 (file)
@@ -323,9 +323,7 @@ pprExternal sty name uniq mod occ mb_p is_wired
 
 pprInternal sty uniq occ
   | codeStyle sty  = pprUnique uniq
-  | debugStyle sty = hsep [pprOccName occ, text "{-", 
-                          text (briefOccNameFlavour occ), 
-                          pprUnique uniq, text "-}"]
+  | debugStyle sty = pprOccName occ <> text "{-" <> pprUnique uniq <> text "-}"
   | otherwise      = pprOccName occ    -- User style
 
 -- Like Internal, except that we only omit the unique in Iface style
index 9f5109f..dbfc12a 100644 (file)
@@ -41,7 +41,10 @@ module Unique (
        mkPArrDataConUnique,
 
        mkBuiltinUnique,
-       mkPseudoUnique3
+       mkPseudoUniqueC,
+       mkPseudoUniqueD,
+       mkPseudoUniqueE,
+       mkPseudoUniqueH
     ) where
 
 #include "HsVersions.h"
@@ -255,13 +258,22 @@ iToBase62 n@(I# n#)
 
 Allocation of unique supply characters:
        v,t,u : for renumbering value-, type- and usage- vars.
-       other a-z: lower case chars for unique supplies (see Main.lhs)
        B:   builtin
        C-E: pseudo uniques     (used in native-code generator)
        X:   uniques derived by deriveUnique
        _:   unifiable tyvars   (above)
        0-9: prelude things below
 
+       other a-z: lower case chars for unique supplies.  Used so far:
+
+       d       desugarer
+       f       AbsC flattener
+       g       SimplStg
+       l       ndpFlatten
+       n       Native codegen
+       r       Hsc name cache
+       s       simplifier
+
 \begin{code}
 mkAlphaTyVarUnique i            = mkUnique '1' i
 
@@ -303,15 +315,13 @@ mkPArrDataConUnique a             = mkUnique ':' (2*a)
 initTyVarUnique :: Unique
 initTyVarUnique = mkUnique 't' 0
 
-mkPseudoUnique1, mkPseudoUnique2, mkPseudoUnique3, 
+mkPseudoUniqueC, mkPseudoUniqueD, mkPseudoUniqueE, mkPseudoUniqueH,
    mkBuiltinUnique :: Int -> Unique
 
-builtinUniques :: [Unique]
-builtinUniques = map mkBuiltinUnique [1..]
-
 mkBuiltinUnique i = mkUnique 'B' i
-mkPseudoUnique1 i = mkUnique 'C' i -- used for getUnique on Regs
-mkPseudoUnique2 i = mkUnique 'D' i -- used in NCG for getUnique on RealRegs
-mkPseudoUnique3 i = mkUnique 'E' i -- used in NCG spiller to create spill VirtualRegs
+mkPseudoUniqueC i = mkUnique 'C' i -- used for getUnique on Regs
+mkPseudoUniqueD i = mkUnique 'D' i -- used in NCG for getUnique on RealRegs
+mkPseudoUniqueE i = mkUnique 'E' i -- used in NCG spiller to create spill VirtualRegs
+mkPseudoUniqueH i = mkUnique 'H' i -- used in NCG spiller to create spill VirtualRegs
 \end{code}
 
diff --git a/ghc/compiler/cmm/CLabel.hs b/ghc/compiler/cmm/CLabel.hs
new file mode 100644 (file)
index 0000000..ae470ca
--- /dev/null
@@ -0,0 +1,671 @@
+-----------------------------------------------------------------------------
+--
+-- 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,
+
+       mkReturnPtLabel,
+       mkReturnInfoLabel,
+       mkAltLabel,
+       mkDefaultLabel,
+       mkBitmapLabel,
+
+       mkClosureTblLabel,
+
+       mkAsmTempLabel,
+
+       mkModuleInitLabel,
+       mkPlainModuleInitLabel,
+
+       mkErrorStdEntryLabel,
+       mkSplitMarkerLabel,
+       mkUpdInfoLabel,
+       mkSeqInfoLabel,
+       mkIndStaticInfoLabel,
+        mkMainCapabilityLabel,
+       mkMAP_FROZEN_infoLabel,
+        mkEMPTY_MVAR_infoLabel,
+
+       mkTopTickyCtrLabel,
+        mkCAFBlackHoleInfoTableLabel,
+        mkSECAFBlackHoleInfoTableLabel,
+       mkRtsPrimOpLabel,
+       mkRtsSlowTickyCtrLabel,
+
+       moduleRegdLabel,
+
+       mkSelectorInfoLabel,
+       mkSelectorEntryLabel,
+
+       mkRtsInfoLabel,
+       mkRtsEntryLabel,
+       mkRtsRetInfoLabel,
+       mkRtsRetLabel,
+       mkRtsCodeLabel,
+       mkRtsDataLabel,
+
+       mkRtsInfoLabelFS,
+       mkRtsEntryLabelFS,
+       mkRtsRetInfoLabelFS,
+       mkRtsRetLabelFS,
+       mkRtsCodeLabelFS,
+       mkRtsDataLabelFS,
+
+       mkForeignLabel,
+
+       mkCCLabel, mkCCSLabel,
+
+       infoLblToEntryLbl, entryLblToInfoLbl,
+       needsCDecl, isAsmTemp, externallyVisibleCLabel,
+       CLabelType(..), labelType, labelDynamic, labelCouldBeDynamic,
+
+       pprCLabel
+    ) where
+
+
+#include "HsVersions.h"
+#include "../includes/ghcconfig.h"
+
+import CmdLineOpts      ( opt_Static, opt_DoTickyProfiling )
+import DataCon         ( ConTag )
+import Module          ( moduleName, moduleNameFS, 
+                         Module, isHomeModule )
+import Name            ( Name, isDllName, 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
+
+  | CaseLabel                  -- A family of labels related to a particular
+                               -- case expression.
+       {-# UNPACK #-} !Unique  -- Unique says which case expression
+       CaseLabelInfo
+
+  | AsmTempLabel 
+       {-# UNPACK #-} !Unique
+
+  | ModuleInitLabel 
+       Module                  -- the module name
+       String                  -- its "way"
+       -- 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 Module         -- without the vesrion & way info
+
+  | 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
+
+  deriving (Eq, Ord)
+
+
+data IdLabelInfo
+  = Closure            -- Label for closure
+  | SRT                 -- Static reference table
+  | SRTDesc             -- Static reference table descriptor
+  | InfoTbl            -- 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
+  | ConInfoTbl                 -- corresponding info table
+  | StaticConEntry     -- static constructor entry point
+  | StaticInfoTbl      -- 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
+  = RtsShouldNeverHappenCode
+
+  | RtsSelectorInfoTbl Bool{-updatable-} Int{-offset-} -- Selector thunks
+  | RtsSelectorEntry   Bool{-updatable-} Int{-offset-}
+
+  | RtsApInfoTbl 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
+
+  | RtsSlowTickyCtr String
+
+  deriving (Eq, Ord)
+       -- NOTE: Eq on LitString compares the pointer only, so this isn't
+       -- a real equality.
+
+-- -----------------------------------------------------------------------------
+-- Constructing CLabels
+
+mkClosureLabel         id      = IdLabel id  Closure
+mkSRTLabel             id      = IdLabel id  SRT
+mkSRTDescLabel         id      = IdLabel id  SRTDesc
+mkInfoTableLabel       id      = IdLabel id  InfoTbl
+mkEntryLabel           id      = IdLabel id  Entry
+mkSlowEntryLabel       id      = IdLabel id  Slow
+mkBitmapLabel          id      = IdLabel id  Bitmap
+mkRednCountsLabel      id      = IdLabel id  RednCounts
+
+mkConInfoTableLabel     con    = IdLabel con ConInfoTbl
+mkConEntryLabel                con     = IdLabel con ConEntry
+mkStaticInfoTableLabel  con    = IdLabel con StaticInfoTbl
+mkStaticConEntryLabel  con     = IdLabel con StaticConEntry
+
+mkClosureTblLabel      id      = IdLabel id ClosureTable
+
+mkReturnPtLabel uniq           = CaseLabel uniq CaseReturnPt
+mkReturnInfoLabel uniq         = CaseLabel uniq CaseReturnInfo
+mkAltLabel      uniq tag       = CaseLabel uniq (CaseAlt tag)
+mkDefaultLabel  uniq           = CaseLabel uniq CaseDefault
+
+mkAsmTempLabel                         = AsmTempLabel
+
+mkModuleInitLabel              = ModuleInitLabel
+mkPlainModuleInitLabel         = PlainModuleInitLabel
+
+       -- Some fixed runtime system labels
+
+mkErrorStdEntryLabel           = RtsLabel RtsShouldNeverHappenCode
+mkSplitMarkerLabel             = RtsLabel (RtsCode SLIT("__stg_split_marker"))
+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_FROZEN"))
+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 (RtsSelectorInfoTbl upd off)
+mkSelectorEntryLabel upd off   = RtsLabel (RtsSelectorEntry   upd off)
+
+mkApInfoTableLabel  upd off    = RtsLabel (RtsApInfoTbl 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)
+
+mkRtsSlowTickyCtrLabel :: String -> CLabel
+mkRtsSlowTickyCtrLabel pat = RtsLabel (RtsSlowTickyCtr pat)
+
+-- -----------------------------------------------------------------------------
+-- Converting info labels to entry labels.
+
+infoLblToEntryLbl :: CLabel -> CLabel 
+infoLblToEntryLbl (IdLabel n InfoTbl) = IdLabel n Entry
+infoLblToEntryLbl (IdLabel n ConInfoTbl) = IdLabel n ConEntry
+infoLblToEntryLbl (IdLabel n StaticInfoTbl) = IdLabel 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 InfoTbl
+entryLblToInfoLbl (IdLabel n ConEntry) = IdLabel n ConInfoTbl
+entryLblToInfoLbl (IdLabel n StaticConEntry) = IdLabel n StaticInfoTbl
+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 (CaseLabel _ CaseReturnPt)  = True
+needsCDecl (CaseLabel _ CaseReturnInfo)        = True
+needsCDecl (ModuleInitLabel _ _)       = True
+needsCDecl (PlainModuleInitLabel _)    = True
+needsCDecl ModuleRegdLabel             = False
+
+needsCDecl (CaseLabel _ _)             = 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 (AsmTempLabel _)   = False
+externallyVisibleCLabel (ModuleInitLabel _ _)= True
+externallyVisibleCLabel (PlainModuleInitLabel _)= True
+externallyVisibleCLabel ModuleRegdLabel    = False
+externallyVisibleCLabel (RtsLabel _)      = True
+externallyVisibleCLabel (ForeignLabel _ _ _) = True
+externallyVisibleCLabel (IdLabel id _)     = isExternalName id
+externallyVisibleCLabel (CC_Label _)      = True
+externallyVisibleCLabel (CCS_Label _)     = True
+
+
+-- -----------------------------------------------------------------------------
+-- Finding the "type" of a CLabel 
+
+-- For generating correct types in label declarations:
+
+data CLabelType
+  = CodeLabel
+  | DataLabel
+
+labelType :: CLabel -> CLabelType
+labelType (RtsLabel (RtsSelectorInfoTbl _ _)) = DataLabel
+labelType (RtsLabel (RtsApInfoTbl _ _))       = 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 (CaseLabel _ CaseReturnInfo)        = DataLabel
+labelType (CaseLabel _ CaseReturnPt)         = CodeLabel
+labelType (ModuleInitLabel _ _)               = CodeLabel
+labelType (PlainModuleInitLabel _)            = CodeLabel
+
+labelType (IdLabel _ info) = 
+  case info of
+    InfoTbl              -> DataLabel
+    Closure              -> DataLabel
+    Bitmap               -> DataLabel
+    ConInfoTbl           -> DataLabel
+    StaticInfoTbl -> DataLabel
+    ClosureTable  -> DataLabel
+    _            -> CodeLabel
+
+labelType _        = DataLabel
+
+
+-- -----------------------------------------------------------------------------
+-- 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
+   -- The special case for RtsShouldNeverHappenCode is because the associated address is
+   -- NULL, i.e. not a DLL entry point
+   RtsLabel RtsShouldNeverHappenCode -> False
+   RtsLabel _               -> not opt_Static  -- i.e., is the RTS in a DLL or not?
+   IdLabel n k       -> isDllName n
+   ForeignLabel _ _ d  -> d
+   ModuleInitLabel m _  -> (not opt_Static) && (not (isHomeModule m))
+   PlainModuleInitLabel m -> (not opt_Static) && (not (isHomeModule m))
+   _                -> False
+
+-- Basically the same as above, but this time for Darwin only.
+-- The things that GHC does when labelDynamic returns true are not quite right
+-- for Darwin. Also, every ForeignLabel might possibly be from a dynamic library,
+-- and a 'false positive' doesn't really hurt on Darwin, so this just returns
+-- True for every ForeignLabel.
+--
+-- ToDo: Clean up DLL-related code so we can do away with the distinction
+--       between this and labelDynamic above.
+
+labelCouldBeDynamic (ForeignLabel _ _ _) = True
+labelCouldBeDynamic lbl = labelDynamic lbl
+
+{-
+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.
+-}
+
+pprCLabel :: CLabel -> SDoc
+
+#if ! OMIT_NATIVE_CODEGEN
+pprCLabel (AsmTempLabel u)
+  =  getPprStyle $ \ sty ->
+     if asmStyle sty then 
+       ptext asmTempLabelPrefix <> pprUnique u
+     else
+       char '_' <> pprUnique u
+#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
+
+-- 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
+pprAsmCLbl lbl
+   = pprCLbl lbl
+
+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 RtsShouldNeverHappenCode) = ptext SLIT("0")
+-- used to be stg_error_entry but Windows can't have DLL entry points as static
+-- initialisers, and besides, this ShouldNeverHappen, right?
+
+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 (RtsSelectorInfoTbl 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 (RtsApInfoTbl 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 id  flavor) = ppr id <> ppIdFlavor flavor
+
+pprCLbl (CC_Label cc)          = ppr cc
+pprCLbl (CCS_Label ccs)        = ppr ccs
+
+pprCLbl (ModuleInitLabel mod way)      
+   = ptext SLIT("__stginit_") <> ftext (moduleNameFS (moduleName mod))
+       <> char '_' <> text way
+pprCLbl (PlainModuleInitLabel mod)     
+   = ptext SLIT("__stginit_") <> ftext (moduleNameFS (moduleName mod))
+
+ppIdFlavor :: IdLabelInfo -> SDoc
+ppIdFlavor x = pp_cSEP <>
+              (case x of
+                      Closure          -> ptext SLIT("closure")
+                      SRT              -> ptext SLIT("srt")
+                      SRTDesc          -> ptext SLIT("srtd")
+                      InfoTbl          -> ptext SLIT("info")
+                      Entry            -> ptext SLIT("entry")
+                      Slow             -> ptext SLIT("slow")
+                      RednCounts       -> ptext SLIT("ct")
+                      Bitmap           -> ptext SLIT("btm")
+                      ConEntry         -> ptext SLIT("con_entry")
+                      ConInfoTbl       -> ptext SLIT("con_info")
+                      StaticConEntry   -> ptext SLIT("static_entry")
+                      StaticInfoTbl    -> 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
diff --git a/ghc/compiler/cmm/Cmm.hs b/ghc/compiler/cmm/Cmm.hs
new file mode 100644 (file)
index 0000000..cf76f45
--- /dev/null
@@ -0,0 +1,305 @@
+-----------------------------------------------------------------------------
+--
+-- 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 )
+
+-----------------------------------------------------------------------------
+--             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
+
+cmmLitRep :: CmmLit -> MachRep
+cmmLitRep (CmmInt _ rep)    = rep
+cmmLitRep (CmmFloat _ rep)  = rep
+cmmLitRep (CmmLabel _)      = wordRep
+cmmLitRep (CmmLabelOff _ _) = 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
+  | UninitialisedData
+  | 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 String
+       -- string of 8-bit values only, not zero terminated.
+       -- ToDo: might be more honest to use [Word8] here?
+
+-----------------------------------------------------------------------------
+--             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
+
+  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/ghc/compiler/cmm/CmmLex.x b/ghc/compiler/cmm/CmmLex.x
new file mode 100644 (file)
index 0000000..e1be71a
--- /dev/null
@@ -0,0 +1,309 @@
+-----------------------------------------------------------------------------
+-- (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+          ;
+
+^\# (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 }
+  
+  $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 (stepOn buf) (len-1) 8 octDecDigit))
+
+tok_hexadecimal span buf len 
+  = return (L span (CmmT_Int  $! parseInteger (stepOnBy 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/ghc/compiler/cmm/CmmLint.hs b/ghc/compiler/cmm/CmmLint.hs
new file mode 100644 (file)
index 0000000..d82fe7c
--- /dev/null
@@ -0,0 +1,152 @@
+-----------------------------------------------------------------------------
+--
+-- 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 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 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/ghc/compiler/cmm/CmmParse.y b/ghc/compiler/cmm/CmmParse.y
new file mode 100644 (file)
index 0000000..e409f25
--- /dev/null
@@ -0,0 +1,878 @@
+-----------------------------------------------------------------------------
+--
+-- (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, mkLblExpr )
+import CmmLex
+import CLabel
+import MachOp
+import SMRep           ( tablesNextToCode, fixedHdrSize, CgRep(..) )
+import Lexer
+
+import ForeignCall     ( CCallConv(..) )
+import Literal         ( mkMachInt )
+import Unique
+import UniqFM
+import SrcLoc
+import CmdLineOpts     ( DynFlags, DynFlag(..), 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 )
+
+#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 [CmmString $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 :: { [CLabel] }
+       : {- empty -}                   { [] }
+       | ',' NAME maybe_vec            { 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 }
+       | '[' 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
+
+-- 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("GET_ENTRY"),    \ [x] -> entryCode (closureInfoPtr x) ),
+  ( FSLIT("STD_INFO"),     \ [x] -> infoTable 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] -> CmmLoad (vectorSlot info conZ) wordRep )
+  ]
+
+-- 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)
+      (info1,info2) = mkRetInfoTable liveness NoC_SRT 
+                               (fromIntegral cl_type) vector
+  return (mkRtsRetInfoLabelFS name, 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
+       stmtEC (CmmCall (CmmForeignCall expr CCallConv) results 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) )
+  ]
+
+parseCmmFile :: DynFlags -> FilePath -> IO (Maybe Cmm)
+parseCmmFile dflags 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 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/ghc/compiler/cmm/CmmUtils.hs b/ghc/compiler/cmm/CmmUtils.hs
new file mode 100644 (file)
index 0000000..b2a107c
--- /dev/null
@@ -0,0 +1,169 @@
+-----------------------------------------------------------------------------
+--
+-- Cmm utilities.
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+module CmmUtils( 
+       CmmStmts, noStmts, oneStmt, mkStmts, plusStmts, stmtList,
+       isNopStmt,
+
+       isTrivialCmmExpr,
+
+       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
+
+---------------------------------------------------
+--
+--     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/ghc/compiler/cmm/MachOp.hs b/ghc/compiler/cmm/MachOp.hs
new file mode 100644 (file)
index 0000000..55aaa3e
--- /dev/null
@@ -0,0 +1,632 @@
+-----------------------------------------------------------------------------
+--
+-- (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,
+       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"
+#include "../includes/ghcconfig.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
+
+-- ----------------------------------------------------------------------------
+-- 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/ghc/compiler/cmm/PprC.hs b/ghc/compiler/cmm/PprC.hs
new file mode 100644 (file)
index 0000000..e7e72ab
--- /dev/null
@@ -0,0 +1,958 @@
+-----------------------------------------------------------------------------
+--
+-- 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 Unique           ( getUnique )
+import UniqSet
+import FiniteMap
+import UniqFM          ( eltsUFM )
+import FastString
+import Outputable
+import Constants
+import CmdLineOpts     ( opt_EnsureSplittableC )
+
+-- The rest
+import Data.List        ( intersperse, group )
+import Data.Bits        ( shiftR )
+import Char             ( ord, chr )
+import IO               ( Handle )
+import DATA_BITS
+
+#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 :: [Cmm] -> SDoc
+pprCs cmms = pprCode CStyle (vcat $ map (\c -> split_marker $$ pprC c) cmms)
+
+writeCs :: Handle -> [Cmm] -> IO ()
+writeCs handle cmms = printForUser handle alwaysQualify (pprCs cmms)
+                       -- ToDo: should be printForC
+
+split_marker
+  | opt_EnsureSplittableC = ptext SLIT("__STG_SPLIT_MARKER")
+  | otherwise             = empty
+
+-- --------------------------------------------------------------------------
+-- 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 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
+       -> ptext SLIT("ASSIGN_Word64") <> 
+               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 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 :: [(CmmReg,MachHint)] -> [(CmmExpr,MachHint)] -> SDoc
+pprCFunType ress args = 
+  res_type ress <> parens (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 ids  = [ i | Just i <- maybe_ids ]
+        pairs = zip [ 0 .. ] (concatMap markfalls (group ids))
+    in 
+        (hang (ptext SLIT("switch") <+> parens ( pprExpr e ) <+> lbrace)
+                4 (vcat ( map caseify pairs )))
+        $$ rbrace
+
+  where
+    -- fall through case
+    caseify (i,Left ident) = 
+        hsep [ ptext SLIT("case") , pprHexVal i <> colon ,
+                        ptext SLIT("/* fall through for"), 
+                        pprBlockId ident, 
+                        ptext SLIT("*/") ]
+
+    caseify (i,Right ident) = 
+        hsep [ ptext SLIT("case") , pprHexVal i <> colon ,
+                        ptext SLIT("goto") , (pprBlockId ident) <> semi ]
+
+    -- mark the bottom of a fallthough sequence of cases as `Right'
+    markfalls [a] = [Right a]
+    markfalls as  = map (\a -> Left a) (init as) ++ [Right (last as)]
+
+
+-- ---------------------------------------------------------------------
+-- 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
+       -> ptext SLIT("PK_Word64") <> 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)) <> semi
+  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
+    CmmFloat f rep     -> parens (machRepCType rep) <> (rational f)
+    CmmLabel clbl      -> mkW_ <> pprCLabel clbl
+    CmmLabelOff clbl i -> mkW_ <> pprCLabel clbl <> char '+' <> int i
+
+pprLit1 :: CmmLit -> SDoc
+pprLit1 lit@(CmmLabelOff _ _) = 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("asin")
+        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("pow")
+        MO_F32_Sin  -> ptext SLIT("sin")
+        MO_F32_Cos  -> ptext SLIT("cos")
+        MO_F32_Tan  -> ptext SLIT("tan")
+        MO_F32_Sinh -> ptext SLIT("sinh")
+        MO_F32_Cosh -> ptext SLIT("cosh")
+        MO_F32_Tanh -> ptext SLIT("tanh")
+        MO_F32_Asin -> ptext SLIT("asin")
+        MO_F32_Acos -> ptext SLIT("acos")
+        MO_F32_Atan -> ptext SLIT("atan")
+        MO_F32_Log  -> ptext SLIT("log")
+        MO_F32_Exp  -> ptext SLIT("exp")
+        MO_F32_Sqrt -> ptext SLIT("sqrt")
+
+-- ---------------------------------------------------------------------
+-- 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
+pprAssign r1 r2
+    = pprCastReg r1 <+> equals <+> 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 r                  = isPtrGlobalReg r
+
+
+-- 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 "pprForeignCall: unknown calling convention"
+
+  | otherwise
+  = save vols $$
+    ptext SLIT("CALLER_SAVE_SYSTEM") $$
+    hcat [ ppr_results results, ppr_fn, 
+          parens (commafy (map pprArg args)), semi ] $$
+    ptext SLIT("CALLER_RESTORE_SYSTEM") $$
+    restore vols
+  where 
+     ppr_results []     = empty
+     ppr_results [(one,hint)]  = pprArg (CmmReg one,hint) <> ptext SLIT(" = ")
+     ppr_results _other = 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
+
+     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
+
+is_cish CCallConv   = True
+is_cish StdCallConv = True
+is_cish _          = False
+
+-- ---------------------------------------------------------------------
+-- 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 _ = 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 (CmmReg r)             = te_Reg r
+te_Expr (CmmLoad e _)          = te_Expr e
+te_Expr (CmmMachOp _ es)       = mapM_ te_Expr es
+te_Expr (CmmRegOff r _)        = te_Reg r
+te_Expr _                      = return ()
+
+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
+
+-- Assumes it contains only characters '\0'..'\xFF'!
+pprFSInCStyle :: FastString -> SDoc
+pprFSInCStyle fs = pprStringInCStyle (unpackFS fs)
+
+pprStringInCStyle :: String -> SDoc
+pprStringInCStyle s = doubleQuotes (text (concatMap charToC s))
+
+charToC :: Char -> String
+charToC '\"' = "\\\""
+charToC '\'' = "\\\'"
+charToC '\\' = "\\\\"
+charToC c | c >= ' ' && c <= '~' = [c]
+          | c > '\xFF' = panic ("charToC "++show 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 -> SDoc
+pprHexVal 0 = ptext SLIT("0x0")
+pprHexVal w 
+  | w < 0     = parens (char '-' <> ptext SLIT("0x") <> go (-w))
+  | otherwise = ptext SLIT("0x") <> go w
+  where
+      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/ghc/compiler/cmm/PprCmm.hs b/ghc/compiler/cmm/PprCmm.hs
new file mode 100644 (file)
index 0000000..fb1dec1
--- /dev/null
@@ -0,0 +1,460 @@
+----------------------------------------------------------------------------
+--
+-- 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 )
+
+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 ... ; }
+--
+-- N.B. we remove 'Nothing's from the list of branches, as they don't
+-- seem to make sense currently. This may change, if they are defined in
+-- some way.
+--
+genSwitch :: CmmExpr -> [Maybe BlockId] -> SDoc
+genSwitch expr maybe_ids 
+
+    = let ids   = [ i | Just i <- maybe_ids ]
+          pairs = groupBy snds (zip [0 .. ] ids )
+
+      in hang (hcat [ ptext SLIT("switch [0 .. ") 
+                    , int (length 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,BlockId)] -> SDoc
+      caseify as 
+        = let (is,ids) = unzip as 
+          in hsep [ ptext SLIT("case")
+                  , hcat (punctuate comma (map int is))
+                  , ptext SLIT(": goto")
+                  , pprBlockId (head 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
+       CmmMachOp mop args  -> genMachOp mop args
+       e                   -> parens (pprExpr e)
+
+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 :)
+           MO_Not    _ -> Just $ char '~'
+            _ -> 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
+
+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 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")
+
+        _ -> panic $ "PprCmm.pprGlobalReg: unknown global reg"
+
+-- --------------------------------------------------------------------------
+-- 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"))
+    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
+
index b195b5c..0f85877 100644 (file)
@@ -8,49 +8,49 @@ module CgBindery (
        CgBindings, CgIdInfo,
        StableLoc, VolatileLoc,
 
-       stableAmodeIdInfo, heapIdInfo, 
+       cgIdInfoId, cgIdInfoArgRep, cgIdInfoLF,
+
+       stableIdInfo, heapIdInfo, 
        letNoEscapeIdInfo, idInfoToAmode,
 
        addBindC, addBindsC,
 
        nukeVolatileBinds,
        nukeDeadBindings,
+       getLiveStackSlots,
 
-       bindNewToStack,  rebindToStack,
+       bindArgsToStack,  rebindToStack,
        bindNewToNode, bindNewToReg, bindArgsToRegs,
        bindNewToTemp, 
-       getArgAmode, getArgAmodes,
-       getCAddrModeAndInfo, getCAddrMode,
+       getArgAmode, getArgAmodes, 
+       getCgIdInfo, 
        getCAddrModeIfVolatile, getVolatileRegs,
-
-       buildContLivenessMask
+       maybeLetNoEscape, 
     ) where
 
 #include "HsVersions.h"
 
-import AbsCSyn
 import CgMonad
-
-import CgUsages                ( getHpRelOffset, getSpRelOffset, getRealSp )
-import CgStackery      ( freeStackSlots, getStackFrame )
-import CLabel          ( mkClosureLabel,
-                         mkBitmapLabel, pprCLabel )
+import CgHeapery       ( getHpRelOffset )
+import CgStackery      ( freeStackSlots, getSpRelOffset )
+import CgUtils         ( cgLit, cmmOffsetW )
+import CLabel          ( mkClosureLabel, pprCLabel )
 import ClosureInfo     ( mkLFImported, mkLFArgument, LambdaFormInfo )
-import Bitmap
-import PrimRep         ( isFollowableRep, getPrimRepSize )
-import Id              ( Id, idPrimRep, idType )
-import Type            ( typePrimRep )
+
+import Cmm
+import PprCmm          ( {- instance Outputable -} )
+import SMRep           ( CgRep(..), WordOff, isFollowableArg, 
+                         isVoidArg, cgRepSizeW, argMachRep, 
+                         idCgRep, typeCgRep )
+import Id              ( Id, idName )
 import VarEnv
 import VarSet          ( varSetElems )
-import Literal         ( Literal )
-import Maybes          ( catMaybes, maybeToBool, seqMaybe )
-import Name            ( isInternalName, NamedThing(..) )
-import PprAbsC         ( pprAmode, pprMagicId )
-import PrimRep          ( PrimRep(..) )
+import Literal         ( literalType )
+import Maybes          ( catMaybes )
+import Name            ( isExternalName )
 import StgSyn          ( StgArg, StgLiveVars, GenStgArg(..), isStgTypeArg )
-import Unique           ( Unique, Uniquable(..) )
+import Unique           ( Uniquable(..) )
 import UniqSet         ( elementOfUniqSet )
-import Util            ( zipWithEqual, sortLt )
 import Outputable
 \end{code}
 
@@ -73,22 +73,30 @@ environment.  So there can be two bindings for a given name.
 type CgBindings = IdEnv CgIdInfo
 
 data CgIdInfo
-  = MkCgIdInfo Id      -- Id that this is the info for
-               VolatileLoc
-               StableLoc
-               LambdaFormInfo
+  = CgIdInfo   
+       { cg_id :: Id   -- Id that this is the info for
+                       -- Can differ from the Id at occurrence sites by 
+                       -- virtue of being externalised, for splittable C
+       , cg_rep :: CgRep
+       , cg_vol :: VolatileLoc
+       , cg_stb :: StableLoc
+       , cg_lf  :: LambdaFormInfo }
+
+mkCgIdInfo id vol stb lf
+  = CgIdInfo { cg_id = id, cg_vol = vol, cg_stb = stb, 
+              cg_lf = lf, cg_rep = idCgRep id }
+
+voidIdInfo id = CgIdInfo { cg_id = id, cg_vol = NoVolatileLoc
+                        , cg_stb = VoidLoc, cg_lf = mkLFArgument id
+                        , cg_rep = VoidArg }
+       -- Used just for VoidRep things
 
 data VolatileLoc
   = NoVolatileLoc
-  | TempVarLoc Unique
-
-  | RegLoc     MagicId                 -- in one of the magic registers
-                                       -- (probably {Int,Float,Char,etc}Reg)
-
-  | VirHpLoc   VirtualHeapOffset       -- Hp+offset (address of closure)
-
-  | VirNodeLoc VirtualHeapOffset       -- Cts of offset indirect from Node
-                                       -- ie *(Node+offset)
+  | RegLoc     CmmReg             -- In one of the registers (global or local)
+  | VirHpLoc   VirtualHpOffset  -- Hp+offset (address of closure)
+  | VirNodeLoc VirtualHpOffset  -- Cts of offset indirect from Node
+                                  -- ie *(Node+offset)
 \end{code}
 
 @StableLoc@ encodes where an Id can be found, used by
@@ -97,33 +105,37 @@ the @CgBindings@ environment in @CgBindery@.
 \begin{code}
 data StableLoc
   = NoStableLoc
-  | VirStkLoc          VirtualSpOffset
-  | LitLoc             Literal
-  | StableAmodeLoc     CAddrMode
 
--- these are so StableLoc can be abstract:
+  | VirStkLoc  VirtualSpOffset         -- The thing is held in this
+                                       -- stack slot
 
-maybeStkLoc (VirStkLoc offset) = Just offset
-maybeStkLoc _                 = Nothing
+  | VirStkLNE  VirtualSpOffset         -- A let-no-escape thing; the
+                                       -- value is this stack pointer
+                                       -- (as opposed to the contents of the slot)
+
+  | StableLoc  CmmExpr
+  | VoidLoc    -- Used only for VoidRep variables.  They never need to
+               -- be saved, so it makes sense to treat treat them as
+               -- having a stable location
 \end{code}
 
 \begin{code}
 instance Outputable CgIdInfo where
-  ppr (MkCgIdInfo id vol stb lf)
+  ppr (CgIdInfo id rep vol stb lf)
     = ppr id <+> ptext SLIT("-->") <+> vcat [ppr vol, ppr stb]
 
 instance Outputable VolatileLoc where
   ppr NoVolatileLoc = empty
-  ppr (TempVarLoc u) = ptext SLIT("tmp") <+> ppr u
-  ppr (RegLoc r)     = ptext SLIT("reg") <+> pprMagicId r
-  ppr (VirHpLoc v)   = ptext SLIT("vh") <+> ppr v
-  ppr (VirNodeLoc v) = ptext SLIT("vn") <+> ppr v
+  ppr (RegLoc r)     = ptext SLIT("reg") <+> ppr r
+  ppr (VirHpLoc v)   = ptext SLIT("vh")  <+> ppr v
+  ppr (VirNodeLoc v) = ptext SLIT("vn")  <+> ppr v
 
 instance Outputable StableLoc where
-  ppr NoStableLoc       = empty
-  ppr (VirStkLoc v)     = ptext SLIT("vs") <+> ppr v
-  ppr (LitLoc l)        = ptext SLIT("lit") <+> ppr l
-  ppr (StableAmodeLoc a) = ptext SLIT("amode") <+> pprAmode a
+  ppr NoStableLoc   = empty
+  ppr VoidLoc       = ptext SLIT("void")
+  ppr (VirStkLoc v) = ptext SLIT("vs")    <+> ppr v
+  ppr (VirStkLNE v) = ptext SLIT("lne")    <+> ppr v
+  ppr (StableLoc a) = ptext SLIT("amode") <+> ppr a
 \end{code}
 
 %************************************************************************
@@ -133,41 +145,49 @@ instance Outputable StableLoc where
 %************************************************************************
 
 \begin{code}
-stableAmodeIdInfo i amode lf_info = MkCgIdInfo i NoVolatileLoc (StableAmodeLoc amode) lf_info
-heapIdInfo i offset       lf_info = MkCgIdInfo i (VirHpLoc offset) NoStableLoc lf_info
-tempIdInfo i uniq         lf_info = MkCgIdInfo i (TempVarLoc uniq) NoStableLoc lf_info
-
-letNoEscapeIdInfo i sp lf_info
-  = MkCgIdInfo i NoVolatileLoc (StableAmodeLoc (CJoinPoint sp)) lf_info
-
-idInfoToAmode :: PrimRep -> CgIdInfo -> FCode CAddrMode
-idInfoToAmode kind (MkCgIdInfo _ vol stab _) = idInfoPiecesToAmode kind vol stab
-
-idInfoPiecesToAmode :: PrimRep -> VolatileLoc -> StableLoc -> FCode CAddrMode
-
-idInfoPiecesToAmode kind (TempVarLoc uniq) stable_loc   = returnFC (CTemp uniq kind)
-idInfoPiecesToAmode kind (RegLoc magic_id) stable_loc   = returnFC (CReg magic_id)
-
-idInfoPiecesToAmode kind NoVolatileLoc (LitLoc lit)           = returnFC (CLit lit)
-idInfoPiecesToAmode kind NoVolatileLoc (StableAmodeLoc amode) = returnFC amode
+stableIdInfo id amode   lf_info = mkCgIdInfo id NoVolatileLoc (StableLoc amode) lf_info
+heapIdInfo id offset    lf_info = mkCgIdInfo id (VirHpLoc offset) NoStableLoc lf_info
+letNoEscapeIdInfo id sp lf_info = mkCgIdInfo id NoVolatileLoc (VirStkLNE sp) lf_info
+stackIdInfo id sp      lf_info = mkCgIdInfo id NoVolatileLoc (VirStkLoc sp) lf_info
+nodeIdInfo id offset    lf_info = mkCgIdInfo id (VirNodeLoc offset) NoStableLoc lf_info
+regIdInfo id reg        lf_info = mkCgIdInfo id (RegLoc reg) NoStableLoc lf_info
+
+idInfoToAmode :: CgIdInfo -> FCode CmmExpr
+idInfoToAmode info
+  = case cg_vol info of {
+      RegLoc reg       -> returnFC (CmmReg reg) ;
+      VirNodeLoc nd_off -> returnFC (CmmLoad (cmmOffsetW (CmmReg nodeReg) nd_off) mach_rep) ;
+      VirHpLoc hp_off   -> getHpRelOffset hp_off ;
+      NoVolatileLoc -> 
+
+    case cg_stb info of
+      StableLoc amode  -> returnFC amode
+      VirStkLoc sp_off -> do { sp_rel <- getSpRelOffset sp_off
+                            ; return (CmmLoad sp_rel mach_rep) }
+
+      VirStkLNE sp_off -> getSpRelOffset sp_off ;
+
+      VoidLoc -> return $ pprPanic "idInfoToAmode: void" (ppr (cg_id info))
+               -- We return a 'bottom' amode, rather than panicing now
+               -- In this way getArgAmode returns a pair of (VoidArg, bottom)
+               -- and that's exactly what we want
+
+      NoStableLoc -> pprPanic "idInfoToAmode: no loc" (ppr (cg_id info))
+    }
+  where
+    mach_rep = argMachRep (cg_rep info)
 
-idInfoPiecesToAmode kind (VirNodeLoc nd_off) stable_loc
-  = returnFC (CVal (nodeRel nd_off) kind)
-    -- Virtual offsets from Node increase into the closures,
-    -- and so do Node-relative offsets (which we want in the CVal),
-    -- so there is no mucking about to do to the offset.
+cgIdInfoId :: CgIdInfo -> Id
+cgIdInfoId = cg_id 
 
-idInfoPiecesToAmode kind (VirHpLoc hp_off) stable_loc
-  = getHpRelOffset hp_off `thenFC` \ rel_hp ->
-    returnFC (CAddr rel_hp)
+cgIdInfoLF :: CgIdInfo -> LambdaFormInfo
+cgIdInfoLF = cg_lf
 
-idInfoPiecesToAmode kind NoVolatileLoc (VirStkLoc i)
-  = getSpRelOffset i `thenFC` \ rel_sp ->
-    returnFC (CVal rel_sp kind)
+cgIdInfoArgRep :: CgIdInfo -> CgRep
+cgIdInfoArgRep = cg_rep
 
-#ifdef DEBUG
-idInfoPiecesToAmode kind NoVolatileLoc NoStableLoc = panic "idInfoPiecesToAmode: no loc"
-#endif
+maybeLetNoEscape (CgIdInfo { cg_stb = VirStkLNE sp_off }) = Just sp_off
+maybeLetNoEscape other                                   = Nothing
 \end{code}
 
 %************************************************************************
@@ -176,8 +196,8 @@ idInfoPiecesToAmode kind NoVolatileLoc NoStableLoc = panic "idInfoPiecesToAmode:
 %*                                                                     *
 %************************************************************************
 
-There are three basic routines, for adding (@addBindC@), modifying
-(@modifyBindC@) and looking up (@lookupBindC@) bindings.
+.There are three basic routines, for adding (@addBindC@), modifying
+(@modifyBindC@) and looking up (@getCgIdInfo@) bindings.
 
 A @Id@ is bound to a @(VolatileLoc, StableLoc)@ triple.
 The name should not already be bound. (nice ASSERT, eh?)
@@ -192,8 +212,8 @@ addBindsC :: [(Id, CgIdInfo)] -> Code
 addBindsC new_bindings = do
        binds <- getBinds
        let new_binds = foldl (\ binds (name,info) -> extendVarEnv binds name info)
-               binds
-               new_bindings
+                             binds
+                             new_bindings
        setBinds new_binds
 
 modifyBindC :: Id -> (CgIdInfo -> CgIdInfo) -> Code
@@ -201,19 +221,34 @@ modifyBindC name mangle_fn = do
        binds <- getBinds
        setBinds $ modifyVarEnv mangle_fn binds name
 
-lookupBindC :: Id -> FCode CgIdInfo
-lookupBindC id = do maybe_info <- lookupBindC_maybe id
-                   case maybe_info of
-                     Just info -> return info
-                     Nothing   -> cgLookupPanic id
-
-lookupBindC_maybe :: Id -> FCode (Maybe CgIdInfo)
-lookupBindC_maybe id
-  = do static_binds <- getStaticBinds
-       local_binds  <- getBinds
-       return (lookupVarEnv local_binds id
-                       `seqMaybe`
-               lookupVarEnv static_binds id)
+getCgIdInfo :: Id -> FCode CgIdInfo
+getCgIdInfo id
+  = do {       -- Try local bindings first
+       ; local_binds  <- getBinds
+       ; case lookupVarEnv local_binds id of {
+           Just info -> return info ;
+           Nothing   -> do
+
+       {       -- Try top-level bindings
+         static_binds <- getStaticBinds
+       ; case lookupVarEnv static_binds id of {
+           Just info -> return info ;
+           Nothing   ->
+
+               -- Should be imported; make up a CgIdInfo for it
+       if isExternalName name then
+           return (stableIdInfo id ext_lbl (mkLFImported id))
+       else
+       if isVoidArg (idCgRep id) then
+               -- Void things are never in the environment
+           return (voidIdInfo id)
+       else
+       -- Bug  
+       cgLookupPanic id
+       }}}}
+  where
+    name    = idName id
+    ext_lbl = CmmLit (CmmLabel (mkClosureLabel name))
                        
 cgLookupPanic :: Id -> FCode a
 cgLookupPanic id
@@ -223,9 +258,9 @@ cgLookupPanic id
        pprPanic "cgPanic"
                (vcat [ppr id,
                ptext SLIT("static binds for:"),
-               vcat [ ppr i | (MkCgIdInfo i _ _ _) <- rngVarEnv static_binds ],
+               vcat [ ppr (cg_id info) | info <- rngVarEnv static_binds ],
                ptext SLIT("local binds for:"),
-               vcat [ ppr i | (MkCgIdInfo i _ _ _) <- rngVarEnv local_binds ],
+               vcat [ ppr (cg_id info) | info <- rngVarEnv local_binds ],
                ptext SLIT("SRT label") <+> pprCLabel srt
              ])
 \end{code}
@@ -244,9 +279,9 @@ nukeVolatileBinds :: CgBindings -> CgBindings
 nukeVolatileBinds binds
   = mkVarEnv (foldr keep_if_stable [] (rngVarEnv binds))
   where
-    keep_if_stable (MkCgIdInfo i _ NoStableLoc entry_info) acc = acc
-    keep_if_stable (MkCgIdInfo i _ stable_loc  entry_info) acc
-      = (i, MkCgIdInfo i NoVolatileLoc stable_loc entry_info) : acc
+    keep_if_stable (CgIdInfo { cg_stb = NoStableLoc }) acc = acc
+    keep_if_stable info acc
+      = (cg_id info, info { cg_vol = NoVolatileLoc }) : acc
 \end{code}
 
 
@@ -256,46 +291,15 @@ nukeVolatileBinds binds
 %*                                                                     *
 %************************************************************************
 
-I {\em think} all looking-up is done through @getCAddrMode(s)@.
-
 \begin{code}
-getCAddrModeAndInfo :: Id -> FCode (Id, CAddrMode, LambdaFormInfo)
-
-getCAddrModeAndInfo id
-  = do
-       maybe_cg_id_info <- lookupBindC_maybe id
-       case maybe_cg_id_info of
-
-               -- Nothing => not in the environment, so should be imported
-         Nothing | isInternalName name -> cgLookupPanic id
-                 | otherwise        -> returnFC (id, global_amode, mkLFImported id)
-
-         Just (MkCgIdInfo id' volatile_loc stable_loc lf_info)
-                 -> do amode <- idInfoPiecesToAmode kind volatile_loc stable_loc
-                       return (id', amode, lf_info)
-  where
-    name = getName id
-    global_amode = CLbl (mkClosureLabel name) kind
-    kind = idPrimRep id
-
-getCAddrMode :: Id -> FCode CAddrMode
-getCAddrMode name = do
-       (_, amode, _) <- getCAddrModeAndInfo name
-       return amode
-\end{code}
-
-\begin{code}
-getCAddrModeIfVolatile :: Id -> FCode (Maybe CAddrMode)
-getCAddrModeIfVolatile name
---  | toplevelishId name = returnFC Nothing
---  | otherwise
-       = do
-       (MkCgIdInfo _ volatile_loc stable_loc lf_info) <- lookupBindC name
-       case stable_loc of
+getCAddrModeIfVolatile :: Id -> FCode (Maybe CmmExpr)
+getCAddrModeIfVolatile id
+  = do { info <- getCgIdInfo id
+       ; case cg_stb info of
                NoStableLoc -> do -- Aha!  So it is volatile!
-                       amode <- idInfoPiecesToAmode (idPrimRep name) volatile_loc NoStableLoc
+                       amode <- idInfoToAmode info
                        return $ Just amode
-               a_stable_loc -> return Nothing
+               a_stable_loc -> return Nothing }
 \end{code}
 
 @getVolatileRegs@ gets a set of live variables, and returns a list of
@@ -306,56 +310,57 @@ stable one (notably, on the stack), we modify the current bindings to
 forget the volatile one.
 
 \begin{code}
-getVolatileRegs :: StgLiveVars -> FCode [MagicId]
+getVolatileRegs :: StgLiveVars -> FCode [GlobalReg]
 
 getVolatileRegs vars = do
-       stuff <- mapFCs snaffle_it (varSetElems vars)
-       returnFC $ catMaybes stuff
-       where
-       snaffle_it var = do
-               (MkCgIdInfo _ volatile_loc stable_loc lf_info) <- lookupBindC var 
-               let
+  do   { stuff <- mapFCs snaffle_it (varSetElems vars)
+       ; returnFC $ catMaybes stuff }
+  where
+    snaffle_it var = do
+       { info <- getCgIdInfo var 
+       ; let
                -- commoned-up code...
-                       consider_reg reg =
-                               if not (isVolatileReg reg) then
-                               -- Potentially dies across C calls
-                               -- For now, that's everything; we leave
-                               -- it to the save-macros to decide which
-                               -- regs *really* need to be saved.
-                                       returnFC Nothing
-                               else
-                                       case stable_loc of
-                                               NoStableLoc -> returnFC (Just reg) -- got one!
-                                               is_a_stable_loc -> do
-                                                       -- has both volatile & stable locations;
-                                                       -- force it to rely on the stable location
-                                                       modifyBindC var nuke_vol_bind 
-                                                       return Nothing
-                       in
-                       case volatile_loc of
-                               RegLoc reg   -> consider_reg reg
-                               VirNodeLoc _ -> consider_reg node
-                               non_reg_loc  -> returnFC Nothing
-
-       nuke_vol_bind (MkCgIdInfo i _ stable_loc lf_info)
-               = MkCgIdInfo i NoVolatileLoc stable_loc lf_info
+            consider_reg reg
+               =       -- We assume that all regs can die across C calls
+                       -- We leave it to the save-macros to decide which
+                       -- regs *really* need to be saved.
+                 case cg_stb info of
+                       NoStableLoc     -> returnFC (Just reg) -- got one!
+                       is_a_stable_loc -> do
+                               { -- has both volatile & stable locations;
+                                 -- force it to rely on the stable location
+                                 modifyBindC var nuke_vol_bind 
+                               ; return Nothing }
+
+       ; case cg_vol info of
+           RegLoc (CmmGlobal reg) -> consider_reg reg
+           VirNodeLoc _           -> consider_reg node
+           other_loc              -> returnFC Nothing  -- Local registers
+       }
+
+    nuke_vol_bind info = info { cg_vol = NoVolatileLoc }
 \end{code}
 
 \begin{code}
-getArgAmodes :: [StgArg] -> FCode [CAddrMode]
-getArgAmodes [] = returnFC []
-getArgAmodes (atom:atoms)
-       | isStgTypeArg atom 
-       = getArgAmodes atoms
-       | otherwise = do
-               amode <- getArgAmode  atom 
-               amodes <- getArgAmodes atoms
-               return ( amode : amodes )
+getArgAmode :: StgArg -> FCode (CgRep, CmmExpr)
+getArgAmode (StgVarArg var) 
+  = do { info <- getCgIdInfo var
+       ; amode <- idInfoToAmode info
+       ; return (cgIdInfoArgRep info, amode ) }
 
-getArgAmode :: StgArg -> FCode CAddrMode
+getArgAmode (StgLitArg lit) 
+  = do { cmm_lit <- cgLit lit
+       ; return (typeCgRep (literalType lit), CmmLit cmm_lit) }
 
-getArgAmode (StgVarArg var) = getCAddrMode var         -- The common case
-getArgAmode (StgLitArg lit) = returnFC (CLit lit)
+getArgAmode (StgTypeArg _) = panic "getArgAmode: type arg"
+
+getArgAmodes :: [StgArg] -> FCode [(CgRep, CmmExpr)]
+getArgAmodes [] = returnFC []
+getArgAmodes (atom:atoms)
+  | isStgTypeArg atom = getArgAmodes atoms
+  | otherwise        = do { amode  <- getArgAmode  atom 
+                          ; amodes <- getArgAmodes atoms
+                          ; return ( amode : amodes ) }
 \end{code}
 
 %************************************************************************
@@ -365,43 +370,40 @@ getArgAmode (StgLitArg lit) = returnFC (CLit lit)
 %************************************************************************
 
 \begin{code}
-bindNewToStack :: (Id, VirtualSpOffset) -> Code
-bindNewToStack (name, offset)
-  = addBindC name info
+bindArgsToStack :: [(Id, VirtualSpOffset)] -> Code
+bindArgsToStack args
+  = mapCs bind args
   where
-    info = MkCgIdInfo name NoVolatileLoc (VirStkLoc offset) (mkLFArgument name)
+    bind(id, offset) = addBindC id (stackIdInfo id offset (mkLFArgument id))
 
-bindNewToNode :: Id -> VirtualHeapOffset -> LambdaFormInfo -> Code
-bindNewToNode name offset lf_info
-  = addBindC name info
+bindArgsToRegs :: [(Id, GlobalReg)] -> Code
+bindArgsToRegs args
+  = mapCs bind args
   where
-    info = MkCgIdInfo name (VirNodeLoc offset) NoStableLoc lf_info
+    bind (arg, reg) = bindNewToReg arg (CmmGlobal reg) (mkLFArgument arg)
+
+bindNewToNode :: Id -> VirtualHpOffset -> LambdaFormInfo -> Code
+bindNewToNode id offset lf_info
+  = addBindC id (nodeIdInfo id offset lf_info)
 
 -- Create a new temporary whose unique is that in the id,
 -- bind the id to it, and return the addressing mode for the
 -- temporary.
-bindNewToTemp :: Id -> FCode CAddrMode
+bindNewToTemp :: Id -> FCode CmmReg
 bindNewToTemp id
-  = do addBindC id id_info
-       return temp_amode
-  where
-    uniq       = getUnique id
-    temp_amode = CTemp uniq (idPrimRep id)
-    id_info    = tempIdInfo id uniq lf_info
-    lf_info    = mkLFArgument id       -- Always used of things we
-                                       -- know nothing about
-
-bindNewToReg :: Id -> MagicId -> LambdaFormInfo -> Code
-bindNewToReg name magic_id lf_info
-  = addBindC name info
+  = do addBindC id (regIdInfo id temp_reg lf_info)
+       return temp_reg
   where
-    info = MkCgIdInfo name (RegLoc magic_id) NoStableLoc lf_info
+    uniq     = getUnique id
+    temp_reg = CmmLocal (LocalReg uniq (argMachRep (idCgRep id)))
+    lf_info  = mkLFArgument id -- Always used of things we
+                               -- know nothing about
 
-bindArgsToRegs :: [Id] -> [MagicId] -> Code
-bindArgsToRegs args regs
-  = listCs (zipWithEqual "bindArgsToRegs" bind args regs)
+bindNewToReg :: Id -> CmmReg -> LambdaFormInfo -> Code
+bindNewToReg name reg lf_info
+  = addBindC name info
   where
-    arg `bind` reg = bindNewToReg arg reg (mkLFArgument arg)
+    info = mkCgIdInfo name (RegLoc reg) NoStableLoc lf_info
 \end{code}
 
 \begin{code}
@@ -409,69 +411,7 @@ rebindToStack :: Id -> VirtualSpOffset -> Code
 rebindToStack name offset
   = modifyBindC name replace_stable_fn
   where
-    replace_stable_fn (MkCgIdInfo i vol stab einfo)
-      = MkCgIdInfo i vol (VirStkLoc offset) einfo
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[CgBindery-liveness]{Build a liveness mask for the current stack}
-%*                                                                     *
-%************************************************************************
-
-There are four kinds of things on the stack:
-
-       - pointer variables (bound in the environment)
-       - non-pointer variables (boudn in the environment)
-       - free slots (recorded in the stack free list)
-       - non-pointer data slots (recorded in the stack free list)
-
-We build up a bitmap of non-pointer slots by searching the environment
-for all the pointer variables, and subtracting these from a bitmap
-with initially all bits set (up to the size of the stack frame).
-
-\begin{code}
-buildLivenessMask 
-       :: VirtualSpOffset      -- size of the stack frame
-       -> VirtualSpOffset      -- offset from which the bitmap should start
-       -> FCode Bitmap         -- mask for free/unlifted slots
-
-buildLivenessMask size sp = do {
-    -- find all live stack-resident pointers
-    binds <- getBinds;
-    ((vsp, _, free, _, _), heap_usage) <- getUsage;
-
-    let {
-       rel_slots = sortLt (<) 
-           [ sp - ofs  -- get slots relative to top of frame
-           | (MkCgIdInfo id _ (VirStkLoc ofs) _) <- rngVarEnv binds,
-             isFollowableRep (idPrimRep id)
-           ];
-    };
-
-    WARN( not (all (>=0) rel_slots), ppr size $$ ppr sp $$ ppr rel_slots $$ ppr binds )
-    return (intsToReverseBitmap size rel_slots)
-  }
-
--- In a continuation, we want a liveness mask that starts from just after
--- the return address, which is on the stack at realSp.
-
-buildContLivenessMask :: Id -> FCode Liveness
-       -- The Id is used just for its unique to make a label
-buildContLivenessMask id = do
-       realSp <- getRealSp
-
-       frame_sp <- getStackFrame
-       -- realSp points to the frame-header for the current stack frame,
-       -- and the end of this frame is frame_sp.  The size is therefore
-       -- realSp - frame_sp - 1 (subtract one for the frame-header).
-       let frame_size = realSp - frame_sp - 1
-
-       mask <- buildLivenessMask frame_size (realSp-1)
-
-        let liveness = Liveness (mkBitmapLabel (getName id)) frame_size mask
-       absC (maybeLargeBitmap liveness)
-       return liveness
+    replace_stable_fn info = info { cg_stb = VirStkLoc offset }
 \end{code}
 
 %************************************************************************
@@ -503,7 +443,7 @@ nukeDeadBindings live_vars = do
        let (dead_stk_slots, bs') =
                dead_slots live_vars 
                        [] []
-                       [ (i, b) | b@(MkCgIdInfo i _ _ _) <- rngVarEnv binds ]
+                       [ (cg_id b, b) | b <- rngVarEnv binds ]
        setBinds $ mkVarEnv bs'
        freeStackSlots dead_stk_slots
 \end{code}
@@ -529,19 +469,23 @@ dead_slots live_vars fbs ds ((v,i):bs)
          -- Instead keep it in the filtered bindings
 
   | otherwise
-    = case i of
-       MkCgIdInfo _ _ stable_loc _
-        | is_stk_loc && size > 0 ->
-          dead_slots live_vars fbs ([offset-size+1 .. offset] ++ ds) bs
-        where
-         maybe_stk_loc = maybeStkLoc stable_loc
-         is_stk_loc    = maybeToBool maybe_stk_loc
-         (Just offset) = maybe_stk_loc
+    = case cg_stb i of
+       VirStkLoc offset
+        | size > 0
+        -> dead_slots live_vars fbs ([offset-size+1 .. offset] ++ ds) bs
 
        _ -> dead_slots live_vars fbs ds bs
   where
+    size :: WordOff
+    size = cgRepSizeW (cg_rep i)
+\end{code}
 
-    size :: Int
-    size = (getPrimRepSize . typePrimRep . idType) v
-
+\begin{code}
+getLiveStackSlots :: FCode [VirtualSpOffset]
+-- Return the offsets of slots in stack containig live pointers
+getLiveStackSlots 
+  = do         { binds <- getBinds
+       ; return [off | CgIdInfo { cg_stb = VirStkLoc off, 
+                                  cg_rep = rep } <- rngVarEnv binds, 
+                       isFollowableArg rep] }
 \end{code}
diff --git a/ghc/compiler/codeGen/CgCallConv.hs b/ghc/compiler/codeGen/CgCallConv.hs
new file mode 100644 (file)
index 0000000..fa98f96
--- /dev/null
@@ -0,0 +1,507 @@
+-----------------------------------------------------------------------------
+--
+--             CgCallConv
+--
+-- The datatypes and functions here encapsulate the 
+-- calling and return conventions used by the code generator.
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+
+module CgCallConv (
+       -- Argument descriptors
+       mkArgDescr, argDescrType,
+
+       -- Liveness
+       isBigLiveness, buildContLiveness, mkRegLiveness, 
+       smallLiveness, mkLivenessCLit,
+
+       -- Register assignment
+       assignCallRegs, assignReturnRegs, assignPrimOpCallRegs,
+
+       -- Calls
+       constructSlowCall, slowArgs, slowCallPattern,
+
+       -- Returns
+       CtrlReturnConvention(..),
+       ctrlReturnConvAlg,
+       dataReturnConvPrim,
+       getSequelAmode
+    ) where
+
+#include "HsVersions.h"
+
+import CgUtils         ( emitRODataLits, mkWordCLit )
+import CgMonad
+
+import Constants       ( mAX_FAMILY_SIZE_FOR_VEC_RETURNS,
+                         mAX_Vanilla_REG, mAX_Float_REG,
+                         mAX_Double_REG, mAX_Long_REG,
+                         mAX_Real_Vanilla_REG, mAX_Real_Float_REG,
+                         mAX_Real_Double_REG, mAX_Real_Long_REG,
+                         bITMAP_BITS_SHIFT
+                       )
+
+import ClosureInfo     ( ArgDescr(..), Liveness(..) )
+import CgStackery      ( getSpRelOffset )
+import SMRep
+import MachOp          ( wordRep )
+import Cmm             ( CmmExpr(..), GlobalReg(..), CmmLit(..), CmmReg(..), node )
+import CmmUtils                ( mkLblExpr )
+import CLabel
+import Maybes          ( mapCatMaybes )
+import Id              ( Id )
+import Name            ( Name )
+import TyCon           ( TyCon, tyConFamilySize )
+import Bitmap          ( Bitmap, mAX_SMALL_BITMAP_SIZE, 
+                         mkBitmap, intsToReverseBitmap )
+import Util            ( isn'tIn, sortLt )
+import CmdLineOpts     ( opt_Unregisterised )
+import FastString      ( LitString )
+import Outputable
+import DATA_BITS
+
+
+-------------------------------------------------------------------------
+--
+--     Making argument descriptors
+--
+--  An argument descriptor describes the layout of args on the stack,
+--  both for   * GC (stack-layout) purposes, and 
+--             * saving/restoring registers when a heap-check fails
+--
+-- Void arguments aren't important, therefore (contrast constructSlowCall)
+--
+-------------------------------------------------------------------------
+
+-- bring in ARG_P, ARG_N, etc.
+#include "../includes/StgFun.h"
+
+-------------------------
+argDescrType :: ArgDescr -> Int
+-- The "argument type" RTS field type
+argDescrType (ArgSpec n) = n
+argDescrType (ArgGen liveness)
+  | isBigLiveness liveness = ARG_GEN_BIG
+  | otherwise             = ARG_GEN
+
+
+mkArgDescr :: Name -> [Id] -> FCode ArgDescr
+mkArgDescr nm args 
+  = case stdPattern arg_reps of
+       Just spec_id -> return (ArgSpec spec_id)
+       Nothing      -> do { liveness <- mkLiveness nm size bitmap
+                          ; return (ArgGen liveness) }
+  where
+    arg_reps = filter nonVoidArg (map idCgRep args)
+       -- Getting rid of voids eases matching of standard patterns
+
+    bitmap   = mkBitmap arg_bits
+    arg_bits = argBits arg_reps
+    size     = length arg_bits
+
+argBits :: [CgRep] -> [Bool]   -- True for non-ptr, False for ptr
+argBits []             = []
+argBits (PtrArg : args) = False : argBits args
+argBits (arg    : args) = take (cgRepSizeW arg) (repeat True) ++ argBits args
+
+stdPattern :: [CgRep] -> Maybe Int
+stdPattern [PtrArg]    = Just ARG_P
+stdPattern [FloatArg]  = Just ARG_F
+stdPattern [DoubleArg] = Just ARG_D
+stdPattern [LongArg]   = Just ARG_L
+stdPattern [NonPtrArg] = Just ARG_N
+        
+stdPattern [NonPtrArg,NonPtrArg] = Just ARG_NN
+stdPattern [NonPtrArg,PtrArg]    = Just ARG_NP
+stdPattern [PtrArg,NonPtrArg]    = Just ARG_PN
+stdPattern [PtrArg,PtrArg]       = Just ARG_PP
+
+stdPattern [NonPtrArg,NonPtrArg,NonPtrArg] = Just ARG_NNN
+stdPattern [NonPtrArg,NonPtrArg,PtrArg]    = Just ARG_NNP
+stdPattern [NonPtrArg,PtrArg,NonPtrArg]    = Just ARG_NPN
+stdPattern [NonPtrArg,PtrArg,PtrArg]      = Just ARG_NPP
+stdPattern [PtrArg,NonPtrArg,NonPtrArg]    = Just ARG_PNN
+stdPattern [PtrArg,NonPtrArg,PtrArg]      = Just ARG_PNP
+stdPattern [PtrArg,PtrArg,NonPtrArg]      = Just ARG_PPN
+stdPattern [PtrArg,PtrArg,PtrArg]         = Just ARG_PPP
+        
+stdPattern [PtrArg,PtrArg,PtrArg,PtrArg]              = Just ARG_PPPP
+stdPattern [PtrArg,PtrArg,PtrArg,PtrArg,PtrArg]        = Just ARG_PPPPP
+stdPattern [PtrArg,PtrArg,PtrArg,PtrArg,PtrArg,PtrArg] = Just ARG_PPPPPP
+stdPattern other = Nothing
+
+
+-------------------------------------------------------------------------
+--
+--     Liveness info
+--
+-------------------------------------------------------------------------
+
+mkLiveness :: Name -> Int -> Bitmap -> FCode Liveness
+mkLiveness name size bits
+  | size > mAX_SMALL_BITMAP_SIZE               -- Bitmap does not fit in one word
+  = do { let lbl = mkBitmapLabel name
+       ; emitRODataLits lbl ( mkWordCLit (fromIntegral size)
+                            : map mkWordCLit bits)
+       ; return (BigLiveness lbl) }
+  
+  | otherwise          -- Bitmap fits in one word
+  = let
+        small_bits = case bits of 
+                       []  -> 0
+                       [b] -> fromIntegral b
+                       _   -> panic "livenessToAddrMode"
+    in
+    return (smallLiveness size small_bits)
+
+smallLiveness :: Int -> StgWord -> Liveness
+smallLiveness size small_bits = SmallLiveness bits
+  where bits = fromIntegral size .|. (small_bits `shiftL` bITMAP_BITS_SHIFT)
+
+-------------------
+isBigLiveness :: Liveness -> Bool
+isBigLiveness (BigLiveness _)   = True
+isBigLiveness (SmallLiveness _) = False
+
+-------------------
+mkLivenessCLit :: Liveness -> CmmLit
+mkLivenessCLit (BigLiveness lbl)    = CmmLabel lbl
+mkLivenessCLit (SmallLiveness bits) = mkWordCLit bits
+
+
+-------------------------------------------------------------------------
+--
+--             Bitmap describing register liveness
+--             across GC when doing a "generic" heap check
+--             (a RET_DYN stack frame).
+--
+-- NB. Must agree with these macros (currently in StgMacros.h): 
+-- GET_NON_PTRS(), GET_PTRS(), GET_LIVENESS().
+-------------------------------------------------------------------------
+
+mkRegLiveness :: [(Id, GlobalReg)] -> Int -> Int -> StgWord
+mkRegLiveness regs ptrs nptrs
+  = (fromIntegral nptrs `shiftL` 16) .|. 
+    (fromIntegral ptrs  `shiftL` 24) .|.
+    all_non_ptrs `xor` reg_bits regs
+  where
+    all_non_ptrs = 0xff
+
+    reg_bits [] = 0
+    reg_bits ((id, VanillaReg i) : regs) | isFollowableArg (idCgRep id)
+       = (1 `shiftL` (i - 1)) .|. reg_bits regs
+    reg_bits (_ : regs)
+       = reg_bits regs
+  
+-------------------------------------------------------------------------
+--
+--             Pushing the arguments for a slow call
+--
+-------------------------------------------------------------------------
+
+-- For a slow call, we must take a bunch of arguments and intersperse
+-- some stg_ap_<pattern>_ret_info return addresses.
+constructSlowCall :: [(CgRep,CmmExpr)] -> (CLabel, [(CgRep,CmmExpr)])
+   -- don't forget the zero case
+constructSlowCall [] 
+  = (stg_ap_0, [])
+  where
+    stg_ap_0 = enterRtsRetLabel SLIT("stg_ap_0")
+
+constructSlowCall amodes
+  = (stg_ap_pat, these ++ slowArgs rest)
+  where 
+    stg_ap_pat = enterRtsRetLabel arg_pat
+    (arg_pat, these, rest) = matchSlowPattern amodes
+
+enterRtsRetLabel arg_pat
+  | tablesNextToCode = mkRtsRetInfoLabel arg_pat
+  | otherwise        = mkRtsRetLabel arg_pat
+
+-- | 'slowArgs' takes a list of function arguments and prepares them for
+-- pushing on the stack for "extra" arguments to a function which requires
+-- fewer arguments than we currently have.
+slowArgs :: [(CgRep,CmmExpr)] -> [(CgRep,CmmExpr)]
+slowArgs [] = []
+slowArgs amodes = (NonPtrArg, mkLblExpr stg_ap_pat) : args ++ slowArgs rest
+  where        (arg_pat, args, rest) = matchSlowPattern amodes
+       stg_ap_pat = mkRtsRetInfoLabel arg_pat
+  
+matchSlowPattern :: [(CgRep,CmmExpr)] 
+                -> (LitString, [(CgRep,CmmExpr)], [(CgRep,CmmExpr)])
+matchSlowPattern amodes = (arg_pat, these, rest)
+  where (arg_pat, n)  = slowCallPattern (map fst amodes)
+       (these, rest) = splitAt n amodes
+
+-- These cases were found to cover about 99% of all slow calls:
+slowCallPattern (PtrArg: PtrArg: PtrArg: PtrArg: PtrArg: PtrArg: _) = (SLIT("stg_ap_pppppp"), 6)
+slowCallPattern (PtrArg: PtrArg: PtrArg: PtrArg: PtrArg: _)    = (SLIT("stg_ap_ppppp"), 5)
+slowCallPattern (PtrArg: PtrArg: PtrArg: PtrArg: _)    = (SLIT("stg_ap_pppp"), 4)
+slowCallPattern (PtrArg: PtrArg: PtrArg: VoidArg: _)   = (SLIT("stg_ap_pppv"), 4)
+slowCallPattern (PtrArg: PtrArg: PtrArg: _)            = (SLIT("stg_ap_ppp"), 3)
+slowCallPattern (PtrArg: PtrArg: VoidArg: _)           = (SLIT("stg_ap_ppv"), 3)
+slowCallPattern (PtrArg: PtrArg: _)                    = (SLIT("stg_ap_pp"), 2)
+slowCallPattern (PtrArg: VoidArg: _)                   = (SLIT("stg_ap_pv"), 2)
+slowCallPattern (PtrArg: _)                            = (SLIT("stg_ap_p"), 1)
+slowCallPattern (VoidArg: _)                           = (SLIT("stg_ap_v"), 1)
+slowCallPattern (NonPtrArg: _)                         = (SLIT("stg_ap_n"), 1)
+slowCallPattern (FloatArg: _)                          = (SLIT("stg_ap_f"), 1)
+slowCallPattern (DoubleArg: _)                         = (SLIT("stg_ap_d"), 1)
+slowCallPattern (LongArg: _)                           = (SLIT("stg_ap_l"), 1)
+slowCallPattern _  = panic "CgStackery.slowCallPattern"
+
+-------------------------------------------------------------------------
+--
+--             Return conventions
+--
+-------------------------------------------------------------------------
+
+-- A @CtrlReturnConvention@ says how {\em control} is returned.
+
+data CtrlReturnConvention
+  = VectoredReturn     Int     -- size of the vector table (family size)
+  | UnvectoredReturn    Int    -- family size
+
+ctrlReturnConvAlg :: TyCon -> CtrlReturnConvention
+ctrlReturnConvAlg tycon
+  = case (tyConFamilySize tycon) of
+      size -> -- we're supposed to know...
+       if (size > (1::Int) && size <= mAX_FAMILY_SIZE_FOR_VEC_RETURNS) then
+           VectoredReturn size
+       else
+           UnvectoredReturn size       
+  -- NB: unvectored returns Include size 0 (no constructors), so that
+  --     the following perverse code compiles (it crashed GHC in 5.02)
+  --       data T1
+  --       data T2 = T2 !T1 Int
+  --     The only value of type T1 is bottom, which never returns anyway.
+
+dataReturnConvPrim :: CgRep -> CmmReg
+dataReturnConvPrim PtrArg    = CmmGlobal (VanillaReg 1)
+dataReturnConvPrim NonPtrArg = CmmGlobal (VanillaReg 1)
+dataReturnConvPrim LongArg   = CmmGlobal (LongReg 1)
+dataReturnConvPrim FloatArg  = CmmGlobal (FloatReg 1)
+dataReturnConvPrim DoubleArg = CmmGlobal (DoubleReg 1)
+dataReturnConvPrim VoidArg   = panic "dataReturnConvPrim: void"
+
+
+-- getSequelAmode returns an amode which refers to an info table.  The info
+-- table will always be of the RET(_VEC)?_(BIG|SMALL) kind.  We're careful
+-- not to handle real code pointers, just in case we're compiling for 
+-- an unregisterised/untailcallish architecture, where info pointers and
+-- code pointers aren't the same.
+-- DIRE WARNING.
+-- The OnStack case of sequelToAmode delivers an Amode which is only
+-- valid just before the final control transfer, because it assumes
+-- that Sp is pointing to the top word of the return address.  This
+-- seems unclean but there you go.
+
+getSequelAmode :: FCode CmmExpr
+getSequelAmode
+  = do { EndOfBlockInfo virt_sp sequel <- getEndOfBlockInfo
+       ; case sequel of
+           OnStack -> do { sp_rel <- getSpRelOffset virt_sp
+                         ; returnFC (CmmLoad sp_rel wordRep) }
+
+           UpdateCode             -> returnFC (CmmLit (CmmLabel mkUpdInfoLabel))
+           CaseAlts lbl _ _ True  -> returnFC (CmmLit (CmmLabel mkSeqInfoLabel))
+           CaseAlts lbl _ _ False -> returnFC (CmmLit (CmmLabel lbl))
+       }
+
+-------------------------------------------------------------------------
+--
+--             Build a liveness mask for the current stack
+--
+-------------------------------------------------------------------------
+
+-- There are four kinds of things on the stack:
+--
+--     - pointer variables (bound in the environment)
+--     - non-pointer variables (boudn in the environment)
+--     - free slots (recorded in the stack free list)
+--     - non-pointer data slots (recorded in the stack free list)
+-- 
+-- We build up a bitmap of non-pointer slots by searching the environment
+-- for all the pointer variables, and subtracting these from a bitmap
+-- with initially all bits set (up to the size of the stack frame).
+
+buildContLiveness :: Name              -- Basis for label (only)
+                 -> [VirtualSpOffset]  -- Live stack slots
+                 -> FCode Liveness
+buildContLiveness name live_slots
+ = do  { stk_usg    <- getStkUsage
+       ; let   StackUsage { realSp = real_sp, 
+                            frameSp = frame_sp } = stk_usg
+
+               start_sp :: VirtualSpOffset
+               start_sp = real_sp - retAddrSizeW
+               -- In a continuation, we want a liveness mask that 
+               -- starts from just after the return address, which is 
+               -- on the stack at real_sp.
+
+               frame_size :: WordOff
+               frame_size = start_sp - frame_sp
+               -- real_sp points to the frame-header for the current
+               -- stack frame, and the end of this frame is frame_sp.
+               -- The size is therefore real_sp - frame_sp - retAddrSizeW
+               -- (subtract one for the frame-header = return address).
+       
+               rel_slots :: [WordOff]
+               rel_slots = sortLt (<) 
+                   [ start_sp - ofs  -- Get slots relative to top of frame
+                   | ofs <- live_slots ]
+
+               bitmap = intsToReverseBitmap frame_size rel_slots
+
+       ; WARN( not (all (>=0) rel_slots), 
+               ppr name $$ ppr live_slots $$ ppr frame_size $$ ppr start_sp $$ ppr rel_slots )
+         mkLiveness name frame_size bitmap }
+
+
+-------------------------------------------------------------------------
+--
+--             Register assignment
+--
+-------------------------------------------------------------------------
+
+--  How to assign registers for 
+--
+--     1) Calling a fast entry point.
+--     2) Returning an unboxed tuple.
+--     3) Invoking an out-of-line PrimOp.
+--
+-- Registers are assigned in order.
+-- 
+-- If we run out, we don't attempt to assign any further registers (even
+-- though we might have run out of only one kind of register); we just
+-- return immediately with the left-overs specified.
+-- 
+-- The alternative version @assignAllRegs@ uses the complete set of
+-- registers, including those that aren't mapped to real machine
+-- registers.  This is used for calling special RTS functions and PrimOps
+-- which expect their arguments to always be in the same registers.
+
+assignCallRegs, assignPrimOpCallRegs, assignReturnRegs
+       :: [(CgRep,a)]          -- Arg or result values to assign
+       -> ([(a, GlobalReg)],   -- Register assignment in same order
+                               -- for *initial segment of* input list
+                               --   (but reversed; doesn't matter)
+                               -- VoidRep args do not appear here
+           [(CgRep,a)])        -- Leftover arg or result values
+
+assignCallRegs args
+  = assign_regs args (mkRegTbl [node])
+       -- The entry convention for a function closure
+       -- never uses Node for argument passing; instead
+       -- Node points to the function closure itself
+
+assignPrimOpCallRegs args
+ = assign_regs args (mkRegTbl_allRegs [])
+       -- For primops, *all* arguments must be passed in registers
+
+assignReturnRegs args
+ = assign_regs args (mkRegTbl [])
+       -- For returning unboxed tuples etc, 
+       -- we use all regs
+
+assign_regs :: [(CgRep,a)]             -- Arg or result values to assign
+           -> AvailRegs        -- Regs still avail: Vanilla, Float, Double, Longs
+           -> ([(a, GlobalReg)], [(CgRep, a)])
+assign_regs args supply
+  = go args [] supply
+  where
+    go [] acc supply = (acc, [])       -- Return the results reversed (doesn't matter)
+    go ((VoidArg,_) : args) acc supply         -- Skip void arguments; they aren't passed, and
+       = go args acc supply            -- there's nothign to bind them to
+    go ((rep,arg) : args) acc supply 
+       = case assign_reg rep supply of
+               Just (reg, supply') -> go args ((arg,reg):acc) supply'
+               Nothing             -> (acc, (rep,arg):args)    -- No more regs
+
+assign_reg :: CgRep -> AvailRegs -> Maybe (GlobalReg, AvailRegs)
+assign_reg FloatArg  (vs, f:fs, ds, ls) = Just (FloatReg f,   (vs, fs, ds, ls))
+assign_reg DoubleArg (vs, fs, d:ds, ls) = Just (DoubleReg d,  (vs, fs, ds, ls))
+assign_reg LongArg   (vs, fs, ds, l:ls) = Just (LongReg l,    (vs, fs, ds, ls))
+assign_reg PtrArg    (v:vs, fs, ds, ls) = Just (VanillaReg v, (vs, fs, ds, ls))
+assign_reg NonPtrArg (v:vs, fs, ds, ls) = Just (VanillaReg v, (vs, fs, ds, ls))
+    -- PtrArg and NonPtrArg both go in a vanilla register
+assign_reg other     not_enough_regs    = Nothing
+
+
+-------------------------------------------------------------------------
+--
+--             Register supplies
+--
+-------------------------------------------------------------------------
+
+-- Vanilla registers can contain pointers, Ints, Chars.
+-- Floats and doubles have separate register supplies.
+--
+-- We take these register supplies from the *real* registers, i.e. those
+-- that are guaranteed to map to machine registers.
+
+useVanillaRegs | opt_Unregisterised = 0
+              | otherwise          = mAX_Real_Vanilla_REG
+useFloatRegs   | opt_Unregisterised = 0
+              | otherwise          = mAX_Real_Float_REG
+useDoubleRegs  | opt_Unregisterised = 0
+              | otherwise          = mAX_Real_Double_REG
+useLongRegs    | opt_Unregisterised = 0
+              | otherwise          = mAX_Real_Long_REG
+
+vanillaRegNos, floatRegNos, doubleRegNos, longRegNos :: [Int]
+vanillaRegNos   = regList useVanillaRegs
+floatRegNos     = regList useFloatRegs
+doubleRegNos    = regList useDoubleRegs
+longRegNos       = regList useLongRegs
+
+allVanillaRegNos, allFloatRegNos, allDoubleRegNos, allLongRegNos :: [Int]
+allVanillaRegNos = regList mAX_Vanilla_REG
+allFloatRegNos  = regList mAX_Float_REG
+allDoubleRegNos         = regList mAX_Double_REG
+allLongRegNos   = regList mAX_Long_REG
+
+regList 0 = []
+regList n = [1 .. n]
+
+type AvailRegs = ( [Int]   -- available vanilla regs.
+                , [Int]   -- floats
+                , [Int]   -- doubles
+                , [Int]   -- longs (int64 and word64)
+                )
+
+mkRegTbl :: [GlobalReg] -> AvailRegs
+mkRegTbl regs_in_use
+  = mkRegTbl' regs_in_use vanillaRegNos floatRegNos doubleRegNos longRegNos
+
+mkRegTbl_allRegs :: [GlobalReg] -> AvailRegs
+mkRegTbl_allRegs regs_in_use
+  = mkRegTbl' regs_in_use allVanillaRegNos allFloatRegNos allDoubleRegNos allLongRegNos
+
+mkRegTbl' regs_in_use vanillas floats doubles longs
+  = (ok_vanilla, ok_float, ok_double, ok_long)
+  where
+    ok_vanilla = mapCatMaybes (select VanillaReg) vanillas
+    ok_float   = mapCatMaybes (select FloatReg)          floats
+    ok_double  = mapCatMaybes (select DoubleReg)  doubles
+    ok_long    = mapCatMaybes (select LongReg)    longs   
+                                   -- rep isn't looked at, hence we can use any old rep.
+
+    select :: (Int -> GlobalReg) -> Int{-cand-} -> Maybe Int
+       -- one we've unboxed the Int, we make a GlobalReg
+       -- and see if it is already in use; if not, return its number.
+
+    select mk_reg_fun cand
+      = let
+           reg = mk_reg_fun cand
+       in
+       if reg `not_elem` regs_in_use
+       then Just cand
+       else Nothing
+      where
+       not_elem = isn'tIn "mkRegTbl"
+
+
index c805aaa..c7b03ef 100644 (file)
@@ -1,7 +1,7 @@
 %
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
-% $Id: CgCase.lhs,v 1.68 2004/08/10 09:02:38 simonmar Exp $
+% $Id: CgCase.lhs,v 1.69 2004/08/13 13:05:51 simonmar Exp $
 %
 %********************************************************
 %*                                                     *
@@ -11,7 +11,7 @@
 
 \begin{code}
 module CgCase (        cgCase, saveVolatileVarsAndRegs, 
-               mkRetDirectTarget, restoreCurrentCostCentre
+               restoreCurrentCostCentre
        ) where
 
 #include "HsVersions.h"
@@ -20,43 +20,42 @@ import {-# SOURCE #-} CgExpr  ( cgExpr )
 
 import CgMonad
 import StgSyn
-import AbsCSyn
-
-import AbsCUtils       ( mkAbstractCs, mkAbsCStmts, mkAlgAltsCSwitch,
-                         getAmodeRep, shimFCallArg )
-import CgBindery       ( getVolatileRegs, getArgAmodes,
+import CgBindery       ( getArgAmodes,
                          bindNewToReg, bindNewToTemp,
-                         getCAddrModeAndInfo,
-                         rebindToStack, getCAddrMode, getCAddrModeIfVolatile,
-                         buildContLivenessMask, nukeDeadBindings,
+                         getCgIdInfo, getArgAmode,
+                         rebindToStack, getCAddrModeIfVolatile,
+                         nukeDeadBindings, idInfoToAmode
                        )
 import CgCon           ( bindConArgs, bindUnboxedTupleComponents )
 import CgHeapery       ( altHeapCheck, unbxTupleHeapCheck )
-import CgRetConv       ( dataReturnConvPrim, ctrlReturnConvAlg,
+import CgCallConv      ( dataReturnConvPrim, ctrlReturnConvAlg,
                          CtrlReturnConvention(..)
                        )
-import CgStackery      ( allocPrimStack, allocStackTop,
-                         deAllocStackTop, freeStackSlots, dataStackSlots
+import CgStackery      ( allocPrimStack, allocStackTop, getSpRelOffset,
+                         deAllocStackTop, freeStackSlots
                        )
 import CgTailCall      ( performTailCall )
-import CgUsages                ( getSpRelOffset )
-import CLabel          ( mkVecTblLabel, mkClosureTblLabel,
-                         mkDefaultLabel, mkAltLabel, mkReturnInfoLabel
-                       )
+import CgPrimOp                ( cgPrimOp )
+import CgForeignCall   ( cgForeignCall )
+import CgUtils         ( newTemp, cgLit, emitLitSwitch, emitSwitch,
+                         tagToClosure )
+import CgProf          ( curCCS, curCCSAddr )
+import CgInfoTbls      ( emitDirectReturnTarget, emitAlgReturnTarget, 
+                         dataConTagZ )
+import SMRep           ( CgRep(..), retAddrSizeW, nonVoidArg, isVoidArg,
+                         idCgRep, tyConCgRep, typeHint )
+import CmmUtils                ( CmmStmts, noStmts, oneStmt, plusStmts )
+import Cmm
+import MachOp          ( wordRep )
 import ClosureInfo     ( mkLFArgument )
 import CmdLineOpts     ( opt_SccProfilingOn )
-import Id              ( Id, idName, isDeadBinder )
-import DataCon         ( dataConTag, fIRST_TAG, ConTag )
+import Id              ( Id, idName, isDeadBinder, idType )
+import ForeignCall     ( ForeignCall(..), CCallSpec(..), playSafe )
 import VarSet          ( varSetElems )
 import CoreSyn         ( AltCon(..) )
-import PrimOp          ( primOpOutOfLine, PrimOp(..) )
-import PrimRep         ( getPrimRepSize, retPrimRepSize, PrimRep(..)
-                       )
-import TyCon           ( TyCon, isEnumerationTyCon, tyConPrimRep       )
-import Unique           ( Unique, Uniquable(..), newTagUnique )
-import ForeignCall
-import Util            ( only )
-import List            ( sortBy )
+import PrimOp          ( PrimOp(..), primOpOutOfLine )
+import TyCon           ( isEnumerationTyCon, tyConFamilySize )
+import Util            ( isSingleton )
 import Outputable
 \end{code}
 
@@ -122,10 +121,11 @@ Special case #1: case of literal.
 
 \begin{code}
 cgCase (StgLit lit) live_in_whole_case live_in_alts bndr srt 
-       alt_type@(PrimAlt tycon) alts 
-  = bindNewToTemp bndr                 `thenFC` \ tmp_amode ->
-    absC (CAssign tmp_amode (CLit lit))        `thenC`
-    cgPrimAlts NoGC tmp_amode alts alt_type
+       alt_type@(PrimAlt tycon) alts
+  = do { tmp_reg <- bindNewToTemp bndr
+       ; cm_lit <- cgLit lit
+       ; stmtC (CmmAssign tmp_reg (CmmLit cm_lit))
+       ; cgPrimAlts NoGC alt_type tmp_reg alts }
 \end{code}
 
 Special case #2: scrutinising a primitive-typed variable.      No
@@ -138,15 +138,15 @@ eliminate a heap check altogether.
 \begin{code}
 cgCase (StgApp v []) live_in_whole_case live_in_alts bndr srt
        alt_type@(PrimAlt tycon) alts
-
-  = -- Careful! we can't just bind the default binder to the same thing
-    -- as the scrutinee, since it might be a stack location, and having
-    -- two bindings pointing at the same stack locn doesn't work (it
-    -- confuses nukeDeadBindings).  Hence, use a new temp.
-    getCAddrMode v                     `thenFC` \ amode ->
-    bindNewToTemp bndr                 `thenFC` \ tmp_amode ->
-    absC (CAssign tmp_amode amode)     `thenC`
-    cgPrimAlts NoGC tmp_amode alts alt_type
+  = do { -- Careful! we can't just bind the default binder to the same thing
+         -- as the scrutinee, since it might be a stack location, and having
+         -- two bindings pointing at the same stack locn doesn't work (it
+         -- confuses nukeDeadBindings).  Hence, use a new temp.
+         v_info <- getCgIdInfo v
+       ; amode <- idInfoToAmode v_info
+       ; tmp_reg <- bindNewToTemp bndr
+       ; stmtC (CmmAssign tmp_reg amode)
+       ; cgPrimAlts NoGC alt_type tmp_reg alts }
 \end{code}
 
 Special case #3: inline PrimOps and foreign calls.
@@ -154,85 +154,8 @@ Special case #3: inline PrimOps and foreign calls.
 \begin{code}
 cgCase (StgOpApp op args _) 
        live_in_whole_case live_in_alts bndr srt alt_type alts
-  | inline_primop
-  =    -- Get amodes for the arguments and results
-    getArgAmodes args                  `thenFC` \ arg_amodes1 ->
-    let 
-       arg_amodes
-         | StgFCallOp{} <- op = zipWith shimFCallArg args arg_amodes1
-         | otherwise          = arg_amodes1
-    in
-    getVolatileRegs live_in_alts        `thenFC` \ vol_regs ->
-
-    case alt_type of 
-      PrimAlt tycon    -- PRIMITIVE ALTS
-       -> bindNewToTemp bndr                                   `thenFC` \ tmp_amode ->
-          absC (COpStmt [tmp_amode] op arg_amodes vol_regs)    `thenC` 
-                        -- Note: no liveness arg
-          cgPrimAlts NoGC tmp_amode alts alt_type
-
-      UbxTupAlt tycon  -- UNBOXED TUPLE ALTS
-       ->      -- No heap check, no yield, just get in there and do it.
-               -- NB: the case binder isn't bound to anything; 
-               --     it has a unboxed tuple type
-          mapFCs bindNewToTemp res_ids                         `thenFC` \ res_tmps ->
-          absC (COpStmt res_tmps op arg_amodes vol_regs)       `thenC`
-          cgExpr rhs
-       where
-          [(_, res_ids, _, rhs)] = alts
-
-      AlgAlt tycon     -- ENUMERATION TYPE RETURN
-        | StgPrimOp primop <- op
-       -> ASSERT( isEnumerationTyCon tycon )
-          let
-            do_enum_primop :: PrimOp -> FCode CAddrMode        -- Returns amode for result
-            do_enum_primop TagToEnumOp -- No code!
-               = returnFC (only arg_amodes)
-            
-            do_enum_primop primop
-             = absC (COpStmt [tag_amode] op arg_amodes vol_regs)       `thenC`
-               returnFC tag_amode
-             where                     
-               tag_amode = CTemp (newTagUnique (getUnique bndr) 'C') IntRep
-                       -- Being a bit short of uniques for temporary
-                       -- variables here, we use newTagUnique to
-                       -- generate a new unique from the case binder.
-                       -- The case binder's unique will presumably
-                       -- have the 'c' tag (generated by CoreToStg),
-                       -- so we just change its tag to 'C' (for
-                       -- 'case') to ensure it doesn't clash with
-                       -- anything else.  We can't use the unique
-                       -- from the case binder, becaus e this is used
-                       -- to hold the actual result closure (via the
-                       -- call to bindNewToTemp)
-          in
-          do_enum_primop primop                `thenFC` \ tag_amode ->
-
-               -- Bind the default binder if necessary
-               -- (avoiding it avoids the assignment)
-               -- The deadness info is set by StgVarInfo
-          (if (isDeadBinder bndr)
-               then nopC
-               else bindNewToTemp bndr         `thenFC` \ tmp_amode ->
-                    absC (CAssign tmp_amode (tagToClosure tycon tag_amode))
-          )                                    `thenC`
-
-               -- Compile the alts
-          cgAlgAlts NoGC (getUnique bndr) 
-                    Nothing{-cc_slot-} False{-no semi-tagging-}
-                    (AlgAlt tycon) alts        `thenFC` \ tagged_alts ->
-
-               -- Do the switch
-          absC (mkAlgAltsCSwitch tag_amode tagged_alts)
-
-      other -> pprPanic "cgCase: case of primop has strange alt type" (ppr alt_type)
-  where
-   inline_primop = case op of
-       StgPrimOp primop  -> not (primOpOutOfLine primop)
-       --StgFCallOp (CCall (CCallSpec _ _ PlayRisky)) _ -> True
-                -- unsafe foreign calls are "inline"
-       _otherwise -> False
-
+  | not (primOpOutOfLine primop)
+  = cgInlinePrimOp primop args bndr alt_type live_in_alts alts
 \end{code}
 
 TODO: Case-of-case of primop can probably be done inline too (but
@@ -240,6 +163,30 @@ maybe better to translate it out beforehand).  See
 ghc/lib/misc/PackedString.lhs for examples where this crops up (with
 4.02).
 
+Special case #4: inline foreign calls: an unsafe foreign call can be done
+right here, just like an inline primop.
+
+\begin{code}
+cgCase (StgOpApp op@(StgFCallOp fcall _) args _) 
+       live_in_whole_case live_in_alts bndr srt alt_type alts
+  | unsafe_foreign_call
+  = ASSERT( isSingleton alts )
+    do -- *must* be an unboxed tuple alt.
+       -- exactly like the cgInlinePrimOp case for unboxed tuple alts..
+       { res_tmps <- mapFCs bindNewToTemp non_void_res_ids
+       ; let res_hints = map (typeHint.idType) non_void_res_ids
+       ; cgForeignCall (zip res_tmps res_hints) fcall args live_in_alts
+       ; cgExpr rhs }
+  where
+   (_, res_ids, _, rhs) = head alts
+   non_void_res_ids = filter (nonVoidArg . idCgRep) res_ids
+
+   unsafe_foreign_call
+        = case fcall of
+               CCall (CCallSpec _ _ s) -> not (playSafe s)
+               _other                  -> False                                
+\end{code}
+
 Special case: scrutinising a non-primitive variable.
 This can be done a little better than the general case, because
 we can reuse/trim the stack slot holding the variable (if it is in one).
@@ -247,8 +194,8 @@ we can reuse/trim the stack slot holding the variable (if it is in one).
 \begin{code}
 cgCase (StgApp fun args)
        live_in_whole_case live_in_alts bndr srt alt_type alts
-  = getCAddrModeAndInfo fun            `thenFC` \ (fun', fun_amode, lf_info) ->
-    getArgAmodes args                  `thenFC` \ arg_amodes ->
+  = do { fun_info <- getCgIdInfo fun
+       ; arg_amodes <- getArgAmodes args
 
        -- Nuking dead bindings *before* calculating the saves is the
        -- value-add here.  We might end up freeing up some slots currently
@@ -256,19 +203,18 @@ cgCase (StgApp fun args)
        -- NOTE: we need to look up the variables used in the call before
        -- doing this, because some of them may not be in the environment
        -- afterward.
-    nukeDeadBindings live_in_alts      `thenC`
-    saveVolatileVarsAndRegs live_in_alts
-                       `thenFC` \ (save_assts, alts_eob_info, maybe_cc_slot) ->
-
-    forkEval alts_eob_info 
-       ( allocStackTop retPrimRepSize
-        `thenFC` \_ -> nopC )
-       ( deAllocStackTop retPrimRepSize `thenFC` \_ ->
-         cgEvalAlts maybe_cc_slot bndr srt alt_type alts ) 
-                                        `thenFC` \ scrut_eob_info ->
-
-    setEndOfBlockInfo (maybeReserveSeqFrame alt_type scrut_eob_info)   $
-    performTailCall fun' fun_amode lf_info arg_amodes save_assts
+       ; nukeDeadBindings live_in_alts 
+       ; (save_assts, alts_eob_info, maybe_cc_slot)
+               <- saveVolatileVarsAndRegs live_in_alts
+
+       ; scrut_eob_info
+           <- forkEval alts_eob_info 
+                       (allocStackTop retAddrSizeW >> nopC)
+                       (do { deAllocStackTop retAddrSizeW
+                           ; cgEvalAlts maybe_cc_slot bndr srt alt_type alts })
+
+       ; setEndOfBlockInfo (maybeReserveSeqFrame alt_type scrut_eob_info)
+                           (performTailCall fun_info arg_amodes save_assts) }
 \end{code}
 
 Note about return addresses: we *always* push a return address, even
@@ -286,26 +232,27 @@ Finally, here is the general case.
 
 \begin{code}
 cgCase expr live_in_whole_case live_in_alts bndr srt alt_type alts
-  =    -- Figure out what volatile variables to save
-    nukeDeadBindings live_in_whole_case        `thenC`
+  = do {       -- Figure out what volatile variables to save
+         nukeDeadBindings live_in_whole_case
     
-    saveVolatileVarsAndRegs live_in_alts
-                       `thenFC` \ (save_assts, alts_eob_info, maybe_cc_slot) ->
-
-    -- Save those variables right now!
-    absC save_assts                    `thenC`
-
-    -- generate code for the alts
-    forkEval alts_eob_info
-       (nukeDeadBindings live_in_alts `thenC` 
-        allocStackTop retPrimRepSize   -- space for retn address 
-        `thenFC` \_ -> nopC
-        )
-       (deAllocStackTop retPrimRepSize `thenFC` \_ ->
-        cgEvalAlts maybe_cc_slot bndr srt alt_type alts) `thenFC` \ scrut_eob_info ->
-
-    setEndOfBlockInfo (maybeReserveSeqFrame alt_type scrut_eob_info)   $
-    cgExpr expr
+       ; (save_assts, alts_eob_info, maybe_cc_slot)
+               <- saveVolatileVarsAndRegs live_in_alts
+
+            -- Save those variables right now!
+       ; emitStmts save_assts
+
+           -- generate code for the alts
+       ; scrut_eob_info
+              <- forkEval alts_eob_info
+                          (do  { nukeDeadBindings live_in_alts
+                               ; allocStackTop retAddrSizeW   -- space for retn address 
+                               ; nopC })
+                          (do  { deAllocStackTop retAddrSizeW
+                               ; cgEvalAlts maybe_cc_slot bndr srt alt_type alts })
+
+       ; setEndOfBlockInfo (maybeReserveSeqFrame alt_type scrut_eob_info)
+                           (cgExpr expr)
+    }
 \end{code}
 
 There's a lot of machinery going on behind the scenes to manage the
@@ -329,25 +276,93 @@ because we don't reserve it until just before the eval.
 
 TODO!!  Problem: however, we have to save the current cost centre
 stack somewhere, because at the eval point the current CCS might be
-different.  So we pick a free stack slot and save CCCS in it.  The
-problem with this is that this slot isn't recorded as free/unboxed in
-the environment, so a case expression in the scrutinee will have the
-wrong bitmap attached.  Fortunately we don't ever seem to see
-case-of-case at the back end.  One solution might be to shift the
-saved CCS to the correct place in the activation record just before
-the jump.
-       --SDM
-
-(one consequence of the above is that activation records on the stack
-don't follow the layout of closures when we're profiling.  The CCS
-could be anywhere within the record).
+different.  So we pick a free stack slot and save CCCS in it.  One
+consequence of this is that activation records on the stack don't
+follow the layout of closures when we're profiling.  The CCS could be
+anywhere within the record).
 
 \begin{code}
-maybeReserveSeqFrame PolyAlt (EndOfBlockInfo args_sp (CaseAlts amode stuff _))
-   = EndOfBlockInfo (args_sp + retPrimRepSize) (CaseAlts amode stuff True)
+maybeReserveSeqFrame PolyAlt (EndOfBlockInfo args_sp (CaseAlts amode stuff bndr _))
+   = EndOfBlockInfo (args_sp + retAddrSizeW) (CaseAlts amode stuff bndr True)
 maybeReserveSeqFrame other scrut_eob_info = scrut_eob_info
 \end{code}
 
+
+%************************************************************************
+%*                                                                     *
+               Inline primops
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+cgInlinePrimOp primop args bndr (PrimAlt tycon) live_in_alts alts
+  | isVoidArg (idCgRep bndr)
+  = ASSERT( con == DEFAULT && isSingleton alts && null bs )
+    do {       -- VOID RESULT; just sequencing, 
+               -- so get in there and do it
+         cgPrimOp [] primop args live_in_alts
+       ; cgExpr rhs }
+  where
+    (con,bs,_,rhs) = head alts
+
+cgInlinePrimOp primop args bndr (PrimAlt tycon) live_in_alts alts
+  = do {       -- PRIMITIVE ALTS, with non-void result
+         tmp_reg <- bindNewToTemp bndr
+       ; cgPrimOp [tmp_reg] primop args live_in_alts
+       ; cgPrimAlts NoGC (PrimAlt tycon) tmp_reg alts }
+
+cgInlinePrimOp primop args bndr (UbxTupAlt tycon) live_in_alts alts
+  = ASSERT( isSingleton alts )
+    do {       -- UNBOXED TUPLE ALTS
+               -- No heap check, no yield, just get in there and do it.
+               -- NB: the case binder isn't bound to anything; 
+               --     it has a unboxed tuple type
+         
+         res_tmps <- mapFCs bindNewToTemp non_void_res_ids
+       ; cgPrimOp res_tmps primop args live_in_alts
+       ; cgExpr rhs }
+  where
+   (_, res_ids, _, rhs) = head alts
+   non_void_res_ids = filter (nonVoidArg . idCgRep) res_ids
+
+cgInlinePrimOp primop args bndr (AlgAlt tycon) live_in_alts alts
+  = do         {       -- ENUMERATION TYPE RETURN
+               -- Typical: case a ># b of { True -> ..; False -> .. }
+               -- The primop itself returns an index into the table of
+               -- closures for the enumeration type.
+          tag_amode <- ASSERT( isEnumerationTyCon tycon )
+                       do_enum_primop primop
+
+               -- Bind the default binder if necessary
+               -- (avoiding it avoids the assignment)
+               -- The deadness info is set by StgVarInfo
+       ; whenC (not (isDeadBinder bndr))
+               (do { tmp_reg <- bindNewToTemp bndr
+                   ; stmtC (CmmAssign tmp_reg (tagToClosure tycon tag_amode)) })
+
+               -- Compile the alts
+       ; (branches, mb_deflt) <- cgAlgAlts NoGC Nothing{-cc_slot-}
+                                           (AlgAlt tycon) alts
+
+               -- Do the switch
+       ; emitSwitch tag_amode branches mb_deflt 0 (tyConFamilySize tycon - 1)
+       }
+  where
+
+    do_enum_primop :: PrimOp -> FCode CmmExpr  -- Returns amode for result
+    do_enum_primop TagToEnumOp -- No code!
+       | [arg] <- args = do
+         (_,e) <- getArgAmode arg
+        return e
+    do_enum_primop primop
+      = do tmp <- newTemp wordRep
+          cgPrimOp [tmp] primop args live_in_alts
+          returnFC (CmmReg tmp)
+
+cgInlinePrimOp primop arg_amodes bndr PolyAlt live_in_alts alts
+  = pprPanic "cgCase: case of primop has polymorphic type" (ppr bndr)
+\end{code}
+
 %************************************************************************
 %*                                                                     *
 \subsection[CgCase-alts]{Alternatives}
@@ -368,6 +383,21 @@ cgEvalAlts :: Maybe VirtualSpOffset        -- Offset of cost-centre to be restored, if
                                -- to be a label so that we can duplicate it 
                                -- without risk of duplicating code
 
+cgEvalAlts cc_slot bndr srt alt_type@(PrimAlt tycon) alts
+  = do { let   rep = tyConCgRep tycon
+               reg = dataReturnConvPrim rep    -- Bottom for voidRep
+
+       ; abs_c <- forkProc $ do
+               {       -- Bind the case binder, except if it's void
+                       -- (reg is bottom in that case)
+                 whenC (nonVoidArg rep) $
+                 bindNewToReg bndr reg (mkLFArgument bndr)
+               ; restoreCurrentCostCentre cc_slot True
+               ; cgPrimAlts GCMayHappen alt_type reg alts }
+
+       ; lbl <- emitDirectReturnTarget (idName bndr) abs_c srt
+       ; returnFC (CaseAlts lbl Nothing bndr False) }
+
 cgEvalAlts cc_slot bndr srt (UbxTupAlt _) [(con,args,_,rhs)]
   =    -- Unboxed tuple case
        -- By now, the simplifier should have have turned it
@@ -376,38 +406,24 @@ cgEvalAlts cc_slot bndr srt (UbxTupAlt _) [(con,args,_,rhs)]
        --              case e of DEFAULT -> e
     ASSERT2( case con of { DataAlt _ -> True; other -> False },
             text "cgEvalAlts: dodgy case of unboxed tuple type" )
-    
-    forkAbsC ( -- forkAbsC for the RHS, so that the envt is
-               -- not changed for the mkRetDirect call
-       bindUnboxedTupleComponents args         `thenFC` \ (live_regs, ptrs, nptrs, _) ->
-               -- restore the CC *after* binding the tuple components, so that we
-               -- get the stack offset of the saved CC right.
-       restoreCurrentCostCentre cc_slot True   `thenC` 
-               -- Generate a heap check if necessary
-       unbxTupleHeapCheck live_regs ptrs nptrs AbsCNop (
-               -- And finally the code for the alternative
-       cgExpr rhs
-    ))                                         `thenFC` \ abs_c ->
-    mkRetDirectTarget bndr abs_c srt           `thenFC` \ lbl ->
-    returnFC (CaseAlts lbl Nothing False)
-
-cgEvalAlts cc_slot bndr srt alt_type@(PrimAlt tycon) alts
-  = forkAbsC ( -- forkAbsC for the RHS, so that the envt is
-               -- not changed for the mkRetDirect call
-       restoreCurrentCostCentre cc_slot True           `thenC` 
-       bindNewToReg bndr reg (mkLFArgument bndr)       `thenC`
-       cgPrimAlts GCMayHappen (CReg reg) alts alt_type
-    )                                          `thenFC` \ abs_c ->
-    mkRetDirectTarget bndr abs_c srt           `thenFC` \ lbl ->
-    returnFC (CaseAlts lbl Nothing False)
-  where
-    reg  = dataReturnConvPrim kind
-    kind = tyConPrimRep tycon
+    do {       -- forkAbsC for the RHS, so that the envt is
+               -- not changed for the emitDirectReturn call
+         abs_c <- forkProc $ do 
+               { (live_regs, ptrs, nptrs, _) <- bindUnboxedTupleComponents args
+                       -- Restore the CC *after* binding the tuple components, 
+                       -- so that we get the stack offset of the saved CC right.
+               ; restoreCurrentCostCentre cc_slot True
+                       -- Generate a heap check if necessary
+                       -- and finally the code for the alternative
+               ; unbxTupleHeapCheck live_regs ptrs nptrs noStmts
+                                    (cgExpr rhs) }
+       ; lbl <- emitDirectReturnTarget (idName bndr) abs_c srt
+       ; returnFC (CaseAlts lbl Nothing bndr False) }
 
 cgEvalAlts cc_slot bndr srt alt_type alts
   =    -- Algebraic and polymorphic case
-       -- Bind the default binder
-    bindNewToReg bndr node (mkLFArgument bndr) `thenC`
+    do {       -- Bind the default binder
+         bindNewToReg bndr nodeReg (mkLFArgument bndr)
 
        -- Generate sequel info for use downstream
        -- At the moment, we only do it if the type is vector-returnable.
@@ -418,25 +434,16 @@ cgEvalAlts cc_slot bndr srt alt_type alts
        --
        -- which is worse than having the alt code in the switch statement
 
-    let        ret_conv = case alt_type of
-                       AlgAlt tc -> ctrlReturnConvAlg tc
-                       PolyAlt   -> UnvectoredReturn 0
-
-       use_labelled_alts = case ret_conv of
-                               VectoredReturn _ -> True
-                               _                -> False
-
-       semi_tagged_stuff = cgSemiTaggedAlts use_labelled_alts bndr alts
-
-    in
-    cgAlgAlts GCMayHappen (getUnique bndr) 
-             cc_slot use_labelled_alts
-             alt_type alts                     `thenFC` \ tagged_alt_absCs ->
+       ; (alts, mb_deflt) <- cgAlgAlts GCMayHappen cc_slot alt_type alts
 
-    mkRetVecTarget bndr tagged_alt_absCs 
-                  srt ret_conv                 `thenFC` \ return_vec ->
+       ; (lbl, branches) <- emitAlgReturnTarget (idName bndr) 
+                               alts mb_deflt srt ret_conv
 
-    returnFC (CaseAlts return_vec semi_tagged_stuff False)
+       ; returnFC (CaseAlts lbl branches bndr False) }
+  where
+    ret_conv = case alt_type of
+               AlgAlt tc -> ctrlReturnConvAlg tc
+               PolyAlt   -> UnvectoredReturn 0
 \end{code}
 
 
@@ -462,94 +469,42 @@ are inlined alternatives.
 
 \begin{code}
 cgAlgAlts :: GCFlag
-       -> Unique
        -> Maybe VirtualSpOffset
-       -> Bool                         -- True <=> branches must be labelled
-                                       --      (used for semi-tagging)
-       -> AltType                      -- ** AlgAlt or PolyAlt only **
-       -> [StgAlt]                     -- The alternatives
-       -> FCode [(AltCon, AbstractC)]  -- The branches
+       -> AltType                              -- ** AlgAlt or PolyAlt only **
+       -> [StgAlt]                             -- The alternatives
+       -> FCode ( [(ConTagZ, CgStmts)], -- The branches
+                 Maybe CgStmts )       -- The default case
+
+cgAlgAlts gc_flag cc_slot alt_type alts
+  = do alts <- forkAlts [ cgAlgAlt gc_flag cc_slot alt_type alt | alt <- alts]
+       let
+           mb_deflt = case alts of -- DEFAULT is always first, if present
+                        ((DEFAULT,blks) : _) -> Just blks
+                        other                -> Nothing
+
+           branches = [(dataConTagZ con, blks) 
+                      | (DataAlt con, blks) <- alts]
+       -- in
+       return (branches, mb_deflt)
 
-cgAlgAlts gc_flag uniq restore_cc must_label_branches alt_type alts
-  = forkAlts [ cgAlgAlt gc_flag uniq restore_cc must_label_branches alt_type alt
-            | alt <- alts]
 
 cgAlgAlt :: GCFlag
-        -> Unique -> Maybe VirtualSpOffset -> Bool     -- turgid state
-        -> AltType                                     -- ** AlgAlt or PolyAlt only **
+        -> Maybe VirtualSpOffset       -- Turgid state
+        -> AltType                     -- ** AlgAlt or PolyAlt only **
         -> StgAlt
-        -> FCode (AltCon, AbstractC)
-
-cgAlgAlt gc_flag uniq cc_slot must_label_branch
-         alt_type (con, args, use_mask, rhs)
-  = getAbsC (bind_con_args con args            `thenFC` \ _ ->
-            restoreCurrentCostCentre cc_slot True      `thenC`
-            maybeAltHeapCheck gc_flag alt_type (cgExpr rhs)
-    )                                          `thenFC` \ abs_c -> 
-    let
-       final_abs_c | must_label_branch = CCodeBlock lbl abs_c
-                   | otherwise         = abs_c
-    in
-    returnFC (con, final_abs_c)
+        -> FCode (AltCon, CgStmts)
+
+cgAlgAlt gc_flag cc_slot alt_type (con, args, use_mask, rhs)
+  = do { abs_c <- getCgStmts $ do
+               { bind_con_args con args
+               ; restoreCurrentCostCentre cc_slot True
+               ; maybeAltHeapCheck gc_flag alt_type (cgExpr rhs) }
+       ; return (con, abs_c) }
   where
-    lbl = case con of
-           DataAlt dc -> mkAltLabel uniq (dataConTag dc)
-           DEFAULT    -> mkDefaultLabel uniq
-           other      -> pprPanic "cgAlgAlt" (ppr con)
-
     bind_con_args DEFAULT      args = nopC
     bind_con_args (DataAlt dc) args = bindConArgs dc args
 \end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection[CgCase-semi-tagged-alts]{The code to deal with sem-tagging}
-%*                                                                     *
-%************************************************************************
-
-Turgid-but-non-monadic code to conjure up the required info from
-algebraic case alternatives for semi-tagging.
-
-\begin{code}
-cgSemiTaggedAlts :: Bool       -- True <=> use semitagging: each alt will be labelled
-                -> Id 
-                -> [StgAlt]
-                -> SemiTaggingStuff
-
-cgSemiTaggedAlts False binder alts
-  = Nothing
-cgSemiTaggedAlts True binder alts
-  = Just ([st_alt con args | (DataAlt con, args, _, _) <- alts],
-         case head alts of
-           (DEFAULT, _, _, _) -> Just st_deflt
-           other              -> Nothing)
-  where
-    uniq = getUnique binder
-
-    st_deflt = (binder,
-               (CCallProfCtrMacro FSLIT("RET_SEMI_BY_DEFAULT") [], -- ToDo: monadise?
-                mkDefaultLabel uniq))
-
-    st_alt con args    -- Ha!  Nothing to do; Node already points to the thing
-      =         (con_tag,
-          (CCallProfCtrMacro FSLIT("RET_SEMI_IN_HEAP") -- ToDo: monadise?
-               [mkIntCLit (length args)], -- how big the thing in the heap is
-            join_label)
-           )
-      where
-       con_tag    = dataConTag con
-       join_label = mkAltLabel uniq con_tag
-
-
-tagToClosure :: TyCon -> CAddrMode -> CAddrMode
--- Primops returning an enumeration type (notably Bool)
--- actually return an index into
--- the table of closures for the enumeration type
-tagToClosure tycon tag_amode
-  = CVal (CIndex closure_tbl tag_amode PtrRep) PtrRep
-  where
-    closure_tbl = CLbl (mkClosureTblLabel tycon) PtrRep
-\end{code}
 
 %************************************************************************
 %*                                                                     *
@@ -566,29 +521,31 @@ As usual, no binders in the alternatives are yet bound.
 
 \begin{code}
 cgPrimAlts :: GCFlag
-          -> CAddrMode -- Scrutinee
+          -> AltType   -- Always PrimAlt, but passed to maybeAltHeapCheck
+          -> CmmReg    -- Scrutinee
           -> [StgAlt]  -- Alternatives
-          -> AltType   
           -> Code
+-- NB: cgPrimAlts emits code that does the case analysis.
+-- It's often used in inline situations, rather than to genearte
+-- a labelled return point.  That's why its interface is a little
+-- different to cgAlgAlts
+--
 -- INVARIANT: the default binder is already bound
-cgPrimAlts gc_flag scrutinee alts alt_type
-  = forkAlts (map (cgPrimAlt gc_flag alt_type) alts)   `thenFC` \ tagged_absCs ->
-    let
-       ((DEFAULT, deflt_absC) : others) = tagged_absCs         -- There is always a default
-       alt_absCs = [(lit,rhs) | (LitAlt lit, rhs) <- others]
-    in
-    absC (CSwitch scrutinee alt_absCs deflt_absC)
-       -- CSwitch does sensible things with one or zero alternatives
+cgPrimAlts gc_flag alt_type scrutinee alts
+  = do { tagged_absCs <- forkAlts (map (cgPrimAlt gc_flag alt_type) alts)
+       ; let ((DEFAULT, deflt_absC) : others) = tagged_absCs   -- There is always a default
+             alt_absCs = [(lit,rhs) | (LitAlt lit, rhs) <- others]
+       ; emitLitSwitch (CmmReg scrutinee) alt_absCs deflt_absC }
 
 cgPrimAlt :: GCFlag
          -> AltType
-         -> StgAlt                     -- The alternative
-         -> FCode (AltCon, AbstractC)  -- Its compiled form
+         -> StgAlt                             -- The alternative
+         -> FCode (AltCon, CgStmts)    -- Its compiled form
 
 cgPrimAlt gc_flag alt_type (con, [], [], rhs)
   = ASSERT( case con of { DEFAULT -> True; LitAlt _ -> True; other -> False } )
-    getAbsC (maybeAltHeapCheck gc_flag alt_type (cgExpr rhs))  `thenFC` \ abs_c ->
-    returnFC (con, abs_c)
+    do { abs_c <- getCgStmts (maybeAltHeapCheck gc_flag alt_type (cgExpr rhs)) 
+       ; returnFC (con, abs_c) }
 \end{code}
 
 
@@ -605,52 +562,42 @@ maybeAltHeapCheck
        -> Code         -- Continuation
        -> Code
 maybeAltHeapCheck NoGC       _        code = code
-maybeAltHeapCheck GCMayHappen alt_type code 
-  =    -- HWL: maybe need yield here
-       -- yield [node] True    -- XXX live regs wrong
-    altHeapCheck alt_type code
+maybeAltHeapCheck GCMayHappen alt_type code = altHeapCheck alt_type code
 
 saveVolatileVarsAndRegs
     :: StgLiveVars                    -- Vars which should be made safe
-    -> FCode (AbstractC,              -- Assignments to do the saves
+    -> FCode (CmmStmts,              -- Assignments to do the saves
              EndOfBlockInfo,         -- sequel for the alts
               Maybe VirtualSpOffset)  -- Slot for current cost centre
 
 saveVolatileVarsAndRegs vars
-  = saveVolatileVars vars       `thenFC` \ var_saves ->
-    saveCurrentCostCentre      `thenFC` \ (maybe_cc_slot, cc_save) ->
-    getEndOfBlockInfo           `thenFC` \ eob_info ->
-    returnFC (mkAbstractCs [var_saves, cc_save],
-             eob_info,
-             maybe_cc_slot)
+  = do { var_saves <- saveVolatileVars vars
+       ; (maybe_cc_slot, cc_save) <- saveCurrentCostCentre
+       ; eob_info <- getEndOfBlockInfo
+       ; returnFC (var_saves `plusStmts` cc_save,
+                   eob_info,
+                   maybe_cc_slot) }
 
 
 saveVolatileVars :: StgLiveVars                -- Vars which should be made safe
-                -> FCode AbstractC     -- Assignments to to the saves
+                -> FCode CmmStmts      -- Assignments to to the saves
 
 saveVolatileVars vars
-  = save_em (varSetElems vars)
+  = do { stmts_s <- mapFCs save_it (varSetElems vars)
+       ; return (foldr plusStmts noStmts stmts_s) }
   where
-    save_em [] = returnFC AbsCNop
-
-    save_em (var:vars)
-      = getCAddrModeIfVolatile var `thenFC` \ v ->
-       case v of
-           Nothing         -> save_em vars -- Non-volatile, so carry on
-
-
-           Just vol_amode  ->  -- Aha! It's volatile
-                              save_var var vol_amode   `thenFC` \ abs_c ->
-                              save_em vars             `thenFC` \ abs_cs ->
-                              returnFC (abs_c `mkAbsCStmts` abs_cs)
+    save_it var
+      = do { v <- getCAddrModeIfVolatile var
+          ; case v of
+               Nothing         -> return noStmts          -- Non-volatile
+               Just vol_amode  -> save_var var vol_amode  -- Aha! It's volatile
+       }
 
     save_var var vol_amode
-      = allocPrimStack (getPrimRepSize kind)   `thenFC` \ slot ->
-       rebindToStack var slot          `thenC`
-       getSpRelOffset slot             `thenFC` \ sp_rel ->
-       returnFC (CAssign (CVal sp_rel kind) vol_amode)
-      where
-       kind = getAmodeRep vol_amode
+      = do { slot <- allocPrimStack (idCgRep var)
+          ; rebindToStack var slot
+          ; sp_rel <- getSpRelOffset slot
+          ; returnFC (oneStmt (CmmStore sp_rel vol_amode)) }
 \end{code}
 
 ---------------------------------------------------------------------------
@@ -663,123 +610,24 @@ virtual offset of the location, to pass on to the alternatives, and
 \begin{code}
 saveCurrentCostCentre ::
        FCode (Maybe VirtualSpOffset,   -- Where we decide to store it
-              AbstractC)               -- Assignment to save it
+              CmmStmts)                -- Assignment to save it
 
 saveCurrentCostCentre
-  = if not opt_SccProfilingOn then
-       returnFC (Nothing, AbsCNop)
-    else
-       allocPrimStack (getPrimRepSize CostCentreRep) `thenFC` \ slot ->
-       dataStackSlots [slot]                         `thenC`
-       getSpRelOffset slot                           `thenFC` \ sp_rel ->
-       returnFC (Just slot,
-                 CAssign (CVal sp_rel CostCentreRep) (CReg CurCostCentre))
+  | not opt_SccProfilingOn 
+  = returnFC (Nothing, noStmts)
+  | otherwise
+  = do { slot <- allocPrimStack PtrArg
+       ; sp_rel <- getSpRelOffset slot
+       ; returnFC (Just slot,
+                   oneStmt (CmmStore sp_rel curCCS)) }
 
 -- Sometimes we don't free the slot containing the cost centre after restoring it
 -- (see CgLetNoEscape.cgLetNoEscapeBody).
 restoreCurrentCostCentre :: Maybe VirtualSpOffset -> Bool -> Code
 restoreCurrentCostCentre Nothing     _freeit = nopC
 restoreCurrentCostCentre (Just slot) freeit
- = getSpRelOffset slot                              `thenFC` \ sp_rel ->
-   (if freeit then freeStackSlots [slot] else nopC)  `thenC`
-   absC (CCallProfCCMacro FSLIT("RESTORE_CCCS") [CVal sp_rel CostCentreRep])
-    -- we use the RESTORE_CCCS macro, rather than just
-    -- assigning into CurCostCentre, in case RESTORE_CCCS
-    -- has some sanity-checking in it.
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[CgCase-return-vec]{Building a return vector}
-%*                                                                     *
-%************************************************************************
-
-Build a return vector, and return a suitable label addressing
-mode for it.
-
-\begin{code}
-mkRetDirectTarget :: Id                -- Used for labelling only
-                 -> AbstractC          -- Return code
-                 -> SRT                -- Live CAFs in return code
-                 -> FCode CAddrMode    -- Emit the labelled return block, 
-                                       -- and return its label
-mkRetDirectTarget bndr abs_c srt
-  = buildContLivenessMask bndr                         `thenFC` \ liveness ->
-    getSRTInfo name srt                                        `thenFC` \ srt_info -> 
-    absC (CRetDirect uniq abs_c srt_info liveness)     `thenC`
-    return lbl
-  where
-    name = idName bndr
-    uniq = getUnique name
-    lbl  = CLbl (mkReturnInfoLabel uniq) RetRep
+ = do  { sp_rel <- getSpRelOffset slot
+       ; whenC freeit (freeStackSlots [slot])
+       ; stmtC (CmmStore curCCSAddr (CmmLoad sp_rel wordRep)) }
 \end{code}
 
-\begin{code}
-mkRetVecTarget :: Id                   -- Just for its unique
-              -> [(AltCon, AbstractC)] -- Branch codes
-              -> SRT                   -- Continuation's SRT
-              -> CtrlReturnConvention
-              -> FCode CAddrMode
-
-mkRetVecTarget bndr tagged_alt_absCs srt (UnvectoredReturn 0)
-  = ASSERT( null other_alts )
-    mkRetDirectTarget bndr deflt_absC srt
-  where
-    ((DEFAULT, deflt_absC) : other_alts) = tagged_alt_absCs
-
-mkRetVecTarget bndr tagged_alt_absCs srt (UnvectoredReturn n)
-  = mkRetDirectTarget bndr switch_absC srt
-  where
-         -- Find the tag explicitly rather than using tag_reg for now.
-        -- on architectures with lots of regs the tag will be loaded
-        -- into tag_reg by the code doing the returning.
-    tag = CMacroExpr WordRep GET_TAG [CVal (nodeRel 0) DataPtrRep]
-    switch_absC = mkAlgAltsCSwitch tag tagged_alt_absCs
-         
-
-mkRetVecTarget bndr tagged_alt_absCs srt (VectoredReturn table_size)
-  = buildContLivenessMask bndr  `thenFC` \ liveness ->
-    getSRTInfo name srt                `thenFC` \ srt_info ->
-    let 
-       ret_vector = CRetVector vtbl_lbl vector_table srt_info liveness
-    in
-    absC (mkAbstractCs alts_absCs `mkAbsCStmts` ret_vector)    `thenC`
-                -- Alts come first, because we don't want to declare all the symbols
-
-    return (CLbl vtbl_lbl DataPtrRep)
-  where
-    tags        = [fIRST_TAG .. (table_size+fIRST_TAG-1)]
-    vector_table = map mk_vector_entry tags
-    alts_absCs   = map snd (sortBy cmp tagged_alt_absCs)
-                       -- The sort is unnecessary; just there for now
-                       -- to make the new order the same as the old
-    (DEFAULT,_) `cmp` (DEFAULT,_) = EQ
-    (DEFAULT,_) `cmp` _          = GT
-    (DataAlt d1,_) `cmp` (DataAlt d2,_) = dataConTag d1 `compare` dataConTag d2
-    (DataAlt d1,_) `cmp` (DEFAULT, _)   = LT
-       -- Others impossible
-
-    name       = idName bndr
-    uniq       = getUnique name 
-    vtbl_lbl   = mkVecTblLabel uniq
-
-    deflt_lbl :: CAddrMode
-    deflt_lbl = case tagged_alt_absCs of
-                  (DEFAULT, abs_c) : _ -> get_block_label abs_c
-                  other                -> mkIntCLit 0
-                       -- 'other' case: the simplifier might have eliminated a case
-                       --                so we may have e.g. case xs of 
-                       --                                       [] -> e
-                       -- In that situation the default should never be taken, 
-                       -- so we just use '0' (=> seg fault if used)
-
-    mk_vector_entry :: ConTag -> CAddrMode
-    mk_vector_entry tag
-      = case [ absC | (DataAlt d, absC) <- tagged_alt_absCs, dataConTag d == tag ] of
-               -- The comprehension neatly, and correctly, ignores the DEFAULT
-            []      -> deflt_lbl
-            [abs_c] -> get_block_label abs_c
-            _       -> panic "mkReturnVector: too many"
-
-    get_block_label (CCodeBlock lbl _) = CLbl lbl CodePtrRep
-\end{code}
index 6e77dc7..dc5e9ea 100644 (file)
@@ -1,7 +1,7 @@
 %
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
-% $Id: CgClosure.lhs,v 1.62 2003/11/17 14:23:31 simonmar Exp $
+% $Id: CgClosure.lhs,v 1.63 2004/08/13 13:05:54 simonmar Exp $
 %
 \section[CgClosure]{Code generation for closures}
 
@@ -13,6 +13,7 @@ with {\em closures} on the RHSs of let(rec)s.  See also
 module CgClosure ( cgTopRhsClosure, 
                   cgStdRhsClosure, 
                   cgRhsClosure,
+                  emitBlackHoleCode,
                   ) where
 
 #include "HsVersions.h"
@@ -21,37 +22,38 @@ import {-# SOURCE #-} CgExpr ( cgExpr )
 
 import CgMonad
 import CgBindery
-import CgUpdate                ( pushUpdateFrame )
 import CgHeapery
-import CgStackery
-import CgUsages
+import CgStackery      ( mkVirtStkOffsets, pushUpdateFrame, getVirtSp,
+                         setRealAndVirtualSp )
+import CgProf          ( chooseDynCostCentres, ldvEnter, enterCostCentre,
+                         costCentreFrom )
+import CgTicky
+import CgParallel      ( granYield, granFetchAndReschedule )
+import CgInfoTbls      ( emitClosureCodeAndInfoTable, getSRTInfo )
+import CgCallConv      ( assignCallRegs, mkArgDescr )
+import CgUtils         ( emitDataLits, addIdReps, cmmRegOffW, 
+                         emitRtsCallWithVols )
 import ClosureInfo     -- lots and lots of stuff
-
-import AbsCUtils       ( getAmodeRep, mkAbstractCs )
-import AbsCSyn
-import CLabel
-
+import SMRep           ( CgRep, cgRepSizeW, argMachRep, fixedHdrSize, WordOff,
+                         idCgRep )
+import MachOp          ( MachHint(..) )
+import Cmm
+import CmmUtils                ( CmmStmts, mkStmts, oneStmt, plusStmts, noStmts,
+                         mkLblExpr )
+import CLabel          ( mkRtsDataLabel, mkClosureLabel, mkRednCountsLabel,
+                         mkSlowEntryLabel, mkIndStaticInfoLabel )
 import StgSyn
-import CmdLineOpts     ( opt_GranMacros, opt_SccProfilingOn, opt_DoTickyProfiling )
+import CmdLineOpts     ( opt_DoTickyProfiling )
 import CostCentre      
-import Id              ( Id, idName, idType, idPrimRep )
-import Name            ( Name, isInternalName )
+import Id              ( Id, idName, idType )
+import Name            ( Name )
 import Module          ( Module, pprModule )
 import ListSetOps      ( minusList )
-import PrimRep         ( PrimRep(..), getPrimRepSize )
-import Util            ( isIn, splitAtList )
-import CmdLineOpts     ( opt_SccProfilingOn )
+import Util            ( isIn, mapAccumL, zipWithEqual )
+import BasicTypes      ( TopLevelFlag(..) )
+import Constants       ( oFFSET_StgInd_indirectee, wORD_SIZE )
 import Outputable
 import FastString
-
-import Name             ( nameOccName )
-import OccName          ( occNameFS )
-
--- Turgid imports for showTypeCategory
-import PrelNames
-import TcType          ( Type, isDictTy, tcSplitTyConApp_maybe, tcSplitFunTy_maybe )
-import TyCon           ( isPrimTyCon, isTupleTyCon, isEnumerationTyCon, maybeTyConSingleCon )
-import Maybe
 \end{code}
 
 %********************************************************
@@ -68,45 +70,29 @@ cgTopRhsClosure :: Id
                -> CostCentreStack      -- Optional cost centre annotation
                -> StgBinderInfo
                -> SRT
+               -> UpdateFlag
                -> [Id]         -- Args
                -> StgExpr
-               -> LambdaFormInfo
                -> FCode (Id, CgIdInfo)
 
-cgTopRhsClosure id ccs binder_info srt args body lf_info
-  = 
-    let
-       name          = idName id
-    in
-    -- LAY OUT THE OBJECT
-    getSRTInfo name srt                `thenFC` \ srt_info ->
-    moduleName                 `thenFC` \ mod_name ->
-    let
-       name          = idName id
-       descr         = closureDescription mod_name name
-       closure_info  = layOutStaticNoFVClosure id lf_info srt_info descr
+cgTopRhsClosure id ccs binder_info srt upd_flag args body = do
+  {    -- LAY OUT THE OBJECT
+    let name = idName id
+  ; lf_info  <- mkClosureLFInfo id TopLevel [] upd_flag args
+  ; srt_info <- getSRTInfo name srt
+  ; mod_name <- moduleName
+  ; let descr         = closureDescription mod_name name
+       closure_info  = mkClosureInfo True id lf_info 0 0 srt_info descr
        closure_label = mkClosureLabel name
-       cg_id_info    = stableAmodeIdInfo id (CLbl closure_label PtrRep) lf_info
-    in
-
-       -- BUILD THE OBJECT (IF NECESSARY)
-    (
-     ({- if staticClosureRequired name binder_info lf_info
-      then -}
-       absC (mkStaticClosure closure_label closure_info ccs [] True)
-      {- else
-       nopC -}
-     )
-                                                       `thenC`
-
-       -- GENERATE THE INFO TABLE (IF NECESSARY)
-    forkClosureBody (closureCodeBody binder_info closure_info
-                                        ccs args body)
+       cg_id_info    = stableIdInfo id (mkLblExpr closure_label) lf_info
+       closure_rep   = mkStaticClosureFields closure_info ccs True []
 
-    ) `thenC`
-
-    returnFC (id, cg_id_info)
+        -- BUILD THE OBJECT, AND GENERATE INFO TABLE (IF NECESSARY)
+  ; emitDataLits closure_label closure_rep
+  ; forkClosureBody (closureCodeBody binder_info closure_info
+                                    ccs args body)
 
+  ; returnFC (id, cg_id_info) }
 \end{code}
 
 %********************************************************
@@ -129,29 +115,26 @@ cgStdRhsClosure
        -> [StgArg]             -- payload
        -> FCode (Id, CgIdInfo)
 
-cgStdRhsClosure binder cc binder_info fvs args body lf_info payload
-               -- AHA!  A STANDARD-FORM THUNK
-  = (
-       -- LAY OUT THE OBJECT
-    getArgAmodes payload               `thenFC` \ amodes ->
-    moduleName                         `thenFC` \ mod_name ->
-    let
-       descr = closureDescription mod_name (idName binder)
-
-       (closure_info, amodes_w_offsets)
-         = layOutDynClosure binder getAmodeRep amodes lf_info NoC_SRT descr
-               -- No SRT for a standard-form closure
-
-       (use_cc, blame_cc) = chooseDynCostCentres cc args fvs body
-    in
+cgStdRhsClosure bndr cc bndr_info fvs args body lf_info payload 
+  = do -- AHA!  A STANDARD-FORM THUNK
+  {    -- LAY OUT THE OBJECT
+    amodes <- getArgAmodes payload
+  ; mod_name <- moduleName
+  ; let (tot_wds, ptr_wds, amodes_w_offsets) = mkVirtHeapOffsets amodes
+
+       descr        = closureDescription mod_name (idName bndr)
+       closure_info = mkClosureInfo False      -- Not static
+                                    bndr lf_info tot_wds ptr_wds 
+                                    NoC_SRT    -- No SRT for a std-form closure
+                                    descr
+               
+  ; (use_cc, blame_cc) <- chooseDynCostCentres cc args body
 
        -- BUILD THE OBJECT
-    allocDynClosure closure_info use_cc blame_cc amodes_w_offsets
-    )
-               `thenFC` \ heap_offset ->
+  ; heap_offset <- allocDynClosure closure_info use_cc blame_cc amodes_w_offsets
 
        -- RETURN
-    returnFC (binder, heapIdInfo binder heap_offset lf_info)
+  ; returnFC (bndr, heapIdInfo bndr heap_offset lf_info) }
 \end{code}
 
 Here's the general case.
@@ -162,15 +145,13 @@ cgRhsClosure      :: Id
                -> StgBinderInfo
                -> SRT
                -> [Id]                 -- Free vars
+               -> UpdateFlag
                -> [Id]                 -- Args
                -> StgExpr
-               -> LambdaFormInfo
                -> FCode (Id, CgIdInfo)
 
-cgRhsClosure binder cc binder_info srt fvs args body lf_info
-  = (
-       -- LAY OUT THE OBJECT
-       --
+cgRhsClosure bndr cc bndr_info srt fvs upd_flag args body = do
+  {    -- LAY OUT THE OBJECT
        -- If the binder is itself a free variable, then don't store
        -- it in the closure.  Instead, just bind it to Node on entry.
        -- NB we can be sure that Node will point to it, because we
@@ -179,62 +160,63 @@ cgRhsClosure binder cc binder_info srt fvs args body lf_info
        -- stored in the closure itself, so it will make sure that
        -- Node points to it...
     let
-       is_elem        = isIn "cgRhsClosure"
-
-       binder_is_a_fv = binder `is_elem` fvs
-       reduced_fvs    = if binder_is_a_fv
-                        then fvs `minusList` [binder]
-                        else fvs
-
-       name = idName binder
-    in
-
-    mapFCs getCAddrModeAndInfo reduced_fvs     `thenFC` \ fvs_w_amodes_and_info ->
-    getSRTInfo name srt                                `thenFC` \ srt_info ->
-    moduleName                                 `thenFC` \ mod_name ->
-    let
-       descr = closureDescription mod_name (idName binder)
-
-       closure_info :: ClosureInfo
-       bind_details :: [((Id, CAddrMode, LambdaFormInfo), VirtualHeapOffset)]
-
-       (closure_info, bind_details)
-         = layOutDynClosure binder get_kind
-                            fvs_w_amodes_and_info lf_info srt_info descr
-
-       bind_fv ((id, _, lf_info), offset) = bindNewToNode id offset lf_info
-
-       amodes_w_offsets = [(amode,offset) | ((_,amode,_), offset) <- bind_details]
-
-       get_kind (id, _, _) = idPrimRep id
-    in
+       name         = idName bndr
+       is_elem      = isIn "cgRhsClosure"
+       bndr_is_a_fv = bndr `is_elem` fvs
+       reduced_fvs | bndr_is_a_fv = fvs `minusList` [bndr]
+                   | otherwise    = fvs
+
+  ; lf_info <- mkClosureLFInfo bndr NotTopLevel fvs upd_flag args
+  ; fv_infos <- mapFCs getCgIdInfo reduced_fvs
+  ; srt_info <- getSRTInfo name srt
+  ; mod_name <- moduleName
+  ; let        bind_details :: [(CgIdInfo, VirtualHpOffset)]
+       (tot_wds, ptr_wds, bind_details) = mkVirtHeapOffsets (map add_rep fv_infos)
+       add_rep info = (cgIdInfoArgRep info, info)
+
+       descr        = closureDescription mod_name name
+       closure_info = mkClosureInfo False      -- Not static
+                                    bndr lf_info tot_wds ptr_wds
+                                    srt_info descr
 
        -- BUILD ITS INFO TABLE AND CODE
-    forkClosureBody (
-               -- Bind the fvs
-           mapCs bind_fv bind_details `thenC`
+  ; forkClosureBody (do
+       {       -- Bind the fvs
+         let bind_fv (info, offset) 
+               = bindNewToNode (cgIdInfoId info) offset (cgIdInfoLF info)
+       ; mapCs bind_fv bind_details
 
                -- Bind the binder itself, if it is a free var
-           (if binder_is_a_fv then
-               bindNewToReg binder node lf_info
-           else
-               nopC)                                   `thenC`
-
+       ; whenC bndr_is_a_fv (bindNewToReg bndr nodeReg lf_info)
+       
                -- Compile the body
-           closureCodeBody binder_info closure_info cc args body
-    )  `thenC`
+       ; closureCodeBody bndr_info closure_info cc args body })
 
        -- BUILD THE OBJECT
-    let
-       (use_cc, blame_cc) = chooseDynCostCentres cc args fvs body
-    in
-    allocDynClosure closure_info use_cc blame_cc amodes_w_offsets
-    )          `thenFC` \ heap_offset ->
+  ; let
+       to_amode (info, offset) = do { amode <- idInfoToAmode info
+                                    ; return (amode, offset) }
+  ; (use_cc, blame_cc) <- chooseDynCostCentres cc args body
+  ; amodes_w_offsets <- mapFCs to_amode bind_details
+  ; heap_offset <- allocDynClosure closure_info use_cc blame_cc amodes_w_offsets
 
        -- RETURN
-    returnFC (binder, heapIdInfo binder heap_offset lf_info)
+  ; returnFC (bndr, heapIdInfo bndr heap_offset lf_info) }
+
+
+mkClosureLFInfo :: Id          -- The binder
+               -> TopLevelFlag -- True of top level
+               -> [Id]         -- Free vars
+               -> UpdateFlag   -- Update flag
+               -> [Id]         -- Args
+               -> FCode LambdaFormInfo
+mkClosureLFInfo bndr top fvs upd_flag args
+  | null args = return (mkLFThunk (idType bndr) top fvs upd_flag)
+  | otherwise = do { arg_descr <- mkArgDescr (idName bndr) args
+                  ; return (mkLFReEntrant top fvs args arg_descr) }
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
 \subsection[code-for-closures]{The code for closures}
@@ -253,32 +235,23 @@ closureCodeBody :: StgBinderInfo
 There are two main cases for the code for closures.  If there are {\em
 no arguments}, then the closure is a thunk, and not in normal form.
 So it should set up an update frame (if it is shared).
+NB: Thunks cannot have a primitive type!
 
 \begin{code}
-closureCodeBody binder_info closure_info cc [] body
-  = -- thunks cannot have a primitive type!
-    getAbsC body_code  `thenFC` \ body_absC ->
-
-    absC (CClosureInfoAndCode closure_info body_absC)
-  where
-    is_box  = case body of { StgApp fun [] -> True; _ -> False }
-
-    ticky_ent_lit = if (isStaticClosure closure_info)
-                    then FSLIT("TICK_ENT_STATIC_THK")
-                    else FSLIT("TICK_ENT_DYN_THK")
-
-    body_code   = profCtrC ticky_ent_lit []                    `thenC`
-                 -- node always points when profiling, so this is ok:
-                 ldvEnter                                      `thenC`
-                 thunkWrapper closure_info (
-                       -- We only enter cc after setting up update so
-                       -- that cc of enclosing scope will be recorded
-                       -- in update frame CAF/DICT functions will be
-                       -- subsumed by this enclosing cc
-                   enterCostCentreCode closure_info cc IsThunk is_box `thenC`
-                   cgExpr body
-                 )
-
+closureCodeBody binder_info cl_info cc [] body = do
+  { body_absC <- getCgStmts $ do
+       { tickyEnterThunk cl_info
+       ; ldvEnter (CmmReg nodeReg)  -- NB: Node always points when profiling
+       ; thunkWrapper cl_info $ do
+               -- We only enter cc after setting up update so
+               -- that cc of enclosing scope will be recorded
+               -- in update frame CAF/DICT functions will be
+               -- subsumed by this enclosing cc
+           { enterCostCentre cl_info cc body
+           ; cgExpr body }
+       }
+    
+  ; emitClosureCodeAndInfoTable cl_info [] body_absC }
 \end{code}
 
 If there is /at least one argument/, then this closure is in
@@ -289,105 +262,60 @@ argSatisfactionCheck (by calling fetchAndReschedule).  There info if
 Node points to closure is available. -- HWL
 
 \begin{code}
-closureCodeBody binder_info closure_info cc all_args body
-  = let arg_reps = map idPrimRep all_args in
-
-    getEntryConvention name lf_info arg_reps  `thenFC` \ entry_conv ->
-
-    let
-       -- Arg mapping for the entry point; as many args as poss in
-       -- registers; the rest on the stack
-       --      arg_regs are the registers used for arg passing
-       --      stk_args are the args which are passed on the stack
-       --
-       -- Args passed on the stack are not tagged.
-       --
-       arg_regs = case entry_conv of
-               DirectEntry lbl arity regs -> regs
-               _ -> panic "closureCodeBody"
-    in
-
-    -- If this function doesn't have a specialised ArgDescr, we need
-    -- to generate the function's arg bitmap, slow-entry code, and
-    -- register-save code for the heap-check failure
-    --
-    (case closureFunInfo closure_info of
-       Just (_, ArgGen slow_lbl liveness) -> 
-               absC (maybeLargeBitmap liveness) `thenC`
-               absC (mkSlowEntryCode name slow_lbl arg_regs arg_reps) `thenC`
-               returnFC (mkRegSaveCode arg_regs arg_reps)
-
-       other -> returnFC AbsCNop
-     )         
-       `thenFC` \ reg_save_code ->
-
-    -- get the current virtual Sp (it might not be zero, eg. if we're
-    -- compiling a let-no-escape).
-    getVirtSp `thenFC` \vSp ->
-
-    let
-       (reg_args, stk_args) = splitAtList arg_regs all_args
-
-       (sp_stk_args, stk_offsets)
-         = mkVirtStkOffsets vSp idPrimRep stk_args
-
-       entry_code = do
-               mod_name <- moduleName
-               profCtrC FSLIT("TICK_CTR") [ 
-                       CLbl ticky_ctr_label DataPtrRep,
-                       mkCString (mkFastString (ppr_for_ticky_name mod_name name)),
-                       mkIntCLit stg_arity,    -- total # of args
-                       mkIntCLit sp_stk_args,  -- # passed on stk
-                       mkCString (mkFastString (map (showTypeCategory . idType) all_args))
-                       ] 
-               let prof = 
-                       profCtrC ticky_ent_lit [
-                               CLbl ticky_ctr_label DataPtrRep
-                       ] 
-
-               -- Bind args to regs/stack as appropriate, and
-               -- record expected position of sps.
-               bindArgsToRegs reg_args arg_regs                    
-               mapCs bindNewToStack stk_offsets                    
-               setRealAndVirtualSp sp_stk_args             
-
-               -- Enter the closures cc, if required
-               enterCostCentreCode closure_info cc IsFunction False
-
-               -- Do the business
-               funWrapper closure_info arg_regs reg_save_code
-                       (prof >> cgExpr body)
-    in
-
-    setTickyCtrLabel ticky_ctr_label (
-
-      forkAbsC entry_code      `thenFC` \ entry_abs_c ->
-      moduleName               `thenFC` \ mod_name ->
-
-      -- Now construct the info table
-      absC (CClosureInfoAndCode closure_info entry_abs_c)
-    )
-  where
-    ticky_ctr_label = mkRednCountsLabel name
-
-    ticky_ent_lit = 
-        if (isStaticClosure closure_info)
-        then FSLIT("TICK_ENT_STATIC_FUN_DIRECT")
-        else FSLIT("TICK_ENT_DYN_FUN_DIRECT")
-        
-    stg_arity = length all_args
-    lf_info = closureLFInfo closure_info
-
-       -- Manufacture labels
-    name       = closureName closure_info
-
-
--- When printing the name of a thing in a ticky file, we want to
--- give the module name even for *local* things.   We print
--- just "x (M)" rather that "M.x" to distinguish them from the global kind.
-ppr_for_ticky_name mod_name name
-  | isInternalName name = showSDocDebug (ppr name <+> (parens (ppr mod_name)))
-  | otherwise       = showSDocDebug (ppr name)
+closureCodeBody binder_info cl_info cc args body = do
+  {    -- Get the current virtual Sp (it might not be zero, 
+       -- eg. if we're compiling a let-no-escape).
+    vSp <- getVirtSp
+  ; let (reg_args, other_args) = assignCallRegs (addIdReps args)
+       (sp_top, stk_args)     = mkVirtStkOffsets vSp other_args
+
+       -- Allocate the global ticky counter
+  ; let ticky_ctr_lbl = mkRednCountsLabel (closureName cl_info)
+  ; emitTickyCounter cl_info args sp_top
+
+       -- ...and establish the ticky-counter 
+       -- label for this block
+  ; setTickyCtrLabel ticky_ctr_lbl $ do
+
+       -- Emit the slow-entry code
+  { reg_save_code <- mkSlowEntryCode cl_info reg_args
+
+       -- Emit the main entry code
+  ; blks <- forkProc $
+           mkFunEntryCode cl_info cc reg_args stk_args
+                          sp_top reg_save_code body
+  ; emitClosureCodeAndInfoTable cl_info [] blks
+  }}
+
+
+
+mkFunEntryCode :: ClosureInfo
+              -> CostCentreStack
+              -> [(Id,GlobalReg)]        -- Args in regs
+              -> [(Id,VirtualSpOffset)]  -- Args on stack
+              -> VirtualSpOffset         -- Last allocated word on stack
+              -> CmmStmts                -- Register-save code in case of GC
+              -> StgExpr
+              -> Code
+-- The main entry code for the closure
+mkFunEntryCode cl_info cc reg_args stk_args sp_top reg_save_code body = do
+  {    -- Bind args to regs/stack as appropriate,
+       -- and record expected position of sps
+  ; bindArgsToRegs  reg_args
+  ; bindArgsToStack stk_args
+  ; setRealAndVirtualSp sp_top
+
+       -- Enter the cost-centre, if required
+       -- ToDo: It's not clear why this is outside the funWrapper,
+       --       but the tickyEnterFun is inside. Perhaps we can put
+       --       them together?
+  ; enterCostCentre cl_info cc body
+
+       -- Do the business
+  ; funWrapper cl_info reg_args reg_save_code $ do
+       { tickyEnterFun cl_info
+       ; cgExpr body }
+  }
 \end{code}
 
 The "slow entry" code for a function.  This entry point takes its
@@ -402,84 +330,45 @@ The slow entry point is used in two places:
  (b) returning from a heap-check failure
 
 \begin{code}
-mkSlowEntryCode :: Name -> CLabel -> [MagicId] -> [PrimRep] -> AbstractC
-mkSlowEntryCode name lbl regs reps
-   = CCodeBlock lbl (
-       mkAbstractCs [assts, stk_adj, jump]
-      )
+mkSlowEntryCode :: ClosureInfo -> [(Id,GlobalReg)] -> FCode CmmStmts
+-- If this function doesn't have a specialised ArgDescr, we need
+-- to generate the function's arg bitmap, slow-entry code, and
+-- register-save code for the heap-check failure
+-- Here, we emit the slow-entry code, and 
+-- return the register-save assignments
+mkSlowEntryCode cl_info reg_args
+  | Just (_, ArgGen _) <- closureFunInfo cl_info
+  = do         { emitSimpleProc slow_lbl (emitStmts load_stmts)
+       ; return save_stmts }
+  | otherwise = return noStmts
   where
-     stk_offsets = scanl (\off rep -> off - getPrimRepSize rep) 0 reps
-
-     assts = mkAbstractCs (zipWith3 mk_asst reps regs stk_offsets)
-     mk_asst rep reg offset = CAssign (CReg reg) (CVal (spRel 0 offset) rep)
-
-     stk_adj = CAssign (CReg Sp) (CAddr (spRel 0 stk_final_offset))
-     stk_final_offset = head (drop (length regs) stk_offsets)
-
-     jump = CJump (CLbl (mkEntryLabel name) CodePtrRep)
-
-mkRegSaveCode :: [MagicId] -> [PrimRep] -> AbstractC
-mkRegSaveCode regs reps 
-  = mkAbstractCs [stk_adj, assts]
-  where
-     stk_adj = CAssign (CReg Sp) (CAddr (spRel 0 (negate stk_final_offset)))
-
-     stk_final_offset = head (drop (length regs) stk_offsets)
-     stk_offsets = scanl (\off rep -> off - getPrimRepSize rep) 0 reps
-
-     assts = mkAbstractCs (zipWith3 mk_asst reps regs stk_offsets)
-     mk_asst rep reg offset = CAssign (CVal (spRel 0 offset) rep) (CReg reg) 
+     name = closureName cl_info
+     slow_lbl = mkSlowEntryLabel name
+
+     load_stmts = mkStmts load_assts `plusStmts` mkStmts [stk_adj_pop, jump_to_entry]
+     save_stmts = oneStmt stk_adj_push `plusStmts`  mkStmts save_assts
+
+     reps_w_regs :: [(CgRep,GlobalReg)]
+     reps_w_regs = [(idCgRep id, reg) | (id,reg) <- reverse reg_args]
+     (final_stk_offset, stk_offsets)
+       = mapAccumL (\off (rep,_) -> (off + cgRepSizeW rep, off))
+                   0 reps_w_regs
+
+     load_assts = zipWithEqual "mk_load" mk_load reps_w_regs stk_offsets
+     mk_load (rep,reg) offset = CmmAssign (CmmGlobal reg) 
+                                         (CmmLoad (cmmRegOffW spReg offset)
+                                                  (argMachRep rep))
+
+     save_assts = zipWithEqual "mk_save" mk_save reps_w_regs stk_offsets
+     mk_save (rep,reg) offset = ASSERT( argMachRep rep == globalRegRep reg )
+                               CmmStore (cmmRegOffW spReg offset) 
+                                        (CmmReg (CmmGlobal reg))
+
+     stk_adj_pop   = CmmAssign spReg (cmmRegOffW spReg final_stk_offset)
+     stk_adj_push  = CmmAssign spReg (cmmRegOffW spReg (- final_stk_offset))
+     jump_to_entry = CmmJump (mkLblExpr (enterIdLabel name)) []
 \end{code}
 
-For lexically scoped profiling we have to load the cost centre from
-the closure entered, if the costs are not supposed to be inherited.
-This is done immediately on entering the fast entry point.
-
-Load current cost centre from closure, if not inherited.
-Node is guaranteed to point to it, if profiling and not inherited.
-
-\begin{code}
-data IsThunk = IsThunk | IsFunction -- Bool-like, local
--- #ifdef DEBUG
-       deriving Eq
--- #endif
-
-enterCostCentreCode 
-   :: ClosureInfo -> CostCentreStack
-   -> IsThunk
-   -> Bool     -- is_box: this closure is a special box introduced by SCCfinal
-   -> Code
-
-enterCostCentreCode closure_info ccs is_thunk is_box
-  = if not opt_SccProfilingOn then
-       nopC
-    else
-       ASSERT2(not (noCCSAttached ccs), ppr (closureName closure_info) <+> ppr ccs)
-
-       if isSubsumedCCS ccs then
-           ASSERT(isToplevClosure closure_info)
-           ASSERT(is_thunk == IsFunction)
-           costCentresC FSLIT("ENTER_CCS_FSUB") []
-       else if isDerivedFromCurrentCCS ccs then 
-           if re_entrant && not is_box
-               then costCentresC FSLIT("ENTER_CCS_FCL") [CReg node]
-               else costCentresC FSLIT("ENTER_CCS_TCL") [CReg node]
-
-       else if isCafCCS ccs then
-           ASSERT(isToplevClosure closure_info)
-           ASSERT(is_thunk == IsThunk)
-               -- might be a PAP, in which case we want to subsume costs
-           if re_entrant
-               then costCentresC FSLIT("ENTER_CCS_FSUB") []
-               else costCentresC FSLIT("ENTER_CCS_CAF") c_ccs
-
-       else panic "enterCostCentreCode"
-
-   where
-       c_ccs = [mkCCostCentreStack ccs]
-       re_entrant = closureReEntrant closure_info
-\end{code}
 
 %************************************************************************
 %*                                                                     *
@@ -489,62 +378,42 @@ enterCostCentreCode closure_info ccs is_thunk is_box
 
 \begin{code}
 thunkWrapper:: ClosureInfo -> Code -> Code
-thunkWrapper closure_info thunk_code
-  =    -- Stack and heap overflow checks
-    nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points ->
+thunkWrapper closure_info thunk_code = do
+  { let node_points = nodeMustPointToIt (closureLFInfo closure_info)
 
     -- HWL: insert macros for GrAnSim; 2 versions depending on liveness of node
     -- (we prefer fetchAndReschedule-style context switches to yield ones)
-    (if opt_GranMacros
-       then if node_points 
-              then fetchAndReschedule [] node_points 
-              else yield [] node_points
-       else absC AbsCNop)                       `thenC`
-
-    let closure_lbl
-               | node_points = Nothing
-               | otherwise   = Just (closureLabelFromCI closure_info)
-    in
-
-        -- stack and/or heap checks
-    thunkChecks closure_lbl (
-
-       -- Overwrite with black hole if necessary
-    blackHoleIt closure_info node_points  `thenC`
-
-    setupUpdate closure_info (                 -- setupUpdate *encloses* the rest
-
-       -- Finally, do the business
-    thunk_code
-    ))
+  ; if node_points 
+    then granFetchAndReschedule [] node_points 
+    else granYield             [] node_points
+
+        -- Stack and/or heap checks
+  ; thunkEntryChecks closure_info $ do
+       {       -- Overwrite with black hole if necessary
+         whenC (blackHoleOnEntry closure_info && node_points)
+               (blackHoleIt closure_info)
+       ; setupUpdate closure_info thunk_code }
+               -- setupUpdate *encloses* the thunk_code
+  }
 
 funWrapper :: ClosureInfo      -- Closure whose code body this is
-          -> [MagicId]         -- List of argument registers (if any)
-          -> AbstractC         -- reg saves for the heap check failure
+          -> [(Id,GlobalReg)]  -- List of argument registers (if any)
+          -> CmmStmts          -- reg saves for the heap check failure
           -> Code              -- Body of function being compiled
           -> Code
-funWrapper closure_info arg_regs reg_save_code fun_body
-  =    -- Stack overflow check
-    nodeMustPointToIt (closureLFInfo closure_info)  `thenFC` \ node_points ->
-
-    -- enter for Ldv profiling
-    (if node_points then ldvEnter else nopC)       `thenC`
+funWrapper closure_info arg_regs reg_save_code fun_body = do
+  { let node_points = nodeMustPointToIt (closureLFInfo closure_info)
 
-    (if opt_GranMacros
-       then yield arg_regs node_points
-       else absC AbsCNop)                           `thenC`
+       -- Enter for Ldv profiling
+  ; whenC node_points (ldvEnter (CmmReg nodeReg))
 
-    let closure_lbl
-               | node_points = Nothing
-               | otherwise   = Just (closureLabelFromCI closure_info)
-    in
+       -- GranSim yeild poin
+  ; granYield arg_regs node_points
 
-        -- heap and/or stack checks
-    funEntryChecks closure_lbl reg_save_code (
-
-       -- Finally, do the business
-    fun_body
-    )
+        -- Heap and/or stack checks wrap the function body
+  ; funEntryChecks closure_info reg_save_code 
+                  fun_body
+  }
 \end{code}
 
 
@@ -556,78 +425,150 @@ funWrapper closure_info arg_regs reg_save_code fun_body
 
 
 \begin{code}
-blackHoleIt :: ClosureInfo -> Bool -> Code     -- Only called for closures with no args
-
-blackHoleIt closure_info node_points
-  = if blackHoleOnEntry closure_info && node_points
-    then
-       let
-         info_label = infoTableLabelFromCI closure_info
-         args = [ CLbl info_label DataPtrRep ]
-       in
-       absC (if closureSingleEntry(closure_info) then
-               CMacroStmt UPD_BH_SINGLE_ENTRY args
-             else
-               CMacroStmt UPD_BH_UPDATABLE args)
-    else
+blackHoleIt :: ClosureInfo -> Code
+-- Only called for closures with no args
+-- Node points to the closure
+blackHoleIt closure_info = emitBlackHoleCode (closureSingleEntry closure_info)
+
+emitBlackHoleCode :: Bool -> Code
+emitBlackHoleCode is_single_entry 
+  | eager_blackholing = do 
+       tickyBlackHole (not is_single_entry)
+       stmtC (CmmStore (CmmReg nodeReg) (CmmLit (CmmLabel bh_lbl)))
+  | otherwise = 
        nopC
+  where
+    bh_lbl | is_single_entry = mkRtsDataLabel SLIT("stg_SE_BLACKHOLE_info")
+          | otherwise       = mkRtsDataLabel SLIT("stg_BLACKHOLE_info")
+
+       -- If we wanted to do eager blackholing with slop filling,
+       -- we'd need to do it at the *end* of a basic block, otherwise
+       -- we overwrite the free variables in the thunk that we still
+       -- need.  We have a patch for this from Andy Cheadle, but not
+       -- incorporated yet. --SDM [6/2004]
+       --
+       -- Profiling needs slop filling (to support LDV profiling), so
+       -- currently eager blackholing doesn't work with profiling.
+       --
+       -- TICKY_TICKY needs EAGER_BLACKHOLING to verify no double-entries of
+       -- single-entry thunks.
+    eager_blackholing 
+       | opt_DoTickyProfiling = True
+       | otherwise            = False
+
 \end{code}
 
 \begin{code}
 setupUpdate :: ClosureInfo -> Code -> Code     -- Only called for closures with no args
        -- Nota Bene: this function does not change Node (even if it's a CAF),
        -- so that the cost centre in the original closure can still be
-       -- extracted by a subsequent ENTER_CC_TCL
-
--- I've tidied up the code for this function, but it should still do the same as
--- it did before (modulo ticky stuff).  KSW 1999-04.
+       -- extracted by a subsequent enterCostCentre
 setupUpdate closure_info code
- = if closureReEntrant closure_info
-   then
-     code
-   else
-     case (closureUpdReqd closure_info, isStaticClosure closure_info) of
-       (False,False) -> profCtrC FSLIT("TICK_UPDF_OMITTED") [] `thenC`
-                       code
-       (False,True ) -> (if opt_DoTickyProfiling
-                         then
-                         -- blackhole the SE CAF
-                           link_caf seCafBlackHoleClosureInfo `thenFC` \ _ -> nopC
-                         else
-                           nopC)                                                       `thenC`
-                        profCtrC FSLIT("TICK_UPD_CAF_BH_SINGLE_ENTRY") [mkCString cl_name] `thenC`
-                        profCtrC FSLIT("TICK_UPDF_OMITTED") []                           `thenC`
-                       code
-       (True ,False) -> pushUpdateFrame (CReg node) code
-       (True ,True ) -> -- blackhole the (updatable) CAF:
-                        link_caf cafBlackHoleClosureInfo           `thenFC` \ update_closure ->
-                        profCtrC FSLIT("TICK_UPD_CAF_BH_UPDATABLE") [mkCString cl_name]    `thenC`
-                        pushUpdateFrame update_closure code
- where
-   cl_name :: FastString
-   cl_name  = (occNameFS . nameOccName . closureName) closure_info
-
-   link_caf :: (ClosureInfo -> ClosureInfo)  -- function yielding BH closure_info
-            -> FCode CAddrMode              -- Returns amode for closure to be updated
-   link_caf bhCI
-     = -- To update a CAF we must allocate a black hole, link the CAF onto the
-       -- CAF list, then update the CAF to point to the fresh black hole.
-       -- This function returns the address of the black hole, so it can be
-       -- updated with the new value when available.
-
-             -- Alloc black hole specifying CC_HDR(Node) as the cost centre
-       let
-           use_cc   = CMacroExpr PtrRep CCS_HDR [nodeReg]
-           blame_cc = use_cc
-       in
-       allocDynClosure (bhCI closure_info) use_cc blame_cc []  `thenFC` \ heap_offset ->
-       getHpRelOffset heap_offset                              `thenFC` \ hp_rel ->
-       let  amode = CAddr hp_rel
-       in
-       absC (CMacroStmt UPD_CAF [CReg node, amode])            `thenC`
-       returnFC amode
+  | closureReEntrant closure_info
+  = code
+
+  | not (isStaticClosure closure_info)
+  = if closureUpdReqd closure_info
+    then do { tickyPushUpdateFrame;  pushUpdateFrame (CmmReg nodeReg) code }
+    else do { tickyUpdateFrameOmitted; code }
+  | otherwise  -- A static closure
+  = do         { tickyUpdateBhCaf closure_info
+
+       ; if closureUpdReqd closure_info
+         then do       -- Blackhole the (updatable) CAF:
+               { upd_closure <- link_caf closure_info True
+               ; pushUpdateFrame upd_closure code }
+         else do
+               {       -- No update reqd, you'd think we don't need to 
+                       -- black-hole it. But when ticky-ticky is on, we 
+                       -- black-hole it regardless, to catch errors in which
+                       -- an allegedly single-entry closure is entered twice
+                       --
+                       -- We discard the pointer returned by link_caf, because
+                       -- we don't push an update frame
+                 whenC opt_DoTickyProfiling -- Blackhole even a SE CAF
+                       (link_caf closure_info False >> nopC)
+               ; tickyUpdateFrameOmitted
+               ; code }
+    }
+
+
+-----------------------------------------------------------------------------
+-- Entering a CAF
+--
+-- When a CAF is first entered, it creates a black hole in the heap,
+-- and updates itself with an indirection to this new black hole.
+--
+-- We update the CAF with an indirection to a newly-allocated black
+-- hole in the heap.  We also set the blocking queue on the newly
+-- allocated black hole to be empty.
+--
+-- Why do we make a black hole in the heap when we enter a CAF?
+--    
+--     - for a  generational garbage collector, which needs a fast
+--       test for whether an updatee is in an old generation or not
+--
+--     - for the parallel system, which can implement updates more
+--       easily if the updatee is always in the heap. (allegedly).
+--
+-- When debugging, we maintain a separate CAF list so we can tell when
+-- a CAF has been garbage collected.
+
+-- newCAF must be called before the itbl ptr is overwritten, since
+-- newCAF records the old itbl ptr in order to do CAF reverting
+-- (which Hugs needs to do in order that combined mode works right.)
+--
+
+-- ToDo [Feb 04]  This entire link_caf nonsense could all be moved
+-- into the "newCAF" RTS procedure, which we call anyway, including
+-- the allocation of the black-hole indirection closure.
+-- That way, code size would fall, the CAF-handling code would 
+-- be closer together, and the compiler wouldn't need to know
+-- about off_indirectee etc.
+
+link_caf :: ClosureInfo
+        -> Bool                -- True <=> updatable, False <=> single-entry
+         -> FCode CmmExpr       -- Returns amode for closure to be updated
+-- To update a CAF we must allocate a black hole, link the CAF onto the
+-- CAF list, then update the CAF to point to the fresh black hole.
+-- This function returns the address of the black hole, so it can be
+-- updated with the new value when available.  The reason for all of this
+-- is that we only want to update dynamic heap objects, not static ones,
+-- so that generational GC is easier.
+link_caf cl_info is_upd = do
+  {    -- Alloc black hole specifying CC_HDR(Node) as the cost centre
+  ; let        use_cc   = costCentreFrom (CmmReg nodeReg)
+        blame_cc = use_cc
+  ; hp_offset <- allocDynClosure bh_cl_info use_cc blame_cc []
+  ; hp_rel    <- getHpRelOffset hp_offset
+
+       -- Call the RTS function newCAF to add the CAF to the CafList
+       -- so that the garbage collector can find them
+       -- This must be done *before* the info table pointer is overwritten, 
+       -- because the old info table ptr is needed for reversion
+  ; emitRtsCallWithVols SLIT("newCAF") [(CmmReg nodeReg,PtrHint)] [node]
+       -- node is live, so save it.
+
+       -- Overwrite the closure with a (static) indirection 
+       -- to the newly-allocated black hole
+  ; stmtsC [ CmmStore (cmmRegOffW nodeReg off_indirectee) hp_rel
+          , CmmStore (CmmReg nodeReg) ind_static_info ]
+
+  ; returnFC hp_rel }
+  where
+    bh_cl_info :: ClosureInfo
+    bh_cl_info | is_upd    = cafBlackHoleClosureInfo   cl_info
+              | otherwise = seCafBlackHoleClosureInfo cl_info
+
+    ind_static_info :: CmmExpr
+    ind_static_info = mkLblExpr mkIndStaticInfoLabel
+
+    off_indirectee :: WordOff
+    off_indirectee = fixedHdrSize + oFFSET_StgInd_indirectee*wORD_SIZE
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
 \subsection[CgClosure-Description]{Profiling Closure Description.}
@@ -635,99 +576,17 @@ setupUpdate closure_info code
 %************************************************************************
 
 For "global" data constructors the description is simply occurrence
-name of the data constructor itself (see \ref{CgConTbls-info-tables}).
-
-Otherwise it is determind by @closureDescription@ from the let
-binding information.
+name of the data constructor itself.  Otherwise it is determined by
+@closureDescription@ from the let binding information.
 
 \begin{code}
 closureDescription :: Module           -- Module
                   -> Name              -- Id of closure binding
                   -> String
-
        -- Not called for StgRhsCon which have global info tables built in
        -- CgConTbls.lhs with a description generated from the data constructor
-
 closureDescription mod_name name
-  = showSDoc (
-       hcat [char '<',
-                  pprModule mod_name,
-                  char '.',
-                  ppr name,
-                  char '>'])
+  = showSDoc (hcat [char '<', pprModule mod_name,
+                   char '.', ppr name, char '>'])
 \end{code}
   
-\begin{code}
-chooseDynCostCentres ccs args fvs body
-  = let
-       use_cc -- cost-centre we record in the object
-         = if currentOrSubsumedCCS ccs
-           then CReg CurCostCentre
-           else mkCCostCentreStack ccs
-
-       blame_cc -- cost-centre on whom we blame the allocation
-         = case (args, fvs, body) of
-             ([], _, StgApp fun [{-no args-}])
-               -> mkCCostCentreStack overheadCCS
-             _ -> use_cc
-
-           -- if it's an utterly trivial RHS, then it must be
-           -- one introduced by boxHigherOrderArgs for profiling,
-           -- so we charge it to "OVERHEAD".
-
-           -- This looks like a HACK to me --SDM
-    in
-    (use_cc, blame_cc)
-\end{code}
-
-
-\begin{code}
-showTypeCategory :: Type -> Char
-  {-
-       {C,I,F,D}   char, int, float, double
-       T           tuple
-       S           other single-constructor type
-       {c,i,f,d}   unboxed ditto
-       t           *unpacked* tuple
-       s           *unpacked" single-cons...
-
-       v           void#
-       a           primitive array
-
-       E           enumeration type
-       +           dictionary, unless it's a ...
-       L           List
-       >           function
-       M           other (multi-constructor) data-con type
-       .           other type
-       -           reserved for others to mark as "uninteresting"
-    -}
-showTypeCategory ty
-  = if isDictTy ty
-    then '+'
-    else
-      case tcSplitTyConApp_maybe ty of
-       Nothing -> if isJust (tcSplitFunTy_maybe ty)
-                  then '>'
-                  else '.'
-
-       Just (tycon, _) ->
-          let utc = getUnique tycon in
-         if      utc == charDataConKey    then 'C'
-         else if utc == intDataConKey     then 'I'
-         else if utc == floatDataConKey   then 'F'
-         else if utc == doubleDataConKey  then 'D'
-         else if utc == smallIntegerDataConKey ||
-                 utc == largeIntegerDataConKey   then 'J'
-         else if utc == charPrimTyConKey  then 'c'
-         else if (utc == intPrimTyConKey || utc == wordPrimTyConKey
-               || utc == addrPrimTyConKey)                then 'i'
-         else if utc  == floatPrimTyConKey                then 'f'
-         else if utc  == doublePrimTyConKey               then 'd'
-         else if isPrimTyCon tycon {- array, we hope -}   then 'A'     -- Bogus
-         else if isEnumerationTyCon tycon                 then 'E'
-         else if isTupleTyCon tycon                       then 'T'
-         else if isJust (maybeTyConSingleCon tycon)       then 'S'
-         else if utc == listTyConKey                      then 'L'
-         else 'M' -- oh, well...
-\end{code}
index 4b8e8c2..3cd67e4 100644 (file)
@@ -11,49 +11,53 @@ with {\em constructors} on the RHSs of let(rec)s.  See also
 module CgCon (
        cgTopRhsCon, buildDynCon,
        bindConArgs, bindUnboxedTupleComponents,
-       cgReturnDataCon
+       cgReturnDataCon,
+       cgTyCon
     ) where
 
 #include "HsVersions.h"
 
 import CgMonad
-import AbsCSyn
 import StgSyn
 
-import AbsCUtils       ( getAmodeRep )
 import CgBindery       ( getArgAmodes, bindNewToNode,
-                         bindArgsToRegs, 
-                         idInfoToAmode, stableAmodeIdInfo,
-                         heapIdInfo, CgIdInfo, bindNewToStack
+                         bindArgsToRegs, idInfoToAmode, stableIdInfo,
+                         heapIdInfo, CgIdInfo, bindArgsToStack
                        )
-import CgStackery      ( mkVirtStkOffsets, freeStackSlots )
-import CgUsages                ( getRealSp, getVirtSp, setRealAndVirtualSp )
-import CgRetConv       ( assignRegs )
+import CgStackery      ( mkVirtStkOffsets, freeStackSlots,
+                         getRealSp, getVirtSp, setRealAndVirtualSp )
+import CgUtils         ( addIdReps, cmmLabelOffW, emitRODataLits, emitDataLits )
+import CgCallConv      ( assignReturnRegs )
 import Constants       ( mAX_INTLIKE, mIN_INTLIKE, mAX_CHARLIKE, mIN_CHARLIKE )
-import CgHeapery       ( allocDynClosure )
-import CgTailCall      ( performReturn, mkStaticAlgReturnCode,
-                         returnUnboxedTuple )
-import CLabel          ( mkClosureLabel )
-import ClosureInfo     ( mkConLFInfo, mkLFArgument, layOutDynConstr, 
-                         layOutStaticConstr, mkStaticClosure
-                       )
+import CgHeapery       ( allocDynClosure, layOutDynConstr, 
+                         layOutStaticConstr, mkStaticClosureFields )
+import CgTailCall      ( performReturn, emitKnownConReturnCode, returnUnboxedTuple )
+import CgProf          ( mkCCostCentreStack, ldvEnter, curCCS )
+import CgTicky
+import CgInfoTbls      ( emitClosureCodeAndInfoTable, dataConTagZ )
+import CLabel          ( mkClosureLabel, mkRtsDataLabel, mkClosureTblLabel )
+import ClosureInfo     ( mkConLFInfo, mkLFArgument )
+import CmmUtils                ( mkLblExpr )
+import Cmm
+import SMRep           ( WordOff, CgRep, separateByPtrFollowness,
+                         fixedHdrSize, typeCgRep )
 import CostCentre      ( currentOrSubsumedCCS, dontCareCCS, CostCentreStack,
                          currentCCS )
-import DataCon         ( DataCon, dataConTag, 
+import Constants       ( mIN_INTLIKE, mAX_INTLIKE, mIN_CHARLIKE, mAX_CHARLIKE )
+import TyCon           ( TyCon, tyConDataCons, isEnumerationTyCon, tyConName )
+import DataCon         ( DataCon, dataConRepArgTys, isNullaryDataCon,
                          isUnboxedTupleCon, dataConWorkId, 
                          dataConName, dataConRepArity
                        )
-import Id              ( Id, idName, idPrimRep, isDeadBinder )
-import Literal         ( Literal(..) )
+import Id              ( Id, idName, isDeadBinder )
+import Type            ( Type )
 import PrelInfo                ( maybeCharLikeCon, maybeIntLikeCon )
-import PrimRep         ( PrimRep(..), isFollowableRep )
-import Util
 import Outputable
-
-import List            ( partition )
-import Char            ( ord )
+import Util            ( lengthIs )
+import ListSetOps      ( assocMaybe )
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
 \subsection[toplevel-constructors]{Top-level constructors}
@@ -68,34 +72,32 @@ cgTopRhsCon :: Id           -- Name of thing bound to this RHS
 cgTopRhsCon id con args
   = ASSERT( not (isDllConApp con args) )
     ASSERT( args `lengthIs` dataConRepArity con )
+    do {       -- LAY IT OUT
+       ; amodes <- getArgAmodes args
+
+       ; let
+           name          = idName id
+           lf_info       = mkConLFInfo con
+           closure_label = mkClosureLabel name
+           caffy         = any stgArgHasCafRefs args
+           (closure_info, amodes_w_offsets) = layOutStaticConstr con amodes
+           closure_rep = mkStaticClosureFields
+                            closure_info
+                            dontCareCCS                -- Because it's static data
+                            caffy                      -- Has CAF refs
+                            payload
+
+           payload = map get_lit amodes_w_offsets      
+           get_lit (CmmLit lit, _offset) = lit
+           get_lit other = pprPanic "CgCon.get_lit" (ppr other)
+               -- NB1: amodes_w_offsets is sorted into ptrs first, then non-ptrs
+               -- NB2: all the amodes should be Lits!
+
+               -- BUILD THE OBJECT
+       ; emitDataLits closure_label closure_rep
 
-       -- LAY IT OUT
-    getArgAmodes args          `thenFC` \ amodes ->
-
-    let
-       name          = idName id
-       lf_info       = mkConLFInfo con
-       closure_label = mkClosureLabel name
-       (closure_info, amodes_w_offsets) 
-               = layOutStaticConstr con getAmodeRep amodes
-       caffy = any stgArgHasCafRefs args
-    in
-
-       -- BUILD THE OBJECT
-    absC (mkStaticClosure
-           closure_label
-           closure_info
-           dontCareCCS                 -- because it's static data
-           (map fst amodes_w_offsets)  -- Sorted into ptrs first, then nonptrs
-           caffy                       -- has CAF refs
-         )                                     `thenC`
-               -- NOTE: can't use idCafInfo instead of nonEmptySRT above,
-               -- because top-level constructors that were floated by
-               -- CorePrep don't have CafInfo attached.  The SRT is more
-               -- reliable.
-
-       -- RETURN
-    returnFC (id, stableAmodeIdInfo id (CLbl closure_label PtrRep) lf_info)
+               -- RETURN
+       ; returnFC (id, stableIdInfo id (mkLblExpr closure_label) lf_info) }
 \end{code}
 
 %************************************************************************
@@ -106,13 +108,13 @@ cgTopRhsCon id con args
 \subsection[code-for-constructors]{The code for constructors}
 
 \begin{code}
-buildDynCon :: Id              -- Name of the thing to which this constr will
-                               -- be bound
-           -> CostCentreStack  -- Where to grab cost centre from;
-                               -- current CCS if currentOrSubsumedCCS
-           -> DataCon          -- The data constructor
-           -> [CAddrMode]      -- Its args
-           -> FCode CgIdInfo   -- Return details about how to find it
+buildDynCon :: Id                -- Name of the thing to which this constr will
+                                 -- be bound
+           -> CostCentreStack    -- Where to grab cost centre from;
+                                 -- current CCS if currentOrSubsumedCCS
+           -> DataCon            -- The data constructor
+           -> [(CgRep,CmmExpr)] -- Its args
+           -> FCode CgIdInfo     -- Return details about how to find it
 
 -- We used to pass a boolean indicating whether all the
 -- args were of size zero, so we could use a static
@@ -135,9 +137,9 @@ at all.
 
 \begin{code}
 buildDynCon binder cc con []
-  = returnFC (stableAmodeIdInfo binder
-                               (CLbl (mkClosureLabel (dataConName con)) PtrRep)
-                               (mkConLFInfo con))
+  = returnFC (stableIdInfo binder
+                          (mkLblExpr (mkClosureLabel (dataConName con)))
+                          (mkConLFInfo con))
 \end{code}
 
 The following three paragraphs about @Char@-like and @Int@-like
@@ -163,36 +165,41 @@ Because of this, we use can safely return an addressing mode.
 
 \begin{code}
 buildDynCon binder cc con [arg_amode]
-  | maybeIntLikeCon con && in_range_int_lit arg_amode
-  = returnFC (stableAmodeIdInfo binder (CIntLike arg_amode) (mkConLFInfo con))
-  where
-    in_range_int_lit (CLit (MachInt val)) = val <= mAX_INTLIKE && val >= mIN_INTLIKE
-    in_range_int_lit _other_amode        = False
+  | maybeIntLikeCon con 
+  , (_, CmmLit (CmmInt val _)) <- arg_amode
+  , let val_int = (fromIntegral val) :: Int
+  , val_int <= mAX_INTLIKE && val_int >= mIN_INTLIKE
+  = do         { let intlike_lbl   = mkRtsDataLabel SLIT("stg_INTLIKE_closure")
+             offsetW = (val_int - mIN_INTLIKE) * (fixedHdrSize + 1)
+               -- INTLIKE closures consist of a header and one word payload
+             intlike_amode = CmmLit (cmmLabelOffW intlike_lbl offsetW)
+       ; returnFC (stableIdInfo binder intlike_amode (mkConLFInfo con)) }
 
 buildDynCon binder cc con [arg_amode]
-  | maybeCharLikeCon con && in_range_char_lit arg_amode
-  = returnFC (stableAmodeIdInfo binder (CCharLike arg_amode) (mkConLFInfo con))
-  where
-    in_range_char_lit (CLit (MachChar val)) = 
-       ord val <= mAX_CHARLIKE && ord val >= mIN_CHARLIKE
-    in_range_char_lit _other_amode         = False
+  | maybeCharLikeCon con 
+  , (_, CmmLit (CmmInt val _)) <- arg_amode
+  , let val_int = (fromIntegral val) :: Int
+  , val_int <= mAX_CHARLIKE && val_int >= mIN_CHARLIKE
+  = do         { let charlike_lbl   = mkRtsDataLabel SLIT("stg_CHARLIKE_closure")
+             offsetW = (val_int - mIN_CHARLIKE) * (fixedHdrSize + 1)
+               -- CHARLIKE closures consist of a header and one word payload
+             charlike_amode = CmmLit (cmmLabelOffW charlike_lbl offsetW)
+       ; returnFC (stableIdInfo binder charlike_amode (mkConLFInfo con)) }
 \end{code}
 
 Now the general case.
 
 \begin{code}
 buildDynCon binder ccs con args
-  = allocDynClosure closure_info use_cc blame_cc amodes_w_offsets `thenFC` \ hp_off ->
-    returnFC (heapIdInfo binder hp_off lf_info)
+  = do { hp_off <- allocDynClosure closure_info use_cc blame_cc amodes_w_offsets
+       ; returnFC (heapIdInfo binder hp_off lf_info) }
   where
     lf_info = mkConLFInfo con
-
-    (closure_info, amodes_w_offsets) = layOutDynConstr con getAmodeRep args
+    (closure_info, amodes_w_offsets) = layOutDynConstr con args
 
     use_cc     -- cost-centre to stick in the object
-      = if currentOrSubsumedCCS ccs
-       then CReg CurCostCentre
-       else mkCCostCentreStack ccs
+      | currentOrSubsumedCCS ccs = curCCS
+      | otherwise               = CmmLit (mkCCostCentreStack ccs)
 
     blame_cc = use_cc -- cost-centre on which to blame the alloc (same)
 \end{code}
@@ -211,16 +218,13 @@ binders $args$, assuming that we have just returned from a @case@ which
 found a $con$.
 
 \begin{code}
-bindConArgs 
-       :: DataCon -> [Id]              -- Constructor and args
-       -> Code
-
+bindConArgs :: DataCon -> [Id] -> Code
 bindConArgs con args
   = ASSERT(not (isUnboxedTupleCon con))
     mapCs bind_arg args_w_offsets
    where
      bind_arg (arg, offset) = bindNewToNode arg offset (mkLFArgument arg)
-     (_, args_w_offsets)    = layOutDynConstr con idPrimRep args
+     (_, args_w_offsets)    = layOutDynConstr con (addIdReps args)
 \end{code}
 
 Unboxed tuples are handled slightly differently - the object is
@@ -228,56 +232,53 @@ returned in registers and on the stack instead of the heap.
 
 \begin{code}
 bindUnboxedTupleComponents
-       :: [Id]                         -- Aargs
-       -> FCode ([MagicId],            -- Regs assigned
-                 Int,                  -- Number of pointer stack slots
-                 Int,                  -- Number of non-pointer stack slots
+       :: [Id]                         -- Args
+       -> FCode ([(Id,GlobalReg)],     -- Regs assigned
+                 WordOff,              -- Number of pointer stack slots
+                 WordOff,              -- Number of non-pointer stack slots
                  VirtualSpOffset)      -- Offset of return address slot
                                        -- (= realSP on entry)
 
 bindUnboxedTupleComponents args
- =      -- Assign as many components as possible to registers
-    let (arg_regs, _leftovers) = assignRegs [] (map idPrimRep args)
-       (reg_args, stk_args)   = splitAtList arg_regs args
-
-       -- separate the rest of the args into pointers and non-pointers
-       (ptr_args, nptr_args) = 
-          partition (isFollowableRep . idPrimRep) stk_args
-    in
+ =  do {   
+         vsp <- getVirtSp
+       ; rsp <- getRealSp
+
+          -- Assign as many components as possible to registers
+       ; let (reg_args, stk_args) = assignReturnRegs (addIdReps args)
+
+               -- Separate the rest of the args into pointers and non-pointers
+             (ptr_args, nptr_args) = separateByPtrFollowness stk_args
   
-    -- Allocate the rest on the stack
-    -- The real SP points to the return address, above which any 
-    -- leftover unboxed-tuple components will be allocated
-    getVirtSp `thenFC` \ vsp ->
-    getRealSp `thenFC` \ rsp ->
-    let 
-       (ptr_sp,  ptr_offsets)  = mkVirtStkOffsets rsp    idPrimRep ptr_args
-       (nptr_sp, nptr_offsets) = mkVirtStkOffsets ptr_sp idPrimRep nptr_args
-        ptrs  = ptr_sp - rsp
-       nptrs = nptr_sp - ptr_sp
-    in
-
-    -- The stack pointer points to the last stack-allocated component
-    setRealAndVirtualSp nptr_sp                `thenC`
-
-    -- We have just allocated slots starting at real SP + 1, and set the new
-    -- virtual SP to the topmost allocated slot.  
-    -- If the virtual SP started *below* the real SP, we've just jumped over
-    -- some slots that won't be in the free-list, so put them there
-    -- This commonly happens because we've freed the return-address slot
-    -- (trimming back the virtual SP), but the real SP still points to that slot
-    freeStackSlots [vsp+1,vsp+2 .. rsp]                `thenC`
-
-    bindArgsToRegs reg_args arg_regs           `thenC`
-    mapCs bindNewToStack ptr_offsets           `thenC`
-    mapCs bindNewToStack nptr_offsets          `thenC`
-
-    returnFC (arg_regs, ptrs, nptrs, rsp)
+               -- Allocate the rest on the stack
+               -- The real SP points to the return address, above which any 
+               -- leftover unboxed-tuple components will be allocated
+             (ptr_sp,  ptr_offsets)  = mkVirtStkOffsets rsp    ptr_args
+             (nptr_sp, nptr_offsets) = mkVirtStkOffsets ptr_sp nptr_args
+              ptrs  = ptr_sp  - rsp
+             nptrs = nptr_sp - ptr_sp
+
+           -- The stack pointer points to the last stack-allocated component
+       ; setRealAndVirtualSp nptr_sp
+
+           -- We have just allocated slots starting at real SP + 1, and set the new
+           -- virtual SP to the topmost allocated slot.  
+           -- If the virtual SP started *below* the real SP, we've just jumped over
+           -- some slots that won't be in the free-list, so put them there
+           -- This commonly happens because we've freed the return-address slot
+           -- (trimming back the virtual SP), but the real SP still points to that slot
+       ; freeStackSlots [vsp+1,vsp+2 .. rsp]
+
+       ; bindArgsToRegs reg_args
+       ; bindArgsToStack ptr_offsets
+       ; bindArgsToStack nptr_offsets
+
+       ; returnFC (reg_args, ptrs, nptrs, rsp) }
 \end{code}
 
 %************************************************************************
 %*                                                                     *
-\subsubsection[CgRetConv-cgReturnDataCon]{Actually generate code for a constructor return}
+       Actually generate code for a constructor return
 %*                                                                     *
 %************************************************************************
 
@@ -285,47 +286,41 @@ bindUnboxedTupleComponents args
 Note: it's the responsibility of the @cgReturnDataCon@ caller to be
 sure the @amodes@ passed don't conflict with each other.
 \begin{code}
-cgReturnDataCon :: DataCon -> [CAddrMode] -> Code
+cgReturnDataCon :: DataCon -> [(CgRep, CmmExpr)] -> Code
 
 cgReturnDataCon con amodes
   = ASSERT( amodes `lengthIs` dataConRepArity con )
-    getEndOfBlockInfo  `thenFC` \ (EndOfBlockInfo args_sp sequel) ->
-
-    case sequel of
-
-      CaseAlts _ (Just (alts, Just (deflt_bndr, (_,deflt_lbl)))) False
-       | not (dataConTag con `is_elem` map fst alts)
-       ->
-               -- Special case!  We're returning a constructor to the default case
-               -- of an enclosing case.  For example:
-               --
-               --      case (case e of (a,b) -> C a b) of
-               --        D x -> ...
-               --        y   -> ...<returning here!>...
-               --
-               -- In this case,
-               --      if the default is a non-bind-default (ie does not use y),
-               --      then we should simply jump to the default join point;
-
-               if isDeadBinder deflt_bndr
-               then performReturn AbsCNop {- No reg assts -} jump_to_join_point
-               else build_it_then jump_to_join_point
-       where
-         is_elem = isIn "cgReturnDataCon"
-         jump_to_join_point sequel = absC (CJump (CLbl deflt_lbl CodePtrRep))
-               -- Ignore the sequel: we've already looked at it above
-
-      other_sequel     -- The usual case
-         | isUnboxedTupleCon con -> returnUnboxedTuple amodes
-          | otherwise ->            build_it_then (mkStaticAlgReturnCode con)
-
+    do { EndOfBlockInfo _ sequel <- getEndOfBlockInfo
+       ; case sequel of
+           CaseAlts _ (Just (alts, deflt_lbl)) bndr _ 
+             ->    -- Ho! We know the constructor so we can
+                   -- go straight to the right alternative
+                case assocMaybe alts (dataConTagZ con) of {
+                   Just join_lbl -> build_it_then (jump_to join_lbl) ;
+                   Nothing
+                       -- Special case!  We're returning a constructor to the default case
+                       -- of an enclosing case.  For example:
+                       --
+                       --      case (case e of (a,b) -> C a b) of
+                       --        D x -> ...
+                       --        y   -> ...<returning here!>...
+                       --
+                       -- In this case,
+                       --      if the default is a non-bind-default (ie does not use y),
+                       --      then we should simply jump to the default join point;
+    
+                       | isDeadBinder bndr -> performReturn (jump_to deflt_lbl)
+                       | otherwise         -> build_it_then (jump_to deflt_lbl) }
+    
+           other_sequel        -- The usual case
+             | isUnboxedTupleCon con -> returnUnboxedTuple amodes
+              | otherwise -> build_it_then (emitKnownConReturnCode con)
+       }
   where
-    move_to_reg :: CAddrMode -> MagicId -> AbstractC
-    move_to_reg src_amode dest_reg = CAssign (CReg dest_reg) src_amode
-
-    build_it_then return =
-               -- BUILD THE OBJECT IN THE HEAP
-               -- The first "con" says that the name bound to this
+    jump_to lbl = stmtC (CmmJump (CmmLit (CmmLabel lbl)) [])
+    build_it_then return_code
+      = do {   -- BUILD THE OBJECT IN THE HEAP
+               -- The first "con" says that the name bound to this
                -- closure is "con", which is a bit of a fudge, but it only
                -- affects profiling
 
@@ -333,12 +328,108 @@ cgReturnDataCon con amodes
                -- temporary variable, if the closure is a CHARLIKE.
                -- funnily enough, this makes the unique always come
                -- out as '54' :-)
-         buildDynCon (dataConWorkId con) currentCCS con amodes `thenFC` \ idinfo ->
-         idInfoToAmode PtrRep idinfo                           `thenFC` \ amode ->
+            tickyReturnNewCon (length amodes)
+          ; idinfo <- buildDynCon (dataConWorkId con) currentCCS con amodes
+          ; amode <- idInfoToAmode idinfo
+          ; checkedAbsC (CmmAssign nodeReg amode)
+          ; performReturn return_code }
+\end{code}
 
 
-               -- RETURN
-         profCtrC FSLIT("TICK_RET_NEW") [mkIntCLit (length amodes)] `thenC`
-         -- could use doTailCall here.
-         performReturn (move_to_reg amode node) return
+%************************************************************************
+%*                                                                     *
+       Generating static stuff for algebraic data types
+%*                                                                     *
+%************************************************************************
+
+       [These comments are rather out of date]
+
+\begin{tabular}{lll}
+Info tbls &     Macro  &            Kind of constructor \\
+\hline
+info & @CONST_INFO_TABLE@&    Zero arity (no info -- compiler uses static closure)\\
+info & @CHARLIKE_INFO_TABLE@& Charlike   (no info -- compiler indexes fixed array)\\
+info & @INTLIKE_INFO_TABLE@&  Intlike; the one macro generates both info tbls\\
+info & @SPEC_INFO_TABLE@&     SPECish, and bigger than or equal to @MIN_UPD_SIZE@\\
+info & @GEN_INFO_TABLE@&      GENish (hence bigger than or equal to @MIN_UPD_SIZE@)\\
+\end{tabular}
+
+Possible info tables for constructor con:
+
+\begin{description}
+\item[@_con_info@:]
+Used for dynamically let(rec)-bound occurrences of
+the constructor, and for updates.  For constructors
+which are int-like, char-like or nullary, when GC occurs,
+the closure tries to get rid of itself.
+
+\item[@_static_info@:]
+Static occurrences of the constructor
+macro: @STATIC_INFO_TABLE@.
+\end{description}
+
+For zero-arity constructors, \tr{con}, we NO LONGER generate a static closure;
+it's place is taken by the top level defn of the constructor.
+
+For charlike and intlike closures there is a fixed array of static
+closures predeclared.
+
+\begin{code}
+cgTyCon :: TyCon -> FCode [Cmm]  -- each constructor gets a separate Cmm
+cgTyCon tycon
+  = do { constrs <- mapM (getCmm . cgDataCon) (tyConDataCons tycon)
+
+           -- Generate a table of static closures for an enumeration type
+           -- Put the table after the data constructor decls, because the
+           -- datatype closure table (for enumeration types)
+           -- to (say) PrelBase_$wTrue_closure, which is defined in code_stuff
+       ; extra <- 
+          if isEnumerationTyCon tycon then do
+               tbl <- getCmm (emitRODataLits (mkClosureTblLabel 
+                                               (tyConName tycon))
+                          [ CmmLabel (mkClosureLabel (dataConName con))
+                          | con <- tyConDataCons tycon])
+               return [tbl]
+          else
+               return []
+
+       ; return (extra ++ constrs)
+    }
+\end{code}
+
+Generate the entry code, info tables, and (for niladic constructor) the
+static closure, for a constructor.
+
+\begin{code}
+cgDataCon :: DataCon -> Code
+cgDataCon data_con
+  = do {     -- Don't need any dynamic closure code for zero-arity constructors
+         whenC (not (isNullaryDataCon data_con))
+               (emit_info dyn_cl_info tickyEnterDynCon)
+
+               -- Dynamic-Closure first, to reduce forward references
+       ; emit_info static_cl_info tickyEnterStaticCon }
+
+  where
+    emit_info cl_info ticky_code
+       = do { code_blks <- getCgStmts the_code
+            ; emitClosureCodeAndInfoTable cl_info [] code_blks }
+       where
+         the_code = do { ticky_code
+                       ; ldvEnter (CmmReg nodeReg)
+                       ; body_code }
+
+    arg_reps :: [(CgRep, Type)]
+    arg_reps = [(typeCgRep ty, ty) | ty <- dataConRepArgTys data_con]
+
+    -- To allow the debuggers, interpreters, etc to cope with static
+    -- data structures (ie those built at compile time), we take care that
+    -- info-table contains the information we need.
+    (static_cl_info, _)       = layOutStaticConstr data_con arg_reps
+    (dyn_cl_info, arg_things) = layOutDynConstr    data_con arg_reps
+
+    body_code = do {   -- NB: We don't set CC when entering data (WDP 94/06)
+                    tickyReturnOldCon (length arg_things)
+                  ; performReturn (emitKnownConReturnCode data_con) }
+                       -- noStmts: Ptr to thing already in Node
 \end{code}
diff --git a/ghc/compiler/codeGen/CgConTbls.lhs b/ghc/compiler/codeGen/CgConTbls.lhs
deleted file mode 100644 (file)
index 37ced1e..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
-%
-\section[CgConTbls]{Info tables and update bits for constructors}
-
-\begin{code}
-module CgConTbls ( genStaticConBits ) where
-
-#include "HsVersions.h"
-
-import AbsCSyn
-import CgMonad
-
-import AbsCUtils       ( mkAbstractCs, mkAbsCStmts )
-import CgTailCall      ( performReturn, mkStaticAlgReturnCode )
-import ClosureInfo     ( layOutStaticConstr, layOutDynConstr, ClosureInfo )
-import DataCon         ( DataCon, dataConRepArgTys, isNullaryDataCon )
-import TyCon           ( tyConDataCons, isEnumerationTyCon, TyCon )
-import Type            ( typePrimRep )
-import CmdLineOpts
-\end{code}
-
-For every constructor we generate the following info tables:
-       A static info table, for static instances of the constructor,
-
-       Plus:
-
-\begin{tabular}{lll}
-Info tbls &     Macro  &            Kind of constructor \\
-\hline
-info & @CONST_INFO_TABLE@&    Zero arity (no info -- compiler uses static closure)\\
-info & @CHARLIKE_INFO_TABLE@& Charlike   (no info -- compiler indexes fixed array)\\
-info & @INTLIKE_INFO_TABLE@&  Intlike; the one macro generates both info tbls\\
-info & @SPEC_INFO_TABLE@&     SPECish, and bigger than or equal to @MIN_UPD_SIZE@\\
-info & @GEN_INFO_TABLE@&      GENish (hence bigger than or equal to @MIN_UPD_SIZE@)\\
-\end{tabular}
-
-Possible info tables for constructor con:
-
-\begin{description}
-\item[@_con_info@:]
-Used for dynamically let(rec)-bound occurrences of
-the constructor, and for updates.  For constructors
-which are int-like, char-like or nullary, when GC occurs,
-the closure tries to get rid of itself.
-
-\item[@_static_info@:]
-Static occurrences of the constructor
-macro: @STATIC_INFO_TABLE@.
-\end{description}
-
-
-For zero-arity constructors, \tr{con}, we NO LONGER generate a static closure;
-it's place is taken by the top level defn of the constructor.
-
-For charlike and intlike closures there is a fixed array of static
-closures predeclared.
-
-\begin{code}
-genStaticConBits :: CompilationInfo    -- global info about the compilation
-                -> [TyCon]             -- tycons to generate
-                -> AbstractC           -- output
-
-genStaticConBits comp_info gen_tycons
-  = -- for each type constructor:
-    --  grab all its data constructors;
-    --     for each one, generate an info table
-    -- for each specialised type constructor
-    --   for each specialisation of the type constructor
-    --     grab data constructors, and generate info tables
-
-    -- ToDo: for tycons and specialisations which are not
-    --       declared in this module we must ensure that the
-    --       C labels are local to this module i.e. static
-    --      since they may be duplicated in other modules
-
-    mkAbstractCs [ gen_for_tycon tc `mkAbsCStmts` enum_closure_table tc
-                | tc <- gen_tycons ]
-  where
-    gen_for_tycon :: TyCon -> AbstractC
-    gen_for_tycon tycon = mkAbstractCs [ genConInfo comp_info data_con 
-                                      | data_con <- tyConDataCons tycon ] 
-
-    enum_closure_table tycon
-       | isEnumerationTyCon tycon = CClosureTbl tycon
-       | otherwise                = AbsCNop
-               -- Put the table after the data constructor decls, because the
-               -- datatype closure table (for enumeration types)
-               -- to (say) PrelBase_$wTrue_closure, which is defined in code_stuff
-\end{code}
-
-
-%************************************************************************
-%*                                                                     *
-\subsection[CgConTbls-info-tables]{Generating info tables for constructors}
-%*                                                                     *
-%************************************************************************
-
-Generate the entry code, info tables, and (for niladic constructor) the
-static closure, for a constructor.
-
-\begin{code}
-genConInfo :: CompilationInfo -> DataCon -> AbstractC
-
-genConInfo comp_info data_con
-  =    -- Order of things is to reduce forward references
-    mkAbstractCs [if opt_EnsureSplittableC then CSplitMarker else AbsCNop,
-                 closure_code,
-                 static_code]
-  where
-    (closure_info, body_code) = mkConCodeAndInfo data_con
-
-    -- To allow the debuggers, interpreters, etc to cope with static
-    -- data structures (ie those built at compile time), we take care that
-    -- info-table contains the information we need.
-    (static_ci,_) = layOutStaticConstr data_con typePrimRep arg_tys
-
-    static_body  = initC comp_info (
-                      profCtrC FSLIT("TICK_ENT_STATIC_CON") [CReg node] `thenC`
-                      ldv_enter_and_body_code)
-
-    closure_body = initC comp_info (
-                      profCtrC FSLIT("TICK_ENT_DYN_CON") [CReg node] `thenC`
-                      ldv_enter_and_body_code)
-
-    ldv_enter_and_body_code = ldvEnter `thenC` body_code
-
-    -- Don't need any dynamic closure code for zero-arity constructors
-    closure_code = if zero_arity_con then 
-                       AbsCNop 
-                  else 
-                       CClosureInfoAndCode closure_info closure_body
-
-    static_code  = CClosureInfoAndCode static_ci static_body
-
-    zero_arity_con   = isNullaryDataCon data_con
-       -- We used to check that all the arg-sizes were zero, but we don't
-       -- really have any constructors with only zero-size args, and it's
-       -- just one more thing to go wrong.
-
-    arg_tys        = dataConRepArgTys  data_con
-\end{code}
-
-\begin{code}
-mkConCodeAndInfo :: DataCon            -- Data constructor
-                -> (ClosureInfo, Code) -- The info table
-
-mkConCodeAndInfo con
-  = let
-       arg_tys = dataConRepArgTys con
-
-       (closure_info, arg_things) = layOutDynConstr con typePrimRep arg_tys
-
-       body_code
-               = -- NB: We don't set CC when entering data (WDP 94/06)
-                 profCtrC FSLIT("TICK_RET_OLD") 
-                       [mkIntCLit (length arg_things)] `thenC`
-
-                 performReturn AbsCNop         -- Ptr to thing already in Node
-                               (mkStaticAlgReturnCode con)
-       in
-       (closure_info, body_code)
-\end{code}
index 88771b9..d72c7c5 100644 (file)
@@ -1,7 +1,7 @@
 %
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
-% $Id: CgExpr.lhs,v 1.58 2004/08/10 09:02:41 simonmar Exp $
+% $Id: CgExpr.lhs,v 1.59 2004/08/13 13:05:58 simonmar Exp $
 %
 %********************************************************
 %*                                                     *
@@ -17,38 +17,39 @@ module CgExpr ( cgExpr ) where
 import Constants       ( mAX_SPEC_SELECTEE_SIZE, mAX_SPEC_AP_SIZE )
 import StgSyn
 import CgMonad
-import AbsCSyn
-import AbsCUtils       ( mkAbstractCs, getAmodeRep, shimFCallArg )
-import CLabel          ( mkClosureTblLabel )
 
-import SMRep           ( fixedHdrSize )
+import SMRep           ( fixedHdrSize, isFollowableArg, CgRep(..), argMachRep,
+                         nonVoidArg, idCgRep, typeCgRep, typeHint,
+                         primRepToCgRep )
 import CoreSyn         ( AltCon(..) )
+import CgProf          ( emitSetCCC )
+import CgHeapery       ( layOutDynConstr )
 import CgBindery       ( getArgAmodes, getArgAmode, CgIdInfo, 
                          nukeDeadBindings, addBindC, addBindsC )
 import CgCase          ( cgCase, saveVolatileVarsAndRegs )
 import CgClosure       ( cgRhsClosure, cgStdRhsClosure )
 import CgCon           ( buildDynCon, cgReturnDataCon )
 import CgLetNoEscape   ( cgLetNoEscapeClosure )
-import CgRetConv       ( dataReturnConvPrim )
-import CgTailCall      ( cgTailCall, performReturn, performPrimReturn,
-                         mkDynamicAlgReturnCode, mkPrimReturnCode,
-                         tailCallPrimOp, ccallReturnUnboxedTuple
-                       )
-import ClosureInfo     ( mkClosureLFInfo, mkSelectorLFInfo,
-                         mkApLFInfo, layOutDynConstr )
-import CostCentre      ( sccAbleCostCentre, isSccCountCostCentre )
-import Id              ( idPrimRep, Id )
+import CgCallConv      ( dataReturnConvPrim )
+import CgTailCall
+import CgInfoTbls      ( emitDirectReturnInstr )
+import CgForeignCall   ( emitForeignCall, shimForeignCallArg )
+import CgPrimOp                ( cgPrimOp )
+import CgUtils         ( addIdReps, newTemp, assignTemp, cgLit, tagToClosure )
+import ClosureInfo     ( mkSelectorLFInfo, mkApLFInfo )
+import Cmm             ( CmmExpr(..), CmmStmt(..), CmmReg, nodeReg )
+import MachOp          ( wordRep, MachHint )
 import VarSet
+import Literal         ( literalType )
 import PrimOp          ( primOpOutOfLine, getPrimOpResultInfo, 
                          PrimOp(..), PrimOpResultInfo(..) )
-import PrimRep         ( PrimRep(..), isFollowableRep )
+import Id              ( Id )
 import TyCon           ( isUnboxedTupleTyCon, isEnumerationTyCon )
-import Type            ( Type, typePrimRep, tyConAppArgs, 
-                         tyConAppTyCon, repType )
+import Type            ( Type, tyConAppArgs, tyConAppTyCon, repType,
+                         PrimRep(VoidRep) )
 import Maybes          ( maybeToBool )
 import ListSetOps      ( assocMaybe )
-import Unique          ( mkBuiltinUnique )
-import BasicTypes      ( TopLevelFlag(..), RecFlag(..) )
+import BasicTypes      ( RecFlag(..) )
 import Util             ( lengthIs )
 import Outputable
 \end{code}
@@ -84,8 +85,8 @@ cgExpr (StgApp fun args) = cgTailCall fun args
 
 \begin{code}
 cgExpr (StgConApp con args)
-  = getArgAmodes args `thenFC` \ amodes ->
-    cgReturnDataCon con amodes
+  = do { amodes <- getArgAmodes args
+       ; cgReturnDataCon con amodes }
 \end{code}
 
 Literals are similar to constructors; they return by putting
@@ -94,99 +95,100 @@ top of the stack.
 
 \begin{code}
 cgExpr (StgLit lit)
-  = performPrimReturn (text "literal" <+> ppr lit) (CLit lit)
+  = do  { cmm_lit <- cgLit lit
+       ; performPrimReturn rep (CmmLit cmm_lit) }
+  where
+    rep = typeCgRep (literalType lit)
 \end{code}
 
 
 %********************************************************
 %*                                                     *
-%*             STG PrimApps  (unboxed primitive ops)   *
+%*     PrimOps and foreign calls.
 %*                                                     *
 %********************************************************
 
-Here is where we insert real live machine instructions.
-
-NOTE about _ccall_GC_:
+NOTE about "safe" foreign calls: a safe foreign call is never compiled
+inline in a case expression.  When we see
 
-A _ccall_GC_ is treated as an out-of-line primop (returns True
-for primOpOutOfLine) so that when we see the call in case context
        case (ccall ...) of { ... }
-we get a proper stack frame on the stack when we perform it.  When we
-get in a tail-call position, however, we need to actually perform the
-call, so we treat it as an inline primop.
+
+We generate a proper return address for the alternatives and push the
+stack frame before doing the call, so that in the event that the call
+re-enters the RTS the stack is in a sane state.
 
 \begin{code}
-cgExpr (StgOpApp op@(StgFCallOp _ _) args res_ty)
-  = primRetUnboxedTuple op args res_ty
+cgExpr (StgOpApp (StgFCallOp fcall _) stg_args res_ty) = do
+    {-
+       First, copy the args into temporaries.  We're going to push
+       a return address right before doing the call, so the args
+       must be out of the way.
+    -}
+    reps_n_amodes <- getArgAmodes stg_args
+    let 
+       -- Get the *non-void* args, and jiggle them with shimForeignCall
+       arg_exprs = [ shimForeignCallArg stg_arg expr 
+                   | (stg_arg, (rep,expr)) <- stg_args `zip` reps_n_amodes, 
+                     nonVoidArg rep]
 
+    -- in
+    arg_tmps <- mapM assignTemp arg_exprs
+    let
+       arg_hints = zip arg_tmps (map (typeHint.stgArgType) stg_args)
+    -- in
+    {-
+       Now, allocate some result regs.
+    -}
+    (res_reps,res_regs,res_hints)  <- newUnboxedTupleRegs res_ty
+    ccallReturnUnboxedTuple (zip res_reps (map CmmReg res_regs)) $
+       emitForeignCall (zip res_regs res_hints) fcall 
+          arg_hints emptyVarSet{-no live vars-}
+      
 -- tagToEnum# is special: we need to pull the constructor out of the table,
 -- and perform an appropriate return.
 
 cgExpr (StgOpApp (StgPrimOp TagToEnumOp) [arg] res_ty) 
   = ASSERT(isEnumerationTyCon tycon)
-    getArgAmode arg `thenFC` \amode ->
-       -- save the tag in a temporary in case amode overlaps
-       -- with node.
-    absC (CAssign dyn_tag amode)       `thenC`
-    performReturn (
-               CAssign (CReg node) 
-                       (CVal (CIndex
-                         (CLbl (mkClosureTblLabel tycon) PtrRep)
-                         dyn_tag PtrRep) PtrRep))
-           (\ sequel -> mkDynamicAlgReturnCode tycon dyn_tag sequel)
+    do { (_,amode) <- getArgAmode arg
+       ; amode' <- assignTemp amode    -- We're going to use it twice,
+                                       -- so save in a temp if non-trivial
+       ; stmtC (CmmAssign nodeReg (tagToClosure tycon amode'))
+       ; performReturn (emitAlgReturnCode tycon amode') }
    where
-        dyn_tag = CTemp (mkBuiltinUnique 0) IntRep
-               -- The '0' is just to get a random spare temp
-         --
-         -- if you're reading this code in the attempt to figure
+         -- If you're reading this code in the attempt to figure
          -- out why the compiler panic'ed here, it is probably because
          -- you used tagToEnum# in a non-monomorphic setting, e.g., 
          --         intToTg :: Enum a => Int -> a ; intToTg (I# x#) = tagToEnum# x#
-          --
          -- That won't work.
-          --
        tycon = tyConAppTyCon res_ty
 
 
 cgExpr x@(StgOpApp op@(StgPrimOp primop) args res_ty)
-  | primOpOutOfLine primop 
-  = tailCallPrimOp primop args
-
-  | otherwise
-  = getArgAmodes args  `thenFC` \ arg_amodes ->
-
-    case (getPrimOpResultInfo primop) of
-
-       ReturnsPrim kind ->
-           let result_amode = CReg (dataReturnConvPrim kind) in
-           performReturn 
-             (COpStmt [result_amode] op arg_amodes [{-no vol_regs-}])
-             (mkPrimReturnCode (text "primapp)" <+> ppr x))
-                         
-       -- otherwise, must be returning an enumerated type (eg. Bool).
-       -- we've only got the tag in R2, so we have to load the constructor
-       -- itself into R1.
-
-       ReturnsAlg tycon
-           | isUnboxedTupleTyCon tycon -> primRetUnboxedTuple op args res_ty
-
-           | isEnumerationTyCon  tycon ->
-               performReturn
-                    (COpStmt [dyn_tag] op arg_amodes [{-no vol_regs-}])
-                         (\ sequel -> 
-                         absC (CAssign (CReg node) closure_lbl) `thenC`
-                         mkDynamicAlgReturnCode tycon dyn_tag sequel)
-
-            where
-              -- Pull a unique out of thin air to put the tag in.  
-              -- It shouldn't matter if this overlaps with anything - we're
-              -- about to return anyway.
-              dyn_tag = CTemp (mkBuiltinUnique 0) IntRep
-
-              closure_lbl = CVal (CIndex
-                              (CLbl (mkClosureTblLabel tycon) PtrRep)
-                              dyn_tag PtrRep) PtrRep
-
+  | primOpOutOfLine primop
+       = tailCallPrimOp primop args
+
+  | ReturnsPrim VoidRep <- result_info
+       = do cgPrimOp [] primop args emptyVarSet
+            performReturn emitDirectReturnInstr
+
+  | ReturnsPrim rep <- result_info
+       = do cgPrimOp [dataReturnConvPrim (primRepToCgRep rep)] 
+                       primop args emptyVarSet
+            performReturn emitDirectReturnInstr
+
+  | ReturnsAlg tycon <- result_info, isUnboxedTupleTyCon tycon
+       = do (reps, regs, _hints) <- newUnboxedTupleRegs res_ty
+            cgPrimOp regs primop args emptyVarSet{-no live vars-}
+            returnUnboxedTuple (zip reps (map CmmReg regs))
+
+  | ReturnsAlg tycon <- result_info, isEnumerationTyCon tycon
+       -- c.f. cgExpr (...TagToEnumOp...)
+       = do tag_reg <- newTemp wordRep
+            cgPrimOp [tag_reg] primop args emptyVarSet
+            stmtC (CmmAssign nodeReg (tagToClosure tycon (CmmReg tag_reg)))
+            performReturn (emitAlgReturnCode tycon (CmmReg tag_reg))
+  where
+       result_info = getPrimOpResultInfo primop
 \end{code}
 
 %********************************************************
@@ -227,20 +229,21 @@ cgExpr (StgLet (StgRec pairs) expr)
 
 \begin{code}
 cgExpr (StgLetNoEscape live_in_whole_let live_in_rhss bindings body)
-  =            -- Figure out what volatile variables to save
-    nukeDeadBindings live_in_whole_let `thenC`
-    saveVolatileVarsAndRegs live_in_rhss
-           `thenFC` \ (save_assts, rhs_eob_info, maybe_cc_slot) ->
+  = do {       -- Figure out what volatile variables to save
+       ; nukeDeadBindings live_in_whole_let
+       ; (save_assts, rhs_eob_info, maybe_cc_slot) 
+               <- saveVolatileVarsAndRegs live_in_rhss
 
        -- Save those variables right now!
-    absC save_assts                            `thenC`
+       ; emitStmts save_assts
 
        -- Produce code for the rhss
        -- and add suitable bindings to the environment
-    cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot bindings `thenC`
+       ; cgLetNoEscapeBindings live_in_rhss rhs_eob_info 
+                               maybe_cc_slot bindings
 
        -- Do the body
-    setEndOfBlockInfo rhs_eob_info (cgExpr body)
+       ; setEndOfBlockInfo rhs_eob_info (cgExpr body) }
 \end{code}
 
 
@@ -252,18 +255,11 @@ cgExpr (StgLetNoEscape live_in_whole_let live_in_rhss bindings body)
 
 SCC expressions are treated specially. They set the current cost
 centre.
+
 \begin{code}
-cgExpr (StgSCC cc expr)
-  = ASSERT(sccAbleCostCentre cc)
-    costCentresC
-       FSLIT("SET_CCC")
-       [mkCCostCentre cc, mkIntCLit (if isSccCountCostCentre cc then 1 else 0)]
-    `thenC`
-    cgExpr expr
+cgExpr (StgSCC cc expr) = do emitSetCCC cc; cgExpr expr
 \end{code}
 
-ToDo: counting of dict sccs ...
-
 %********************************************************
 %*                                                     *
 %*             Non-top-level bindings                  *
@@ -279,9 +275,9 @@ cgRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo)
        -- the Id is passed along so a binding can be set up
 
 cgRhs name (StgRhsCon maybe_cc con args)
-  = getArgAmodes args                          `thenFC` \ amodes ->
-    buildDynCon name maybe_cc con amodes       `thenFC` \ idinfo ->
-    returnFC (name, idinfo)
+  = do { amodes <- getArgAmodes args
+       ; idinfo <- buildDynCon name maybe_cc con amodes
+       ; returnFC (name, idinfo) }
 
 cgRhs name (StgRhsClosure cc bi fvs upd_flag srt args body)
   = mkRhsClosure name cc bi srt fvs upd_flag args body
@@ -328,7 +324,7 @@ mkRhsClosure        bndr cc bi srt
     cgStdRhsClosure bndr cc bi [the_fv] [] body lf_info [StgVarArg the_fv]
   where
     lf_info              = mkSelectorLFInfo bndr offset_into_int (isUpdatable upd_flag)
-    (_, params_w_offsets) = layOutDynConstr con idPrimRep params
+    (_, params_w_offsets) = layOutDynConstr con (addIdReps params)
                                -- Just want the layout
     maybe_offset         = assocMaybe params_w_offsets selectee
     Just the_offset      = maybe_offset
@@ -359,7 +355,7 @@ mkRhsClosure        bndr cc bi srt
                body@(StgApp fun_id args)
 
   | args `lengthIs` (arity-1)
-       && all isFollowableRep (map idPrimRep fvs) 
+       && all isFollowableArg (map idCgRep fvs) 
        && isUpdatable upd_flag
        && arity <= mAX_SPEC_AP_SIZE 
 
@@ -370,17 +366,15 @@ mkRhsClosure      bndr cc bi srt
        lf_info = mkApLFInfo bndr upd_flag arity
        -- the payload has to be in the correct order, hence we can't
        -- just use the fvs.
-       payload    = StgVarArg fun_id : args
-       arity      = length fvs
+       payload = StgVarArg fun_id : args
+       arity   = length fvs
 \end{code}
 
 The default case
 ~~~~~~~~~~~~~~~~
 \begin{code}
 mkRhsClosure bndr cc bi srt fvs upd_flag args body
-  = cgRhsClosure bndr cc bi srt fvs args body lf_info
-  where
-    lf_info = mkClosureLFInfo bndr NotTopLevel fvs upd_flag args
+  = cgRhsClosure bndr cc bi srt fvs upd_flag args body
 \end{code}
 
 
@@ -392,20 +386,19 @@ mkRhsClosure bndr cc bi srt fvs upd_flag args body
 \begin{code}
 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot 
        (StgNonRec binder rhs)
-  = cgLetNoEscapeRhs live_in_rhss rhs_eob_info maybe_cc_slot   
-                    NonRecursive binder rhs 
-                               `thenFC` \ (binder, info) ->
-    addBindC binder info
+  = do { (binder,info) <- cgLetNoEscapeRhs live_in_rhss rhs_eob_info 
+                                           maybe_cc_slot       
+                                           NonRecursive binder rhs 
+       ; addBindC binder info }
 
 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot (StgRec pairs)
-  = fixC (\ new_bindings ->
-               addBindsC new_bindings  `thenC`
-               listFCs [ cgLetNoEscapeRhs full_live_in_rhss 
+  = do { new_bindings <- fixC (\ new_bindings -> do
+               { addBindsC new_bindings
+               ; listFCs [ cgLetNoEscapeRhs full_live_in_rhss 
                                rhs_eob_info maybe_cc_slot Recursive b e 
-                       | (b,e) <- pairs ]
-    ) `thenFC` \ new_bindings ->
+                         | (b,e) <- pairs ] })
 
-    addBindsC new_bindings
+       ; addBindsC new_bindings }
   where
     -- We add the binders to the live-in-rhss set so that we don't
     -- delete the bindings for the binder from the environment!
@@ -443,41 +436,15 @@ cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot rec binder
 
 Little helper for primitives that return unboxed tuples.
 
-
 \begin{code}
-primRetUnboxedTuple :: StgOp -> [StgArg] -> Type -> Code
-primRetUnboxedTuple op args res_ty
-  = getArgAmodes args      `thenFC` \ arg_amodes1 ->
-    {-
-      For a foreign call, we might need to fiddle with some of the args:
-      for example, when passing a ByteArray#, we pass a ptr to the goods
-      rather than the heap object.
-    -}
-    let 
-       arg_amodes
-         | StgFCallOp{} <- op = zipWith shimFCallArg args arg_amodes1
-         | otherwise          = arg_amodes1
-    in
-    {-
-      put all the arguments in temporaries so they don't get stomped when
-      we push the return address.
-    -}
-    let
-      n_args             = length args
-      arg_uniqs                  = map mkBuiltinUnique [0 .. n_args-1]
-      arg_reps           = map getAmodeRep arg_amodes
-      arg_temps                  = zipWith CTemp arg_uniqs arg_reps
-    in
-    absC (mkAbstractCs (zipWith CAssign arg_temps arg_amodes)) `thenC`
-    {-
-      allocate some temporaries for the return values.
-    -}
-    let
-      ty_args     = tyConAppArgs (repType res_ty)
-      prim_reps   = map typePrimRep ty_args
-      temp_uniqs  = map mkBuiltinUnique [ n_args .. n_args + length ty_args - 1]
-      temp_amodes = zipWith CTemp temp_uniqs prim_reps
-    in
-    ccallReturnUnboxedTuple temp_amodes
-       (absC (COpStmt temp_amodes op arg_temps []))
+newUnboxedTupleRegs :: Type -> FCode ([CgRep], [CmmReg], [MachHint])
+newUnboxedTupleRegs res_ty =
+   let
+       ty_args = tyConAppArgs (repType res_ty)
+       (reps,hints) = unzip [ (rep, typeHint ty) | ty <- ty_args, 
+                                                   let rep = typeCgRep ty,
+                                                   nonVoidArg rep ]
+   in do
+   regs <- mapM (newTemp . argMachRep) reps
+   return (reps,regs,hints)
 \end{code}
diff --git a/ghc/compiler/codeGen/CgForeignCall.hs b/ghc/compiler/codeGen/CgForeignCall.hs
new file mode 100644 (file)
index 0000000..9a8ef9e
--- /dev/null
@@ -0,0 +1,216 @@
+-----------------------------------------------------------------------------
+--
+-- Code generation for foreign calls.
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+module CgForeignCall (
+  emitForeignCall,
+  cgForeignCall,
+  shimForeignCallArg,
+  emitSaveThreadState, -- will be needed by the Cmm parser
+  emitLoadThreadState, -- ditto
+  emitCloseNursery,
+  emitOpenNursery,
+ ) where
+
+#include "HsVersions.h"
+
+import StgSyn          ( StgLiveVars, StgArg, stgArgType )
+import CgProf          ( curCCS, curCCSAddr )
+import CgBindery       ( getVolatileRegs, getArgAmodes )
+import CgMonad
+import CgUtils         ( cmmOffsetW, cmmOffsetB, cmmLoadIndexW, newTemp )
+import Type            ( tyConAppTyCon, repType )
+import TysPrim
+import CLabel          ( mkForeignLabel, mkRtsCodeLabel )
+import Cmm
+import CmmUtils
+import MachOp
+import SMRep
+import ForeignCall
+import Constants
+import CmdLineOpts     ( opt_SccProfilingOn )
+import Outputable
+
+import Monad           ( when )
+
+-- -----------------------------------------------------------------------------
+-- Code generation for Foreign Calls
+
+cgForeignCall
+       :: [(CmmReg,MachHint)]  -- where to put the results
+       -> ForeignCall          -- the op
+       -> [StgArg]             -- arguments
+       -> StgLiveVars  -- live vars, in case we need to save them
+       -> Code
+cgForeignCall results fcall stg_args live
+  = do 
+  reps_n_amodes <- getArgAmodes stg_args
+  let
+       -- Get the *non-void* args, and jiggle them with shimForeignCall
+       arg_exprs = [ shimForeignCallArg stg_arg expr 
+                   | (stg_arg, (rep,expr)) <- stg_args `zip` reps_n_amodes, 
+                      nonVoidArg rep]
+
+       arg_hints = zip arg_exprs (map (typeHint.stgArgType) stg_args)
+  -- in
+  emitForeignCall results fcall arg_hints live
+
+
+emitForeignCall
+       :: [(CmmReg,MachHint)]  -- where to put the results
+       -> ForeignCall          -- the op
+       -> [(CmmExpr,MachHint)] -- arguments
+       -> StgLiveVars  -- live vars, in case we need to save them
+       -> Code
+
+emitForeignCall results (CCall (CCallSpec target cconv safety)) args live
+  | not (playSafe safety) 
+  = do 
+    vols <- getVolatileRegs live
+    stmtC (the_call vols)
+  
+  | otherwise -- it's a safe foreign call
+  = do
+    vols <- getVolatileRegs live
+    id <- newTemp wordRep
+    emitSaveThreadState
+    stmtC (CmmCall (CmmForeignCall suspendThread CCallConv) [(id,NoHint)]
+                       [ (CmmReg (CmmGlobal BaseReg), NoHint) ] 
+                       Nothing{-save all; ToDo-}
+                       )
+    stmtC (the_call vols)
+    stmtC (CmmCall (CmmForeignCall resumeThread CCallConv) []
+                       [ (CmmReg id, NoHint) ] (Just vols)
+                       )
+    emitLoadThreadState
+
+  where
+      (call_args, cmm_target)
+       = case target of
+          StaticTarget lbl -> (args, CmmLit (CmmLabel 
+                                       (mkForeignLabel lbl Nothing False)))
+                               -- ToDo: what about the size here?
+                               -- it is currently tacked on by the NCG.
+          DynamicTarget    ->  case args of (fn,_):rest -> (rest, fn)
+
+      the_call vols = CmmCall (CmmForeignCall cmm_target cconv) 
+                         results call_args (Just vols)
+
+
+emitForeignCall results (DNCall _) args live
+  = panic "emitForeignCall: DNCall"
+
+suspendThread = CmmLit (CmmLabel (mkRtsCodeLabel SLIT("suspendThread")))
+resumeThread  = CmmLit (CmmLabel (mkRtsCodeLabel SLIT("resumeThread")))
+
+-- -----------------------------------------------------------------------------
+-- Save/restore the thread state in the TSO
+
+-- This stuff can't be done in suspendThread/resumeThread, because it
+-- refers to global registers which aren't available in the C world.
+
+emitSaveThreadState = do
+  -- CurrentTSO->sp = Sp;
+  stmtC $ CmmStore (cmmOffset stgCurrentTSO tso_SP) stgSp
+  emitCloseNursery
+  -- and save the current cost centre stack in the TSO when profiling:
+  when opt_SccProfilingOn $
+       stmtC (CmmStore (cmmOffset stgCurrentTSO tso_CCCS) curCCS)
+
+   -- CurrentNursery->free = Hp+1;
+emitCloseNursery = stmtC $ CmmStore nursery_bdescr_free (cmmOffsetW stgHp 1)
+
+emitLoadThreadState = do
+  tso <- newTemp wordRep
+  stmtsC [
+       -- tso = CurrentTSO;
+       CmmAssign tso stgCurrentTSO,
+       -- Sp = tso->sp;
+       CmmAssign sp (CmmLoad (cmmOffset (CmmReg tso) tso_SP)
+                             wordRep),
+       -- SpLim = tso->stack + RESERVED_STACK_WORDS;
+       CmmAssign spLim (cmmOffsetW (cmmOffset (CmmReg tso) tso_STACK)
+                                   rESERVED_STACK_WORDS)
+    ]
+  emitOpenNursery
+  -- and load the current cost centre stack from the TSO when profiling:
+  when opt_SccProfilingOn $
+       stmtC (CmmStore curCCSAddr 
+               (CmmLoad (cmmOffset (CmmReg tso) tso_CCCS) wordRep))
+
+emitOpenNursery = stmtsC [
+        -- Hp = CurrentNursery->free - 1;
+       CmmAssign hp (cmmOffsetW (CmmLoad nursery_bdescr_free wordRep) (-1)),
+
+        -- HpLim = CurrentNursery->start + 
+       --              CurrentNursery->blocks*BLOCK_SIZE_W - 1;
+       CmmAssign hpLim
+           (cmmOffsetExpr
+               (CmmLoad nursery_bdescr_start wordRep)
+               (cmmOffset
+                 (CmmMachOp mo_wordMul [
+                   CmmMachOp (MO_S_Conv I32 wordRep)
+                     [CmmLoad nursery_bdescr_blocks I32],
+                   CmmLit (mkIntCLit bLOCK_SIZE)
+                  ])
+                 (-1)
+               )
+           )
+   ]
+
+
+nursery_bdescr_free   = cmmOffset stgCurrentNursery oFFSET_bdescr_free
+nursery_bdescr_start  = cmmOffset stgCurrentNursery oFFSET_bdescr_start
+nursery_bdescr_blocks = cmmOffset stgCurrentNursery oFFSET_bdescr_blocks
+
+tso_SP    = tsoFieldB     oFFSET_StgTSO_sp
+tso_STACK = tsoFieldB     oFFSET_StgTSO_stack
+tso_CCCS  = tsoProfFieldB oFFSET_StgTSO_CCCS
+
+-- The TSO struct has a variable header, and an optional StgTSOProfInfo in
+-- the middle.  The fields we're interested in are after the StgTSOProfInfo.
+tsoFieldB :: ByteOff -> ByteOff
+tsoFieldB off
+  | opt_SccProfilingOn = off + sIZEOF_StgTSOProfInfo + fixedHdrSize * wORD_SIZE
+  | otherwise          = off + fixedHdrSize * wORD_SIZE
+
+tsoProfFieldB :: ByteOff -> ByteOff
+tsoProfFieldB off = off + fixedHdrSize * wORD_SIZE
+
+stgSp            = CmmReg sp
+stgHp            = CmmReg hp
+stgCurrentTSO    = CmmReg currentTSO
+stgCurrentNursery = CmmReg currentNursery
+
+sp               = CmmGlobal Sp
+spLim            = CmmGlobal SpLim
+hp               = CmmGlobal Hp
+hpLim            = CmmGlobal HpLim
+currentTSO       = CmmGlobal CurrentTSO
+currentNursery           = CmmGlobal CurrentNursery
+
+-- -----------------------------------------------------------------------------
+-- For certain types passed to foreign calls, we adjust the actual
+-- value passed to the call.  Two main cases: for ForeignObj# we pass
+-- the pointer inside the ForeignObj# closure, and for ByteArray#/Array# we
+-- pass the address of the actual array, not the address of the heap object.
+
+shimForeignCallArg :: StgArg -> CmmExpr -> CmmExpr
+shimForeignCallArg arg expr
+  | tycon == foreignObjPrimTyCon
+       = cmmLoadIndexW expr fixedHdrSize
+
+  | tycon == arrayPrimTyCon || tycon == mutableArrayPrimTyCon
+       = cmmOffsetB expr arrPtrsHdrSize
+
+  | tycon == byteArrayPrimTyCon || tycon == mutableByteArrayPrimTyCon
+       = cmmOffsetB expr arrWordsHdrSize
+
+  | otherwise = expr
+  where        
+       -- should be a tycon app, since this is a foreign call
+       tycon = tyConAppTyCon (repType (stgArgType arg))
index 2329dcb..6abffe7 100644 (file)
 %
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
-% $Id: CgHeapery.lhs,v 1.39 2003/07/28 16:05:35 simonmar Exp $
+% $Id: CgHeapery.lhs,v 1.40 2004/08/13 13:06:00 simonmar Exp $
 %
 \section[CgHeapery]{Heap management functions}
 
 \begin{code}
 module CgHeapery (
-       funEntryChecks, altHeapCheck, unbxTupleHeapCheck, thunkChecks,
-       allocDynClosure,
+       initHeapUsage, getVirtHp, setVirtHp, setRealHp, 
+       getHpRelOffset, hpRel,
 
-        -- new functions, basically inserting macro calls into Code -- HWL
-        ,fetchAndReschedule, yield
+       funEntryChecks, thunkEntryChecks, 
+       altHeapCheck, unbxTupleHeapCheck, 
+       hpChkGen, hpChkNodePointsAssignSp0,
+       stkChkGen, stkChkNodePoints,
+
+       layOutDynConstr, layOutStaticConstr,
+       mkVirtHeapOffsets, mkStaticClosureFields, mkStaticClosure,
+
+       allocDynClosure, emitSetDynHdr
     ) where
 
 #include "HsVersions.h"
 
-import AbsCSyn
+import Constants       ( mIN_UPD_SIZE )
 import StgSyn          ( AltType(..) )
-import CLabel
+import CLabel          ( CLabel, mkRtsCodeLabel )
+import CgUtils         ( mkWordCLit, cmmRegOffW, cmmOffsetW,
+                         cmmOffsetExprB )
 import CgMonad
-import CgStackery      ( getFinalStackHW )
-import AbsCUtils       ( mkAbstractCs, getAmodeRep )
-import CgUsages                ( getVirtAndRealHp, getRealSp, setVirtHp, setRealHp,
-                         initHeapUsage
-                       )
-import CgRetConv       ( dataReturnConvPrim )
-import ClosureInfo     ( closureSize, closureGoodStuffSize,
-                         slopSize, allocProfilingMsg, ClosureInfo
-                       )
+import CgProf          ( staticProfHdr, profDynAlloc, dynProfHdr )
+import CgTicky         ( staticTickyHdr, tickyDynAlloc, tickyAllocHeap )
+import CgParallel      ( staticGranHdr, staticParHdr, doGranAllocate )
+import CgStackery      ( getFinalStackHW, getRealSp )
+import CgCallConv      ( mkRegLiveness )
+import ClosureInfo     ( closureSize, closureUpdReqd,
+                         staticClosureNeedsLink, 
+                         mkConInfo, 
+                         infoTableLabelFromCI, closureLabelFromCI,
+                         nodeMustPointToIt, closureLFInfo,                     
+                         ClosureInfo )
+import SMRep           ( CgRep(..), cgRepSizeW, separateByPtrFollowness,
+                         WordOff, fixedHdrSize, isVoidArg, primRepToCgRep )
+
+import Cmm             ( CmmLit(..), CmmStmt(..), CmmExpr(..), GlobalReg(..),
+                         CmmReg(..), hpReg, nodeReg, spReg )
+import MachOp          ( mo_wordULt, mo_wordUGt, mo_wordSub )
+import CmmUtils                ( mkIntCLit, CmmStmts, noStmts, oneStmt, plusStmts,
+                         mkStmts )
+import Id              ( Id )
+import DataCon         ( DataCon )
 import TyCon           ( tyConPrimRep )
-import PrimRep         ( PrimRep(..), isFollowableRep )
-import CmdLineOpts     ( opt_GranMacros )
+import CostCentre      ( CostCentreStack )
+import Util            ( mapAccumL, filterOut )
+import Constants       ( wORD_SIZE )
 import Outputable
-#ifdef DEBUG
-import PprAbsC         ( pprMagicId ) 
-#endif
 
 import GLAEXTS
+
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
+\subsection[CgUsages-heapery]{Monad things for fiddling with heap usage}
+%*                                                                     *
+%************************************************************************
+
+The heap always grows upwards, so hpRel is easy
+
+\begin{code}
+hpRel :: VirtualHpOffset       -- virtual offset of Hp
+      -> VirtualHpOffset       -- virtual offset of The Thing
+      -> WordOff                       -- integer word offset
+hpRel hp off = off - hp
+\end{code}
+
+@initHeapUsage@ applies a function to the amount of heap that it uses.
+It initialises the heap usage to zeros, and passes on an unchanged
+heap usage.
+
+It is usually a prelude to performing a GC check, so everything must
+be in a tidy and consistent state.
+
+rje: Note the slightly suble fixed point behaviour needed here
+
+\begin{code}
+initHeapUsage :: (VirtualHpOffset -> Code) -> Code
+initHeapUsage fcode
+  = do { orig_hp_usage <- getHpUsage
+       ; setHpUsage initHpUsage
+       ; fixC (\heap_usage2 -> do
+               { fcode (heapHWM heap_usage2)
+               ; getHpUsage })
+       ; setHpUsage orig_hp_usage }
+
+setVirtHp :: VirtualHpOffset -> Code
+setVirtHp new_virtHp
+  = do { hp_usage <- getHpUsage
+       ; setHpUsage (hp_usage {virtHp = new_virtHp}) }
+
+getVirtHp :: FCode VirtualHpOffset
+getVirtHp 
+  = do { hp_usage <- getHpUsage
+       ; return (virtHp hp_usage) }
+
+setRealHp ::  VirtualHpOffset -> Code
+setRealHp new_realHp
+  = do { hp_usage <- getHpUsage
+       ; setHpUsage (hp_usage {realHp = new_realHp}) }
+
+getHpRelOffset :: VirtualHpOffset -> FCode CmmExpr
+getHpRelOffset virtual_offset
+  = do { hp_usg <- getHpUsage
+       ; return (cmmRegOffW hpReg (hpRel (realHp hp_usg) virtual_offset)) }
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
+               Layout of heap objects
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+layOutDynConstr, layOutStaticConstr
+       :: DataCon      
+       -> [(CgRep,a)]
+       -> (ClosureInfo,
+           [(a,VirtualHpOffset)])
+
+layOutDynConstr    = layOutConstr False
+layOutStaticConstr = layOutConstr True
+
+layOutConstr is_static data_con args
+   = (mkConInfo is_static data_con tot_wds ptr_wds,
+      things_w_offsets)
+  where
+    (tot_wds,           -- #ptr_wds + #nonptr_wds
+     ptr_wds,           -- #ptr_wds
+     things_w_offsets) = mkVirtHeapOffsets args
+\end{code}
+
+@mkVirtHeapOffsets@ always returns boxed things with smaller offsets
+than the unboxed things, and furthermore, the offsets in the result
+list
+
+\begin{code}
+mkVirtHeapOffsets
+         :: [(CgRep,a)]        -- Things to make offsets for
+         -> (WordOff,          -- *Total* number of words allocated
+             WordOff,          -- Number of words allocated for *pointers*
+             [(a, VirtualHpOffset)])
+                               -- Things with their offsets from start of 
+                               --  object in order of increasing offset
+
+-- First in list gets lowest offset, which is initial offset + 1.
+
+mkVirtHeapOffsets things
+  = let non_void_things                      = filterOut (isVoidArg . fst) things
+       (ptrs, non_ptrs)              = separateByPtrFollowness non_void_things
+       (wds_of_ptrs, ptrs_w_offsets) = mapAccumL computeOffset 0 ptrs
+       (tot_wds, non_ptrs_w_offsets) = mapAccumL computeOffset wds_of_ptrs non_ptrs
+    in
+    (tot_wds, wds_of_ptrs, ptrs_w_offsets ++ non_ptrs_w_offsets)
+  where
+    computeOffset wds_so_far (rep, thing)
+      = (wds_so_far + cgRepSizeW rep, (thing, fixedHdrSize + wds_so_far))
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
+               Lay out a static closure
+%*                                                                     *
+%************************************************************************
+
+Make a static closure, adding on any extra padding needed for CAFs,
+and adding a static link field if necessary.
+
+\begin{code}
+mkStaticClosureFields 
+       :: ClosureInfo 
+       -> CostCentreStack 
+       -> Bool                 -- Has CAF refs
+       -> [CmmLit]             -- Payload
+       -> [CmmLit]             -- The full closure
+mkStaticClosureFields cl_info ccs caf_refs payload
+  = mkStaticClosure info_lbl ccs payload padding_wds static_link_field
+  where
+    info_lbl = infoTableLabelFromCI cl_info
+
+    upd_reqd = closureUpdReqd cl_info
+
+    -- for the purposes of laying out the static closure, we consider all
+    -- thunks to be "updatable", so that the static link field is always
+    -- in the same place.
+    padding_wds
+       | not upd_reqd = []
+       | otherwise    = replicate n (mkIntCLit 0) -- a bunch of 0s
+       where n = max 0 (mIN_UPD_SIZE - length payload)
+
+       -- We always have a static link field for a thunk, it's used to
+       -- save the closure's info pointer when we're reverting CAFs
+       -- (see comment in Storage.c)
+    static_link_field
+       | upd_reqd || staticClosureNeedsLink cl_info = [static_link_value]
+       | otherwise                                  = []
+
+       -- for a static constructor which has NoCafRefs, we set the
+       -- static link field to a non-zero value so the garbage
+       -- collector will ignore it.
+    static_link_value
+       | caf_refs      = mkIntCLit 0
+       | otherwise     = mkIntCLit 1
+
+mkStaticClosure :: CLabel -> CostCentreStack -> [CmmLit]
+  -> [CmmLit] -> [CmmLit] -> [CmmLit]
+mkStaticClosure info_lbl ccs payload padding_wds static_link_field
+  =  [CmmLabel info_lbl]
+  ++ variable_header_words
+  ++ payload
+  ++ padding_wds
+  ++ static_link_field
+  where
+    variable_header_words
+       =  staticGranHdr
+       ++ staticParHdr
+       ++ staticProfHdr ccs
+       ++ staticTickyHdr
 \end{code}
 
 %************************************************************************
@@ -54,86 +245,53 @@ beginning of every slow entry code in order to simulate the fetching of
 closures. If fetching is necessary (i.e. current closure is not local) then
 an automatic context switch is done.
 
------------------------------------------------------------------------------
+--------------------------------------------------------------
 A heap/stack check at a function or thunk entry point.
 
 \begin{code}
-funEntryChecks :: Maybe CLabel -> AbstractC -> Code -> Code
-funEntryChecks closure_lbl reg_save_code code 
-  = hpStkCheck closure_lbl True reg_save_code code
-
-thunkChecks :: Maybe CLabel -> Code -> Code
-thunkChecks closure_lbl code 
-  = hpStkCheck closure_lbl False AbsCNop code
-
-hpStkCheck
-       :: Maybe CLabel                 -- function closure
-       -> Bool                         -- is a function? (not a thunk)
-       -> AbstractC                    -- register saves
-       -> Code
-       -> Code
-
-hpStkCheck closure_lbl is_fun reg_save_code code
-  =  getFinalStackHW                            (\ spHw -> 
-     getRealSp                                  `thenFC` \ sp ->
-     let stk_words = spHw - sp in
-     initHeapUsage                              (\ hHw  ->
-
-     getTickyCtrLabel `thenFC` \ ticky_ctr ->
-
-     absC (checking_code stk_words hHw ticky_ctr) `thenC`
-
-     setRealHp hHw `thenC`
-     code))
-
+funEntryChecks :: ClosureInfo -> CmmStmts -> Code -> Code
+funEntryChecks cl_info reg_save_code code 
+  = hpStkCheck cl_info True reg_save_code code
+
+thunkEntryChecks :: ClosureInfo -> Code -> Code
+thunkEntryChecks cl_info code 
+  = hpStkCheck cl_info False noStmts code
+
+hpStkCheck :: ClosureInfo      -- Function closure
+          -> Bool              -- Is a function? (not a thunk)
+          -> CmmStmts          -- Register saves
+          -> Code
+          -> Code
+
+hpStkCheck cl_info is_fun reg_save_code code
+  =  getFinalStackHW   $ \ spHw -> do
+       { sp <- getRealSp
+       ; let stk_words = spHw - sp
+       ; initHeapUsage $ \ hpHw  -> do
+           {   -- Emit heap checks, but be sure to do it lazily so 
+               -- that the conditionals on hpHw don't cause a black hole
+             codeOnly $ do
+               { do_checks stk_words hpHw full_save_code rts_label
+               ; tickyAllocHeap hpHw }
+           ; setRealHp hpHw
+           ; code }
+       }
   where
-    node_asst
-       | Just lbl <- closure_lbl = CAssign nodeReg (CLbl lbl PtrRep)
-       | otherwise = AbsCNop
-
-    save_code = mkAbstractCs [node_asst, reg_save_code]
-
-    checking_code stk hp ctr
-        = mkAbstractCs 
-         [ if is_fun
-               then do_checks_fun stk hp save_code
-               else do_checks_np  stk hp save_code,
-            if hp == 0
-               then AbsCNop 
-               else profCtrAbsC FSLIT("TICK_ALLOC_HEAP") 
-                         [ mkIntCLit hp, CLbl ctr DataPtrRep ]
-         ]
-
-
--- For functions:
-
-do_checks_fun
-       :: Int          -- stack headroom
-       -> Int          -- heap  headroom
-       -> AbstractC    -- assignments to perform on failure
-       -> AbstractC
-do_checks_fun 0 0 _ = AbsCNop
-do_checks_fun 0 hp_words assts =
-    CCheck HP_CHK_FUN [ mkIntCLit hp_words ] assts
-do_checks_fun stk_words 0 assts =
-    CCheck STK_CHK_FUN [ mkIntCLit stk_words ] assts
-do_checks_fun stk_words hp_words assts =
-    CCheck HP_STK_CHK_FUN [ mkIntCLit stk_words, mkIntCLit hp_words ] assts
-
--- For thunks:
-
-do_checks_np
-       :: Int          -- stack headroom
-       -> Int          -- heap  headroom
-       -> AbstractC    -- assignments to perform on failure
-       -> AbstractC
-do_checks_np 0 0 _ = AbsCNop
-do_checks_np 0 hp_words assts =
-    CCheck HP_CHK_NP [ mkIntCLit hp_words ] assts
-do_checks_np stk_words 0 assts =
-    CCheck STK_CHK_NP [ mkIntCLit stk_words ] assts
-do_checks_np stk_words hp_words assts =
-    CCheck HP_STK_CHK_NP [ mkIntCLit stk_words, mkIntCLit hp_words ] assts
+    node_asst 
+       | nodeMustPointToIt (closureLFInfo cl_info)
+       = noStmts
+       | otherwise
+       = oneStmt (CmmAssign nodeReg (CmmLit (CmmLabel closure_lbl)))
+    closure_lbl = closureLabelFromCI cl_info
+
+    full_save_code = node_asst `plusStmts` reg_save_code
+
+    rts_label | is_fun    = CmmReg (CmmGlobal GCFun)
+                               -- Function entry point
+             | otherwise = CmmReg (CmmGlobal GCEnter1)
+                               -- Thunk or case return
+       -- In the thunk/case-return case, R1 points to a closure
+       -- which should be (re)-entered after GC
 \end{code}
 
 Heap checks in a case alternative are nice and easy, provided this is
@@ -153,12 +311,6 @@ For primitive returns, we have an unlifted value in some register
 (either R1 or FloatReg1 or DblReg1).  This means using specialised
 heap-check code for these cases.
 
-For unboxed tuple returns, there are an arbitrary number of possibly
-unboxed return values, some of which will be in registers, and the
-others will be on the stack.  We always organise the stack-resident
-fields into pointers & non-pointers, and pass the number of each to
-the heap check code.
-
 \begin{code}
 altHeapCheck 
     :: AltType -- PolyAlt, PrimAlt, AlgAlt, but *not* UbxTupAlt
@@ -166,150 +318,183 @@ altHeapCheck
     -> Code    -- Continuation
     -> Code
 altHeapCheck alt_type code
-  = initHeapUsage (\ hHw -> 
-       do_heap_chk hHw `thenC` 
-       setRealHp hHw   `thenC`
-       code)
+  = initHeapUsage $ \ hpHw -> do
+       { codeOnly $ do
+            { do_checks 0 {- no stack chk -} hpHw
+                        noStmts {- nothign to save -}
+                        (rts_label alt_type)
+            ; tickyAllocHeap hpHw }
+       ; setRealHp hpHw
+       ; code }
   where
-    do_heap_chk :: HeapOffset -> Code
-    do_heap_chk words_required
-      = getTickyCtrLabel       `thenFC` \ ctr ->
-       absC (  -- NB The conditional is inside the absC,
-               -- so the monadic stuff doesn't depend on
-               -- the value of words_required!
-              if words_required == 0
-              then  AbsCNop
-              else  mkAbstractCs 
-                      [ CCheck (checking_code alt_type) 
-                           [mkIntCLit words_required] AbsCNop,
-                        profCtrAbsC FSLIT("TICK_ALLOC_HEAP") 
-                           [ mkIntCLit words_required, CLbl ctr DataPtrRep ]
-                      ])
-
-    checking_code PolyAlt
-      = HP_CHK_UNPT_R1 -- Do *not* enter R1 after a heap check in
-                       -- a polymorphic case.  It might be a function
-                       -- and the entry code for a function (currently)
-                       -- applies it
-                       --
-                       -- However R1 is guaranteed to be a pointer
-
-    checking_code (AlgAlt tc)
-      =        HP_CHK_NP       -- Enter R1 after the heap check; it's a pointer
-                       -- The "NP" is short for "Node (R1) Points to it"
+    rts_label PolyAlt = CmmLit (CmmLabel (mkRtsCodeLabel SLIT( "stg_gc_unpt_r1")))
+       -- Do *not* enter R1 after a heap check in
+       -- a polymorphic case.  It might be a function
+       -- and the entry code for a function (currently)
+       -- applies it
+       --
+       -- However R1 is guaranteed to be a pointer
+
+    rts_label (AlgAlt tc) = stg_gc_enter1
+       -- Enter R1 after the heap check; it's a pointer
        
-    checking_code (PrimAlt tc)
-      = case dataReturnConvPrim (tyConPrimRep tc) of
-         VoidReg      -> HP_CHK_NOREGS
-         FloatReg  1# -> HP_CHK_F1
-         DoubleReg 1# -> HP_CHK_D1
-         LongReg _ 1# -> HP_CHK_L1
-         VanillaReg rep 1# 
-           | isFollowableRep rep -> HP_CHK_UNPT_R1     -- R1 is boxed but unlifted: 
-           | otherwise           -> HP_CHK_UNBX_R1     -- R1 is unboxed
-#ifdef DEBUG
-         other_reg -> pprPanic "CgHeapery.altHeapCheck" (ppr tc <+> pprMagicId other_reg)
-#endif
-
--- Unboxed tuple alternatives and let-no-escapes (the two most annoying
--- constructs to generate code for!):
+    rts_label (PrimAlt tc)
+      = CmmLit $ CmmLabel $ 
+       case primRepToCgRep (tyConPrimRep tc) of
+         VoidArg   -> mkRtsCodeLabel SLIT( "stg_gc_noregs")
+         FloatArg  -> mkRtsCodeLabel SLIT( "stg_gc_f1")
+         DoubleArg -> mkRtsCodeLabel SLIT( "stg_gc_d1")
+         LongArg   -> mkRtsCodeLabel SLIT( "stg_gc_l1")
+                               -- R1 is boxed but unlifted: 
+         PtrArg    -> mkRtsCodeLabel SLIT( "stg_gc_unpt_r1")
+                               -- R1 is unboxed:
+         NonPtrArg -> mkRtsCodeLabel SLIT( "stg_gc_unbx_r1")
+
+    rts_label (UbxTupAlt _) = panic "altHeapCheck"
+\end{code}
+
 
+Unboxed tuple alternatives and let-no-escapes (the two most annoying
+constructs to generate code for!)  For unboxed tuple returns, there
+are an arbitrary number of possibly unboxed return values, some of
+which will be in registers, and the others will be on the stack.  We
+always organise the stack-resident fields into pointers &
+non-pointers, and pass the number of each to the heap check code.
+
+\begin{code}
 unbxTupleHeapCheck 
-       :: [MagicId]            -- live registers
-       -> Int                  -- no. of stack slots containing ptrs
-       -> Int                  -- no. of stack slots containing nonptrs
-       -> AbstractC            -- code to insert in the failure path
+       :: [(Id, GlobalReg)]    -- Live registers
+       -> WordOff      -- no. of stack slots containing ptrs
+       -> WordOff      -- no. of stack slots containing nonptrs
+       -> CmmStmts     -- code to insert in the failure path
        -> Code
        -> Code
 
 unbxTupleHeapCheck regs ptrs nptrs fail_code code
-  -- we can't manage more than 255 pointers/non-pointers in a generic
-  -- heap check.
+  -- We can't manage more than 255 pointers/non-pointers 
+  -- in a generic heap check.
   | ptrs > 255 || nptrs > 255 = panic "altHeapCheck"
-  | otherwise = initHeapUsage (\ hHw -> do_heap_chk hHw `thenC` code)
+  | otherwise 
+  = initHeapUsage $ \ hpHw -> do
+       { codeOnly $ do { do_checks 0 {- no stack check -} hpHw
+                                   full_fail_code rts_label
+                       ; tickyAllocHeap hpHw }
+       ; setRealHp hpHw
+       ; code }
   where
-    do_heap_chk words_required 
-      = getTickyCtrLabel `thenFC` \ ctr ->
-       absC ( if words_required == 0
-                 then  AbsCNop
-                 else  mkAbstractCs 
-                       [ checking_code words_required,
-                         profCtrAbsC FSLIT("TICK_ALLOC_HEAP") 
-                           [ mkIntCLit words_required, CLbl ctr DataPtrRep ]
-                       ]
-       )  `thenC`
-       setRealHp words_required
-
-    liveness = I# (word2Int# (mkRegLiveness regs ptrs nptrs))
-    checking_code words_required = CCheck HP_CHK_UNBX_TUPLE
-                                            [mkIntCLit words_required, 
-                                             mkIntCLit liveness]
-                                            fail_code
-
--- build up a bitmap of the live pointer registers
-
-#if __GLASGOW_HASKELL__ >= 503
-shiftL = uncheckedShiftL#
-#else
-shiftL = shiftL#
-#endif
-
-mkRegLiveness :: [MagicId] -> Int -> Int -> Word#
-mkRegLiveness [] (I# ptrs) (I# nptrs) =  
-  (int2Word# nptrs `shiftL` 16#) `or#` (int2Word# ptrs `shiftL` 24#)
-mkRegLiveness (VanillaReg rep i : regs) ptrs nptrs | isFollowableRep rep 
-  =  ((int2Word# 1#) `shiftL` (i -# 1#)) `or#` mkRegLiveness regs ptrs nptrs
-mkRegLiveness (_ : regs)  ptrs nptrs =  mkRegLiveness regs ptrs nptrs
-
--- The two functions below are only used in a GranSim setup
--- Emit macro for simulating a fetch and then reschedule
-
-fetchAndReschedule ::   [MagicId]               -- Live registers
-                       -> Bool                 -- Node reqd?
-                       -> Code
-
-fetchAndReschedule regs node_reqd  = 
-      if (node `elem` regs || node_reqd)
-       then fetch_code `thenC` reschedule_code
-       else absC AbsCNop
-      where
-        liveness_mask = mkRegLiveness regs 0 0
-       reschedule_code = absC  (CMacroStmt GRAN_RESCHEDULE [
-                                 mkIntCLit (I# (word2Int# liveness_mask)), 
-                                mkIntCLit (if node_reqd then 1 else 0)])
-
-        --HWL: generate GRAN_FETCH macro for GrAnSim
-        --     currently GRAN_FETCH and GRAN_FETCH_AND_RESCHEDULE are miai
-       fetch_code = absC (CMacroStmt GRAN_FETCH [])
+    full_fail_code  = fail_code `plusStmts` oneStmt assign_liveness
+    assign_liveness = CmmAssign (CmmGlobal (VanillaReg 9))     -- Ho ho ho!
+                               (CmmLit (mkWordCLit liveness))
+    liveness       = mkRegLiveness regs ptrs nptrs
+    rts_label      = CmmLit (CmmLabel (mkRtsCodeLabel SLIT("stg_gc_ut")))
+
 \end{code}
 
-The @GRAN_YIELD@ macro is taken from JSM's  code for Concurrent Haskell. It
-allows to context-switch at  places where @node@ is  not alive (it uses the
-@Continue@ rather  than the @EnterNodeCode@  function in the  RTS). We emit
-this kind of macro at the beginning of the following kinds of basic bocks:
-\begin{itemize}
- \item Slow entry code where node is not alive (see @CgClosure.lhs@). Normally 
-       we use @fetchAndReschedule@ at a slow entry code.
- \item Fast entry code (see @CgClosure.lhs@).
- \item Alternatives in case expressions (@CLabelledCode@ structures), provided
-       that they are not inlined (see @CgCases.lhs@). These alternatives will 
-       be turned into separate functions.
-\end{itemize}
+
+%************************************************************************
+%*                                                                     *
+               Heap/Stack Checks.
+%*                                                                     *
+%************************************************************************
+
+When failing a check, we save a return address on the stack and
+jump to a pre-compiled code fragment that saves the live registers
+and returns to the scheduler.
+
+The return address in most cases will be the beginning of the basic
+block in which the check resides, since we need to perform the check
+again on re-entry because someone else might have stolen the resource
+in the meantime.
 
 \begin{code}
-yield ::   [MagicId]               -- Live registers
-             -> Bool                 -- Node reqd?
-             -> Code 
-
-yield regs node_reqd = 
-   if opt_GranMacros && node_reqd
-     then yield_code
-     else absC AbsCNop
-   where
-     liveness_mask = mkRegLiveness regs 0 0
-     yield_code = 
-       absC (CMacroStmt GRAN_YIELD 
-                          [mkIntCLit (I# (word2Int# liveness_mask))])
+do_checks :: WordOff   -- Stack headroom
+         -> WordOff    -- Heap  headroom
+         -> CmmStmts   -- Assignments to perform on failure
+         -> CmmExpr    -- Rts address to jump to on failure
+         -> Code
+do_checks 0 0 _ _   = nopC
+do_checks stk hp reg_save_code rts_lbl
+  = do_checks' (CmmLit (mkIntCLit (stk*wORD_SIZE))) 
+              (CmmLit (mkIntCLit (hp*wORD_SIZE)))
+        (stk /= 0) (hp /= 0) reg_save_code rts_lbl
+
+-- The offsets are now in *bytes*
+do_checks' stk_expr hp_expr stk_nonzero hp_nonzero reg_save_code rts_lbl
+  = do { doGranAllocate hp_expr
+
+       -- Emit a block for the heap-check-failure code
+       ; blk_id <- forkLabelledCode $ do
+                       { whenC hp_nonzero $
+                               stmtC (CmmAssign (CmmGlobal HpAlloc) hp_expr)
+                       ; emitStmts reg_save_code
+                       ; stmtC (CmmJump rts_lbl []) }
+
+       -- Check for stack overflow *FIRST*; otherwise
+       -- we might bumping Hp and then failing stack oflo
+       ; whenC stk_nonzero
+               (stmtC (CmmCondBranch stk_oflo blk_id))
+
+       ; whenC hp_nonzero
+               (stmtsC [CmmAssign hpReg 
+                               (cmmOffsetExprB (CmmReg hpReg) hp_expr),
+                       CmmCondBranch hp_oflo blk_id]) 
+               -- Bump heap pointer, and test for heap exhaustion
+               -- Note that we don't move the heap pointer unless the 
+               -- stack check succeeds.  Otherwise we might end up
+               -- with slop at the end of the current block, which can 
+               -- confuse the LDV profiler.
+    }
+  where
+       -- Stk overflow if (Sp - stk_bytes < SpLim)
+    stk_oflo = CmmMachOp mo_wordULt 
+                 [CmmMachOp mo_wordSub [CmmReg spReg, stk_expr],
+                  CmmReg (CmmGlobal SpLim)]
+
+       -- Hp overflow if (Hpp > HpLim)
+       -- (Hp has been incremented by now)
+       -- HpLim points to the LAST WORD of valid allocation space.
+    hp_oflo = CmmMachOp mo_wordUGt 
+                 [CmmReg hpReg, CmmReg (CmmGlobal HpLim)]
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+     Generic Heap/Stack Checks - used in the RTS
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+hpChkGen :: CmmExpr -> CmmExpr -> CmmExpr -> Code
+hpChkGen bytes liveness reentry
+  = do_checks' (CmmLit (mkIntCLit 0)) bytes False True assigns stg_gc_gen
+  where
+    assigns = mkStmts [
+               CmmAssign (CmmGlobal (VanillaReg 9))  liveness,
+               CmmAssign (CmmGlobal (VanillaReg 10)) reentry
+               ]
+
+-- a heap check where R1 points to the closure to enter on return, and
+-- we want to assign to Sp[0] on failure (used in AutoApply.cmm:BUILD_PAP).
+hpChkNodePointsAssignSp0 :: CmmExpr -> CmmExpr -> Code
+hpChkNodePointsAssignSp0 bytes sp0
+  = do_checks' (CmmLit (mkIntCLit 0)) bytes False True assign stg_gc_enter1
+  where assign = oneStmt (CmmStore (CmmReg spReg) sp0)
+
+stkChkGen :: CmmExpr -> CmmExpr -> CmmExpr -> Code
+stkChkGen bytes liveness reentry
+  = do_checks' bytes (CmmLit (mkIntCLit 0)) True False assigns stg_gc_gen
+  where
+    assigns = mkStmts [
+               CmmAssign (CmmGlobal (VanillaReg 9))  liveness,
+               CmmAssign (CmmGlobal (VanillaReg 10)) reentry
+               ]
+
+stkChkNodePoints :: CmmExpr -> Code
+stkChkNodePoints bytes
+  = do_checks' bytes (CmmLit (mkIntCLit 0)) True False noStmts stg_gc_enter1
+
+stg_gc_gen = CmmLit (CmmLabel (mkRtsCodeLabel SLIT("stg_gc_gen")))
+stg_gc_enter1 = CmmReg (CmmGlobal GCEnter1)
 \end{code}
 
 %************************************************************************
@@ -324,47 +509,65 @@ to account for this.
 \begin{code}
 allocDynClosure
        :: ClosureInfo
-       -> CAddrMode            -- Cost Centre to stick in the object
-       -> CAddrMode            -- Cost Centre to blame for this alloc
+       -> CmmExpr              -- Cost Centre to stick in the object
+       -> CmmExpr              -- Cost Centre to blame for this alloc
                                -- (usually the same; sometimes "OVERHEAD")
 
-       -> [(CAddrMode, VirtualHeapOffset)]     -- Offsets from start of the object
-                                               -- ie Info ptr has offset zero.
-       -> FCode VirtualHeapOffset              -- Returns virt offset of object
+       -> [(CmmExpr, VirtualHpOffset)] -- Offsets from start of the object
+                                       -- ie Info ptr has offset zero.
+       -> FCode VirtualHpOffset        -- Returns virt offset of object
 
-allocDynClosure closure_info use_cc blame_cc amodes_with_offsets
-  = getVirtAndRealHp                           `thenFC` \ (virtHp, realHp) ->
+allocDynClosure cl_info use_cc blame_cc amodes_with_offsets
+  = do { virt_hp <- getVirtHp
 
        -- FIND THE OFFSET OF THE INFO-PTR WORD
-       -- virtHp points to last allocated word, ie 1 *before* the
-       -- info-ptr word of new object.
-    let  info_offset = virtHp + 1
-
-       -- do_move IS THE ASSIGNMENT FUNCTION
-        do_move (amode, offset_from_start)
-          = CAssign (CVal (hpRel realHp
-                                 (info_offset + offset_from_start))
-                          (getAmodeRep amode))
-                    amode
-    in
+       ; let   info_offset = virt_hp + 1
+               -- info_offset is the VirtualHpOffset of the first
+               -- word of the new object
+               -- Remember, virtHp points to last allocated word, 
+               -- ie 1 *before* the info-ptr word of new object.
+
+               info_ptr = CmmLit (CmmLabel (infoTableLabelFromCI cl_info))
+               hdr_w_offsets = initDynHdr info_ptr use_cc `zip` [0..]
+
        -- SAY WHAT WE ARE ABOUT TO DO
-    profCtrC (allocProfilingMsg closure_info)
-                          [mkIntCLit (closureGoodStuffSize closure_info),
-                           mkIntCLit slop_size]        `thenC`
+       ; profDynAlloc cl_info use_cc   
+               -- ToDo: This is almost certainly wrong
+               -- We're ignoring blame_cc. But until we've
+               -- fixed the boxing hack in chooseDynCostCentres etc,
+               -- we're worried about making things worse by "fixing"
+               -- this part to use blame_cc!
 
-       -- GENERATE THE CODE
-    absC ( mkAbstractCs (
-          [ CInitHdr closure_info 
-               (CAddr (hpRel realHp info_offset)) 
-               use_cc closure_size ]
-          ++ (map do_move amodes_with_offsets)))       `thenC`
+       ; tickyDynAlloc cl_info
 
-       -- BUMP THE VIRTUAL HEAP POINTER
-    setVirtHp (virtHp + closure_size)                  `thenC`
+       -- ALLOCATE THE OBJECT
+       ; base <- getHpRelOffset info_offset
+       ; hpStore base (hdr_w_offsets ++ amodes_with_offsets)
 
+       -- BUMP THE VIRTUAL HEAP POINTER
+       ; setVirtHp (virt_hp + closureSize cl_info)
+       
        -- RETURN PTR TO START OF OBJECT
-    returnFC info_offset
-  where
-    closure_size = closureSize closure_info
-    slop_size    = slopSize closure_info
+       ; returnFC info_offset }
+
+
+initDynHdr :: CmmExpr 
+          -> CmmExpr           -- Cost centre to put in object
+          -> [CmmExpr]
+initDynHdr info_ptr cc
+  =  [info_ptr]
+       -- ToDo: Gransim stuff
+       -- ToDo: Parallel stuff
+  ++ dynProfHdr cc
+       -- No ticky header
+
+hpStore :: CmmExpr -> [(CmmExpr, VirtualHpOffset)] -> Code
+-- Store the item (expr,off) in base[off]
+hpStore base es
+  = stmtsC [ CmmStore (cmmOffsetW base off) val 
+          | (val, off) <- es ]
+
+emitSetDynHdr :: CmmExpr -> CmmExpr -> CmmExpr -> Code
+emitSetDynHdr base info_ptr ccs 
+  = hpStore base (zip (initDynHdr info_ptr ccs) [0..])
 \end{code}
diff --git a/ghc/compiler/codeGen/CgInfoTbls.hs b/ghc/compiler/codeGen/CgInfoTbls.hs
new file mode 100644 (file)
index 0000000..2f10073
--- /dev/null
@@ -0,0 +1,538 @@
+-----------------------------------------------------------------------------
+--
+-- Building info tables.
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+module CgInfoTbls (
+       emitClosureCodeAndInfoTable,
+       emitInfoTableAndCode,
+       dataConTagZ,
+       getSRTInfo,
+       emitDirectReturnTarget, emitAlgReturnTarget,
+       emitDirectReturnInstr, emitVectoredReturnInstr,
+       mkRetInfoTable,
+       mkStdInfoTable,
+       mkFunGenInfoExtraBits,
+       entryCode, closureInfoPtr,
+       getConstrTag,
+       infoTable, infoTableClosureType,
+       infoTablePtrs, infoTableNonPtrs,
+       funInfoTable,
+       vectorSlot,
+  ) where
+
+
+#include "HsVersions.h"
+
+import ClosureInfo     ( ClosureInfo, closureTypeDescr, closureName,
+                         infoTableLabelFromCI, Liveness,
+                         closureValDescr, closureSRT, closureSMRep,
+                         closurePtrsSize, closureNonHdrSize, closureFunInfo,
+                         C_SRT(..), needsSRT, isConstrClosure_maybe,
+                         ArgDescr(..) )
+import SMRep           ( StgHalfWord, hALF_WORD_SIZE_IN_BITS, hALF_WORD_SIZE,
+                         WordOff, ByteOff,
+                         smRepClosureTypeInt, tablesNextToCode,
+                         rET_BIG, rET_SMALL, rET_VEC_BIG, rET_VEC_SMALL )
+import CgBindery       ( getLiveStackSlots )
+import CgCallConv      ( isBigLiveness, mkLivenessCLit, buildContLiveness,
+                         argDescrType, getSequelAmode,
+                         CtrlReturnConvention(..) )
+import CgUtils         ( mkStringCLit, packHalfWordsCLit, mkWordCLit, 
+                         cmmOffsetB, cmmOffsetExprW, cmmLabelOffW, cmmOffsetW,
+                         emitDataLits, emitRODataLits, emitSwitch, cmmNegate )
+import CgMonad
+
+import CmmUtils                ( mkIntCLit, zeroCLit )
+import Cmm             ( CmmStmt(..), CmmExpr(..), CmmLit(..), LocalReg,
+                         CmmBasicBlock, nodeReg )
+import MachOp          ( MachOp(..), wordRep, halfWordRep )
+import CLabel
+import StgSyn          ( SRT(..) )
+import Name            ( Name )
+import DataCon         ( DataCon, dataConTag, fIRST_TAG )
+import Unique          ( Uniquable(..) )
+import CmdLineOpts     ( opt_SccProfilingOn )
+import ListSetOps      ( assocDefault )
+import Maybes          ( isJust )
+import Constants       ( wORD_SIZE, sIZEOF_StgFunInfoExtra )
+import Outputable
+
+
+-------------------------------------------------------------------------
+--
+--     Generating the info table and code for a closure
+--
+-------------------------------------------------------------------------
+
+-- Here we make a concrete info table, represented as a list of CmmAddr
+-- (it can't be simply a list of Word, because the SRT field is
+-- represented by a label+offset expression).
+
+-- With tablesNextToCode, the layout is
+--     <reversed variable part>
+--     <normal forward StgInfoTable, but without 
+--             an entry point at the front>
+--     <code>
+--
+-- Without tablesNextToCode, the layout of an info table is
+--     <entry label>
+--     <normal forward rest of StgInfoTable>
+--     <forward variable part>
+--
+--     See includes/InfoTables.h
+
+emitClosureCodeAndInfoTable :: ClosureInfo -> [LocalReg] -> CgStmts -> Code
+emitClosureCodeAndInfoTable cl_info args body
+ = do  { ty_descr_lit <- 
+               if opt_SccProfilingOn 
+                  then mkStringCLit (closureTypeDescr cl_info)
+                  else return (mkIntCLit 0)
+       ; cl_descr_lit <- 
+               if opt_SccProfilingOn 
+                  then mkStringCLit cl_descr_string
+                  else return (mkIntCLit 0)
+       ; let std_info = mkStdInfoTable ty_descr_lit cl_descr_lit 
+                                       cl_type srt_len layout_lit
+
+       ; blks <- cgStmtsToBlocks body
+       ; emitInfoTableAndCode info_lbl std_info extra_bits args blks }
+  where
+    info_lbl  = infoTableLabelFromCI cl_info
+
+    cl_descr_string = closureValDescr cl_info
+    cl_type = smRepClosureTypeInt (closureSMRep cl_info)
+
+    srt = closureSRT cl_info        
+    needs_srt = needsSRT srt
+
+    mb_con = isConstrClosure_maybe  cl_info
+    is_con = isJust mb_con
+
+    (srt_label,srt_len)
+       = case mb_con of
+           Just con -> -- Constructors don't have an SRT
+                       -- We keep the *zero-indexed* tag in the srt_len
+                       -- field of the info table. 
+                       (mkIntCLit 0, fromIntegral (dataConTagZ con)) 
+
+           Nothing  -> -- Not a constructor
+                       srtLabelAndLength srt
+
+    ptrs       = closurePtrsSize cl_info
+    nptrs      = size - ptrs
+    size       = closureNonHdrSize cl_info
+    layout_lit = packHalfWordsCLit ptrs nptrs
+
+    extra_bits
+       | is_fun    = fun_extra_bits
+       | is_con    = []
+       | needs_srt = [srt_label]
+       | otherwise = []
+
+    maybe_fun_stuff = closureFunInfo cl_info
+    is_fun = isJust maybe_fun_stuff
+    (Just (arity, arg_descr)) = maybe_fun_stuff
+
+    fun_extra_bits
+       | ArgGen liveness <- arg_descr
+       = [ fun_amode,
+           srt_label,
+           mkLivenessCLit liveness, 
+           CmmLabel (mkSlowEntryLabel (closureName cl_info)) ]
+       | needs_srt = [fun_amode, srt_label]
+       | otherwise = [fun_amode]
+
+    fun_amode = packHalfWordsCLit fun_type arity
+    fun_type  = argDescrType arg_descr
+
+-- We keep the *zero-indexed* tag in the srt_len field of the info
+-- table of a data constructor.
+dataConTagZ :: DataCon -> ConTagZ
+dataConTagZ con = dataConTag con - fIRST_TAG
+
+-- A low-level way to generate the variable part of a fun-style info table.
+-- (must match fun_extra_bits above).  Used by the C-- parser.
+mkFunGenInfoExtraBits :: Int -> Int -> CmmLit -> CmmLit -> CmmLit -> [CmmLit]
+mkFunGenInfoExtraBits fun_type arity srt_label liveness slow_entry
+  = [ packHalfWordsCLit fun_type arity,
+      srt_label,
+      liveness,
+      slow_entry ]
+
+-------------------------------------------------------------------------
+--
+--     Generating the info table and code for a return point
+--
+-------------------------------------------------------------------------
+
+--     Here's the layout of a return-point info table
+--
+-- Tables next to code:
+--
+--                     <reversed vector table>
+--                     <srt slot>
+--                     <standard info table>
+--     ret-addr -->    <entry code (if any)>
+--
+-- Not tables-next-to-code:
+--
+--     ret-addr -->    <ptr to entry code>
+--                     <standard info table>
+--                     <srt slot>
+--                     <forward vector table>
+--
+-- * The vector table is only present for vectored returns
+--
+-- * The SRT slot is only there if either
+--     (a) there is SRT info to record, OR
+--     (b) if the return is vectored
+--   The latter (b) is necessary so that the vector is in a
+--   predictable place
+
+vectorSlot :: CmmExpr -> CmmExpr -> CmmExpr
+-- Get the vector slot from the info pointer
+vectorSlot info_amode zero_indexed_tag
+  | tablesNextToCode 
+  = cmmOffsetExprW (cmmOffsetW info_amode (- (stdInfoTableSizeW + 2)))
+                  (cmmNegate zero_indexed_tag)
+       -- The "2" is one for the SRT slot, and one more 
+       -- to get to the first word of the vector
+
+  | otherwise 
+  = cmmOffsetExprW (cmmOffsetW info_amode (stdInfoTableSizeW + 2))
+                  zero_indexed_tag
+       -- The "2" is one for the entry-code slot and one for the SRT slot
+
+
+emitReturnTarget
+   :: Name
+   -> CgStmts                  -- The direct-return code (if any)
+                               --      (empty for vectored returns)
+   -> [CLabel]                 -- Vector of return points 
+                               --      (empty for non-vectored returns)
+   -> SRT
+   -> FCode CLabel
+emitReturnTarget name stmts vector srt
+  = do { live_slots <- getLiveStackSlots
+       ; liveness   <- buildContLiveness name live_slots
+       ; srt_info   <- getSRTInfo name srt
+
+       ; let
+             cl_type = case (null vector, isBigLiveness liveness) of
+                        (True,  True)  -> rET_BIG
+                        (True,  False) -> rET_SMALL
+                        (False, True)  -> rET_VEC_BIG
+                        (False, False) -> rET_VEC_SMALL
+             (std_info, extra_bits) = 
+                  mkRetInfoTable liveness srt_info cl_type vector
+
+       ; blks <- cgStmtsToBlocks stmts
+       ; emitInfoTableAndCode info_lbl std_info extra_bits args blks
+       ; return info_lbl }
+  where
+    args = trace "emitReturnTarget: missing args" []
+    uniq      = getUnique name
+    info_lbl  = mkReturnInfoLabel uniq
+
+
+mkRetInfoTable
+  :: Liveness          -- liveness
+  -> C_SRT             -- SRT Info
+  -> Int               -- type (eg. rET_SMALL)
+  -> [CLabel]          -- vector
+  -> ([CmmLit],[CmmLit])
+mkRetInfoTable liveness srt_info cl_type vector
+  =  (std_info, extra_bits)
+  where
+       (srt_label, srt_len) = srtLabelAndLength srt_info
+       srt_slot | need_srt  = [srt_label]
+                | otherwise = []
+
+       need_srt = needsSRT srt_info || not (null vector)
+               -- If there's a vector table then we must allocate
+               -- an SRT slot, so that the vector table is at a 
+               -- known offset from the info pointer
+       liveness_lit = mkLivenessCLit liveness
+       std_info = mkStdInfoTable zeroCLit zeroCLit cl_type srt_len liveness_lit
+        extra_bits = srt_slot ++ map CmmLabel vector
+
+
+emitDirectReturnTarget
+   :: Name
+   -> CgStmts          -- The direct-return code
+   -> SRT
+   -> FCode CLabel
+emitDirectReturnTarget name code srt
+  = emitReturnTarget name code [] srt
+
+emitAlgReturnTarget
+       :: Name                         -- Just for its unique
+       -> [(ConTagZ, CgStmts)]         -- Tagged branches
+       -> Maybe CgStmts                -- Default branch (if any)
+       -> SRT                          -- Continuation's SRT
+       -> CtrlReturnConvention
+       -> FCode (CLabel, SemiTaggingStuff)
+
+emitAlgReturnTarget name branches mb_deflt srt ret_conv
+  = case ret_conv of
+      UnvectoredReturn fam_sz -> do    
+       { blks <- getCgStmts $
+                   emitSwitch tag_expr branches mb_deflt 0 (fam_sz - 1)
+               -- NB: tag_expr is zero-based
+       ; lbl <- emitDirectReturnTarget name blks srt 
+       ; return (lbl, Nothing) }
+               -- Nothing: the internal branches in the switch don't have
+               -- global labels, so we can't use them at the 'call site'
+
+      VectoredReturn fam_sz -> do
+       { tagged_lbls <- mapFCs emit_alt branches
+       ; deflt_lbl   <- emit_deflt mb_deflt
+       ; let vector = [ assocDefault deflt_lbl tagged_lbls i 
+                      | i <- [0..fam_sz-1]]
+       ; lbl <- emitReturnTarget name noCgStmts vector srt 
+       ; return (lbl, Just (tagged_lbls, deflt_lbl)) }
+  where
+    uniq = getUnique name 
+    tag_expr = getConstrTag (CmmReg nodeReg)
+
+    emit_alt :: (Int, CgStmts) -> FCode (Int, CLabel)
+       -- Emit the code for the alternative as a top-level
+       -- code block returning a label for it
+    emit_alt (tag, stmts) = do  { let lbl = mkAltLabel uniq tag
+                                ; blks <- cgStmtsToBlocks stmts
+                                ; emitProc [] lbl [] blks
+                                ; return (tag, lbl) }
+
+    emit_deflt (Just stmts) = do { let lbl = mkDefaultLabel uniq
+                                ; blks <- cgStmtsToBlocks stmts
+                                ; emitProc [] lbl [] blks
+                                ; return lbl }
+    emit_deflt Nothing = return mkErrorStdEntryLabel
+               -- Nothing case: the simplifier might have eliminated a case
+               --               so we may have e.g. case xs of 
+               --                                       [] -> e
+               -- In that situation the default should never be taken, 
+               -- so we just use mkErrorStdEntryLabel
+
+--------------------------------
+emitDirectReturnInstr :: Code
+emitDirectReturnInstr 
+  = do         { info_amode <- getSequelAmode
+       ; stmtC (CmmJump (entryCode info_amode) []) }
+
+emitVectoredReturnInstr :: CmmExpr     -- *Zero-indexed* constructor tag
+                       -> Code
+emitVectoredReturnInstr zero_indexed_tag
+  = do { info_amode <- getSequelAmode
+       ; let slot = vectorSlot info_amode zero_indexed_tag
+       ; stmtC (CmmJump (CmmLoad slot wordRep) []) }
+
+
+
+-------------------------------------------------------------------------
+--
+--     Generating a standard info table
+--
+-------------------------------------------------------------------------
+
+-- The standard bits of an info table.  This part of the info table
+-- corresponds to the StgInfoTable type defined in InfoTables.h.
+--
+-- Its shape varies with ticky/profiling/tables next to code etc
+-- so we can't use constant offsets from Constants
+
+mkStdInfoTable
+   :: CmmLit           -- closure type descr (profiling)
+   -> CmmLit           -- closure descr (profiling)
+   -> Int              -- closure type
+   -> StgHalfWord      -- SRT length
+   -> CmmLit           -- layout field
+   -> [CmmLit]
+
+mkStdInfoTable type_descr closure_descr cl_type srt_len layout_lit
+ =     -- Parallel revertible-black hole field
+    prof_info
+       -- Ticky info (none at present)
+       -- Debug info (none at present)
+ ++ [layout_lit, type_lit]
+
+ where  
+    prof_info 
+       | opt_SccProfilingOn = [closure_descr, type_descr]
+       | otherwise          = []
+
+    type_lit = packHalfWordsCLit cl_type srt_len
+       
+stdInfoTableSizeW :: WordOff
+-- The size of a standard info table varies with profiling/ticky etc,
+-- so we can't get it from Constants
+-- It must vary in sync with mkStdInfoTable
+stdInfoTableSizeW
+  = size_fixed + size_prof
+  where
+    size_fixed = 2     -- layout, type
+    size_prof | opt_SccProfilingOn = 2
+             | otherwise          = 0
+
+stdInfoTableSizeB = stdInfoTableSizeW * wORD_SIZE :: ByteOff
+
+stdSrtBitmapOffset :: ByteOff
+-- Byte offset of the SRT bitmap half-word which is 
+-- in the *higher-addressed* part of the type_lit
+stdSrtBitmapOffset = stdInfoTableSizeB - hALF_WORD_SIZE
+
+stdClosureTypeOffset :: ByteOff
+-- Byte offset of the closure type half-word 
+stdClosureTypeOffset = stdInfoTableSizeB - wORD_SIZE
+
+stdPtrsOffset, stdNonPtrsOffset :: ByteOff
+stdPtrsOffset    = stdInfoTableSizeB - 2*wORD_SIZE
+stdNonPtrsOffset = stdInfoTableSizeB - 2*wORD_SIZE + hALF_WORD_SIZE
+
+-------------------------------------------------------------------------
+--
+--     Accessing fields of an info table
+--
+-------------------------------------------------------------------------
+
+closureInfoPtr :: CmmExpr -> CmmExpr
+-- Takes a closure pointer and returns the info table pointer
+closureInfoPtr e = CmmLoad e wordRep
+
+entryCode :: CmmExpr -> CmmExpr
+-- Takes an info pointer (the first word of a closure)
+-- and returns its entry code
+entryCode e | tablesNextToCode = e
+           | otherwise        = CmmLoad e wordRep
+
+getConstrTag :: CmmExpr -> CmmExpr
+-- Takes a closure pointer, and return the *zero-indexed*
+-- constructor tag obtained from the info table
+-- This lives in the SRT field of the info table
+-- (constructors don't need SRTs).
+getConstrTag closure_ptr 
+  = CmmMachOp (MO_U_Conv halfWordRep wordRep) [infoTableConstrTag info_table]
+  where
+    info_table = infoTable (closureInfoPtr closure_ptr)
+
+infoTable :: CmmExpr -> CmmExpr
+-- Takes an info pointer (the first word of a closure)
+-- and returns a pointer to the first word of the standard-form
+-- info table, excluding the entry-code word (if present)
+infoTable info_ptr
+  | tablesNextToCode = cmmOffsetB info_ptr (- stdInfoTableSizeB)
+  | otherwise       = cmmOffsetW info_ptr 1    -- Past the entry code pointer
+
+infoTableConstrTag :: CmmExpr -> CmmExpr
+-- Takes an info table pointer (from infoTable) and returns the constr tag
+-- field of the info table (same as the srt_bitmap field)
+infoTableConstrTag = infoTableSrtBitmap
+
+infoTableSrtBitmap :: CmmExpr -> CmmExpr
+-- Takes an info table pointer (from infoTable) and returns the srt_bitmap
+-- field of the info table
+infoTableSrtBitmap info_tbl
+  = CmmLoad (cmmOffsetB info_tbl stdSrtBitmapOffset) halfWordRep
+
+infoTableClosureType :: CmmExpr -> CmmExpr
+-- Takes an info table pointer (from infoTable) and returns the closure type
+-- field of the info table.
+infoTableClosureType info_tbl 
+  = CmmLoad (cmmOffsetB info_tbl stdClosureTypeOffset) halfWordRep
+
+infoTablePtrs :: CmmExpr -> CmmExpr
+infoTablePtrs info_tbl 
+  = CmmLoad (cmmOffsetB info_tbl stdPtrsOffset) halfWordRep
+
+infoTableNonPtrs :: CmmExpr -> CmmExpr
+infoTableNonPtrs info_tbl 
+  = CmmLoad (cmmOffsetB info_tbl stdNonPtrsOffset) halfWordRep
+
+funInfoTable :: CmmExpr -> CmmExpr
+-- Takes the info pointer of a function,
+-- and returns a pointer to the first word of the StgFunInfoExtra struct
+-- in the info table.
+funInfoTable info_ptr
+  | tablesNextToCode
+  = cmmOffsetB info_ptr (- stdInfoTableSizeB - sIZEOF_StgFunInfoExtra)
+  | otherwise
+  = cmmOffsetW info_ptr (1 + stdInfoTableSizeW)
+                               -- Past the entry code pointer
+
+-------------------------------------------------------------------------
+--
+--     Emit the code for a closure (or return address)
+--     and its associated info table
+--
+-------------------------------------------------------------------------
+
+-- The complication here concerns whether or not we can
+-- put the info table next to the code
+
+emitInfoTableAndCode 
+       :: CLabel               -- Label of info table
+       -> [CmmLit]             -- ...its invariant part
+       -> [CmmLit]             -- ...and its variant part
+       -> [LocalReg]           -- ...args
+       -> [CmmBasicBlock]      -- ...and body
+       -> Code
+
+emitInfoTableAndCode info_lbl std_info extra_bits args blocks
+  | tablesNextToCode   -- Reverse the extra_bits; and emit the top-level proc
+  = emitProc (reverse extra_bits ++ std_info) 
+            entry_lbl args blocks
+       -- NB: the info_lbl is discarded
+
+  | null blocks -- No actual code; only the info table is significant
+  =            -- Use a zero place-holder in place of the 
+               -- entry-label in the info table
+    emitRODataLits info_lbl (zeroCLit : std_info ++ extra_bits)
+
+  | otherwise  -- Separately emit info table (with the function entry 
+  =            -- point as first entry) and the entry code 
+    do { emitDataLits info_lbl (CmmLabel entry_lbl : std_info ++ extra_bits)
+       ; emitProc [] entry_lbl args blocks }
+
+  where
+       entry_lbl = infoLblToEntryLbl info_lbl
+
+-------------------------------------------------------------------------
+--
+--     Static reference tables
+--
+-------------------------------------------------------------------------
+
+-- There is just one SRT for each top level binding; all the nested
+-- bindings use sub-sections of this SRT.  The label is passed down to
+-- the nested bindings via the monad.
+
+getSRTInfo :: Name -> SRT -> FCode C_SRT
+getSRTInfo id NoSRT = return NoC_SRT
+getSRTInfo id (SRT off len bmp)
+  | len > hALF_WORD_SIZE_IN_BITS || bmp == [fromIntegral srt_escape]
+  = do { srt_lbl <- getSRTLabel
+       ; let srt_desc_lbl = mkSRTDescLabel id
+       ; emitRODataLits srt_desc_lbl
+                  ( cmmLabelOffW srt_lbl off
+                  : mkWordCLit (fromIntegral len)
+                  : map mkWordCLit bmp)
+       ; return (C_SRT srt_desc_lbl 0 srt_escape) }
+
+  | otherwise 
+  = do { srt_lbl <- getSRTLabel
+       ; return (C_SRT srt_lbl off (fromIntegral (head bmp))) }
+               -- The fromIntegral converts to StgHalfWord
+
+srt_escape = (-1) :: StgHalfWord
+
+srtLabelAndLength :: C_SRT -> (CmmLit, StgHalfWord)
+srtLabelAndLength NoC_SRT               = (zeroCLit,            0)
+srtLabelAndLength (C_SRT lbl off bitmap) = (cmmLabelOffW lbl off, bitmap)
+
index 80b80ee..3ea0597 100644 (file)
@@ -1,7 +1,7 @@
 %
 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1998
 %
-% $Id: CgLetNoEscape.lhs,v 1.24 2003/07/21 11:01:07 simonmar Exp $
+% $Id: CgLetNoEscape.lhs,v 1.25 2004/08/13 13:06:03 simonmar Exp $
 %
 %********************************************************
 %*                                                     *
@@ -18,21 +18,23 @@ import {-# SOURCE #-} CgExpr ( cgExpr )
 
 import StgSyn
 import CgMonad
-import AbsCSyn
 
 import CgBindery       ( CgIdInfo, letNoEscapeIdInfo, nukeDeadBindings )
-import CgCase          ( mkRetDirectTarget, restoreCurrentCostCentre )
+import CgCase          ( restoreCurrentCostCentre )
 import CgCon           ( bindUnboxedTupleComponents )
 import CgHeapery       ( unbxTupleHeapCheck )
-import CgStackery      ( allocStackTop, deAllocStackTop )
-import CgUsages                ( getSpRelOffset )
+import CgInfoTbls      ( emitDirectReturnTarget )
+import CgStackery      ( allocStackTop, deAllocStackTop, getSpRelOffset )
+import Cmm             ( CmmStmt(..) )
+import CmmUtils                ( mkLblExpr, oneStmt )
 import CLabel          ( mkReturnInfoLabel )
 import ClosureInfo     ( mkLFLetNoEscape )
 import CostCentre       ( CostCentreStack )
-import Id              ( Id )
+import Id              ( Id, idName )
 import Var             ( idUnique )
-import PrimRep         ( PrimRep(..), retPrimRepSize )
+import SMRep           ( retAddrSizeW )
 import BasicTypes      ( RecFlag(..) )
+import Outputable
 \end{code}
 
 %************************************************************************
@@ -156,25 +158,23 @@ cgLetNoEscapeClosure
        arity   = length args
        lf_info = mkLFLetNoEscape arity
     in
-
     -- saveVolatileVarsAndRegs done earlier in cgExpr.
 
-    forkEvalHelp
-       rhs_eob_info
+    do  { (vSp, _) <- forkEvalHelp rhs_eob_info
+
+               (do { allocStackTop retAddrSizeW
+                   ; nukeDeadBindings full_live_in_rhss })
 
-       (allocStackTop retPrimRepSize   `thenFC` \_ ->
-        nukeDeadBindings full_live_in_rhss)
+               (do { deAllocStackTop retAddrSizeW
+                   ; abs_c <- forkProc $ cgLetNoEscapeBody bndr cc 
+                                                 cc_slot args body
 
-       (deAllocStackTop retPrimRepSize         `thenFC` \_ ->
-        forkAbsC (
-           cgLetNoEscapeBody bndr cc cc_slot args body
-        )                                      `thenFC` \ abs_c ->
-        mkRetDirectTarget bndr abs_c srt
-               -- Ignore the label that comes back from
-               -- mkRetDirectTarget.  It must be conjured up elswhere
-       )                               `thenFC` \ (vSp, _) ->
+                       -- Ignore the label that comes back from
+                       -- mkRetDirectTarget.  It must be conjured up elswhere
+                   ; emitDirectReturnTarget (idName bndr) abs_c srt
+                   ; return () })
 
-    returnFC (bndr, letNoEscapeIdInfo bndr vSp lf_info)
+       ; returnFC (bndr, letNoEscapeIdInfo bndr vSp lf_info) }
 \end{code}
 
 \begin{code}
@@ -185,28 +185,28 @@ cgLetNoEscapeBody :: Id           -- Name of the joint point
                  -> StgExpr    -- Body
                  -> Code
 
-cgLetNoEscapeBody bndr cc cc_slot all_args body
-   = bindUnboxedTupleComponents all_args       `thenFC` \ (arg_regs, ptrs, nptrs, ret_slot) ->
+cgLetNoEscapeBody bndr cc cc_slot all_args body = do
+  { (arg_regs, ptrs, nptrs, ret_slot) <- bindUnboxedTupleComponents all_args
 
      -- restore the saved cost centre.  BUT: we must not free the stack slot
      -- containing the cost centre, because it might be needed for a
      -- recursive call to this let-no-escape.
-     restoreCurrentCostCentre cc_slot False{-don't free-}      `thenC`
+  ; restoreCurrentCostCentre cc_slot False{-don't free-}
 
        -- Enter the closures cc, if required
-     --enterCostCentreCode closure_info cc IsFunction  `thenC`
+  ; -- enterCostCentreCode closure_info cc IsFunction
 
        -- The "return address" slot doesn't have a return address in it;
        -- but the heap-check needs it filled in if the heap-check fails.
        -- So we pass code to fill it in to the heap-check macro
-     getSpRelOffset ret_slot                   `thenFC` \ sp_rel ->
-     let lbl           = mkReturnInfoLabel (idUnique bndr)
-        frame_hdr_asst = CAssign (CVal sp_rel RetRep) (CLbl lbl RetRep)
-     in
+  ; sp_rel <- getSpRelOffset ret_slot
+
+  ; let        lbl            = mkReturnInfoLabel (idUnique bndr)
+       frame_hdr_asst = oneStmt (CmmStore sp_rel (mkLblExpr lbl))
 
        -- Do heap check [ToDo: omit for non-recursive case by recording in
        --      in envt and absorbing at call site]
-     unbxTupleHeapCheck arg_regs ptrs nptrs frame_hdr_asst (
-       cgExpr body
-     )
+  ; unbxTupleHeapCheck arg_regs ptrs nptrs frame_hdr_asst 
+                       (cgExpr body)
+  }
 \end{code}
index 88083f7..003be97 100644 (file)
@@ -1,7 +1,7 @@
 %
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
-% $Id: CgMonad.lhs,v 1.39 2003/07/02 13:12:38 simonpj Exp $
+% $Id: CgMonad.lhs,v 1.40 2004/08/13 13:06:03 simonmar Exp $
 %
 \section[CgMonad]{The code generation monad}
 
@@ -14,56 +14,64 @@ module CgMonad (
        FCode,  -- type
 
        initC, thenC, thenFC, listCs, listFCs, mapCs, mapFCs,
-       returnFC, fixC, absC, nopC, getAbsC,
+       returnFC, fixC, checkedAbsC, 
+       stmtC, stmtsC, labelC, emitStmts, nopC, whenC, newLabelC,
+       newUnique, newUniqSupply, 
 
+       CgStmts, emitCgStmts, forkCgStmts, cgStmtsToBlocks,
+       getCgStmts', getCgStmts,
+       noCgStmts, oneCgStmt, consCgStmt,
+
+       getCmm,
+       emitData, emitProc, emitSimpleProc,
+
+       forkLabelledCode,
        forkClosureBody, forkStatics, forkAlts, forkEval,
-       forkEvalHelp, forkAbsC,
-       SemiTaggingStuff,
+       forkEvalHelp, forkProc, codeOnly,
+       SemiTaggingStuff, ConTagZ,
 
        EndOfBlockInfo(..),
        setEndOfBlockInfo, getEndOfBlockInfo,
 
-       setSRTLabel, getSRTLabel, getSRTInfo,
+       setSRTLabel, getSRTLabel, 
        setTickyCtrLabel, getTickyCtrLabel,
 
-       StackUsage, Slot(..), HeapUsage,
-
-       profCtrC, profCtrAbsC, ldvEnter,
+       StackUsage(..), HeapUsage(..),
+       VirtualSpOffset, VirtualHpOffset,
+       initStkUsage, initHpUsage,
+       getHpUsage,  setHpUsage,
+       heapHWM,
 
-       costCentresC, moduleName,
+       moduleName,
 
        Sequel(..), -- ToDo: unabstract?
-       sequelToAmode,
 
        -- ideally we wouldn't export these, but some other modules access internal state
        getState, setState, getInfoDown,
 
        -- more localised access to monad state 
-       getUsage, setUsage,
+       getStkUsage, setStkUsage,
        getBinds, setBinds, getStaticBinds,
 
        -- out of general friendliness, we also export ...
-       CgInfoDownwards(..), CgState(..),       -- non-abstract
-       CompilationInfo(..)
+       CgInfoDownwards(..), CgState(..)        -- non-abstract
     ) where
 
 #include "HsVersions.h"
 
 import {-# SOURCE #-} CgBindery ( CgBindings, nukeVolatileBinds )
-import {-# SOURCE #-} CgUsages  ( getSpRelOffset )
 
-import AbsCSyn
+import Cmm
+import CmmUtils                ( CmmStmts, isNopStmt )
 import CLabel
-import StgSyn          ( SRT(..) )
-import AbsCUtils       ( mkAbsCStmts )
-import CmdLineOpts     ( opt_SccProfilingOn, opt_DoTickyProfiling )
+import SMRep           ( WordOff )
 import Module          ( Module )
-import DataCon         ( ConTag )
 import Id              ( Id )
-import Name            ( Name )
 import VarEnv
-import PrimRep         ( PrimRep(..) )
-import SMRep           ( StgHalfWord, hALF_WORD )
+import OrdList
+import Unique          ( Unique )
+import Util            ( mapAccumL )
+import UniqSupply      ( UniqSupply, mkSplitUniqSupply, splitUniqSupply, uniqFromSupply )
 import FastString
 import Outputable
 
@@ -83,29 +91,46 @@ along.
 
 \begin{code}
 data CgInfoDownwards   -- information only passed *downwards* by the monad
-  = MkCgInfoDown
-     CompilationInfo   -- COMPLETELY STATIC info about this compilation
-                       --  (e.g., what flags were passed to the compiler)
-
-     CgBindings                -- [Id -> info] : static environment
-
-     CLabel            -- label of the current SRT
-
-     CLabel            -- current destination for ticky counts
-
-     EndOfBlockInfo    -- Info for stuff to do at end of basic block:
-
-
-data CompilationInfo
-  = MkCompInfo
-       Module          -- the module name
+  = MkCgInfoDown {
+       cgd_mod     :: Module,          -- Module being compiled
+       cgd_statics :: CgBindings,      -- [Id -> info] : static environment
+       cgd_srt     :: CLabel,          -- label of the current SRT
+       cgd_ticky   :: CLabel,          -- current destination for ticky counts
+       cgd_eob     :: EndOfBlockInfo   -- Info for stuff to do at end of basic block:
+  }
+
+initCgInfoDown :: Module -> CgInfoDownwards
+initCgInfoDown mod
+  = MkCgInfoDown {     cgd_mod    = mod,
+                       cgd_statics = emptyVarEnv,
+                       cgd_srt     = error "initC: srt",
+                       cgd_ticky   = mkTopTickyCtrLabel,
+                       cgd_eob     = initEobInfo }
 
 data CgState
-  = MkCgState
-       AbstractC       -- code accumulated so far
-       CgBindings      -- [Id -> info] : *local* bindings environment
-                       -- Bindings for top-level things are given in the info-down part
-       CgStksAndHeapUsage
+  = MkCgState {
+     cgs_stmts :: OrdList CgStmt,        -- Current proc
+     cgs_tops  :: OrdList CmmTop,
+       -- Other procedures and data blocks in this compilation unit
+       -- Both the latter two are ordered only so that we can 
+       -- reduce forward references, when it's easy to do so
+     
+     cgs_binds :: CgBindings,  -- [Id -> info] : *local* bindings environment
+                               -- Bindings for top-level things are given in
+                               -- the info-down part
+     
+     cgs_stk_usg :: StackUsage,
+     cgs_hp_usg  :: HeapUsage,
+     
+     cgs_uniqs :: UniqSupply }
+
+initCgState :: UniqSupply -> CgState
+initCgState uniqs
+  = MkCgState { cgs_stmts = nilOL, cgs_tops = nilOL,
+               cgs_binds = emptyVarEnv, 
+               cgs_stk_usg = initStkUsage, 
+               cgs_hp_usg = initHpUsage,
+               cgs_uniqs = uniqs }
 \end{code}
 
 @EndOfBlockInfo@ tells what to do at the end of this block of code or,
@@ -123,7 +148,7 @@ data EndOfBlockInfo
                          -- by a case alternative.
        Sequel
 
-initEobInfo = EndOfBlockInfo 0 (OnStack 0)
+initEobInfo = EndOfBlockInfo 0 OnStack
 \end{code}
 
 Any addressing modes inside @Sequel@ must be ``robust,'' in the sense
@@ -132,105 +157,164 @@ block.
 
 \begin{code}
 data Sequel
-  = OnStack 
-       VirtualSpOffset   -- Continuation is on the stack, at the
-                         -- specified location
-
-  | UpdateCode
+  = OnStack            -- Continuation is on the stack
+  | UpdateCode         -- Continuation is update
 
   | CaseAlts
-         CAddrMode   -- Jump to this; if the continuation is for a vectored
-                     -- case this might be the label of a return
-                     -- vector Guaranteed to be a non-volatile
-                     -- addressing mode (I think)
+         CLabel     -- Jump to this; if the continuation is for a vectored
+                    -- case this might be the label of a return vector
          SemiTaggingStuff
-
+         Id          -- The case binder, only used to see if it's dead
          Bool        -- True <=> polymorphic, push a SEQ frame too
 
-
 type SemiTaggingStuff
-  = Maybe                          -- Maybe[1] we don't have any semi-tagging stuff...
-     ([(ConTag, JoinDetails)],     -- Alternatives
-      Maybe (Id, JoinDetails)      -- Default (but Maybe[2] we don't have one)
-                                   -- The default branch expects a 
-                                   -- it expects a ptr to the thing
-                                   -- in Node, bound to b
-     )
-
-type JoinDetails
-  = (AbstractC, CLabel)                -- Code to load regs from heap object + profiling macros,
-                               -- and join point label
-
--- The abstract C is executed only from a successful semitagging
+  = Maybe                      -- Maybe[1] we don't have any semi-tagging stuff...
+     ([(ConTagZ, CLabel)],     -- Alternatives
+      CLabel)                  -- Default (will be a can't happen RTS label if can't happen)
+
+type ConTagZ = Int     -- A *zero-indexed* contructor tag
+
+-- The case branch is executed only from a successful semitagging
 -- venture, when a case has looked at a variable, found that it's
 -- evaluated, and wants to load up the contents and go to the join
 -- point.
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+               CgStmt type
+%*                                                                     *
+%************************************************************************
+
+The CgStmts type is what the code generator outputs: it is a tree of
+statements, including in-line labels.  The job of flattenCgStmts is to
+turn this into a list of basic blocks, each of which ends in a jump
+statement (either a local branch or a non-local jump).
+
+\begin{code}
+type CgStmts = OrdList CgStmt
+
+data CgStmt
+  = CgStmt  CmmStmt
+  | CgLabel BlockId
+  | CgFork  BlockId CgStmts
+
+flattenCgStmts :: BlockId -> CgStmts -> [CmmBasicBlock]
+flattenCgStmts id stmts = 
+       case flatten (fromOL stmts) of
+         ([],blocks)    -> blocks
+         (block,blocks) -> BasicBlock id block : blocks
+ where
+  flatten [] = ([],[])
+
+  -- A label at the end of a function or fork: this label must not be reachable,
+  -- but it might be referred to from another BB that also isn't reachable.
+  -- Eliminating these has to be done with a dead-code analysis.  For now,
+  -- we just make it into a well-formed block by adding a recursive jump.
+  flatten [CgLabel id]
+    = ( [], [BasicBlock id [CmmBranch id]] )
+
+  -- A jump/branch: throw away all the code up to the next label, because
+  -- it is unreachable.  Be careful to keep forks that we find on the way.
+  flatten (CgStmt stmt : stmts)
+    | isJump stmt
+    = case dropWhile isOrdinaryStmt stmts of
+       []                     -> ( [stmt], [] )
+       [CgLabel id]           -> ( [stmt], [BasicBlock id [CmmBranch id]])
+       (CgLabel id : stmts)   -> ( [stmt], BasicBlock id block : blocks )
+           where (block,blocks) = flatten stmts
+       (CgFork fork_id stmts : ss) -> 
+          flatten (CgFork fork_id stmts : CgStmt stmt : ss)
+
+  flatten (s:ss) = 
+       case s of
+         CgStmt stmt -> (stmt:block,blocks)
+         CgLabel id  -> ([CmmBranch id],BasicBlock id block:blocks)
+         CgFork fork_id stmts -> 
+               (block, BasicBlock fork_id fork_block : fork_blocks ++ blocks)
+               where (fork_block, fork_blocks) = flatten (fromOL stmts)
+    where (block,blocks) = flatten ss
+
+isJump (CmmJump _ _) = True
+isJump (CmmBranch _) = True
+isJump _ = False
+
+isOrdinaryStmt (CgStmt _) = True
+isOrdinaryStmt _ = False
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+               Stack and heap models
+%*                                                                     *
+%************************************************************************
 
--- DIRE WARNING.
--- The OnStack case of sequelToAmode delivers an Amode which is only
--- valid just before the final control transfer, because it assumes
--- that Sp is pointing to the top word of the return address.  This
--- seems unclean but there you go.
-
--- sequelToAmode returns an amode which refers to an info table.  The info
--- table will always be of the RET(_VEC)?_(BIG|SMALL) kind.  We're careful
--- not to handle real code pointers, just in case we're compiling for 
--- an unregisterised/untailcallish architecture, where info pointers and
--- code pointers aren't the same.
-
-sequelToAmode :: Sequel -> FCode CAddrMode
-
-sequelToAmode (OnStack virt_sp_offset)
-  = getSpRelOffset virt_sp_offset `thenFC` \ sp_rel ->
-    returnFC (CVal sp_rel RetRep)
-
-sequelToAmode UpdateCode = returnFC (CLbl mkUpdInfoLabel RetRep)
-
-sequelToAmode (CaseAlts amode _ False) = returnFC amode
-sequelToAmode (CaseAlts amode _ True)  = returnFC (CLbl mkSeqInfoLabel RetRep)
-
-type CgStksAndHeapUsage                -- stacks and heap usage information
-  = (StackUsage, HeapUsage)
-
-data Slot = Free | NonPointer 
-  deriving
-#ifdef DEBUG
-       (Eq,Show)
-#else
-       Eq
-#endif
-
-type StackUsage =
-       (Int,              -- virtSp:  Virtual offset of topmost allocated slot
-        Int,              -- frameSp: End of the current stack frame
-        [(Int,Slot)],     -- free:    List of free slots, in increasing order
-        Int,              -- realSp:  Virtual offset of real stack pointer
-        Int)              -- hwSp:    Highest value ever taken by virtSp
-
--- ToDo (SDM, 7 Jan 2003): I'm not sure that the distinction between
--- Free and NonPointer in the free list is needed any more.  It used
--- to be needed because we constructed bitmaps from the free list, but
--- now we construct bitmaps by finding all the live pointer bindings
--- instead.  Non-pointer stack slots (i.e. saved cost centres) can
--- just be removed from the free list instead of being recorded as a
--- NonPointer.
-
-type HeapUsage =
-       (HeapOffset,    -- virtHp: Virtual offset of highest-allocated word
-        HeapOffset)    -- realHp: Virtual offset of real heap ptr
+\begin{code}
+type VirtualHpOffset = WordOff -- Both are in
+type VirtualSpOffset = WordOff -- units of words
+
+data StackUsage 
+  = StackUsage {
+       virtSp :: VirtualSpOffset,
+               -- Virtual offset of topmost allocated slot
+
+       frameSp :: VirtualSpOffset,
+               -- Virtual offset of the return address of the enclosing frame.
+               -- This RA describes the liveness/pointedness of
+               -- all the stack from frameSp downwards
+               -- INVARIANT: less than or equal to virtSp
+
+        freeStk :: [VirtualSpOffset], 
+               -- List of free slots, in *increasing* order
+               -- INVARIANT: all <= virtSp
+               -- All slots <= virtSp are taken except these ones
+
+        realSp :: VirtualSpOffset,     
+               -- Virtual offset of real stack pointer register
+
+        hwSp :: VirtualSpOffset
+  }               -- Highest value ever taken by virtSp
+
+-- INVARAINT: The environment contains no Stable references to
+--           stack slots below (lower offset) frameSp
+--           It can contain volatile references to this area though.
+
+data HeapUsage =
+  HeapUsage {
+       virtHp :: VirtualHpOffset,      -- Virtual offset of highest-allocated word
+       realHp :: VirtualHpOffset       -- realHp: Virtual offset of real heap ptr
+  }
 \end{code}
 
-NB: absolutely every one of the above Ints is really
-a VirtualOffset of some description (the code generator
-works entirely in terms of VirtualOffsets).
+The heap high water mark is the larger of virtHp and hwHp.  The latter is
+only records the high water marks of forked-off branches, so to find the
+heap high water mark you have to take the max of virtHp and hwHp.  Remember,
+virtHp never retreats!
 
-Initialisation.
+Note Jan 04: ok, so why do we only look at the virtual Hp??
 
 \begin{code}
-initialStateC = MkCgState AbsCNop emptyVarEnv initUsage
+heapHWM :: HeapUsage -> VirtualHpOffset
+heapHWM = virtHp
+\end{code}
 
-initUsage :: CgStksAndHeapUsage
-initUsage  = ((0,0,[],0,0), (0,0))
+Initialisation.
+
+\begin{code}
+initStkUsage :: StackUsage
+initStkUsage = StackUsage {
+                       virtSp = 0,
+                       frameSp = 0,
+                       freeStk = [],
+                       realSp = 0,
+                       hwSp = 0
+              }
+               
+initHpUsage :: HeapUsage 
+initHpUsage = HeapUsage {
+               virtHp = 0,
+               realHp = 0
+             }
 \end{code}
 
 @stateIncUsage@$~e_1~e_2$ incorporates in $e_1$ the stack and heap high water
@@ -238,24 +322,42 @@ marks found in $e_2$.
 
 \begin{code}
 stateIncUsage :: CgState -> CgState -> CgState
+stateIncUsage s1 s2@(MkCgState { cgs_stk_usg = stk_usg, cgs_hp_usg = hp_usg })
+     = s1 { cgs_hp_usg  = cgs_hp_usg  s1 `maxHpHw`  virtHp hp_usg,
+           cgs_stk_usg = cgs_stk_usg s1 `maxStkHw` hwSp   stk_usg }
+       `addCodeBlocksFrom` s2
+               
+stateIncUsageEval :: CgState -> CgState -> CgState
+stateIncUsageEval s1 s2
+     = s1 { cgs_stk_usg = cgs_stk_usg s1 `maxStkHw` hwSp (cgs_stk_usg s2) }
+       `addCodeBlocksFrom` s2
+       -- We don't max the heap high-watermark because stateIncUsageEval is
+       -- used only in forkEval, which in turn is only used for blocks of code
+       -- which do their own heap-check.
 
-stateIncUsage (MkCgState abs_c bs ((v,t,f,r,h1),(vH1,rH1)))
-             (MkCgState _     _  ((_,_,_,_,h2),(vH2, _)))
-     = MkCgState abs_c
-                bs
-                ((v,t,f,r,h1 `max` h2),
-                 (vH1 `max` vH2, rH1))
+addCodeBlocksFrom :: CgState -> CgState -> CgState
+-- Add code blocks from the latter to the former
+-- (The cgs_stmts will often be empty, but not always; see codeOnly)
+s1 `addCodeBlocksFrom` s2
+  = s1 { cgs_stmts = cgs_stmts s1 `appOL` cgs_stmts s2,
+        cgs_tops  = cgs_tops  s1 `appOL` cgs_tops  s2 }
+
+maxHpHw :: HeapUsage -> VirtualHpOffset -> HeapUsage
+hp_usg `maxHpHw` hw = hp_usg { virtHp = virtHp hp_usg `max` hw }
+
+maxStkHw :: StackUsage -> VirtualSpOffset -> StackUsage
+stk_usg `maxStkHw` hw = stk_usg { hwSp = hwSp stk_usg `max` hw }
 \end{code}
 
 %************************************************************************
 %*                                                                     *
-\subsection[CgMonad-basics]{Basic code-generation monad magic}
+               The FCode monad
 %*                                                                     *
 %************************************************************************
 
 \begin{code}
 newtype FCode a = FCode (CgInfoDownwards -> CgState -> (a, CgState))
-type Code    = FCode ()
+type Code       = FCode ()
 
 instance Monad FCode where
        (>>=) = thenFC
@@ -268,17 +370,13 @@ instance Monad FCode where
 The Abstract~C is not in the environment so as to improve strictness.
 
 \begin{code}
-initC :: CompilationInfo -> Code -> AbstractC
-
-initC cg_info (FCode code)
-  = case (code (MkCgInfoDown 
-                       cg_info 
-                       emptyVarEnv -- (error "initC: statics")
-                       (error "initC: srt")
-                       (mkTopTickyCtrLabel)
-                       initEobInfo)
-              initialStateC) of
-      ((),MkCgState abc _ _) -> abc
+initC :: Module -> FCode a -> IO a
+
+initC mod (FCode code)
+  = do { uniqs <- mkSplitUniqSupply 'c'
+       ; case code (initCgInfoDown mod) (initCgState uniqs) of
+             (res, _) -> return res
+       }
 
 returnFC :: a -> FCode a
 returnFC val = FCode (\info_down state -> (val, state))
@@ -332,9 +430,12 @@ fixC fcode = FCode (
        )
 \end{code}
 
-Operators for getting and setting the state and "info_down".
-To maximise encapsulation, code should try to only get and set the
-state it actually uses.
+%************************************************************************
+%*                                                                     *
+       Operators for getting and setting the state and "info_down".
+
+%*                                                                     *
+%************************************************************************
 
 \begin{code}
 getState :: FCode CgState
@@ -343,35 +444,58 @@ getState = FCode $ \info_down state -> (state,state)
 setState :: CgState -> FCode ()
 setState state = FCode $ \info_down _ -> ((),state)
 
-getUsage :: FCode CgStksAndHeapUsage
-getUsage = do
-       MkCgState absC binds usage <- getState
-       return usage
+getStkUsage :: FCode StackUsage
+getStkUsage = do
+       state <- getState
+       return $ cgs_stk_usg state
 
-setUsage :: CgStksAndHeapUsage -> FCode ()
-setUsage newusage = do
-       MkCgState absC binds usage <- getState
-       setState $ MkCgState absC binds newusage
+setStkUsage :: StackUsage -> Code
+setStkUsage new_stk_usg = do
+       state <- getState
+       setState $ state {cgs_stk_usg = new_stk_usg}
+
+getHpUsage :: FCode HeapUsage
+getHpUsage = do
+       state <- getState
+       return $ cgs_hp_usg state
+       
+setHpUsage :: HeapUsage -> Code
+setHpUsage new_hp_usg = do
+       state <- getState
+       setState $ state {cgs_hp_usg = new_hp_usg}
 
 getBinds :: FCode CgBindings
 getBinds = do
-       MkCgState absC binds usage <- getState
-       return binds
+       state <- getState
+       return $ cgs_binds state
        
 setBinds :: CgBindings -> FCode ()
-setBinds newbinds = do
-       MkCgState absC binds usage <- getState
-       setState $ MkCgState absC newbinds usage
+setBinds new_binds = do
+       state <- getState
+       setState $ state {cgs_binds = new_binds}
 
 getStaticBinds :: FCode CgBindings
 getStaticBinds = do
-       (MkCgInfoDown _ static_binds _ _ _) <- getInfoDown
-       return static_binds
+       info  <- getInfoDown
+       return (cgd_statics info)
 
 withState :: FCode a -> CgState -> FCode (a,CgState)
 withState (FCode fcode) newstate = FCode $ \info_down state -> 
        let (retval, state2) = fcode info_down newstate in ((retval,state2), state)
 
+newUniqSupply :: FCode UniqSupply
+newUniqSupply = do
+       state <- getState
+       let (us1, us2) = splitUniqSupply (cgs_uniqs state)
+       setState $ state { cgs_uniqs = us1 }
+       return us2
+
+newUnique :: FCode Unique
+newUnique = do
+       us <- newUniqSupply
+       return (uniqFromSupply us)
+
+------------------
 getInfoDown :: FCode CgInfoDownwards
 getInfoDown = FCode $ \info_down state -> (info_down,state)
 
@@ -383,16 +507,22 @@ doFCode (FCode fcode) info_down state = fcode info_down state
 \end{code}
 
 
+%************************************************************************
+%*                                                                     *
+               Forking
+%*                                                                     *
+%************************************************************************
+
 @forkClosureBody@ takes a code, $c$, and compiles it in a completely
 fresh environment, except that:
        - compilation info and statics are passed in unchanged.
 The current environment is passed on completely unaltered, except that
 abstract C from the fork is incorporated.
 
-@forkAbsC@ takes a code and compiles it in the current environment,
-returning the abstract C thus constructed.  The current environment
-is passed on completely unchanged.  It is pretty similar to @getAbsC@,
-except that the latter does affect the environment. ToDo: combine?
+@forkProc@ takes a code and compiles it in the current environment,
+returning the basic blocks thus constructed.  The current environment
+is passed on completely unchanged.  It is pretty similar to
+@getBlocks@, except that the latter does affect the environment.
 
 @forkStatics@ $fc$ compiles $fc$ in an environment whose statics come
 from the current bindings, but which is otherwise freshly initialised.
@@ -401,40 +531,57 @@ bindings and usage information is otherwise unchanged.
 
 \begin{code}
 forkClosureBody :: Code -> Code
-
-forkClosureBody (FCode code) = do
-       (MkCgInfoDown cg_info statics srt ticky _) <- getInfoDown
-       (MkCgState absC_in binds un_usage) <- getState
-       let     body_info_down = MkCgInfoDown cg_info statics srt ticky initEobInfo
-       let     ((),fork_state)             = code body_info_down initialStateC
-       let     MkCgState absC_fork _ _ = fork_state
-       setState $ MkCgState (AbsCStmts absC_in absC_fork) binds un_usage
+forkClosureBody body_code
+  = do { info <- getInfoDown
+       ; us   <- newUniqSupply
+       ; state <- getState
+       ; let   body_info_down = info { cgd_eob = initEobInfo }
+               ((),fork_state) = doFCode body_code body_info_down 
+                                         (initCgState us)
+       ; ASSERT( isNilOL (cgs_stmts fork_state) )
+         setState $ state `addCodeBlocksFrom` fork_state }
        
 forkStatics :: FCode a -> FCode a
-
-forkStatics (FCode fcode) = FCode (
-       \(MkCgInfoDown cg_info _ srt ticky _)
-       (MkCgState absC_in statics un_usage)
-  -> 
-       let
-               (result, state) = fcode rhs_info_down initialStateC
-               MkCgState absC_fork _ _ = state -- Don't merge these this line with the one
-                               -- above or it becomes too strict!
-               rhs_info_down = MkCgInfoDown cg_info statics srt ticky initEobInfo
-       in
-               (result, MkCgState (AbsCStmts absC_in absC_fork) statics un_usage)
-       )
-
-forkAbsC :: Code -> FCode AbstractC
-forkAbsC (FCode code) =
-       do
-               info_down <- getInfoDown
-               (MkCgState absC1 bs usage) <- getState
-               let ((),MkCgState absC2 _ ((_, _, _, _,h2), _)) = code info_down (MkCgState AbsCNop bs usage)
-               let ((v, t, f, r, h1), heap_usage) = usage
-               let new_usage = ((v, t, f, r, h1 `max` h2), heap_usage)
-               setState $ MkCgState absC1 bs new_usage
-               return absC2
+forkStatics body_code
+  = do { info  <- getInfoDown
+       ; us    <- newUniqSupply
+       ; state <- getState
+       ; let   rhs_info_down = info { cgd_statics = cgs_binds state,
+                                      cgd_eob     = initEobInfo }
+               (result, fork_state_out) = doFCode body_code rhs_info_down 
+                                                  (initCgState us)
+       ; ASSERT( isNilOL (cgs_stmts fork_state_out) )
+         setState (state `addCodeBlocksFrom` fork_state_out)
+       ; return result }
+
+forkProc :: Code -> FCode CgStmts
+forkProc body_code
+  = do { info_down <- getInfoDown
+       ; us    <- newUniqSupply
+       ; state <- getState
+       ; let   fork_state_in = (initCgState us) 
+                                       { cgs_binds   = cgs_binds state,
+                                         cgs_stk_usg = cgs_stk_usg state,
+                                         cgs_hp_usg  = cgs_hp_usg state }
+                       -- ToDo: is the hp usage necesary?
+               (code_blks, fork_state_out) = doFCode (getCgStmts body_code) 
+                                                     info_down fork_state_in
+       ; setState $ state `stateIncUsageEval` fork_state_out
+       ; return code_blks }
+
+codeOnly :: Code -> Code
+-- Emit any code from the inner thing into the outer thing
+-- Do not affect anything else in the outer state
+-- Used in almost-circular code to prevent false loop dependencies
+codeOnly body_code
+  = do { info_down <- getInfoDown
+       ; us   <- newUniqSupply
+       ; state <- getState
+       ; let   fork_state_in = (initCgState us) { cgs_binds   = cgs_binds state,
+                                                  cgs_stk_usg = cgs_stk_usg state,
+                                                  cgs_hp_usg  = cgs_hp_usg state }
+               ((), fork_state_out) = doFCode body_code info_down fork_state_in
+       ; setState $ state `addCodeBlocksFrom` fork_state_out }
 \end{code}
 
 @forkAlts@ $bs~d$ takes fcodes $bs$ for the branches of a @case@, and
@@ -448,13 +595,23 @@ that
 forkAlts :: [FCode a] -> FCode [a]
 
 forkAlts branch_fcodes
-  = do info_down <- getInfoDown
-       in_state  <- getState
-       let compile (FCode fc)                  = fc info_down in_state
-       let (branch_results, branch_out_states) = unzip (map compile branch_fcodes)
-       setState $ foldl stateIncUsage in_state branch_out_states
-                       -- NB foldl.  in_state is the *left* argument to stateIncUsage
-       return branch_results
+  = do { info_down <- getInfoDown
+       ; us <- newUniqSupply
+       ; state <- getState
+       ; let compile us branch 
+               = (us2, doFCode branch info_down branch_state)
+               where
+                 (us1,us2) = splitUniqSupply us
+                 branch_state = (initCgState us1) {
+                                       cgs_binds   = cgs_binds state,
+                                       cgs_stk_usg = cgs_stk_usg state,
+                                       cgs_hp_usg  = cgs_hp_usg state }
+
+             (_us, results) = mapAccumL compile us branch_fcodes
+             (branch_results, branch_out_states) = unzip results
+       ; setState $ foldl stateIncUsage state branch_out_states
+               -- NB foldl.  state is the *left* argument to stateIncUsage
+       ; return branch_results }
 \end{code}
 
 @forkEval@ takes two blocks of code.
@@ -479,162 +636,204 @@ forkEval :: EndOfBlockInfo              -- For the body
         -> FCode EndOfBlockInfo        -- The new end of block info
 
 forkEval body_eob_info env_code body_code
-  = forkEvalHelp body_eob_info env_code body_code `thenFC` \ (v, sequel) ->
-    returnFC (EndOfBlockInfo v sequel)
+  = do  { (v, sequel) <- forkEvalHelp body_eob_info env_code body_code
+       ; returnFC (EndOfBlockInfo v sequel) }
 
 forkEvalHelp :: EndOfBlockInfo  -- For the body
             -> Code            -- Code to set environment
             -> FCode a         -- The code to do after the eval
-            -> FCode (Int,     -- Sp
-                      a)       -- Result of the FCode
-
-forkEvalHelp body_eob_info env_code body_code =
-       do
-               info_down@(MkCgInfoDown cg_info statics srt ticky _) <- getInfoDown
-               state <- getState
-               let info_down_for_body = MkCgInfoDown cg_info statics srt ticky body_eob_info
-               let (_,MkCgState _ binds ((v,t,f,_,_),_)) = 
-                       doFCode env_code info_down_for_body state
-               let state_for_body = MkCgState AbsCNop
-                            (nukeVolatileBinds binds)
-                            ((v,t,f,v,v), (0,0))
-               let (value_returned, state_at_end_return) = 
-                       doFCode body_code info_down_for_body state_for_body             
-               setState $ state `stateIncUsageEval` state_at_end_return
-               return (v,value_returned)
-               
-stateIncUsageEval :: CgState -> CgState -> CgState
-stateIncUsageEval (MkCgState absC1 bs ((v,t,f,r,h1),heap_usage))
-                 (MkCgState absC2 _  ((_,_,_,_,h2),         _))
-     = MkCgState (absC1 `mkAbsCStmts` absC2)
-                -- The AbsC coming back should consist only of nested declarations,
+            -> FCode (VirtualSpOffset, -- Sp
+                      a)               -- Result of the FCode
+       -- A disturbingly complicated function
+forkEvalHelp body_eob_info env_code body_code
+  = do { info_down@(MkCgInfoDown cg_info statics srt ticky _) <- getInfoDown
+       ; us   <- newUniqSupply
+       ; state <- getState
+       ; let { info_down_for_body = info_down {cgd_eob = body_eob_info}
+             ; (_, env_state) = doFCode env_code info_down_for_body 
+                                        (state {cgs_uniqs = us})
+             ; state_for_body = (initCgState (cgs_uniqs env_state)) 
+                                       { cgs_binds   = binds_for_body,
+                                         cgs_stk_usg = stk_usg_for_body }
+             ; binds_for_body   = nukeVolatileBinds (cgs_binds env_state)
+             ; stk_usg_from_env = cgs_stk_usg env_state
+             ; virtSp_from_env  = virtSp stk_usg_from_env
+             ; stk_usg_for_body = stk_usg_from_env {realSp = virtSp_from_env,
+                                                    hwSp   = virtSp_from_env}
+             ; (value_returned, state_at_end_return)
+                       = doFCode body_code info_down_for_body state_for_body           
+         } 
+       ; ASSERT( isNilOL (cgs_stmts state_at_end_return) )
+                -- The code coming back should consist only of nested declarations,
                 -- notably of the return vector!
-                bs
-                ((v,t,f,r,h1 `max` h2), heap_usage)
-       -- We don't max the heap high-watermark because stateIncUsageEval is
-       -- used only in forkEval, which in turn is only used for blocks of code
-       -- which do their own heap-check.
-\end{code}
+         setState $ state `stateIncUsageEval` state_at_end_return
+       ; return (virtSp_from_env, value_returned) }
 
-%************************************************************************
-%*                                                                     *
-\subsection[CgMonad-spitting-AbstractC]{Spitting out @AbstractC@}
-%*                                                                     *
-%************************************************************************
 
-@nopC@ is the no-op for the @Code@ monad; it adds no Abstract~C to the
-environment; @absC@ glues @ab_C@ onto the Abstract~C collected so far.
-\begin{code}
+-- ----------------------------------------------------------------------------
+-- Combinators for emitting code
+
 nopC :: Code
 nopC = return ()
 
-absC :: AbstractC -> Code
-absC more_absC = do
-       state@(MkCgState absC binds usage) <- getState
-       setState $ MkCgState (mkAbsCStmts absC more_absC) binds usage
-\end{code}
-
-These two are just like @absC@, except they examine the compilation
-info (whether SCC profiling or profiling-ctrs going) and possibly emit
-nothing.
-
-\begin{code}
-costCentresC :: FastString -> [CAddrMode] -> Code
-costCentresC macro args
- | opt_SccProfilingOn  = absC (CCallProfCCMacro macro args)
- | otherwise           = nopC
-
-profCtrC :: FastString -> [CAddrMode] -> Code
-profCtrC macro args
- | opt_DoTickyProfiling = absC (CCallProfCtrMacro macro args)
- | otherwise            = nopC
-
-profCtrAbsC :: FastString -> [CAddrMode] -> AbstractC
-profCtrAbsC macro args
- | opt_DoTickyProfiling = CCallProfCtrMacro macro args
- | otherwise            = AbsCNop
-
-ldvEnter :: Code
-ldvEnter = costCentresC FSLIT("LDV_ENTER") [CReg node]
-
-{- Try to avoid adding too many special compilation strategies here.
-   It's better to modify the header files as necessary for particular
-   targets, so that we can get away with as few variants of .hc files
-   as possible.
--}
-\end{code}
-
-@getAbsC@ compiles the code in the current environment, and returns
-the abstract C thus constructed (leaving the abstract C being carried
-around in the state untouched).         @getAbsC@ does not generate any
-in-line Abstract~C itself, but the environment it returns is that
-obtained from the compilation.
+whenC :: Bool -> Code -> Code
+whenC True  code = code
+whenC False code = nopC
+
+stmtC :: CmmStmt -> Code
+stmtC stmt = emitCgStmt (CgStmt stmt)
+
+labelC :: BlockId -> Code
+labelC id = emitCgStmt (CgLabel id)
+
+newLabelC :: FCode BlockId
+newLabelC = do { id <- newUnique; return (BlockId id) }
+
+checkedAbsC :: CmmStmt -> Code
+-- Emit code, eliminating no-ops
+checkedAbsC stmt = emitStmts (if isNopStmt stmt then nilOL
+                             else unitOL stmt)
+
+stmtsC :: [CmmStmt] -> Code
+stmtsC stmts = emitStmts (toOL stmts)
+
+-- Emit code; no no-op checking
+emitStmts :: CmmStmts -> Code
+emitStmts stmts = emitCgStmts (fmap CgStmt stmts)
+
+-- forkLabelledCode is for emitting a chunk of code with a label, outside
+-- of the current instruction stream.
+forkLabelledCode :: Code -> FCode BlockId
+forkLabelledCode code = getCgStmts code >>= forkCgStmts
+
+emitCgStmt :: CgStmt -> Code
+emitCgStmt stmt
+  = do { state <- getState
+       ; setState $ state { cgs_stmts = cgs_stmts state `snocOL` stmt }
+       }
+
+emitData :: Section -> [CmmStatic] -> Code
+emitData sect lits
+  = do         { state <- getState
+       ; setState $ state { cgs_tops = cgs_tops state `snocOL` data_block } }
+  where
+    data_block = CmmData sect lits
+
+emitProc :: [CmmLit] -> CLabel -> [LocalReg] -> [CmmBasicBlock] -> Code
+emitProc lits lbl args blocks
+  = do  { let proc_block = CmmProc (map CmmStaticLit lits) lbl args blocks
+       ; state <- getState
+       ; setState $ state { cgs_tops = cgs_tops state `snocOL` proc_block } }
+
+emitSimpleProc :: CLabel -> Code -> Code
+-- Emit a procedure whose body is the specified code; no info table
+emitSimpleProc lbl code
+  = do { stmts <- getCgStmts code
+       ; blks <- cgStmtsToBlocks stmts
+       ; emitProc [] lbl [] blks }
+
+getCmm :: Code -> FCode Cmm
+-- Get all the CmmTops (there should be no stmts)
+getCmm code 
+  = do { state1 <- getState
+       ; ((), state2) <- withState code (state1 { cgs_tops  = nilOL })
+       ; setState $ state2 { cgs_tops = cgs_tops state1 } 
+       ; return (Cmm (fromOL (cgs_tops state2))) }
+
+-- ----------------------------------------------------------------------------
+-- CgStmts
+
+-- These functions deal in terms of CgStmts, which is an abstract type
+-- representing the code in the current proc.
+
+
+-- emit CgStmts into the current instruction stream
+emitCgStmts :: CgStmts -> Code
+emitCgStmts stmts
+  = do { state <- getState
+       ; setState $ state { cgs_stmts = cgs_stmts state `appOL` stmts } }
+
+-- emit CgStmts outside the current instruction stream, and return a label
+forkCgStmts :: CgStmts -> FCode BlockId
+forkCgStmts stmts
+  = do  { id <- newLabelC
+       ; emitCgStmt (CgFork id stmts)
+       ; return id
+       }
+
+-- turn CgStmts into [CmmBasicBlock], for making a new proc.
+cgStmtsToBlocks :: CgStmts -> FCode [CmmBasicBlock]
+cgStmtsToBlocks stmts
+  = do  { id <- newLabelC
+       ; return (flattenCgStmts id stmts)
+       }       
+
+-- collect the code emitted by an FCode computation
+getCgStmts' :: FCode a -> FCode (a, CgStmts)
+getCgStmts' fcode
+  = do { state1 <- getState
+       ; (a, state2) <- withState fcode (state1 { cgs_stmts = nilOL })
+       ; setState $ state2 { cgs_stmts = cgs_stmts state1  }
+       ; return (a, cgs_stmts state2) }
+
+getCgStmts :: FCode a -> FCode CgStmts
+getCgStmts fcode = do { (_,stmts) <- getCgStmts' fcode; return stmts }
+
+-- Simple ways to construct CgStmts:
+noCgStmts :: CgStmts
+noCgStmts = nilOL
+
+oneCgStmt :: CmmStmt -> CgStmts
+oneCgStmt stmt = unitOL (CgStmt stmt)
+
+consCgStmt :: CmmStmt -> CgStmts -> CgStmts
+consCgStmt stmt stmts = CgStmt stmt `consOL` stmts
+
+-- ----------------------------------------------------------------------------
+-- Get the current module name
 
-\begin{code}
-getAbsC :: Code -> FCode AbstractC
-getAbsC code = do
-       MkCgState absC binds usage <- getState
-       ((),MkCgState absC2 binds2 usage2) <- withState code (MkCgState AbsCNop binds usage)
-       setState $ MkCgState absC binds2 usage2
-       return absC2
-\end{code}
-
-\begin{code}
 moduleName :: FCode Module
-moduleName = do
-       (MkCgInfoDown (MkCompInfo mod_name) _ _ _ _) <- getInfoDown
-       return mod_name
-\end{code}
+moduleName = do { info <- getInfoDown; return (cgd_mod info) }
+
+-- ----------------------------------------------------------------------------
+-- Get/set the end-of-block info
 
-\begin{code}
 setEndOfBlockInfo :: EndOfBlockInfo -> Code -> Code
 setEndOfBlockInfo eob_info code        = do
-       (MkCgInfoDown c_info statics srt ticky _) <- getInfoDown
-       withInfoDown code (MkCgInfoDown c_info statics srt ticky eob_info)
+       info  <- getInfoDown
+       withInfoDown code (info {cgd_eob = eob_info})
 
 getEndOfBlockInfo :: FCode EndOfBlockInfo
 getEndOfBlockInfo = do
-       (MkCgInfoDown c_info statics _ _ eob_info) <- getInfoDown
-       return eob_info
-\end{code}
+       info <- getInfoDown
+       return (cgd_eob info)
 
-There is just one SRT for each top level binding; all the nested
-bindings use sub-sections of this SRT.  The label is passed down to
-the nested bindings via the monad.
+-- ----------------------------------------------------------------------------
+-- Get/set the current SRT label
 
-\begin{code}
-getSRTInfo :: Name -> SRT -> FCode C_SRT
-getSRTInfo id NoSRT = return NoC_SRT
-getSRTInfo id (SRT off len bmp)
-  | len > hALF_WORD || bmp == [fromIntegral srt_escape] = do 
-       srt_lbl <- getSRTLabel
-       let srt_desc_lbl = mkSRTDescLabel id
-       absC (CSRTDesc srt_desc_lbl srt_lbl off len bmp)
-       return (C_SRT srt_desc_lbl 0 srt_escape)
-  | otherwise = do
-       srt_lbl <- getSRTLabel
-       return (C_SRT srt_lbl off (fromIntegral (head bmp)))
-
-srt_escape = (-1) :: StgHalfWord
+-- There is just one SRT for each top level binding; all the nested
+-- bindings use sub-sections of this SRT.  The label is passed down to
+-- the nested bindings via the monad.
 
 getSRTLabel :: FCode CLabel    -- Used only by cgPanic
-getSRTLabel = do MkCgInfoDown _ _ srt_lbl _ _ <- getInfoDown
-                return srt_lbl
+getSRTLabel = do info  <- getInfoDown
+                return (cgd_srt info)
 
 setSRTLabel :: CLabel -> FCode a -> FCode a
 setSRTLabel srt_lbl code
-  = do  MkCgInfoDown c_info statics _ ticky eob_info <- getInfoDown
-       withInfoDown code (MkCgInfoDown c_info statics srt_lbl ticky eob_info)
-\end{code}
+  = do  info <- getInfoDown
+       withInfoDown code (info { cgd_srt = srt_lbl})
+
+-- ----------------------------------------------------------------------------
+-- Get/set the current ticky counter label
 
-\begin{code}
 getTickyCtrLabel :: FCode CLabel
 getTickyCtrLabel = do
-       (MkCgInfoDown _ _ _ ticky _) <- getInfoDown
-       return ticky
+       info <- getInfoDown
+       return (cgd_ticky info)
 
 setTickyCtrLabel :: CLabel -> Code -> Code
 setTickyCtrLabel ticky code = do
-       (MkCgInfoDown c_info statics srt _ eob_info) <- getInfoDown
-       withInfoDown code (MkCgInfoDown c_info statics srt ticky eob_info)
+       info <- getInfoDown
+       withInfoDown code (info {cgd_ticky = ticky})
 \end{code}
diff --git a/ghc/compiler/codeGen/CgParallel.hs b/ghc/compiler/codeGen/CgParallel.hs
new file mode 100644 (file)
index 0000000..74cbeb5
--- /dev/null
@@ -0,0 +1,90 @@
+-- Code generation relaed to GpH
+--     (a) parallel
+--     (b) GranSim
+
+module CgParallel(
+       staticGranHdr,staticParHdr,
+       granFetchAndReschedule, granYield,
+       doGranAllocate
+  ) where
+
+import CgMonad
+import CgCallConv      ( mkRegLiveness )
+import Id              ( Id )
+import Cmm             ( CmmLit, GlobalReg(..), node, CmmExpr )
+import CmdLineOpts     ( opt_GranMacros )
+import Outputable
+
+staticParHdr :: [CmmLit]
+-- Parallel header words in a static closure
+staticParHdr = []
+
+--------------------------------------------------------
+--             GranSim stuff
+--------------------------------------------------------
+
+staticGranHdr :: [CmmLit]
+-- Gransim header words in a static closure
+staticGranHdr = []
+
+doGranAllocate :: CmmExpr -> Code      
+-- macro DO_GRAN_ALLOCATE
+doGranAllocate hp 
+  | not opt_GranMacros = nopC
+  | otherwise         = panic "doGranAllocate"
+
+
+
+-------------------------
+granFetchAndReschedule :: [(Id,GlobalReg)]  -- Live registers
+                      -> Bool                  -- Node reqd?
+                      -> Code
+-- Emit code for simulating a fetch and then reschedule.
+granFetchAndReschedule regs node_reqd
+  | opt_GranMacros && (node `elem` map snd regs || node_reqd)
+  = do { fetch
+       ; reschedule liveness node_reqd }
+  | otherwise
+  = nopC
+  where
+    liveness = mkRegLiveness regs 0 0
+
+fetch = panic "granFetch"
+       -- Was: absC (CMacroStmt GRAN_FETCH [])
+       --HWL: generate GRAN_FETCH macro for GrAnSim
+       --     currently GRAN_FETCH and GRAN_FETCH_AND_RESCHEDULE are miai
+
+reschedule liveness node_reqd = panic "granReschedule"
+       -- Was: absC  (CMacroStmt GRAN_RESCHEDULE [
+       --                mkIntCLit (I# (word2Int# liveness_mask)), 
+       --                mkIntCLit (if node_reqd then 1 else 0)])
+    
+
+-------------------------
+-- The @GRAN_YIELD@ macro is taken from JSM's  code for Concurrent Haskell. It
+-- allows to context-switch at  places where @node@ is  not alive (it uses the
+-- @Continue@ rather  than the @EnterNodeCode@  function in the  RTS). We emit
+-- this kind of macro at the beginning of the following kinds of basic bocks:
+-- \begin{itemize}
+--  \item Slow entry code where node is not alive (see @CgClosure.lhs@). Normally 
+--        we use @fetchAndReschedule@ at a slow entry code.
+--  \item Fast entry code (see @CgClosure.lhs@).
+--  \item Alternatives in case expressions (@CLabelledCode@ structures), provided
+--        that they are not inlined (see @CgCases.lhs@). These alternatives will 
+--        be turned into separate functions.
+
+granYield :: [(Id,GlobalReg)]   -- Live registers
+          -> Bool               -- Node reqd?
+          -> Code 
+
+granYield regs node_reqd
+  | opt_GranMacros && node_reqd = yield liveness
+  | otherwise                  = nopC
+  where
+     liveness = mkRegLiveness regs 0 0
+
+yield liveness = panic "granYield"
+       -- Was : absC (CMacroStmt GRAN_YIELD 
+        --                  [mkIntCLit (I# (word2Int# liveness_mask))])
+
+
diff --git a/ghc/compiler/codeGen/CgPrimOp.hs b/ghc/compiler/codeGen/CgPrimOp.hs
new file mode 100644 (file)
index 0000000..65ad0cc
--- /dev/null
@@ -0,0 +1,588 @@
+-----------------------------------------------------------------------------
+--
+-- Code generation for PrimOps.
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+module CgPrimOp (
+   cgPrimOp
+ ) where
+
+import StgSyn          ( StgLiveVars, StgArg )
+import CgBindery       ( getVolatileRegs, getArgAmodes )
+import CgMonad
+import CgInfoTbls      ( getConstrTag )
+import CgUtils         ( cmmOffsetW, cmmOffsetB, cmmLoadIndexW )
+import Cmm
+import CLabel          ( mkMAP_FROZEN_infoLabel )
+import CmmUtils
+import MachOp
+import SMRep
+import PrimOp          ( PrimOp(..) )
+import SMRep           ( tablesNextToCode )
+import Constants       ( wORD_SIZE, wORD_SIZE_IN_BITS )
+import Outputable
+
+-- ---------------------------------------------------------------------------
+-- Code generation for PrimOps
+
+cgPrimOp   :: [CmmReg]                 -- where to put the results
+          -> PrimOp            -- the op
+          -> [StgArg]          -- arguments
+          -> StgLiveVars       -- live vars, in case we need to save them
+          -> Code
+
+cgPrimOp results op args live
+  = do arg_exprs <- getArgAmodes args
+       let non_void_args = [ e | (r,e) <- arg_exprs, nonVoidArg r ] 
+       emitPrimOp results op non_void_args live
+
+
+emitPrimOp :: [CmmReg]                 -- where to put the results
+          -> PrimOp            -- the op
+          -> [CmmExpr]         -- arguments
+          -> StgLiveVars       -- live vars, in case we need to save them
+          -> Code
+
+--  First we handle various awkward cases specially.  The remaining
+-- easy cases are then handled by translateOp, defined below.
+
+emitPrimOp [res_r,res_c] IntAddCOp [aa,bb] live
+{- 
+   With some bit-twiddling, we can define int{Add,Sub}Czh portably in
+   C, and without needing any comparisons.  This may not be the
+   fastest way to do it - if you have better code, please send it! --SDM
+  
+   Return : r = a + b,  c = 0 if no overflow, 1 on overflow.
+  
+   We currently don't make use of the r value if c is != 0 (i.e. 
+   overflow), we just convert to big integers and try again.  This
+   could be improved by making r and c the correct values for
+   plugging into a new J#.  
+   
+   { r = ((I_)(a)) + ((I_)(b));                                        \
+     c = ((StgWord)(~(((I_)(a))^((I_)(b))) & (((I_)(a))^r)))   \
+         >> (BITS_IN (I_) - 1);                                        \
+   } 
+   Wading through the mass of bracketry, it seems to reduce to:
+   c = ( (~(a^b)) & (a^r) ) >>unsigned (BITS_IN(I_)-1)
+
+-}
+   = stmtsC [
+        CmmAssign res_r (CmmMachOp mo_wordAdd [aa,bb]),
+        CmmAssign res_c $
+         CmmMachOp mo_wordUShr [
+               CmmMachOp mo_wordAnd [
+                   CmmMachOp mo_wordNot [CmmMachOp mo_wordXor [aa,bb]],
+                   CmmMachOp mo_wordXor [aa, CmmReg res_r]
+               ], 
+               CmmLit (mkIntCLit (wORD_SIZE_IN_BITS - 1))
+         ]
+     ]
+
+
+emitPrimOp [res_r,res_c] IntSubCOp [aa,bb] live
+{- Similarly:
+   #define subIntCzh(r,c,a,b)                                  \
+   { r = ((I_)(a)) - ((I_)(b));                                        \
+     c = ((StgWord)((((I_)(a))^((I_)(b))) & (((I_)(a))^r)))    \
+         >> (BITS_IN (I_) - 1);                                        \
+   }
+
+   c =  ((a^b) & (a^r)) >>unsigned (BITS_IN(I_)-1)
+-}
+   = stmtsC [
+        CmmAssign res_r (CmmMachOp mo_wordSub [aa,bb]),
+        CmmAssign res_c $
+         CmmMachOp mo_wordUShr [
+               CmmMachOp mo_wordAnd [
+                   CmmMachOp mo_wordXor [aa,bb],
+                   CmmMachOp mo_wordXor [aa, CmmReg res_r]
+               ], 
+               CmmLit (mkIntCLit (wORD_SIZE_IN_BITS - 1))
+         ]
+     ]
+
+
+emitPrimOp [res] ParOp [arg] live
+   = stmtC (CmmAssign res (CmmLit (mkIntCLit 1)))
+
+emitPrimOp [res] ReadMutVarOp [mutv] live
+   = stmtC (CmmAssign res (cmmLoadIndexW mutv fixedHdrSize))
+
+emitPrimOp [] WriteMutVarOp [mutv,var] live
+   = stmtC (CmmStore (cmmOffsetW mutv fixedHdrSize) var)
+
+emitPrimOp [res] ForeignObjToAddrOp [fo] live
+   = stmtC (CmmAssign res (cmmLoadIndexW fo fixedHdrSize))
+
+emitPrimOp [] WriteForeignObjOp [fo,addr] live
+   = stmtC (CmmStore (cmmOffsetW fo fixedHdrSize) addr)
+
+-- #define sizzeofByteArrayzh(r,a) \
+--     r = (((StgArrWords *)(a))->words * sizeof(W_))
+emitPrimOp [res] SizeofByteArrayOp [arg] live
+   = stmtC $
+       CmmAssign res (CmmMachOp mo_wordMul [
+                         cmmLoadIndexW arg fixedHdrSize,
+                         CmmLit (mkIntCLit wORD_SIZE)
+                       ])
+
+-- #define sizzeofMutableByteArrayzh(r,a) \
+--      r = (((StgArrWords *)(a))->words * sizeof(W_))
+emitPrimOp [res] SizeofMutableByteArrayOp [arg] live
+   = emitPrimOp [res] SizeofByteArrayOp [arg] live
+
+
+-- #define touchzh(o)                  /* nothing */
+emitPrimOp [] TouchOp [arg] live
+   = nopC
+
+-- #define byteArrayContentszh(r,a) r = BYTE_ARR_CTS(a)
+emitPrimOp [res] ByteArrayContents_Char [arg] live
+   = stmtC (CmmAssign res (cmmOffsetB arg arrWordsHdrSize))
+
+-- #define stableNameToIntzh(r,s)   (r = ((StgStableName *)s)->sn)
+emitPrimOp [res] StableNameToIntOp [arg] live
+   = stmtC (CmmAssign res (cmmLoadIndexW arg fixedHdrSize))
+
+-- #define eqStableNamezh(r,sn1,sn2)                                   \
+--    (r = (((StgStableName *)sn1)->sn == ((StgStableName *)sn2)->sn))
+emitPrimOp [res] EqStableNameOp [arg1,arg2] live
+   = stmtC (CmmAssign res (CmmMachOp mo_wordEq [
+                               cmmLoadIndexW arg1 fixedHdrSize,
+                               cmmLoadIndexW arg2 fixedHdrSize
+                        ]))
+
+
+emitPrimOp [res] ReallyUnsafePtrEqualityOp [arg1,arg2] live
+   = stmtC (CmmAssign res (CmmMachOp mo_wordEq [arg1,arg2]))
+
+-- #define addrToHValuezh(r,a) r=(P_)a
+emitPrimOp [res] AddrToHValueOp [arg] live
+   = stmtC (CmmAssign res arg)
+
+-- #define dataToTagzh(r,a)  r=(GET_TAG(((StgClosure *)a)->header.info))
+emitPrimOp [res] DataToTagOp [arg] live
+   = stmtC (CmmAssign res (getConstrTag arg))
+
+{- Freezing arrays-of-ptrs requires changing an info table, for the
+   benefit of the generational collector.  It needs to scavenge mutable
+   objects, even if they are in old space.  When they become immutable,
+   they can be removed from this scavenge list.         -}
+
+-- #define unsafeFreezzeArrayzh(r,a)
+--     {
+--        SET_INFO((StgClosure *)a,&stg_MUT_ARR_PTRS_FROZEN_info);
+--       r = a;
+--     }
+emitPrimOp [res] UnsafeFreezeArrayOp [arg] live
+   = stmtsC [ setInfo arg (CmmLit (CmmLabel mkMAP_FROZEN_infoLabel)),
+            CmmAssign res arg ]
+
+-- #define unsafeFreezzeByteArrayzh(r,a)       r=(a)
+emitPrimOp [res] UnsafeFreezeByteArrayOp [arg] live
+   = stmtC (CmmAssign res arg)
+
+-- Reading/writing pointer arrays
+
+emitPrimOp [r] ReadArrayOp  [obj,ix]   live  = doReadPtrArrayOp r obj ix
+emitPrimOp [r] IndexArrayOp [obj,ix]   live  = doReadPtrArrayOp r obj ix
+emitPrimOp []  WriteArrayOp [obj,ix,v] live  = doWritePtrArrayOp obj ix v
+
+-- IndexXXXoffForeignObj
+
+emitPrimOp res IndexOffForeignObjOp_Char      args live = doIndexOffForeignObjOp (Just mo_u_8ToWord) I8 res args
+emitPrimOp res IndexOffForeignObjOp_WideChar  args live = doIndexOffForeignObjOp (Just mo_u_32ToWord) I32 res args
+emitPrimOp res IndexOffForeignObjOp_Int       args live = doIndexOffForeignObjOp Nothing wordRep res args
+emitPrimOp res IndexOffForeignObjOp_Word      args live = doIndexOffForeignObjOp Nothing wordRep res args
+emitPrimOp res IndexOffForeignObjOp_Addr      args live = doIndexOffForeignObjOp Nothing wordRep res args
+emitPrimOp res IndexOffForeignObjOp_Float     args live = doIndexOffForeignObjOp Nothing F32 res args
+emitPrimOp res IndexOffForeignObjOp_Double    args live = doIndexOffForeignObjOp Nothing F64 res args
+emitPrimOp res IndexOffForeignObjOp_StablePtr args live = doIndexOffForeignObjOp Nothing wordRep res args
+emitPrimOp res IndexOffForeignObjOp_Int8      args live = doIndexOffForeignObjOp (Just mo_s_8ToWord) I8  res args
+emitPrimOp res IndexOffForeignObjOp_Int16     args live = doIndexOffForeignObjOp (Just mo_s_16ToWord) I16 res args
+emitPrimOp res IndexOffForeignObjOp_Int32     args live = doIndexOffForeignObjOp (Just mo_s_32ToWord) I32 res args
+emitPrimOp res IndexOffForeignObjOp_Int64     args live = doIndexOffForeignObjOp Nothing I64 res args
+emitPrimOp res IndexOffForeignObjOp_Word8     args live = doIndexOffForeignObjOp (Just mo_u_8ToWord) I8  res args
+emitPrimOp res IndexOffForeignObjOp_Word16    args live = doIndexOffForeignObjOp (Just mo_u_16ToWord) I16 res args
+emitPrimOp res IndexOffForeignObjOp_Word32    args live = doIndexOffForeignObjOp (Just mo_u_32ToWord) I32 res args
+emitPrimOp res IndexOffForeignObjOp_Word64    args live = doIndexOffForeignObjOp Nothing I64 res args
+
+-- IndexXXXoffAddr
+
+emitPrimOp res IndexOffAddrOp_Char      args live = doIndexOffAddrOp (Just mo_u_8ToWord) I8 res args
+emitPrimOp res IndexOffAddrOp_WideChar  args live = doIndexOffAddrOp (Just mo_u_32ToWord) I32 res args
+emitPrimOp res IndexOffAddrOp_Int       args live = doIndexOffAddrOp Nothing wordRep res args
+emitPrimOp res IndexOffAddrOp_Word      args live = doIndexOffAddrOp Nothing wordRep res args
+emitPrimOp res IndexOffAddrOp_Addr      args live = doIndexOffAddrOp Nothing wordRep res args
+emitPrimOp res IndexOffAddrOp_Float     args live = doIndexOffAddrOp Nothing F32 res args
+emitPrimOp res IndexOffAddrOp_Double    args live = doIndexOffAddrOp Nothing F64 res args
+emitPrimOp res IndexOffAddrOp_StablePtr args live = doIndexOffAddrOp Nothing wordRep res args
+emitPrimOp res IndexOffAddrOp_Int8      args live = doIndexOffAddrOp (Just mo_s_8ToWord) I8  res args
+emitPrimOp res IndexOffAddrOp_Int16     args live = doIndexOffAddrOp (Just mo_s_16ToWord) I16 res args
+emitPrimOp res IndexOffAddrOp_Int32     args live = doIndexOffAddrOp (Just mo_s_32ToWord) I32 res args
+emitPrimOp res IndexOffAddrOp_Int64     args live = doIndexOffAddrOp Nothing I64 res args
+emitPrimOp res IndexOffAddrOp_Word8     args live = doIndexOffAddrOp (Just mo_u_8ToWord) I8  res args
+emitPrimOp res IndexOffAddrOp_Word16    args live = doIndexOffAddrOp (Just mo_u_16ToWord) I16 res args
+emitPrimOp res IndexOffAddrOp_Word32    args live = doIndexOffAddrOp (Just mo_u_32ToWord) I32 res args
+emitPrimOp res IndexOffAddrOp_Word64    args live = doIndexOffAddrOp Nothing I64 res args
+
+-- ReadXXXoffAddr, which are identical, for our purposes, to IndexXXXoffAddr.
+
+emitPrimOp res ReadOffAddrOp_Char      args live = doIndexOffAddrOp (Just mo_u_8ToWord) I8 res args
+emitPrimOp res ReadOffAddrOp_WideChar  args live = doIndexOffAddrOp (Just mo_u_32ToWord) I32 res args
+emitPrimOp res ReadOffAddrOp_Int       args live = doIndexOffAddrOp Nothing wordRep res args
+emitPrimOp res ReadOffAddrOp_Word      args live = doIndexOffAddrOp Nothing wordRep res args
+emitPrimOp res ReadOffAddrOp_Addr      args live = doIndexOffAddrOp Nothing wordRep res args
+emitPrimOp res ReadOffAddrOp_Float     args live = doIndexOffAddrOp Nothing F32 res args
+emitPrimOp res ReadOffAddrOp_Double    args live = doIndexOffAddrOp Nothing F64 res args
+emitPrimOp res ReadOffAddrOp_StablePtr args live = doIndexOffAddrOp Nothing wordRep res args
+emitPrimOp res ReadOffAddrOp_Int8      args live = doIndexOffAddrOp (Just mo_s_8ToWord) I8  res args
+emitPrimOp res ReadOffAddrOp_Int16     args live = doIndexOffAddrOp (Just mo_s_16ToWord) I16 res args
+emitPrimOp res ReadOffAddrOp_Int32     args live = doIndexOffAddrOp (Just mo_s_32ToWord) I32 res args
+emitPrimOp res ReadOffAddrOp_Int64     args live = doIndexOffAddrOp Nothing I64 res args
+emitPrimOp res ReadOffAddrOp_Word8     args live = doIndexOffAddrOp (Just mo_u_8ToWord) I8  res args
+emitPrimOp res ReadOffAddrOp_Word16    args live = doIndexOffAddrOp (Just mo_u_16ToWord) I16 res args
+emitPrimOp res ReadOffAddrOp_Word32    args live = doIndexOffAddrOp (Just mo_u_32ToWord) I32 res args
+emitPrimOp res ReadOffAddrOp_Word64    args live = doIndexOffAddrOp Nothing I64 res args
+
+-- IndexXXXArray
+
+emitPrimOp res IndexByteArrayOp_Char      args live = doIndexByteArrayOp (Just mo_u_8ToWord) I8 res args
+emitPrimOp res IndexByteArrayOp_WideChar  args live = doIndexByteArrayOp (Just mo_u_32ToWord) I32 res args
+emitPrimOp res IndexByteArrayOp_Int       args live = doIndexByteArrayOp Nothing wordRep res args
+emitPrimOp res IndexByteArrayOp_Word      args live = doIndexByteArrayOp Nothing wordRep res args
+emitPrimOp res IndexByteArrayOp_Addr      args live = doIndexByteArrayOp Nothing wordRep res args
+emitPrimOp res IndexByteArrayOp_Float     args live = doIndexByteArrayOp Nothing F32 res args
+emitPrimOp res IndexByteArrayOp_Double    args live = doIndexByteArrayOp Nothing F64 res args
+emitPrimOp res IndexByteArrayOp_StablePtr args live = doIndexByteArrayOp Nothing wordRep res args
+emitPrimOp res IndexByteArrayOp_Int8      args live = doIndexByteArrayOp (Just mo_s_8ToWord) I8  res args
+emitPrimOp res IndexByteArrayOp_Int16     args live = doIndexByteArrayOp (Just mo_s_16ToWord) I16  res args
+emitPrimOp res IndexByteArrayOp_Int32     args live = doIndexByteArrayOp (Just mo_s_32ToWord) I32  res args
+emitPrimOp res IndexByteArrayOp_Int64     args live = doIndexByteArrayOp Nothing I64  res args
+emitPrimOp res IndexByteArrayOp_Word8     args live = doIndexByteArrayOp (Just mo_u_8ToWord) I8  res args
+emitPrimOp res IndexByteArrayOp_Word16    args live = doIndexByteArrayOp (Just mo_u_16ToWord) I16  res args
+emitPrimOp res IndexByteArrayOp_Word32    args live = doIndexByteArrayOp (Just mo_u_32ToWord) I32  res args
+emitPrimOp res IndexByteArrayOp_Word64    args live = doIndexByteArrayOp Nothing I64  res args
+
+-- ReadXXXArray, identical to IndexXXXArray.
+
+emitPrimOp res ReadByteArrayOp_Char       args live = doIndexByteArrayOp (Just mo_u_8ToWord) I8 res args
+emitPrimOp res ReadByteArrayOp_WideChar   args live = doIndexByteArrayOp (Just mo_u_32ToWord) I32 res args
+emitPrimOp res ReadByteArrayOp_Int        args live = doIndexByteArrayOp Nothing wordRep res args
+emitPrimOp res ReadByteArrayOp_Word       args live = doIndexByteArrayOp Nothing wordRep res args
+emitPrimOp res ReadByteArrayOp_Addr       args live = doIndexByteArrayOp Nothing wordRep res args
+emitPrimOp res ReadByteArrayOp_Float      args live = doIndexByteArrayOp Nothing F32 res args
+emitPrimOp res ReadByteArrayOp_Double     args live = doIndexByteArrayOp Nothing F64 res args
+emitPrimOp res ReadByteArrayOp_StablePtr  args live = doIndexByteArrayOp Nothing wordRep res args
+emitPrimOp res ReadByteArrayOp_Int8       args live = doIndexByteArrayOp (Just mo_s_8ToWord) I8  res args
+emitPrimOp res ReadByteArrayOp_Int16      args live = doIndexByteArrayOp (Just mo_s_16ToWord) I16  res args
+emitPrimOp res ReadByteArrayOp_Int32      args live = doIndexByteArrayOp (Just mo_s_32ToWord) I32  res args
+emitPrimOp res ReadByteArrayOp_Int64      args live = doIndexByteArrayOp Nothing I64  res args
+emitPrimOp res ReadByteArrayOp_Word8      args live = doIndexByteArrayOp (Just mo_u_8ToWord) I8  res args
+emitPrimOp res ReadByteArrayOp_Word16     args live = doIndexByteArrayOp (Just mo_u_16ToWord) I16  res args
+emitPrimOp res ReadByteArrayOp_Word32     args live = doIndexByteArrayOp (Just mo_u_32ToWord) I32  res args
+emitPrimOp res ReadByteArrayOp_Word64     args live = doIndexByteArrayOp Nothing I64  res args
+
+-- WriteXXXoffAddr
+
+emitPrimOp res WriteOffAddrOp_Char       args live = doWriteOffAddrOp (Just mo_WordTo8) I8 res args
+emitPrimOp res WriteOffAddrOp_WideChar   args live = doWriteOffAddrOp (Just mo_WordTo32) I32 res args
+emitPrimOp res WriteOffAddrOp_Int        args live = doWriteOffAddrOp Nothing wordRep res args
+emitPrimOp res WriteOffAddrOp_Word       args live = doWriteOffAddrOp Nothing wordRep res args
+emitPrimOp res WriteOffAddrOp_Addr       args live = doWriteOffAddrOp Nothing wordRep res args
+emitPrimOp res WriteOffAddrOp_Float      args live = doWriteOffAddrOp Nothing F32 res args
+emitPrimOp res WriteOffAddrOp_ForeignObj args live = doWriteOffAddrOp Nothing wordRep res args
+emitPrimOp res WriteOffAddrOp_Double     args live = doWriteOffAddrOp Nothing F64 res args
+emitPrimOp res WriteOffAddrOp_StablePtr  args live = doWriteOffAddrOp Nothing wordRep res args
+emitPrimOp res WriteOffAddrOp_Int8       args live = doWriteOffAddrOp (Just mo_WordTo8) I8  res args
+emitPrimOp res WriteOffAddrOp_Int16      args live = doWriteOffAddrOp (Just mo_WordTo16) I16 res args
+emitPrimOp res WriteOffAddrOp_Int32      args live = doWriteOffAddrOp (Just mo_WordTo32) I32 res args
+emitPrimOp res WriteOffAddrOp_Int64      args live = doWriteOffAddrOp Nothing I64 res args
+emitPrimOp res WriteOffAddrOp_Word8      args live = doWriteOffAddrOp (Just mo_WordTo8) I8  res args
+emitPrimOp res WriteOffAddrOp_Word16     args live = doWriteOffAddrOp (Just mo_WordTo16) I16 res args
+emitPrimOp res WriteOffAddrOp_Word32     args live = doWriteOffAddrOp (Just mo_WordTo32) I32 res args
+emitPrimOp res WriteOffAddrOp_Word64     args live = doWriteOffAddrOp Nothing I64 res args
+
+-- WriteXXXArray
+
+emitPrimOp res WriteByteArrayOp_Char      args live = doWriteByteArrayOp (Just mo_WordTo8) I8 res args
+emitPrimOp res WriteByteArrayOp_WideChar  args live = doWriteByteArrayOp (Just mo_WordTo32) I32 res args
+emitPrimOp res WriteByteArrayOp_Int       args live = doWriteByteArrayOp Nothing wordRep res args
+emitPrimOp res WriteByteArrayOp_Word      args live = doWriteByteArrayOp Nothing wordRep res args
+emitPrimOp res WriteByteArrayOp_Addr      args live = doWriteByteArrayOp Nothing wordRep res args
+emitPrimOp res WriteByteArrayOp_Float     args live = doWriteByteArrayOp Nothing F32 res args
+emitPrimOp res WriteByteArrayOp_Double    args live = doWriteByteArrayOp Nothing F64 res args
+emitPrimOp res WriteByteArrayOp_StablePtr args live = doWriteByteArrayOp Nothing wordRep res args
+emitPrimOp res WriteByteArrayOp_Int8      args live = doWriteByteArrayOp (Just mo_WordTo8) I8  res args
+emitPrimOp res WriteByteArrayOp_Int16     args live = doWriteByteArrayOp (Just mo_WordTo16) I16  res args
+emitPrimOp res WriteByteArrayOp_Int32     args live = doWriteByteArrayOp (Just mo_WordTo32) I32  res args
+emitPrimOp res WriteByteArrayOp_Int64     args live = doWriteByteArrayOp Nothing I64  res args
+emitPrimOp res WriteByteArrayOp_Word8     args live = doWriteByteArrayOp (Just mo_WordTo8) I8  res args
+emitPrimOp res WriteByteArrayOp_Word16    args live = doWriteByteArrayOp (Just mo_WordTo16) I16  res args
+emitPrimOp res WriteByteArrayOp_Word32    args live = doWriteByteArrayOp (Just mo_WordTo32) I32  res args
+emitPrimOp res WriteByteArrayOp_Word64    args live = doWriteByteArrayOp Nothing I64  res args
+
+
+-- The rest just translate straightforwardly
+emitPrimOp [res] op [arg] live
+   | nopOp op
+   = stmtC (CmmAssign res arg)
+
+   | Just (mop,rep) <- narrowOp op
+   = stmtC (CmmAssign res (CmmMachOp (mop rep wordRep) [
+                         CmmMachOp (mop wordRep rep) [arg]]))
+
+emitPrimOp [res] op args live
+   | Just prim <- callishOp op
+   = do vols <- getVolatileRegs live
+       stmtC (CmmCall (CmmPrim prim) [(res,NoHint)] 
+               [(a,NoHint) | a<-args] (Just vols)) -- ToDo: hints?
+
+   | Just mop <- translateOp op
+   = let stmt = CmmAssign res (CmmMachOp mop args) in
+     stmtC stmt
+
+emitPrimOp _ op _ _
+ = pprPanic "emitPrimOp: can't translate PrimOp" (ppr op)
+
+
+-- These PrimOps are NOPs in Cmm
+
+nopOp Int2WordOp     = True
+nopOp Word2IntOp     = True
+nopOp Int2AddrOp     = True
+nopOp Addr2IntOp     = True
+nopOp _                     = False
+
+-- These PrimOps turn into double casts
+
+narrowOp Narrow8IntOp   = Just (MO_S_Conv, I8)
+narrowOp Narrow16IntOp  = Just (MO_S_Conv, I16)
+narrowOp Narrow32IntOp  = Just (MO_S_Conv, I32)
+narrowOp Narrow8WordOp  = Just (MO_U_Conv, I8)
+narrowOp Narrow16WordOp = Just (MO_U_Conv, I16)
+narrowOp Narrow32WordOp = Just (MO_U_Conv, I32)
+narrowOp _             = Nothing
+
+-- Native word signless ops
+
+translateOp IntAddOp       = Just mo_wordAdd
+translateOp IntSubOp       = Just mo_wordSub
+translateOp WordAddOp      = Just mo_wordAdd
+translateOp WordSubOp      = Just mo_wordSub
+translateOp AddrAddOp      = Just mo_wordAdd
+translateOp AddrSubOp      = Just mo_wordSub
+
+translateOp IntEqOp        = Just mo_wordEq
+translateOp IntNeOp        = Just mo_wordNe
+translateOp WordEqOp       = Just mo_wordEq
+translateOp WordNeOp       = Just mo_wordNe
+translateOp AddrEqOp       = Just mo_wordEq
+translateOp AddrNeOp       = Just mo_wordNe
+
+translateOp AndOp          = Just mo_wordAnd
+translateOp OrOp           = Just mo_wordOr
+translateOp XorOp          = Just mo_wordXor
+translateOp NotOp          = Just mo_wordNot
+translateOp SllOp         = Just mo_wordShl
+translateOp SrlOp         = Just mo_wordUShr
+
+translateOp AddrRemOp     = Just mo_wordURem
+
+-- Native word signed ops
+
+translateOp IntMulOp        = Just mo_wordMul
+translateOp IntMulMayOfloOp = Just (MO_S_MulMayOflo wordRep)
+translateOp IntQuotOp       = Just mo_wordSQuot
+translateOp IntRemOp        = Just mo_wordSRem
+translateOp IntNegOp        = Just mo_wordSNeg
+
+
+translateOp IntGeOp        = Just mo_wordSGe
+translateOp IntLeOp        = Just mo_wordSLe
+translateOp IntGtOp        = Just mo_wordSGt
+translateOp IntLtOp        = Just mo_wordSLt
+
+translateOp ISllOp        = Just mo_wordShl
+translateOp ISraOp        = Just mo_wordSShr
+translateOp ISrlOp        = Just mo_wordUShr
+
+-- Native word unsigned ops
+
+translateOp WordGeOp       = Just mo_wordUGe
+translateOp WordLeOp       = Just mo_wordULe
+translateOp WordGtOp       = Just mo_wordUGt
+translateOp WordLtOp       = Just mo_wordULt
+
+translateOp WordMulOp      = Just mo_wordMul
+translateOp WordQuotOp     = Just mo_wordUQuot
+translateOp WordRemOp      = Just mo_wordURem
+
+translateOp AddrGeOp       = Just mo_wordUGe
+translateOp AddrLeOp       = Just mo_wordULe
+translateOp AddrGtOp       = Just mo_wordUGt
+translateOp AddrLtOp       = Just mo_wordULt
+
+-- 32-bit unsigned ops
+
+translateOp CharEqOp       = Just (MO_Eq I32)
+translateOp CharNeOp       = Just (MO_Ne I32)
+translateOp CharGeOp       = Just (MO_U_Ge I32)
+translateOp CharLeOp       = Just (MO_U_Le I32)
+translateOp CharGtOp       = Just (MO_U_Gt I32)
+translateOp CharLtOp       = Just (MO_U_Lt I32)
+
+-- Double ops
+
+translateOp DoubleEqOp     = Just (MO_Eq F64)
+translateOp DoubleNeOp     = Just (MO_Ne F64)
+translateOp DoubleGeOp     = Just (MO_S_Ge F64)
+translateOp DoubleLeOp     = Just (MO_S_Le F64)
+translateOp DoubleGtOp     = Just (MO_S_Gt F64)
+translateOp DoubleLtOp     = Just (MO_S_Lt F64)
+
+translateOp DoubleAddOp    = Just (MO_Add F64)
+translateOp DoubleSubOp    = Just (MO_Sub F64)
+translateOp DoubleMulOp    = Just (MO_Mul F64)
+translateOp DoubleDivOp    = Just (MO_S_Quot F64)
+translateOp DoubleNegOp    = Just (MO_S_Neg F64)
+
+-- Float ops
+
+translateOp FloatEqOp     = Just (MO_Eq F32)
+translateOp FloatNeOp     = Just (MO_Ne F32)
+translateOp FloatGeOp     = Just (MO_S_Ge F32)
+translateOp FloatLeOp     = Just (MO_S_Le F32)
+translateOp FloatGtOp     = Just (MO_S_Gt F32)
+translateOp FloatLtOp     = Just (MO_S_Lt F32)
+
+translateOp FloatAddOp    = Just (MO_Add F32)
+translateOp FloatSubOp    = Just (MO_Sub F32)
+translateOp FloatMulOp    = Just (MO_Mul F32)
+translateOp FloatDivOp    = Just (MO_S_Quot F32)
+translateOp FloatNegOp    = Just (MO_S_Neg F32)
+
+-- Conversions
+
+translateOp Int2DoubleOp   = Just (MO_S_Conv wordRep F64)
+translateOp Double2IntOp   = Just (MO_S_Conv F64 wordRep)
+
+translateOp Int2FloatOp    = Just (MO_S_Conv wordRep F32)
+translateOp Float2IntOp    = Just (MO_S_Conv F32 wordRep)
+
+translateOp Float2DoubleOp = Just (MO_S_Conv F32 F64)
+translateOp Double2FloatOp = Just (MO_S_Conv F64 F32)
+
+translateOp OrdOp          = Just (MO_U_Conv I32 wordRep)
+translateOp ChrOp          = Just (MO_U_Conv wordRep I32)
+
+-- Word comparisons masquerading as more exotic things.
+
+translateOp SameMutVarOp           = Just mo_wordEq
+translateOp SameMVarOp             = Just mo_wordEq
+translateOp SameMutableArrayOp     = Just mo_wordEq
+translateOp SameMutableByteArrayOp = Just mo_wordEq
+translateOp EqForeignObj           = Just mo_wordEq
+translateOp EqStablePtrOp          = Just mo_wordEq
+
+translateOp _ = Nothing
+
+-- These primops are implemented by CallishMachOps, because they sometimes
+-- turn into foreign calls depending on the backend.
+
+callishOp DoublePowerOp  = Just MO_F64_Pwr
+callishOp DoubleSinOp    = Just MO_F64_Sin
+callishOp DoubleCosOp    = Just MO_F64_Cos
+callishOp DoubleTanOp    = Just MO_F64_Tan
+callishOp DoubleSinhOp   = Just MO_F64_Sinh
+callishOp DoubleCoshOp   = Just MO_F64_Cosh
+callishOp DoubleTanhOp   = Just MO_F64_Tanh
+callishOp DoubleAsinOp   = Just MO_F64_Asin
+callishOp DoubleAcosOp   = Just MO_F64_Acos
+callishOp DoubleAtanOp   = Just MO_F64_Atan
+callishOp DoubleLogOp    = Just MO_F64_Log
+callishOp DoubleExpOp    = Just MO_F64_Exp
+callishOp DoubleSqrtOp   = Just MO_F64_Sqrt
+
+callishOp FloatPowerOp  = Just MO_F32_Pwr
+callishOp FloatSinOp    = Just MO_F32_Sin
+callishOp FloatCosOp    = Just MO_F32_Cos
+callishOp FloatTanOp    = Just MO_F32_Tan
+callishOp FloatSinhOp   = Just MO_F32_Sinh
+callishOp FloatCoshOp   = Just MO_F32_Cosh
+callishOp FloatTanhOp   = Just MO_F32_Tanh
+callishOp FloatAsinOp   = Just MO_F32_Asin
+callishOp FloatAcosOp   = Just MO_F32_Acos
+callishOp FloatAtanOp   = Just MO_F32_Atan
+callishOp FloatLogOp    = Just MO_F32_Log
+callishOp FloatExpOp    = Just MO_F32_Exp
+callishOp FloatSqrtOp   = Just MO_F32_Sqrt
+
+callishOp _ = Nothing
+
+------------------------------------------------------------------------------
+-- Helpers for translating various minor variants of array indexing.
+
+doIndexOffForeignObjOp maybe_post_read_cast rep [res] [addr,idx]
+   = mkBasicIndexedRead 0 maybe_post_read_cast rep res 
+       (cmmLoadIndexW addr fixedHdrSize) idx
+doIndexOffForeignObjOp _ _ _ _ 
+   = panic "CgPrimOp: doIndexOffForeignObjOp"
+
+doIndexOffAddrOp maybe_post_read_cast rep [res] [addr,idx]
+   = mkBasicIndexedRead 0 maybe_post_read_cast rep res addr idx
+doIndexOffAddrOp _ _ _ _
+   = panic "CgPrimOp: doIndexOffAddrOp"
+
+doIndexByteArrayOp maybe_post_read_cast rep [res] [addr,idx]
+   = mkBasicIndexedRead arrWordsHdrSize maybe_post_read_cast rep res addr idx
+doIndexByteArrayOp _ _ _ _ 
+   = panic "CgPrimOp: doIndexByteArrayOp"
+
+doReadPtrArrayOp res addr idx
+   = mkBasicIndexedRead arrPtrsHdrSize Nothing wordRep res addr idx
+
+
+doWriteOffAddrOp maybe_pre_write_cast rep [] [addr,idx,val]
+   = mkBasicIndexedWrite 0 maybe_pre_write_cast rep addr idx val
+doWriteOffAddrOp _ _ _ _
+   = panic "CgPrimOp: doWriteOffAddrOp"
+
+doWriteByteArrayOp maybe_pre_write_cast rep [] [addr,idx,val]
+   = mkBasicIndexedWrite arrWordsHdrSize maybe_pre_write_cast rep addr idx val
+doWriteByteArrayOp _ _ _ _ 
+   = panic "CgPrimOp: doWriteByteArrayOp"
+
+doWritePtrArrayOp addr idx val
+   = mkBasicIndexedWrite arrPtrsHdrSize Nothing wordRep addr idx val
+
+
+mkBasicIndexedRead off Nothing read_rep res base idx
+   = stmtC (CmmAssign res (cmmLoadIndexOffExpr off read_rep base idx))
+mkBasicIndexedRead off (Just cast) read_rep res base idx
+   = stmtC (CmmAssign res (CmmMachOp cast [
+                               cmmLoadIndexOffExpr off read_rep base idx]))
+
+mkBasicIndexedWrite off Nothing write_rep base idx val
+   = stmtC (CmmStore (cmmIndexOffExpr off write_rep base idx) val)
+mkBasicIndexedWrite off (Just cast) write_rep base idx val
+   = stmtC (CmmStore (cmmIndexOffExpr off write_rep base idx) (CmmMachOp cast [val]))
+
+-- ----------------------------------------------------------------------------
+-- Misc utils
+
+cmmIndexOffExpr :: ByteOff -> MachRep -> CmmExpr -> CmmExpr -> CmmExpr
+cmmIndexOffExpr off rep base idx
+   = cmmIndexExpr rep (cmmOffsetB base off) idx
+
+cmmLoadIndexOffExpr :: ByteOff -> MachRep -> CmmExpr -> CmmExpr -> CmmExpr
+cmmLoadIndexOffExpr off rep base idx
+   = CmmLoad (cmmIndexOffExpr off rep base idx) rep
+
+setInfo :: CmmExpr -> CmmExpr -> CmmStmt
+setInfo closure_ptr info_ptr = CmmStore closure_ptr info_ptr
+
diff --git a/ghc/compiler/codeGen/CgProf.hs b/ghc/compiler/codeGen/CgProf.hs
new file mode 100644 (file)
index 0000000..30f801d
--- /dev/null
@@ -0,0 +1,474 @@
+-----------------------------------------------------------------------------
+--
+-- Code generation for profiling
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+module CgProf (
+       mkCCostCentre, mkCCostCentreStack,
+
+       -- Cost-centre Profiling
+       dynProfHdr, profDynAlloc, profAlloc, staticProfHdr, initUpdFrameProf,
+       enterCostCentre, enterCostCentrePAP, enterCostCentreThunk, 
+       chooseDynCostCentres, 
+       costCentreFrom, 
+       curCCS, curCCSAddr,
+       emitCostCentreDecl, emitCostCentreStackDecl, 
+       emitRegisterCC, emitRegisterCCS,
+       emitSetCCC, emitCCS,
+
+       -- Lag/drag/void stuff
+       ldvEnter, ldvRecordCreate
+  ) where
+
+#include "HsVersions.h"
+#include "../includes/ghcconfig.h"
+       -- Needed by Constants.h
+#include "../includes/Constants.h"
+       -- For LDV_CREATE_MASK, LDV_STATE_USE
+       -- which are StgWords
+#include "../includes/DerivedConstants.h"
+       -- For REP_xxx constants, which are MachReps
+
+import ClosureInfo     ( ClosureInfo, closureSize,
+                         closureName, isToplevClosure, closureReEntrant, )
+import CgUtils
+import CgMonad
+import SMRep           ( StgWord, profHdrSize )
+
+import Cmm
+import MachOp
+import CmmUtils                ( zeroCLit, mkIntCLit, mkLblExpr )
+import CLabel          ( mkCCLabel, mkCCSLabel, mkRtsDataLabel )
+
+import Module          ( moduleNameUserString )
+import Id              ( Id )
+import CostCentre
+import StgSyn          ( GenStgExpr(..), StgExpr )
+import CmdLineOpts     ( opt_SccProfilingOn )
+import FastString      ( FastString, mkFastString, LitString ) 
+import Constants       -- Lots of field offsets
+import Outputable
+
+import Maybe
+import Char            ( ord )
+import Monad           ( when )
+
+-----------------------------------------------------------------------------
+--
+-- Cost-centre-stack Profiling
+--
+-----------------------------------------------------------------------------
+
+-- Expression representing the current cost centre stack
+curCCS :: CmmExpr
+curCCS = CmmLoad curCCSAddr wordRep
+
+-- Address of current CCS variable, for storing into
+curCCSAddr :: CmmExpr
+curCCSAddr = CmmLit (CmmLabel (mkRtsDataLabel SLIT("CCCS")))
+
+mkCCostCentre :: CostCentre -> CmmLit
+mkCCostCentre cc = CmmLabel (mkCCLabel cc)
+
+mkCCostCentreStack :: CostCentreStack -> CmmLit
+mkCCostCentreStack ccs = CmmLabel (mkCCSLabel ccs)
+
+costCentreFrom :: CmmExpr      -- A closure pointer
+              -> CmmExpr       -- The cost centre from that closure
+costCentreFrom cl = CmmLoad (cmmOffsetB cl oFFSET_StgHeader_ccs) wordRep
+
+staticProfHdr :: CostCentreStack -> [CmmLit]
+-- The profiling header words in a static closure
+-- Was SET_STATIC_PROF_HDR
+staticProfHdr ccs = ifProfilingL [mkCCostCentreStack ccs, 
+                                 staticLdvInit]
+
+dynProfHdr :: CmmExpr -> [CmmExpr]
+-- Profiling header words in a dynamic closure
+dynProfHdr ccs = ifProfilingL [ccs, dynLdvInit]
+
+initUpdFrameProf :: CmmExpr -> Code
+-- Initialise the profiling field of an update frame
+initUpdFrameProf frame_amode 
+  = ifProfiling $      -- frame->header.prof.ccs = CCCS
+    stmtC (CmmStore (cmmOffsetB frame_amode oFFSET_StgHeader_ccs) curCCS)
+       -- frame->header.prof.hp.rs = NULL (or frame-header.prof.hp.ldvw = 0) 
+       -- is unnecessary because it is not used anyhow.
+
+-- -----------------------------------------------------------------------------
+-- Recording allocation in a cost centre
+
+-- | Record the allocation of a closure.  The CmmExpr is the cost
+-- centre stack to which to attribute the allocation.
+profDynAlloc :: ClosureInfo -> CmmExpr -> Code
+profDynAlloc cl_info ccs
+  = ifProfiling $
+    profAlloc (CmmLit (mkIntCLit (closureSize cl_info))) ccs
+
+-- | Record the allocation of a closure (size is given by a CmmExpr)
+-- The size must be in words, because the allocation counter in a CCS counts
+-- in words.
+profAlloc :: CmmExpr -> CmmExpr -> Code
+profAlloc words ccs
+  = ifProfiling $
+    stmtC (addToMemE alloc_rep
+               (cmmOffsetB ccs oFFSET_CostCentreStack_mem_alloc)
+               (CmmMachOp (MO_U_Conv wordRep alloc_rep) $
+                 [CmmMachOp mo_wordSub [words, 
+                                        CmmLit (mkIntCLit profHdrSize)]]))
+               -- subtract the "profiling overhead", which is the
+               -- profiling header in a closure.
+ where 
+       alloc_rep =  REP_CostCentreStack_mem_alloc
+
+-- ----------------------------------------------------------------------
+-- Setting the cost centre in a new closure
+
+chooseDynCostCentres :: CostCentreStack
+                    -> [Id]            -- Args
+                    -> StgExpr         -- Body
+                    -> FCode (CmmExpr, CmmExpr)
+-- Called when alllcating a closure
+-- Tells which cost centre to put in the object, and which
+-- to blame the cost of allocation on
+chooseDynCostCentres ccs args body = do
+  -- Cost-centre we record in the object
+  use_ccs <- emitCCS ccs
+
+  -- Cost-centre on whom we blame the allocation
+  let blame_ccs
+       | null args && isBox body = CmmLit (mkCCostCentreStack overheadCCS)
+       | otherwise               = use_ccs
+
+  return (use_ccs, blame_ccs)
+
+
+-- Some CostCentreStacks are a sequence of pushes on top of CCCS.
+-- These pushes must be performed before we can refer to the stack in
+-- an expression.
+emitCCS :: CostCentreStack -> FCode CmmExpr
+emitCCS ccs = push_em (ccsExpr ccs') (reverse cc's)
+  where
+       (cc's, ccs') = decomposeCCS ccs
+
+       push_em ccs [] = return ccs
+       push_em ccs (cc:rest) = do
+         tmp <- newTemp wordRep
+         pushCostCentre tmp ccs cc
+         push_em (CmmReg tmp) rest
+
+ccsExpr :: CostCentreStack -> CmmExpr
+ccsExpr ccs
+  | isCurrentCCS ccs = curCCS
+  | otherwise        = CmmLit (mkCCostCentreStack ccs)
+
+
+isBox :: StgExpr -> Bool
+-- If it's an utterly trivial RHS, then it must be
+-- one introduced by boxHigherOrderArgs for profiling,
+-- so we charge it to "OVERHEAD".
+-- This looks like a GROSS HACK to me --SDM
+isBox (StgApp fun []) = True
+isBox other          = False
+
+
+-- -----------------------------------------------------------------------
+-- Setting the current cost centre on entry to a closure
+
+-- For lexically scoped profiling we have to load the cost centre from
+-- the closure entered, if the costs are not supposed to be inherited.
+-- This is done immediately on entering the fast entry point.
+
+-- Load current cost centre from closure, if not inherited.
+-- Node is guaranteed to point to it, if profiling and not inherited.
+
+enterCostCentre
+   :: ClosureInfo 
+   -> CostCentreStack
+   -> StgExpr  -- The RHS of the closure
+   -> Code
+
+-- We used to have a special case for bindings of form
+--     f = g True
+-- where g has arity 2.  The RHS is a thunk, but we don't
+-- need to update it; and we want to subsume costs.
+-- We don't have these sort of PAPs any more, so the special
+-- case has gone away.
+
+enterCostCentre closure_info ccs body
+  = ifProfiling $
+    ASSERT2(not (noCCSAttached ccs), ppr (closureName closure_info) <+> ppr ccs)
+    enter_cost_centre closure_info ccs body
+
+enter_cost_centre closure_info ccs body
+  | isSubsumedCCS ccs
+  = ASSERT(isToplevClosure closure_info)
+    ASSERT(re_entrant)
+    enter_ccs_fsub
+       
+  | isDerivedFromCurrentCCS ccs
+  = do {
+       if re_entrant && not is_box
+         then
+               enter_ccs_fun node_ccs
+         else
+               stmtC (CmmStore curCCSAddr node_ccs)
+
+       -- don't forget to bump the scc count.  This closure might have been
+       -- of the form   let x = _scc_ "x" e in ...x..., which the SCCfinal
+       -- pass has turned into simply  let x = e in ...x... and attached
+       -- the _scc_ as PushCostCentre(x,CCCS) on the x closure.  So that
+       -- we don't lose the scc counter, bump it in the entry code for x.
+       -- ToDo: for a multi-push we should really bump the counter for
+       -- each of the intervening CCSs, not just the top one.
+       ; when (not (isCurrentCCS ccs)) $
+               stmtC (bumpSccCount curCCS)
+       }
+
+  | isCafCCS ccs
+  = ASSERT(isToplevClosure closure_info)
+    ASSERT(not re_entrant)
+    do {       -- This is just a special case of the isDerivedFromCurrentCCS
+               -- case above.  We could delete this, but it's a micro
+               -- optimisation and saves a bit of code.
+         stmtC (CmmStore curCCSAddr enc_ccs)
+       ; stmtC (bumpSccCount node_ccs)
+       }
+
+  | otherwise
+  = panic "enterCostCentre"
+  where
+    enc_ccs    = CmmLit (mkCCostCentreStack ccs)
+    re_entrant = closureReEntrant closure_info
+    node_ccs   = costCentreFrom (CmmReg nodeReg)
+    is_box     = isBox body
+
+-- set the current CCS when entering a PAP
+enterCostCentrePAP :: CmmExpr -> Code
+enterCostCentrePAP closure = 
+  ifProfiling $ do 
+    enter_ccs_fun (costCentreFrom closure)
+    enteringPAP 1
+  
+enterCostCentreThunk :: CmmExpr -> Code
+enterCostCentreThunk closure = 
+  ifProfiling $ do 
+    stmtC $ CmmStore curCCSAddr (costCentreFrom closure)
+
+enter_ccs_fun stack = emitRtsCall SLIT("EnterFunCCS") [(stack,PtrHint)]
+
+enter_ccs_fsub = enteringPAP 0
+
+-- When entering a PAP, EnterFunCCS is called by both the PAP entry
+-- code and the function entry code; we don't want the function's
+-- entry code to also update CCCS in the event that it was called via
+-- a PAP, so we set the flag entering_PAP to indicate that we are
+-- entering via a PAP.
+enteringPAP :: Integer -> Code
+enteringPAP n
+  = stmtC (CmmStore (CmmLit (CmmLabel (mkRtsDataLabel SLIT("entering_PAP"))))
+               (CmmLit (CmmInt n cIntRep)))
+
+ifProfiling :: Code -> Code
+ifProfiling code
+  | opt_SccProfilingOn = code
+  | otherwise         = nopC
+
+ifProfilingL :: [a] -> [a]
+ifProfilingL xs
+  | opt_SccProfilingOn = xs
+  | otherwise         = []
+
+
+-- ---------------------------------------------------------------------------
+-- Initialising Cost Centres & CCSs
+
+emitCostCentreDecl
+   :: CostCentre
+   -> Code
+emitCostCentreDecl cc = do 
+  { label <- mkStringCLit (costCentreUserName cc)
+  ; modl  <- mkStringCLit (moduleNameUserString (cc_mod cc))
+  ; let
+     lits = [ zero,    -- StgInt ccID,
+             label,    -- char *label,
+             modl,     -- char *module,
+              zero,    -- StgWord time_ticks
+              zero64,  -- StgWord64 mem_alloc
+             subsumed, -- StgInt is_caf
+             zero      -- struct _CostCentre *link
+           ] 
+  ; emitDataLits (mkCCLabel cc) lits
+  }
+  where
+       subsumed | isCafCC cc = mkIntCLit (ord 'c')  -- 'c' == is a CAF
+                | otherwise  = mkIntCLit (ord 'B')  -- 'B' == is boring
+           
+
+emitCostCentreStackDecl
+   :: CostCentreStack
+   -> Code
+emitCostCentreStackDecl ccs 
+  | Just cc <- maybeSingletonCCS ccs = do
+  { let
+     lits = [ zero,
+             mkCCostCentre cc,
+             zero,   -- struct _CostCentreStack *prevStack;
+             zero,   -- struct _IndexTable *indexTable;
+             zero,   -- StgWord    selected;       
+             zero64, -- StgWord64  scc_count;      
+             zero,   -- StgWord    time_ticks;     
+             zero64, -- StgWord64  mem_alloc;      
+             zero,   -- StgWord    inherited_ticks;
+             zero64, -- StgWord64  inherited_alloc;
+             zero    -- CostCentre *root;
+          ]
+  ; emitDataLits (mkCCSLabel ccs) lits
+  }
+  | otherwise = pprPanic "emitCostCentreStackDecl" (ppr ccs)
+
+zero = mkIntCLit 0
+zero64 = CmmInt 0 I64
+
+
+-- ---------------------------------------------------------------------------
+-- Registering CCs and CCSs
+
+--   (cc)->link = CC_LIST;
+--   CC_LIST = (cc);
+--   (cc)->ccID = CC_ID++;
+
+emitRegisterCC :: CostCentre -> Code
+emitRegisterCC cc = do
+  { tmp <- newTemp cIntRep
+  ; stmtsC [
+     CmmStore (cmmOffsetB cc_lit oFFSET_CostCentre_link)
+                (CmmLoad cC_LIST wordRep),
+     CmmStore cC_LIST cc_lit,
+     CmmAssign tmp (CmmLoad cC_ID cIntRep),
+     CmmStore (cmmOffsetB cc_lit oFFSET_CostCentre_ccID) (CmmReg tmp),
+     CmmStore cC_ID (cmmRegOffB tmp 1)
+   ]
+  }
+  where
+    cc_lit = CmmLit (CmmLabel (mkCCLabel cc))
+
+--  (ccs)->prevStack = CCS_LIST;
+--  CCS_LIST = (ccs);
+--  (ccs)->ccsID = CCS_ID++;
+
+emitRegisterCCS :: CostCentreStack -> Code
+emitRegisterCCS ccs = do
+  { tmp <- newTemp cIntRep
+  ; stmtsC [
+     CmmStore (cmmOffsetB ccs_lit oFFSET_CostCentreStack_prevStack) 
+                       (CmmLoad cCS_LIST wordRep),
+     CmmStore cCS_LIST ccs_lit,
+     CmmAssign tmp (CmmLoad cCS_ID cIntRep),
+     CmmStore (cmmOffsetB ccs_lit oFFSET_CostCentreStack_ccsID) (CmmReg tmp),
+     CmmStore cCS_ID (cmmRegOffB tmp 1)
+   ]
+  }
+  where
+    ccs_lit = CmmLit (CmmLabel (mkCCSLabel ccs))
+
+
+cC_LIST = CmmLit (CmmLabel (mkRtsDataLabel SLIT("CC_LIST")))
+cC_ID   = CmmLit (CmmLabel (mkRtsDataLabel SLIT("CC_ID")))
+
+cCS_LIST = CmmLit (CmmLabel (mkRtsDataLabel SLIT("CCS_LIST")))
+cCS_ID   = CmmLit (CmmLabel (mkRtsDataLabel SLIT("CCS_ID")))
+
+-- ---------------------------------------------------------------------------
+-- Set the current cost centre stack
+
+emitSetCCC :: CostCentre -> Code
+emitSetCCC cc
+  | not opt_SccProfilingOn = nopC
+  | otherwise = do 
+    ASSERTM(sccAbleCostCentre cc)
+    tmp <- newTemp wordRep
+    pushCostCentre tmp curCCS cc
+    stmtC (CmmStore curCCSAddr (CmmReg tmp))
+    when (isSccCountCostCentre cc) $ 
+       stmtC (bumpSccCount curCCS)
+
+pushCostCentre :: CmmReg -> CmmExpr -> CostCentre -> Code
+pushCostCentre result ccs cc
+  = emitRtsCallWithResult result PtrHint
+       SLIT("PushCostCentre") [(ccs,PtrHint), 
+                               (CmmLit (mkCCostCentre cc), PtrHint)]
+
+bumpSccCount :: CmmExpr -> CmmStmt
+bumpSccCount ccs
+  = addToMem REP_CostCentreStack_scc_count
+        (cmmOffsetB ccs oFFSET_CostCentreStack_scc_count) 1
+
+-----------------------------------------------------------------------------
+--
+--             Lag/drag/void stuff
+--
+-----------------------------------------------------------------------------
+
+--
+-- Initial value for the LDV field in a static closure
+--
+staticLdvInit :: CmmLit
+staticLdvInit = zeroCLit
+
+--
+-- Initial value of the LDV field in a dynamic closure
+--
+dynLdvInit :: CmmExpr
+dynLdvInit =     -- (era << LDV_SHIFT) | LDV_STATE_CREATE  
+  CmmMachOp mo_wordOr [
+      CmmMachOp mo_wordShl [loadEra, CmmLit (mkIntCLit lDV_SHIFT) ],
+      CmmLit (mkWordCLit lDV_STATE_CREATE)
+  ]
+        
+--
+-- Initialise the LDV word of a new closure
+--
+ldvRecordCreate :: CmmExpr -> Code
+ldvRecordCreate closure = stmtC $ CmmStore (ldvWord closure) dynLdvInit
+
+--
+-- Called when a closure is entered, marks the closure as having been "used".
+-- The closure is not an 'inherently used' one.
+-- The closure is not IND or IND_OLDGEN because neither is considered for LDV
+-- profiling.
+--
+ldvEnter :: CmmExpr -> Code
+-- Argument is a closure pointer
+ldvEnter cl_ptr 
+  =  ifProfiling $
+     -- if (era > 0) {
+     --    LDVW((c)) = (LDVW((c)) & LDV_CREATE_MASK) |
+     --                era | LDV_STATE_USE }
+    emitIf (CmmMachOp mo_wordUGt [loadEra, CmmLit zeroCLit])
+          (stmtC (CmmStore ldv_wd new_ldv_wd))
+  where
+    ldv_wd = ldvWord cl_ptr
+    new_ldv_wd = cmmOrWord (cmmAndWord (CmmLoad ldv_wd wordRep)
+                                      (CmmLit (mkWordCLit lDV_CREATE_MASK)))
+                (cmmOrWord loadEra (CmmLit (mkWordCLit lDV_STATE_USE)))
+
+loadEra :: CmmExpr 
+loadEra = CmmLoad (mkLblExpr (mkRtsDataLabel SLIT("era"))) cIntRep
+
+ldvWord :: CmmExpr -> CmmExpr
+-- Takes the address of a closure, and returns 
+-- the address of the LDV word in the closure
+ldvWord closure_ptr = cmmOffsetB closure_ptr oFFSET_StgHeader_ldvw
+
+-- LDV constants, from ghc/includes/Constants.h
+lDV_SHIFT       = (LDV_SHIFT :: Int)
+--lDV_STATE_MASK   = (LDV_STATE_MASK :: StgWord)
+lDV_CREATE_MASK  = (LDV_CREATE_MASK :: StgWord)
+--lDV_LAST_MASK    = (LDV_LAST_MASK :: StgWord)
+lDV_STATE_CREATE = (LDV_STATE_CREATE :: StgWord)
+lDV_STATE_USE    = (LDV_STATE_USE :: StgWord)
+
diff --git a/ghc/compiler/codeGen/CgRetConv.hi-boot b/ghc/compiler/codeGen/CgRetConv.hi-boot
deleted file mode 100644 (file)
index 9b14f43..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-_interface_ CgRetConv 1
-_exports_
-CgRetConv CtrlReturnConvention(VectoredReturn UnvectoredReturn) ctrlReturnConvAlg;
-_declarations_
-1 data CtrlReturnConvention = VectoredReturn PrelBase.Int | UnvectoredReturn PrelBase.Int;
-1 ctrlReturnConvAlg _:_ TyCon.TyCon -> CtrlReturnConvention ;;
-
diff --git a/ghc/compiler/codeGen/CgRetConv.lhs b/ghc/compiler/codeGen/CgRetConv.lhs
deleted file mode 100644 (file)
index ecf7d52..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-%
-% (c) The GRASP Project, Glasgow University, 1992-1998
-%
-% $Id: CgRetConv.lhs,v 1.34 2003/10/09 11:58:46 simonpj Exp $
-%
-\section[CgRetConv]{Return conventions for the code generator}
-
-The datatypes and functions here encapsulate what there is to know
-about return conventions.
-
-\begin{code}
-module CgRetConv (
-       CtrlReturnConvention(..),
-       ctrlReturnConvAlg,
-       dataReturnConvPrim,
-       assignRegs, assignAllRegs
-    ) where
-
-#include "HsVersions.h"
-
-import AbsCSyn         -- quite a few things
-import Constants       ( mAX_FAMILY_SIZE_FOR_VEC_RETURNS,
-                         mAX_Vanilla_REG, mAX_Float_REG,
-                         mAX_Double_REG, mAX_Long_REG,
-                         mAX_Real_Vanilla_REG, mAX_Real_Float_REG,
-                         mAX_Real_Double_REG, mAX_Real_Long_REG
-                       )
-import CmdLineOpts     ( opt_Unregisterised )
-import Maybes          ( mapCatMaybes )
-import PrimRep         ( isFloatingRep, PrimRep(..), is64BitRep )
-import TyCon           ( TyCon, tyConFamilySize )
-import Util            ( isn'tIn )
-import FastTypes
-import Outputable
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[CgRetConv-possibilities]{Data types that encode possible return conventions}
-%*                                                                     *
-%************************************************************************
-
-A @CtrlReturnConvention@ says how {\em control} is returned.
-\begin{code}
-data CtrlReturnConvention
-  = VectoredReturn     Int     -- size of the vector table (family size)
-  | UnvectoredReturn    Int    -- family size
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[CgRetConv-algebraic]{Return conventions for algebraic datatypes}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-ctrlReturnConvAlg :: TyCon -> CtrlReturnConvention
-
-ctrlReturnConvAlg tycon
-  = case (tyConFamilySize tycon) of
-      size -> -- we're supposed to know...
-       if (size > (1::Int) && size <= mAX_FAMILY_SIZE_FOR_VEC_RETURNS) then
-           VectoredReturn size
-       else
-           UnvectoredReturn size       
-  -- NB: unvectored returns Include size 0 (no constructors), so that
-  --     the following perverse code compiles (it crashed GHC in 5.02)
-  --       data T1
-  --       data T2 = T2 !T1 Int
-  --     The only value of type T1 is bottom, which never returns anyway.
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[CgRetConv-prim]{Return conventions for primitive datatypes}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-dataReturnConvPrim :: PrimRep -> MagicId
-
-dataReturnConvPrim PtrRep       = VanillaReg PtrRep  (_ILIT 1)
-dataReturnConvPrim IntRep      = VanillaReg IntRep  (_ILIT 1)
-dataReturnConvPrim WordRep     = VanillaReg WordRep (_ILIT 1)
-dataReturnConvPrim Int32Rep    = VanillaReg Int32Rep (_ILIT 1)
-dataReturnConvPrim Word32Rep   = VanillaReg Word32Rep (_ILIT 1)
-dataReturnConvPrim Int64Rep    = LongReg Int64Rep  (_ILIT 1)
-dataReturnConvPrim Word64Rep   = LongReg Word64Rep (_ILIT 1)
-dataReturnConvPrim AddrRep     = VanillaReg AddrRep (_ILIT 1)
-dataReturnConvPrim CharRep     = VanillaReg CharRep (_ILIT 1)
-dataReturnConvPrim Int8Rep     = VanillaReg Int8Rep (_ILIT 1)
-dataReturnConvPrim FloatRep    = FloatReg  (_ILIT 1)
-dataReturnConvPrim DoubleRep   = DoubleReg (_ILIT 1)
-dataReturnConvPrim StablePtrRep = VanillaReg StablePtrRep  (_ILIT 1)
-dataReturnConvPrim VoidRep     = VoidReg
-
-#ifdef DEBUG
-dataReturnConvPrim rep         = pprPanic "dataReturnConvPrim:" (ppr rep)
-#endif
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsubsection[CgRetConv-regs]{Register assignment}
-%*                                                                     *
-%************************************************************************
-
-How to assign registers for 
-
-       1) Calling a fast entry point.
-       2) Returning an unboxed tuple.
-       3) Invoking an out-of-line PrimOp.
-
-Registers are assigned in order.
-
-If we run out, we don't attempt to assign any further registers (even
-though we might have run out of only one kind of register); we just
-return immediately with the left-overs specified.
-
-The alternative version @assignAllRegs@ uses the complete set of
-registers, including those that aren't mapped to real machine
-registers.  This is used for calling special RTS functions and PrimOps
-which expect their arguments to always be in the same registers.
-
-\begin{code}
-assignRegs, assignAllRegs
-       :: [MagicId]    -- Unavailable registers
-       -> [PrimRep]    -- Arg or result kinds to assign
-       -> ([MagicId],  -- Register assignment in same order
-                               -- for *initial segment of* input list
-           [PrimRep])-- leftover kinds
-
-assignRegs regs_in_use kinds
- = assign_reg kinds [] (mkRegTbl regs_in_use)
-
-assignAllRegs regs_in_use kinds
- = assign_reg kinds [] (mkRegTbl_allRegs regs_in_use)
-
-assign_reg 
-       :: [PrimRep]              -- arg kinds being scrutinized
-       -> [MagicId]              -- accum. regs assigned so far (reversed)
-       -> AvailRegs              -- regs still avail: Vanilla, Float, Double, longs
-       -> ([MagicId], [PrimRep])
-
-assign_reg (VoidRep:ks) acc supply
-       = assign_reg ks (VoidReg:acc) supply 
-       -- one VoidReg is enough for everybody!
-
-assign_reg (FloatRep:ks) acc (vanilla_rs, f:float_rs, double_rs, long_rs)
-       = assign_reg ks (FloatReg (iUnbox f):acc) 
-                        (vanilla_rs, float_rs, double_rs, long_rs)
-
-assign_reg (DoubleRep:ks) acc (vanilla_rs, float_rs, d:double_rs, long_rs)
-       = assign_reg ks (DoubleReg (iUnbox d):acc) 
-                        (vanilla_rs, float_rs, double_rs, long_rs)
-
-assign_reg (Word64Rep:ks) acc (vanilla_rs, float_rs, double_rs, u:long_rs)
-       = assign_reg ks (LongReg Word64Rep (iUnbox u):acc) 
-                        (vanilla_rs, float_rs, double_rs, long_rs)
-
-assign_reg (Int64Rep:ks) acc (vanilla_rs, float_rs, double_rs, l:long_rs)
-       = assign_reg ks (LongReg Int64Rep (iUnbox l):acc) 
-                        (vanilla_rs, float_rs, double_rs, long_rs)
-
-assign_reg (k:ks) acc (v:vanilla_rs, float_rs, double_rs, long_rs)
-       | not (isFloatingRep k || is64BitRep k)
-       = assign_reg ks (VanillaReg k (iUnbox v):acc) 
-                        (vanilla_rs, float_rs, double_rs, long_rs)
-
--- The catch-all.  It can happen because either
---     (a) we've assigned all the regs so leftover_ks is []
---  (b) we couldn't find a spare register in the appropriate supply
---  or, I suppose,
---  (c) we came across a Kind we couldn't handle (this one shouldn't happen)
-assign_reg leftover_ks acc _ = (reverse acc, leftover_ks)
-
-\end{code}
-
-Register supplies.  Vanilla registers can contain pointers, Ints, Chars.
-Floats and doubles have separate register supplies.
-
-We take these register supplies from the *real* registers, i.e. those
-that are guaranteed to map to machine registers.
-
-\begin{code}
-useVanillaRegs | opt_Unregisterised = 0
-              | otherwise          = mAX_Real_Vanilla_REG
-useFloatRegs   | opt_Unregisterised = 0
-              | otherwise          = mAX_Real_Float_REG
-useDoubleRegs  | opt_Unregisterised = 0
-              | otherwise          = mAX_Real_Double_REG
-useLongRegs    | opt_Unregisterised = 0
-              | otherwise          = mAX_Real_Long_REG
-
-vanillaRegNos, floatRegNos, doubleRegNos, longRegNos :: [Int]
-vanillaRegNos   = regList useVanillaRegs
-floatRegNos     = regList useFloatRegs
-doubleRegNos    = regList useDoubleRegs
-longRegNos       = regList useLongRegs
-
-allVanillaRegNos, allFloatRegNos, allDoubleRegNos, allLongRegNos :: [Int]
-allVanillaRegNos = regList mAX_Vanilla_REG
-allFloatRegNos  = regList mAX_Float_REG
-allDoubleRegNos         = regList mAX_Double_REG
-allLongRegNos   = regList mAX_Long_REG
-
-regList 0 = []
-regList n = [1 .. n]
-
-type AvailRegs = ( [Int]   -- available vanilla regs.
-                , [Int]   -- floats
-                , [Int]   -- doubles
-                , [Int]   -- longs (int64 and word64)
-                )
-
-mkRegTbl :: [MagicId] -> AvailRegs
-mkRegTbl regs_in_use
-  = mkRegTbl' regs_in_use vanillaRegNos floatRegNos doubleRegNos longRegNos
-
-mkRegTbl_allRegs :: [MagicId] -> AvailRegs
-mkRegTbl_allRegs regs_in_use
-  = mkRegTbl' regs_in_use allVanillaRegNos allFloatRegNos allDoubleRegNos allLongRegNos
-
-mkRegTbl' regs_in_use vanillas floats doubles longs
-  = (ok_vanilla, ok_float, ok_double, ok_long)
-  where
-    ok_vanilla = mapCatMaybes (select (VanillaReg VoidRep)) vanillas
-    ok_float   = mapCatMaybes (select FloatReg)                    floats
-    ok_double  = mapCatMaybes (select DoubleReg)           doubles
-    ok_long    = mapCatMaybes (select (LongReg Int64Rep))   longs   
-                                   -- rep isn't looked at, hence we can use any old rep.
-
-    select :: (FastInt -> MagicId) -> Int{-cand-} -> Maybe Int
-       -- one we've unboxed the Int, we make a MagicId
-       -- and see if it is already in use; if not, return its number.
-
-    select mk_reg_fun cand
-      = let
-           reg = mk_reg_fun (iUnbox cand)
-       in
-       if reg `not_elem` regs_in_use
-       then Just cand
-       else Nothing
-      where
-       not_elem = isn'tIn "mkRegTbl"
-\end{code}
index 4b1b414..206dcc2 100644 (file)
@@ -1,7 +1,7 @@
 %
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
-% $Id: CgStackery.lhs,v 1.24 2003/11/17 14:42:47 simonmar Exp $
+% $Id: CgStackery.lhs,v 1.25 2004/08/13 13:06:12 simonmar Exp $
 %
 \section[CgStackery]{Stack management functions}
 
@@ -10,33 +10,92 @@ Stack-twiddling operations, which are pretty low-down and grimy.
 
 \begin{code}
 module CgStackery (
+       spRel, getVirtSp, getRealSp, setRealSp,
+       setRealAndVirtualSp, getSpRelOffset,
+
        allocPrimStack, allocStackTop, deAllocStackTop,
        adjustStackHW, getFinalStackHW, 
        setStackFrame, getStackFrame,
        mkVirtStkOffsets, mkStkAmodes,
-       freeStackSlots, dataStackSlots,
-       updateFrameSize,
-       constructSlowCall, slowArgs,
+       freeStackSlots, 
+       pushUpdateFrame, emitPushUpdateFrame,
     ) where
 
 #include "HsVersions.h"
 
 import CgMonad
-import AbsCSyn
-import CLabel          ( mkRtsApplyInfoLabel, mkRtsApplyEntryLabel )
-
-import CgUsages                ( getRealSp )
-import AbsCUtils       ( mkAbstractCs, getAmodeRep )
-import PrimRep
-import CmdLineOpts     ( opt_SccProfilingOn, opt_GranMacros )
+import CgUtils         ( cmmOffsetB, cmmRegOffW )
+import CgProf          ( initUpdFrameProf )
+import SMRep
+import Cmm
+import CmmUtils                ( CmmStmts, mkLblExpr )
+import CLabel          ( mkUpdInfoLabel )
 import Constants
 import Util            ( sortLt )
 import FastString      ( LitString )
-import Panic
-       
-import TRACE           ( trace )
+import OrdList         ( toOL )
+import Outputable
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+\subsection[CgUsages-stackery]{Monad things for fiddling with stack usage}
+%*                                                                     *
+%************************************************************************
+
+spRel is a little function that abstracts the stack direction.  Note that most
+of the code generator is dependent on the stack direction anyway, so
+changing this on its own spells certain doom.  ToDo: remove?
+
+       THIS IS DIRECTION SENSITIVE!
+
+Stack grows down, positive virtual offsets correspond to negative
+additions to the stack pointer.
+
+\begin{code}
+spRel :: VirtualSpOffset       -- virtual offset of Sp
+      -> VirtualSpOffset       -- virtual offset of The Thing
+      -> WordOff               -- integer offset
+spRel sp off = sp - off
+\end{code}
+
+@setRealAndVirtualSp@ sets into the environment the offsets of the
+current position of the real and virtual stack pointers in the current
+stack frame.  The high-water mark is set too.  It generates no code.
+It is used to initialise things at the beginning of a closure body.
+
+\begin{code}
+setRealAndVirtualSp :: VirtualSpOffset         -- New real Sp
+                    -> Code
+
+setRealAndVirtualSp new_sp 
+  = do { stk_usg <- getStkUsage
+       ; setStkUsage (stk_usg {virtSp = new_sp, 
+                               realSp = new_sp, 
+                               hwSp   = new_sp}) }
+
+getVirtSp :: FCode VirtualSpOffset
+getVirtSp
+  = do { stk_usg <- getStkUsage
+       ; return (virtSp stk_usg) }
+
+getRealSp :: FCode VirtualSpOffset
+getRealSp
+  = do { stk_usg <- getStkUsage
+       ; return (realSp stk_usg) }
+
+setRealSp :: VirtualSpOffset -> Code
+setRealSp new_real_sp
+  = do { stk_usg <- getStkUsage
+       ; setStkUsage (stk_usg {realSp = new_real_sp}) }
+
+getSpRelOffset :: VirtualSpOffset -> FCode CmmExpr
+getSpRelOffset virtual_offset
+  = do { real_sp <- getRealSp
+       ; return (cmmRegOffW spReg (spRel real_sp virtual_offset)) }
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
 \subsection[CgStackery-layout]{Laying out a stack frame}
@@ -50,24 +109,22 @@ increase towards the top of stack).
 \begin{code}
 mkVirtStkOffsets
          :: VirtualSpOffset    -- Offset of the last allocated thing
-         -> (a -> PrimRep)     -- to be able to grab kinds
-         -> [a]                        -- things to make offsets for
+         -> [(CgRep,a)]                -- things to make offsets for
          -> (VirtualSpOffset,          -- OUTPUTS: Topmost allocated word
-             [(a, VirtualSpOffset)])   -- things with offsets
+             [(a, VirtualSpOffset)])   -- things with offsets (voids filtered out)
 
-mkVirtStkOffsets init_Sp_offset kind_fun things
+mkVirtStkOffsets init_Sp_offset things
     = loop init_Sp_offset [] (reverse things)
   where
     loop offset offs [] = (offset,offs)
-    loop offset offs (t:things) =
-            let
-                size = getPrimRepSize (kind_fun t)
-                thing_slot = offset + size
-            in
-            loop thing_slot ((t,thing_slot):offs) things
-    -- offset of thing is offset+size, because we're growing the stack
-    -- *downwards* as the offsets increase.
-
+    loop offset offs ((VoidArg,t):things) = loop offset offs things
+       -- ignore Void arguments
+    loop offset offs ((rep,t):things)
+       = loop thing_slot ((t,thing_slot):offs) things
+       where
+         thing_slot = offset + cgRepSizeW rep
+           -- offset of thing is offset+size, because we're 
+           -- growing the stack *downwards* as the offsets increase.
 
 -- | 'mkStkAmodes' is a higher-level version of
 -- 'mkVirtStkOffsets'.  It starts from the tail-call locations.
@@ -77,87 +134,17 @@ mkVirtStkOffsets init_Sp_offset kind_fun things
 
 mkStkAmodes 
        :: VirtualSpOffset          -- Tail call positions
-       -> [CAddrMode]              -- things to make offsets for
+       -> [(CgRep,CmmExpr)]        -- things to make offsets for
        -> FCode (VirtualSpOffset,  -- OUTPUTS: Topmost allocated word
-                 AbstractC)        -- Assignments to appropriate stk slots
+                 CmmStmts)         -- Assignments to appropriate stk slots
 
 mkStkAmodes tail_Sp things
-  = getRealSp `thenFC` \ realSp ->
-    let
-      (last_Sp_offset, offsets) = mkVirtStkOffsets tail_Sp getAmodeRep things
-
-      abs_cs =
-         [ CAssign (CVal (spRel realSp offset) (getAmodeRep thing)) thing
-         | (thing, offset) <- offsets
-         ]
-    in
-    returnFC (last_Sp_offset, mkAbstractCs abs_cs)
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{Pushing the arguments for a slow call}
-%*                                                                     *
-%************************************************************************
-
-For a slow call, we must take a bunch of arguments and intersperse
-some stg_ap_<pattern>_ret_info return addresses.
-
-\begin{code}
-constructSlowCall :: [CAddrMode] -> (CAddrMode, [CAddrMode])
-   -- don't forget the zero case
-constructSlowCall [] = (CLbl stg_ap_0 CodePtrRep , []) 
-constructSlowCall amodes = 
-  -- traceSlowCall amodes $    
-  (CLbl lbl CodePtrRep, these ++ slowArgs rest)
-  where (tag, these, rest) = matchSlowPattern amodes
-       lbl = mkRtsApplyEntryLabel tag
-
-stg_ap_0 = mkRtsApplyEntryLabel SLIT("0")
-
--- | 'slowArgs' takes a list of function arguments and prepares them for
--- pushing on the stack for "extra" arguments to a function which requires
--- fewer arguments than we currently have.
-slowArgs :: [CAddrMode] -> [CAddrMode]
-slowArgs [] = []
-slowArgs amodes = CLbl lbl RetRep : args ++ slowArgs rest
-  where        (tag, args, rest) = matchSlowPattern amodes
-       lbl = mkRtsApplyInfoLabel tag
-  
-matchSlowPattern :: [CAddrMode] -> (LitString, [CAddrMode], [CAddrMode])
-matchSlowPattern amodes = (tag, these, rest)
-  where reps = map getAmodeRep amodes
-        (tag, n) = findMatch (map primRepToArgRep reps)
-       (these, rest) = splitAt n amodes
-
--- These cases were found to cover about 99% of all slow calls:
-findMatch (RepP: RepP: RepP: RepP: RepP: RepP: RepP: _) = (SLIT("ppppppp"), 7)
-findMatch (RepP: RepP: RepP: RepP: RepP: RepP: _)       = (SLIT("pppppp"), 6)
-findMatch (RepP: RepP: RepP: RepP: RepP: _)            = (SLIT("ppppp"), 5)
-findMatch (RepP: RepP: RepP: RepP: _)                  = (SLIT("pppp"), 4)
-findMatch (RepP: RepP: RepP: _)                        = (SLIT("ppp"), 3)
-findMatch (RepP: RepP: RepV: _)                        = (SLIT("ppv"), 3)
-findMatch (RepP: RepP: _)                              = (SLIT("pp"), 2)
-findMatch (RepP: RepV: _)                              = (SLIT("pv"), 2)
-findMatch (RepP: _)                                    = (SLIT("p"), 1)
-findMatch (RepV: _)                                    = (SLIT("v"), 1)
-findMatch (RepN: _)                                    = (SLIT("n"), 1)
-findMatch (RepF: _)                                    = (SLIT("f"), 1)
-findMatch (RepD: _)                                    = (SLIT("d"), 1)
-findMatch (RepL: _)                                    = (SLIT("l"), 1)
-findMatch _  = panic "CgStackery.findMatch"
-
-#ifdef DEBUG
-primRepChar p | isFollowableRep p     = 'p'
-primRepChar VoidRep                   = 'v'
-primRepChar FloatRep                  = 'f'
-primRepChar DoubleRep                 = 'd'
-primRepChar p | getPrimRepSize p == 1 = 'n'
-primRepChar p | is64BitRep p          = 'l'
-
-traceSlowCall amodes and_then 
- = trace ("call: " ++ map primRepChar (map getAmodeRep amodes)) and_then
-#endif
+  = do { rSp <- getRealSp
+       ; let (last_Sp_offset, offsets) = mkVirtStkOffsets tail_Sp things
+             abs_cs = [ CmmStore (cmmRegOffW spReg (spRel rSp offset)) amode
+                      | (amode, offset) <- offsets
+                      ]
+       ; returnFC (last_Sp_offset, toOL abs_cs) }
 \end{code}
 
 %************************************************************************
@@ -169,108 +156,150 @@ traceSlowCall amodes and_then
 Allocate a virtual offset for something.
 
 \begin{code}
-allocPrimStack :: Int -> FCode VirtualSpOffset
-allocPrimStack size = do
-       ((virt_sp, frame, free_stk, real_sp, hw_sp),h_usage) <- getUsage
-       let push_virt_sp = virt_sp + size
-       let (chosen_slot, new_stk_usage) = 
-               case find_block free_stk of
-                  Nothing -> (push_virt_sp, 
-                                (push_virt_sp, frame, free_stk, real_sp,
-                                 hw_sp `max` push_virt_sp))
+allocPrimStack :: CgRep -> FCode VirtualSpOffset
+allocPrimStack rep
+  = do { stk_usg <- getStkUsage
+       ; let free_stk = freeStk stk_usg
+       ; case find_block free_stk of
+            Nothing -> do 
+               { let push_virt_sp = virtSp stk_usg + size
+               ; setStkUsage (stk_usg { virtSp = push_virt_sp,
+                                        hwSp   = hwSp stk_usg `max` push_virt_sp })
                                                -- Adjust high water mark
-                  Just slot -> (slot, 
-                                 (virt_sp, frame, 
-                                  delete_block free_stk slot, 
-                                  real_sp, hw_sp))
-       setUsage (new_stk_usage, h_usage)
-       return chosen_slot
-       
-       where
-               -- find_block looks for a contiguous chunk of free slots
-               find_block :: [(VirtualSpOffset,Slot)] -> Maybe VirtualSpOffset
-               find_block [] = Nothing
-               find_block ((off,free):slots)
-                       | take size ((off,free):slots) == 
-                         zip [off..top_slot] (repeat Free) = Just top_slot
-                       | otherwise                                = find_block slots
-                               -- The stack grows downwards, with increasing virtual offsets.
-                               -- Therefore, the address of a multi-word object is the *highest*
-                               -- virtual offset it occupies (top_slot below).
-                       where top_slot = off+size-1
-
-               delete_block free_stk slot = [ (s,f) | (s,f) <- free_stk, 
-                                          (s<=slot-size) || (s>slot) ]
-                             -- Retain slots which are not in the range
-                             -- slot-size+1..slot
+               ; return push_virt_sp }
+            Just slot -> do
+               { setStkUsage (stk_usg { freeStk = delete_block free_stk slot }) 
+               ; return slot }
+       }
+  where
+    size :: WordOff
+    size = cgRepSizeW rep
+
+       -- Find_block looks for a contiguous chunk of free slots
+       -- returning the offset of its topmost word
+    find_block :: [VirtualSpOffset] -> Maybe VirtualSpOffset
+    find_block [] = Nothing
+    find_block (slot:slots)
+       | take size (slot:slots) == [slot..top_slot]
+       = Just top_slot
+       | otherwise
+       = find_block slots
+       where   -- The stack grows downwards, with increasing virtual offsets.
+               -- Therefore, the address of a multi-word object is the *highest*
+               -- virtual offset it occupies (top_slot below).
+           top_slot = slot+size-1
+
+    delete_block free_stk slot = [ s | s <- free_stk, 
+                                      (s<=slot-size) || (s>slot) ]
+                     -- Retain slots which are not in the range
+                     -- slot-size+1..slot
 \end{code}
 
 Allocate a chunk ON TOP OF the stack.  
 
-ToDo: should really register this memory as NonPointer stuff in the
-free list.
-
 \begin{code}
-allocStackTop :: Int -> FCode VirtualSpOffset
-allocStackTop size = do
-       ((virt_sp, frame, free_stk, real_sp, hw_sp), h_usage) <- getUsage
-       let push_virt_sp = virt_sp + size
-       let new_stk_usage = (push_virt_sp, frame, free_stk, real_sp, 
-                               hw_sp `max` push_virt_sp)
-       setUsage (new_stk_usage, h_usage)
-       return push_virt_sp
+allocStackTop :: WordOff -> FCode VirtualSpOffset
+allocStackTop size
+  = do { stk_usg <- getStkUsage
+       ; let push_virt_sp = virtSp stk_usg + size
+       ; setStkUsage (stk_usg { virtSp = push_virt_sp,
+                                hwSp   = hwSp stk_usg `max` push_virt_sp })
+       ; return push_virt_sp }
 \end{code}
 
 Pop some words from the current top of stack.  This is used for
 de-allocating the return address in a case alternative.
 
 \begin{code}
-deAllocStackTop :: Int -> FCode VirtualSpOffset
-deAllocStackTop size = do
-       ((virt_sp, frame, free_stk, real_sp, hw_sp), h_usage) <- getUsage
-       let pop_virt_sp = virt_sp - size
-       let new_stk_usage = (pop_virt_sp, frame, free_stk, real_sp, hw_sp)
-       setUsage (new_stk_usage, h_usage)
-       return pop_virt_sp
+deAllocStackTop :: WordOff -> FCode VirtualSpOffset
+deAllocStackTop size
+  = do { stk_usg <- getStkUsage
+       ; let pop_virt_sp = virtSp stk_usg - size
+       ; setStkUsage (stk_usg { virtSp = pop_virt_sp })
+       ; return pop_virt_sp }
 \end{code}
 
 \begin{code}
 adjustStackHW :: VirtualSpOffset -> Code
-adjustStackHW offset = do
-       ((vSp,fTop,fSp,realSp,hwSp), h_usage) <- getUsage
-       setUsage ((vSp, fTop, fSp, realSp, max offset hwSp), h_usage)
+adjustStackHW offset
+  = do { stk_usg <- getStkUsage
+       ; setStkUsage (stk_usg { hwSp = hwSp stk_usg `max` offset }) }
 \end{code}
 
 A knot-tying beast.
 
 \begin{code}
 getFinalStackHW :: (VirtualSpOffset -> Code) -> Code
-getFinalStackHW fcode = do
-       fixC (\hwSp -> do
-               fcode hwSp
-               ((_,_,_,_, hwSp),_) <- getUsage
-               return hwSp)
-       return ()
+getFinalStackHW fcode
+  = do { fixC (\hw_sp -> do
+               { fcode hw_sp
+               ; stk_usg <- getStkUsage
+               ; return (hwSp stk_usg) })
+       ; return () }
 \end{code}
 
 \begin{code}
 setStackFrame :: VirtualSpOffset -> Code
-setStackFrame offset = do
-       ((vSp,_,fSp,realSp,hwSp), h_usage) <- getUsage
-       setUsage ((vSp, offset, fSp, realSp, hwSp), h_usage)
+setStackFrame offset
+  = do { stk_usg <- getStkUsage
+       ; setStkUsage (stk_usg { frameSp = offset }) }
 
 getStackFrame :: FCode VirtualSpOffset
-getStackFrame = do
-       ((vSp,frame,fSp,realSp,hwSp), h_usage) <- getUsage
-       return frame
+getStackFrame
+  = do { stk_usg <- getStkUsage
+       ; return (frameSp stk_usg) }
 \end{code}
 
+
+%********************************************************
+%*                                                     *
+%*             Setting up update frames                *
+%*                                                     *
+%********************************************************
+
+@pushUpdateFrame@ $updatee$ pushes a general update frame which
+points to $updatee$ as the thing to be updated.  It is only used
+when a thunk has just been entered, so the (real) stack pointers
+are guaranteed to be nicely aligned with the top of stack.
+@pushUpdateFrame@ adjusts the virtual and tail stack pointers
+to reflect the frame pushed.
+
 \begin{code}
-updateFrameSize | opt_SccProfilingOn = pROF_UF_SIZE
-               | opt_GranMacros     = trace ("updateFrameSize = " ++ (show gRAN_UF_SIZE))gRAN_UF_SIZE
-               | otherwise          = uF_SIZE
+pushUpdateFrame :: CmmExpr -> Code -> Code
+
+pushUpdateFrame updatee code
+  = do {
+#ifdef DEBUG
+         EndOfBlockInfo _ sequel <- getEndOfBlockInfo ;
+         ASSERT(case sequel of { OnStack -> True; _ -> False})
+#endif
+
+         allocStackTop (fixedHdrSize + 
+                          sIZEOF_StgUpdateFrame_NoHdr `quot` wORD_SIZE)
+       ; vsp <- getVirtSp
+       ; setStackFrame vsp
+       ; frame_addr <- getSpRelOffset vsp
+               -- The location of the lowest-address
+               -- word of the update frame itself
+
+       ; setEndOfBlockInfo (EndOfBlockInfo vsp UpdateCode) $
+           do  { emitPushUpdateFrame frame_addr updatee
+               ; code }
+       }
+
+emitPushUpdateFrame :: CmmExpr -> CmmExpr -> Code
+emitPushUpdateFrame frame_addr updatee = do
+       stmtsC [  -- Set the info word
+                 CmmStore frame_addr (mkLblExpr mkUpdInfoLabel)
+               , -- And the updatee
+                 CmmStore (cmmOffsetB frame_addr off_updatee) updatee ]
+       initUpdFrameProf frame_addr
+
+off_updatee :: ByteOff
+off_updatee = fixedHdrSize*wORD_SIZE + oFFSET_StgUpdateFrame_updatee
 \end{code}                     
 
+
 %************************************************************************
 %*                                                                     *
 \subsection[CgStackery-free]{Free stack slots}
@@ -280,50 +309,31 @@ updateFrameSize | opt_SccProfilingOn = pROF_UF_SIZE
 Explicitly free some stack space.
 
 \begin{code}
-addFreeStackSlots :: [VirtualSpOffset] -> Slot -> Code
-addFreeStackSlots extra_free slot = do
-       ((vsp, frame,free, real, hw),heap_usage) <- getUsage
-       let all_free = addFreeSlots free (zip (sortLt (<) extra_free) (repeat slot))
-       let (new_vsp, new_free) = trim vsp all_free
-       let new_usage = ((new_vsp, frame, new_free, real, hw), heap_usage)
-       setUsage new_usage
-
 freeStackSlots :: [VirtualSpOffset] -> Code
-freeStackSlots slots = addFreeStackSlots slots Free
-
-dataStackSlots :: [VirtualSpOffset] -> Code
-dataStackSlots slots = addFreeStackSlots slots NonPointer
-
-addFreeSlots :: [(Int,Slot)] -> [(Int,Slot)] -> [(Int,Slot)]
+freeStackSlots extra_free
+  = do { stk_usg <- getStkUsage
+       ; let all_free = addFreeSlots (freeStk stk_usg) (sortLt (<) extra_free)
+       ; let (new_vsp, new_free) = trim (virtSp stk_usg) all_free
+       ; setStkUsage (stk_usg { virtSp = new_vsp, freeStk = new_free }) }
+
+addFreeSlots :: [VirtualSpOffset] -> [VirtualSpOffset] -> [VirtualSpOffset]
+-- Merge the two, assuming both are in increasing order
 addFreeSlots cs [] = cs
 addFreeSlots [] ns = ns
-addFreeSlots ((c,s):cs) ((n,s'):ns)
- = if c < n then
-       (c,s) : addFreeSlots cs ((n,s'):ns)
-   else if c > n then
-       (n,s') : addFreeSlots ((c,s):cs) ns
-   else if s /= s' then -- c == n
-       (c,s') : addFreeSlots cs ns
-   else
-       panic ("addFreeSlots: equal slots: " ++ show (c:map fst cs)
-                                            ++ show (n:map fst ns))
-
-trim :: Int{-offset-} -> [(Int,Slot)] -> (Int{-offset-}, [(Int,Slot)])
-trim current_sp free_slots
-  = try current_sp free_slots
-  where
-       try csp [] = (csp,[])
-
-       try csp (slot@(off,state):slots) = 
-               if state == Free && null slots' then
-                   if csp' < off then 
-                       (csp', [])
-                   else if csp' == off then
-                       (csp'-1, [])
-                   else 
-                       (csp',[slot])
-               else
-                   (csp', slot:slots')
-               where
-                   (csp',slots') = try csp slots
+addFreeSlots (c:cs) (n:ns)
+  | c < n     = c : addFreeSlots cs (n:ns)
+  | otherwise = n : addFreeSlots (c:cs) ns
+
+trim :: VirtualSpOffset -> [VirtualSpOffset] -> (VirtualSpOffset, [VirtualSpOffset])
+-- Try to trim back the virtual stack pointer, where there is a
+-- continuous bunch of free slots at the end of the free list
+trim vsp [] = (vsp, [])
+trim vsp (slot:slots)
+  = case trim vsp slots of
+      (vsp', []) 
+       | vsp' < slot  -> pprTrace "trim: strange" (ppr vsp <+> ppr (slot:slots))
+                         (vsp',   [])
+       | vsp' == slot -> (vsp'-1, [])
+       | otherwise    -> (vsp',   [slot])
+      (vsp', slots')   -> (vsp',   slot:slots')
 \end{code}
index 9d5118a..982891b 100644 (file)
@@ -1,7 +1,7 @@
 %
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
-% $Id: CgTailCall.lhs,v 1.38 2003/06/02 13:27:34 simonpj Exp $
+% $Id: CgTailCall.lhs,v 1.39 2004/08/13 13:06:13 simonmar Exp $
 %
 %********************************************************
 %*                                                     *
@@ -13,9 +13,9 @@
 module CgTailCall (
        cgTailCall, performTailCall,
        performReturn, performPrimReturn,
-       mkStaticAlgReturnCode, mkDynamicAlgReturnCode,
+       emitKnownConReturnCode, emitAlgReturnCode,
        returnUnboxedTuple, ccallReturnUnboxedTuple,
-       mkPrimReturnCode,
+       pushUnboxedTuple,
        tailCallPrimOp,
 
        pushReturnAddress
@@ -24,31 +24,31 @@ module CgTailCall (
 #include "HsVersions.h"
 
 import CgMonad
-import CgBindery       ( getArgAmodes, getCAddrMode, getCAddrModeAndInfo )
-import CgRetConv
-import CgStackery
-import CgUsages                ( getSpRelOffset, adjustSpAndHp )
+import CgBindery       ( getArgAmodes, getCgIdInfo, CgIdInfo, maybeLetNoEscape,
+                         idInfoToAmode, cgIdInfoId, cgIdInfoLF,
+                         cgIdInfoArgRep )
+import CgInfoTbls      ( entryCode, emitDirectReturnInstr, dataConTagZ,
+                         emitVectoredReturnInstr, closureInfoPtr )
+import CgCallConv
+import CgStackery      ( setRealSp, mkStkAmodes, adjustStackHW,
+                         getSpRelOffset )
+import CgHeapery       ( setRealHp, getHpRelOffset )
+import CgUtils         ( emitSimultaneously )
+import CgTicky
 import ClosureInfo
-
-import AbsCUtils       ( mkAbstractCs, getAmodeRep )
-import AbsCSyn
-import CLabel          ( mkRtsPrimOpLabel, mkSeqInfoLabel )
-
-import Id              ( Id, idType, idName )
-import DataCon         ( DataCon, dataConTyCon, dataConTag, fIRST_TAG )
-import PrimRep         ( PrimRep(..) )
-import StgSyn          ( StgArg )
+import SMRep           ( CgRep, isVoidArg, separateByPtrFollowness )
+import Cmm     
+import CmmUtils
+import CLabel          ( CLabel, mkRtsPrimOpLabel, mkSeqInfoLabel )
 import Type            ( isUnLiftedType )
-import Name            ( Name )
+import Id              ( Id, idName, idUnique, idType )
+import DataCon         ( DataCon, dataConTyCon )
+import StgSyn          ( StgArg )
 import TyCon            ( TyCon )
 import PrimOp          ( PrimOp )
-import Util            ( zipWithEqual, splitAtList )
-import ListSetOps      ( assocMaybe )
-import PrimRep         ( isFollowableRep )
 import Outputable
-import Panic           ( panic, assertPanic )
 
-import List            ( partition )
+import Monad           ( when )
 
 -----------------------------------------------------------------------------
 -- Tail Calls
@@ -75,339 +75,205 @@ cgTailCall :: Id -> [StgArg] -> Code
 -- Treat unboxed locals exactly like literals (above) except use the addr
 -- mode for the local instead of (CLit lit) in the assignment.
 
--- Case for unboxed returns first:
-cgTailCall fun []
-  | isUnLiftedType (idType fun)
-  = getCAddrMode fun           `thenFC` \ amode ->
-    performPrimReturn (ppr fun) amode
-
--- The general case (@fun@ is boxed):
 cgTailCall fun args
-  = getCAddrModeAndInfo fun            `thenFC` \ (fun', fun_amode, lf_info) ->
-    getArgAmodes args                  `thenFC` \ arg_amodes ->
-    performTailCall fun' fun_amode lf_info arg_amodes AbsCNop
-
+  = do { fun_info <- getCgIdInfo fun
+
+       ; if isUnLiftedType (idType fun)
+         then  -- Primitive return
+               ASSERT( null args )
+           do  { fun_amode <- idInfoToAmode fun_info
+               ; performPrimReturn (cgIdInfoArgRep fun_info) fun_amode } 
+
+         else -- Normal case, fun is boxed
+           do  { arg_amodes <- getArgAmodes args
+               ; performTailCall fun_info arg_amodes noStmts }
+       }
+               
 
 -- -----------------------------------------------------------------------------
 -- The guts of a tail-call
 
 performTailCall 
-       :: Id           -- function
-       -> CAddrMode    -- function amode
-       -> LambdaFormInfo
-       -> [CAddrMode]
-       -> AbstractC    -- Pending simultaneous assignments
-                       -- *** GUARANTEED to contain only stack assignments.
+       :: CgIdInfo             -- The function
+       -> [(CgRep,CmmExpr)]    -- Args
+       -> CmmStmts             -- Pending simultaneous assignments
+                               -- *** GUARANTEED to contain only stack assignments.
        -> Code
 
-performTailCall fun fun_amode lf_info arg_amodes pending_assts =
-    nodeMustPointToIt lf_info          `thenFC` \ node_points ->
-    let
-       -- assign to node if necessary
-       node_asst
-          | node_points = CAssign (CReg node) fun_amode
-          | otherwise   = AbsCNop
-    in
-  
-    getEndOfBlockInfo `thenFC` \ eob@(EndOfBlockInfo args_sp sequel) ->        
-
-    let
-       -- set up for a let-no-escape if necessary
-       join_sp = case fun_amode of
-                       CJoinPoint sp -> sp
-                       other         -> args_sp
-    in
-
-    -- decide how to code the tail-call: which registers assignments to make,
-    -- what args to push on the stack, and how to make the jump
-    constructTailCall (idName fun) lf_info arg_amodes join_sp
-       node_points fun_amode sequel 
-               `thenFC` \ (final_sp, arg_assts, jump_code) ->
-
-    let sim_assts = mkAbstractCs [node_asst,
-                                 pending_assts,
-                                 arg_assts]
-
-       is_lne = case fun_amode of { CJoinPoint _ -> True; _ -> False }
-    in
-
-    doFinalJump final_sp sim_assts is_lne (const jump_code)
-
-
--- Figure out how to do a particular tail-call.
-
-constructTailCall
-       :: Name
-       -> LambdaFormInfo
-       -> [CAddrMode]
-       -> VirtualSpOffset              -- Sp at which to make the call
-       -> Bool                         -- node points to the fun closure?
-       -> CAddrMode                    -- addressing mode of the function
-       -> Sequel                       -- the sequel, in case we need it
-       -> FCode (
-               VirtualSpOffset,        -- Sp after pushing the args
-               AbstractC,              -- assignments
-               Code                    -- code to do the jump
-          )
-               
-constructTailCall name lf_info arg_amodes sp node_points fun_amode sequel =
-
-    getEntryConvention name lf_info (map getAmodeRep arg_amodes)
-               `thenFC` \ entry_conv ->
-
-    case entry_conv of
-       EnterIt -> returnFC (sp, AbsCNop, code)
-         where code = profCtrC FSLIT("TICK_ENT_VIA_NODE") [] `thenC`
-                      absC (CJump (CMacroExpr CodePtrRep ENTRY_CODE 
-                               [CVal (nodeRel 0) DataPtrRep]))
-
-       -- A function, but we have zero arguments.  It is already in WHNF,
-       -- so we can just return it.
-       ReturnIt -> returnFC (sp, asst, code)
-         where -- if node doesn't already point to the closure, we have to
-               -- load it up.
-               asst | node_points = AbsCNop
-                    | otherwise   = CAssign (CReg node) fun_amode
-
-               code = sequelToAmode sequel     `thenFC` \ dest_amode ->
-                      absC (CReturn dest_amode DirectReturn)
-
-       JumpToIt lbl -> returnFC (sp, AbsCNop, code)
-         where code = absC (CJump (CLbl lbl CodePtrRep))
-
-       -- a slow function call via the RTS apply routines
-       SlowCall -> 
-               let (apply_fn, new_amodes) = constructSlowCall arg_amodes
-
-                       -- if node doesn't already point to the closure, 
-                       -- we have to load it up.
-                   node_asst | node_points = AbsCNop
-                             | otherwise   = CAssign (CReg node) fun_amode
-               in
-
-               -- Fill in all the arguments on the stack
-               mkStkAmodes sp new_amodes `thenFC` 
-                       \ (final_sp, stk_assts) ->
-
-               returnFC
-                 (final_sp + 1,   -- add one, because the stg_ap functions
-                                  -- expect there to be a free slot on the stk
-                  mkAbstractCs [node_asst, stk_assts],
-                  absC (CJump apply_fn)
-                 )
-
-       -- A direct function call (possibly with some left-over arguments)
-       DirectEntry lbl arity regs
-
-          -- A let-no-escape is slightly different, because we
+performTailCall fun_info arg_amodes pending_assts
+  | Just join_sp <- maybeLetNoEscape fun_info
+  =       -- A let-no-escape is slightly different, because we
           -- arrange the stack arguments into pointers and non-pointers
           -- to make the heap check easier.  The tail-call sequence
           -- is very similar to returning an unboxed tuple, so we
           -- share some code.
-          | is_let_no_escape ->
-           pushUnboxedTuple sp arg_amodes   `thenFC` \ (final_sp, assts) ->
-           returnFC (final_sp, assts, absC (CJump (CLbl lbl CodePtrRep)))
-
-
-          -- A normal fast call
-          | otherwise ->
-          let
-               -- first chunk of args go in registers
-               (reg_arg_amodes, stk_arg_amodes) = 
-                   splitAtList regs arg_amodes
-
-               -- the rest of this function's args go straight on the stack
-               (stk_args, extra_stk_args) = 
-                   splitAt (arity - length regs) stk_arg_amodes
-
-               -- any "extra" arguments are placed in frames on the
-               -- stack after the other arguments.
-               slow_stk_args = slowArgs extra_stk_args
-
-               reg_assts
-                   = mkAbstractCs (zipWithEqual "assign_to_reg2" 
-                                       assign_to_reg regs reg_arg_amodes)
+     do        { (final_sp, arg_assts) <- pushUnboxedTuple join_sp arg_amodes
+       ; emitSimultaneously (pending_assts `plusStmts` arg_assts)
+       ; let lbl = enterReturnPtLabel (idUnique (cgIdInfoId fun_info))
+       ; doFinalJump final_sp True {- Is LNE -} (jumpToLbl lbl) }
+
+  | otherwise
+  = do         { fun_amode <- idInfoToAmode fun_info
+       ; let node_asst = oneStmt (CmmAssign nodeReg fun_amode)
+             opt_node_asst | nodeMustPointToIt lf_info = node_asst
+                           | otherwise                 = noStmts
+       ; EndOfBlockInfo sp _ <- getEndOfBlockInfo
+
+       ; case (getCallMethod fun_name lf_info (length arg_amodes)) of
+
+           -- Node must always point to things we enter
+           EnterIt -> do
+               { emitSimultaneously (node_asst `plusStmts` pending_assts) 
+               ; let target = entryCode (closureInfoPtr (CmmReg nodeReg))
+               ; doFinalJump sp False (stmtC (CmmJump target [])) }
+    
+           -- A function, but we have zero arguments.  It is already in WHNF,
+           -- so we can just return it.  
+           -- As with any return, Node must point to it.
+           ReturnIt -> do
+               { emitSimultaneously (node_asst `plusStmts` pending_assts)
+               ; doFinalJump sp False emitDirectReturnInstr }
+    
+           -- A real constructor.  Don't bother entering it, 
+           -- just do the right sort of return instead.
+           -- As with any return, Node must point to it.
+           ReturnCon con -> do
+               { emitSimultaneously (node_asst `plusStmts` pending_assts)
+               ; doFinalJump sp False (emitKnownConReturnCode con) }
+
+           JumpToIt lbl -> do
+               { emitSimultaneously (opt_node_asst `plusStmts` pending_assts)
+               ; doFinalJump sp False (jumpToLbl lbl) }
+    
+           -- A slow function call via the RTS apply routines
+           -- Node must definitely point to the thing
+           SlowCall -> do 
+               { let (apply_lbl, new_amodes) = constructSlowCall arg_amodes
 
-           in
-           mkStkAmodes sp (stk_args ++ slow_stk_args) `thenFC` 
-                       \ (final_sp, stk_assts) ->
+                   -- Fill in all the arguments on the stack
+               ; (final_sp,stk_assts) <- mkStkAmodes sp new_amodes
+    
+               ; emitSimultaneously (node_asst `plusStmts` stk_assts 
+                                               `plusStmts` pending_assts)
+
+               ; when (not (null arg_amodes)) $ do
+                  { if (isKnownFun lf_info) 
+                       then tickyKnownCallTooFewArgs
+                       else tickyUnknownCall
+                  ; tickySlowCallPat (map fst arg_amodes)
+                 } 
+
+               ; doFinalJump (final_sp + 1)
+                       -- Add one, because the stg_ap functions
+                       -- expect there to be a free slot on the stk
+                     False (jumpToLbl apply_lbl)
+               }
+    
+           -- A direct function call (possibly with some left-over arguments)
+           DirectEntry lbl arity -> do
+               { let
+                    -- The args beyond the arity go straight on the stack
+                    (arity_args, extra_stk_args) = splitAt arity arg_amodes
+     
+                    -- First chunk of args go in registers
+                    (reg_arg_amodes, stk_args) = assignCallRegs arity_args
+     
+                    -- Any "extra" arguments are placed in frames on the
+                    -- stack after the other arguments.
+                    slow_stk_args = slowArgs extra_stk_args
+     
+                    reg_assts = assignToRegs reg_arg_amodes
+
+               ; if null slow_stk_args
+                       then tickyKnownCallExact
+                       else do tickyKnownCallExtraArgs
+                               tickySlowCallPat (map fst extra_stk_args)
+
+               ; (final_sp, stk_assts) <- mkStkAmodes sp 
+                                               (stk_args ++ slow_stk_args)
+
+               ; emitSimultaneously (opt_node_asst `plusStmts` 
+                                     reg_assts     `plusStmts`
+                                     stk_assts     `plusStmts`
+                                     pending_assts)
+
+               ; doFinalJump final_sp False (jumpToLbl lbl) }
+       }
+  where
+    fun_name  = idName (cgIdInfoId fun_info)
+    lf_info   = cgIdInfoLF fun_info
 
-           returnFC
-               (final_sp,
-                mkAbstractCs [reg_assts, stk_assts],
-                absC (CJump (CLbl lbl CodePtrRep))
-               )
 
-       where is_let_no_escape = case fun_amode of
-                                       CJoinPoint _ -> True
-                                       _ -> False
 
 -- -----------------------------------------------------------------------------
 -- The final clean-up before we do a jump at the end of a basic block.
 -- This code is shared by tail-calls and returns.
 
-doFinalJump :: VirtualSpOffset -> AbstractC -> Bool -> (Sequel -> Code) -> Code 
-doFinalJump final_sp sim_assts is_let_no_escape jump_code =
-
-    -- adjust the high-water mark if necessary
-    adjustStackHW final_sp     `thenC`
+doFinalJump :: VirtualSpOffset -> Bool -> Code -> Code 
+doFinalJump final_sp is_let_no_escape jump_code
+  = do { -- Adjust the high-water mark if necessary
+         adjustStackHW final_sp
 
-    -- Do the simultaneous assignments,
-    absC (CSimultaneous sim_assts) `thenC`
-
-       -- push a return address if necessary (after the assignments
+       -- Push a return address if necessary (after the assignments
        -- above, in case we clobber a live stack location)
        --
        -- DONT push the return address when we're about to jump to a
        -- let-no-escape: the final tail call in the let-no-escape
        -- will do this.
-    getEndOfBlockInfo `thenFC` \ eob@(EndOfBlockInfo args_sp sequel) ->
-    (if is_let_no_escape then nopC
-                        else pushReturnAddress eob)    `thenC`
+       ; eob <- getEndOfBlockInfo
+       ; whenC (not is_let_no_escape) (pushReturnAddress eob)
 
-    -- Final adjustment of Sp/Hp
-    adjustSpAndHp final_sp             `thenC`
+           -- Final adjustment of Sp/Hp
+       ; adjustSpAndHp final_sp
 
-    -- and do the jump
-    jump_code sequel
+           -- and do the jump
+       ; jump_code }
 
 -- -----------------------------------------------------------------------------
 -- A general return (just a special case of doFinalJump, above)
 
-performReturn :: AbstractC         -- Simultaneous assignments to perform
-             -> (Sequel -> Code)   -- The code to execute to actually do
-                                   -- the return, given an addressing mode
-                                   -- for the return address
+performReturn :: Code          -- The code to execute to actually do the return
              -> Code
 
-performReturn sim_assts finish_code
-  = getEndOfBlockInfo  `thenFC` \ eob@(EndOfBlockInfo args_sp sequel) ->
-    doFinalJump args_sp sim_assts False{-not a LNE-} finish_code
+performReturn finish_code
+  = do  { EndOfBlockInfo args_sp sequel <- getEndOfBlockInfo
+       ; doFinalJump args_sp False{-not a LNE-} finish_code }
 
 -- -----------------------------------------------------------------------------
 -- Primitive Returns
-
 -- Just load the return value into the right register, and return.
 
-performPrimReturn :: SDoc      -- Just for debugging (sigh)
-                 -> CAddrMode  -- The thing to return
+performPrimReturn :: CgRep -> CmmExpr  -- The thing to return
                  -> Code
-
-performPrimReturn doc amode
-  = let
-       kind = getAmodeRep amode
-       ret_reg = dataReturnConvPrim kind
-
-       assign_possibly = case kind of
-                               VoidRep -> AbsCNop
-                               kind -> (CAssign (CReg ret_reg) amode)
-    in
-    performReturn assign_possibly (mkPrimReturnCode doc)
-
-mkPrimReturnCode :: SDoc               -- Debugging only
-                -> Sequel
-                -> Code
-mkPrimReturnCode doc UpdateCode        = pprPanic "mkPrimReturnCode: Upd" doc
-mkPrimReturnCode doc sequel    = sequelToAmode sequel  `thenFC` \ dest_amode ->
-                                 absC (CReturn dest_amode DirectReturn)
-                                 -- Direct, no vectoring
+performPrimReturn rep amode
+  =  do { whenC (not (isVoidArg rep))
+               (stmtC (CmmAssign ret_reg amode))
+       ; performReturn emitDirectReturnInstr }
+  where
+    ret_reg = dataReturnConvPrim rep
 
 -- -----------------------------------------------------------------------------
 -- Algebraic constructor returns
 
 -- Constructor is built on the heap; Node is set.
--- All that remains is
---     (a) to set TagReg, if necessary
---     (c) to do the right sort of jump.
-
-mkStaticAlgReturnCode :: DataCon       -- The constructor
-                     -> Sequel         -- where to return to
-                     -> Code
-
-mkStaticAlgReturnCode con sequel
-  =    -- Generate profiling code if necessary
-    (case return_convention of
-       VectoredReturn sz -> profCtrC FSLIT("TICK_VEC_RETURN") [mkIntCLit sz]
-       other             -> nopC
-    )                                  `thenC`
-
-       -- Set tag if necessary
-       -- This is done by a macro, because if we are short of registers
-       -- we don't set TagReg; instead the continuation gets the tag
-       -- by indexing off the info ptr
-    (case return_convention of
-
-       UnvectoredReturn no_of_constrs
-        | no_of_constrs > 1
-               -> absC (CMacroStmt SET_TAG [mkIntCLit zero_indexed_tag])
-
-       other   -> nopC
-    )                                  `thenC`
-
-       -- Generate the right jump or return
-    (case sequel of
-       CaseAlts _ (Just (alts, _)) False -> -- Ho! We know the constructor so
-                                       -- we can go right to the alternative
-
-               case assocMaybe alts tag of
-                  Just (alt_absC, join_lbl) -> 
-                       absC (CJump (CLbl join_lbl CodePtrRep))
-                  Nothing -> panic "mkStaticAlgReturnCode: default"
-                               -- The Nothing case should never happen; 
-                               -- it's the subject of a wad of special-case 
-                               -- code in cgReturnCon
-
-       other ->        -- OnStack, or (CaseAlts ret_amode Nothing),
-                       -- or UpdateCode.
-                   sequelToAmode sequel        `thenFC` \ ret_amode ->
-                   absC (CReturn ret_amode return_info)
-    )
+-- All that remains is to do the right sort of jump.
 
-  where
-    tag                      = dataConTag   con
-    tycon            = dataConTyCon con
-    return_convention = ctrlReturnConvAlg tycon
-    zero_indexed_tag  = tag - fIRST_TAG              -- Adjust tag to be zero-indexed
-                                             -- cf AbsCUtils.mkAlgAltsCSwitch
-
-    return_info = 
-       case return_convention of
-               UnvectoredReturn _ -> DirectReturn
-               VectoredReturn _   -> StaticVectoredReturn zero_indexed_tag
-
-
--- -----------------------------------------------------------------------------
--- Returning an enumerated type from a PrimOp
+emitKnownConReturnCode :: DataCon -> Code
+emitKnownConReturnCode con
+  = emitAlgReturnCode (dataConTyCon con)
+                     (CmmLit (mkIntCLit (dataConTagZ con)))
+                       -- emitAlgReturnCode requires zero-indexed tag
 
--- This function is used by PrimOps that return enumerated types (i.e.
+emitAlgReturnCode :: TyCon -> CmmExpr -> Code
+-- emitAlgReturnCode is used both by emitKnownConReturnCode,
+-- and by by PrimOps that return enumerated types (i.e.
 -- all the comparison operators).
-
-mkDynamicAlgReturnCode :: TyCon -> CAddrMode -> Sequel -> Code
-
-mkDynamicAlgReturnCode tycon dyn_tag sequel
-  = case ctrlReturnConvAlg tycon of
-       VectoredReturn sz ->
-
-               profCtrC FSLIT("TICK_VEC_RETURN") [mkIntCLit sz] `thenC`
-               sequelToAmode sequel            `thenFC` \ ret_addr ->
-               absC (CReturn ret_addr (DynamicVectoredReturn dyn_tag))
-
-       UnvectoredReturn no_of_constrs ->
-
-               -- Set tag if necessary
-               -- This is done by a macro, because if we are short of registers
-               -- we don't set TagReg; instead the continuation gets the tag
-               -- by indexing off the info ptr
-               (if no_of_constrs > 1 then
-                       absC (CMacroStmt SET_TAG [dyn_tag])
-               else
-                       nopC
-               )                       `thenC`
-
-
-               sequelToAmode sequel            `thenFC` \ ret_addr ->
-               -- Generate the right jump or return
-               absC (CReturn ret_addr DirectReturn)
+emitAlgReturnCode tycon tag
+ =  do { case ctrlReturnConvAlg tycon of
+           VectoredReturn fam_sz -> do { tickyVectoredReturn fam_sz
+                                       ; emitVectoredReturnInstr tag }
+           UnvectoredReturn _    -> emitDirectReturnInstr 
+       }
 
 
 -- ---------------------------------------------------------------------------
@@ -424,59 +290,37 @@ mkDynamicAlgReturnCode tycon dyn_tag sequel
 --     let-no-escape functions, because they also can't be partially
 --     applied.
 
-returnUnboxedTuple :: [CAddrMode] -> Code
-returnUnboxedTuple amodes =
-    getEndOfBlockInfo  `thenFC` \ eob@(EndOfBlockInfo args_sp sequel) ->
-
-    profCtrC FSLIT("TICK_RET_UNBOXED_TUP") [mkIntCLit (length amodes)] `thenC`
-
-    pushUnboxedTuple args_sp amodes `thenFC` \ (final_sp, assts) ->
-    doFinalJump final_sp assts False{-not a LNE-} mkUnboxedTupleReturnCode
-
-
-pushUnboxedTuple
-       :: VirtualSpOffset              -- Sp at which to start pushing
-       -> [CAddrMode]                  -- amodes of the components
-       -> FCode (VirtualSpOffset,      -- final Sp
-                 AbstractC)            -- assignments (regs+stack)
-
-pushUnboxedTuple sp amodes =
-    let
-        (arg_regs, _leftovers) = assignRegs [] (map getAmodeRep amodes)
-
-       (reg_arg_amodes, stk_arg_amodes) = splitAtList arg_regs amodes
-
-       -- separate the rest of the args into pointers and non-pointers
-       ( ptr_args, nptr_args ) = 
-          partition (isFollowableRep . getAmodeRep) stk_arg_amodes
-
-       reg_arg_assts
-         = mkAbstractCs (zipWithEqual "assign_to_reg2" 
-                               assign_to_reg arg_regs reg_arg_amodes)
-    in
-
-    -- push ptrs, then nonptrs, on the stack
-    mkStkAmodes sp ptr_args       `thenFC` \ (ptr_sp,  ptr_assts) ->
-    mkStkAmodes ptr_sp  nptr_args `thenFC` \ (final_sp, nptr_assts) ->
+returnUnboxedTuple :: [(CgRep, CmmExpr)] -> Code
+returnUnboxedTuple amodes
+  = do         { eob@(EndOfBlockInfo args_sp sequel) <- getEndOfBlockInfo
+       ; tickyUnboxedTupleReturn (length amodes)
+       ; (final_sp, assts) <- pushUnboxedTuple args_sp amodes
+       ; emitSimultaneously assts
+       ; doFinalJump final_sp False{-not a LNE-} emitDirectReturnInstr }
+
+pushUnboxedTuple :: VirtualSpOffset            -- Sp at which to start pushing
+                -> [(CgRep, CmmExpr)]          -- amodes of the components
+                -> FCode (VirtualSpOffset,     -- final Sp
+                          CmmStmts)            -- assignments (regs+stack)
+
+pushUnboxedTuple sp [] 
+  = return (sp, noStmts)
+pushUnboxedTuple sp amodes
+  = do { let   (reg_arg_amodes, stk_arg_amodes) = assignReturnRegs amodes
+       
+               -- separate the rest of the args into pointers and non-pointers
+               (ptr_args, nptr_args) = separateByPtrFollowness stk_arg_amodes
+               reg_arg_assts = assignToRegs reg_arg_amodes
+               
+           -- push ptrs, then nonptrs, on the stack
+       ; (ptr_sp,   ptr_assts)  <- mkStkAmodes sp ptr_args
+       ; (final_sp, nptr_assts) <- mkStkAmodes ptr_sp nptr_args
 
-    returnFC (final_sp, 
-             mkAbstractCs [reg_arg_assts, ptr_assts, nptr_assts])
+       ; returnFC (final_sp,
+                   reg_arg_assts `plusStmts` 
+                   ptr_assts `plusStmts` nptr_assts) }
     
                  
-
-mkUnboxedTupleReturnCode :: Sequel -> Code
-mkUnboxedTupleReturnCode sequel
-    = case sequel of
-       -- can't update with an unboxed tuple!
-       UpdateCode -> panic "mkUnboxedTupleReturnCode"
-
-       CaseAlts _ (Just ([(_,(alt_absC,join_lbl))], _)) False ->
-                       absC (CJump (CLbl join_lbl CodePtrRep))
-
-       other ->        -- OnStack, or (CaseAlts ret_amode something)
-                   sequelToAmode sequel        `thenFC` \ ret_amode ->
-                   absC (CReturn ret_amode DirectReturn)
-
 -- -----------------------------------------------------------------------------
 -- Returning unboxed tuples.  This is mainly to support _ccall_GC_, where
 -- we want to do things in a slightly different order to normal:
@@ -494,44 +338,35 @@ mkUnboxedTupleReturnCode sequel
 -- (in order to avoid pushing it again), so we end up doing a needless
 -- indirect jump (ToDo).
 
-ccallReturnUnboxedTuple :: [CAddrMode] -> Code -> Code
+ccallReturnUnboxedTuple :: [(CgRep, CmmExpr)] -> Code -> Code
 ccallReturnUnboxedTuple amodes before_jump
-  = getEndOfBlockInfo  `thenFC` \ eob@(EndOfBlockInfo args_sp sequel) ->
-
-       -- push a return address if necessary
-    pushReturnAddress eob              `thenC`
-    setEndOfBlockInfo (EndOfBlockInfo args_sp (OnStack args_sp)) (
-
-       -- Adjust Sp/Hp
-    adjustSpAndHp args_sp              `thenC`
+  = do         { eob@(EndOfBlockInfo args_sp _) <- getEndOfBlockInfo
 
-    before_jump                                `thenC`
-  
-    returnUnboxedTuple amodes
-  )
+       -- Push a return address if necessary
+       ; pushReturnAddress eob
+       ; setEndOfBlockInfo (EndOfBlockInfo args_sp OnStack)
+           (do { adjustSpAndHp args_sp
+               ; before_jump
+               ; returnUnboxedTuple amodes })
+    }
 
 -- -----------------------------------------------------------------------------
 -- Calling an out-of-line primop
 
 tailCallPrimOp :: PrimOp -> [StgArg] -> Code
-tailCallPrimOp op args =
-    -- we're going to perform a normal-looking tail call, 
-    -- except that *all* the arguments will be in registers.
-    getArgAmodes args          `thenFC` \ arg_amodes ->
-    let (arg_regs, leftovers) = assignAllRegs [] (map getAmodeRep arg_amodes)
+tailCallPrimOp op args
+ = do  {       -- We're going to perform a normal-looking tail call, 
+               -- except that *all* the arguments will be in registers.
+               -- Hence the ASSERT( null leftovers )
+         arg_amodes <- getArgAmodes args
+       ; let (arg_regs, leftovers) = assignPrimOpCallRegs arg_amodes
+             jump_to_primop = jumpToLbl (mkRtsPrimOpLabel op)
 
-       reg_arg_assts
-         = mkAbstractCs (zipWithEqual "assign_to_reg2" 
-                               assign_to_reg arg_regs arg_amodes)
+       ; ASSERT(null leftovers) -- no stack-resident args
+         emitSimultaneously (assignToRegs arg_regs)
 
-       jump_to_primop = 
-          absC (CJump (CLbl (mkRtsPrimOpLabel op) CodePtrRep))
-    in
-
-    ASSERT(null leftovers) -- no stack-resident args
-
-    getEndOfBlockInfo  `thenFC` \ eob@(EndOfBlockInfo args_sp sequel) ->
-    doFinalJump args_sp reg_arg_assts False{-not a LNE-} (const jump_to_primop)
+       ; EndOfBlockInfo args_sp _ <- getEndOfBlockInfo
+       ; doFinalJump args_sp False{-not a LNE-} jump_to_primop }
 
 -- -----------------------------------------------------------------------------
 -- Return Addresses
@@ -551,23 +386,72 @@ tailCallPrimOp op args =
 
 pushReturnAddress :: EndOfBlockInfo -> Code
 
-pushReturnAddress (EndOfBlockInfo args_sp sequel@(CaseAlts amode _ False)) =
-    getSpRelOffset args_sp                      `thenFC` \ sp_rel ->
-    absC (CAssign (CVal sp_rel RetRep) amode)
+pushReturnAddress (EndOfBlockInfo args_sp sequel@(CaseAlts lbl _ _ False))
+  = do { sp_rel <- getSpRelOffset args_sp
+       ; stmtC (CmmStore sp_rel (mkLblExpr lbl)) }
 
 -- For a polymorphic case, we have two return addresses to push: the case
 -- return, and stg_seq_frame_info which turns a possible vectored return
 -- into a direct one.
-pushReturnAddress (EndOfBlockInfo args_sp sequel@(CaseAlts amode _ True)) =
-    getSpRelOffset (args_sp-1)                  `thenFC` \ sp_rel ->
-    absC (CAssign (CVal sp_rel RetRep) amode)   `thenC`
-    getSpRelOffset args_sp                      `thenFC` \ sp_rel ->
-    absC (CAssign (CVal sp_rel RetRep) (CLbl mkSeqInfoLabel RetRep))
+pushReturnAddress (EndOfBlockInfo args_sp sequel@(CaseAlts lbl _ _ True))
+  = do { sp_rel <- getSpRelOffset (args_sp-1)
+       ; stmtC (CmmStore sp_rel (mkLblExpr lbl))
+       ; sp_rel <- getSpRelOffset args_sp
+       ; stmtC (CmmStore sp_rel (CmmLit (CmmLabel mkSeqInfoLabel))) }
+
 pushReturnAddress _ = nopC
 
 -- -----------------------------------------------------------------------------
 -- Misc.
 
-assign_to_reg reg_id amode = CAssign (CReg reg_id) amode
+jumpToLbl :: CLabel -> Code
+-- Passes no argument to the destination procedure
+jumpToLbl lbl = stmtC (CmmJump (CmmLit (CmmLabel lbl)) [{- No args -}])
 
+assignToRegs :: [(CmmExpr, GlobalReg)] -> CmmStmts
+assignToRegs reg_args 
+  = mkStmts [ CmmAssign (CmmGlobal reg_id) expr
+           | (expr, reg_id) <- reg_args ] 
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
+\subsection[CgStackery-adjust]{Adjusting the stack pointers}
+%*                                                                     *
+%************************************************************************
+
+This function adjusts the stack and heap pointers just before a tail
+call or return.  The stack pointer is adjusted to its final position
+(i.e. to point to the last argument for a tail call, or the activation
+record for a return).  The heap pointer may be moved backwards, in
+cases where we overallocated at the beginning of the basic block (see
+CgCase.lhs for discussion).
+
+These functions {\em do not} deal with high-water-mark adjustment.
+That's done by functions which allocate stack space.
+
+\begin{code}
+adjustSpAndHp :: VirtualSpOffset       -- New offset for Arg stack ptr
+             -> Code
+adjustSpAndHp newRealSp 
+  = do { -- Adjust stack, if necessary.
+         -- NB: the conditional on the monad-carried realSp
+         --     is out of line (via codeOnly), to avoid a black hole
+       ; new_sp <- getSpRelOffset newRealSp
+       ; checkedAbsC (CmmAssign spReg new_sp)  -- Will generate no code in the case
+       ; setRealSp newRealSp                   -- where realSp==newRealSp
+
+         -- Adjust heap.  The virtual heap pointer may be less than the real Hp
+         -- because the latter was advanced to deal with the worst-case branch
+         -- of the code, and we may be in a better-case branch.  In that case,
+         -- move the real Hp *back* and retract some ticky allocation count.
+       ; hp_usg <- getHpUsage
+       ; let rHp = realHp hp_usg
+             vHp = virtHp hp_usg
+       ; new_hp <- getHpRelOffset vHp
+       ; checkedAbsC (CmmAssign hpReg new_hp)  -- Generates nothing when vHp==rHp
+       ; tickyAllocHeap (vHp - rHp)            -- ...ditto
+       ; setRealHp vHp
+       }
 \end{code}
diff --git a/ghc/compiler/codeGen/CgTicky.hs b/ghc/compiler/codeGen/CgTicky.hs
new file mode 100644 (file)
index 0000000..19dbc43
--- /dev/null
@@ -0,0 +1,370 @@
+-----------------------------------------------------------------------------
+--
+-- Code generation for ticky-ticky profiling
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+module CgTicky (
+       emitTickyCounter,
+
+       tickyDynAlloc,
+       tickyAllocHeap,
+       tickyAllocPrim,
+       tickyAllocThunk,
+       tickyAllocPAP,
+
+       tickyPushUpdateFrame,
+       tickyUpdateFrameOmitted,
+
+       tickyEnterDynCon,
+       tickyEnterStaticCon,
+       tickyEnterViaNode,
+
+       tickyEnterFun, 
+       tickyEnterThunk,
+
+       tickyUpdateBhCaf,
+       tickyBlackHole,
+       tickyUnboxedTupleReturn, tickyVectoredReturn,
+       tickyReturnOldCon, tickyReturnNewCon,
+
+       tickyKnownCallTooFewArgs, tickyKnownCallExact, tickyKnownCallExtraArgs,
+       tickyUnknownCall, tickySlowCallPat,
+
+       staticTickyHdr,
+  ) where
+
+#include "HsVersions.h"
+#include "../includes/DerivedConstants.h"
+       -- For REP_xxx constants, which are MachReps
+
+import ClosureInfo     ( ClosureInfo, closureSize, slopSize, closureSMRep,
+                         closureUpdReqd, closureName, isStaticClosure )
+import CgUtils
+import CgMonad
+import SMRep           ( ClosureType(..), smRepClosureType, CgRep )
+
+import Cmm
+import MachOp
+import CmmUtils                ( zeroCLit, mkIntCLit, mkLblExpr, cmmIndexExpr )
+import CLabel          ( CLabel, mkRtsDataLabel, mkRednCountsLabel )
+
+import Name            ( isInternalName )
+import Id              ( Id, idType )
+import CmdLineOpts     ( opt_DoTickyProfiling )
+import BasicTypes      ( Arity )
+import FastString      ( FastString, mkFastString, LitString ) 
+import Constants       -- Lots of field offsets
+import Outputable
+
+-- Turgid imports for showTypeCategory
+import PrelNames
+import TcType          ( Type, isDictTy, tcSplitTyConApp_maybe,
+                         tcSplitFunTy_maybe )
+import TyCon           ( isPrimTyCon, isTupleTyCon, isEnumerationTyCon,
+                         maybeTyConSingleCon )
+import Maybe
+
+-----------------------------------------------------------------------------
+--
+--             Ticky-ticky profiling
+--
+-----------------------------------------------------------------------------
+
+staticTickyHdr :: [CmmLit]
+-- The ticky header words in a static closure
+-- Was SET_STATIC_TICKY_HDR
+staticTickyHdr 
+  | not opt_DoTickyProfiling = []
+  | otherwise               = [zeroCLit]
+
+emitTickyCounter :: ClosureInfo -> [Id] -> Int -> Code
+emitTickyCounter cl_info args on_stk
+  = ifTicky $
+    do { mod_name <- moduleName
+       ; fun_descr_lit <- mkStringCLit (fun_descr mod_name)
+       ; arg_descr_lit <- mkStringCLit arg_descr
+       ; emitDataLits ticky_ctr_label  -- Must match layout of StgEntCounter
+           [ CmmInt 0 I16,
+             CmmInt (fromIntegral (length args)) I16,  -- Arity
+             CmmInt (fromIntegral on_stk) I16,         -- Words passed on stack
+             CmmInt 0 I16,                             -- 2-byte gap
+             fun_descr_lit,
+             arg_descr_lit,
+             zeroCLit,                 -- Entry count
+             zeroCLit,                 -- Allocs
+             zeroCLit                  -- Link
+           ] }
+  where
+    name = closureName cl_info
+    ticky_ctr_label = mkRednCountsLabel name
+    arg_descr = map (showTypeCategory . idType) args
+    fun_descr mod_name = ppr_for_ticky_name mod_name name
+
+-- When printing the name of a thing in a ticky file, we want to
+-- give the module name even for *local* things.   We print
+-- just "x (M)" rather that "M.x" to distinguish them from the global kind.
+ppr_for_ticky_name mod_name name
+  | isInternalName name = showSDocDebug (ppr name <+> (parens (ppr mod_name)))
+  | otherwise          = showSDocDebug (ppr name)
+
+-- -----------------------------------------------------------------------------
+-- Ticky stack frames
+
+tickyPushUpdateFrame    = ifTicky $ bumpTickyCounter SLIT("UPDF_PUSHED_ctr")
+tickyUpdateFrameOmitted = ifTicky $ bumpTickyCounter SLIT("UPDF_OMITTED_ctr")
+
+-- -----------------------------------------------------------------------------
+-- Ticky entries
+
+tickyEnterDynCon      = ifTicky $ bumpTickyCounter SLIT("ENT_DYN_CON_ctr")
+tickyEnterDynThunk    = ifTicky $ bumpTickyCounter SLIT("ENT_DYN_THK_ctr")
+tickyEnterStaticCon   = ifTicky $ bumpTickyCounter SLIT("ENT_STATIC_CON_ctr")
+tickyEnterStaticThunk = ifTicky $ bumpTickyCounter SLIT("ENT_STATIC_THK_ctr")
+tickyEnterViaNode     = ifTicky $ bumpTickyCounter SLIT("ENT_VIA_NODE_ctr")
+
+tickyEnterThunk :: ClosureInfo -> Code
+tickyEnterThunk cl_info
+  | isStaticClosure cl_info = tickyEnterStaticThunk
+  | otherwise              = tickyEnterDynThunk
+
+tickyBlackHole :: Bool{-updatable-} -> Code
+tickyBlackHole updatable
+  = ifTicky (bumpTickyCounter ctr)
+  where
+    ctr | updatable = SLIT("UPD_BH_SINGLE_ENTRY_ctr")
+       | otherwise = SLIT("UPD_BH_UPDATABLE_ctr")
+
+tickyUpdateBhCaf cl_info
+  = ifTicky (bumpTickyCounter ctr)
+  where
+    ctr | closureUpdReqd cl_info = SLIT("UPD_CAF_BH_SINGLE_ENTRY_ctr")
+       | otherwise              = SLIT("UPD_CAF_BH_UPDATABLE_ctr")
+
+tickyEnterFun :: ClosureInfo -> Code
+tickyEnterFun cl_info
+  = ifTicky $ 
+    do         { bumpTickyCounter ctr
+       ; fun_ctr_lbl <- getTickyCtrLabel
+       ; registerTickyCtr fun_ctr_lbl
+       ; bumpTickyCounter' fun_ctr_lbl }
+  where
+    ctr | isStaticClosure cl_info = SLIT("TICK_ENT_STATIC_FUN_DIRECT")
+       | otherwise               = SLIT("TICK_ENT_DYN_FUN_DIRECT")
+
+registerTickyCtr :: CLabel -> Code
+-- Register a ticky counter
+--   if ( ! f_ct.registeredp ) {
+--         f_ct.link = ticky_entry_ctrs;       /* hook this one onto the front of the list */
+--         ticky_entry_ctrs = & (f_ct);        /* mark it as "registered" */
+--         f_ct.registeredp = 1 }
+registerTickyCtr ctr_lbl
+  = emitIf test (stmtsC register_stmts)
+  where
+    test = CmmMachOp (MO_Not I16) 
+           [CmmLoad (CmmLit (cmmLabelOffB ctr_lbl 
+                               oFFSET_StgEntCounter_registeredp)) I16]
+    register_stmts
+      =        [ CmmStore (CmmLit (cmmLabelOffB ctr_lbl oFFSET_StgEntCounter_link))
+                  (CmmLoad ticky_entry_ctrs wordRep)
+       , CmmStore ticky_entry_ctrs (mkLblExpr ctr_lbl)
+       , CmmStore (CmmLit (cmmLabelOffB ctr_lbl 
+                               oFFSET_StgEntCounter_registeredp))
+                  (CmmLit (mkIntCLit 1)) ]
+    ticky_entry_ctrs = mkLblExpr (mkRtsDataLabel SLIT("ticky_entry_ctrs"))
+
+tickyReturnOldCon, tickyReturnNewCon :: Arity -> Code
+tickyReturnOldCon arity 
+  = ifTicky $ do { bumpTickyCounter SLIT("RET_OLD_ctr")
+                ; bumpHistogram SLIT("RET_OLD_hst") arity }
+tickyReturnNewCon arity 
+  | not opt_DoTickyProfiling = nopC
+  | otherwise
+  = ifTicky $ do { bumpTickyCounter SLIT("RET_NEW_ctr")
+                ; bumpHistogram SLIT("RET_NEW_hst") arity }
+
+tickyUnboxedTupleReturn :: Int -> Code
+tickyUnboxedTupleReturn arity
+  = ifTicky $ do { bumpTickyCounter SLIT("RET_UNBOXED_TUP_ctr")
+                ; bumpHistogram SLIT("RET_UNBOXED_TUP_hst") arity }
+
+tickyVectoredReturn :: Int -> Code
+tickyVectoredReturn family_size 
+  = ifTicky $ do { bumpTickyCounter SLIT("VEC_RETURN_ctr")
+                ; bumpHistogram SLIT("RET_VEC_RETURN_hst") family_size }
+
+-- -----------------------------------------------------------------------------
+-- Ticky calls
+
+-- Ticks at a *call site*:
+tickyKnownCallTooFewArgs = ifTicky $ bumpTickyCounter SLIT("KNOWN_CALL_TOO_FEW_ARGS_ctr")
+tickyKnownCallExact = ifTicky $ bumpTickyCounter SLIT("KNOWN_CALL_ctr")
+tickyKnownCallExtraArgs = ifTicky $ bumpTickyCounter SLIT("KNOWN_CALL_EXTRA_ctr")
+tickyUnknownCall = ifTicky $ bumpTickyCounter SLIT("UNKNOWN_CALL_ctr")
+
+-- Tick for the call pattern at slow call site (i.e. in addition to
+-- tickyUnknownCall, tickyKnownCallExtraArgs, etc.)
+tickySlowCallPat :: [CgRep] -> Code
+tickySlowCallPat args = return ()
+{- LATER: (introduces recursive module dependency now).
+  case callPattern args of
+    (str, True)  -> bumpTickyCounter' (mkRtsSlowTickyCtrLabel pat)
+    (str, False) -> bumpTickyCounter  SLIT("TICK_SLOW_CALL_OTHER")
+
+callPattern :: [CgRep] -> (String,Bool)
+callPattern reps 
+  | match == length reps = (chars, True)
+  | otherwise            = (chars, False)
+  where (_,match) = findMatch reps
+       chars     = map argChar reps
+
+argChar VoidArg   = 'v'
+argChar PtrArg    = 'p'
+argChar NonPtrArg = 'n'
+argChar LongArg   = 'l'
+argChar FloatArg  = 'f'
+argChar DoubleArg = 'd'
+-}
+
+-- -----------------------------------------------------------------------------
+-- Ticky allocation
+
+tickyDynAlloc :: ClosureInfo -> Code
+-- Called when doing a dynamic heap allocation
+tickyDynAlloc cl_info
+  = ifTicky $
+    case smRepClosureType (closureSMRep cl_info) of
+       Constr        -> tick_alloc_con
+       ConstrNoCaf   -> tick_alloc_con
+       Fun           -> tick_alloc_fun
+       Thunk         -> tick_alloc_thk
+       ThunkSelector -> tick_alloc_thk
+  where
+       -- will be needed when we fill in stubs
+    cl_size   =        closureSize cl_info
+    slop_size = slopSize cl_info
+
+    tick_alloc_thk 
+       | closureUpdReqd cl_info = tick_alloc_up_thk
+       | otherwise              = tick_alloc_se_thk
+
+    tick_alloc_con = panic "ToDo: tick_alloc"
+    tick_alloc_fun = panic "ToDo: tick_alloc"
+    tick_alloc_up_thk = panic "ToDo: tick_alloc"
+    tick_alloc_se_thk = panic "ToDo: tick_alloc"
+
+tickyAllocPrim :: CmmExpr -> CmmExpr -> CmmExpr -> Code
+tickyAllocPrim hdr goods slop = ifTicky $ panic "ToDo: tickyAllocPrim"
+
+tickyAllocThunk :: CmmExpr -> CmmExpr -> Code
+tickyAllocThunk goods slop = ifTicky $ panic "ToDo: tickyAllocThunk"
+
+tickyAllocPAP :: CmmExpr -> CmmExpr -> Code
+tickyAllocPAP goods slop = ifTicky $ panic "ToDo: tickyAllocPAP"
+
+tickyAllocHeap :: VirtualHpOffset -> Code
+-- Called when doing a heap check [TICK_ALLOC_HEAP]
+tickyAllocHeap hp
+  = ifTicky $
+    do { ticky_ctr <- getTickyCtrLabel
+       ; stmtsC $
+         if hp == 0 then []    -- Inside the stmtC to avoid control
+         else [                -- dependency on the argument
+               -- Bump the allcoation count in the StgEntCounter
+           addToMem REP_StgEntCounter_allocs 
+                       (CmmLit (cmmLabelOffB ticky_ctr 
+                               oFFSET_StgEntCounter_allocs)) hp,
+               -- Bump ALLOC_HEAP_ctr
+           addToMemLbl cLongRep (mkRtsDataLabel SLIT("ALLOC_HEAP_ctr")) 1,
+               -- Bump ALLOC_HEAP_tot
+           addToMemLbl cLongRep (mkRtsDataLabel SLIT("ALLOC_HEAP_tot")) hp] }
+
+-- -----------------------------------------------------------------------------
+-- Ticky utils
+
+ifTicky :: Code -> Code
+ifTicky code
+  | opt_DoTickyProfiling = code
+  | otherwise           = nopC
+
+addToMemLbl :: MachRep -> CLabel -> Int -> CmmStmt
+addToMemLbl rep lbl n = addToMem rep (CmmLit (CmmLabel lbl)) n
+
+-- All the ticky-ticky counters are declared "unsigned long" in C
+bumpTickyCounter :: LitString -> Code
+bumpTickyCounter lbl = bumpTickyCounter' (mkRtsDataLabel lbl)
+
+bumpTickyCounter' :: CLabel -> Code
+bumpTickyCounter' lbl = stmtC (addToMemLbl cLongRep lbl 1)
+
+addToMemLong = addToMem cLongRep
+
+bumpHistogram :: LitString -> Int -> Code
+bumpHistogram lbl n 
+  = bumpHistogramE lbl (CmmLit (CmmInt (fromIntegral n) cLongRep))
+
+bumpHistogramE :: LitString -> CmmExpr -> Code
+bumpHistogramE lbl n 
+  = do  t <- newTemp cLongRep
+       stmtC (CmmAssign t n)
+       emitIf (CmmMachOp (MO_U_Le cLongRep) [CmmReg t, eight]) $
+               stmtC (CmmAssign t eight)
+       stmtC (addToMemLong (cmmIndexExpr cLongRep 
+                               (CmmLit (CmmLabel (mkRtsDataLabel lbl)))
+                               (CmmReg t))
+                           1)
+  where 
+   eight = CmmLit (CmmInt 8 cLongRep)
+
+------------------------------------------------------------------
+-- Showing the "type category" for ticky-ticky profiling
+
+showTypeCategory :: Type -> Char
+  {-   {C,I,F,D}   char, int, float, double
+       T           tuple
+       S           other single-constructor type
+       {c,i,f,d}   unboxed ditto
+       t           *unpacked* tuple
+       s           *unpacked" single-cons...
+
+       v           void#
+       a           primitive array
+
+       E           enumeration type
+       +           dictionary, unless it's a ...
+       L           List
+       >           function
+       M           other (multi-constructor) data-con type
+       .           other type
+       -           reserved for others to mark as "uninteresting"
+    -}
+showTypeCategory ty
+  = if isDictTy ty
+    then '+'
+    else
+      case tcSplitTyConApp_maybe ty of
+       Nothing -> if isJust (tcSplitFunTy_maybe ty)
+                  then '>'
+                  else '.'
+
+       Just (tycon, _) ->
+          let utc = getUnique tycon in
+         if      utc == charDataConKey    then 'C'
+         else if utc == intDataConKey     then 'I'
+         else if utc == floatDataConKey   then 'F'
+         else if utc == doubleDataConKey  then 'D'
+         else if utc == smallIntegerDataConKey ||
+                 utc == largeIntegerDataConKey   then 'J'
+         else if utc == charPrimTyConKey  then 'c'
+         else if (utc == intPrimTyConKey || utc == wordPrimTyConKey
+               || utc == addrPrimTyConKey)                then 'i'
+         else if utc  == floatPrimTyConKey                then 'f'
+         else if utc  == doublePrimTyConKey               then 'd'
+         else if isPrimTyCon tycon {- array, we hope -}   then 'A'     -- Bogus
+         else if isEnumerationTyCon tycon                 then 'E'
+         else if isTupleTyCon tycon                       then 'T'
+         else if isJust (maybeTyConSingleCon tycon)       then 'S'
+         else if utc == listTyConKey                      then 'L'
+         else 'M' -- oh, well...
diff --git a/ghc/compiler/codeGen/CgUpdate.lhs b/ghc/compiler/codeGen/CgUpdate.lhs
deleted file mode 100644 (file)
index 879dafe..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
-%
-\section[CgUpdate]{Manipulating update frames}
-
-\begin{code}
-module CgUpdate ( pushUpdateFrame ) where
-
-#include "HsVersions.h"
-
-import CgMonad
-import AbsCSyn
-
-import CgStackery      ( allocStackTop, updateFrameSize, setStackFrame )
-import CgUsages                ( getVirtSp )
-import Panic           ( assertPanic )
-\end{code}
-
-
-%********************************************************
-%*                                                     *
-%*             Setting up update frames                *
-%*                                                     *
-%********************************************************
-\subsection[setting-update-frames]{Setting up update frames}
-
-@pushUpdateFrame@ $updatee$ pushes a general update frame which
-points to $updatee$ as the thing to be updated.  It is only used
-when a thunk has just been entered, so the (real) stack pointers
-are guaranteed to be nicely aligned with the top of stack.
-@pushUpdateFrame@ adjusts the virtual and tail stack pointers
-to reflect the frame pushed.
-
-\begin{code}
-pushUpdateFrame :: CAddrMode -> Code -> Code
-
-pushUpdateFrame updatee code
-  = 
-#ifdef DEBUG
-    getEndOfBlockInfo                  `thenFC` \ eob_info ->
-    ASSERT(case eob_info of { EndOfBlockInfo _ (OnStack _) -> True; 
-                             _ -> False})
-#endif
-
-    allocStackTop updateFrameSize      `thenFC` \ _ ->
-    getVirtSp                          `thenFC` \ vsp ->
-
-    setStackFrame vsp                  `thenC`
-
-    setEndOfBlockInfo (EndOfBlockInfo vsp UpdateCode) (
-
-               -- Emit the push macro
-           absC (CMacroStmt PUSH_UPD_FRAME [
-                       updatee,
-                       int_CLit0  -- we just entered a closure, so must be zero
-           ])
-           `thenC` code
-    )
-
-int_CLit0 = mkIntCLit 0 -- out here to avoid pushUpdateFrame CAF (sigh)
-\end{code}
diff --git a/ghc/compiler/codeGen/CgUsages.lhs b/ghc/compiler/codeGen/CgUsages.lhs
deleted file mode 100644 (file)
index c8b98f6..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
-%
-\section[CgUsages]{Accessing and modifying stacks and heap usage info}
-
-This module provides the functions to access (\tr{get*} functions) and
-modify (\tr{set*} functions) the stacks and heap usage information.
-
-\begin{code}
-module CgUsages (
-       initHeapUsage, setVirtHp, getVirtAndRealHp, setRealHp,
-       setRealAndVirtualSp,
-
-       getVirtSp, getRealSp,
-
-       getHpRelOffset, getSpRelOffset,
-
-       adjustSpAndHp
-    ) where
-
-#include "HsVersions.h"
-
-import AbsCSyn
-import PrimRep         ( PrimRep(..) )
-import AbsCUtils       ( mkAbstractCs )
-import CgMonad
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[CgUsages-heapery]{Monad things for fiddling with heap usage}
-%*                                                                     *
-%************************************************************************
-
-@initHeapUsage@ applies a function to the amount of heap that it uses.
-It initialises the heap usage to zeros, and passes on an unchanged
-heap usage.
-
-It is usually a prelude to performing a GC check, so everything must
-be in a tidy and consistent state.
-
-rje: Note the slightly suble fixed point behaviour needed here
-\begin{code}
-initHeapUsage :: (VirtualHeapOffset -> Code) -> Code
-
-initHeapUsage fcode = do 
-       (stk_usage, heap_usage) <- getUsage
-       setUsage (stk_usage, (0,0))
-       fixC (\heap_usage2 -> do
-               fcode (heapHWM heap_usage2)
-               (_, heap_usage2) <- getUsage
-               return heap_usage2)
-       (stk_usage2, heap_usage2) <- getUsage
-       setUsage (stk_usage2, heap_usage {-unchanged -})
-\end{code}
-
-\begin{code}
-setVirtHp :: VirtualHeapOffset -> Code
-setVirtHp new_virtHp = do
-       (stk, (virtHp, realHp)) <- getUsage
-       setUsage (stk, (new_virtHp, realHp))
-\end{code}
-
-\begin{code}
-getVirtAndRealHp :: FCode (VirtualHeapOffset, VirtualHeapOffset)
-getVirtAndRealHp = do 
-       (_, (virtHp, realHp)) <- getUsage
-       return (virtHp, realHp)
-\end{code}
-
-\begin{code}
-setRealHp ::  VirtualHeapOffset -> Code
-setRealHp realHp = do
-       (stk_usage, (vHp, _)) <- getUsage
-       setUsage (stk_usage, (vHp, realHp))
-\end{code}
-
-\begin{code}
-getHpRelOffset :: VirtualHeapOffset -> FCode RegRelative
-getHpRelOffset virtual_offset = do
-       (_,(_,realHp)) <- getUsage
-       return $ hpRel realHp virtual_offset
-\end{code}
-
-The heap high water mark is the larger of virtHp and hwHp.  The latter is
-only records the high water marks of forked-off branches, so to find the
-heap high water mark you have to take the max of virtHp and hwHp.  Remember,
-virtHp never retreats!
-
-\begin{code}
-heapHWM (virtHp, realHp) = virtHp
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[CgUsages-stackery]{Monad things for fiddling with stack usage}
-%*                                                                     *
-%************************************************************************
-
-@setRealAndVirtualSp@ sets into the environment the offsets of the
-current position of the real and virtual stack pointers in the current
-stack frame.  The high-water mark is set too.  It generates no code.
-It is used to initialise things at the beginning of a closure body.
-
-\begin{code}
-setRealAndVirtualSp :: VirtualSpOffset         -- New real Sp
-                    -> Code
-
-setRealAndVirtualSp sp = do
-       ((vsp,frame,f,realSp,hwsp), h_usage) <- getUsage
-       let new_usage = ((sp, frame, f, sp, sp), h_usage)
-       setUsage new_usage
-\end{code}
-
-\begin{code}
-getVirtSp :: FCode VirtualSpOffset
-getVirtSp = do 
-       ((virtSp,_,_,_,_), _) <- getUsage
-       return virtSp
-
-getRealSp :: FCode VirtualSpOffset
-getRealSp = do
-       ((_,_,_,realSp,_),_) <- getUsage
-       return realSp
-\end{code}
-
-\begin{code}
-getSpRelOffset :: VirtualSpOffset -> FCode RegRelative
-getSpRelOffset virtual_offset = do
-       ((_,_,_,realSp,_),_) <- getUsage
-       return $ spRel realSp virtual_offset
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[CgStackery-adjust]{Adjusting the stack pointers}
-%*                                                                     *
-%************************************************************************
-
-This function adjusts the stack and heap pointers just before a tail
-call or return.  The stack pointer is adjusted to its final position
-(i.e. to point to the last argument for a tail call, or the activation
-record for a return).  The heap pointer may be moved backwards, in
-cases where we overallocated at the beginning of the basic block (see
-CgCase.lhs for discussion).
-
-These functions {\em do not} deal with high-water-mark adjustment.
-That's done by functions which allocate stack space.
-
-\begin{code}
-adjustSpAndHp :: VirtualSpOffset       -- New offset for Arg stack ptr
-             -> Code
-adjustSpAndHp newRealSp = do
-       (MkCgInfoDown _ _ _ ticky_ctr _) <- getInfoDown
-       (MkCgState absC binds
-                  ((vSp,frame,fSp,realSp,hwSp),        
-                  (vHp, rHp))) <- getState
-       let move_sp = if (newRealSp == realSp) then AbsCNop
-             else (CAssign (CReg Sp)
-                           (CAddr (spRel realSp newRealSp)))
-       let move_hp = 
-               if (rHp == vHp) then AbsCNop
-               else mkAbstractCs [
-               CAssign (CReg Hp) (CAddr (hpRel rHp vHp)),
-                       profCtrAbsC FSLIT("TICK_ALLOC_HEAP") 
-                       [ mkIntCLit (vHp - rHp), CLbl ticky_ctr DataPtrRep ]
-               ]
-       let new_usage = ((vSp, frame, fSp, newRealSp, hwSp), (vHp,vHp))
-       setState $ MkCgState (mkAbstractCs [absC,move_sp,move_hp]) binds new_usage
-\end{code}
diff --git a/ghc/compiler/codeGen/CgUtils.hs b/ghc/compiler/codeGen/CgUtils.hs
new file mode 100644 (file)
index 0000000..e74bd14
--- /dev/null
@@ -0,0 +1,622 @@
+-----------------------------------------------------------------------------
+--
+-- Code generator utilities; mostly monadic
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+module CgUtils (
+       addIdReps,
+       cgLit,
+       emitDataLits, emitRODataLits, emitIf, emitIfThenElse,
+       emitRtsCall, emitRtsCallWithVols, emitRtsCallWithResult,
+       assignTemp, newTemp,
+       emitSimultaneously,
+       emitSwitch, emitLitSwitch,
+       tagToClosure,
+
+       cmmAndWord, cmmOrWord, cmmNegate, cmmEqWord, cmmNeWord,
+       cmmOffsetExprW, cmmOffsetExprB,
+       cmmRegOffW, cmmRegOffB,
+       cmmLabelOffW, cmmLabelOffB,
+       cmmOffsetW, cmmOffsetB,
+       cmmOffsetLitW, cmmOffsetLitB,
+       cmmLoadIndexW,
+
+       addToMem, addToMemE,
+       mkWordCLit,
+       mkStringCLit,
+       packHalfWordsCLit,
+       blankWord
+  ) where
+
+#include "HsVersions.h"
+
+import CgMonad
+import TyCon           ( TyCon, tyConName )
+import Id              ( Id )
+import Constants       ( wORD_SIZE )
+import SMRep           ( CgRep, StgWord, hALF_WORD_SIZE_IN_BITS, ByteOff,
+                         WordOff, idCgRep )
+import PprCmm          ( {- instances -} )
+import Cmm
+import CLabel
+import CmmUtils
+import MachOp          ( MachRep(..), wordRep, MachOp(..),  MachHint(..),
+                         mo_wordOr, mo_wordAnd, mo_wordNe, mo_wordEq,
+                         mo_wordULt, machRepByteWidth )
+import ForeignCall     ( CCallConv(..) )
+import Literal         ( Literal(..) )
+import CLabel          ( CLabel, mkAsmTempLabel )
+import Digraph         ( SCC(..), stronglyConnComp )
+import ListSetOps      ( assocDefault )
+import Util            ( filterOut, sortLt )
+import Char            ( ord )
+import FastString      ( LitString, FastString, unpackFS )
+import Outputable
+
+import DATA_BITS
+
+#include "../includes/ghcconfig.h"
+       -- For WORDS_BIGENDIAN
+
+-------------------------------------------------------------------------
+--
+--     Random small functions
+--
+-------------------------------------------------------------------------
+
+addIdReps :: [Id] -> [(CgRep, Id)]
+addIdReps ids = [(idCgRep id, id) | id <- ids]
+
+-------------------------------------------------------------------------
+--
+--     Literals
+--
+-------------------------------------------------------------------------
+
+cgLit :: Literal -> FCode CmmLit
+cgLit (MachStr s) = mkStringCLit (unpackFS s)
+cgLit other_lit   = return (mkSimpleLit other_lit)
+
+mkSimpleLit :: Literal -> CmmLit
+mkSimpleLit (MachChar  c)    = CmmInt (fromIntegral (ord c)) wordRep
+mkSimpleLit MachNullAddr      = zeroCLit
+mkSimpleLit (MachInt i)       = CmmInt i wordRep
+mkSimpleLit (MachInt64 i)     = CmmInt i I64
+mkSimpleLit (MachWord i)      = CmmInt i wordRep
+mkSimpleLit (MachWord64 i)    = CmmInt i I64
+mkSimpleLit (MachFloat r)     = CmmFloat r F32
+mkSimpleLit (MachDouble r)    = CmmFloat r F64
+mkSimpleLit (MachLabel fs ms) = CmmLabel (mkForeignLabel fs ms is_dyn)
+                             where
+                               is_dyn = False  -- ToDo: fix me
+       
+mkLtOp :: Literal -> MachOp
+-- On signed literals we must do a signed comparison
+mkLtOp (MachInt _)    = MO_S_Lt wordRep
+mkLtOp (MachFloat _)  = MO_S_Lt F32
+mkLtOp (MachDouble _) = MO_S_Lt F64
+mkLtOp lit           = MO_U_Lt (cmmLitRep (mkSimpleLit lit))
+
+
+---------------------------------------------------
+--
+--     Cmm data type functions
+--
+---------------------------------------------------
+
+-----------------------
+-- The "B" variants take byte offsets
+cmmRegOffB :: CmmReg -> ByteOff -> CmmExpr
+cmmRegOffB = cmmRegOff
+
+cmmOffsetB :: CmmExpr -> ByteOff -> CmmExpr
+cmmOffsetB = cmmOffset
+
+cmmOffsetExprB :: CmmExpr -> CmmExpr -> CmmExpr
+cmmOffsetExprB = cmmOffsetExpr
+
+cmmLabelOffB :: CLabel -> ByteOff -> CmmLit
+cmmLabelOffB = cmmLabelOff
+
+cmmOffsetLitB :: CmmLit -> ByteOff -> CmmLit
+cmmOffsetLitB = cmmOffsetLit
+
+-----------------------
+-- The "W" variants take word offsets
+cmmOffsetExprW :: CmmExpr -> CmmExpr -> CmmExpr
+-- The second arg is a *word* offset; need to change it to bytes
+cmmOffsetExprW e (CmmLit (CmmInt n _)) = cmmOffsetW e (fromInteger n)
+cmmOffsetExprW e wd_off = cmmIndexExpr wordRep e wd_off
+
+cmmOffsetW :: CmmExpr -> WordOff -> CmmExpr
+cmmOffsetW e n = cmmOffsetB e (wORD_SIZE * n)
+
+cmmRegOffW :: CmmReg -> WordOff -> CmmExpr
+cmmRegOffW reg wd_off = cmmRegOffB reg (wd_off * wORD_SIZE)
+
+cmmOffsetLitW :: CmmLit -> WordOff -> CmmLit
+cmmOffsetLitW lit wd_off = cmmOffsetLitB lit (wORD_SIZE * wd_off)
+
+cmmLabelOffW :: CLabel -> WordOff -> CmmLit
+cmmLabelOffW lbl wd_off = cmmLabelOffB lbl (wORD_SIZE * wd_off)
+
+cmmLoadIndexW :: CmmExpr -> Int -> CmmExpr
+cmmLoadIndexW base off
+  = CmmLoad (cmmOffsetW base off) wordRep
+
+-----------------------
+cmmNeWord, cmmEqWord, cmmOrWord, cmmAndWord :: CmmExpr -> CmmExpr -> CmmExpr
+cmmOrWord  e1 e2 = CmmMachOp mo_wordOr  [e1, e2]
+cmmAndWord e1 e2 = CmmMachOp mo_wordAnd [e1, e2]
+cmmNeWord  e1 e2 = CmmMachOp mo_wordNe  [e1, e2]
+cmmEqWord  e1 e2 = CmmMachOp mo_wordEq  [e1, e2]
+cmmULtWord e1 e2 = CmmMachOp mo_wordULt  [e1, e2]
+
+cmmNegate :: CmmExpr -> CmmExpr
+cmmNegate (CmmLit (CmmInt n rep)) = CmmLit (CmmInt (-n) rep)
+cmmNegate e                      = CmmMachOp (MO_S_Neg (cmmExprRep e)) [e]
+
+blankWord :: CmmStatic
+blankWord = CmmUninitialised wORD_SIZE
+
+-----------------------
+--     Making literals
+
+mkWordCLit :: StgWord -> CmmLit
+mkWordCLit wd = CmmInt (fromIntegral wd) wordRep
+
+packHalfWordsCLit :: (Integral a, Integral b) => a -> b -> CmmLit
+-- Make a single word literal in which the lower_half_word is
+-- at the lower address, and the upper_half_word is at the 
+-- higher address
+-- ToDo: consider using half-word lits instead
+--      but be careful: that's vulnerable when reversed
+packHalfWordsCLit lower_half_word upper_half_word
+#ifdef WORDS_BIGENDIAN
+   = mkWordCLit ((fromIntegral lower_half_word `shiftL` hALF_WORD_SIZE_IN_BITS)
+                .|. fromIntegral upper_half_word)
+#else 
+   = mkWordCLit ((fromIntegral lower_half_word) 
+                .|. (fromIntegral upper_half_word `shiftL` hALF_WORD_SIZE_IN_BITS))
+#endif
+
+--------------------------------------------------------------------------
+--
+-- Incrementing a memory location
+--
+--------------------------------------------------------------------------
+
+addToMem :: MachRep    -- rep of the counter
+        -> CmmExpr     -- Address
+        -> Int         -- What to add (a word)
+        -> CmmStmt
+addToMem rep ptr n = addToMemE rep ptr (CmmLit (CmmInt (toInteger n) rep))
+
+addToMemE :: MachRep   -- rep of the counter
+         -> CmmExpr    -- Address
+         -> CmmExpr    -- What to add (a word-typed expression)
+         -> CmmStmt
+addToMemE rep ptr n
+  = CmmStore ptr (CmmMachOp (MO_Add rep) [CmmLoad ptr rep, n])
+
+-------------------------------------------------------------------------
+--
+--     Converting a closure tag to a closure for enumeration types
+--      (this is the implementation of tagToEnum#).
+--
+-------------------------------------------------------------------------
+
+tagToClosure :: TyCon -> CmmExpr -> CmmExpr
+tagToClosure tycon tag
+  = CmmLoad (cmmOffsetExprW closure_tbl tag) wordRep
+  where closure_tbl = CmmLit (CmmLabel (mkClosureTblLabel (tyConName tycon)))
+
+-------------------------------------------------------------------------
+--
+--     Conditionals and rts calls
+--
+-------------------------------------------------------------------------
+
+emitIf :: CmmExpr      -- Boolean
+       -> Code         -- Then part
+       -> Code         
+-- Emit (if e then x)
+-- ToDo: reverse the condition to avoid the extra branch instruction if possible
+-- (some conditionals aren't reversible. eg. floating point comparisons cannot
+-- be inverted because there exist some values for which both comparisons
+-- return False, such as NaN.)
+emitIf cond then_part
+  = do { then_id <- newLabelC
+       ; join_id <- newLabelC
+       ; stmtC (CmmCondBranch cond then_id)
+       ; stmtC (CmmBranch join_id)
+       ; labelC then_id
+       ; then_part
+       ; labelC join_id
+       }
+
+emitIfThenElse :: CmmExpr      -- Boolean
+                       -> Code         -- Then part
+                       -> Code         -- Else part
+                       -> Code         
+-- Emit (if e then x else y)
+emitIfThenElse cond then_part else_part
+  = do { then_id <- newLabelC
+       ; else_id <- newLabelC
+       ; join_id <- newLabelC
+       ; stmtC (CmmCondBranch cond then_id)
+       ; else_part
+       ; stmtC (CmmBranch join_id)
+       ; labelC then_id
+       ; then_part
+       ; labelC join_id
+       }
+
+emitRtsCall :: LitString -> [(CmmExpr,MachHint)] -> Code
+emitRtsCall fun args = emitRtsCall' [] fun args Nothing
+   -- The 'Nothing' says "save all global registers"
+
+emitRtsCallWithVols :: LitString -> [(CmmExpr,MachHint)] -> [GlobalReg] -> Code
+emitRtsCallWithVols fun args vols
+   = emitRtsCall' [] fun args (Just vols)
+
+emitRtsCallWithResult :: CmmReg -> MachHint -> LitString
+       -> [(CmmExpr,MachHint)] -> Code
+emitRtsCallWithResult res hint fun args
+   = emitRtsCall' [(res,hint)] fun args Nothing
+
+-- Make a call to an RTS C procedure
+emitRtsCall'
+   :: [(CmmReg,MachHint)]
+   -> LitString
+   -> [(CmmExpr,MachHint)]
+   -> Maybe [GlobalReg]
+   -> Code
+emitRtsCall' res fun args vols = stmtC (CmmCall target res args vols)
+  where
+    target   = CmmForeignCall fun_expr CCallConv
+    fun_expr = mkLblExpr (mkRtsCodeLabel fun)
+
+
+-------------------------------------------------------------------------
+--
+--     Strings gnerate a top-level data block
+--
+-------------------------------------------------------------------------
+
+emitDataLits :: CLabel -> [CmmLit] -> Code
+-- Emit a data-segment data block
+emitDataLits lbl lits
+  = emitData Data (CmmDataLabel lbl : map CmmStaticLit lits)
+
+emitRODataLits :: CLabel -> [CmmLit] -> Code
+-- Emit a read-only data block
+emitRODataLits lbl lits
+  = emitData ReadOnlyData (CmmDataLabel lbl : map CmmStaticLit lits)
+
+mkStringCLit :: String -> FCode CmmLit
+-- Make a global definition for the string,
+-- and return its label
+mkStringCLit str 
+  = do         { uniq <- newUnique
+       ; let lbl = mkAsmTempLabel uniq
+       ; emitData ReadOnlyData [CmmDataLabel lbl, CmmString str]
+       ; return (CmmLabel lbl) }
+
+-------------------------------------------------------------------------
+--
+--     Assigning expressions to temporaries
+--
+-------------------------------------------------------------------------
+
+assignTemp :: CmmExpr -> FCode CmmExpr
+-- For a non-trivial expression, e, create a local
+-- variable and assign the expression to it
+assignTemp e 
+  | isTrivialCmmExpr e = return e
+  | otherwise         = do { reg <- newTemp (cmmExprRep e)
+                           ; stmtC (CmmAssign reg e)
+                           ; return (CmmReg reg) }
+
+
+newTemp :: MachRep -> FCode CmmReg
+newTemp rep = do { uniq <- newUnique; return (CmmLocal (LocalReg uniq rep)) }
+
+
+-------------------------------------------------------------------------
+--
+--     Building case analysis
+--
+-------------------------------------------------------------------------
+
+emitSwitch
+       :: CmmExpr                -- Tag to switch on
+       -> [(ConTagZ, CgStmts)]   -- Tagged branches
+       -> Maybe CgStmts          -- Default branch (if any)
+       -> ConTagZ -> ConTagZ     -- Min and Max possible values; behaviour
+                                 --    outside this range is undefined
+       -> Code
+
+-- ONLY A DEFAULT BRANCH: no case analysis to do
+emitSwitch tag_expr [] (Just stmts) _ _
+  = emitCgStmts stmts
+
+-- Right, off we go
+emitSwitch tag_expr branches mb_deflt lo_tag hi_tag
+  =    -- Just sort the branches before calling mk_sritch
+    do { mb_deflt_id <-
+               case mb_deflt of
+                 Nothing    -> return Nothing
+                 Just stmts -> do id <- forkCgStmts stmts; return (Just id)
+
+       ; stmts <- mk_switch tag_expr (sortLt lt branches) 
+                       mb_deflt_id lo_tag hi_tag
+       ; emitCgStmts stmts
+       }
+  where
+    (t1,_) `lt` (t2,_) = t1 < t2
+
+
+mk_switch :: CmmExpr -> [(ConTagZ, CgStmts)]
+         -> Maybe BlockId -> ConTagZ -> ConTagZ
+         -> FCode CgStmts
+
+-- SINGLETON TAG RANGE: no case analysis to do
+mk_switch tag_expr [(tag,stmts)] _ lo_tag hi_tag
+  | lo_tag == hi_tag
+  = ASSERT( tag == lo_tag )
+    return stmts
+
+-- SINGLETON BRANCH, NO DEFUALT: no case analysis to do
+mk_switch tag_expr [(tag,stmts)] Nothing lo_tag hi_tag
+  = return stmts
+       -- The simplifier might have eliminated a case
+       --       so we may have e.g. case xs of 
+       --                               [] -> e
+       -- In that situation we can be sure the (:) case 
+       -- can't happen, so no need to test
+
+-- SINGLETON BRANCH: one equality check to do
+mk_switch tag_expr [(tag,stmts)] (Just deflt) lo_tag hi_tag
+  = return (CmmCondBranch cond deflt `consCgStmt` stmts)
+  where
+    cond  =  cmmNeWord tag_expr (CmmLit (mkIntCLit tag))
+       -- We have lo_tag < hi_tag, but there's only one branch, 
+       -- so there must be a default
+
+-- ToDo: we might want to check for the two branch case, where one of
+-- the branches is the tag 0, because comparing '== 0' is likely to be
+-- more efficient than other kinds of comparison.
+
+-- DENSE TAG RANGE: use a switch statment
+mk_switch tag_expr branches mb_deflt lo_tag hi_tag
+  | use_switch         -- Use a switch
+  = do { deflt_id <- get_deflt_id mb_deflt
+       ; branch_ids <- mapM forkCgStmts (map snd branches)
+       ; let 
+               tagged_blk_ids = zip (map fst branches) branch_ids
+
+               find_branch :: BlockId -> ConTagZ -> BlockId
+               find_branch deflt_id i = assocDefault deflt_id tagged_blk_ids i
+
+               arms = [ Just (find_branch deflt_id (i+lo_tag))
+                      | i <- [0..n_tags-1]]
+
+               switch_stmt = CmmSwitch (cmmOffset tag_expr (- lo_tag)) arms
+
+       ; return (oneCgStmt switch_stmt)
+       }
+
+  | otherwise  -- Use an if-tree
+  = do { (assign_tag, tag_expr') <- assignTemp' tag_expr
+               -- To avoid duplication
+       ; lo_stmts <- mk_switch tag_expr' lo_branches mb_deflt lo_tag (mid_tag-1)
+       ; hi_stmts <- mk_switch tag_expr' hi_branches mb_deflt mid_tag hi_tag
+       ; lo_id <- forkCgStmts lo_stmts
+       ; let cond = cmmULtWord tag_expr' (CmmLit (mkIntCLit mid_tag))
+             branch_stmt = CmmCondBranch cond lo_id
+       ; return (assign_tag `consCgStmt` (branch_stmt `consCgStmt` hi_stmts)) 
+       }
+  where
+    use_switch          = ASSERT( n_branches > 1 && n_tags > 1 ) 
+                  n_tags > 2 && (small || dense)
+                -- a 2-branch switch always turns into an if.
+    small               = n_tags <= 4
+    dense               = n_branches > (n_tags `div` 2)
+    exhaustive   = n_tags == n_branches
+    n_tags              = hi_tag - lo_tag + 1
+    n_branches   = length branches
+    
+       -- INVARIANT: Provided hi_tag > lo_tag (which is true)
+       --      lo_tag <= mid_tag < hi_tag
+       --      lo_branches have tags <  mid_tag
+       --      hi_branches have tags >= mid_tag
+
+    (mid_tag,_) = branches !! (n_branches `div` 2)
+       -- 2 branches => n_branches `div` 2 = 1
+       --            => branches !! 1 give the *second* tag
+       -- There are always at least 2 branches here
+
+    (lo_branches, hi_branches) = span is_lo branches
+    is_lo (t,_) = t < mid_tag
+
+       -- Add a default block if the case is not exhaustive
+    get_deflt_id  (Just deflt_id) = return deflt_id
+    get_deflt_id  Nothing
+       | exhaustive 
+       = return (pprPanic "mk_deflt_blks" (ppr tag_expr))
+       | otherwise
+       = do { stmts <- getCgStmts (stmtC jump_to_impossible)
+            ; id <- forkCgStmts stmts
+            ; return id }
+
+    jump_to_impossible 
+      = CmmJump (mkLblExpr mkErrorStdEntryLabel) []
+
+
+assignTemp' e
+  | isTrivialCmmExpr e = return (CmmNop, e)
+  | otherwise          = do { reg <- newTemp (cmmExprRep e)
+                            ; return (CmmAssign reg e, CmmReg reg) }
+
+
+emitLitSwitch :: CmmExpr                       -- Tag to switch on
+             -> [(Literal, CgStmts)]           -- Tagged branches
+             -> CgStmts                        -- Default branch (always)
+             -> Code                           -- Emit the code
+-- Used for general literals, whose size might not be a word, 
+-- where there is always a default case, and where we don't know
+-- the range of values for certain.  For simplicity we always generate a tree.
+emitLitSwitch scrut [] deflt 
+  = emitCgStmts deflt
+emitLitSwitch scrut branches deflt_blk
+  = do { scrut' <- assignTemp scrut
+       ; deflt_blk_id <- forkCgStmts deflt_blk
+       ; blk <- mk_lit_switch scrut' deflt_blk_id (sortLt lt branches)
+       ; emitCgStmts blk }
+  where
+    lt (t1,_) (t2,_) = t1 < t2
+
+mk_lit_switch :: CmmExpr -> BlockId 
+             -> [(Literal,CgStmts)]
+             -> FCode CgStmts
+mk_lit_switch scrut deflt_blk_id [(lit,blk)] 
+  = return (consCgStmt if_stmt blk)
+  where
+    cmm_lit = mkSimpleLit lit
+    rep     = cmmLitRep cmm_lit
+    cond    = CmmMachOp (MO_Ne rep) [scrut, CmmLit cmm_lit]
+    if_stmt = CmmCondBranch cond deflt_blk_id
+
+mk_lit_switch scrut deflt_blk_id branches
+  = do { hi_blk <- mk_lit_switch scrut deflt_blk_id hi_branches
+       ; lo_blk <- mk_lit_switch scrut deflt_blk_id lo_branches
+       ; lo_blk_id <- forkCgStmts lo_blk
+       ; let if_stmt = CmmCondBranch cond lo_blk_id
+       ; return (if_stmt `consCgStmt` hi_blk) }
+  where
+    n_branches = length branches
+    (mid_lit,_) = branches !! (n_branches `div` 2)
+       -- See notes above re mid_tag
+
+    (lo_branches, hi_branches) = span is_lo branches
+    is_lo (t,_) = t < mid_lit
+
+    cond    = CmmMachOp (mkLtOp mid_lit) 
+                       [scrut, CmmLit (mkSimpleLit mid_lit)]
+
+-------------------------------------------------------------------------
+--
+--     Simultaneous assignment
+--
+-------------------------------------------------------------------------
+
+
+emitSimultaneously :: CmmStmts -> Code
+-- Emit code to perform the assignments in the
+-- input simultaneously, using temporary variables when necessary.
+--
+-- The Stmts must be:
+--     CmmNop, CmmComment, CmmAssign, CmmStore
+-- and nothing else
+
+
+-- We use the strongly-connected component algorithm, in which
+--     * the vertices are the statements
+--     * an edge goes from s1 to s2 iff
+--             s1 assigns to something s2 uses
+--       that is, if s1 should *follow* s2 in the final order
+
+type CVertex = (Int, CmmStmt)  -- Give each vertex a unique number,
+                               -- for fast comparison
+
+emitSimultaneously stmts
+  = codeOnly $
+    case filterOut isNopStmt (stmtList stmts) of 
+       -- Remove no-ops
+      []       -> nopC
+      [stmt]   -> stmtC stmt   -- It's often just one stmt
+      stmt_list -> doSimultaneously1 (zip [(1::Int)..] stmt_list)
+
+doSimultaneously1 :: [CVertex] -> Code
+doSimultaneously1 vertices
+  = let
+       edges = [ (vertex, key1, edges_from stmt1)
+               | vertex@(key1, stmt1) <- vertices
+               ]
+       edges_from stmt1 = [ key2 | (key2, stmt2) <- vertices, 
+                                   stmt1 `mustFollow` stmt2
+                          ]
+       components = stronglyConnComp edges
+
+       -- do_components deal with one strongly-connected component
+       -- Not cyclic, or singleton?  Just do it
+       do_component (AcyclicSCC (n,stmt))  = stmtC stmt
+       do_component (CyclicSCC [(n,stmt)]) = stmtC stmt
+
+               -- Cyclic?  Then go via temporaries.  Pick one to
+               -- break the loop and try again with the rest.
+       do_component (CyclicSCC ((n,first_stmt) : rest))
+         = do  { from_temp <- go_via_temp first_stmt
+               ; doSimultaneously1 rest
+               ; stmtC from_temp }
+
+       go_via_temp (CmmAssign dest src)
+         = do  { tmp <- newTemp (cmmRegRep dest)
+               ; stmtC (CmmAssign tmp src)
+               ; return (CmmAssign dest (CmmReg tmp)) }
+       go_via_temp (CmmStore dest src)
+         = do  { tmp <- newTemp (cmmExprRep src)
+               ; stmtC (CmmAssign tmp src)
+               ; return (CmmStore dest (CmmReg tmp)) }
+    in
+    mapCs do_component components
+
+mustFollow :: CmmStmt -> CmmStmt -> Bool
+CmmAssign reg _  `mustFollow` stmt = anySrc (reg `regUsedIn`) stmt
+CmmStore loc e   `mustFollow` stmt = anySrc (locUsedIn loc (cmmExprRep e)) stmt
+CmmNop           `mustFollow` stmt = False
+CmmComment _     `mustFollow` stmt = False
+
+
+anySrc :: (CmmExpr -> Bool) -> CmmStmt -> Bool
+-- True if the fn is true of any input of the stmt
+anySrc p (CmmAssign _ e)    = p e
+anySrc p (CmmStore e1 e2)   = p e1 || p e2     -- Might be used in either side
+anySrc p (CmmComment _)            = False
+anySrc p CmmNop                    = False
+anySrc p other             = True              -- Conservative
+
+regUsedIn :: CmmReg -> CmmExpr -> Bool
+reg `regUsedIn` CmmLit _        = False
+reg `regUsedIn` CmmLoad e  _    = reg `regUsedIn` e
+reg `regUsedIn` CmmReg reg'     = reg == reg'
+reg `regUsedIn` CmmRegOff reg' _ = reg == reg'
+reg `regUsedIn` CmmMachOp _ es   = any (reg `regUsedIn`) es
+
+locUsedIn :: CmmExpr -> MachRep -> CmmExpr -> Bool
+-- (locUsedIn a r e) checks whether writing to r[a] could affect the value of
+-- 'e'.  Returns True if it's not sure.
+locUsedIn loc rep (CmmLit _)        = False
+locUsedIn loc rep (CmmLoad e ld_rep) = possiblySameLoc loc rep e ld_rep
+locUsedIn loc rep (CmmReg reg')      = False
+locUsedIn loc rep (CmmRegOff reg' _) = False
+locUsedIn loc rep (CmmMachOp _ es)   = any (locUsedIn loc rep) es
+
+possiblySameLoc :: CmmExpr -> MachRep -> CmmExpr -> MachRep -> Bool
+-- Assumes that distinct registers (eg Hp, Sp) do not 
+-- point to the same location, nor any offset thereof.
+possiblySameLoc (CmmReg r1)       rep1 (CmmReg r2)      rep2  = r1==r2
+possiblySameLoc (CmmReg r1)       rep1 (CmmRegOff r2 0) rep2  = r1==r2
+possiblySameLoc (CmmRegOff r1 0)  rep1 (CmmReg r2)      rep2  = r1==r2
+possiblySameLoc (CmmRegOff r1 start1) rep1 (CmmRegOff r2 start2) rep2 
+  = r1==r2 && end1 > start2 && end2 > start1
+  where
+    end1 = start1 + machRepByteWidth rep1
+    end2 = start2 + machRepByteWidth rep2
+
+possiblySameLoc l1 rep1 (CmmLit _) rep2 = False
+possiblySameLoc l1 rep1 l2        rep2 = True  -- Conservative
index 86380ec..0abf831 100644 (file)
@@ -1,9 +1,11 @@
 %
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
+% (c) The Univserity of Glasgow 1992-2004
 %
-% $Id: ClosureInfo.lhs,v 1.62 2004/03/31 15:23:17 simonmar Exp $
-%
-\section[ClosureInfo]{Data structures which describe closures}
+
+       Data structures which describe closures, and
+       operations over those data structures
+
+               Nothing monadic in here
 
 Much of the rationale for these things is in the ``details'' part of
 the STG paper.
@@ -11,86 +13,73 @@ the STG paper.
 \begin{code}
 module ClosureInfo (
        ClosureInfo, LambdaFormInfo, SMRep,     -- all abstract
-       StandardFormInfo, ArgDescr(..),
+       StandardFormInfo, 
 
-       CallingConvention(..),
+       ArgDescr(..), Liveness(..), 
+       C_SRT(..), needsSRT,
 
-       mkClosureLFInfo, mkConLFInfo, mkSelectorLFInfo,
+       mkLFThunk, mkLFReEntrant, mkConLFInfo, mkSelectorLFInfo,
        mkApLFInfo, mkLFImported, mkLFArgument, mkLFLetNoEscape,
 
+       mkClosureInfo, mkConInfo,
+
        closureSize, closureNonHdrSize,
        closureGoodStuffSize, closurePtrsSize,
-       slopSize,
+       slopSize, 
 
-       layOutDynClosure, layOutStaticClosure, layOutStaticNoFVClosure,
-       layOutDynConstr, layOutStaticConstr,
-       mkVirtHeapOffsets, mkStaticClosure,
+       closureName, infoTableLabelFromCI,
+       closureLabelFromCI, closureSRT,
+       closureLFInfo, closureSMRep, closureUpdReqd,
+       closureSingleEntry, closureReEntrant, isConstrClosure_maybe,
+       closureFunInfo, isStandardFormThunk, isKnownFun,
 
-       nodeMustPointToIt, getEntryConvention, 
-       FCode, CgInfoDownwards, CgState, 
+       enterIdLabel, enterReturnPtLabel,
+
+       nodeMustPointToIt, 
+       CallMethod(..), getCallMethod,
 
        blackHoleOnEntry,
 
        staticClosureRequired,
-
-       closureName, infoTableLabelFromCI,
-       closureLabelFromCI, closureSRT,
-       entryLabelFromCI, 
-       closureLFInfo, closureSMRep, closureUpdReqd,
-       closureSingleEntry, closureReEntrant, closureSemiTag,
-       closureFunInfo, isStandardFormThunk,
+       getClosureType,
 
        isToplevClosure,
-       closureTypeDescr,               -- profiling
+       closureValDescr, closureTypeDescr,      -- profiling
 
        isStaticClosure,
-       allocProfilingMsg,
        cafBlackHoleClosureInfo, seCafBlackHoleClosureInfo,
 
        staticClosureNeedsLink,
-
-       mkInfoTable, mkRetInfoTable, mkVecInfoTable,
     ) where
 
-#include "../includes/config.h"
 #include "../includes/MachDeps.h"
 #include "HsVersions.h"
 
-import AbsCSyn         
 import StgSyn
-import CgMonad
+import SMRep           -- all of it
 
-import Constants       ( mIN_UPD_SIZE, mIN_SIZE_NonUpdHeapObject )
-import CgRetConv       ( assignRegs )
 import CLabel
+
+import Constants       ( mIN_UPD_SIZE, mIN_SIZE_NonUpdHeapObject )
 import CmdLineOpts     ( opt_SccProfilingOn, opt_OmitBlackHoling,
                          opt_Parallel, opt_DoTickyProfiling,
-                         opt_SMP, opt_Unregisterised )
-import Id              ( Id, idType, idArity, idName, idPrimRep )
-import DataCon         ( DataCon, dataConTag, fIRST_TAG, dataConTyCon,
-                         isNullaryDataCon, dataConName
-                       )
-import Name            ( Name, nameUnique, getOccName, getName, getOccString )
+                         opt_SMP )
+import Id              ( Id, idType, idArity, idName )
+import DataCon         ( DataCon, dataConTyCon, isNullaryDataCon, dataConName )
+import Name            ( Name, nameUnique, getOccName, getOccString )
 import OccName         ( occNameUserString )
-import PrimRep
-import SMRep           -- all of it
 import Type            ( isUnLiftedType, Type, repType, splitTyConApp_maybe )
 import TcType          ( tcSplitSigmaTy )
 import TyCon           ( isFunTyCon, isAbstractTyCon )
 import BasicTypes      ( TopLevelFlag(..), isNotTopLevel, isTopLevel, ipNameName )
-import Util            ( mapAccumL, listLengthCmp, lengthIs )
 import FastString
 import Outputable
-import Literal
 import Constants
-import Bitmap
-
-import Maybe           ( isJust )
-import DATA_BITS
 
 import TypeRep -- TEMP
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
 \subsection[ClosureInfo-datatypes]{Data types for closure information}
@@ -121,12 +110,22 @@ data ClosureInfo
        closureDescr  :: !String          -- closure description (for profiling)
     }
 
-  -- constructor closures don't have a unique info table label (they use
+  -- Constructor closures don't have a unique info table label (they use
   -- the constructor's info table), and they don't have an SRT.
   | ConInfo {
        closureCon       :: !DataCon,
        closureSMRep     :: !SMRep
     }
+
+-- C_SRT is what StgSyn.SRT gets translated to... 
+-- we add a label for the table, and expect only the 'offset/length' form
+
+data C_SRT = NoC_SRT
+          | C_SRT !CLabel !WordOff !StgHalfWord {-bitmap or escape-}
+
+needsSRT :: C_SRT -> Bool
+needsSRT NoC_SRT       = False
+needsSRT (C_SRT _ _ _) = True
 \end{code}
 
 %************************************************************************
@@ -147,11 +146,11 @@ ClosureInfo contains a LambdaFormInfo.
 data LambdaFormInfo
   = LFReEntrant                -- Reentrant closure (a function)
        TopLevelFlag    -- True if top level
-       !Int            -- Arity
+       !Int            -- Arity. Invariant: always > 0
        !Bool           -- True <=> no fvs
        ArgDescr        -- Argument descriptor (should reall be in ClosureInfo)
 
-  | LFCon              -- Constructor
+  | LFCon              -- A saturated constructor application
        DataCon         -- The constructor
 
   | LFThunk            -- Thunk (zero arity)
@@ -179,36 +178,58 @@ data LambdaFormInfo
         CLabel          -- Flavour (info label, eg CAF_BLACKHOLE_info).
 
 
-data StandardFormInfo  -- Tells whether this thunk has one of a small number
-                       -- of standard forms
+-------------------------
+-- An ArgDsecr describes the argument pattern of a function
 
-  = NonStandardThunk   -- No, it isn't
+data ArgDescr
+  = ArgSpec            -- Fits one of the standard patterns
+       !Int            -- RTS type identifier ARG_P, ARG_N, ...
 
-  | SelectorThunk
-       Int                     -- 0-origin offset of ak within the "goods" of 
-                       -- constructor (Recall that the a1,...,an may be laid
-                       -- out in the heap in a non-obvious order.)
+  | ArgGen             -- General case
+       Liveness        -- Details about the arguments
 
-{- A SelectorThunk is of form
 
-     case x of
-       con a1,..,an -> ak
+-------------------------
+-- We represent liveness bitmaps as a Bitmap (whose internal
+-- representation really is a bitmap).  These are pinned onto case return
+-- vectors to indicate the state of the stack for the garbage collector.
+-- 
+-- In the compiled program, liveness bitmaps that fit inside a single
+-- word (StgWord) are stored as a single word, while larger bitmaps are
+-- stored as a pointer to an array of words. 
 
-   and the constructor is from a single-constr type.
--}
+data Liveness
+  = SmallLiveness      -- Liveness info that fits in one word
+       StgWord         -- Here's the bitmap
+
+  | BigLiveness                -- Liveness info witha a multi-word bitmap
+       CLabel          -- Label for the bitmap
 
-  | ApThunk 
-       Int             -- arity
 
-{- An ApThunk is of form
+-------------------------
+-- StandardFormInfo tells whether this thunk has one of 
+-- a small number of standard forms
 
-       x1 ... xn
+data StandardFormInfo
+  = NonStandardThunk
+       -- Not of of the standard forms
 
-   The code for the thunk just pushes x2..xn on the stack and enters x1.
-   There are a few of these (for 1 <= n <= MAX_SPEC_AP_SIZE) pre-compiled
-   in the RTS to save space.
--}
+  | SelectorThunk
+       -- A SelectorThunk is of form
+       --      case x of
+       --             con a1,..,an -> ak
+       -- and the constructor is from a single-constr type.
+       WordOff                 -- 0-origin offset of ak within the "goods" of 
+                       -- constructor (Recall that the a1,...,an may be laid
+                       -- out in the heap in a non-obvious order.)
 
+  | ApThunk 
+       -- An ApThunk is of form
+       --      x1 ... xn
+       -- The code for the thunk just pushes x2..xn on the stack and enters x1.
+       -- There are a few of these (for 1 <= n <= MAX_SPEC_AP_SIZE) pre-compiled
+       -- in the RTS to save space.
+       Int             -- Arity, n
 \end{code}
 
 %************************************************************************
@@ -217,31 +238,27 @@ data StandardFormInfo     -- Tells whether this thunk has one of a small number
 %*                                                                     *
 %************************************************************************
 
-@mkClosureLFInfo@ figures out the appropriate LFInfo for the closure.
-
 \begin{code}
-mkClosureLFInfo :: Id          -- The binder
-               -> TopLevelFlag -- True of top level
-               -> [Id]         -- Free vars
-               -> UpdateFlag   -- Update flag
-               -> [Id]         -- Args
-               -> LambdaFormInfo
-
-mkClosureLFInfo bndr top fvs upd_flag args@(_:_) -- Non-empty args
-  = LFReEntrant top (length args) (null fvs) (mkArgDescr (getName bndr) args)
-
-mkClosureLFInfo bndr top fvs upd_flag []
-  = ASSERT( not updatable || not (isUnLiftedType id_ty) )
-    LFThunk top (null fvs) updatable NonStandardThunk 
-       (might_be_a_function id_ty)
-  where
-       updatable = isUpdatable upd_flag
-       id_ty = idType bndr
+mkLFReEntrant :: TopLevelFlag  -- True of top level
+             -> [Id]           -- Free vars
+             -> [Id]           -- Args
+             -> ArgDescr       -- Argument descriptor
+             -> LambdaFormInfo
+
+mkLFReEntrant top fvs args arg_descr 
+  = LFReEntrant top (length args) (null fvs) arg_descr
+
+mkLFThunk thunk_ty top fvs upd_flag
+  = ASSERT( not (isUpdatable upd_flag) || not (isUnLiftedType thunk_ty) )
+    LFThunk top (null fvs) 
+           (isUpdatable upd_flag)
+           NonStandardThunk 
+           (might_be_a_function thunk_ty)
 
 might_be_a_function :: Type -> Bool
 might_be_a_function ty
   | Just (tc,_) <- splitTyConApp_maybe (repType ty), 
-    not (isFunTyCon tc) && not (isAbstractTyCon tc) = False
+    not (isFunTyCon tc)  && not (isAbstractTyCon tc) = False
        -- don't forget to check for abstract types, which might
        -- be functions too.
   | otherwise = True
@@ -278,15 +295,51 @@ mkLFImported id
 
 %************************************************************************
 %*                                                                     *
+       Building ClosureInfos
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+mkClosureInfo :: Bool          -- Is static
+             -> Id
+             -> LambdaFormInfo 
+             -> Int -> Int     -- Total and pointer words
+             -> C_SRT
+             -> String         -- String descriptor
+             -> ClosureInfo
+mkClosureInfo is_static id lf_info tot_wds ptr_wds srt_info descr
+  = ClosureInfo { closureName = name, 
+                 closureLFInfo = lf_info,
+                 closureSMRep = sm_rep, 
+                 closureSRT = srt_info,
+                 closureType = idType id,
+                 closureDescr = descr }
+  where
+    name   = idName id
+    sm_rep = chooseSMRep is_static lf_info tot_wds ptr_wds
+
+mkConInfo :: Bool      -- Is static
+         -> DataCon    
+         -> Int -> Int -- Total and pointer words
+         -> ClosureInfo
+mkConInfo is_static data_con tot_wds ptr_wds
+   = ConInfo { closureSMRep = sm_rep,
+               closureCon = data_con }
+  where
+    sm_rep = chooseSMRep is_static (mkConLFInfo data_con) tot_wds ptr_wds
+\end{code}
+
+%************************************************************************
+%*                                                                     *
 \subsection[ClosureInfo-sizes]{Functions about closure {\em sizes}}
 %*                                                                     *
 %************************************************************************
 
 \begin{code}
-closureSize :: ClosureInfo -> HeapOffset
+closureSize :: ClosureInfo -> WordOff
 closureSize cl_info = fixedHdrSize + closureNonHdrSize cl_info
 
-closureNonHdrSize :: ClosureInfo -> Int
+closureNonHdrSize :: ClosureInfo -> WordOff
 closureNonHdrSize cl_info
   = tot_wds + computeSlopSize tot_wds 
                              (closureSMRep cl_info)
@@ -302,24 +355,24 @@ closureNeedsUpdSpace (ClosureInfo { closureLFInfo =
                                        LFThunk TopLevel _ _ _ _ }) = True
 closureNeedsUpdSpace cl_info = closureUpdReqd cl_info
 
-slopSize :: ClosureInfo -> Int
+slopSize :: ClosureInfo -> WordOff
 slopSize cl_info
   = computeSlopSize (closureGoodStuffSize cl_info)
                    (closureSMRep cl_info)
                    (closureNeedsUpdSpace cl_info)
 
-closureGoodStuffSize :: ClosureInfo -> Int
+closureGoodStuffSize :: ClosureInfo -> WordOff
 closureGoodStuffSize cl_info
   = let (ptrs, nonptrs) = sizes_from_SMRep (closureSMRep cl_info)
     in ptrs + nonptrs
 
-closurePtrsSize :: ClosureInfo -> Int
+closurePtrsSize :: ClosureInfo -> WordOff
 closurePtrsSize cl_info
   = let (ptrs, _) = sizes_from_SMRep (closureSMRep cl_info)
     in ptrs
 
 -- not exported:
-sizes_from_SMRep :: SMRep -> (Int,Int)
+sizes_from_SMRep :: SMRep -> (WordOff,WordOff)
 sizes_from_SMRep (GenericRep _ ptrs nonptrs _)   = (ptrs, nonptrs)
 sizes_from_SMRep BlackHoleRep                   = (0, 0)
 \end{code}
@@ -353,7 +406,7 @@ Static closures have an extra ``static link field'' at the end, but we
 don't bother taking that into account here.
 
 \begin{code}
-computeSlopSize :: Int -> SMRep -> Bool -> Int
+computeSlopSize :: WordOff -> SMRep -> Bool -> WordOff
 
 computeSlopSize tot_wds (GenericRep _ _ _ _) True              -- Updatable
   = max 0 (mIN_UPD_SIZE - tot_wds)
@@ -370,129 +423,6 @@ computeSlopSize tot_wds BlackHoleRep _                    -- Updatable
 
 %************************************************************************
 %*                                                                     *
-\subsection[layOutDynClosure]{Lay out a closure}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-layOutDynClosure, layOutStaticClosure
-       :: Id                       -- STG identifier of this closure
-       -> (a -> PrimRep)           -- how to get a PrimRep for the fields
-       -> [a]                      -- the "things" being layed out
-       -> LambdaFormInfo           -- what sort of closure it is
-       -> C_SRT                    -- its SRT
-       -> String                   -- closure description
-       -> (ClosureInfo,            -- info about the closure
-           [(a, VirtualHeapOffset)])   -- things w/ offsets pinned on them
-
-layOutDynClosure    = layOutClosure False
-layOutStaticClosure = layOutClosure True
-
-layOutStaticNoFVClosure id lf_info srt_info descr
-  = fst (layOutClosure True id (panic "kind_fn") [] lf_info srt_info descr)
-
-layOutClosure
-       :: Bool                     -- True <=> static closure
-       -> Id                       -- STG identifier of this closure
-       -> (a -> PrimRep)           -- how to get a PrimRep for the fields
-       -> [a]                      -- the "things" being layed out
-       -> LambdaFormInfo           -- what sort of closure it is
-       -> C_SRT                    -- its SRT
-       -> String                   -- closure description
-       -> (ClosureInfo,            -- info about the closure
-           [(a, VirtualHeapOffset)])   -- things w/ offsets pinned on them
-
-layOutClosure is_static id kind_fn things lf_info srt_info descr
-  = (ClosureInfo { closureName = name, 
-                  closureLFInfo = lf_info,
-                  closureSMRep = sm_rep, 
-                  closureSRT = srt_info,
-                  closureType = idType id,
-                  closureDescr = descr },
-     things_w_offsets)
-  where
-    name = idName id
-    (tot_wds,           -- #ptr_wds + #nonptr_wds
-     ptr_wds,           -- #ptr_wds
-     things_w_offsets) = mkVirtHeapOffsets kind_fn things
-    sm_rep = chooseSMRep is_static lf_info tot_wds ptr_wds
-
-
-layOutDynConstr, layOutStaticConstr
-       :: DataCon      
-       -> (a -> PrimRep)
-       -> [a]
-       -> (ClosureInfo,
-           [(a,VirtualHeapOffset)])
-
-layOutDynConstr    = layOutConstr False
-layOutStaticConstr = layOutConstr True
-
-layOutConstr is_static data_con kind_fn args
-   = (ConInfo { closureSMRep = sm_rep,
-               closureCon = data_con },
-      things_w_offsets)
-  where
-    (tot_wds,           -- #ptr_wds + #nonptr_wds
-     ptr_wds,           -- #ptr_wds
-     things_w_offsets) = mkVirtHeapOffsets kind_fn args
-    sm_rep = chooseSMRep is_static (mkConLFInfo data_con) tot_wds ptr_wds
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[mkStaticClosure]{Make a static closure}
-%*                                                                     *
-%************************************************************************
-
-Make a static closure, adding on any extra padding needed for CAFs,
-and adding a static link field if necessary.
-
-\begin{code}
-mkStaticClosure lbl cl_info ccs fields cafrefs
-  | opt_SccProfilingOn =
-            CStaticClosure
-               lbl
-               cl_info
-               (mkCCostCentreStack ccs)
-               all_fields
-  | otherwise =
-            CStaticClosure
-               lbl
-               cl_info
-               (panic "absent cc")
-               all_fields
-
-   where
-    all_fields = fields ++ padding_wds ++ static_link_field
-
-    upd_reqd = closureUpdReqd cl_info
-
-    -- for the purposes of laying out the static closure, we consider all
-    -- thunks to be "updatable", so that the static link field is always
-    -- in the same place.
-    padding_wds
-       | not upd_reqd = []
-       | otherwise    = replicate n (mkIntCLit 0) -- a bunch of 0s
-       where n = max 0 (mIN_UPD_SIZE - length fields)
-
-       -- We always have a static link field for a thunk, it's used to
-       -- save the closure's info pointer when we're reverting CAFs
-       -- (see comment in Storage.c)
-    static_link_field
-       | upd_reqd || staticClosureNeedsLink cl_info = [static_link_value]
-       | otherwise                                  = []
-
-       -- for a static constructor which has NoCafRefs, we set the
-       -- static link field to a non-zero value so the garbage
-       -- collector will ignore it.
-    static_link_value
-       | cafrefs       = mkIntCLit 0
-       | otherwise     = mkIntCLit 1
-\end{code}
-
-%************************************************************************
-%*                                                                     *
 \subsection[SMreps]{Choosing SM reps}
 %*                                                                     *
 %************************************************************************
@@ -501,23 +431,23 @@ mkStaticClosure lbl cl_info ccs fields cafrefs
 chooseSMRep
        :: Bool                 -- True <=> static closure
        -> LambdaFormInfo
-       -> Int -> Int           -- Tot wds, ptr wds
+       -> WordOff -> WordOff   -- Tot wds, ptr wds
        -> SMRep
 
 chooseSMRep is_static lf_info tot_wds ptr_wds
   = let
         nonptr_wds   = tot_wds - ptr_wds
-        closure_type = getClosureType is_static tot_wds ptr_wds lf_info
+        closure_type = getClosureType is_static ptr_wds lf_info
     in
     GenericRep is_static ptr_wds nonptr_wds closure_type       
 
--- we *do* get non-updatable top-level thunks sometimes.  eg. f = g
+-- We *do* get non-updatable top-level thunks sometimes.  eg. f = g
 -- gets compiled to a jump to g (if g has non-zero arity), instead of
 -- messing around with update frames and PAPs.  We set the closure type
 -- to FUN_STATIC in this case.
 
-getClosureType :: Bool -> Int -> Int -> LambdaFormInfo -> ClosureType
-getClosureType is_static tot_wds ptr_wds lf_info
+getClosureType :: Bool -> WordOff -> LambdaFormInfo -> ClosureType
+getClosureType is_static ptr_wds lf_info
   = case lf_info of
        LFCon con | is_static && ptr_wds == 0   -> ConstrNoCaf
                  | otherwise                   -> Constr
@@ -529,42 +459,6 @@ getClosureType is_static tot_wds ptr_wds lf_info
 
 %************************************************************************
 %*                                                                     *
-\subsection[mkVirtHeapOffsets]{Assigning heap offsets in a closure}
-%*                                                                     *
-%************************************************************************
-
-@mkVirtHeapOffsets@ (the heap version) always returns boxed things with
-smaller offsets than the unboxed things, and furthermore, the offsets in
-the result list
-
-\begin{code}
-mkVirtHeapOffsets :: 
-         (a -> PrimRep)        -- To be able to grab kinds;
-                               --      w/ a kind, we can find boxedness
-         -> [a]                -- Things to make offsets for
-         -> (Int,              -- *Total* number of words allocated
-             Int,              -- Number of words allocated for *pointers*
-             [(a, VirtualHeapOffset)])
-                               -- Things with their offsets from start of 
-                               --  object in order of increasing offset
-
--- First in list gets lowest offset, which is initial offset + 1.
-
-mkVirtHeapOffsets kind_fun things
-  = let (ptrs, non_ptrs)             = separateByPtrFollowness kind_fun things
-       (wds_of_ptrs, ptrs_w_offsets) = mapAccumL computeOffset 0 ptrs
-       (tot_wds, non_ptrs_w_offsets) = mapAccumL computeOffset wds_of_ptrs non_ptrs
-    in
-       (tot_wds, wds_of_ptrs, ptrs_w_offsets ++ non_ptrs_w_offsets)
-  where
-    computeOffset wds_so_far thing
-      = (wds_so_far + (getPrimRepSize . kind_fun) thing,
-        (thing, fixedHdrSize + wds_so_far)
-       )
-\end{code}
-
-%************************************************************************
-%*                                                                     *
 \subsection[ClosureInfo-4-questions]{Four major questions about @ClosureInfo@}
 %*                                                                     *
 %************************************************************************
@@ -572,13 +466,10 @@ mkVirtHeapOffsets kind_fun things
 Be sure to see the stg-details notes about these...
 
 \begin{code}
-nodeMustPointToIt :: LambdaFormInfo -> FCode Bool
-nodeMustPointToIt lf_info
-
-  = case lf_info of
-       LFReEntrant top _ no_fvs _ -> returnFC (
-           not no_fvs ||   -- Certainly if it has fvs we need to point to it
-           isNotTopLevel top
+nodeMustPointToIt :: LambdaFormInfo -> Bool
+nodeMustPointToIt (LFReEntrant top _ no_fvs _)
+  = not no_fvs ||   -- Certainly if it has fvs we need to point to it
+    isNotTopLevel top
                    -- If it is not top level we will point to it
                    --   We can have a \r closure with no_fvs which
                    --   is not top level as special case cgRhsClosure
@@ -587,9 +478,8 @@ nodeMustPointToIt lf_info
                -- For lex_profiling we also access the cost centre for a
                -- non-inherited function i.e. not top level
                -- the  not top  case above ensures this is ok.
-           )
 
-       LFCon _ -> returnFC True
+nodeMustPointToIt (LFCon _) = True
 
        -- Strictly speaking, the above two don't need Node to point
        -- to it if the arity = 0.  But this is a *really* unlikely
@@ -602,9 +492,8 @@ nodeMustPointToIt lf_info
        -- having Node point to the result of an update.  SLPJ
        -- 27/11/92.
 
-       LFThunk _ no_fvs updatable NonStandardThunk _
-         -> returnFC (updatable || not no_fvs || opt_SccProfilingOn)
-
+nodeMustPointToIt (LFThunk _ no_fvs updatable NonStandardThunk _)
+  = updatable || not no_fvs || opt_SccProfilingOn
          -- For the non-updatable (single-entry case):
          --
          -- True if has fvs (in which case we need access to them, and we
@@ -612,15 +501,12 @@ nodeMustPointToIt lf_info
          -- or profiling (in which case we need to recover the cost centre
          --             from inside it)
 
-       LFThunk _ no_fvs updatable some_standard_form_thunk _
-         -> returnFC True
-         -- Node must point to any standard-form thunk.
+nodeMustPointToIt (LFThunk _ no_fvs updatable some_standard_form_thunk _)
+  = True  -- Node must point to any standard-form thunk
 
-       LFUnknown _   -> returnFC True
-       LFBlackHole _ -> returnFC True
-                   -- BH entry may require Node to point
-
-       LFLetNoEscape _ -> returnFC False
+nodeMustPointToIt (LFUnknown _)     = True
+nodeMustPointToIt (LFBlackHole _)   = True    -- BH entry may require Node to point
+nodeMustPointToIt (LFLetNoEscape _) = False 
 \end{code}
 
 The entry conventions depend on the type of closure being entered,
@@ -652,7 +538,7 @@ When black-holing, single-entry closures could also be entered via node
 (rather than directly) to catch double-entry.
 
 \begin{code}
-data CallingConvention
+data CallMethod
   = EnterIt                            -- no args, not a function
 
   | JumpToIt CLabel                    -- no args, not a function, but we
@@ -662,96 +548,72 @@ data CallingConvention
                                        -- zero args to apply to it, so just
                                        -- return it.
 
+  | ReturnCon DataCon                  -- It's a data constructor, just return it
+
   | SlowCall                           -- Unknown fun, or known fun with
                                        -- too few args.
 
   | DirectEntry                        -- Jump directly, with args in regs
        CLabel                          --   The code label
        Int                             --   Its arity
-       [MagicId]                       --   Its register assignments 
-                                       --      (possibly empty)
-
-getEntryConvention :: Name             -- Function being applied
-                  -> LambdaFormInfo    -- Its info
-                  -> [PrimRep]         -- Available arguments
-                  -> FCode CallingConvention
-
-getEntryConvention name lf_info arg_kinds
- =  nodeMustPointToIt lf_info  `thenFC` \ node_points ->
-    returnFC (
-
-    -- if we're parallel, then we must always enter via node.  The reason
-    -- is that the closure may have been fetched since we allocated it.
-
-    if (node_points && opt_Parallel) then EnterIt else
-
-    -- Commented out by SDM after futher thoughts:
-    --   - the only closure type that can be blackholed is a thunk
-    --   - we already enter thunks via node (unless the closure is
-    --     non-updatable, in which case why is it being re-entered...)
-
-    case lf_info of
-
-       LFReEntrant _ arity _ _ ->
-           if null arg_kinds then
-               if arity == 0 then
-                  EnterIt              -- a non-updatable thunk
-               else 
-                  ReturnIt             -- no args at all
-           else if listLengthCmp arg_kinds arity == LT then
-               SlowCall                -- not enough args
-           else
-               DirectEntry (mkEntryLabel name) arity arg_regs
-         where
-           (arg_regs, _) = assignRegs [node] (take arity arg_kinds)
-               -- we don't use node to pass args now (SDM)
-
-       LFCon con
-           | isNullaryDataCon con
-             -- a real constructor.  Don't bother entering it, just jump
-             -- to the constructor entry code directly.
-                         -> --false:ASSERT (null arg_kinds)    
-                            -- Should have no args (meaning what?)
-                            JumpToIt (mkStaticConEntryLabel (dataConName con))
-
-            | otherwise {- not nullary -}
-                         -> --false:ASSERT (null arg_kinds)    
-                            -- Should have no args (meaning what?)
-                            JumpToIt (mkConEntryLabel (dataConName con))
-
-       LFThunk _ _ updatable std_form_info is_fun
-         -- must always "call" a function-typed thing, cannot just enter it
-         | is_fun -> SlowCall
-         | updatable || opt_DoTickyProfiling  -- to catch double entry
-               || opt_SMP  -- always enter via node on SMP, since the
+
+getCallMethod :: Name          -- Function being applied
+             -> LambdaFormInfo -- Its info
+             -> Int            -- Number of available arguments
+             -> CallMethod
+
+getCallMethod name lf_info n_args
+  | nodeMustPointToIt lf_info && opt_Parallel
+  =    -- If we're parallel, then we must always enter via node.  
+       -- The reason is that the closure may have been         
+       -- fetched since we allocated it.
+    EnterIt
+
+getCallMethod name (LFReEntrant _ arity _ _) n_args
+  | n_args == 0    = ASSERT( arity /= 0 )
+                    ReturnIt   -- No args at all
+  | n_args < arity = SlowCall  -- Not enough args
+  | otherwise      = DirectEntry (enterIdLabel name) arity
+
+getCallMethod name (LFCon con) n_args
+  = ASSERT( n_args == 0 )
+    ReturnCon con
+
+getCallMethod name (LFThunk _ _ updatable std_form_info is_fun) n_args
+  | is_fun     -- Must always "call" a function-typed 
+  = SlowCall   -- thing, cannot just enter it [in eval/apply, the entry code
+               -- is the fast-entry code]
+
+  | updatable || opt_DoTickyProfiling  -- to catch double entry
+             || opt_SMP    -- Always enter via node on SMP, since the
                            -- thunk might have been blackholed in the 
                            -- meantime.
-            -> ASSERT(null arg_kinds) EnterIt
-         | otherwise
-            -> ASSERT(null arg_kinds) 
-               JumpToIt (thunkEntryLabel name std_form_info updatable)
-
-       LFUnknown True  -> SlowCall -- might be a function
-       LFUnknown False -> ASSERT2 (null arg_kinds, ppr name <+> ppr arg_kinds) EnterIt -- not a function
-
-       LFBlackHole _ -> SlowCall -- Presumably the black hole has by now
-                                 -- been updated, but we don't know with
-                                 -- what, so we slow call it
-
-       LFLetNoEscape 0
-         -> JumpToIt (mkReturnPtLabel (nameUnique name))
-
-       LFLetNoEscape arity
-         -> if (not (arg_kinds `lengthIs` arity)) then pprPanic "let-no-escape: " (ppr name <+> ppr arity) else
-            DirectEntry (mkReturnPtLabel (nameUnique name)) arity arg_regs
-        where
-           (arg_regs, _) = assignRegs [] arg_kinds
-           -- node never points to a LetNoEscape, see above --SDM
-           --live_regs     = if node_points then [node] else []
-    )
+  = ASSERT( n_args == 0 ) EnterIt
 
-blackHoleOnEntry :: ClosureInfo -> Bool
+  | otherwise  -- Jump direct to code for single-entry thunks
+  = ASSERT( n_args == 0 )
+    JumpToIt (thunkEntryLabel name std_form_info updatable)
+
+getCallMethod name (LFUnknown True) n_args
+  = SlowCall -- might be a function
+
+getCallMethod name (LFUnknown False) n_args
+  = ASSERT2 ( n_args == 0, ppr name <+> ppr n_args ) 
+    EnterIt -- Not a function
 
+getCallMethod name (LFBlackHole _) n_args
+  = SlowCall   -- Presumably the black hole has by now
+               -- been updated, but we don't know with
+               -- what, so we slow call it
+
+getCallMethod name (LFLetNoEscape 0) n_args
+  = JumpToIt (enterReturnPtLabel (nameUnique name))
+
+getCallMethod name (LFLetNoEscape arity) n_args
+  | n_args == arity = DirectEntry (enterReturnPtLabel (nameUnique name)) arity
+  | otherwise = pprPanic "let-no-escape: " (ppr name <+> ppr arity)
+
+blackHoleOnEntry :: ClosureInfo -> Bool
 -- Static closures are never themselves black-holed.
 -- Updatable ones will be overwritten with a CAFList cell, which points to a 
 -- black hole;
@@ -777,11 +639,14 @@ blackHoleOnEntry (ClosureInfo { closureLFInfo = lf_info, closureSMRep = rep })
        other -> panic "blackHoleOnEntry"       -- Should never happen
 
 isStandardFormThunk :: LambdaFormInfo -> Bool
-
 isStandardFormThunk (LFThunk _ _ _ (SelectorThunk _) _) = True
 isStandardFormThunk (LFThunk _ _ _ (ApThunk _) _)      = True
 isStandardFormThunk other_lf_info                      = False
 
+isKnownFun :: LambdaFormInfo -> Bool
+isKnownFun (LFReEntrant _ _ _ _) = True
+isKnownFun (LFLetNoEscape _) = True
+isKnownFun _ = False
 \end{code}
 
 -----------------------------------------------------------------------------
@@ -908,10 +773,9 @@ closureReEntrant :: ClosureInfo -> Bool
 closureReEntrant (ClosureInfo { closureLFInfo = LFReEntrant _ _ _ _ }) = True
 closureReEntrant other_closure = False
 
-closureSemiTag :: ClosureInfo -> Maybe Int
-closureSemiTag (ConInfo { closureCon = data_con })
-      = Just (dataConTag data_con - fIRST_TAG)
-closureSemiTag _ = Nothing
+isConstrClosure_maybe :: ClosureInfo -> Maybe DataCon
+isConstrClosure_maybe (ConInfo { closureCon = data_con }) = Just data_con
+isConstrClosure_maybe _                                  = Nothing
 
 closureFunInfo :: ClosureInfo -> Maybe (Int, ArgDescr)
 closureFunInfo (ClosureInfo { closureLFInfo = LFReEntrant _ arity _ arg_desc})
@@ -948,8 +812,7 @@ infoTableLabelFromCI (ClosureInfo { closureName = name,
 
        LFThunk{}      -> mkInfoTableLabel name
 
-       LFReEntrant _ _ _ (ArgGen _ _) -> mkInfoTableLabel name
-       LFReEntrant _ _ _ _             -> mkInfoTableLabel name
+       LFReEntrant _ _ _ _ -> mkInfoTableLabel name
 
        other -> panic "infoTableLabelFromCI"
 
@@ -964,50 +827,37 @@ mkConInfoPtr con rep
   where
     name = dataConName con
 
-mkConEntryPtr :: DataCon -> SMRep -> CLabel
-mkConEntryPtr con rep
-  | isStaticRep rep = mkStaticConEntryLabel (dataConName con)
-  | otherwise       = mkConEntryLabel       (dataConName con)
-
 closureLabelFromCI (ClosureInfo { closureName = nm }) = mkClosureLabel nm
 closureLabelFromCI _ = panic "closureLabelFromCI"
 
-entryLabelFromCI :: ClosureInfo -> CLabel
-entryLabelFromCI (ClosureInfo { closureName = id, 
-                               closureLFInfo = lf_info, 
-                               closureSMRep = rep })
-  = case lf_info of
-       LFThunk _ _ upd_flag std_form_info _ -> 
-               thunkEntryLabel id std_form_info upd_flag
-       other -> mkEntryLabel id
-
-entryLabelFromCI (ConInfo { closureCon = con, closureSMRep = rep })
-  = mkConEntryPtr con rep
-
-
 -- thunkEntryLabel is a local help function, not exported.  It's used from both
--- entryLabelFromCI and getEntryConvention.
+-- entryLabelFromCI and getCallMethod.
 
 thunkEntryLabel thunk_id (ApThunk arity) is_updatable
-  = mkApEntryLabel is_updatable arity
+  = enterApLabel is_updatable arity
 thunkEntryLabel thunk_id (SelectorThunk offset) upd_flag
-  = mkSelectorEntryLabel upd_flag offset
+  = enterSelectorLabel upd_flag offset
 thunkEntryLabel thunk_id _ is_updatable
-  = mkEntryLabel thunk_id
-\end{code}
+  = enterIdLabel thunk_id
 
-\begin{code}
-allocProfilingMsg :: ClosureInfo -> FastString
-allocProfilingMsg ConInfo{} = FSLIT("TICK_ALLOC_CON")
-allocProfilingMsg ClosureInfo{ closureLFInfo = lf_info }
-  = case lf_info of
-      LFReEntrant _ _ _ _   -> FSLIT("TICK_ALLOC_FUN")
-      LFThunk _ _ True _ _  -> FSLIT("TICK_ALLOC_UP_THK")  -- updatable
-      LFThunk _ _ False _ _ -> FSLIT("TICK_ALLOC_SE_THK")  -- nonupdatable
-      LFBlackHole _        -> FSLIT("TICK_ALLOC_BH")
-      _                            -> panic "allocProfilingMsg"
+enterApLabel is_updatable arity
+  | tablesNextToCode = mkApInfoTableLabel is_updatable arity
+  | otherwise        = mkApEntryLabel is_updatable arity
+
+enterSelectorLabel upd_flag offset
+  | tablesNextToCode = mkSelectorInfoLabel upd_flag offset
+  | otherwise        = mkSelectorEntryLabel upd_flag offset
+
+enterIdLabel id
+  | tablesNextToCode = mkInfoTableLabel id
+  | otherwise        = mkEntryLabel id
+
+enterReturnPtLabel name
+  | tablesNextToCode = mkReturnInfoLabel name
+  | otherwise        = mkReturnPtLabel name
 \end{code}
 
+
 We need a black-hole closure info to pass to @allocDynClosure@ when we
 want to allocate the black hole on entry to a CAF.  These are the only
 ways to build an LFBlackHole, maintaining the invariant that it really
@@ -1051,7 +901,12 @@ The type is determined from the type information stored with the @Id@
 in the closure info using @closureTypeDescr@.
 
 \begin{code}
-closureTypeDescr :: ClosureInfo -> String
+closureValDescr, closureTypeDescr :: ClosureInfo -> String
+closureValDescr (ClosureInfo {closureDescr = descr}) 
+  = descr
+closureValDescr (ConInfo {closureCon = con})
+  = occNameUserString (getOccName con)
+
 closureTypeDescr (ClosureInfo { closureType = ty })
   = getTyDescription ty
 closureTypeDescr (ConInfo { closureCon = data_con })
@@ -1079,268 +934,4 @@ getPredTyDescription (ClassP cl tys) = getOccString cl
 getPredTyDescription (IParam ip ty)  = getOccString (ipNameName ip)
 \end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection{Making argument bitmaps}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
--- bring in ARG_P, ARG_N, etc.
-#include "../includes/StgFun.h"
-
-data ArgDescr
-  = ArgSpec
-       !Int            -- ARG_P, ARG_N, ...
-  | ArgGen 
-       CLabel          -- label for a slow-entry point
-       Liveness        -- the arg bitmap: describes pointedness of arguments
-
-mkArgDescr :: Name -> [Id] -> ArgDescr
-mkArgDescr nm args = argDescr nm (filter nonVoidRep (map idPrimRep args))
-  where nonVoidRep VoidRep = False
-       nonVoidRep _ = True
-
-argDescr nm [PtrRep]    = ArgSpec ARG_P
-argDescr nm [FloatRep]  = ArgSpec ARG_F
-argDescr nm [DoubleRep] = ArgSpec ARG_D
-argDescr nm [r] | is64BitRep r  = ArgSpec ARG_L
-argDescr nm [r] | isNonPtrRep r = ArgSpec ARG_N
-
-argDescr nm [r1,r2] | isNonPtrRep r1 && isNonPtrRep r2 = ArgSpec ARG_NN
-argDescr nm [r1,PtrRep] | isNonPtrRep r1 = ArgSpec ARG_NP
-argDescr nm [PtrRep,r1] | isNonPtrRep r1 = ArgSpec ARG_PN
-argDescr nm [PtrRep,PtrRep] = ArgSpec ARG_PP
-
-argDescr nm [r1,r2,r3] | isNonPtrRep r1 && isNonPtrRep r2 && isNonPtrRep r3 = ArgSpec ARG_NNN
-argDescr nm [r1,r2,PtrRep] | isNonPtrRep r1 && isNonPtrRep r2 = ArgSpec ARG_NNP
-argDescr nm [r1,PtrRep,r2] | isNonPtrRep r1 && isNonPtrRep r2 = ArgSpec ARG_NPN
-argDescr nm [r1,PtrRep,PtrRep] | isNonPtrRep r1 = ArgSpec ARG_NPP
-argDescr nm [PtrRep,r1,r2] | isNonPtrRep r1 && isNonPtrRep r2 = ArgSpec ARG_PNN
-argDescr nm [PtrRep,r1,PtrRep] | isNonPtrRep r1 = ArgSpec ARG_PNP
-argDescr nm [PtrRep,PtrRep,r1] | isNonPtrRep r1 = ArgSpec ARG_PPN
-argDescr nm [PtrRep,PtrRep,PtrRep] = ArgSpec ARG_PPP
-
-argDescr nm [PtrRep,PtrRep,PtrRep,PtrRep] = ArgSpec ARG_PPPP
-argDescr nm [PtrRep,PtrRep,PtrRep,PtrRep,PtrRep] = ArgSpec ARG_PPPPP
-argDescr nm [PtrRep,PtrRep,PtrRep,PtrRep,PtrRep,PtrRep] = ArgSpec ARG_PPPPPP
-
-argDescr name reps = ArgGen (mkSlowEntryLabel name) liveness
- where bitmap = argBits reps
-       lbl = mkBitmapLabel name
-       liveness = Liveness lbl (length bitmap) (mkBitmap bitmap) 
-
-argBits [] = []
-argBits (rep : args)
-  | isFollowableRep rep = False : argBits args
-  | otherwise = take (getPrimRepSize rep) (repeat True) ++ argBits args
-\end{code}
-
 
-%************************************************************************
-%*                                                                     *
-\subsection{Generating info tables}
-%*                                                                     *
-%************************************************************************
-
-Here we make a concrete info table, represented as a list of CAddrMode
-(it can't be simply a list of Word, because the SRT field is
-represented by a label+offset expression).
-
-\begin{code}
-mkInfoTable :: ClosureInfo -> [CAddrMode]
-mkInfoTable cl_info
- | tablesNextToCode = extra_bits ++ std_info
- | otherwise        = std_info ++ extra_bits
- where
-    std_info = mkStdInfoTable entry_amode
-                 ty_descr_amode cl_descr_amode cl_type srt_len layout_amode
-
-    entry_amode = CLbl (entryLabelFromCI cl_info) CodePtrRep 
-
-    closure_descr = 
-       case cl_info of
-         ClosureInfo { closureDescr = descr } -> descr
-         ConInfo { closureCon = con } -> occNameUserString (getOccName con)
-
-    ty_descr_amode = CLit (MachStr (mkFastString (closureTypeDescr cl_info)))
-    cl_descr_amode = CLit (MachStr (mkFastString closure_descr))
-
-    cl_type = getSMRepClosureTypeInt (closureSMRep cl_info)
-
-    srt = closureSRT cl_info        
-    needs_srt = needsSRT srt
-
-    semi_tag = closureSemiTag cl_info
-    is_con = isJust semi_tag
-
-    (srt_label,srt_len)
-       | Just tag <- semi_tag = (mkIntCLit 0, fromIntegral tag) -- constructor
-       | otherwise = 
-         case srt of
-           NoC_SRT -> (mkIntCLit 0, 0)
-           C_SRT lbl off bitmap -> 
-             (CAddr (CIndex (CLbl lbl DataPtrRep) (mkIntCLit off) WordRep),
-              bitmap)
-
-    ptrs  = closurePtrsSize cl_info
-    nptrs = size - ptrs
-    size  = closureNonHdrSize cl_info
-
-    layout_info :: StgWord
-#ifdef WORDS_BIGENDIAN
-    layout_info = (fromIntegral ptrs `shiftL` hALF_WORD) .|. fromIntegral nptrs
-#else 
-    layout_info = (fromIntegral ptrs) .|. (fromIntegral nptrs `shiftL` hALF_WORD)
-#endif      
-
-    layout_amode = mkWordCLit layout_info
-
-    extra_bits
-       | is_fun    = fun_extra_bits
-       | is_con    = []
-       | needs_srt = [srt_label]
-       | otherwise = []
-
-    maybe_fun_stuff = closureFunInfo cl_info
-    is_fun = isJust maybe_fun_stuff
-    (Just (arity, arg_descr)) = maybe_fun_stuff
-
-    fun_extra_bits
-       | tablesNextToCode = reg_fun_extra_bits
-       | otherwise        = reverse reg_fun_extra_bits
-
-    reg_fun_extra_bits
-       | ArgGen slow_lbl liveness <- arg_descr
-               = [
-                  CLbl slow_lbl CodePtrRep, 
-                  livenessToAddrMode liveness,
-                  srt_label,
-                  fun_amode
-                 ]
-       | needs_srt = [srt_label, fun_amode]
-       | otherwise = [fun_amode]
-
-#ifdef WORDS_BIGENDIAN
-    fun_desc = (fromIntegral fun_type `shiftL` hALF_WORD) .|. fromIntegral arity
-#else 
-    fun_desc = (fromIntegral fun_type) .|. (fromIntegral arity `shiftL` hALF_WORD)
-#endif
-
-    fun_amode = mkWordCLit fun_desc
-
-    fun_type = case arg_descr of
-               ArgSpec n -> n
-               ArgGen _ (Liveness _ size _)
-                       | size <= mAX_SMALL_BITMAP_SIZE -> ARG_GEN
-                       | otherwise                     -> ARG_GEN_BIG
-
--- Return info tables come in two flavours: direct returns and
--- vectored returns.
-
-mkRetInfoTable :: CLabel -> C_SRT -> Liveness -> [CAddrMode]
-mkRetInfoTable entry_lbl srt liveness
- = mkBitmapInfoTable (CLbl entry_lbl CodePtrRep) srt liveness []
-
-mkVecInfoTable :: [CAddrMode] -> C_SRT -> Liveness -> [CAddrMode]
-mkVecInfoTable vector srt liveness
- = mkBitmapInfoTable zero_amode srt liveness vector
-
-mkBitmapInfoTable
-   :: CAddrMode
-   -> C_SRT -> Liveness
-   -> [CAddrMode]
-   -> [CAddrMode]
-mkBitmapInfoTable entry_amode srt liveness vector
- | tablesNextToCode = extra_bits ++ std_info
- | otherwise        = std_info ++ extra_bits
- where
-   std_info = mkStdInfoTable entry_amode zero_amode zero_amode 
-               cl_type srt_len liveness_amode
-
-   liveness_amode = livenessToAddrMode liveness
-
-   (srt_label,srt_len) =
-         case srt of
-           NoC_SRT -> (mkIntCLit 0, 0)
-           C_SRT lbl off bitmap -> 
-                   (CAddr (CIndex (CLbl lbl DataPtrRep) (mkIntCLit off) WordRep),
-                    bitmap)
-
-   cl_type = case (null vector, isBigLiveness liveness) of
-               (True, True)   -> rET_BIG
-               (True, False)  -> rET_SMALL
-               (False, True)  -> rET_VEC_BIG
-               (False, False) -> rET_VEC_SMALL
-
-   srt_bit | needsSRT srt || not (null vector) = [srt_label]
-          | otherwise = []
-
-   extra_bits | tablesNextToCode = reverse vector ++ srt_bit
-              | otherwise        = srt_bit ++ vector
-
--- The standard bits of an info table.  This part of the info table
--- corresponds to the StgInfoTable type defined in InfoTables.h.
-
-mkStdInfoTable
-   :: CAddrMode                                -- entry label
-   -> CAddrMode                                -- closure type descr (profiling)
-   -> CAddrMode                                -- closure descr (profiling)
-   -> Int                              -- closure type
-   -> StgHalfWord                      -- SRT length
-   -> CAddrMode                                -- layout field
-   -> [CAddrMode]
-mkStdInfoTable entry_lbl type_descr closure_descr cl_type srt_len layout_amode
- = std_info
- where  
-    std_info
-       | tablesNextToCode = std_info'
-       | otherwise        = entry_lbl : std_info'
-
-    std_info' =
-         -- par info
-         prof_info ++
-         -- ticky info
-         -- debug info
-         [layout_amode] ++
-         CLit (MachWord (fromIntegral type_info)) :
-         []
-
-    prof_info 
-       | opt_SccProfilingOn = [ type_descr, closure_descr ]
-       | otherwise = []
-
-    -- sigh: building up the info table is endian-dependent.
-    -- ToDo: do this using .byte and .word directives.
-    type_info :: StgWord
-#ifdef WORDS_BIGENDIAN
-    type_info = (fromIntegral cl_type `shiftL` hALF_WORD) .|.
-               (fromIntegral srt_len)
-#else 
-    type_info = (fromIntegral cl_type) .|.
-               (fromIntegral srt_len `shiftL` hALF_WORD)
-#endif
-
-isBigLiveness (Liveness _ size _) = size > mAX_SMALL_BITMAP_SIZE
-
-livenessToAddrMode :: Liveness -> CAddrMode
-livenessToAddrMode (Liveness lbl size bits)
-       | size <= mAX_SMALL_BITMAP_SIZE = small
-       | otherwise = CLbl lbl DataPtrRep
-       where
-         small = mkWordCLit (fromIntegral size .|. (small_bits `shiftL` bITMAP_BITS_SHIFT))
-         small_bits = case bits of 
-                       []  -> 0
-                       [b] -> fromIntegral b
-                       _   -> panic "livenessToAddrMode"
-
-zero_amode = mkIntCLit 0
-
--- IA64 mangler doesn't place tables next to code
-tablesNextToCode :: Bool
-#ifdef ia64_TARGET_ARCH
-tablesNextToCode = False
-#else
-tablesNextToCode = not opt_Unregisterised
-#endif
-\end{code}
index 1c817ae..d7f2f70 100644 (file)
@@ -19,39 +19,41 @@ module CodeGen ( codeGen ) where
 
 #include "HsVersions.h"
 
+import DriverState     ( v_Build_tag, v_MainModIs )
+
 -- Kludge (??) so that CgExpr is reached via at least one non-SOURCE
 -- import.  Before, that wasn't the case, and CM therefore didn't 
 -- bother to compile it.
 import CgExpr           ( {-NOTHING!-} )       -- DO NOT DELETE THIS IMPORT
+import CgProf
+import CgMonad
+import CgBindery       ( CgIdInfo, addBindC, addBindsC, getCgIdInfo,
+                         cgIdInfoId )
+import CgClosure       ( cgTopRhsClosure )
+import CgCon           ( cgTopRhsCon, cgTyCon )
+import CgUtils         ( cmmRegOffW, emitRODataLits, cmmNeWord, emitRtsCall )
+
+import CLabel          ( mkSRTLabel, mkClosureLabel, moduleRegdLabel,
+                         mkPlainModuleInitLabel, mkModuleInitLabel )
+import Cmm
+import CmmUtils                ( zeroCLit, mkIntCLit, mkLblExpr )
+import PprCmm          ( pprCmms )
+import MachOp          ( wordRep, MachHint(..) )
 
-import DriverState     ( v_Build_tag, v_MainModIs )
 import StgSyn
-import CgMonad
-import AbsCSyn
 import PrelNames       ( gHC_PRIM, rOOT_MAIN, mAIN_Name, pREL_TOP_HANDLER )
-import CLabel          ( mkSRTLabel, mkClosureLabel, 
-                         mkPlainModuleInitLabel, mkModuleInitLabel )
-import PprAbsC         ( dumpRealC )
-import AbsCUtils       ( mkAbstractCs, flattenAbsC )
-import CgBindery       ( CgIdInfo, addBindC, addBindsC, getCAddrModeAndInfo )
-import CgClosure       ( cgTopRhsClosure )
-import CgCon           ( cgTopRhsCon )
-import CgConTbls       ( genStaticConBits )
-import ClosureInfo     ( mkClosureLFInfo )
-import CmdLineOpts     ( DynFlags, DynFlag(..),
-                         opt_SccProfilingOn, opt_EnsureSplittableC )
+import CmdLineOpts     ( DynFlags, DynFlag(..), opt_EnsureSplittableC,
+                         opt_SccProfilingOn )
+
 import HscTypes                ( ForeignStubs(..), TypeEnv, typeEnvTyCons )
 import CostCentre       ( CollectedCCs )
 import Id               ( Id, idName, setIdName )
 import Name            ( nameSrcLoc, nameOccName, nameUnique, isInternalName, mkExternalName )
 import OccName         ( mkLocalOcc )
-import PrimRep         ( PrimRep(..) )
 import TyCon            ( isDataTyCon )
 import Module          ( Module, mkModuleName )
-import BasicTypes      ( TopLevelFlag(..) )
-import UniqSupply      ( mkSplitUniqSupply )
 import ErrUtils                ( dumpIfSet_dyn, showPass )
-import Panic           ( assertPanic )
+import Panic           ( assertPanic, trace )
 import qualified Module ( moduleName )
 
 #ifdef DEBUG
@@ -69,44 +71,37 @@ codeGen :: DynFlags
        -> [Module]             -- directly-imported modules
        -> CollectedCCs         -- (Local/global) cost-centres needing declaring/registering.
        -> [(StgBinding,[(Id,[Id])])]   -- Bindings to convert, with SRTs
-       -> IO AbstractC         -- Output
+       -> IO [Cmm]             -- Output
 
 codeGen dflags this_mod type_env foreign_stubs imported_mods 
        cost_centre_info stg_binds
   = do 
-       showPass dflags "CodeGen"
-       fl_uniqs <- mkSplitUniqSupply 'f'
-       way <- readIORef v_Build_tag
-       mb_main_mod <- readIORef v_MainModIs
-
-       let
-           tycons         = typeEnvTyCons type_env
-           data_tycons    = filter isDataTyCon tycons
-
-       mapM_ (\x -> seq x (return ())) data_tycons
-
-       let
-
-           cinfo          = MkCompInfo this_mod
-
-           datatype_stuff = genStaticConBits cinfo data_tycons
-           code_stuff     = initC cinfo (mapCs cgTopBinding stg_binds)
-           init_stuff     = mkModuleInit way cost_centre_info 
-                                         this_mod mb_main_mod
-                                         foreign_stubs imported_mods
-
-           abstractC = mkAbstractCs [ maybeSplitCode,
-                                      init_stuff, 
-                                      code_stuff,
-                                      datatype_stuff]
+  { showPass dflags "CodeGen"
+  ; way <- readIORef v_Build_tag
+  ; mb_main_mod <- readIORef v_MainModIs
+
+  ; let     tycons     = typeEnvTyCons type_env
+           data_tycons = filter isDataTyCon tycons
+
+-- Why?
+--   ; mapM_ (\x -> seq x (return ())) data_tycons
+
+  ; code_stuff <- initC this_mod $ do 
+                       { cmm_binds  <- mapM (getCmm . cgTopBinding) stg_binds
+                       ; cmm_tycons <- mapM cgTyCon data_tycons
+                       ; cmm_init   <- getCmm (mkModuleInit way cost_centre_info 
+                                                    this_mod mb_main_mod
+                                                    foreign_stubs imported_mods)
+                       ; return (cmm_binds ++ concat cmm_tycons ++ [cmm_init]) 
+                       }
                -- Put datatype_stuff after code_stuff, because the
                -- datatype closure table (for enumeration types) to
                -- (say) PrelBase_True_closure, which is defined in
                -- code_stuff
 
-       dumpIfSet_dyn dflags Opt_D_dump_absC "Abstract C" (dumpRealC abstractC)
+  ; dumpIfSet_dyn dflags Opt_D_dump_cmm "Cmm" (pprCmms code_stuff)
 
-       return $! flattenAbsC fl_uniqs abstractC
+  ; return code_stuff }
 \end{code}
 
 %************************************************************************
@@ -115,6 +110,43 @@ codeGen dflags this_mod type_env foreign_stubs imported_mods
 %*                                                                     *
 %************************************************************************
 
+/* -----------------------------------------------------------------------------
+   Module initialisation
+
+   The module initialisation code looks like this, roughly:
+
+       FN(__stginit_Foo) {
+         JMP_(__stginit_Foo_1_p)
+       }
+
+       FN(__stginit_Foo_1_p) {
+       ...
+       }
+
+   We have one version of the init code with a module version and the
+   'way' attached to it.  The version number helps to catch cases
+   where modules are not compiled in dependency order before being
+   linked: if a module has been compiled since any modules which depend on
+   it, then the latter modules will refer to a different version in their
+   init blocks and a link error will ensue.
+
+   The 'way' suffix helps to catch cases where modules compiled in different
+   ways are linked together (eg. profiled and non-profiled).
+
+   We provide a plain, unadorned, version of the module init code
+   which just jumps to the version with the label and way attached.  The
+   reason for this is that when using foreign exports, the caller of
+   startupHaskell() must supply the name of the init function for the "top"
+   module in the program, and we don't want to require that this name
+   has the version and way info appended to it.
+   -------------------------------------------------------------------------- */
+
+We initialise the module tree by keeping a work-stack, 
+       * pointed to by Sp
+       * that grows downward
+       * Sp points to the last occupied slot
+
+
 \begin{code}
 mkModuleInit 
        :: String               -- the "way"
@@ -123,61 +155,95 @@ mkModuleInit
        -> Maybe String         -- Just m ==> we have flag: -main-is Foo.baz 
        -> ForeignStubs
        -> [Module]
-       -> AbstractC
+       -> Code
 mkModuleInit way cost_centre_info this_mod mb_main_mod foreign_stubs imported_mods
-  = let
-       (cc_decls, cc_regs) = mkCostCentreStuff cost_centre_info
+  = do {       
 
-       register_foreign_exports 
-               = case foreign_stubs of
-                       NoStubs                     -> []
-                       ForeignStubs _ _ _ fe_bndrs -> map mk_export_register fe_bndrs
+       -- Allocate the static boolean that records if this
+       -- module has been registered already
+       ; emitData Data [CmmDataLabel moduleRegdLabel, 
+                        CmmStaticLit zeroCLit]
 
-       mk_export_register bndr
-         = CMacroStmt REGISTER_FOREIGN_EXPORT [lbl]
-         where
-           lbl = CLbl (mkClosureLabel (idName bndr)) PtrRep
-               -- we don't want/need to init GHC.Prim, so filter it out
+       ; emitSimpleProc real_init_lbl $ do
+           {   -- The return-code pops the work stack by 
+               -- incrementing Sp, and then jumpd to the popped item
+             ret_blk <- forkLabelledCode $ stmtsC
+                       [ CmmAssign spReg (cmmRegOffW spReg 1)
+                       , CmmJump (CmmLoad (cmmRegOffW spReg (-1)) wordRep) [] ]
 
-       mk_import_register mod
-           | mod == gHC_PRIM = AbsCNop
-           | otherwise       = CMacroStmt REGISTER_IMPORT [
-                                  CLbl (mkModuleInitLabel mod way) AddrRep
-                               ]
+           ; init_blk <- forkLabelledCode $ do
+                           { mod_init_code; stmtC (CmmBranch ret_blk) }
+                       
+           ; stmtC (CmmCondBranch (cmmNeWord (CmmLit zeroCLit) mod_reg_val)
+                       ret_blk)
+           ; stmtC (CmmBranch init_blk)            
+           }
 
-       extra_imported_mods
-         | Module.moduleName this_mod == main_mod_name = [ pREL_TOP_HANDLER ]
-         | otherwise                                   = [ ]
 
-       register_mod_imports = 
-               map mk_import_register (imported_mods ++ extra_imported_mods)
+           -- Make the "plain" procedure jump to the "real" init procedure
+       ; emitSimpleProc plain_init_lbl jump_to_init
 
        -- When compiling the module in which the 'main' function lives,
+       -- (that is, Module.moduleName this_mod == main_mod_name)
        -- we inject an extra stg_init procedure for stg_init_ZCMain, for the 
        -- RTS to invoke.  We must consult the -main-is flag in case the
        -- user specified a different function to Main.main
-       main_mod_name = case mb_main_mod of
-                         Just mod_name -> mkModuleName mod_name
-                         Nothing       -> mAIN_Name
-       main_init_block
-         | Module.moduleName this_mod /= main_mod_name 
-         = AbsCNop     -- The normal case
-         | otherwise   -- this_mod contains the main function
-         = CCodeBlock (mkPlainModuleInitLabel rOOT_MAIN)
-                      (CJump (CLbl (mkPlainModuleInitLabel this_mod) CodePtrRep))
-                            
-    in
-    mkAbstractCs [
-       cc_decls,
-        CModuleInitBlock (mkPlainModuleInitLabel this_mod)
-                        (mkModuleInitLabel this_mod way)
-                        (mkAbstractCs (register_foreign_exports ++
-                                       cc_regs :
-                                       register_mod_imports)),
-       main_init_block
-    ]
+       ; whenC (Module.moduleName this_mod == main_mod_name)
+               (emitSimpleProc plain_main_init_lbl jump_to_init)
+    }
+  where
+    plain_init_lbl = mkPlainModuleInitLabel this_mod
+    real_init_lbl  = mkModuleInitLabel this_mod way
+    plain_main_init_lbl = mkPlainModuleInitLabel rOOT_MAIN
+
+    jump_to_init = stmtC (CmmJump (mkLblExpr real_init_lbl) [])
+
+    mod_reg_val = CmmLoad (mkLblExpr moduleRegdLabel) wordRep
+
+    main_mod_name = case mb_main_mod of
+                       Just mod_name -> mkModuleName mod_name
+                       Nothing       -> mAIN_Name
+
+    -- Main refers to GHC.TopHandler.runIO, so make sure we call the
+    -- init function for GHC.TopHandler.
+    extra_imported_mods
+       | Module.moduleName this_mod == main_mod_name = [pREL_TOP_HANDLER]
+       | otherwise                                   = []
+
+    mod_init_code = do
+       {       -- Set mod_reg to 1 to record that we've been here
+         stmtC (CmmStore (mkLblExpr moduleRegdLabel) (CmmLit (mkIntCLit 1)))
+
+               -- Now do local stuff
+       ; registerForeignExports foreign_stubs
+       ; initCostCentres cost_centre_info
+       ; mapCs (registerModuleImport way) (imported_mods++extra_imported_mods)
+       } 
+
+
+-----------------------
+registerModuleImport :: String -> Module -> Code
+registerModuleImport way mod 
+  | mod == gHC_PRIM
+  = nopC 
+  | otherwise  -- Push the init procedure onto the work stack
+  = stmtsC [ CmmAssign spReg (cmmRegOffW spReg (-1))
+          , CmmStore (CmmReg spReg) (mkLblExpr (mkModuleInitLabel mod way)) ]
+
+-----------------------
+registerForeignExports :: ForeignStubs -> Code
+registerForeignExports NoStubs 
+  = nopC
+registerForeignExports (ForeignStubs _ _ _ fe_bndrs)
+  = mapM_ mk_export_register fe_bndrs
+  where
+       mk_export_register bndr
+         = emitRtsCall SLIT("getStablePtr") 
+               [ (CmmLit (CmmLabel (mkClosureLabel (idName bndr))), PtrHint) ]
 \end{code}
 
+
+
 Cost-centre profiling: Besides the usual stuff, we must produce
 declarations for the cost-centres defined in this module;
 
@@ -185,28 +251,16 @@ declarations for the cost-centres defined in this module;
 code-generator.)
 
 \begin{code}
-mkCostCentreStuff (local_CCs, extern_CCs, singleton_CCSs)
-  | not opt_SccProfilingOn = (AbsCNop, AbsCNop)
-  | otherwise = 
-       ( mkAbstractCs (
-               map (CCostCentreDecl True)   local_CCs ++
-               map (CCostCentreDecl False)  extern_CCs ++
-               map CCostCentreStackDecl     singleton_CCSs),
-         mkAbstractCs (mkCcRegister local_CCs singleton_CCSs)
-       )
-  where
-    mkCcRegister ccs cc_stacks
-      = let
-           register_ccs       = mkAbstractCs (map mk_register ccs)
-           register_cc_stacks = mkAbstractCs (map mk_register_ccs cc_stacks)
-       in
-       [ register_ccs, register_cc_stacks ]
-      where
-       mk_register cc
-         = CCallProfCCMacro FSLIT("REGISTER_CC") [mkCCostCentre cc]
-
-       mk_register_ccs ccs
-         = CCallProfCCMacro FSLIT("REGISTER_CCS") [mkCCostCentreStack ccs]
+initCostCentres :: CollectedCCs -> Code
+-- Emit the declarations, and return code to register them
+initCostCentres (local_CCs, ___extern_CCs, singleton_CCSs)
+  | not opt_SccProfilingOn = nopC
+  | otherwise
+  = do { mapM_ emitCostCentreDecl       local_CCs
+       ; mapM_ emitCostCentreStackDecl  singleton_CCSs
+       ; mapM_ emitRegisterCC           local_CCs
+       ; mapM_ emitRegisterCCS          singleton_CCSs
+       }
 \end{code}
 
 %************************************************************************
@@ -228,44 +282,37 @@ variable.
 \begin{code}
 cgTopBinding :: (StgBinding,[(Id,[Id])]) -> Code
 cgTopBinding (StgNonRec id rhs, srts)
-  = absC maybeSplitCode                `thenC`
-    maybeExternaliseId id      `thenFC` \ id' ->
-    mapM_ (mkSRT [id']) srts   `thenC`
-    cgTopRhs id' rhs           `thenFC` \ (id, info) ->
-    addBindC id info           `thenC`
-       -- Add the un-externalised Id to the envt, so we
-       -- find it when we look up occurrences
-    nopC
+  = do { id' <- maybeExternaliseId id
+       ; mapM_ (mkSRT [id']) srts
+       ; (id,info) <- cgTopRhs id' rhs
+       ; addBindC id info      -- Add the *un-externalised* Id to the envt,
+                               -- so we find it when we look up occurrences
+       }
 
 cgTopBinding (StgRec pairs, srts)
-  = absC maybeSplitCode                        `thenC`
-    let
-        (bndrs, rhss) = unzip pairs
-    in
-    mapFCs maybeExternaliseId bndrs    `thenFC` \ bndrs' ->
-    let
-       pairs' = zip bndrs' rhss
-    in
-    mapM_ (mkSRT bndrs')  srts         `thenC`
-    fixC (\ new_binds -> 
-               addBindsC new_binds             `thenC`
-               mapFCs ( \ (b,e) -> cgTopRhs b e ) pairs'
-     )  `thenFC` \ new_binds -> 
-     nopC
+  = do { let (bndrs, rhss) = unzip pairs
+       ; bndrs' <- mapFCs maybeExternaliseId bndrs
+       ; let pairs' = zip bndrs' rhss
+       ; mapM_ (mkSRT bndrs')  srts
+       ; new_binds <- fixC (\ new_binds -> do 
+               { addBindsC new_binds
+               ; mapFCs ( \ (b,e) -> cgTopRhs b e ) pairs' })
+       ; nopC }
 
 mkSRT :: [Id] -> (Id,[Id]) -> Code
 mkSRT these (id,[])  = nopC
 mkSRT these (id,ids)
-  = mapFCs remap ids `thenFC` \ ids ->
-    remap id        `thenFC` \ id ->
-    absC (CSRT (mkSRTLabel (idName id)) (map (mkClosureLabel . idName) ids))
+  = do { ids <- mapFCs remap ids
+       ; id  <- remap id
+       ; emitRODataLits (mkSRTLabel (idName id)) 
+                      (map (CmmLabel . mkClosureLabel . idName) ids)
+       }
   where
-       -- sigh, better map all the ids against the environment in case they've
-       -- been externalised (see maybeExternaliseId below).
+       -- Sigh, better map all the ids against the environment in 
+       -- case they've been externalised (see maybeExternaliseId below).
     remap id = case filter (==id) these of
-               [] ->  getCAddrModeAndInfo id 
-                               `thenFC` \ (id, _, _) -> returnFC id
                (id':_) -> returnFC id'
+               [] -> do { info <- getCgIdInfo id; return (cgIdInfoId info) }
 
 -- Urgh!  I tried moving the forkStatics call from the rhss of cgTopRhs
 -- to enclose the listFCs in cgTopBinding, but that tickled the
@@ -280,12 +327,8 @@ cgTopRhs bndr (StgRhsCon cc con args)
 
 cgTopRhs bndr (StgRhsClosure cc bi fvs upd_flag srt args body)
   = ASSERT(null fvs)    -- There should be no free variables
-    let 
-       srt_label = mkSRTLabel (idName bndr)
-       lf_info = mkClosureLFInfo bndr TopLevel [{-no fvs-}] upd_flag args
-    in
-    setSRTLabel srt_label $ 
-      forkStatics (cgTopRhsClosure bndr cc bi srt args body lf_info)
+    setSRTLabel (mkSRTLabel (idName bndr)) $ 
+    forkStatics (cgTopRhsClosure bndr cc bi srt upd_flag args body)
 \end{code}
 
 
@@ -303,21 +346,17 @@ which refers to this name).
 maybeExternaliseId :: Id -> FCode Id
 maybeExternaliseId id
   | opt_EnsureSplittableC,     -- Externalise the name for -split-objs
-    isInternalName name
-  = moduleName                          `thenFC` \ mod ->
-    returnFC (setIdName id (mkExternalName uniq mod new_occ Nothing (nameSrcLoc name)))
-  | otherwise          
-  = returnFC id
+    isInternalName name = do { mod <- moduleName
+                            ; returnFC (setIdName id (externalise mod)) }
+  | otherwise          = returnFC id
   where
-    name       = idName id
-    uniq       = nameUnique name
-    new_occ    = mkLocalOcc uniq (nameOccName name)
+    externalise mod = mkExternalName uniq mod new_occ Nothing loc
+    name    = idName id
+    uniq    = nameUnique name
+    new_occ = mkLocalOcc uniq (nameOccName name)
+    loc     = nameSrcLoc name
        -- We want to conjure up a name that can't clash with any
        -- existing name.  So we generate
        --      Mod_$L243foo
        -- where 243 is the unique.
-
-maybeSplitCode
-  | opt_EnsureSplittableC = CSplitMarker 
-  | otherwise             = AbsCNop
 \end{code}
index 4f53f4b..92b9513 100644 (file)
@@ -8,27 +8,236 @@ Other modules should access this info through ClosureInfo.
 
 \begin{code}
 module SMRep (
+       -- Words and bytes
+       StgWord, StgHalfWord, 
+       hALF_WORD_SIZE, hALF_WORD_SIZE_IN_BITS,
+       WordOff, ByteOff,
+
+       -- Argument/return representations
+       CgRep(..), nonVoidArg,
+       argMachRep, primRepToCgRep, primRepHint,
+       isFollowableArg, isVoidArg, 
+       isFloatingArg, isNonPtrArg, is64BitArg,
+       separateByPtrFollowness,
+       cgRepSizeW, cgRepSizeB,
+       retAddrSizeW,
+
+       typeCgRep, idCgRep, tyConCgRep, typeHint,
+
+       -- Closure repesentation
        SMRep(..), ClosureType(..),
        isStaticRep,
        fixedHdrSize, arrWordsHdrSize, arrPtrsHdrSize,
-        stdItblSize, retItblSize,
-       getSMRepClosureTypeInt,
+       profHdrSize,
+       tablesNextToCode,
+       smRepClosureType, smRepClosureTypeInt,
 
-       rET_SMALL, rET_VEC_SMALL, rET_BIG, rET_VEC_BIG,
-
-       StgWord, StgHalfWord, hALF_WORD,
+       rET_SMALL, rET_VEC_SMALL, rET_BIG, rET_VEC_BIG
     ) where
 
 #include "HsVersions.h"
 #include "../includes/MachDeps.h"
 
-import CmdLineOpts
+import Id              ( Id, idType )
+import Type            ( Type, typePrimRep, PrimRep(..) )
+import TyCon           ( TyCon, tyConPrimRep )
+import MachOp          ( MachRep(..), MachHint(..), wordRep )
+import CmdLineOpts     ( opt_SccProfilingOn, opt_GranMacros, opt_Unregisterised )
 import Constants
 import Outputable
 
 import DATA_WORD
 \end{code}
 
+
+%************************************************************************
+%*                                                                     *
+               Words and bytes
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+type WordOff = Int     -- Word offset, or word count
+type ByteOff = Int     -- Byte offset, or byte count
+\end{code}
+
+StgWord is a type representing an StgWord on the target platform.
+
+\begin{code}
+#if SIZEOF_HSWORD == 4
+type StgWord     = Word32
+type StgHalfWord = Word16
+hALF_WORD_SIZE = 2 :: ByteOff
+hALF_WORD_SIZE_IN_BITS = 16 :: Int
+#elif SIZEOF_HSWORD == 8
+type StgWord     = Word64
+type StgHalfWord = Word32
+hALF_WORD_SIZE = 4 :: ByteOff
+hALF_WORD_SIZE_IN_BITS = 32 :: Int
+#else
+#error unknown SIZEOF_HSWORD
+#endif
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
+                       CgRep
+%*                                                                     *
+%************************************************************************
+
+An CgRep is an abstraction of a Type which tells the code generator
+all it needs to know about the calling convention for arguments (and
+results) of that type.  In particular, the ArgReps of a function's
+arguments are used to decide which of the RTS's generic apply
+functions to call when applying an unknown function.
+
+It contains more information than the back-end data type MachRep,
+so one can easily convert from CgRep -> MachRep.  (Except that
+there's no MachRep for a VoidRep.)
+
+It distinguishes 
+       pointers from non-pointers (we sort the pointers together
+       when building closures)
+
+       void from other types: a void argument is different from no argument
+
+All 64-bit types map to the same CgRep, because they're passed in the
+same register, but a PtrArg is still different from an NonPtrArg
+because the function's entry convention has to take into account the
+pointer-hood of arguments for the purposes of describing the stack on
+entry to the garbage collector.
+
+\begin{code}
+data CgRep 
+  = VoidArg    -- Void
+  | PtrArg     -- Word-sized Ptr
+  | NonPtrArg  -- Word-sized non-pointer
+  | LongArg    -- 64-bit non-pointer
+  | FloatArg   -- 32-bit float
+  | DoubleArg  -- 64-bit float
+  deriving Eq
+
+instance Outputable CgRep where
+    ppr VoidArg   = ptext SLIT("V_")
+    ppr PtrArg    = ptext SLIT("P_")
+    ppr NonPtrArg = ptext SLIT("I_")
+    ppr LongArg   = ptext SLIT("L_")
+    ppr FloatArg  = ptext SLIT("F_")
+    ppr DoubleArg = ptext SLIT("D_")
+
+argMachRep :: CgRep -> MachRep
+argMachRep PtrArg    = wordRep
+argMachRep NonPtrArg = wordRep
+argMachRep LongArg   = I64
+argMachRep FloatArg  = F32
+argMachRep DoubleArg = F64
+argMachRep VoidArg   = panic "argMachRep:VoidRep"
+
+primRepToCgRep :: PrimRep -> CgRep
+primRepToCgRep VoidRep    = VoidArg
+primRepToCgRep PtrRep     = PtrArg
+primRepToCgRep IntRep    = NonPtrArg
+primRepToCgRep WordRep   = NonPtrArg
+primRepToCgRep Int64Rep   = LongArg
+primRepToCgRep Word64Rep  = LongArg
+primRepToCgRep AddrRep    = NonPtrArg
+primRepToCgRep FloatRep   = FloatArg
+primRepToCgRep DoubleRep  = DoubleArg
+
+primRepHint :: PrimRep -> MachHint
+primRepHint VoidRep    = panic "primRepHint:VoidRep"
+primRepHint PtrRep     = PtrHint
+primRepHint IntRep     = SignedHint
+primRepHint WordRep    = NoHint
+primRepHint Int64Rep   = SignedHint
+primRepHint Word64Rep  = NoHint
+primRepHint AddrRep     = PtrHint -- NB! PtrHint, but NonPtrArg
+primRepHint FloatRep   = FloatHint
+primRepHint DoubleRep  = FloatHint
+
+idCgRep :: Id -> CgRep
+idCgRep = typeCgRep . idType
+
+tyConCgRep :: TyCon -> CgRep
+tyConCgRep = primRepToCgRep . tyConPrimRep
+
+typeCgRep :: Type -> CgRep
+typeCgRep = primRepToCgRep . typePrimRep
+
+typeHint :: Type -> MachHint
+typeHint = primRepHint . typePrimRep
+\end{code}
+
+Whether or not the thing is a pointer that the garbage-collector
+should follow. Or, to put it another (less confusing) way, whether
+the object in question is a heap object. 
+
+Depending on the outcome, this predicate determines what stack
+the pointer/object possibly will have to be saved onto, and the
+computation of GC liveness info.
+
+\begin{code}
+isFollowableArg :: CgRep -> Bool  -- True <=> points to a heap object
+isFollowableArg PtrArg  = True
+isFollowableArg other = False
+
+isVoidArg :: CgRep -> Bool
+isVoidArg VoidArg = True
+isVoidArg other   = False
+
+nonVoidArg :: CgRep -> Bool
+nonVoidArg VoidArg = False
+nonVoidArg other   = True
+
+-- isFloatingArg is used to distinguish @Double@ and @Float@ which
+-- cause inadvertent numeric conversions if you aren't jolly careful.
+-- See codeGen/CgCon:cgTopRhsCon.
+
+isFloatingArg :: CgRep -> Bool
+isFloatingArg DoubleArg = True
+isFloatingArg FloatArg  = True
+isFloatingArg _         = False
+
+isNonPtrArg :: CgRep -> Bool
+-- Identify anything which is one word large and not a pointer.
+isNonPtrArg NonPtrArg = True
+isNonPtrArg other     = False
+
+is64BitArg :: CgRep -> Bool
+is64BitArg LongArg = True
+is64BitArg _       = False
+\end{code}
+
+\begin{code}
+separateByPtrFollowness :: [(CgRep,a)] -> ([(CgRep,a)], [(CgRep,a)])
+-- Returns (ptrs, non-ptrs)
+separateByPtrFollowness things
+  = sep_things things [] []
+    -- accumulating params for follow-able and don't-follow things...
+  where
+    sep_things []             bs us = (reverse bs, reverse us)
+    sep_things ((PtrArg,a):ts) bs us = sep_things ts ((PtrArg,a):bs) us
+    sep_things (t         :ts) bs us = sep_things ts bs                     (t:us)
+\end{code}
+
+\begin{code}
+cgRepSizeB :: CgRep -> ByteOff
+cgRepSizeB DoubleArg = dOUBLE_SIZE
+cgRepSizeB LongArg   = wORD64_SIZE
+cgRepSizeB VoidArg   = 0
+cgRepSizeB _         = wORD_SIZE
+
+cgRepSizeW :: CgRep -> ByteOff
+cgRepSizeW DoubleArg = dOUBLE_SIZE `quot` wORD_SIZE
+cgRepSizeW LongArg   = wORD64_SIZE `quot` wORD_SIZE
+cgRepSizeW VoidArg   = 0
+cgRepSizeW _         = 1
+
+retAddrSizeW :: WordOff
+retAddrSizeW = 1       -- One word
+\end{code}
+
 %************************************************************************
 %*                                                                     *
 \subsubsection[SMRep-datatype]{@SMRep@---storage manager representation}
@@ -59,44 +268,32 @@ data ClosureType   -- Corresponds 1-1 with the varieties of closures
 Size of a closure header.
 
 \begin{code}
-fixedHdrSize :: Int{-words-}
+fixedHdrSize :: WordOff
 fixedHdrSize = sTD_HDR_SIZE + profHdrSize + granHdrSize
 
-profHdrSize  :: Int{-words-}
+profHdrSize  :: WordOff
 profHdrSize  | opt_SccProfilingOn   = pROF_HDR_SIZE
             | otherwise            = 0
 
-granHdrSize  :: Int{-words-}
+granHdrSize  :: WordOff
 granHdrSize  | opt_GranMacros      = gRAN_HDR_SIZE
             | otherwise            = 0
 
-arrWordsHdrSize   :: Int{-words-}
-arrWordsHdrSize   = fixedHdrSize + aRR_WORDS_HDR_SIZE
+arrWordsHdrSize   :: ByteOff
+arrWordsHdrSize   = fixedHdrSize*wORD_SIZE + sIZEOF_StgArrWords_NoHdr
 
-arrPtrsHdrSize   :: Int{-words-}
-arrPtrsHdrSize   = fixedHdrSize + aRR_PTRS_HDR_SIZE
+arrPtrsHdrSize    :: ByteOff
+arrPtrsHdrSize    = fixedHdrSize*wORD_SIZE + sIZEOF_StgMutArrPtrs_NoHdr
 \end{code}
 
-Size of an info table.
-
 \begin{code}
-stdItblSize :: Int{-words-}
-stdItblSize = sTD_ITBL_SIZE + profItblSize + granItblSize + tickyItblSize
-
-retItblSize :: Int{-words-}
-retItblSize = stdItblSize + rET_ITBL_SIZE
-
-profItblSize  :: Int{-words-}
-profItblSize  | opt_SccProfilingOn  = pROF_ITBL_SIZE
-             | otherwise           = 0
-
-granItblSize  :: Int{-words-}
-granItblSize  | opt_GranMacros     = gRAN_ITBL_SIZE
-             | otherwise           = 0
-
-tickyItblSize :: Int{-words-}
-tickyItblSize | opt_DoTickyProfiling = tICKY_ITBL_SIZE
-             | otherwise            = 0
+-- IA64 mangler doesn't place tables next to code
+tablesNextToCode :: Bool
+#ifdef ia64_TARGET_ARCH
+tablesNextToCode = False
+#else
+tablesNextToCode = not opt_Unregisterised
+#endif
 \end{code}
 
 \begin{code}
@@ -109,38 +306,43 @@ isStaticRep BlackHoleRep           = False
 #include "../includes/ClosureTypes.h"
 -- Defines CONSTR, CONSTR_1_0 etc
 
-getSMRepClosureTypeInt :: SMRep -> Int
-getSMRepClosureTypeInt (GenericRep False 1 0 Constr) = CONSTR_1_0
-getSMRepClosureTypeInt (GenericRep False 0 1 Constr) = CONSTR_0_1
-getSMRepClosureTypeInt (GenericRep False 2 0 Constr) = CONSTR_2_0
-getSMRepClosureTypeInt (GenericRep False 1 1 Constr) = CONSTR_1_1
-getSMRepClosureTypeInt (GenericRep False 0 2 Constr) = CONSTR_0_2
-getSMRepClosureTypeInt (GenericRep False _ _ Constr) = CONSTR
 
-getSMRepClosureTypeInt (GenericRep False 1 0 Fun) = FUN_1_0
-getSMRepClosureTypeInt (GenericRep False 0 1 Fun) = FUN_0_1
-getSMRepClosureTypeInt (GenericRep False 2 0 Fun) = FUN_2_0
-getSMRepClosureTypeInt (GenericRep False 1 1 Fun) = FUN_1_1
-getSMRepClosureTypeInt (GenericRep False 0 2 Fun) = FUN_0_2
-getSMRepClosureTypeInt (GenericRep False _ _ Fun) = FUN
+smRepClosureType :: SMRep -> ClosureType
+smRepClosureType (GenericRep _ _ _ ty) = ty
+smRepClosureType BlackHoleRep         = panic "smRepClosureType: black hole"
+
+smRepClosureTypeInt :: SMRep -> Int
+smRepClosureTypeInt (GenericRep False 1 0 Constr) = CONSTR_1_0
+smRepClosureTypeInt (GenericRep False 0 1 Constr) = CONSTR_0_1
+smRepClosureTypeInt (GenericRep False 2 0 Constr) = CONSTR_2_0
+smRepClosureTypeInt (GenericRep False 1 1 Constr) = CONSTR_1_1
+smRepClosureTypeInt (GenericRep False 0 2 Constr) = CONSTR_0_2
+smRepClosureTypeInt (GenericRep False _ _ Constr) = CONSTR
+
+smRepClosureTypeInt (GenericRep False 1 0 Fun) = FUN_1_0
+smRepClosureTypeInt (GenericRep False 0 1 Fun) = FUN_0_1
+smRepClosureTypeInt (GenericRep False 2 0 Fun) = FUN_2_0
+smRepClosureTypeInt (GenericRep False 1 1 Fun) = FUN_1_1
+smRepClosureTypeInt (GenericRep False 0 2 Fun) = FUN_0_2
+smRepClosureTypeInt (GenericRep False _ _ Fun) = FUN
 
-getSMRepClosureTypeInt (GenericRep False 1 0 Thunk) = THUNK_1_0
-getSMRepClosureTypeInt (GenericRep False 0 1 Thunk) = THUNK_0_1
-getSMRepClosureTypeInt (GenericRep False 2 0 Thunk) = THUNK_2_0
-getSMRepClosureTypeInt (GenericRep False 1 1 Thunk) = THUNK_1_1
-getSMRepClosureTypeInt (GenericRep False 0 2 Thunk) = THUNK_0_2
-getSMRepClosureTypeInt (GenericRep False _ _ Thunk) = THUNK
+smRepClosureTypeInt (GenericRep False 1 0 Thunk) = THUNK_1_0
+smRepClosureTypeInt (GenericRep False 0 1 Thunk) = THUNK_0_1
+smRepClosureTypeInt (GenericRep False 2 0 Thunk) = THUNK_2_0
+smRepClosureTypeInt (GenericRep False 1 1 Thunk) = THUNK_1_1
+smRepClosureTypeInt (GenericRep False 0 2 Thunk) = THUNK_0_2
+smRepClosureTypeInt (GenericRep False _ _ Thunk) = THUNK
 
-getSMRepClosureTypeInt (GenericRep False _ _ ThunkSelector) =  THUNK_SELECTOR
+smRepClosureTypeInt (GenericRep False _ _ ThunkSelector) =  THUNK_SELECTOR
 
-getSMRepClosureTypeInt (GenericRep True _ _ Constr)      = CONSTR_STATIC
-getSMRepClosureTypeInt (GenericRep True _ _ ConstrNoCaf) = CONSTR_NOCAF_STATIC
-getSMRepClosureTypeInt (GenericRep True _ _ Fun)         = FUN_STATIC
-getSMRepClosureTypeInt (GenericRep True _ _ Thunk)       = THUNK_STATIC
+smRepClosureTypeInt (GenericRep True _ _ Constr)      = CONSTR_STATIC
+smRepClosureTypeInt (GenericRep True _ _ ConstrNoCaf) = CONSTR_NOCAF_STATIC
+smRepClosureTypeInt (GenericRep True _ _ Fun)         = FUN_STATIC
+smRepClosureTypeInt (GenericRep True _ _ Thunk)       = THUNK_STATIC
 
-getSMRepClosureTypeInt BlackHoleRep = BLACKHOLE
+smRepClosureTypeInt BlackHoleRep = BLACKHOLE
 
-getSMRepClosureTypeInt rep = panic "getSMRepClosureTypeInt"
+smRepClosureTypeInt rep = panic "smRepClosuretypeint"
 
 
 -- We export these ones
@@ -150,18 +352,3 @@ rET_BIG       = (RET_BIG       :: Int)
 rET_VEC_BIG   = (RET_VEC_BIG   :: Int)
 \end{code}
 
-A type representing an StgWord on the target platform.
-
-\begin{code}
-#if SIZEOF_HSWORD == 4
-type StgWord     = Word32
-type StgHalfWord = Word16
-hALF_WORD = 16 :: Int
-#elif SIZEOF_HSWORD == 8
-type StgWord     = Word64
-type StgHalfWord = Word32
-hALF_WORD = 32 :: Int
-#else
-#error unknown SIZEOF_HSWORD
-#endif
-\end{code}
index e645cf2..ce6302a 100644 (file)
@@ -4,7 +4,6 @@
 % The Compilation Manager
 %
 \begin{code}
-{-# OPTIONS -fvia-C #-}
 module CompManager ( 
     ModuleGraph, ModSummary(..),
 
index f30993c..57bace2 100644 (file)
@@ -23,7 +23,8 @@ import CoreUtils      ( exprType, mkCoerce2 )
 import Id              ( Id, mkWildId )
 import MkId            ( mkFCallId, realWorldPrimId, mkPrimOpId )
 import Maybes          ( maybeToBool )
-import ForeignCall     ( ForeignCall(..), CCallSpec(..), CCallTarget(..), Safety, CCallConv(..) )
+import ForeignCall     ( ForeignCall(..), CCallSpec(..), CCallTarget(..), Safety, 
+                         CCallConv(..), CLabelString )
 import DataCon         ( splitProductType_maybe, dataConSourceArity, dataConWrapId )
 import ForeignCall     ( ForeignCall, CCallTarget(..) )
 
@@ -51,7 +52,6 @@ import TysWiredIn     ( unitDataConId,
                        )
 import BasicTypes       ( Boxity(..) )
 import Literal         ( mkMachInt )
-import CStrings                ( CLabelString )
 import PrelNames       ( Unique, hasKey, ioTyConKey, boolTyConKey, unitTyConKey,
                          int8TyConKey, int16TyConKey, int32TyConKey,
                          word8TyConKey, word16TyConKey, word32TyConKey
index 05dcb05..269274c 100644 (file)
@@ -18,6 +18,8 @@ import DsMonad
 
 import HsSyn           ( ForeignDecl(..), ForeignExport(..), LForeignDecl,
                          ForeignImport(..), CImportSpec(..) )
+import MachOp          ( machRepByteWidth )
+import SMRep           ( argMachRep, primRepToCgRep )
 import CoreUtils       ( exprType, mkInlineMe )
 import Id              ( Id, idType, idName, mkSysLocal, setInlinePragma )
 import Literal         ( Literal(..) )
@@ -34,14 +36,12 @@ import BasicTypes       ( Boxity(..) )
 import HscTypes                ( ForeignStubs(..) )
 import ForeignCall     ( ForeignCall(..), CCallSpec(..), 
                          Safety(..), playSafe,
-                         CExportSpec(..),
+                         CExportSpec(..), CLabelString,
                          CCallConv(..), ccallConvToInt,
                          ccallConvAttribute
                        )
-import CStrings                ( CLabelString )
 import TysWiredIn      ( unitTy, tupleTyCon )
 import TysPrim         ( addrPrimTy, mkStablePtrPrimTy, alphaTy )
-import PrimRep          ( getPrimRepSizeInBytes )
 import PrelNames       ( hasKey, ioTyConKey, stablePtrTyConName, newStablePtrName, bindIOName,
                          checkDotnetResName )
 import BasicTypes      ( Activation( NeverActive ) )
@@ -389,7 +389,7 @@ dsFExportDynamic id cconv
        -- (probably in the RTS.) 
       adjustor  = FSLIT("createAdjustor")
       
-      sz_args   = sum (map (getPrimRepSizeInBytes . typePrimRep) stub_args)
+      sz_args   = sum (map (machRepByteWidth.argMachRep.primRepToCgRep.typePrimRep) stub_args)
       mb_sz_args = case cconv of
                      StdCallConv -> Just sz_args
                      _           -> Nothing
index 53340e7..3958753 100644 (file)
@@ -26,10 +26,9 @@ import FiniteMap     ( addToFM, lookupFM, emptyFM )
 import Literal         ( Literal(..) )
 import TyCon           ( TyCon )
 import PrimOp          ( PrimOp )
-import PrimRep         ( PrimRep(..), isFollowableRep, is64BitRep )
 import Constants       ( wORD_SIZE )
 import FastString      ( FastString(..) )
-import SMRep           ( StgWord )
+import SMRep           ( CgRep(..), StgWord )
 import FiniteMap
 import Outputable
 
@@ -356,27 +355,19 @@ mkBits findLabel st proto_insns
        literal st other            = pprPanic "ByteCodeLink.literal" (ppr other)
 
 
-push_alts WordRep   = bci_PUSH_ALTS_N
-push_alts IntRep    = bci_PUSH_ALTS_N
-push_alts AddrRep   = bci_PUSH_ALTS_N
-push_alts CharRep   = bci_PUSH_ALTS_N
-push_alts FloatRep  = bci_PUSH_ALTS_F
-push_alts DoubleRep = bci_PUSH_ALTS_D
-push_alts VoidRep   = bci_PUSH_ALTS_V
-push_alts pk
- | is64BitRep pk      = bci_PUSH_ALTS_L
- | isFollowableRep pk = bci_PUSH_ALTS_P
-
-return_ubx WordRep   = bci_RETURN_N
-return_ubx IntRep    = bci_RETURN_N
-return_ubx AddrRep   = bci_RETURN_N
-return_ubx CharRep   = bci_RETURN_N
-return_ubx FloatRep  = bci_RETURN_F
-return_ubx DoubleRep = bci_RETURN_D
-return_ubx VoidRep   = bci_RETURN_V
-return_ubx pk
- | is64BitRep pk      = bci_RETURN_L
- | isFollowableRep pk = bci_RETURN_P
+push_alts NonPtrArg = bci_PUSH_ALTS_N
+push_alts FloatArg  = bci_PUSH_ALTS_F
+push_alts DoubleArg = bci_PUSH_ALTS_D
+push_alts VoidArg   = bci_PUSH_ALTS_V
+push_alts LongArg   = bci_PUSH_ALTS_L
+push_alts PtrArg    = bci_PUSH_ALTS_P
+
+return_ubx NonPtrArg = bci_RETURN_N
+return_ubx FloatArg  = bci_RETURN_F
+return_ubx DoubleArg = bci_RETURN_D
+return_ubx VoidArg   = bci_RETURN_V
+return_ubx LongArg   = bci_RETURN_L
+return_ubx PtrArg    = bci_RETURN_P
 
 
 -- The size in 16-bit entities of an instruction.
index 78cfa61..fe258dd 100644 (file)
@@ -9,7 +9,7 @@ module ByteCodeFFI ( mkMarshalCode, moan64 ) where
 #include "HsVersions.h"
 
 import Outputable
-import PrimRep         ( PrimRep(..), getPrimRepSize )
+import SMRep           ( CgRep(..), cgRepSizeW )
 import ForeignCall     ( CCallConv(..) )
 
 -- DON'T remove apparently unused imports here .. 
@@ -66,7 +66,7 @@ itself expects only to be called using the ccall convention -- that is,
 we don't clear our own (single) arg off the C stack.
 -}
 mkMarshalCode :: CCallConv
-              -> (Int, PrimRep) -> Int -> [(Int, PrimRep)] 
+              -> (Int, CgRep) -> Int -> [(Int, CgRep)] 
               -> IO (Ptr Word8)
 mkMarshalCode cconv (r_offW, r_rep) addr_offW arg_offs_n_reps
    = let bytes = mkMarshalCode_wrk cconv (r_offW, r_rep) 
@@ -77,7 +77,7 @@ mkMarshalCode cconv (r_offW, r_rep) addr_offW arg_offs_n_reps
 
 
 mkMarshalCode_wrk :: CCallConv 
-                  -> (Int, PrimRep) -> Int -> [(Int, PrimRep)] 
+                  -> (Int, CgRep) -> Int -> [(Int, CgRep)] 
                   -> [Word8]
 
 mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps
@@ -90,7 +90,7 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps
          offsets_to_pushW
             = concat
               [   -- reversed because x86 is little-endian
-                  reverse [a_offW .. a_offW + getPrimRepSize a_rep - 1]
+                  reverse [a_offW .. a_offW + cgRepSizeW a_rep - 1]
 
                 -- reversed because args are pushed L -> R onto C stack
                 | (a_offW, a_rep) <- reverse arg_offs_n_reps
@@ -187,7 +187,7 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps
      ++ movl_offespmem_esi 32
 
      {- For each arg in args_offs_n_reps, examine the associated
-        PrimRep to determine how many words there are.  This gives a
+        CgRep to determine how many words there are.  This gives a
         bunch of offsets on the H stack to copy to the C stack:
 
            movl        off1(%esi), %ecx
@@ -235,15 +235,11 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps
             f64 = fstpl_offesimem 0
         in
         case r_rep of
-           CharRep   -> i32
-           IntRep    -> i32
-           WordRep   -> i32
-           AddrRep   -> i32
-           DoubleRep -> f64  
-           FloatRep  -> f32
-           -- Word64Rep -> i64
-           -- Int64Rep  -> i64
-           VoidRep   -> []
+           NonPtrArg -> i32
+           DoubleArg -> f64  
+           FloatArg  -> f32
+           -- LongArg -> i64
+           VoidArg   -> []
            other     -> moan64 "ByteCodeFFI.mkMarshalCode_wrk(x86)" 
                                (ppr r_rep)
 
@@ -278,7 +274,7 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps
 
          offsets_to_pushW
             = concat
-              [  [a_offW .. a_offW + getPrimRepSize a_rep - 1]
+              [  [a_offW .. a_offW + cgRepSizeW a_rep - 1]
 
                 | (a_offW, a_rep) <- arg_offs_n_reps
               ]
@@ -385,7 +381,7 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps
      [mkSAVE sp (- ({-92-}112 + 4*argWs_on_stack_ROUNDED_UP)) sp]
 
      {- For each arg in args_offs_n_reps, examine the associated
-        PrimRep to determine how many words there are.  This gives a
+        CgRep to determine how many words there are.  This gives a
         bunch of offsets on the H stack.  Move the first 6 words into
         %o0 .. %o5 and the rest on the stack, starting at [%sp+92].
         Use %g1 as a temp. 
@@ -429,13 +425,10 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps
             f64 = [mkSTF f0 i0 0, mkSTF f1 i0 4]
         in
             case r_rep of
-               CharRep   -> i32
-               IntRep    -> i32
-               WordRep   -> i32
-               AddrRep   -> i32
-               DoubleRep -> f64
-               FloatRep  -> f32
-               VoidRep   -> []
+               NonPtrArg -> i32
+               DoubleArg -> f64
+               FloatArg  -> f32
+               VoidArg   -> []
                other     -> moan64 "ByteCodeFFI.mkMarshalCode_wrk(sparc)" 
                                    (ppr r_rep)
 
@@ -460,7 +453,7 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps
          result_off  = r_offW * bytes_per_word
 
          linkageArea = 24
-         parameterArea = sum [ getPrimRepSize a_rep * bytes_per_word
+         parameterArea = sum [ cgRepSizeW a_rep * bytes_per_word
                         | (_, a_rep) <- arg_offs_n_reps ]
          savedRegisterArea = 4
          frameSize = padTo16 (linkageArea + max parameterArea 32 + savedRegisterArea)
@@ -472,7 +465,7 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps
          pass_parameters ((a_offW, a_rep):args) nextFPR offsetW =
             let
                haskellArgOffset = a_offW * bytes_per_word
-               offsetW' = offsetW + getPrimRepSize a_rep
+               offsetW' = offsetW + cgRepSizeW a_rep
                
                pass_word w 
                    | offsetW + w < 8 =
@@ -489,34 +482,34 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps
                      dst = linkageArea + (offsetW+w) * bytes_per_word
             in
                case a_rep of
-                  FloatRep | nextFPR < 14 ->
+                  FloatArg | nextFPR < 14 ->
                       (0xc01f0000    -- lfs fX, haskellArgOffset(r31)
                         .|. (fromIntegral haskellArgOffset .&. 0xFFFF)
                         .|. (fromIntegral nextFPR `shiftL` 21))
                       : pass_parameters args (nextFPR+1) offsetW'
-                  DoubleRep | nextFPR < 14 ->
+                  DoubleArg | nextFPR < 14 ->
                       (0xc81f0000    -- lfd fX, haskellArgOffset(r31)
                         .|. (fromIntegral haskellArgOffset .&. 0xFFFF)
                         .|. (fromIntegral nextFPR `shiftL` 21))
                       : pass_parameters args (nextFPR+1) offsetW'
                   _ ->
-                      concatMap pass_word [0 .. getPrimRepSize a_rep - 1]
+                      concatMap pass_word [0 .. cgRepSizeW a_rep - 1]
                       ++ pass_parameters args nextFPR offsetW'              
                
          gather_result = case r_rep of
-            VoidRep -> []
-            FloatRep -> 
+            VoidArg -> []
+            FloatArg -> 
                [0xd03f0000 .|. (fromIntegral result_off .&. 0xFFFF)]
                -- stfs f1, result_off(r31)
-            DoubleRep -> 
+            DoubleArg -> 
                [0xd83f0000 .|. (fromIntegral result_off .&. 0xFFFF)]
                -- stfs f1, result_off(r31)
-            _ | getPrimRepSize r_rep == 2 ->
+            _ | cgRepSizeW r_rep == 2 ->
                [0x907f0000 .|. (fromIntegral result_off .&. 0xFFFF),
                 0x909f0000 .|. (fromIntegral (result_off+4) .&. 0xFFFF)]
                -- stw r3, result_off(r31)
                -- stw r4, result_off+4(r31)
-            _ | getPrimRepSize r_rep == 1 ->
+            _ | cgRepSizeW r_rep == 1 ->
                [0x907f0000 .|. (fromIntegral result_off .&. 0xFFFF)]
                -- stw r3, result_off(r31)
      in
index d7a477b..f7256f3 100644 (file)
@@ -23,11 +23,10 @@ import HscTypes             ( TypeEnv, typeEnvTyCons, typeEnvClasses )
 import CoreUtils       ( exprType )
 import CoreSyn
 import PprCore         ( pprCoreExpr )
-import Literal         ( Literal(..), literalPrimRep )
-import PrimRep
+import Literal         ( Literal(..), literalType )
 import PrimOp          ( PrimOp(..) )
 import CoreFVs         ( freeVars )
-import Type            ( typePrimRep, isUnLiftedType, splitTyConApp_maybe )
+import Type            ( isUnLiftedType, splitTyConApp_maybe )
 import DataCon         ( DataCon, dataConTag, fIRST_TAG, dataConTyCon, 
                           isUnboxedTupleCon, isNullaryDataCon, dataConWorkId,
                          dataConRepArity )
@@ -42,13 +41,13 @@ import VarSet               ( VarSet, varSetElems )
 import TysPrim         ( arrayPrimTyCon, mutableArrayPrimTyCon,
                          byteArrayPrimTyCon, mutableByteArrayPrimTyCon
                        )
-import PrimRep         ( isFollowableRep )
 import CmdLineOpts     ( DynFlags, DynFlag(..) )
 import ErrUtils                ( showPass, dumpIfSet_dyn )
-import Unique          ( mkPseudoUnique3 )
+import Unique          ( mkPseudoUniqueE )
 import FastString      ( FastString(..), unpackFS )
 import Panic           ( GhcException(..) )
-import SMRep           ( arrWordsHdrSize, arrPtrsHdrSize, StgWord )
+import SMRep           ( typeCgRep, arrWordsHdrSize, arrPtrsHdrSize, StgWord, 
+                         CgRep(..), cgRepSizeW, isFollowableArg, idCgRep )
 import Bitmap          ( intsToReverseBitmap, mkBitmap )
 import OrdList
 import Constants       ( wORD_SIZE )
@@ -103,7 +102,7 @@ coreExprToBCOs dflags expr
 
       -- create a totally bogus name for the top-level BCO; this
       -- should be harmless, since it's never used for anything
-      let invented_name  = mkSystemName (mkPseudoUnique3 0) FSLIT("ExprTopLevel")
+      let invented_name  = mkSystemName (mkPseudoUniqueE 0) FSLIT("ExprTopLevel")
           invented_id    = mkLocalId invented_name (panic "invented_id's type")
          
       (BcM_State final_ctr mallocd, proto_bco) 
@@ -134,7 +133,7 @@ ppBCEnv p
      $$ nest 4 (vcat (map pp_one (sortBy cmp_snd (fmToList p))))
      $$ text "end-env"
      where
-        pp_one (var, offset) = int offset <> colon <+> ppr var <+> ppr (idPrimRep var)
+        pp_one (var, offset) = int offset <> colon <+> ppr var <+> ppr (idCgRep var)
         cmp_snd x y = compare (snd x) (snd y)
 
 -- Create a BCO and do a spot of peephole optimisation on the insns
@@ -195,11 +194,11 @@ mkProtoBCO nm instrs_ordlist origin arity bitmap_size bitmap
         peep []
            = []
 
-argBits :: [PrimRep] -> [Bool]
+argBits :: [CgRep] -> [Bool]
 argBits [] = []
 argBits (rep : args)
-  | isFollowableRep rep = False : argBits args
-  | otherwise = take (getPrimRepSize rep) (repeat True) ++ argBits args
+  | isFollowableArg rep = False : argBits args
+  | otherwise = take (cgRepSizeW rep) (repeat True) ++ argBits args
 
 -- -----------------------------------------------------------------------------
 -- schemeTopBind
@@ -272,7 +271,7 @@ schemeR_wrk fvs nm original_body (args, body)
          p_init    = listToFM (zip all_args (mkStackOffsets 0 szsw_args))
 
         -- make the arg bitmap
-        bits = argBits (reverse (map idPrimRep all_args))
+        bits = argBits (reverse (map idCgRep all_args))
         bitmap_size = length bits
         bitmap = mkBitmap bits
      in
@@ -319,11 +318,11 @@ schemeE d s p e@(AnnVar v)
                `snocOL` RETURN_UBX v_rep)      -- go
    where
       v_type = idType v
-      v_rep = typePrimRep v_type
+      v_rep = typeCgRep v_type
 
 schemeE d s p (AnnLit literal)
    = pushAtom d p (AnnLit literal)     `thenBc` \ (push, szw) ->
-     let l_rep = literalPrimRep literal
+     let l_rep = typeCgRep (literalType literal)
      in  returnBc (push                        -- value onto stack
                    `appOL`  mkSLIDE szw (d-s)  -- clear to sequel
                    `snocOL` RETURN_UBX l_rep)  -- go
@@ -393,9 +392,9 @@ schemeE d s p (AnnLet binds (_,body))
 
 
 schemeE d s p (AnnCase scrut bndr [(DataAlt dc, [bind1, bind2], rhs)])
-   | isUnboxedTupleCon dc && VoidRep == typePrimRep (idType bind1)
+   | isUnboxedTupleCon dc, VoidArg <- typeCgRep (idType bind1)
        -- Convert 
-       --      case .... of x { (# VoidRep'd-thing, a #) -> ... }
+       --      case .... of x { (# VoidArg'd-thing, a #) -> ... }
        -- to
        --      case .... of a { DEFAULT -> ... }
        -- becuse the return convention for both are identical.
@@ -403,11 +402,11 @@ schemeE d s p (AnnCase scrut bndr [(DataAlt dc, [bind1, bind2], rhs)])
        -- Note that it does not matter losing the void-rep thing from the
        -- envt (it won't be bound now) because we never look such things up.
 
-   = --trace "automagic mashing of case alts (# VoidRep, a #)" $
+   = --trace "automagic mashing of case alts (# VoidArg, a #)" $
      doCase d s p scrut bind2 [(DEFAULT, [], rhs)] True{-unboxed tuple-}
 
-   | isUnboxedTupleCon dc && VoidRep == typePrimRep (idType bind2)
-   = --trace "automagic mashing of case alts (# a, VoidRep #)" $
+   | isUnboxedTupleCon dc, VoidArg <- typeCgRep (idType bind2)
+   = --trace "automagic mashing of case alts (# a, VoidArg #)" $
      doCase d s p scrut bind1 [(DEFAULT, [], rhs)] True{-unboxed tuple-}
 
 schemeE d s p (AnnCase scrut bndr [(DataAlt dc, [bind1], rhs)])
@@ -441,9 +440,9 @@ schemeE d s p other
 --
 -- 1.  The fn denotes a ccall.  Defer to generateCCall.
 --
--- 2.  (Another nasty hack).  Spot (# a::VoidRep, b #) and treat
+-- 2.  (Another nasty hack).  Spot (# a::VoidArg, b #) and treat
 --     it simply as  b  -- since the representations are identical
---     (the VoidRep takes up zero stack space).  Also, spot
+--     (the VoidArg takes up zero stack space).  Also, spot
 --     (# b #) and treat it as  b.
 --
 -- 3.  Application of a constructor, by defn saturated.
@@ -483,9 +482,9 @@ schemeT d s p app
    | Just con <- maybe_saturated_dcon,
      isUnboxedTupleCon con
    = case args_r_to_l of
-       [arg1,arg2] | isVoidRepAtom arg1 -> 
+       [arg1,arg2] | isVoidArgAtom arg1 -> 
                  unboxedTupleReturn d s p arg2
-       [arg1,arg2] | isVoidRepAtom arg2 -> 
+       [arg1,arg2] | isVoidArgAtom arg2 -> 
                  unboxedTupleReturn d s p arg1
        _other -> unboxedTupleException
 
@@ -589,7 +588,7 @@ doTailCall
        -> Id -> [AnnExpr' Id VarSet]
        -> BcM BCInstrList
 doTailCall init_d s p fn args
-  = do_pushes init_d args (map (primRepToArgRep.atomRep) args)
+  = do_pushes init_d args (map atomRep args)
   where
   do_pushes d [] reps = do
        ASSERTM( null reps )
@@ -613,29 +612,29 @@ doTailCall init_d s p fn args
     return (final_d, push_code `appOL` more_push_code)
 
 -- v. similar to CgStackery.findMatch, ToDo: merge
-findPushSeq (RepP: RepP: RepP: RepP: RepP: RepP: RepP: rest)
+findPushSeq (PtrArg: PtrArg: PtrArg: PtrArg: PtrArg: PtrArg: PtrArg: rest)
   = (PUSH_APPLY_PPPPPPP, 7, rest)
-findPushSeq (RepP: RepP: RepP: RepP: RepP: RepP: rest)
+findPushSeq (PtrArg: PtrArg: PtrArg: PtrArg: PtrArg: PtrArg: rest)
   = (PUSH_APPLY_PPPPPP, 6, rest)
-findPushSeq (RepP: RepP: RepP: RepP: RepP: rest)
+findPushSeq (PtrArg: PtrArg: PtrArg: PtrArg: PtrArg: rest)
   = (PUSH_APPLY_PPPPP, 5, rest)
-findPushSeq (RepP: RepP: RepP: RepP: rest)
+findPushSeq (PtrArg: PtrArg: PtrArg: PtrArg: rest)
   = (PUSH_APPLY_PPPP, 4, rest)
-findPushSeq (RepP: RepP: RepP: rest)
+findPushSeq (PtrArg: PtrArg: PtrArg: rest)
   = (PUSH_APPLY_PPP, 3, rest)
-findPushSeq (RepP: RepP: rest)
+findPushSeq (PtrArg: PtrArg: rest)
   = (PUSH_APPLY_PP, 2, rest)
-findPushSeq (RepP: rest)
+findPushSeq (PtrArg: rest)
   = (PUSH_APPLY_P, 1, rest)
-findPushSeq (RepV: rest)
+findPushSeq (VoidArg: rest)
   = (PUSH_APPLY_V, 1, rest)
-findPushSeq (RepN: rest)
+findPushSeq (NonPtrArg: rest)
   = (PUSH_APPLY_N, 1, rest)
-findPushSeq (RepF: rest)
+findPushSeq (FloatArg: rest)
   = (PUSH_APPLY_F, 1, rest)
-findPushSeq (RepD: rest)
+findPushSeq (DoubleArg: rest)
   = (PUSH_APPLY_D, 1, rest)
-findPushSeq (RepL: rest)
+findPushSeq (LongArg: rest)
   = (PUSH_APPLY_L, 1, rest)
 findPushSeq _
   = panic "ByteCodeGen.findPushSeq"
@@ -688,7 +687,7 @@ doCase d s p (_,scrut)
           -- algebraic alt with some binders
            | ASSERT(isAlgCase) otherwise =
              let
-                (ptrs,nptrs) = partition (isFollowableRep.idPrimRep) real_bndrs
+                (ptrs,nptrs) = partition (isFollowableArg.idCgRep) real_bndrs
                 ptr_sizes    = map idSizeW ptrs
                 nptrs_sizes  = map idSizeW nptrs
                 bind_sizes   = ptr_sizes ++ nptrs_sizes
@@ -736,7 +735,7 @@ doCase d s p (_,scrut)
          binds = fmToList p
          rel_slots = concat (map spread binds)
          spread (id, offset)
-               | isFollowableRep (idPrimRep id) = [ rel_offset ]
+               | isFollowableArg (idCgRep id) = [ rel_offset ]
                | otherwise = []
                where rel_offset = d - offset - 1
 
@@ -754,7 +753,7 @@ doCase d s p (_,scrut)
      alt_bco' <- emitBc alt_bco
      let push_alts
            | isAlgCase = PUSH_ALTS alt_bco'
-           | otherwise = PUSH_ALTS_UNLIFTED alt_bco' (typePrimRep bndr_ty)
+           | otherwise = PUSH_ALTS_UNLIFTED alt_bco' (typeCgRep bndr_ty)
      returnBc (push_alts `consOL` scrut_code)
 
 
@@ -777,12 +776,12 @@ generateCCall :: Int -> Sequel            -- stack and sequel depths
 generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
    = let 
          -- useful constants
-         addr_sizeW = getPrimRepSize AddrRep
+         addr_sizeW = cgRepSizeW NonPtrArg
 
          -- Get the args on the stack, with tags and suitably
          -- dereferenced for the CCall.  For each arg, return the
          -- depth to the first word of the bits for that arg, and the
-         -- PrimRep of what was actually pushed.
+         -- CgRep of what was actually pushed.
 
          pargs d [] = returnBc []
          pargs d (a:az) 
@@ -796,13 +795,13 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
                        -> pargs (d + addr_sizeW) az    `thenBc` \ rest ->
                           parg_ArrayishRep arrPtrsHdrSize d p a
                                                        `thenBc` \ code ->
-                          returnBc ((code,AddrRep):rest)
+                          returnBc ((code,NonPtrArg):rest)
 
                     | t == byteArrayPrimTyCon || t == mutableByteArrayPrimTyCon
                        -> pargs (d + addr_sizeW) az    `thenBc` \ rest ->
                           parg_ArrayishRep arrWordsHdrSize d p a
                                                        `thenBc` \ code ->
-                          returnBc ((code,AddrRep):rest)
+                          returnBc ((code,NonPtrArg):rest)
 
                     -- Default case: push taggedly, but otherwise intact.
                     other
@@ -813,13 +812,11 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
          -- Do magic for Ptr/Byte arrays.  Push a ptr to the array on
          -- the stack but then advance it over the headers, so as to
          -- point to the payload.
-         parg_ArrayishRep hdrSizeW d p a
+         parg_ArrayishRep hdrSize d p a
             = pushAtom d p a `thenBc` \ (push_fo, _) ->
               -- The ptr points at the header.  Advance it over the
               -- header and then pretend this is an Addr#.
-              returnBc (push_fo `snocOL` 
-                        SWIZZLE 0 (hdrSizeW * getPrimRepSize WordRep
-                                            * wORD_SIZE))
+              returnBc (push_fo `snocOL` SWIZZLE 0 hdrSize)
 
      in
          pargs d0 args_r_to_l                  `thenBc` \ code_n_reps ->
@@ -827,9 +824,9 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
          (pushs_arg, a_reps_pushed_r_to_l) = unzip code_n_reps
 
          push_args    = concatOL pushs_arg
-         d_after_args = d0 + sum (map getPrimRepSize a_reps_pushed_r_to_l)
+         d_after_args = d0 + sum (map cgRepSizeW a_reps_pushed_r_to_l)
          a_reps_pushed_RAW
-            | null a_reps_pushed_r_to_l || head a_reps_pushed_r_to_l /= VoidRep
+            | null a_reps_pushed_r_to_l || head a_reps_pushed_r_to_l /= VoidArg
             = panic "ByteCodeGen.generateCCall: missing or invalid World token?"
             | otherwise
             = reverse (tail a_reps_pushed_r_to_l)
@@ -841,7 +838,7 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
          -- Get the result rep.
          (returns_void, r_rep)
             = case maybe_getCCallReturnRep (idType fn) of
-                 Nothing -> (True,  VoidRep)
+                 Nothing -> (True,  VoidArg)
                  Just rr -> (False, rr) 
          {-
          Because the Haskell stack grows down, the a_reps refer to 
@@ -906,8 +903,8 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
             = (nilOL, d_after_args)
 
          -- Push the return placeholder.  For a call returning nothing,
-         -- this is a VoidRep (tag).
-         r_sizeW   = getPrimRepSize r_rep
+         -- this is a VoidArg (tag).
+         r_sizeW   = cgRepSizeW r_rep
          d_after_r = d_after_Addr + r_sizeW
          r_lit     = mkDummyLiteral r_rep
          push_r    = (if   returns_void 
@@ -919,7 +916,7 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
          addr_offW    = r_sizeW
          arg1_offW    = r_sizeW + addr_sizeW
          args_offW    = map (arg1_offW +) 
-                            (init (scanl (+) 0 (map getPrimRepSize a_reps)))
+                            (init (scanl (+) 0 (map cgRepSizeW a_reps)))
      in
          ioToBc (mkMarshalCode cconv
                     (r_offW, r_rep) addr_offW
@@ -938,7 +935,7 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
          wrapup       = mkSLIDE r_sizeW (d_after_r - r_sizeW - s)
                         `snocOL` RETURN_UBX r_rep
      in
-         --trace (show (arg1_offW, args_offW  ,  (map getPrimRepSize a_reps) )) $
+         --trace (show (arg1_offW, args_offW  ,  (map cgRepSizeW a_reps) )) $
          returnBc (
          push_args `appOL`
          push_Addr `appOL` push_r `appOL` do_call `appOL` wrapup
@@ -947,15 +944,12 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
 
 -- Make a dummy literal, to be used as a placeholder for FFI return
 -- values on the stack.
-mkDummyLiteral :: PrimRep -> Literal
+mkDummyLiteral :: CgRep -> Literal
 mkDummyLiteral pr
    = case pr of
-        CharRep   -> MachChar (chr 0)
-        IntRep    -> MachInt 0
-        WordRep   -> MachWord 0
-        DoubleRep -> MachDouble 0
-        FloatRep  -> MachFloat 0
-        AddrRep   | getPrimRepSize AddrRep == getPrimRepSize WordRep -> MachWord 0
+        NonPtrArg -> MachWord 0
+        DoubleArg -> MachDouble 0
+        FloatArg  -> MachFloat 0
         _         -> moan64 "mkDummyLiteral" (ppr pr)
 
 
@@ -964,7 +958,7 @@ mkDummyLiteral pr
 --                   -> (# GHC.Prim.State# GHC.Prim.RealWorld, GHC.Prim.Int# #)
 --
 -- to  Just IntRep
--- and check that an unboxed pair is returned wherein the first arg is VoidRep'd.
+-- and check that an unboxed pair is returned wherein the first arg is VoidArg'd.
 --
 -- Alternatively, for call-targets returning nothing, convert
 --
@@ -973,21 +967,21 @@ mkDummyLiteral pr
 --
 -- to  Nothing
 
-maybe_getCCallReturnRep :: Type -> Maybe PrimRep
+maybe_getCCallReturnRep :: Type -> Maybe CgRep
 maybe_getCCallReturnRep fn_ty
    = let (a_tys, r_ty) = splitFunTys (dropForAlls fn_ty)
          maybe_r_rep_to_go  
             = if isSingleton r_reps then Nothing else Just (r_reps !! 1)
          (r_tycon, r_reps) 
             = case splitTyConApp_maybe (repType r_ty) of
-                      (Just (tyc, tys)) -> (tyc, map typePrimRep tys)
+                      (Just (tyc, tys)) -> (tyc, map typeCgRep tys)
                       Nothing -> blargh
-         ok = ( ( r_reps `lengthIs` 2 && VoidRep == head r_reps)
-                || r_reps == [VoidRep] )
+         ok = ( ( r_reps `lengthIs` 2 && VoidArg == head r_reps)
+                || r_reps == [VoidArg] )
               && isUnboxedTupleTyCon r_tycon
               && case maybe_r_rep_to_go of
                     Nothing    -> True
-                    Just r_rep -> r_rep /= PtrRep
+                    Just r_rep -> r_rep /= PtrArg
                                   -- if it was, it would be impossible 
                                   -- to create a valid return value 
                                   -- placeholder on the stack
@@ -1047,7 +1041,7 @@ pushAtom d p (AnnLam x e)
 
 pushAtom d p (AnnVar v)
 
-   | idPrimRep v == VoidRep
+   | idCgRep v == VoidArg
    = returnBc (nilOL, 0)
 
    | isFCallId v
@@ -1079,16 +1073,16 @@ pushAtom d p (AnnVar v)
 
 pushAtom d p (AnnLit lit)
    = case lit of
-        MachLabel fs _ -> code CodePtrRep
-        MachWord w     -> code WordRep
-        MachInt i      -> code IntRep
-        MachFloat r    -> code FloatRep
-        MachDouble r   -> code DoubleRep
-        MachChar c     -> code CharRep
+        MachLabel fs _ -> code NonPtrArg
+        MachWord w     -> code NonPtrArg
+        MachInt i      -> code PtrArg
+        MachFloat r    -> code FloatArg
+        MachDouble r   -> code DoubleArg
+        MachChar c     -> code NonPtrArg
         MachStr s      -> pushStr s
      where
         code rep
-           = let size_host_words = getPrimRepSize rep
+           = let size_host_words = cgRepSizeW rep
              in  returnBc (unitOL (PUSH_UBX (Left lit) size_host_words), 
                            size_host_words)
 
@@ -1256,7 +1250,7 @@ lookupBCEnv_maybe :: BCEnv -> Id -> Maybe Int
 lookupBCEnv_maybe = lookupFM
 
 idSizeW :: Id -> Int
-idSizeW id = getPrimRepSize (typePrimRep (idType id))
+idSizeW id = cgRepSizeW (typeCgRep (idType id))
 
 unboxedTupleException :: a
 unboxedTupleException 
@@ -1284,21 +1278,21 @@ isTypeAtom :: AnnExpr' id ann -> Bool
 isTypeAtom (AnnType _) = True
 isTypeAtom _           = False
 
-isVoidRepAtom :: AnnExpr' id ann -> Bool
-isVoidRepAtom (AnnVar v)        = typePrimRep (idType v) == VoidRep
-isVoidRepAtom (AnnNote n (_,e)) = isVoidRepAtom e
-isVoidRepAtom _                = False
+isVoidArgAtom :: AnnExpr' id ann -> Bool
+isVoidArgAtom (AnnVar v)        = typeCgRep (idType v) == VoidArg
+isVoidArgAtom (AnnNote n (_,e)) = isVoidArgAtom e
+isVoidArgAtom _                = False
 
-atomRep :: AnnExpr' Id ann -> PrimRep
-atomRep (AnnVar v)    = typePrimRep (idType v)
-atomRep (AnnLit l)    = literalPrimRep l
+atomRep :: AnnExpr' Id ann -> CgRep
+atomRep (AnnVar v)    = typeCgRep (idType v)
+atomRep (AnnLit l)    = typeCgRep (literalType l)
 atomRep (AnnNote n b) = atomRep (snd b)
 atomRep (AnnApp f (_, AnnType _)) = atomRep (snd f)
 atomRep (AnnLam x e) | isTyVar x = atomRep (snd e)
 atomRep other = pprPanic "atomRep" (ppr (deAnnotate (undefined,other)))
 
 isPtrAtom :: AnnExpr' Id ann -> Bool
-isPtrAtom e = isFollowableRep (atomRep e)
+isPtrAtom e = atomRep e == PtrArg
 
 -- Let szsw be the sizes in words of some items pushed onto the stack,
 -- which has initial depth d'.  Return the values which the stack environment
index 05c4fe4..43c5515 100644 (file)
@@ -17,11 +17,10 @@ import Id           ( Id )
 import CoreSyn
 import PprCore         ( pprCoreExpr, pprCoreAlt )
 import Literal         ( Literal )
-import PrimRep         ( PrimRep )
 import DataCon         ( DataCon )
 import VarSet          ( VarSet )
 import PrimOp          ( PrimOp )
-import SMRep           ( StgWord )
+import SMRep           ( StgWord, CgRep )
 import GHC.Ptr
 
 -- ----------------------------------------------------------------------------
@@ -59,7 +58,7 @@ data BCInstr
 
    -- Push an alt continuation
    | PUSH_ALTS          (ProtoBCO Name)
-   | PUSH_ALTS_UNLIFTED (ProtoBCO Name) PrimRep
+   | PUSH_ALTS_UNLIFTED (ProtoBCO Name) CgRep
 
    -- Pushing literals
    | PUSH_UBX  (Either Literal (Ptr ())) Int
@@ -125,7 +124,7 @@ data BCInstr
    -- To Infinity And Beyond
    | ENTER
    | RETURN            -- return a lifted value
-   | RETURN_UBX PrimRep -- return an unlifted value, here's its rep
+   | RETURN_UBX CgRep -- return an unlifted value, here's its rep
 
 -- -----------------------------------------------------------------------------
 -- Printing bytecode instructions
index 5325f8f..c44e562 100644 (file)
@@ -13,11 +13,11 @@ module ByteCodeItbls ( ItblEnv, ItblPtr, mkITbls ) where
 
 import Name            ( Name, getName )
 import NameEnv
-import Type            ( typePrimRep )
+import SMRep           ( typeCgRep )
 import DataCon         ( DataCon, dataConRepArgTys )
 import TyCon           ( TyCon, tyConFamilySize, isDataTyCon, tyConDataCons )
 import Constants       ( mIN_SIZE_NonUpdHeapObject )
-import ClosureInfo     ( mkVirtHeapOffsets )
+import CgHeapery       ( mkVirtHeapOffsets )
 import FastString      ( FastString(..) )
 import Util             ( lengthIs, listLengthCmp )
 
@@ -87,8 +87,10 @@ make_constr_itbls cons
 
         mk_itbl :: DataCon -> Int -> Ptr () -> IO (Name,ItblPtr)
         mk_itbl dcon conNo entry_addr
-           = let (tot_wds, ptr_wds, _) 
-                    = mkVirtHeapOffsets typePrimRep (dataConRepArgTys dcon)
+           = let rep_args = [ (typeCgRep arg,arg) 
+                           | arg <- dataConRepArgTys dcon ]
+                (tot_wds, ptr_wds, _) = mkVirtHeapOffsets rep_args
+
                  ptrs  = ptr_wds
                  nptrs = tot_wds - ptr_wds
                  nptrs_really
index c4b5aeb..38b2485 100644 (file)
@@ -1,6 +1,6 @@
 {-# OPTIONS -#include "Linker.h" #-}
 -----------------------------------------------------------------------------
--- $Id: InteractiveUI.hs,v 1.172 2004/08/12 13:10:35 simonmar Exp $
+-- $Id: InteractiveUI.hs,v 1.173 2004/08/13 13:06:42 simonmar Exp $
 --
 -- GHC Interactive User Interface
 --
@@ -12,7 +12,7 @@ module InteractiveUI (
        ghciWelcomeMsg
    ) where
 
-#include "../includes/config.h"
+#include "../includes/ghcconfig.h"
 #include "HsVersions.h"
 
 import CompManager
index 0879aa3..0849859 100644 (file)
@@ -20,7 +20,7 @@ module Linker ( HValue, showLinkerState,
                linkPackages,
        ) where
 
-#include "../includes/config.h"
+#include "../includes/ghcconfig.h"
 #include "HsVersions.h"
 
 import ObjLink         ( loadDLL, loadObj, unloadObj, resolveObjs, initObjLinker )
index 827bec8..3a61002 100644 (file)
@@ -40,12 +40,11 @@ import HscTypes             ( DeprecTxt )
 import CoreSyn         ( RuleName )
 import BasicTypes      ( Activation(..) )
 import ForeignCall     ( CCallTarget(..), DNCallSpec, CCallConv, Safety,
-                         CExportSpec(..)) 
+                         CExportSpec(..), CLabelString ) 
 
 -- others:
 import FunDeps         ( pprFundeps )
 import Class           ( FunDep )
-import CStrings                ( CLabelString )
 import Outputable      
 import Util            ( count )
 import SrcLoc          ( Located(..), unLoc )
index b68d236..64ed4ad 100644 (file)
@@ -210,7 +210,7 @@ data FloatOutSwitches
 data DynFlag
 
    -- debugging flags
-   = Opt_D_dump_absC
+   = Opt_D_dump_cmm
    | Opt_D_dump_asm
    | Opt_D_dump_cpranal
    | Opt_D_dump_deriv
@@ -220,7 +220,6 @@ data DynFlag
    | Opt_D_dump_inlinings
    | Opt_D_dump_occur_anal
    | Opt_D_dump_parsed
-   | Opt_D_dump_realC
    | Opt_D_dump_rn
    | Opt_D_dump_simpl
    | Opt_D_dump_simpl_iterations
@@ -235,7 +234,7 @@ data DynFlag
    | Opt_D_dump_worker_wrapper
    | Opt_D_dump_rn_trace
    | Opt_D_dump_rn_stats
-   | Opt_D_dump_stix
+   | Opt_D_dump_opt_cmm
    | Opt_D_dump_simpl_stats
    | Opt_D_dump_tc_trace
    | Opt_D_dump_if_trace
@@ -250,6 +249,7 @@ data DynFlag
    | Opt_D_dump_minimal_imports
    | Opt_DoCoreLinting
    | Opt_DoStgLinting
+   | Opt_DoCmmLinting
 
    | Opt_WarnIsError           -- -Werror; makes warnings fatal
    | Opt_WarnDuplicateExports
index 9a24fc0..7732497 100644 (file)
@@ -24,25 +24,27 @@ import qualified PrintJava
 import OccurAnal       ( occurAnalyseBinds )
 #endif
 
+import PprC            ( writeCs )
+import CmmLint         ( cmmLint )
 import Packages
 import DriverState     ( getExplicitPackagesAnd, getPackageCIncludes )
 import FastString      ( unpackFS )
-import AbsCSyn         ( AbstractC )
-import PprAbsC         ( dumpRealC, writeRealC )
+import Cmm             ( Cmm )
 import HscTypes
 import CmdLineOpts
-import ErrUtils                ( dumpIfSet_dyn, showPass )
+import ErrUtils                ( dumpIfSet_dyn, showPass, ghcExit )
 import Outputable
 import Pretty          ( Mode(..), printDoc )
 import Module          ( Module )
 import ListSetOps      ( removeDupsEq )
+import Maybes          ( firstJust )
 
-import Directory ( doesFileExist )
+import Directory       ( doesFileExist )
+import Data.List       ( intersperse )
 import Monad           ( when )
 import IO
 \end{code}
 
-
 %************************************************************************
 %*                                                                     *
 \subsection{Steering}
@@ -54,7 +56,7 @@ codeOutput :: DynFlags
           -> Module
           -> ForeignStubs
           -> Dependencies
-          -> AbstractC                 -- Compiled abstract C
+          -> [Cmm]                     -- Compiled C--
           -> IO (Bool{-stub_h_exists-}, Bool{-stub_c_exists-})
 
 codeOutput dflags this_mod foreign_stubs deps flat_abstractC
@@ -65,7 +67,17 @@ codeOutput dflags this_mod foreign_stubs deps flat_abstractC
 
     -- Dunno if the above comment is still meaningful now.  JRS 001024.
 
-    do { showPass dflags "CodeOutput"
+    do { when (dopt Opt_DoCmmLinting dflags) $ do
+               { showPass dflags "CmmLint"
+               ; let lints = map cmmLint flat_abstractC
+               ; case firstJust lints of
+                       Just err -> do { printDump err
+                                      ; ghcExit 1
+                                      }
+                       Nothing  -> return ()
+               }
+
+       ; showPass dflags "CodeOutput"
        ; let filenm = dopt_OutName dflags 
        ; stubs_exist <- outputForeignStubs dflags foreign_stubs
        ; case dopt_HscLang dflags of {
@@ -104,8 +116,7 @@ doOutput filenm io_action = bracket (openFile filenm WriteMode) hClose io_action
 \begin{code}
 outputC dflags filenm flat_absC 
        (stub_h_exists, _) dependencies foreign_stubs
-  = do dumpIfSet_dyn dflags Opt_D_dump_realC "Real C" (dumpRealC flat_absC)
-
+  = do 
        -- figure out which header files to #include in the generated .hc file:
        --
        --   * extra_includes from packages
@@ -142,7 +153,7 @@ outputC dflags filenm flat_absC
          hPutStr h cc_injects
          when stub_h_exists $ 
             hPutStrLn h ("#include \"" ++ (hscStubHOutName dflags) ++ "\"")
-         writeRealC h flat_absC
+         writeCs h flat_absC
 \end{code}
 
 
@@ -158,9 +169,8 @@ outputAsm dflags filenm flat_absC
 #ifndef OMIT_NATIVE_CODEGEN
 
   = do ncg_uniqs <- mkSplitUniqSupply 'n'
-       let (stix_final, ncg_output_d) = _scc_ "NativeCodeGen" 
-                                       nativeCodeGen flat_absC ncg_uniqs
-       dumpIfSet_dyn dflags Opt_D_dump_stix "Final stix code" stix_final
+       ncg_output_d <- _scc_ "NativeCodeGen" 
+                         nativeCodeGen dflags flat_absC ncg_uniqs
        dumpIfSet_dyn dflags Opt_D_dump_asm "Asm code" (docToSDoc ncg_output_d)
        _scc_ "OutputAsm" doOutput filenm $
           \f -> printDoc LeftMode f ncg_output_d
@@ -247,7 +257,7 @@ outputForeignStubs dflags (ForeignStubs h_code c_code _ _)
        stub_c_file_exists
            <- outputForeignStubs_help (hscStubCOutName dflags) stub_c_output_w
                ("#define IN_STG_CODE 0\n" ++ 
-                "#include \"RtsAPI.h\"\n" ++
+                "#include \"Rts.h\"\n" ++
                 rts_includes ++
                 cplusplus_hdr)
                 cplusplus_ftr
index 9d6a7cc..091a7de 100644 (file)
@@ -4,68 +4,7 @@
 \section[Constants]{Info about this compilation}
 
 \begin{code}
-module Constants (
-       mAX_CONTEXT_REDUCTION_DEPTH,
-       mAX_TUPLE_SIZE,
-
-       mAX_SPEC_THUNK_SIZE,
-       mAX_SPEC_FUN_SIZE,
-       mAX_SPEC_CONSTR_SIZE,
-       mAX_SPEC_SELECTEE_SIZE,
-       mAX_SPEC_AP_SIZE,
-
-       mIN_UPD_SIZE,
-       mIN_SIZE_NonUpdHeapObject,
-
-       sTD_HDR_SIZE,
-       pROF_HDR_SIZE,
-       gRAN_HDR_SIZE,
-       aRR_WORDS_HDR_SIZE,
-       aRR_PTRS_HDR_SIZE,
-        rESERVED_C_STACK_BYTES,
-        rESERVED_STACK_WORDS,
-
-       sTD_ITBL_SIZE,
-       rET_ITBL_SIZE,
-       pROF_ITBL_SIZE,
-       gRAN_ITBL_SIZE,
-       tICKY_ITBL_SIZE,
-
-       mAX_FAMILY_SIZE_FOR_VEC_RETURNS,
-
-       uF_SIZE,
-       pROF_UF_SIZE,
-       gRAN_UF_SIZE,  -- HWL
-       uF_RET,
-       uF_UPDATEE,
-
-       mAX_Vanilla_REG,
-       mAX_Float_REG,
-       mAX_Double_REG,
-       mAX_Long_REG,
-
-       mAX_Real_Vanilla_REG,
-       mAX_Real_Float_REG,
-       mAX_Real_Double_REG,
-       mAX_Real_Long_REG,
-
-       mAX_INTLIKE, mIN_INTLIKE,
-       mAX_CHARLIKE, mIN_CHARLIKE,
-
-       spRelToInt,
-
-       dOUBLE_SIZE,
-       iNT64_SIZE,
-       wORD64_SIZE,
-       
-       wORD_SIZE,
-       wORD_SIZE_IN_BITS,
-
-       bLOCK_SIZE,
-       bLOCK_SIZE_W,
-
-       bITMAP_BITS_SHIFT,
-    ) where
+module Constants (module Constants) where
 
 -- This magical #include brings in all the everybody-knows-these magic
 -- constants unfortunately, we need to be *explicit* about which one
@@ -73,7 +12,7 @@ module Constants (
 -- be in trouble.
 
 #include "HsVersions.h"
-#include "../includes/config.h"
+#include "../includes/ghcconfig.h"
 #include "../includes/MachRegs.h"
 #include "../includes/Constants.h"
 #include "../includes/MachDeps.h"
@@ -107,47 +46,20 @@ mIN_SIZE_NonUpdHeapObject  = (MIN_NONUPD_SIZE::Int)
 \end{code}
 
 \begin{code}
-mIN_INTLIKE, mAX_INTLIKE :: Integer    -- Only used to compare with (MachInt Integer)
+mIN_INTLIKE, mAX_INTLIKE :: Int        
 mIN_INTLIKE = MIN_INTLIKE
 mAX_INTLIKE = MAX_INTLIKE
 
-mIN_CHARLIKE, mAX_CHARLIKE :: Int      -- Only used to compare with (MachChar Int)
+mIN_CHARLIKE, mAX_CHARLIKE :: Int
 mIN_CHARLIKE = MIN_CHARLIKE
 mAX_CHARLIKE = MAX_CHARLIKE
 \end{code}
 
-A little function that abstracts the stack direction.  Note that most
-of the code generator is dependent on the stack direction anyway, so
-changing this on its own spells certain doom.  ToDo: remove?
-
-\begin{code}
--- THIS IS DIRECTION SENSITIVE!
-
--- stack grows down, positive virtual offsets correspond to negative
--- additions to the stack pointer.
-
-spRelToInt :: Int{-VirtualSpOffset-} -> Int{-VirtualSpOffset-} -> Int
-spRelToInt sp off = sp - off
-\end{code}
-
 A section of code-generator-related MAGIC CONSTANTS.
 
 \begin{code}
 mAX_FAMILY_SIZE_FOR_VEC_RETURNS = (MAX_VECTORED_RTN::Int)  -- pretty arbitrary
 -- If you change this, you may need to change runtimes/standard/Update.lhc
-
--- The update frame sizes
-uF_SIZE        = (STD_UF_SIZE::Int)
-
--- Same again, with profiling
-pROF_UF_SIZE = (PROF_UF_SIZE::Int)
-
--- Same again, with gransim
-gRAN_UF_SIZE = (GRAN_UF_SIZE::Int)
-
--- Offsets in an update frame.  They don't change with profiling!
-uF_RET         = (UF_RET::Int)
-uF_UPDATEE     = (UF_UPDATEE::Int)
 \end{code}
 
 \begin{code}
@@ -172,8 +84,6 @@ Closure header sizes.
 sTD_HDR_SIZE       = (STD_HDR_SIZE       :: Int)
 pROF_HDR_SIZE      = (PROF_HDR_SIZE      :: Int)
 gRAN_HDR_SIZE      = (GRAN_HDR_SIZE      :: Int)
-aRR_WORDS_HDR_SIZE = (ARR_WORDS_HDR_SIZE :: Int)
-aRR_PTRS_HDR_SIZE  = (ARR_PTRS_HDR_SIZE  :: Int)
 \end{code}
 
 Info Table sizes.
@@ -189,8 +99,8 @@ tICKY_ITBL_SIZE = (TICKY_ITBL_SIZE :: Int)
 Size of a double in StgWords.
 
 \begin{code}
-dOUBLE_SIZE     = (SIZEOF_DOUBLE `quot` SIZEOF_HSWORD :: Int)
-wORD64_SIZE     = (8 `quot` SIZEOF_HSWORD :: Int)
+dOUBLE_SIZE     = SIZEOF_DOUBLE :: Int
+wORD64_SIZE     = 8 :: Int
 iNT64_SIZE      = wORD64_SIZE
 \end{code}
 
@@ -219,7 +129,7 @@ Size of a storage manager block (in bytes).
 
 \begin{code}
 bLOCK_SIZE = (BLOCK_SIZE :: Int)
-bLOCK_SIZE_W = (bLOCK_SIZE `div` wORD_SIZE :: Int)
+bLOCK_SIZE_W = (bLOCK_SIZE `quot` wORD_SIZE :: Int)
 \end{code}
 
 Number of bits to shift a bitfield left by in an info table.
@@ -227,3 +137,10 @@ Number of bits to shift a bitfield left by in an info table.
 \begin{code}
 bITMAP_BITS_SHIFT = (BITMAP_BITS_SHIFT :: Int)
 \end{code}
+
+Constants derived from headers in ghc/includes, generated by the program
+../includes/mkDerivedConstants.c.
+
+\begin{code}
+#include "../includes/GHCConstants.h"
+\end{code}
index 766da42..c09e43a 100644 (file)
@@ -14,7 +14,7 @@ module DriverFlags (
   ) where
 
 #include "HsVersions.h"
-#include "../includes/config.h"
+#include "../includes/ghcconfig.h"
 
 import MkIface         ( showIface )
 import DriverState
@@ -347,7 +347,7 @@ dynamic_flags = [
        ------ Debugging ----------------------------------------------------
   ,  ( "dstg-stats",   NoArg (writeIORef v_StgStats True) )
 
-  ,  ( "ddump-absC",            NoArg (setDynFlag Opt_D_dump_absC) )
+  ,  ( "ddump-cmm",             NoArg (setDynFlag Opt_D_dump_cmm) )
   ,  ( "ddump-asm",             NoArg (setDynFlag Opt_D_dump_asm) )
   ,  ( "ddump-cpranal",         NoArg (setDynFlag Opt_D_dump_cpranal) )
   ,  ( "ddump-deriv",           NoArg (setDynFlag Opt_D_dump_deriv) )
@@ -357,7 +357,6 @@ dynamic_flags = [
   ,  ( "ddump-inlinings",       NoArg (setDynFlag Opt_D_dump_inlinings) )
   ,  ( "ddump-occur-anal",      NoArg (setDynFlag Opt_D_dump_occur_anal) )
   ,  ( "ddump-parsed",          NoArg (setDynFlag Opt_D_dump_parsed) )
-  ,  ( "ddump-realC",           NoArg (setDynFlag Opt_D_dump_realC) )
   ,  ( "ddump-rn",              NoArg (setDynFlag Opt_D_dump_rn) )
   ,  ( "ddump-simpl",           NoArg (setDynFlag Opt_D_dump_simpl) )
   ,  ( "ddump-simpl-iterations", NoArg (setDynFlag Opt_D_dump_simpl_iterations) )
@@ -376,7 +375,7 @@ dynamic_flags = [
   ,  ( "ddump-tc-trace",         NoArg (setDynFlag Opt_D_dump_tc_trace) )
   ,  ( "ddump-splices",          NoArg (setDynFlag Opt_D_dump_splices) )
   ,  ( "ddump-rn-stats",         NoArg (setDynFlag Opt_D_dump_rn_stats) )
-  ,  ( "ddump-stix",             NoArg (setDynFlag Opt_D_dump_stix) )
+  ,  ( "ddump-opt-cmm",          NoArg (setDynFlag Opt_D_dump_opt_cmm) )
   ,  ( "ddump-simpl-stats",      NoArg (setDynFlag Opt_D_dump_simpl_stats) )
   ,  ( "ddump-bcos",             NoArg (setDynFlag Opt_D_dump_BCOs) )
   ,  ( "dsource-stats",          NoArg (setDynFlag Opt_D_source_stats) )
@@ -388,6 +387,7 @@ dynamic_flags = [
   ,  ( "ddump-vect",            NoArg (setDynFlag Opt_D_dump_vect) )
   ,  ( "dcore-lint",            NoArg (setDynFlag Opt_DoCoreLinting) )
   ,  ( "dstg-lint",             NoArg (setDynFlag Opt_DoStgLinting) )
+  ,  ( "dcmm-lint",             NoArg (setDynFlag Opt_DoCmmLinting) )
 
        ------ Machine dependant (-m<blah>) stuff ---------------------------
 
index c094663..89a6100 100644 (file)
@@ -1,5 +1,5 @@
 -----------------------------------------------------------------------------
--- $Id: DriverPhases.hs,v 1.28 2003/10/22 14:31:09 simonmar Exp $
+-- $Id: DriverPhases.hs,v 1.29 2004/08/13 13:06:57 simonmar Exp $
 --
 -- GHC Driver
 --
@@ -7,7 +7,7 @@
 --
 -----------------------------------------------------------------------------
 
-#include "../includes/config.h"
+#include "../includes/ghcconfig.h"
 
 module DriverPhases (
    Phase(..),
@@ -54,6 +54,8 @@ data Phase
        | SplitAs
        | As
        | Ln
+       | CmmCpp        -- pre-process Cmm source
+       | Cmm           -- parse & compile Cmm code
 #ifdef ILX
         | Ilx2Il
        | Ilasm
@@ -65,10 +67,13 @@ data Phase
 -- pipeline will stop at some point (see DriverPipeline.runPipeline).
 x `happensBefore` y 
        | x `elem` haskell_pipe = y `elem` tail (dropWhile (/= x) haskell_pipe)
+       | x `elem` cmm_pipe     = y `elem` tail (dropWhile (/= x) cmm_pipe)
        | x `elem` c_pipe       = y `elem` tail (dropWhile (/= x) c_pipe)
        | otherwise = False
 
-haskell_pipe = [Unlit,Cpp,HsPp,Hsc,HCc,Mangle,SplitMangle,As,SplitAs,Ln]
+haskell_post_hsc = [HCc,Mangle,SplitMangle,As,SplitAs,Ln]
+haskell_pipe = Unlit : Cpp : HsPp : Hsc : haskell_post_hsc
+cmm_pipe     = CmmCpp : Cmm : haskell_post_hsc
 c_pipe       = [Cc,As,Ln]
 
 -- the first compilation phase for a given file is determined
@@ -88,6 +93,8 @@ startPhase "raw_s" = Mangle
 startPhase "s"     = As
 startPhase "S"     = As
 startPhase "o"     = Ln
+startPhase "cmm"   = CmmCpp
+startPhase "cmmcpp" = Cmm
 startPhase _       = Ln           -- all unknown file types
 
 -- the output suffix for a given phase is uniquely determined by
@@ -103,13 +110,15 @@ phaseInputExt SplitMangle = "split_s"     -- not really generated
 phaseInputExt As          = "s"
 phaseInputExt SplitAs     = "split_s"   -- not really generated
 phaseInputExt Ln          = "o"
+phaseInputExt CmmCpp     = "cmm"
+phaseInputExt Cmm        = "cmmcpp"
 #ifdef ILX
 phaseInputExt Ilx2Il      = "ilx"
 phaseInputExt Ilasm       = "il"
 #endif
 
-haskellish_suffixes          = [ "hs", "lhs", "hspp", "hscpp", "hcr", "hc", "raw_s" ]
-haskellish_src_suffixes      = [ "hs", "lhs", "hspp", "hscpp", "hcr"]
+haskellish_suffixes          = [ "hs", "lhs", "hspp", "hscpp", "hcr", "hc", "raw_s", "cmm" ]
+haskellish_src_suffixes      = [ "hs", "lhs", "hspp", "hscpp", "hcr", "cmm" ]
 cish_suffixes                = [ "c", "cpp", "C", "cc", "cxx", "s", "S" ]
 extcoreish_suffixes          = [ "hcr" ]
 haskellish_user_src_suffixes = [ "hs", "lhs" ]
index 072978a..81c2f46 100644 (file)
@@ -6,7 +6,7 @@
 --
 -----------------------------------------------------------------------------
 
-#include "../includes/config.h"
+#include "../includes/ghcconfig.h"
 
 module DriverPipeline (
 
@@ -491,40 +491,8 @@ runPhase Cpp basename suff input_fn get_output_fn maybe_loc
           -- to the next phase of the pipeline.
           return (Just HsPp, maybe_loc, input_fn)
        else do
-           hscpp_opts      <- getOpts opt_P
-                   hs_src_cpp_opts <- readIORef v_Hs_source_cpp_opts
-
-           cmdline_include_paths <- readIORef v_Include_paths
-
-           pkg_include_dirs <- getPackageIncludePath []
-           let include_paths = foldr (\ x xs -> "-I" : x : xs) []
-                                 (cmdline_include_paths ++ pkg_include_dirs)
-
-           verb <- getVerbFlag
-           (md_c_flags, _) <- machdepCCOpts
-
            output_fn <- get_output_fn HsPp maybe_loc
-
-           SysTools.runCpp ([SysTools.Option verb]
-                           ++ map SysTools.Option include_paths
-                           ++ map SysTools.Option hs_src_cpp_opts
-                           ++ map SysTools.Option hscpp_opts
-                           ++ map SysTools.Option md_c_flags
-                           ++ [ SysTools.Option     "-x"
-                              , SysTools.Option     "c"
-                              , SysTools.Option     input_fn
-       -- We hackily use Option instead of FileOption here, so that the file
-       -- name is not back-slashed on Windows.  cpp is capable of
-       -- dealing with / in filenames, so it works fine.  Furthermore
-       -- if we put in backslashes, cpp outputs #line directives
-       -- with *double* backslashes.   And that in turn means that
-       -- our error messages get double backslashes in them.
-       -- In due course we should arrange that the lexer deals
-       -- with these \\ escapes properly.
-                              , SysTools.Option     "-o"
-                              , SysTools.FileOption "" output_fn
-                              ])
-
+           doCpp True{-raw-} False{-no CC opts-} input_fn output_fn
            return (Just HsPp, maybe_loc, output_fn)
 
 -------------------------------------------------------------------------------
@@ -662,6 +630,34 @@ runPhase Hsc basename suff input_fn get_output_fn _maybe_loc = do
                      _ -> return (Just next_phase, Just location, output_fn)
 
 -----------------------------------------------------------------------------
+-- Cmm phase
+
+runPhase CmmCpp basename suff input_fn get_output_fn maybe_loc
+  = do
+       output_fn <- get_output_fn Cmm maybe_loc
+       doCpp False{-not raw-} True{-include CC opts-} input_fn output_fn       
+       return (Just Cmm, maybe_loc, output_fn)
+
+runPhase Cmm basename suff input_fn get_output_fn maybe_loc
+  = do
+        dyn_flags <- getDynFlags
+       hsc_lang <- hscMaybeAdjustLang (hscLang dyn_flags)
+       next_phase <- hscNextPhase hsc_lang
+       output_fn <- get_output_fn next_phase maybe_loc
+
+        let dyn_flags' = dyn_flags { hscLang = hsc_lang,
+                                    hscOutName = output_fn,
+                                    hscStubCOutName = basename ++ "_stub.c",
+                                    hscStubHOutName = basename ++ "_stub.h",
+                                    extCoreName = basename ++ ".hcr" }
+
+       ok <- hscCmmFile dyn_flags' input_fn
+
+       when (not ok) $ throwDyn (PhaseFailed "cmm" (ExitFailure 1))
+
+       return (Just next_phase, maybe_loc, output_fn)
+
+-----------------------------------------------------------------------------
 -- Cc phase
 
 -- we don't support preprocessing .c files (with -E) now.  Doing so introduces
@@ -1150,6 +1146,50 @@ doMkDLL o_files dep_packages = do
 -- -----------------------------------------------------------------------------
 -- Misc.
 
+doCpp :: Bool -> Bool -> FilePath -> FilePath -> IO ()
+doCpp raw include_cc_opts input_fn output_fn = do
+    hscpp_opts     <- getOpts opt_P
+
+    cmdline_include_paths <- readIORef v_Include_paths
+
+    pkg_include_dirs <- getPackageIncludePath []
+    let include_paths = foldr (\ x xs -> "-I" : x : xs) []
+                         (cmdline_include_paths ++ pkg_include_dirs)
+
+    verb <- getVerbFlag
+
+    cc_opts <- if not include_cc_opts 
+                 then return []
+                 else do optc <- getOpts opt_c
+                         (md_c_flags, _) <- machdepCCOpts
+                         return (optc ++ md_c_flags)
+
+    let cpp_prog args | raw       = SysTools.runCpp args
+                     | otherwise = SysTools.runCc (SysTools.Option "-E" : args)
+
+    cpp_prog       ([SysTools.Option verb]
+                   ++ map SysTools.Option include_paths
+                   ++ map SysTools.Option hsSourceCppOpts
+                   ++ map SysTools.Option hscpp_opts
+                   ++ map SysTools.Option cc_opts
+                   ++ [ SysTools.Option     "-x"
+                      , SysTools.Option     "c"
+                      , SysTools.Option     input_fn
+       -- We hackily use Option instead of FileOption here, so that the file
+       -- name is not back-slashed on Windows.  cpp is capable of
+       -- dealing with / in filenames, so it works fine.  Furthermore
+       -- if we put in backslashes, cpp outputs #line directives
+       -- with *double* backslashes.   And that in turn means that
+       -- our error messages get double backslashes in them.
+       -- In due course we should arrange that the lexer deals
+       -- with these \\ escapes properly.
+                      , SysTools.Option     "-o"
+                      , SysTools.FileOption "" output_fn
+                      ])
+
+-- -----------------------------------------------------------------------------
+-- Misc.
+
 hscNextPhase :: HscLang -> IO Phase
 hscNextPhase hsc_lang = do
   split <- readIORef v_Split_object_files
@@ -1171,8 +1211,6 @@ hscMaybeAdjustLang current_hsc_lang = do
         | current_hsc_lang == HscInterpreted = current_hsc_lang
        -- force -fvia-C if we are being asked for a .hc file
         | todo == StopBefore HCc  || keep_hc = HscC
-       -- force -fvia-C when profiling or ticky-ticky is on
-        | opt_SccProfilingOn || opt_DoTickyProfiling = HscC
        -- otherwise, stick to the plan
         | otherwise = current_hsc_lang
   return hsc_lang
index 543a487..a34d4a1 100644 (file)
@@ -1,5 +1,4 @@
 -----------------------------------------------------------------------------
--- $Id: DriverState.hs,v 1.104 2004/04/30 15:51:10 simonmar Exp $
 --
 -- Settings for the driver
 --
@@ -9,7 +8,7 @@
 
 module DriverState where
 
-#include "../includes/config.h"
+#include "../includes/ghcconfig.h"
 #include "HsVersions.h"
 
 import ParsePkgConf    ( loadPackageConfig )
@@ -71,14 +70,13 @@ isCompManagerMode _             = False
 -----------------------------------------------------------------------------
 -- Global compilation flags
 
--- Cpp-related flags
-v_Hs_source_cpp_opts = global
+-- Default CPP defines in Haskell source
+hsSourceCppOpts =
        [ "-D__HASKELL1__="++cHaskell1Version
        , "-D__GLASGOW_HASKELL__="++cProjectVersionInt                          
        , "-D__HASKELL98__"
        , "-D__CONCURRENT_HASKELL__"
        ]
-{-# NOINLINE v_Hs_source_cpp_opts #-}
 
 
 -- Keep output from intermediate phases
index 80ca04b..b8796c1 100644 (file)
@@ -1,5 +1,5 @@
 -----------------------------------------------------------------------------
--- $Id: DriverUtil.hs,v 1.42 2004/06/24 09:35:13 simonmar Exp $
+-- $Id: DriverUtil.hs,v 1.43 2004/08/13 13:07:02 simonmar Exp $
 --
 -- Utils for the driver
 --
@@ -19,7 +19,7 @@ module DriverUtil (
        remove_spaces, escapeSpaces,
   ) where
 
-#include "../includes/config.h"
+#include "../includes/ghcconfig.h"
 #include "HsVersions.h"
 
 import Util
index f5f0b9b..3a53644 100644 (file)
@@ -178,9 +178,7 @@ dumpIfSet_core dflags flag hdr doc
 dumpIfSet_dyn :: DynFlags -> DynFlag -> String -> SDoc -> IO ()
 dumpIfSet_dyn dflags flag hdr doc
   | dopt flag dflags || verbosity dflags >= 4 
-  = if   flag `elem` [Opt_D_dump_stix, Opt_D_dump_asm]
-    then printForC stdout (mkDumpDoc hdr doc)
-    else printDump (mkDumpDoc hdr doc)
+  = printDump (mkDumpDoc hdr doc)
   | otherwise
   = return ()
 
index 8187bab..7b1a102 100644 (file)
@@ -6,7 +6,7 @@
 
 \begin{code}
 module HscMain ( 
-       HscResult(..), hscMain, newHscEnv, hscBufferFrontEnd
+       HscResult(..), hscMain, newHscEnv, hscCmmFile, hscBufferFrontEnd
 #ifdef GHCI
        , hscStmt, hscTcExpr, hscKcType, hscThing, 
        , compileExpr
@@ -57,6 +57,7 @@ import CoreToStg      ( coreToStg )
 import Name            ( Name, NamedThing(..) )
 import SimplStg                ( stg2stg )
 import CodeGen         ( codeGen )
+import CmmParse                ( parseCmmFile )
 import CodeOutput      ( codeOutput )
 
 import CmdLineOpts
@@ -449,6 +450,18 @@ hscBackEnd dflags
    }
 
 
+hscCmmFile :: DynFlags -> FilePath -> IO Bool
+hscCmmFile dflags filename = do
+  maybe_cmm <- parseCmmFile dflags filename
+  case maybe_cmm of
+    Nothing -> return False
+    Just cmm -> do
+       codeOutput dflags no_mod NoStubs noDependencies [cmm]
+       return True
+  where
+       no_mod = panic "hscCmmFile: no_mod"
+
+
 myParseModule dflags src_filename
  = do --------------------------  Parser  ----------------
       showPass dflags "Parser"
index cf25bde..7a2ae0c 100644 (file)
@@ -1,7 +1,7 @@
 {-# OPTIONS -fno-warn-incomplete-patterns -optc-DNON_POSIX_SOURCE #-}
 
 -----------------------------------------------------------------------------
--- $Id: Main.hs,v 1.137 2004/08/12 13:10:40 simonmar Exp $
+-- $Id: Main.hs,v 1.138 2004/08/13 13:07:05 simonmar Exp $
 --
 -- GHC Driver program
 --
@@ -10,7 +10,7 @@
 -----------------------------------------------------------------------------
 
 -- with path so that ghc -M can find config.h
-#include "../includes/config.h"
+#include "../includes/ghcconfig.h"
 
 module Main (main) where
 
@@ -168,14 +168,10 @@ main =
    -- by module basis, using only the -fvia-C and -fasm flags.  If the global
    -- HscLang is not HscC or HscAsm, -fvia-C and -fasm have no effect.
    dyn_flags <- getDynFlags
-   build_tag <- readIORef v_Build_tag
    let lang = case mode of 
                 DoInteractive  -> HscInterpreted
                 DoEval _       -> HscInterpreted
-                _other | build_tag /= "" -> HscC
-                       | otherwise       -> hscLang dyn_flags
-               -- for ways other that the normal way, we must 
-               -- compile via C.
+                _other         -> hscLang dyn_flags
 
    setDynFlags (dyn_flags{ stgToDo  = stg_todo,
                           hscLang  = lang,
index da65fe2..fcd62de 100644 (file)
@@ -84,7 +84,7 @@ import IO             ( try, catch,
 import Directory       ( doesFileExist, removeFile )
 import List             ( partition )
 
-#include "../includes/config.h"
+#include "../includes/ghcconfig.h"
 
 -- GHC <= 4.08 didn't have rawSystem, and runs into problems with long command
 -- lines on mingw32, so we disallow it now.
diff --git a/ghc/compiler/nativeGen/AbsCStixGen.lhs b/ghc/compiler/nativeGen/AbsCStixGen.lhs
deleted file mode 100644 (file)
index 4a53f14..0000000
+++ /dev/null
@@ -1,694 +0,0 @@
-%
-% (c) The AQUA Project, Glasgow University, 1993-1998
-%
-
-\begin{code}
-module AbsCStixGen ( genCodeAbstractC ) where
-
-#include "HsVersions.h"
-
-import Ratio   ( Rational )
-
-import AbsCSyn
-import Stix
-import MachMisc
-
-import AbsCUtils       ( getAmodeRep, mixedTypeLocn,
-                         nonemptyAbsC, mkAbsCStmts
-                       )
-import PprAbsC          ( dumpRealC )
-import SMRep           ( retItblSize )
-import CLabel           ( CLabel, mkReturnInfoLabel, mkReturnPtLabel,
-                          mkClosureTblLabel, mkClosureLabel,
-                         labelDynamic, mkSplitMarkerLabel )
-import ClosureInfo
-import Literal         ( Literal(..), word2IntLit )
-import StgSyn          ( StgOp(..) )
-import MachOp          ( MachOp(..), resultRepOfMachOp )
-import PrimRep         ( isFloatingRep, is64BitRep, 
-                         PrimRep(..), getPrimRepSizeInBytes )
-import StixMacro       ( macroCode, checkCode )
-import StixPrim                ( foreignCallCode, amodeToStix, amodeToStix' )
-import Outputable       ( pprPanic, ppr )
-import UniqSupply      ( returnUs, thenUs, mapUs, getUniqueUs, UniqSM )
-import Util            ( naturalMergeSortLe )
-import Panic           ( panic )
-import TyCon           ( tyConDataCons )
-import Name             ( NamedThing(..) )
-import CmdLineOpts     ( opt_EnsureSplittableC )
-import Outputable      ( assertPanic )
-
-import Char            ( ord )
-
--- DEBUGGING ONLY
---import TRACE         ( trace )
---import Outputable    ( showSDoc )
---import MachOp                ( pprMachOp )
-
-#include "nativeGen/NCG.h"
-\end{code}
-
-For each independent chunk of AbstractC code, we generate a list of
-@StixTree@s, where each tree corresponds to a single Stix instruction.
-We leave the chunks separated so that register allocation can be
-performed locally within the chunk.
-
-\begin{code}
-genCodeAbstractC :: AbstractC -> UniqSM [StixStmt]
-
-genCodeAbstractC absC
-  = gentopcode absC
- where
- a2stix      = amodeToStix
- a2stix'     = amodeToStix'
- volsaves    = volatileSaves
- volrestores = volatileRestores
- -- real code follows... ---------
-\end{code}
-
-Here we handle top-level things, like @CCodeBlock@s and
-@CClosureInfoTable@s.
-
-\begin{code}
- {-
- genCodeTopAbsC
-    :: AbstractC
-    -> UniqSM [StixTree]
- -}
-
- gentopcode (CCodeBlock lbl absC)
-  = gencode absC                               `thenUs` \ code ->
-    returnUs (StSegment TextSegment : StFunBegin lbl : code [StFunEnd lbl])
-
- gentopcode stmt@(CStaticClosure lbl closure_info _ _)
-  = genCodeStaticClosure stmt                  `thenUs` \ code ->
-    returnUs ( StSegment DataSegment 
-             : StLabel lbl : code []
-             )
-
- gentopcode stmt@(CRetVector lbl amodes srt liveness)
-  = returnUs ( StSegment TextSegment
-            : StData PtrRep table
-            : StLabel lbl
-            : []
-            )
-  where
-    table = map amodeToStix (mkVecInfoTable amodes srt liveness)
-
- gentopcode stmt@(CRetDirect uniq absC srt liveness)
-  = gencode absC                                      `thenUs` \ code ->
-    returnUs ( StSegment TextSegment
-            : StData PtrRep table
-            : StLabel info_lbl
-            : StLabel ret_lbl
-            : code [])
-  where 
-    info_lbl = mkReturnInfoLabel uniq
-    ret_lbl  = mkReturnPtLabel uniq
-    table    = map amodeToStix (mkRetInfoTable ret_lbl srt liveness)
-
- gentopcode stmt@(CClosureInfoAndCode cl_info entry)
-  = gencode entry                      `thenUs` \ slow_code ->
-    returnUs ( StSegment TextSegment
-            : StData PtrRep table
-            : StLabel info_lbl
-            : StFunBegin entry_lbl
-            : slow_code [StFunEnd entry_lbl])
-  where
-    entry_lbl = entryLabelFromCI cl_info
-    info_lbl = infoTableLabelFromCI cl_info
-    table    = map amodeToStix (mkInfoTable cl_info)
-
- gentopcode stmt@(CSRT lbl closures)
-  = returnUs [ StSegment TextSegment 
-            , StLabel lbl 
-            , StData DataPtrRep (map mk_StCLbl_for_SRT closures)
-            ]
-    where
-       mk_StCLbl_for_SRT :: CLabel -> StixExpr
-       mk_StCLbl_for_SRT label
-          | labelDynamic label
-          = StIndex Int8Rep (StCLbl label) (StInt 1)
-          | otherwise
-          = StCLbl label
-
- gentopcode stmt@(CBitmap l@(Liveness lbl size mask))
-  = returnUs 
-       [ StSegment TextSegment 
-       , StLabel lbl 
-       , StData WordRep (map StInt (toInteger size : map toInteger mask))
-       ]
-
- gentopcode stmt@(CSRTDesc lbl srt_lbl off len bitmap)
-  = returnUs 
-       [ StSegment TextSegment 
-       , StLabel lbl 
-       , StData WordRep (
-               StIndex PtrRep (StCLbl srt_lbl) (StInt (toInteger off)) :
-               map StInt (toInteger len : map toInteger bitmap)
-           )
-       ]
-
- gentopcode stmt@(CClosureTbl tycon)
-  = returnUs [ StSegment TextSegment
-             , StLabel (mkClosureTblLabel tycon)
-             , StData DataPtrRep (map (StCLbl . mkClosureLabel . getName) 
-                                      (tyConDataCons tycon) )
-             ]
-
- gentopcode stmt@(CModuleInitBlock plain_lbl lbl absC)
-  = gencode absC                       `thenUs` \ code ->
-    getUniqLabelNCG                    `thenUs` \ tmp_lbl ->
-    getUniqLabelNCG                    `thenUs` \ flag_lbl ->
-    returnUs ( StSegment DataSegment
-            : StLabel flag_lbl
-            : StData IntRep [StInt 0]
-            : StSegment TextSegment
-            : StLabel plain_lbl
-            : StJump NoDestInfo (StCLbl lbl)
-            : StLabel lbl
-            : StCondJump tmp_lbl (StMachOp MO_Nat_Ne
-                                    [StInd IntRep (StCLbl flag_lbl),
-                                     StInt 0])
-            : StAssignMem IntRep (StCLbl flag_lbl) (StInt 1)
-            : code 
-            [ StLabel tmp_lbl
-            , StAssignReg PtrRep stgSp
-                           (StIndex PtrRep (StReg stgSp) (StInt (-1)))
-            , StJump NoDestInfo (StInd WordRep (StReg stgSp))
-            ])
-
- gentopcode absC
-  = gencode absC                               `thenUs` \ code ->
-    returnUs (StSegment TextSegment : code [])
-\end{code}
-
-\begin{code}
- {-
- genCodeStaticClosure
-    :: AbstractC
-    -> UniqSM StixTreeList
- -}
- genCodeStaticClosure (CStaticClosure lbl cl_info cost_centre amodes)
-  = returnUs (\xs -> table ++ xs)
-  where
-    table = StData PtrRep [StCLbl (infoTableLabelFromCI cl_info)] : 
-           foldr do_one_amode [] amodes
-
-    do_one_amode amode rest
-       | rep == VoidRep = rest
-       | otherwise      = StData (promote_to_word rep) [a2stix amode] : rest
-       where 
-         rep = getAmodeRep amode
-
-    -- We need to promote any item smaller than a word to a word
-    promote_to_word pk 
-       | getPrimRepSizeInBytes pk >= getPrimRepSizeInBytes IntRep  = pk
-       | otherwise                                                 = IntRep
-\end{code}
-
-Now the individual AbstractC statements.
-
-\begin{code}
- {-
- gencode
-    :: AbstractC
-    -> UniqSM StixTreeList
- -}
-\end{code}
-
-@AbsCNop@s just disappear.
-
-\begin{code}
-
- gencode AbsCNop = returnUs id
-
-\end{code}
-
-Split markers just insert a __stg_split_marker, which is caught by the
-split-mangler later on and used to split the assembly into chunks.
-
-\begin{code}
-
- gencode CSplitMarker
-   | opt_EnsureSplittableC = returnUs (\xs -> StLabel mkSplitMarkerLabel : xs)
-   | otherwise             = returnUs id
-
-\end{code}
-
-AbstractC instruction sequences are handled individually, and the
-resulting StixTreeLists are joined together.
-
-\begin{code}
-
- gencode (AbsCStmts c1 c2)
-  = gencode c1                         `thenUs` \ b1 ->
-    gencode c2                         `thenUs` \ b2 ->
-    returnUs (b1 . b2)
-
- gencode (CSequential stuff)
-  = foo stuff
-    where
-       foo [] = returnUs id
-       foo (s:ss) = gencode s  `thenUs` \ stix ->
-                    foo ss     `thenUs` \ stixes ->
-                    returnUs (stix . stixes)
-
-\end{code}
-
-Initialising closure headers in the heap...a fairly complex ordeal if
-done properly. For now, we just set the info pointer, but we should
-really take a peek at the flags to determine whether or not there are
-other things to be done (setting cost centres, age headers, global
-addresses, etc.)
-
-\begin{code}
-
- gencode (CInitHdr cl_info reg_rel _ _)
-  = let
-       lhs = a2stix reg_rel
-       lbl = infoTableLabelFromCI cl_info
-    in
-       returnUs (\xs -> StAssignMem PtrRep lhs (StCLbl lbl) : xs)
-
-\end{code}
-
-Heap/Stack Checks.
-
-\begin{code}
-
- gencode (CCheck macro args assts)
-  = gencode assts `thenUs` \assts_stix ->
-    checkCode macro args assts_stix
-
-\end{code}
-
-Assignment, the curse of von Neumann, is the center of the code we
-produce.  In most cases, the type of the assignment is determined
-by the type of the destination.  However, when the destination can
-have mixed types, the type of the assignment is ``StgWord'' (we use
-PtrRep for lack of anything better).  Think:  do we also want a cast
-of the source?  Be careful about floats/doubles.
-
-\begin{code}
-
- gencode (CAssign lhs rhs)
-  | lhs_rep == VoidRep 
-  = returnUs id
-  | otherwise
-  = let -- This is a Hack.  Should be cleaned up.
-        -- JRS, 10 Dec 01
-        pk' | ncg_target_is_32bit && is64BitRep lhs_rep
-            = lhs_rep
-            | otherwise
-            = if   mixedTypeLocn lhs && not (isFloatingRep lhs_rep) 
-              then IntRep 
-              else lhs_rep
-       lhs' = a2stix lhs
-       rhs' = a2stix' rhs
-    in
-       returnUs (\xs -> mkStAssign pk' lhs' rhs' : xs)
-    where 
-       lhs_rep = getAmodeRep lhs
-
-\end{code}
-
-Unconditional jumps, including the special ``enter closure'' operation.
-Note that the new entry convention requires that we load the InfoPtr (R2)
-with the address of the info table before jumping to the entry code for Node.
-
-For a vectored return, we must subtract the size of the info table to
-get at the return vector.  This depends on the size of the info table,
-which varies depending on whether we're profiling etc.
-
-\begin{code}
-
- gencode (CJump dest)
-  = returnUs (\xs -> StJump NoDestInfo (a2stix dest) : xs)
-
- gencode (CFallThrough (CLbl lbl _))
-  = returnUs (\xs -> StFallThrough lbl : xs)
-
- gencode (CReturn dest DirectReturn)
-  = returnUs (\xs -> StJump NoDestInfo (a2stix dest) : xs)
-
- gencode (CReturn table (StaticVectoredReturn n))
-  = returnUs (\xs -> StJump NoDestInfo dest : xs)
-  where
-    dest = StInd PtrRep (StIndex PtrRep (a2stix table)
-                                 (StInt (toInteger (-n-retItblSize-1))))
-
- gencode (CReturn table (DynamicVectoredReturn am))
-  = returnUs (\xs -> StJump NoDestInfo dest : xs)
-  where
-    dest = StInd PtrRep (StIndex PtrRep (a2stix table) dyn_off)
-    dyn_off = StMachOp MO_Nat_Sub [StMachOp MO_NatS_Neg [a2stix am], 
-                                  StInt (toInteger (retItblSize+1))]
-
-\end{code}
-
-Now the PrimOps, some of which may need caller-saves register wrappers.
-
-\begin{code}
- gencode (COpStmt results (StgFCallOp fcall _) args vols)
-  = ASSERT( null vols )
-    foreignCallCode (nonVoid results) fcall (nonVoid args)
-
- gencode (COpStmt results (StgPrimOp op) args vols)
-  = panic "AbsCStixGen.gencode: un-translated PrimOp"
-
- gencode (CMachOpStmt res mop args vols)
-  = returnUs (\xs -> mkStAssign (resultRepOfMachOp mop) (a2stix res) 
-                                (StMachOp mop (map a2stix args))
-                     : xs
-             )
-\end{code}
-
-Now the dreaded conditional jump.
-
-Now the if statement.  Almost *all* flow of control are of this form.
-@
-       if (am==lit) { absC } else { absCdef }
-@
-       =>
-@
-       IF am = lit GOTO l1:
-       absC
-       jump l2:
-   l1:
-       absCdef
-   l2:
-@
-
-\begin{code}
-
- gencode (CSwitch discrim alts deflt)
-  = case alts of
-      [] -> gencode deflt
-
-      [(tag,alt_code)] -> case maybe_empty_deflt of
-                               Nothing -> gencode alt_code
-                               Just dc -> mkIfThenElse discrim tag alt_code dc
-
-      [(tag1@(MachInt i1), alt_code1),
-       (tag2@(MachInt i2), alt_code2)]
-       | deflt_is_empty && i1 == 0 && i2 == 1
-       -> mkIfThenElse discrim tag1 alt_code1 alt_code2
-       | deflt_is_empty && i1 == 1 && i2 == 0
-       -> mkIfThenElse discrim tag2 alt_code2 alt_code1
-
-       -- If the @discrim@ is simple, then this unfolding is safe.
-      other | simple_discrim -> mkSimpleSwitches discrim alts deflt
-
-       -- Otherwise, we need to do a bit of work.
-      other ->  getUniqueUs                      `thenUs` \ u ->
-               gencode (AbsCStmts
-               (CAssign (CTemp u pk) discrim)
-               (CSwitch (CTemp u pk) alts deflt))
-
-  where
-    maybe_empty_deflt = nonemptyAbsC deflt
-    deflt_is_empty = case maybe_empty_deflt of
-                       Nothing -> True
-                       Just _  -> False
-
-    pk = getAmodeRep discrim
-
-    simple_discrim = case discrim of
-                       CReg _    -> True
-                       CTemp _ _ -> True
-                       other     -> False
-\end{code}
-
-
-
-Finally, all of the disgusting AbstractC macros.
-
-\begin{code}
-
- gencode (CMacroStmt macro args) = macroCode macro (map amodeToStix args)
-
- gencode (CCallProfCtrMacro macro _)
-  = returnUs (\xs -> StComment macro : xs)
-
- gencode (CCallProfCCMacro macro _)
-  = returnUs (\xs -> StComment macro : xs)
-
- gencode CCallTypedef{} = returnUs id
-
- gencode other
-  = pprPanic "AbsCStixGen.gencode" (dumpRealC other)
-
- nonVoid = filter ((/= VoidRep) . getAmodeRep)
-\end{code}
-
-Here, we generate a jump table if there are more than four (integer)
-alternatives and the jump table occupancy is greater than 50%.
-Otherwise, we generate a binary comparison tree.  (Perhaps this could
-be tuned.)
-
-\begin{code}
-
- intTag :: Literal -> Integer
- intTag (MachChar c)  = toInteger (ord c)
- intTag (MachInt i)   = i
- intTag (MachWord w)  = intTag (word2IntLit (MachWord w))
- intTag _             = panic "intTag"
-
- fltTag :: Literal -> Rational
-
- fltTag (MachFloat f)  = f
- fltTag (MachDouble d) = d
- fltTag x              = pprPanic "fltTag" (ppr x)
-
- {-
- mkSimpleSwitches
-    :: CAddrMode -> [(Literal,AbstractC)] -> AbstractC
-    -> UniqSM StixTreeList
- -}
- mkSimpleSwitches am alts absC
-  = getUniqLabelNCG                                    `thenUs` \ udlbl ->
-    getUniqLabelNCG                                    `thenUs` \ ujlbl ->
-    let am' = a2stix am
-       joinedAlts = map (\ (tag,code) -> (tag, mkJoin code ujlbl)) alts
-       sortedAlts = naturalMergeSortLe leAlt joinedAlts
-                    -- naturalMergeSortLe, because we often get sorted alts to begin with
-
-       lowTag = intTag (fst (head sortedAlts))
-       highTag = intTag (fst (last sortedAlts))
-
-       -- lowest and highest possible values the discriminant could take
-       lowest = if floating then targetMinDouble else targetMinInt
-       highest = if floating then targetMaxDouble else targetMaxInt
-    in
-       (
-       if  not floating && choices > 4 
-            && highTag - lowTag < toInteger (2 * choices)
-        then
-           mkJumpTable am' sortedAlts lowTag highTag udlbl
-       else
-           mkBinaryTree am' floating sortedAlts choices lowest highest udlbl
-       )
-                                               `thenUs` \ alt_code ->
-       gencode absC                            `thenUs` \ dflt_code ->
-
-       returnUs (\xs -> alt_code (StLabel udlbl : dflt_code (StLabel ujlbl : xs)))
-
-    where
-       floating = isFloatingRep (getAmodeRep am)
-       choices = length alts
-
-       (x@(MachChar _),_)  `leAlt` (y,_) = intTag x <= intTag y
-       (x@(MachInt _), _)  `leAlt` (y,_) = intTag x <= intTag y
-       (x@(MachWord _), _) `leAlt` (y,_) = intTag x <= intTag y
-       (x,_)               `leAlt` (y,_) = fltTag x <= fltTag y
-
-\end{code}
-
-We use jump tables when doing an integer switch on a relatively dense
-list of alternatives.  We expect to be given a list of alternatives,
-sorted by tag, and a range of values for which we are to generate a
-table.  Of course, the tags of the alternatives should lie within the
-indicated range.  The alternatives need not cover the range; a default
-target is provided for the missing alternatives.
-
-If a join is necessary after the switch, the alternatives should
-already finish with a jump to the join point.
-
-\begin{code}
- {-
- mkJumpTable
-    :: StixTree                -- discriminant
-    -> [(Literal, AbstractC)]  -- alternatives
-    -> Integer                         -- low tag
-    -> Integer                         -- high tag
-    -> CLabel                  -- default label
-    -> UniqSM StixTreeList
- -}
-
- mkJumpTable am alts lowTag highTag dflt
-  = getUniqLabelNCG                                    `thenUs` \ utlbl ->
-    mapUs genLabel alts                                `thenUs` \ branches ->
-    let        cjmpLo = StCondJump dflt (StMachOp MO_NatS_Lt [am, StInt (toInteger lowTag)])
-       cjmpHi = StCondJump dflt (StMachOp MO_NatS_Gt [am, StInt (toInteger highTag)])
-
-       offset = StMachOp MO_Nat_Sub [am, StInt lowTag]
-        dsts   = DestInfo (dflt : map fst branches)
-
-       jump = StJump dsts (StInd PtrRep (StIndex PtrRep (StCLbl utlbl) offset))
-       tlbl = StLabel utlbl
-       table = StData PtrRep (mkTable branches [lowTag..highTag] [])
-    in
-       mapUs mkBranch branches                         `thenUs` \ alts ->
-
-       returnUs (\xs -> cjmpLo : cjmpHi : jump :
-                        StSegment DataSegment : tlbl : table :
-                        StSegment TextSegment : foldr1 (.) alts xs)
-
-    where
-       genLabel x = getUniqLabelNCG `thenUs` \ lbl -> returnUs (lbl, x)
-
-       mkBranch (lbl,(_,alt)) =
-           gencode alt                         `thenUs` \ alt_code ->
-           returnUs (\xs -> StLabel lbl : alt_code xs)
-
-       mkTable _  []     tbl = reverse tbl
-       mkTable [] (x:xs) tbl = mkTable [] xs (StCLbl dflt : tbl)
-       mkTable alts@((lbl,(tag,_)):rest) (x:xs) tbl
-         | intTag tag == x = mkTable rest xs (StCLbl lbl : tbl)
-         | otherwise = mkTable alts xs (StCLbl dflt : tbl)
-
-\end{code}
-
-We generate binary comparison trees when a jump table is inappropriate.
-We expect to be given a list of alternatives, sorted by tag, and for
-convenience, the length of the alternative list.  We recursively break
-the list in half and do a comparison on the first tag of the second half
-of the list.  (Odd lists are broken so that the second half of the list
-is longer.)  We can handle either integer or floating kind alternatives,
-so long as they are not mixed.  (We assume that the type of the discriminant
-determines the type of the alternatives.)
-
-As with the jump table approach, if a join is necessary after the switch, the
-alternatives should already finish with a jump to the join point.
-
-\begin{code}
- {-
- mkBinaryTree
-    :: StixTree                -- discriminant
-    -> Bool                    -- floating point?
-    -> [(Literal, AbstractC)]  -- alternatives
-    -> Int                     -- number of choices
-    -> Literal                 -- low tag
-    -> Literal                 -- high tag
-    -> CLabel                  -- default code label
-    -> UniqSM StixTreeList
- -}
-
- mkBinaryTree am floating [(tag,alt)] _ lowTag highTag udlbl
-  | rangeOfOne = gencode alt
-  | otherwise
-  = let        tag' = a2stix (CLit tag)
-       cmpOp = if floating then MO_Dbl_Ne else MO_Nat_Ne
-       test = StMachOp cmpOp [am, tag']
-       cjmp = StCondJump udlbl test
-    in
-       gencode alt                             `thenUs` \ alt_code ->
-       returnUs (\xs -> cjmp : alt_code xs)
-
-    where
-       rangeOfOne = not floating && intTag lowTag + 1 >= intTag highTag
-       -- When there is only one possible tag left in range, we skip the comparison
-
- mkBinaryTree am floating alts choices lowTag highTag udlbl
-  = getUniqLabelNCG                                    `thenUs` \ uhlbl ->
-    let tag' = a2stix (CLit splitTag)
-       cmpOp = if floating then MO_Dbl_Ge else MO_NatS_Ge
-       test = StMachOp cmpOp [am, tag']
-       cjmp = StCondJump uhlbl test
-    in
-       mkBinaryTree am floating alts_lo half lowTag splitTag udlbl
-                                                       `thenUs` \ lo_code ->
-       mkBinaryTree am floating alts_hi (choices - half) splitTag highTag udlbl
-                                                       `thenUs` \ hi_code ->
-
-       returnUs (\xs -> cjmp : lo_code (StLabel uhlbl : hi_code xs))
-
-    where
-       half = choices `div` 2
-       (alts_lo, alts_hi) = splitAt half alts
-       splitTag = fst (head alts_hi)
-
-\end{code}
-
-\begin{code}
- {-
- mkIfThenElse
-    :: CAddrMode           -- discriminant
-    -> Literal             -- tag
-    -> AbstractC           -- if-part
-    -> AbstractC           -- else-part
-    -> UniqSM StixTreeList
- -}
-
- mkIfThenElse discrim tag alt deflt
-  = getUniqLabelNCG                                    `thenUs` \ ujlbl ->
-    getUniqLabelNCG                                    `thenUs` \ utlbl ->
-    let discrim' = a2stix discrim
-       tag' = a2stix (CLit tag)
-       cmpOp = if (isFloatingRep (getAmodeRep discrim)) then MO_Dbl_Ne else MO_Nat_Ne
-       test = StMachOp cmpOp [discrim', tag']
-       cjmp = StCondJump utlbl test
-       dest = StLabel utlbl
-       join = StLabel ujlbl
-    in
-       gencode (mkJoin alt ujlbl)              `thenUs` \ alt_code ->
-       gencode deflt                           `thenUs` \ dflt_code ->
-       returnUs (\xs -> cjmp : alt_code (dest : dflt_code (join : xs)))
-
-
-mkJoin :: AbstractC -> CLabel -> AbstractC
-mkJoin code lbl
-  | mightFallThrough code = mkAbsCStmts code (CJump (CLbl lbl PtrRep))
-  | otherwise = code
-\end{code}
-
-%---------------------------------------------------------------------------
-
-This answers the question: Can the code fall through to the next
-line(s) of code?  This errs towards saying True if it can't choose,
-because it is used for eliminating needless jumps.  In other words, if
-you might possibly {\em not} jump, then say yes to falling through.
-
-\begin{code}
-mightFallThrough :: AbstractC -> Bool
-
-mightFallThrough absC = ft absC True
- where
-  ft AbsCNop      if_empty = if_empty
-
-  ft (CJump _)       if_empty = False
-  ft (CReturn _ _)   if_empty = False
-  ft (CSwitch _ alts deflt) if_empty
-       = ft deflt if_empty ||
-         or [ft alt if_empty | (_,alt) <- alts]
-
-  ft (AbsCStmts c1 c2) if_empty = ft c2 (ft c1 if_empty)
-  ft _ if_empty = if_empty
-
-{- Old algorithm, which called nonemptyAbsC for every subexpression! =========
-fallThroughAbsC (AbsCStmts c1 c2)
-  = case nonemptyAbsC c2 of
-       Nothing -> fallThroughAbsC c1
-       Just x -> fallThroughAbsC x
-fallThroughAbsC (CJump _)       = False
-fallThroughAbsC (CReturn _ _)   = False
-fallThroughAbsC (CSwitch _ choices deflt)
-  = (not (isEmptyAbsC deflt) && fallThroughAbsC deflt)
-    || or (map (fallThroughAbsC . snd) choices)
-fallThroughAbsC other           = True
-
-isEmptyAbsC :: AbstractC -> Bool
-isEmptyAbsC = not . maybeToBool . nonemptyAbsC
-================= End of old, quadratic, algorithm -}
-\end{code}
index 6510b41..b2fcb6c 100644 (file)
@@ -1,6 +1,10 @@
-%
-% (c) The AQUA Project, Glasgow University, 1993-1998
-%
+-- -----------------------------------------------------------------------------
+--
+-- (c) The University of Glasgow 1993-2004
+-- 
+-- This is the top-level module in the native code generator.
+--
+-- -----------------------------------------------------------------------------
 
 \begin{code}
 module AsmCodeGen ( nativeCodeGen ) where
@@ -8,34 +12,35 @@ module AsmCodeGen ( nativeCodeGen ) where
 #include "HsVersions.h"
 #include "NCG.h"
 
-import MachMisc
+import MachInstrs
 import MachRegs
-import MachCode
+import MachCodeGen
 import PprMach
+import RegisterAlloc
+import RegAllocInfo    ( jumpDests )
+import NCGMonad
+
+import Cmm
+import PprCmm          ( pprStmt, pprCmms )
+import MachOp
+import CLabel           ( CLabel, mkSplitMarkerLabel )
+#if powerpc_TARGET_ARCH
+import CLabel           ( mkRtsCodeLabel )
+#endif
 
-import AbsCStixGen     ( genCodeAbstractC )
-import AbsCSyn         ( AbstractC, MagicId(..) )
-import AbsCUtils       ( mkAbsCStmtList, magicIdPrimRep )
-import AsmRegAlloc     ( runRegAllocate )
-import MachOp          ( MachOp(..), isCommutableMachOp, isComparisonMachOp )
-import RegAllocInfo    ( findReservedRegs )
-import Stix            ( StixReg(..), StixStmt(..), StixExpr(..), StixVReg(..),
-                          pprStixStmts, pprStixStmt, 
-                          stixStmt_CountTempUses, stixStmt_Subst,
-                          liftStrings,
-                          initNat, 
-                          mkNatM_State,
-                          uniqOfNatM_State, deltaOfNatM_State,
-                         importsOfNatM_State )
-import UniqSupply      ( returnUs, thenUs, initUs, 
-                          UniqSM, UniqSupply,
-                         lazyMapUs )
-import MachMisc                ( IF_ARCH_i386(i386_insert_ffrees,) )
+import UniqFM
+import Unique          ( Unique, getUnique )
+import UniqSupply
+import FastTypes
 #if darwin_TARGET_OS
 import PprMach         ( pprDyldSymbolStub )
 import List            ( group, sort )
 #endif
+import ErrUtils                ( dumpIfSet_dyn )
+import CmdLineOpts     ( DynFlags, DynFlag(..), dopt, opt_Static,
+                         opt_EnsureSplittableC )
 
+import Digraph
 import qualified Pretty
 import Outputable
 import FastString
@@ -46,377 +51,775 @@ import FastString
 #ifdef NCG_DEBUG
 import List            ( intersperse )
 #endif
-\end{code}
 
-The 96/03 native-code generator has machine-independent and
-machine-dependent modules (those \tr{#include}'ing \tr{NCG.h}).
+import DATA_INT
+import DATA_WORD
+import DATA_BITS
+import GLAEXTS
 
-This module (@AsmCodeGen@) is the top-level machine-independent
-module.  It uses @AbsCStixGen.genCodeAbstractC@ to produce @StixTree@s
-(defined in module @Stix@), using support code from @StixPrim@
-(primitive operations), @StixMacro@ (Abstract C macros), and
-@StixInteger@ (GMP arbitrary-precision operations).
+{-
+The native-code generator has machine-independent and
+machine-dependent modules.
 
-Before entering machine-dependent land, we do some machine-independent
-@genericOpt@imisations (defined below) on the @StixTree@s.
+This module ("AsmCodeGen") is the top-level machine-independent
+module.  Before entering machine-dependent land, we do some
+machine-independent optimisations (defined below) on the
+'CmmStmts's.
 
-We convert to the machine-specific @Instr@ datatype with
-@stmt2Instrs@, assuming an ``infinite'' supply of registers.  We then
-use a machine-independent register allocator (@runRegAllocate@) to
-rejoin reality.  Obviously, @runRegAllocate@ has machine-specific
-helper functions (see about @RegAllocInfo@ below).
+We convert to the machine-specific 'Instr' datatype with
+'cmmCodeGen', assuming an infinite supply of registers.  We then use
+a machine-independent register allocator ('regAlloc') to rejoin
+reality.  Obviously, 'regAlloc' has machine-specific helper
+functions (see about "RegAllocInfo" below).
+
+Finally, we order the basic blocks of the function so as to minimise
+the number of jumps between blocks, by utilising fallthrough wherever
+possible.
 
 The machine-dependent bits break down as follows:
-\begin{description}
-\item[@MachRegs@:]  Everything about the target platform's machine
+
+  * ["MachRegs"]  Everything about the target platform's machine
     registers (and immediate operands, and addresses, which tend to
     intermingle/interact with registers).
 
-\item[@MachMisc@:]  Includes the @Instr@ datatype (possibly should
+  * ["MachInstrs"]  Includes the 'Instr' datatype (possibly should
     have a module of its own), plus a miscellany of other things
-    (e.g., @targetDoubleSize@, @smStablePtrTable@, ...)
+    (e.g., 'targetDoubleSize', 'smStablePtrTable', ...)
 
-\item[@MachCode@:]  @stmt2Instrs@ is where @Stix@ stuff turns into
+  * ["MachCodeGen"]  is where 'Cmm' stuff turns into
     machine instructions.
 
-\item[@PprMach@:] @pprInstr@ turns an @Instr@ into text (well, really
-    an @Doc@).
+  * ["PprMach"] 'pprInstr' turns an 'Instr' into text (well, really
+    a 'Doc').
 
-\item[@RegAllocInfo@:] In the register allocator, we manipulate
-    @MRegsState@s, which are @BitSet@s, one bit per machine register.
+  * ["RegAllocInfo"] In the register allocator, we manipulate
+    'MRegsState's, which are 'BitSet's, one bit per machine register.
     When we want to say something about a specific machine register
     (e.g., ``it gets clobbered by this instruction''), we set/unset
-    its bit.  Obviously, we do this @BitSet@ thing for efficiency
+    its bit.  Obviously, we do this 'BitSet' thing for efficiency
     reasons.
 
-    The @RegAllocInfo@ module collects together the machine-specific
+    The 'RegAllocInfo' module collects together the machine-specific
     info needed to do register allocation.
-\end{description}
 
-So, here we go:
+   * ["RegisterAlloc"] The (machine-independent) register allocator.
+-}
 
-\begin{code}
-nativeCodeGen :: AbstractC -> UniqSupply -> (SDoc, Pretty.Doc)
-nativeCodeGen absC us
-   = let absCstmts         = mkAbsCStmtList absC
-         (results, us1)    = initUs us (lazyMapUs absCtoNat absCstmts)
-         stix_sdocs        = [ stix | (stix, insn, imports) <- results ]
-         insn_sdocs        = [ insn | (stix, insn, imports) <- results ]
-         imports           = [ imports | (stix, insn, imports) <- results ]
+-- -----------------------------------------------------------------------------
+-- Top-level of the native codegen
 
-         insn_sdoc         = my_vcat insn_sdocs IF_OS_darwin(Pretty.$$ dyld_stubs,)
-         stix_sdoc         = vcat stix_sdocs
+-- NB. We *lazilly* compile each block of code for space reasons.
 
-#if darwin_TARGET_OS
-        -- Generate "symbol stubs" for all external symbols that might
-        -- come from a dynamic library.
+nativeCodeGen :: DynFlags -> [Cmm] -> UniqSupply -> IO Pretty.Doc
+nativeCodeGen dflags cmms us
+  | not opt_Static
+  = panic "NCG does not handle dynamic libraries right now"
+  -- ToDo: MachCodeGen used to have derefDLL function which expanded
+  -- dynamic CLabels (labelDynamic lbl == True) into the appropriate
+  -- dereferences.  This should be done in the pre-NCG cmmToCmm pass instead.
+  -- It doesn't apply to static data, of course.  There are hacks so that
+  -- the RTS knows what to do for references to closures in a DLL in SRTs,
+  -- and we never generate a reference to a closure in another DLL in a
+  -- static constructor.
 
-         dyld_stubs         = Pretty.vcat $  map pprDyldSymbolStub $
-                                            map head $ group $ sort $ concat imports
-#endif
+  | otherwise
+  = let ((ppr_cmms, insn_sdoc, imports), _) = initUs us $
+          cgCmm (concat (map add_split cmms))
 
-#        ifdef NCG_DEBUG
-         my_trace m x = trace m x
-         my_vcat sds = Pretty.vcat (
-                          intersperse (
-                             Pretty.char ' ' 
-                                Pretty.$$ Pretty.ptext SLIT("# ___ncg_debug_marker")
-                                Pretty.$$ Pretty.char ' '
-                          ) 
-                          sds
-                       )
-#        else
-         my_vcat sds = Pretty.vcat sds
-         my_trace m x = x
-#        endif
-     in
-         my_trace "nativeGen: begin"
-                  (stix_sdoc, insn_sdoc)
-
-
-absCtoNat :: AbstractC -> UniqSM (SDoc, Pretty.Doc, [FastString])
-absCtoNat absC
-   = _scc_ "genCodeAbstractC" genCodeAbstractC absC        `thenUs` \ stixRaw ->
-     _scc_ "genericOpt"       genericOpt stixRaw           `bind`   \ stixOpt ->
-     _scc_ "liftStrings"      liftStrings stixOpt          `thenUs` \ stixLifted ->
-     _scc_ "genMachCode"      genMachCode stixLifted       `thenUs` \ (pre_regalloc, imports) ->
-     _scc_ "regAlloc"         regAlloc pre_regalloc        `bind`   \ almost_final ->
-     _scc_ "x86fp_kludge"     x86fp_kludge almost_final    `bind`   \ final_mach_code ->
-     _scc_ "vcat"     Pretty.vcat (map pprInstr final_mach_code)  `bind`   \ final_sdoc ->
-     _scc_ "pprStixTrees"     pprStixStmts stixOpt         `bind`   \ stix_sdoc ->
-     returnUs ({-\_ -> Pretty.vcat (map pprInstr almost_final),-}
-               stix_sdoc, final_sdoc, imports)
-     where
-        bind f x = x f
+       cgCmm :: [CmmTop] -> UniqSM (Cmm, Pretty.Doc, [(Bool, CLabel)])
+       cgCmm tops = 
+          lazyMapUs (cmmNativeGen dflags) tops  `thenUs` \ results -> 
+          let (cmms,docs,imps) = unzip3 results in
+          returnUs (Cmm cmms, my_vcat docs, concat imps)
+    in do
+    dumpIfSet_dyn dflags Opt_D_dump_opt_cmm "Optimised Cmm" (pprCmms [ppr_cmms])
+    return (insn_sdoc Pretty.$$ dyld_stubs imports)
 
-        x86fp_kludge :: [Instr] -> [Instr]
-        x86fp_kludge = IF_ARCH_i386(i386_insert_ffrees,id)
+  where
 
-        regAlloc :: InstrBlock -> [Instr]
-        regAlloc = runRegAllocate allocatableRegs findReservedRegs
-\end{code}
+    add_split (Cmm tops)
+       | opt_EnsureSplittableC = split_marker : tops
+       | otherwise             = tops
 
-Top level code generator for a chunk of stix code.  For this part of
-the computation, we switch from the UniqSM monad to the NatM monad.
-The latter carries not only a Unique, but also an Int denoting the
-current C stack pointer offset in the generated code; this is needed
-for creating correct spill offsets on architectures which don't offer,
-or for which it would be prohibitively expensive to employ, a frame
-pointer register.  Viz, x86.
+    split_marker = CmmProc [] mkSplitMarkerLabel [] []
 
-The offset is measured in bytes, and indicates the difference between
-the current (simulated) C stack-ptr and the value it was at the
-beginning of the block.  For stacks which grow down, this value should
-be either zero or negative.
+#if darwin_TARGET_OS
+        -- Generate "symbol stubs" for all external symbols that might
+        -- come from a dynamic library.
+    dyld_stubs imps = Pretty.vcat $ map pprDyldSymbolStub $
+                                   map head $ group $ sort imps
+#else
+    dyld_stubs imps = Pretty.empty
+#endif
 
-Switching between the two monads whilst carrying along the same Unique
-supply breaks abstraction.  Is that bad?
+#ifndef NCG_DEBUG
+    my_vcat sds = Pretty.vcat sds
+#else
+    my_vcat sds = Pretty.vcat (
+                      intersperse (
+                         Pretty.char ' ' 
+                            Pretty.$$ Pretty.ptext SLIT("# ___ncg_debug_marker")
+                            Pretty.$$ Pretty.char ' '
+                      ) 
+                      sds
+                   )
+#endif
 
-\begin{code}
-genMachCode :: [StixStmt] -> UniqSM (InstrBlock, [FastString])
 
-genMachCode stmts initial_us
+-- Complete native code generation phase for a single top-level chunk
+-- of Cmm.
+
+cmmNativeGen :: DynFlags -> CmmTop -> UniqSM (CmmTop, Pretty.Doc, [(Bool,CLabel)])
+cmmNativeGen dflags cmm
+   = {-# SCC "fixAssigns"       #-} 
+       fixAssignsTop cmm            `thenUs` \ fixed_cmm ->
+     {-# SCC "genericOpt"       #-} 
+       cmmToCmm fixed_cmm           `bind`   \ cmm ->
+        (if dopt Opt_D_dump_opt_cmm dflags  -- space leak avoidance
+          then cmm 
+          else CmmData Text [])     `bind`   \ ppr_cmm ->
+     {-# SCC "genMachCode"      #-}
+       genMachCode cmm              `thenUs` \ (pre_regalloc, imports) ->
+     {-# SCC "regAlloc"         #-}
+       map regAlloc pre_regalloc    `bind`   \ with_regs ->
+     {-# SCC "sequenceBlocks"   #-}
+       map sequenceTop with_regs    `bind`   \ sequenced ->
+     {-# SCC "x86fp_kludge"     #-}
+       map x86fp_kludge sequenced   `bind`   \ final_mach_code ->
+     {-# SCC "vcat"             #-}
+       Pretty.vcat (map pprNatCmmTop final_mach_code)  `bind`   \ final_sdoc ->
+
+        returnUs (ppr_cmm, final_sdoc Pretty.$$ Pretty.text "", imports)
+     where
+        x86fp_kludge :: NatCmmTop -> NatCmmTop
+        x86fp_kludge top@(CmmData _ _) = top
+#if i386_TARGET_ARCH
+        x86fp_kludge top@(CmmProc info lbl params code) = 
+               CmmProc info lbl params (map bb_i386_insert_ffrees code)
+               where
+                 bb_i386_insert_ffrees (BasicBlock id instrs) =
+                       BasicBlock id (i386_insert_ffrees instrs)
+#else
+        x86fp_kludge top =  top
+#endif
+
+-- -----------------------------------------------------------------------------
+-- Sequencing the basic blocks
+
+-- Cmm BasicBlocks are self-contained entities: they always end in a
+-- jump, either non-local or to another basic block in the same proc.
+-- In this phase, we attempt to place the basic blocks in a sequence
+-- such that as many of the local jumps as possible turn into
+-- fallthroughs.
+
+sequenceTop :: NatCmmTop -> NatCmmTop
+sequenceTop top@(CmmData _ _) = top
+sequenceTop (CmmProc info lbl params blocks) = 
+  CmmProc info lbl params (sequenceBlocks blocks)
+
+-- The algorithm is very simple (and stupid): we make a graph out of
+-- the blocks where there is an edge from one block to another iff the
+-- first block ends by jumping to the second.  Then we topologically
+-- sort this graph.  Then traverse the list: for each block, we first
+-- output the block, then if it has an out edge, we move the
+-- destination of the out edge to the front of the list, and continue.
+
+sequenceBlocks :: [NatBasicBlock] -> [NatBasicBlock]
+sequenceBlocks [] = []
+sequenceBlocks (entry:blocks) = 
+  seqBlocks (mkNode entry : reverse (flattenSCCs (sccBlocks blocks)))
+  -- the first block is the entry point ==> it must remain at the start.
+
+sccBlocks :: [NatBasicBlock] -> [SCC (NatBasicBlock,Unique,[Unique])]
+sccBlocks blocks = stronglyConnCompR (map mkNode blocks)
+
+getOutEdges :: [Instr] -> [Unique]
+getOutEdges instrs = case jumpDests (last instrs) [] of
+                       [one] -> [getUnique one]
+                       _many -> []
+               -- we're only interested in the last instruction of
+               -- the block, and only if it has a single destination.
+
+mkNode block@(BasicBlock id instrs) = (block, getUnique id, getOutEdges instrs)
+
+seqBlocks [] = []
+seqBlocks ((block,_,[]) : rest)
+  = block : seqBlocks rest
+seqBlocks ((block@(BasicBlock id instrs),_,[next]) : rest)
+  | can_fallthrough = BasicBlock id (init instrs) : seqBlocks rest'
+  | otherwise       = block : seqBlocks rest'
+  where
+       (can_fallthrough, rest') = reorder next [] rest
+         -- TODO: we should do a better job for cycles; try to maximise the
+         -- fallthroughs within a loop.
+seqBlocks _ = panic "AsmCodegen:seqBlocks"
+
+reorder id accum [] = (False, reverse accum)
+reorder id accum (b@(block,id',out) : rest)
+  | id == id'  = (True, (block,id,out) : reverse accum ++ rest)
+  | otherwise  = reorder id (b:accum) rest
+
+-- -----------------------------------------------------------------------------
+-- Instruction selection
+
+-- Native code instruction selection for a chunk of stix code.  For
+-- this part of the computation, we switch from the UniqSM monad to
+-- the NatM monad.  The latter carries not only a Unique, but also an
+-- Int denoting the current C stack pointer offset in the generated
+-- code; this is needed for creating correct spill offsets on
+-- architectures which don't offer, or for which it would be
+-- prohibitively expensive to employ, a frame pointer register.  Viz,
+-- x86.
+
+-- The offset is measured in bytes, and indicates the difference
+-- between the current (simulated) C stack-ptr and the value it was at
+-- the beginning of the block.  For stacks which grow down, this value
+-- should be either zero or negative.
+
+-- Switching between the two monads whilst carrying along the same
+-- Unique supply breaks abstraction.  Is that bad?
+
+genMachCode :: CmmTop -> UniqSM ([NatCmmTop], [(Bool,CLabel)])
+
+genMachCode cmm_top initial_us
   = let initial_st             = mkNatM_State initial_us 0
-        (instr_list, final_st) = initNat initial_st (stmtsToInstrs stmts)
-        final_us               = uniqOfNatM_State final_st
-        final_delta            = deltaOfNatM_State final_st
-       final_imports          = importsOfNatM_State final_st
+        (new_tops, final_st)   = initNat initial_st (cmmTopCodeGen cmm_top)
+        final_us               = natm_us final_st
+        final_delta            = natm_delta final_st
+       final_imports          = natm_imports final_st
     in
         if   final_delta == 0
-        then ((instr_list, final_imports), final_us)
+        then ((new_tops, final_imports), final_us)
         else pprPanic "genMachCode: nonzero final delta"
                       (int final_delta)
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[NCOpt]{The Generic Optimiser}
-%*                                                                     *
-%************************************************************************
-
-This is called between translating Abstract C to its Tree and actually
-using the Native Code Generator to generate the annotations.  It's a
-chance to do some strength reductions.
-
-** Remember these all have to be machine independent ***
-
-Note that constant-folding should have already happened, but we might
-have introduced some new opportunities for constant-folding wrt
-address manipulations.
-
-\begin{code}
-genericOpt :: [StixStmt] -> [StixStmt]
-genericOpt = map stixStmt_ConFold . stixPeep
-
-
-
-stixPeep :: [StixStmt] -> [StixStmt]
 
--- This transformation assumes that the temp assigned to in t1
--- is not assigned to in t2; for otherwise the target of the
--- second assignment would be substituted for, giving nonsense
--- code.  As far as I can see, StixTemps are only ever assigned
--- to once.  It would be nice to be sure!
-
-stixPeep ( t1@(StAssignReg pka (StixTemp (StixVReg u pk)) rhs)
-         : t2
-         : ts )
-   | stixStmt_CountTempUses u t2 == 1
-     && sum (map (stixStmt_CountTempUses u) ts) == 0
-   = 
-#    ifdef NCG_DEBUG
-     trace ("nativeGen: inlining " ++ showSDoc (pprStixExpr rhs))
-#    endif
-           (stixPeep (stixStmt_Subst u rhs t2 : ts))
-
-stixPeep (t1:t2:ts) = t1 : stixPeep (t2:ts)
-stixPeep [t1]       = [t1]
-stixPeep []         = []
-\end{code}
+-- -----------------------------------------------------------------------------
+-- Fixup assignments to global registers so that they assign to 
+-- locations within the RegTable, if appropriate.
+
+-- Note that we currently don't fixup reads here: they're done by
+-- the generic optimiser below, to avoid having two separate passes
+-- over the Cmm.
+
+fixAssignsTop :: CmmTop -> UniqSM CmmTop
+fixAssignsTop top@(CmmData _ _) = returnUs top
+fixAssignsTop (CmmProc info lbl params blocks) =
+  mapUs fixAssignsBlock blocks `thenUs` \ blocks' ->
+  returnUs (CmmProc info lbl params blocks')
+
+fixAssignsBlock :: CmmBasicBlock -> UniqSM CmmBasicBlock
+fixAssignsBlock (BasicBlock id stmts) =
+  fixAssigns stmts `thenUs` \ stmts' ->
+  returnUs (BasicBlock id stmts')
+
+fixAssigns :: [CmmStmt] -> UniqSM [CmmStmt]
+fixAssigns stmts =
+  mapUs fixAssign stmts `thenUs` \ stmtss ->
+  returnUs (concat stmtss)
+
+fixAssign :: CmmStmt -> UniqSM [CmmStmt]
+fixAssign (CmmAssign (CmmGlobal BaseReg) src)
+   = panic "cmmStmtConFold: assignment to BaseReg";
+
+fixAssign (CmmAssign (CmmGlobal reg) src)
+  | Left  realreg <- reg_or_addr
+  = returnUs [CmmAssign (CmmGlobal reg) (cmmExprConFold src)]
+  | Right baseRegAddr <- reg_or_addr
+  = returnUs [CmmStore baseRegAddr src]
+           -- Replace register leaves with appropriate StixTrees for
+           -- the given target. GlobalRegs which map to a reg on this
+           -- arch are left unchanged.  Assigning to BaseReg is always
+           -- illegal, so we check for that.
+  where
+       reg_or_addr = get_GlobalReg_reg_or_addr reg
+
+fixAssign (CmmCall target results args vols)
+  = mapAndUnzipUs fixResult results `thenUs` \ (results',stores) ->
+    returnUs (CmmCall target results' args vols : concat stores)
+  where
+       fixResult g@(CmmGlobal reg,hint) = 
+         case get_GlobalReg_reg_or_addr reg of
+               Left realreg -> returnUs (g, [])
+               Right baseRegAddr ->
+                   getUniqueUs `thenUs` \ uq ->
+                   let local = CmmLocal (LocalReg uq (globalRegRep reg)) in
+                   returnUs ((local,hint), 
+                             [CmmStore baseRegAddr (CmmReg local)])
+       fixResult other =
+         returnUs (other,[])
+
+fixAssign other_stmt = returnUs [other_stmt]
+
+-- -----------------------------------------------------------------------------
+-- Generic Cmm optimiser
+
+{-
+Here we do:
+
+  (a) Constant folding
+  (b) Simple inlining: a temporary which is assigned to and then
+      used, once, can be shorted.
+  (c) Replacement of references to GlobalRegs which do not have
+      machine registers by the appropriate memory load (eg.
+      Hp ==>  *(BaseReg + 34) ).
+
+Ideas for other things we could do (ToDo):
+
+  - shortcut jumps-to-jumps
+  - eliminate dead code blocks
+-}
+
+cmmToCmm :: CmmTop -> CmmTop
+cmmToCmm top@(CmmData _ _) = top
+cmmToCmm (CmmProc info lbl params blocks) = 
+  CmmProc info lbl params (map cmmBlockConFold (cmmPeep blocks))
+
+cmmBlockConFold :: CmmBasicBlock -> CmmBasicBlock
+cmmBlockConFold (BasicBlock id stmts) = BasicBlock id (map cmmStmtConFold stmts)
+
+cmmStmtConFold stmt
+   = case stmt of
+        CmmAssign reg src
+           -> case cmmExprConFold src of
+                CmmReg reg' | reg == reg' -> CmmNop
+                new_src -> CmmAssign reg new_src
+
+        CmmStore addr src
+           -> CmmStore (cmmExprConFold addr) (cmmExprConFold src)
+
+        CmmJump addr regs
+           -> CmmJump (cmmExprConFold addr) regs
+
+       CmmCall target regs args vols
+          -> CmmCall (case target of 
+                        CmmForeignCall e conv -> 
+                               CmmForeignCall (cmmExprConFold e) conv
+                        other -> other)
+                 regs
+                 [ (cmmExprConFold arg,hint) | (arg,hint) <- args ]
+                 vols
+
+        CmmCondBranch test dest
+           -> let test_opt = cmmExprConFold test
+              in 
+             case test_opt of
+               CmmLit (CmmInt 0 _) -> 
+                   CmmComment (mkFastString ("deleted: " ++ 
+                                       showSDoc (pprStmt stmt)))
 
-For most nodes, just optimize the children.
+               CmmLit (CmmInt n _) ->  CmmBranch dest
+               other ->  CmmCondBranch (cmmExprConFold test) dest
 
-\begin{code}
-stixExpr_ConFold :: StixExpr -> StixExpr
-stixStmt_ConFold :: StixStmt -> StixStmt
+       CmmSwitch expr ids
+          -> CmmSwitch (cmmExprConFold expr) ids
 
-stixStmt_ConFold stmt
-   = case stmt of
-        StAssignReg pk reg@(StixTemp _) src
-           -> StAssignReg pk reg (stixExpr_ConFold src)
-        StAssignReg pk reg@(StixMagicId mid) src
-           -- Replace register leaves with appropriate StixTrees for 
-           -- the given target. MagicIds which map to a reg on this arch are left unchanged. 
-           -- Assigning to BaseReg is always illegal, so we check for that.
-           -> case mid of { 
-                 BaseReg -> panic "stixStmt_ConFold: assignment to BaseReg";
-                 other ->
-                 case get_MagicId_reg_or_addr mid of
-                    Left  realreg 
-                       -> StAssignReg pk reg (stixExpr_ConFold src)
-                    Right baseRegAddr 
-                       -> stixStmt_ConFold (StAssignMem pk baseRegAddr src)
-              }
-        StAssignMem pk addr src
-           -> StAssignMem pk (stixExpr_ConFold addr) (stixExpr_ConFold src)
-        StVoidable expr
-           -> StVoidable (stixExpr_ConFold expr)
-        StJump dsts addr
-           -> StJump dsts (stixExpr_ConFold addr)
-        StCondJump addr test
-           -> let test_opt = stixExpr_ConFold test
-              in 
-              if  manifestlyZero test_opt
-              then StComment (mkFastString ("deleted: " ++ showSDoc (pprStixStmt stmt)))
-              else StCondJump addr (stixExpr_ConFold test)
-        StData pk datas
-           -> StData pk (map stixExpr_ConFold datas)
         other
            -> other
-     where
-        manifestlyZero (StInt 0) = True
-        manifestlyZero other     = False
 
-stixExpr_ConFold expr
+
+cmmExprConFold expr
    = case expr of
-        StInd pk addr
-           -> StInd pk (stixExpr_ConFold addr)
-        StCall fn cconv pk args
-           -> StCall fn cconv pk (map stixExpr_ConFold args)
-        StIndex pk (StIndex pk' base off) off'
-           -- Fold indices together when the types match:
-           |  pk == pk'
-           -> StIndex pk (stixExpr_ConFold base)
-                         (stixExpr_ConFold (StMachOp MO_Nat_Add [off, off']))
-        StIndex pk base off
-           -> StIndex pk (stixExpr_ConFold base) (stixExpr_ConFold off)
-
-        StMachOp mop args
-           -- For PrimOps, we first optimize the children, and then we try 
+        CmmLoad addr rep
+           -> CmmLoad (cmmExprConFold addr) rep
+
+        CmmMachOp mop args
+           -- For MachOps, we first optimize the children, and then we try 
            -- our hand at some constant-folding.
-           -> stixMachOpFold mop (map stixExpr_ConFold args)
-        StReg (StixMagicId mid)
-           -- Replace register leaves with appropriate StixTrees for 
-           -- the given target.  MagicIds which map to a reg on this arch are left unchanged. 
-           -- For the rest, BaseReg is taken to mean the address of the reg table 
-           -- in MainCapability, and for all others we generate an indirection to 
-           -- its location in the register table.
-           -> case get_MagicId_reg_or_addr mid of
+           -> cmmMachOpFold mop (map cmmExprConFold args)
+
+#if powerpc_TARGET_ARCH
+           -- On powerpc, it's easier to jump directly to a label than
+           -- to use the register table, so we replace these registers
+           -- with the corresponding labels:
+        CmmReg (CmmGlobal GCEnter1)
+          -> CmmLit (CmmLabel (mkRtsCodeLabel SLIT( "__stg_gc_enter_1"))) 
+        CmmReg (CmmGlobal GCFun)
+          -> CmmLit (CmmLabel (mkRtsCodeLabel SLIT( "__stg_gc_fun")))
+#endif
+
+        CmmReg (CmmGlobal mid)
+           -- Replace register leaves with appropriate StixTrees for
+           -- the given target.  MagicIds which map to a reg on this
+           -- arch are left unchanged.  For the rest, BaseReg is taken
+           -- to mean the address of the reg table in MainCapability,
+           -- and for all others we generate an indirection to its
+           -- location in the register table.
+           -> case get_GlobalReg_reg_or_addr mid of
                  Left  realreg -> expr
                  Right baseRegAddr 
                     -> case mid of 
-                          BaseReg -> stixExpr_ConFold baseRegAddr
-                          other   -> stixExpr_ConFold (StInd (magicIdPrimRep mid) baseRegAddr)
+                          BaseReg -> cmmExprConFold baseRegAddr
+                          other   -> cmmExprConFold (CmmLoad baseRegAddr 
+                                                       (globalRegRep mid))
+          -- eliminate zero offsets
+       CmmRegOff reg 0
+          -> cmmExprConFold (CmmReg reg)
+
+        CmmRegOff (CmmGlobal mid) offset
+           -- RegOf leaves are just a shorthand form. If the reg maps
+           -- to a real reg, we keep the shorthand, otherwise, we just
+           -- expand it and defer to the above code. 
+           -> case get_GlobalReg_reg_or_addr mid of
+                Left  realreg -> expr
+                Right baseRegAddr
+                   -> cmmExprConFold (CmmMachOp (MO_Add wordRep) [
+                                        CmmReg (CmmGlobal mid),
+                                        CmmLit (CmmInt (fromIntegral offset)
+                                                       wordRep)])
         other
            -> other
-\end{code}
 
-Now, try to constant-fold the PrimOps.  The arguments have already
-been optimized and folded.
 
-\begin{code}
-stixMachOpFold
-    :: MachOp          -- The operation from an StMachOp
-    -> [StixExpr]      -- The optimized arguments
-    -> StixExpr
+-- -----------------------------------------------------------------------------
+-- MachOp constant folder
 
-stixMachOpFold mop arg@[StInt x]
-  = case mop of
-       MO_NatS_Neg -> StInt (-x)
-       other       -> StMachOp mop arg
+-- Now, try to constant-fold the MachOps.  The arguments have already
+-- been optimized and folded.
 
-stixMachOpFold mop args@[StInt x, StInt y]
-  = case mop of
-       MO_32U_Gt   -> StInt (if x > y  then 1 else 0)
-       MO_32U_Ge   -> StInt (if x >= y then 1 else 0)
-       MO_32U_Eq   -> StInt (if x == y then 1 else 0)
-       MO_32U_Ne   -> StInt (if x /= y then 1 else 0)
-       MO_32U_Lt   -> StInt (if x < y  then 1 else 0)
-       MO_32U_Le   -> StInt (if x <= y then 1 else 0)
-       MO_Nat_Add  -> StInt (x + y)
-       MO_Nat_Sub  -> StInt (x - y)
-       MO_NatS_Mul -> StInt (x * y)
-       MO_NatS_Quot | y /= 0 -> StInt (x `quot` y)
-       MO_NatS_Rem  | y /= 0 -> StInt (x `rem` y)
-       MO_NatS_Gt  -> StInt (if x > y  then 1 else 0)
-       MO_NatS_Ge  -> StInt (if x >= y then 1 else 0)
-       MO_Nat_Eq   -> StInt (if x == y then 1 else 0)
-       MO_Nat_Ne   -> StInt (if x /= y then 1 else 0)
-       MO_NatS_Lt  -> StInt (if x < y  then 1 else 0)
-       MO_NatS_Le  -> StInt (if x <= y then 1 else 0)
-        MO_Nat_Shl  | y >= 0 && y < 32 -> do_shl x y
-       other       -> StMachOp mop args
-    where
-       do_shl :: Integer -> Integer -> StixExpr
-       do_shl v 0         = StInt v
-       do_shl v n | n > 0 = do_shl (v*2) (n-1)
-\end{code}
+cmmMachOpFold
+    :: MachOp          -- The operation from an CmmMachOp
+    -> [CmmExpr]       -- The optimized arguments
+    -> CmmExpr
 
-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 arg@[CmmLit (CmmInt x rep)]
+  = case op of
+      MO_S_Neg r -> CmmLit (CmmInt (-x) rep)
+      MO_Not r   -> CmmLit (CmmInt (complement x) rep)
 
-\begin{code}
-stixMachOpFold op [x@(StInt _), y] | isCommutableMachOp op 
-   = stixMachOpFold op [y, x]
-\end{code}
-
-We can often do something with constants of 0 and 1 ...
+       -- 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 -> CmmLit (CmmInt (narrowS from x) to)
+      MO_U_Conv from to -> CmmLit (CmmInt (narrowU from x) to)
+      _  -> panic "cmmMachOpFold: unknown unary op"
 
-\begin{code}
-stixMachOpFold mop args@[x, y@(StInt 0)]
-  = case mop of
-       MO_Nat_Add  -> x
-       MO_Nat_Sub  -> x
-       MO_NatS_Mul -> y
-       MO_NatU_Mul -> y
-       MO_Nat_And  -> y
-       MO_Nat_Or   -> x
-       MO_Nat_Xor  -> x
-       MO_Nat_Shl  -> x
-       MO_Nat_Shr  -> x
-       MO_Nat_Sar  -> x
-        MO_Nat_Ne | x_is_comparison -> x
-       other       -> StMachOp mop args
-    where
-       x_is_comparison
-          = case x of
-               StMachOp mopp [_, _] -> isComparisonMachOp mopp
-               _                    -> False
+-- Eliminate conversion NOPs
+cmmMachOpFold (MO_S_Conv rep1 rep2) [x] | rep1 == rep2 = x
+cmmMachOpFold (MO_U_Conv rep1 rep2) [x] | rep1 == rep2 = x
 
-stixMachOpFold mop args@[x, y@(StInt 1)]
-  = case mop of
-       MO_NatS_Mul  -> x
-       MO_NatU_Mul  -> x
-       MO_NatS_Quot -> x
-       MO_NatU_Quot -> x
-       MO_NatS_Rem  -> StInt 0
-       MO_NatU_Rem  -> StInt 0
-       other        -> StMachOp mop args
-\end{code}
+-- ToDo: eliminate multiple conversions.  Be careful though: can't remove
+-- a narrowing, and can't remove conversions to/from floating point types.
 
-Now look for multiplication/division by powers of 2 (integers).
+-- ToDo: eliminate nested comparisons:
+--    CmmMachOp MO_Lt [CmmMachOp MO_Eq [x,y], CmmLit (CmmInt 0 _)]
+-- turns into a simple equality test.
 
-\begin{code}
-stixMachOpFold mop args@[x, y@(StInt n)]
+cmmMachOpFold mop args@[CmmLit (CmmInt x xrep), CmmLit (CmmInt y _)]
   = case mop of
-       MO_NatS_Mul 
+       -- 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]
+   where 
+    isLit (CmmLit _) = True
+    isLit _          = False
+
+-- 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?
+cmmMachOpFold mop1 [CmmMachOp mop2 [arg1,arg2], arg3]
+   | mop1 == mop2 && isAssociative mop1
+   = cmmMachOpFold mop1 [arg1, cmmMachOpFold mop2 [arg2,arg3]]
+   where
+       isAssociative (MO_Add _) = True
+       isAssociative (MO_Mul _) = True
+       isAssociative (MO_And _) = True
+       isAssociative (MO_Or  _) = True
+       isAssociative (MO_Xor _) = True
+       isAssociative _          = False
+
+-- 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  -> StMachOp MO_Nat_Shl [x, StInt p]
-       MO_NatS_Quot 
+                 Just p  -> CmmMachOp (MO_Shl rep) [x, CmmLit (CmmInt p rep)]
+       MO_S_Quot rep
            -> case exactLog2 n of
                  Nothing -> unchanged
-                 Just p  -> StMachOp MO_Nat_Shr [x, StInt p]
+                 Just p  -> CmmMachOp (MO_S_Shr rep) [x, CmmLit (CmmInt p rep)]
        other 
            -> unchanged
     where
-       unchanged = StMachOp mop args
+       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 iUnbox (fromInteger x) of { x# ->
+       if (w2i ((i2w x#) `and#` (i2w (0# -# x#))) /=# x#) then
+         Nothing
+       else
+         Just (toInteger (iBox (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"
+
+-- -----------------------------------------------------------------------------
+-- The mini-inliner
+
+-- This pass inlines assignments to temporaries that are used just
+-- once in the very next statement only.  Generalising this would be
+-- quite difficult (have to take into account aliasing of memory
+-- writes, and so on), but at the moment it catches a number of useful
+-- cases and lets the code generator generate much better code.
+
+-- NB. This assumes that temporaries are single-assignment.
+
+cmmPeep :: [CmmBasicBlock] -> [CmmBasicBlock]
+cmmPeep 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 (cmmMiniInline uses stmts)
+
+
+cmmMiniInline :: UniqFM Int -> [CmmStmt] -> [CmmStmt]
+cmmMiniInline uses [] = []
+cmmMiniInline 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
+     cmmMiniInline uses stmts'
+
+cmmMiniInline uses (stmt:stmts)
+  = stmt : cmmMiniInline 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 (stmt:stmts)
+  = case lookupUFM (getStmtUses stmt) u of
+       Just 1 -> Just (inlineStmt u expr stmt : stmts)
+       _other -> Nothing
+
+-- -----------------------------------------------------------------------------
+-- 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
+
+-- -----------------------------------------------------------------------------
+-- Utils
+
+bind f x = x $! f
+
+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
 \end{code}
 
-Anything else is just too hard.
-
-\begin{code}
-stixMachOpFold mop args = StMachOp mop args
-\end{code}
diff --git a/ghc/compiler/nativeGen/AsmRegAlloc.lhs b/ghc/compiler/nativeGen/AsmRegAlloc.lhs
deleted file mode 100644 (file)
index 90b379a..0000000
+++ /dev/null
@@ -1,941 +0,0 @@
-%
-% (c) The AQUA Project, Glasgow University, 1993-2000
-%
-\section[AsmRegAlloc]{Register allocator}
-
-\begin{code}
-module AsmRegAlloc ( runRegAllocate ) where    
-
-#include "HsVersions.h"
-
-import MachCode                ( InstrBlock )
-import MachMisc                ( Instr(..) )
-import PprMach         ( pprInstr )    -- Just for debugging
-import MachRegs
-import RegAllocInfo
-
-import FiniteMap       ( FiniteMap, emptyFM, 
-                         lookupFM, eltsFM, addToFM_C, addToFM,
-                         listToFM, fmToList )
-import OrdList         ( fromOL )
-import Outputable
-import Unique          ( mkPseudoUnique3 )
-import CLabel          ( CLabel, pprCLabel )
-import FastTypes
-
-import List            ( mapAccumL, nub, sort )
-import Array           ( Array, array, (!), bounds )
-\end{code}
-
-This is the generic register allocator.  It does allocation for all
-architectures.  Details for specific architectures are given in
-RegAllocInfo.lhs.  In practice the allocator needs to know next to
-nothing about an architecture to do its job:
-
-* It needs to be given a list of the registers it can allocate to.
-
-* It needs to be able to find out which registers each insn reads and
-  writes.
-
-* It needs be able to change registers in instructions into other
-  registers.
-
-* It needs to be able to find out where execution could go after an
-  in instruction.
-
-* It needs to be able to discover sets of registers which can be
-  used to attempt spilling.
-
-First we try something extremely simple.  If that fails, we have to do
-things the hard way.
-
-\begin{code}
-runRegAllocate
-    :: [Reg]
-    -> ([Instr] -> [[Reg]])
-    -> InstrBlock
-    -> [Instr]
-
-runRegAllocate regs find_reserve_regs instrs
-  = --trace ("runRegAllocate: " ++ show regs) (
-    case simpleAlloc of
-       Just simple -> --trace "SIMPLE" 
-                      simple
-       Nothing     -> --trace "GENERAL"
-                      (tryGeneral reserves)
-    --)
-  where
-    tryGeneral [] 
-       = pprPanic "nativeGen: spilling failed.  Workaround: compile with -fvia-C.\n"
-            ( (text "reserves = " <> ppr reserves)
-              $$
-              (text "code = ")
-              $$
-              (vcat (map (docToSDoc.pprInstr) flatInstrs))
-            )
-    tryGeneral (resv:resvs)
-       = case generalAlloc resv of
-            Just success -> success
-            Nothing      -> tryGeneral resvs
-
-    reserves           = find_reserve_regs flatInstrs
-    flatInstrs         = fromOL instrs
-    simpleAlloc        = doSimpleAlloc regs flatInstrs
-    generalAlloc resvd = doGeneralAlloc regs resvd flatInstrs
-\end{code}
-
-Rather than invoke the heavyweight machinery in @doGeneralAlloc@ for
-each and every code block, we first try using this simple, fast and
-utterly braindead allocator.  In practice it handles about 60\% of the
-code blocks really fast, even with only 3 integer registers available.
-Since we can always give up and fall back to @doGeneralAlloc@,
-@doSimpleAlloc@ is geared to handling the common case as fast as
-possible.  It will succeed only if:
-
-* The code mentions registers only of integer class, not floating
-  class.
-
-* The code doesn't mention any real registers, so we don't have to
-  think about dodging and weaving to work around fixed register uses.
-
-* The code mentions at most N virtual registers, where N is the number
-  of real registers for allocation.
-
-If those conditions are satisfied, we simply trundle along the code, 
-doling out a real register every time we see mention of a new virtual
-register.  We either succeed at this, or give up when one of the above
-three conditions is no longer satisfied.
-
-\begin{code}
-doSimpleAlloc :: [Reg] -> [Instr] -> Maybe [Instr]
-doSimpleAlloc available_real_regs instrs
-   = let available_iregs 
-            = filter ((== RcInteger).regClass) available_real_regs
-
-         trundle :: [( {-Virtual-}Reg, {-Real-}Reg )]
-                    -> [ {-Real-}Reg ]
-                    -> [Instr]
-                    -> [Instr]
-                    -> Maybe [Instr]
-         trundle vreg_map uncommitted_rregs ris_done []
-            = Just (reverse ris_done)
-         trundle vreg_map uncommitted_rregs ris_done (i:is)
-            = case regUsage i of
-                 RU rds wrs
-
-                    -- Mentions no regs?  Move on quickly
-                    |  null rds_l && null wrs_l
-                    -> trundle vreg_map uncommitted_rregs (i:ris_done) is
-
-                    -- A case we can't be bothered to handle?
-                    |  any isFloatingOrReal rds_l || any isFloatingOrReal wrs_l
-                    -> Nothing
-
-                    -- Update the rreg commitments, and map the insn
-                    |  otherwise
-                    -> case upd_commitment (wrs_l++rds_l) 
-                                           vreg_map uncommitted_rregs of
-                          Nothing -- out of rregs; give up
-                             -> Nothing
-                          Just (vreg_map2, uncommitted_rregs2)
-                             -> let i2 = patchRegs i (subst_reg vreg_map2)
-                                in  trundle vreg_map2 uncommitted_rregs2 
-                                            (i2:ris_done) is
-                       where
-                          isFloatingOrReal reg
-                             = isRealReg reg || regClass reg == RcFloat
-                                             || regClass reg == RcDouble
-
-                          rds_l = regSetToList rds
-                          wrs_l = regSetToList wrs
-
-                          upd_commitment [] vr_map uncomm
-                             = Just (vr_map, uncomm)
-                          upd_commitment (reg:regs) vr_map uncomm
-                             | isRealReg reg 
-                             = upd_commitment regs vr_map uncomm
-                             | reg `elem` (map fst vr_map)
-                             = upd_commitment regs vr_map uncomm
-                             | null uncomm
-                             = Nothing
-                             | otherwise
-                             = upd_commitment regs ((reg, head uncomm):vr_map) 
-                                                   (tail uncomm)
-
-                          subst_reg vreg_map r
-                             -- If it's a RealReg, it must be STG-specific one 
-                             -- (Hp,Sp,BaseReg,etc), since regUsage filters them out,
-                             -- so isFloatingOrReal would not have objected to it.
-                             | isRealReg r 
-                             = r
-                             | otherwise 
-                             = case [rr | (vr,rr) <- vreg_map, vr == r] of
-                                  [rr2] -> rr2
-                                  other -> pprPanic 
-                                              "doSimpleAlloc: unmapped VirtualReg"
-                                              (ppr r)
-     in
-         trundle [] available_iregs [] instrs
-\end{code}
-
-From here onwards is the general register allocator and spiller.  For
-each flow edge (possible transition between instructions), we compute
-which virtual and real registers are live on that edge.  Then the
-mapping is inverted, to give a mapping from register (virtual+real) to
-sets of flow edges on which the register is live.  Finally, we can use
-those sets to decide whether a virtual reg v can be assigned to a real
-reg r, by checking that v's live-edge-set does not intersect with r's
-current live-edge-set.  Having made that assignment, we then augment
-r's current live-edge-set (its current commitment, you could say) with
-v's live-edge-set.
-
-doGeneralAlloc takes reserve_regs as the regs to use as spill
-temporaries.  First it tries to allocate using all regs except
-reserve_regs.  If that fails, it inserts spill code and tries again to
-allocate regs, but this time with the spill temporaries available.
-Even this might not work if there are insufficient spill temporaries:
-in the worst case on x86, we'd need 3 of them, for insns like addl
-(%reg1,%reg2,4) %reg3, since this insn uses all 3 regs as input.
-
-\begin{code}
-doGeneralAlloc 
-    :: [Reg]            -- all allocatable regs
-    -> [Reg]            -- the reserve regs
-    -> [Instr]          -- instrs in
-    -> Maybe [Instr]    -- instrs out
-
-doGeneralAlloc all_regs reserve_regs instrs
-   -- succeeded without spilling
-   | prespill_ok
-   = Just prespill_insns
-
-   -- failed, and no spill regs avail, so pointless to attempt spilling 
-   | null reserve_regs  = Nothing
-   -- success after spilling
-   | postspill_ok       = maybetrace (spillMsg True) (Just postspill_insns)
-   -- still not enough reserves after spilling; we have to give up
-   | otherwise          = maybetrace (spillMsg False) Nothing
-     where
-         prespill_regs 
-            = filter (`notElem` reserve_regs) all_regs
-         (prespill_ok, prespill_insns)
-            = allocUsingTheseRegs instrs prespill_regs
-         instrs_with_spill_code
-            = insertSpillCode prespill_insns
-         (postspill_ok, postspill_insns)
-            = allocUsingTheseRegs instrs_with_spill_code all_regs
-
-         spillMsg success
-            = "nativeGen: spilling " 
-              ++ (if success then "succeeded" else "failed   ")
-              ++ " using " 
-              ++ showSDoc (hsep (map ppr reserve_regs))
-
-#        ifdef NCG_DEBUG
-         maybetrace msg x = trace msg x
-#        else
-         maybetrace msg x = x
-#        endif
-\end{code}
-
-Here we patch instructions that reference ``registers'' which are
-really in memory somewhere (the mapping is under the control of the
-machine-specific code generator).  We place the appropriate load
-sequences before any instructions that use memory registers as
-sources, and we place the appropriate spill sequences after any
-instructions that use memory registers as destinations.  The offending
-instructions are rewritten with new dynamic registers, so generalAlloc
-has to run register allocation again after all of this is said and
-done.
-
-On some architectures (x86, currently), we do without a frame-pointer,
-and instead spill relative to the stack pointer (%esp on x86).
-Because the stack pointer may move, the patcher needs to keep track of
-the current stack pointer "delta".  That's easy, because all it needs
-to do is spot the DELTA bogus-insns which will have been inserted by
-the relevant insn selector precisely so as to notify the spiller of
-stack-pointer movement.  The delta is passed to loadReg and spillReg,
-since they generate the actual spill code.  We expect the final delta
-to be the same as the starting one (zero), reflecting the fact that
-changes to the stack pointer should not extend beyond a basic block.
-
-Finally, there is the issue of mapping an arbitrary set of unallocated
-VirtualRegs into a contiguous sequence of spill slots.  The failed
-allocation will have left the code peppered with references to
-VirtualRegs, each of which contains a unique.  So we make an env which
-maps these VirtualRegs to integers, starting from zero, and pass that
-env through to loadReg and spillReg.  There, they are used to look up
-spill slot numbers for the uniques.
-
-\begin{code}
-insertSpillCode :: [Instr] -> [Instr]
-insertSpillCode insns
-   = let uniques_in_insns
-            = map getVRegUnique 
-                  (regSetToList 
-                     (foldl unionRegSets emptyRegSet 
-                            (map vregs_in_insn insns)))
-         vregs_in_insn i
-            = case regUsage i of
-                 RU rds wrs -> filterRegSet isVirtualReg 
-                                             (rds `unionRegSets` wrs)
-         vreg_to_slot_map :: FiniteMap VRegUnique Int
-         vreg_to_slot_map
-            = listToFM (zip uniques_in_insns [0..])
-
-         ((final_stack_delta, final_ctr), insnss) 
-            = mapAccumL (patchInstr vreg_to_slot_map) (0,0) insns
-     in
-         if   final_stack_delta == 0
-         then concat insnss
-         else pprPanic "patchMem: non-zero final delta" 
-                       (int final_stack_delta)
-
-
--- patchInstr has as a running state two Ints, one the current stack delta,
--- needed to figure out offsets to stack slots on archs where we spill relative
--- to the stack pointer, as opposed to the frame pointer.  The other is a 
--- counter, used to manufacture new temporary register names.
-
-patchInstr :: FiniteMap VRegUnique Int -> (Int,Int) -> Instr -> ((Int,Int), [Instr])
-patchInstr vreg_to_slot_map (delta,ctr) instr
-
- | null memSrcs && null memDsts 
- = ((delta',ctr), [instr])
-
- | otherwise
- = ((delta',ctr'), loadSrcs ++ [instr'] ++ spillDsts)
-   where
-        delta' = case instr of DELTA d -> d ; _ -> delta
-
-        (RU srcs dsts) = regUsage instr
-
-        -- The instr being patched may mention several vregs -- those which
-        -- could not be assigned real registers.  For each such vreg, we 
-        -- invent a new vreg, used only around this instruction and nowhere
-        -- else.  These new vregs replace the unallocatable vregs; they are
-        -- loaded from the spill area, the instruction is done with them,
-        -- and results if any are then written back to the spill area.
-        vregs_in_instr 
-           = nub (filter isVirtualReg 
-                         (regSetToList srcs ++ regSetToList dsts))
-        n_vregs_in_instr
-           = length vregs_in_instr
-        ctr' 
-           = ctr + n_vregs_in_instr
-        vreg_env
-           = zip vregs_in_instr [ctr, ctr+1 ..]
-
-        mkTmpReg vreg
-           | isVirtualReg vreg
-           = case [vi | (vreg', vi) <- vreg_env, vreg' == vreg] of
-                [i] -> case regClass vreg of
-                          RcInteger -> VirtualRegI (pseudoVReg i)
-                          RcFloat   -> VirtualRegF (pseudoVReg i)
-                          RcDouble  -> VirtualRegD (pseudoVReg i)
-                _   -> pprPanic "patchInstr: unmapped VReg" (ppr vreg)
-           | otherwise
-           = vreg
-
-        pseudoVReg i = VRegUniqueLo (mkPseudoUnique3 i)
-
-       memSrcs   = filter isVirtualReg (regSetToList srcs)
-       memDsts   = filter isVirtualReg (regSetToList dsts)
-
-       loadSrcs  = map load  memSrcs
-       spillDsts = map spill memDsts
-
-       load mem  = loadReg  vreg_to_slot_map delta  mem (mkTmpReg mem)
-       spill mem = spillReg vreg_to_slot_map delta' (mkTmpReg mem) mem
-
-       instr'    = patchRegs instr mkTmpReg
-\end{code}
-
-allocUsingTheseRegs is the register allocator proper.  It attempts
-to allocate dynamic regs to real regs, given a list of real regs
-which it may use.  If it fails due to lack of real regs, the returned
-instructions use what real regs there are, but will retain uses of
-dynamic regs for which a real reg could not be found.  It is these
-leftover dynamic reg references which insertSpillCode will later
-assign to spill slots.
-
-Some implementation notes.
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-Instructions are numbered sequentially, starting at zero.
-
-A flow edge (FE) is a pair of insn numbers (MkFE Int Int) denoting
-a possible flow of control from the first insn to the second.
-
-The input to the register allocator is a list of instructions, which
-mention Regs.  A Reg can be a RealReg -- a real machine reg -- or a
-VirtualReg, which carries a unique.  After allocation, all the 
-VirtualReg references will have been converted into RealRegs, and
-possible some spill code will have been inserted.
-
-The heart of the register allocator works in four phases.
-
-1.  (find_flow_edges) Calculate all the FEs for the code list.
-    Return them not as a [FE], but implicitly, as a pair of 
-    Array Int [Int], being the successor and predecessor maps
-    for instructions.
-
-2.  (calc_liveness) Returns a FiniteMap FE RegSet.  For each 
-    FE, indicates the set of registers live on that FE.  Note
-    that the set includes both RealRegs and VirtualRegs.  The
-    former appear because the code could mention fixed register
-    usages, and we need to take them into account from the start.
-
-3.  (calc_live_range_sets) Invert the above mapping, giving a 
-    FiniteMap Reg FeSet, indicating, for each virtual and real
-    reg mentioned in the code, which FEs it is live on.
-
-4.  (calc_vreg_to_rreg_mapping) For virtual reg, try and find
-    an allocatable real register for it.  Each real register has
-    a "current commitment", indicating the set of FEs it is 
-    currently live on.  A virtual reg v can be assigned to 
-    real reg r iff v's live-fe-set does not intersect with r's
-    current commitment fe-set.  If the assignment is made,
-    v's live-fe-set is union'd into r's current commitment fe-set.
-    There is also the minor restriction that v and r must be of
-    the same register class (integer or floating).
-
-    Once this mapping is established, we simply apply it to the
-    input insns, and that's it.
-
-    If no suitable real register can be found, the vreg is mapped
-    to itself, and we deem allocation to have failed.  The partially
-    allocated code is returned.  The higher echelons of the allocator
-    (doGeneralAlloc and runRegAlloc) then cooperate to insert spill
-    code and re-run allocation, until a successful allocation is found.
-\begin{code}
-
-allocUsingTheseRegs :: [Instr] -> [Reg] -> (Bool, [Instr])
-allocUsingTheseRegs instrs available_real_regs
-   = let (all_vregs_mapped, v_to_r_mapping)
-            = calc_vreg_to_rreg_mapping instrs available_real_regs
-         new_insns
-            = map (flip patchRegs sr) instrs
-         sr reg
-            | isRealReg reg
-            = reg
-            | otherwise
-            = case lookupFM v_to_r_mapping reg of
-                 Just r  -> r
-                 Nothing -> pprPanic "allocateUsingTheseRegs: unmapped vreg: " 
-                                     (ppr reg)
-     in
-         --trace ("allocUsingTheseRegs: " ++ show available_real_regs) (
-         (all_vregs_mapped, new_insns)
-         --)
-
-
--- the heart of the matter.  
-calc_vreg_to_rreg_mapping :: [Instr] -> [Reg] -> (Bool, FiniteMap Reg Reg)
-calc_vreg_to_rreg_mapping insns available_real_regs
-   = let 
-         lr_sets  :: FiniteMap Reg FeSet
-         lr_sets = calc_live_range_sets insns
-
-         -- lr_sets maps: vregs mentioned in insns to sets of live FEs
-         -- and also:     rregs mentioned in insns to sets of live FEs
-         -- We need to extract the rreg mapping, and use it as the
-         -- initial real-register-commitment.  Also, add to the initial
-         -- commitment, empty commitments for any real regs not
-         -- mentioned in it.
-
-         -- which real regs do we want to keep track of in the running
-         -- commitment mapping?  Precisely the available_real_regs.  
-         -- We don't care about real regs mentioned by insns which are
-         -- not in this list, since we're not allocating to them.
-         initial_rr_commitment :: FiniteMap Reg FeSet
-         initial_rr_commitment
-            = listToFM [(rreg,
-                         case lookupFM lr_sets rreg of
-                            Nothing            -> emptyFeSet
-                            Just fixed_use_fes -> fixed_use_fes
-                        )
-                        | rreg <- available_real_regs]
-
-         -- These are the vregs for which we actually have to (try to) 
-         -- assign a real register. (ie, the whole reason we're here at all :)
-         vreg_liveness_list :: [(Reg, FeSet)]
-         vreg_liveness_list = filter (not.isRealReg.fst) 
-                                     (fmToList lr_sets)
-
-         -- A loop, which attempts to assign each vreg to a rreg.
-         loop rr_commitment v_to_r_map [] 
-            = v_to_r_map
-         loop rr_commitment v_to_r_map ((vreg,vreg_live_fes):not_yet_done)
-            = let
-                  -- find a real reg which is not live for any of vreg_live_fes
-                  cand_reals
-                     = [rreg 
-                           | (rreg,rreg_live_FEs) <- fmToList rr_commitment,
-                              regClass vreg == regClass rreg,
-                              isEmptyFeSet (intersectionFeSets rreg_live_FEs 
-                                                               vreg_live_fes)
-                       ]
-              in
-                 case cand_reals of
-                    [] -> -- bummer.  No register is available.  Just go on to
-                          -- the next vreg, mapping the vreg to itself.
-                          loop rr_commitment (addToFM v_to_r_map vreg vreg)
-                               not_yet_done
-                    (r:_) 
-                       -> -- Hurrah!  Found a free reg of the right class.
-                          -- Now we need to update the RR commitment.
-                          loop rr_commitment2 (addToFM v_to_r_map vreg r)
-                               not_yet_done
-                          where
-                             rr_commitment2
-                                = addToFM_C unionFeSets rr_commitment r 
-                                            vreg_live_fes
-
-         -- the final vreg to rreg mapping
-         vreg_assignment
-            = loop initial_rr_commitment emptyFM vreg_liveness_list
-         -- did we succeed in mapping everyone to a real reg?
-         allocation_succeeded
-            = all isRealReg (eltsFM vreg_assignment)
-     in
-         (allocation_succeeded, vreg_assignment)
-
-
-
--- calculate liveness, then produce the live range info
--- as a mapping of VRegs to the set of FEs on which they are live.
--- The difficult part is inverting the mapping of Reg -> FeSet
--- to produce a mapping FE -> RegSet.
-
-calc_live_range_sets :: [Instr] -> FiniteMap Reg FeSet
-calc_live_range_sets insns
-   = let 
-         -- this is the "original" (old) mapping
-         lis :: FiniteMap FE RegSet
-         lis = calc_liveness insns
-
-         -- establish the totality of reg names mentioned by the
-         -- insns, by scanning over the insns.
-         all_mentioned_regs :: RegSet
-         all_mentioned_regs 
-            = foldl unionRegSets emptyRegSet
-                    (map (\i -> case regUsage i of
-                                   RU rds wrs -> unionRegSets rds wrs)
-                         insns)
-
-         -- Initial inverted mapping, from Reg to sets of FEs
-         initial_imap :: FiniteMap Reg FeSet
-         initial_imap
-            = listToFM [(reg, emptyFeSet) 
-                        | reg <- regSetToList all_mentioned_regs]
-
-         -- Update the new map with one element of the old map
-         upd_imap :: FiniteMap Reg FeSet -> (FE, RegSet)
-                     -> FiniteMap Reg FeSet
-         upd_imap imap (fe, regset)
-             = foldl upd_1_imap imap (regSetToList regset)
-               where
-                  upd_1_imap curr reg
-                     = addToFM_C unionFeSets curr reg (unitFeSet fe)
-
-         -- the complete inverse mapping
-         final_imap :: FiniteMap Reg FeSet
-         final_imap
-             = foldl upd_imap initial_imap (fmToList lis)
-     in
-         final_imap
-
-
-
--- Given the insns, calculate the FEs, and then doing fixpointing to
--- figure out the set of live regs (virtual regs AND real regs) live
--- on each FE.
-
-calc_liveness :: [Instr] -> FiniteMap FE RegSet
-calc_liveness insns
-   = let (pred_map, succ_map)
-            = find_flow_edges insns
-
-         -- We use the convention that if the current approximation
-         -- doesn't give a mapping for some FE, that FE maps to the
-         -- empty set.
-         initial_approx, fixpoint :: FiniteMap FE RegSet
-         initial_approx
-            = mk_initial_approx 0 insns succ_map emptyFM
-         fixpoint 
-            = fix_set initial_approx 1
-              -- If you want to live dangerously, and promise that the code
-              -- doesn't contain any loops (ie, there are no back edges in
-              -- the flow graph), you should be able to get away with this:
-              -- = upd_liveness_info pred_map succ_map insn_array initial_approx
-              -- But since I'm paranoid, and since it hardly makes any difference
-              -- to the compiler run-time (about 0.1%), I prefer to do the
-              -- the full fixpointing game.
-
-         insn_array
-            = let n = length insns 
-              in  array (0, n-1) (zip [0..] insns)
-              
-         sameSets []     []       = True
-         sameSets (c:cs) (n:ns)   = eqRegSets c n && sameSets cs ns
-         sameSets _      _        = False
-
-         fix_set curr_approx iter_number
-            = let next_approx
-                     = upd_liveness_info pred_map succ_map insn_array curr_approx
-                  curr_sets
-                     = eltsFM curr_approx
-                  next_sets
-                     = eltsFM next_approx
-                  same
-                     = sameSets curr_sets next_sets
-                  final_approx
-                     = if same then curr_approx 
-                               else fix_set next_approx (iter_number+1)
-              in
-                  --trace (let qqq (fe, regset) 
-                  --             = show fe ++ "  " ++ show (regSetToList regset)
-                  --       in
-                  --          "\n::iteration " ++ show iter_number ++ "\n" 
-                  --          ++ (unlines . map qqq . fmToList) 
-                  --                               next_approx ++"\n"
-                  --      )
-                  final_approx
-     in
-         fixpoint
-
-
--- Create a correct initial approximation.  For each instruction that
--- writes a register, we deem that the register is live on the 
--- flow edges leaving the instruction.  Subsequent iterations of
--- the liveness AbI augment this based purely on reads of regs, not
--- writes.  We need to start off with at least this minimal write-
--- based information in order that writes to vregs which are never
--- used have non-empty live ranges.  If we don't do that, we eventually
--- wind up assigning such vregs to any old real reg, since they don't
--- apparently conflict -- you can't conflict with an empty live range.
--- This kludge is unfortunate, but we need to do it to cover not only
--- writes to vregs which are never used, but also to deal correctly
--- with the fact that calls to C will trash the callee saves registers.
-
-mk_initial_approx :: Int -> [Instr] -> Array Int [Int]
-                     -> FiniteMap FE RegSet
-                     -> FiniteMap FE RegSet
-mk_initial_approx ino [] succ_map ia_so_far 
-   = ia_so_far
-mk_initial_approx ino (i:is) succ_map ia_so_far
-   = let wrs 
-            = case regUsage i of RU rrr www -> www
-         new_fes 
-            = [case iUnbox ino of      { inoh ->
-               case iUnbox ino_succ of { ino_succh ->
-               MkFE inoh ino_succh 
-               }}
-                  | ino_succ <- succ_map ! ino]
-
-         loop [] ia = ia
-         loop (fe:fes) ia
-            = loop fes (addToFM_C unionRegSets ia fe wrs)
-
-         next_ia
-            = loop new_fes ia_so_far
-     in
-         mk_initial_approx (ino+1) is succ_map next_ia
-
--- Do one step in the liveness info calculation (AbI :).  Given the
--- prior approximation (which tells you a subset of live VRegs+RRegs 
--- for each flow edge), calculate new information for all FEs.
--- Rather than do this by iterating over FEs, it's easier to iterate
--- over insns, and update their incoming FEs.
-
-upd_liveness_info :: Array Int [Int]         -- instruction pred map
-                     -> Array Int [Int]      -- instruction succ map
-                     -> Array Int Instr      -- array of instructions
-                     -> FiniteMap FE RegSet  -- previous approx
-                     -> FiniteMap FE RegSet  -- improved approx
-
-upd_liveness_info pred_map succ_map insn_array prev_approx
-   = do_insns hi prev_approx
-     where
-        (lo, hi) = bounds insn_array
-
-        enquireMapFE :: FiniteMap FE RegSet -> FE 
-                        -> RegSet
-        enquireMapFE fm fe
-           = case lookupFM fm fe of
-                Just set -> set
-                Nothing  -> emptyRegSet
-
-        -- Work backwards, from the highest numbered insn to the lowest.
-        -- This is a heuristic which causes faster convergence to the
-        -- fixed point.  In particular, for straight-line code with no
-        -- branches at all, arrives at the fixpoint in one iteration.
-        do_insns ino approx
-           | ino < lo
-           = approx
-           | otherwise
-           = let fes_to_futures
-                    = [case iUnbox ino of        { inoh ->
-                       case iUnbox future_ino of { future_inoh ->
-                       MkFE inoh future_inoh
-                       }}
-                          | future_ino <- succ_map ! ino]
-                 future_lives
-                    = map (enquireMapFE approx) fes_to_futures
-                 future_live
-                    = foldr unionRegSets emptyRegSet future_lives
-
-                 fes_from_histories
-                    = [case iUnbox history_ino of { history_inoh ->
-                       case iUnbox ino of         { inoh ->
-                       MkFE history_inoh inoh
-                       }}
-                          | history_ino <- pred_map ! ino]
-                 new_approx
-                    = foldl update_one_history approx fes_from_histories
-                 
-                 insn
-                    = insn_array ! ino
-                 history_independent_component
-                    = case regUsage insn of
-                         RU rds wrs
-                            -> unionRegSets rds
-                                  (minusRegSets future_live wrs)
-
-                 update_one_history :: FiniteMap FE RegSet
-                                       -> FE
-                                       -> FiniteMap FE RegSet
-                 update_one_history approx0 fe
-                      = addToFM_C unionRegSets approx0 fe 
-                                  history_independent_component
-
-                 rest_done
-                    = do_insns (ino-1) new_approx
-             in
-                 rest_done
-                 
-
-
--- Extract the flow edges from a list of insns.  Express the information 
--- as two mappings, from insn number to insn numbers of predecessors,
--- and from insn number to insn numbers of successors.  (Since that's
--- what we need to know when computing live ranges later).  Instructions
--- are numbered starting at zero.  This function is long and complex 
--- in order to be efficient; it could equally well be shorter and slower.
-
-find_flow_edges :: [Instr] -> (Array Int [Int],
-                               Array Int [Int])
-find_flow_edges insns
-   = let 
-         -- First phase: make a temp env which maps labels
-         -- to insn numbers, so the second pass can know the insn
-         -- numbers for jump targets.
-
-         label_env :: FiniteMap CLabel Int
-
-         mk_label_env n env [] = env
-         mk_label_env n env ((LABEL clbl):is)
-            = mk_label_env (n+1) (addToFM env clbl n) is
-         mk_label_env n env (i:is)
-            = mk_label_env (n+1) env is
-   
-         label_env = mk_label_env 0 emptyFM insns
-
-         find_label :: CLabel -> Int
-         find_label jmptarget
-            = case lookupFM label_env jmptarget of
-                 Just ino -> ino
-                 Nothing  -> pprPanic "find_flow_edges: unmapped label" 
-                                      (pprCLabel jmptarget)
-
-         -- Second phase: traverse the insns, and make up the successor map.
-
-         least_ino, greatest_ino :: Int
-         least_ino    = 0
-         greatest_ino = length insns - 1
-
-         mk_succ_map :: Int -> [(Int, [Int])] -> [Instr] -> [(Int, [Int])]
-
-         mk_succ_map i_num rsucc_map [] 
-            = reverse rsucc_map
-
-         mk_succ_map i_num rsucc_map (i:is)
-            = let i_num_1 = i_num + 1
-              in
-              case insnFuture i of
-
-                 NoFuture
-                    -> -- A non-local jump.  We can regard this insn as a terminal
-                       -- insn in the graph, so we don't add any edges.
-                       mk_succ_map i_num_1 ((i_num,[]):rsucc_map) is
-
-                 Next 
-                    |  null is -- this is the last insn, and it doesn't go anywhere
-                               -- (a meaningless scenario); handle it anyway
-                    -> mk_succ_map i_num_1 ((i_num,[]):rsucc_map) is
-
-                    |  otherwise -- flows to next insn; add fe i_num -> i_num+1
-                    -> mk_succ_map i_num_1 ((i_num, [i_num_1]): rsucc_map)
-                                           is
-
-                 Branch lab -- jmps to lab; add fe i_num -> i_target
-                    -> let i_target = find_label lab
-                       in 
-                       mk_succ_map i_num_1 ((i_num, [i_target]): rsucc_map) is
-
-                 NextOrBranch lab
-                    |  null is   -- jmps to label, or falls through, and this is
-                                 -- the last insn (a meaningless scenario); 
-                                 -- flag an error
-                    -> error "find_flow_edges: NextOrBranch is last"
-
-                    |  otherwise -- add fes i_num -> i_num+1  
-                                 --     and i_num -> i_target
-                    -> let i_target = find_label lab
-                       in
-                       mk_succ_map i_num_1 ((i_num, [i_num_1, i_target]):rsucc_map)
-                                           is
-                 MultiFuture labels
-                    -> -- A jump, whose targets are listed explicitly.  
-                       -- (Generated from table-based switch translations).
-                       -- Add fes  i_num -> x  for each x in labels
-                       let is_target = nub (map find_label labels)
-                       in
-                       mk_succ_map i_num_1 ((i_num, is_target):rsucc_map) is
-
-         -- Third phase: invert the successor map to get the predecessor
-         -- map, using an algorithm which is quadratic in the worst case,
-         -- but runs in almost-linear time, because of the nature of our
-         -- inputs: most insns have a single successor, the next insn.
-
-         invert :: [(Int, [Int])] -> [(Int, [Int])]
-         invert fmap
-            = let inverted_pairs
-                     = concatMap ( \ (a, bs) -> [(b,a) | b <- bs] ) fmap
-                  sorted_inverted_pairs
-                     = isort inverted_pairs
-         
-                  grp :: Int -> [Int] -> [(Int,Int)] -> [(Int,[Int])]
-                  grp k vs [] = [(k, vs)]
-                  grp k vs ((kk,vv):rest)
-                     | k == kk   = grp k (vv:vs) rest
-                     | otherwise = (k,vs) : grp kk [vv] rest
-
-                  grp_start []             = []
-                  grp_start ((kk,vv):rest) = grp kk [vv] rest
-
-                  grouped
-                     = grp_start sorted_inverted_pairs
-
-                  -- make sure that the reverse mapping maps all inos
-                  add_empties ino []
-                     | ino > greatest_ino  = []
-                     | otherwise           = (ino,[]): add_empties (ino+1) []
-                  add_empties ino ((k,vs):rest)
-                     | ino <  k   = (ino,[]): add_empties (ino+1) ((k,vs):rest)
-                     | ino == k   = (k,vs) : add_empties (ino+1) rest
-
-                  -- This is nearly linear provided that the fsts of the 
-                  -- list are nearly in order -- a critical assumption 
-                  -- for efficiency.
-                  isort :: [(Int,Int)] -> [(Int,Int)]
-                  isort []     = []
-                  isort (x:xs) = insert x (isort xs)
-
-                  insert :: (Int,Int) -> [(Int,Int)] -> [(Int,Int)]
-                  insert y []     = [y]
-                  insert y (z:zs)
-                     -- specifically, this first test should almost always
-                     -- be True in order for the near-linearity to happen
-                     | fst y <= fst z  = y:z:zs 
-                     | otherwise       = z: insert y zs
-              in
-                 add_empties least_ino grouped
-
-         -- Finally ...
-
-         succ_list
-            = mk_succ_map 0 [] insns
-         succ_map
-            = array (least_ino, greatest_ino) succ_list
-         pred_list
-            = invert succ_list
-         pred_map
-            = array (least_ino, greatest_ino) pred_list
-     in
-         (pred_map, succ_map)
-
-
--- That's all, folks!  From here on is just some dull supporting stuff.
-
--- A data type for flow edges
-data FE 
-   = MkFE FastInt FastInt deriving (Eq, Ord)
-
--- deriving Show on types with unboxed fields doesn't work
-instance Show FE where
-    showsPrec _ (MkFE s d) 
-       = showString "MkFE" . shows (iBox s) . shows ' ' . shows (iBox d)
-
--- Blargh.  Use ghc stuff soon!  Or: perhaps that's not such a good
--- idea.  Most of these sets are either empty or very small, and it
--- might be that the overheads of the FiniteMap based set implementation
--- is a net loss.  The same might be true of RegSets.
-
-newtype FeSet = MkFeSet [FE]
-
-feSetFromList xs 
-   = MkFeSet (nukeDups (sort xs))
-     where nukeDups :: [FE] -> [FE]
-           nukeDups []  = []
-           nukeDups [x] = [x]
-           nukeDups (x:y:xys)
-              = if x == y then nukeDups (y:xys)
-                          else x : nukeDups (y:xys)
-
-feSetToList (MkFeSet xs)            = xs
-isEmptyFeSet (MkFeSet xs)           = null xs
-emptyFeSet                          = MkFeSet []
-eqFeSet (MkFeSet xs1) (MkFeSet xs2) = xs1 == xs2
-unitFeSet x                         = MkFeSet [x]
-
-elemFeSet x (MkFeSet xs) 
-   = f xs
-     where
-        f []     = False
-        f (y:ys) | x == y    = True
-                 | x < y     = False
-                 | otherwise = f ys
-
-unionFeSets (MkFeSet xs1) (MkFeSet xs2)
-   = MkFeSet (f xs1 xs2)
-     where
-        f [] bs = bs
-        f as [] = as
-        f (a:as) (b:bs)
-           | a < b      = a : f as (b:bs)
-           | a > b      = b : f (a:as) bs
-           | otherwise  = a : f as bs
-
-minusFeSets (MkFeSet xs1) (MkFeSet xs2)
-   = MkFeSet (f xs1 xs2)
-     where
-        f [] bs = []
-        f as [] = as
-        f (a:as) (b:bs)
-           | a < b      = a : f as (b:bs)
-           | a > b      = f (a:as) bs
-           | otherwise  = f as bs
-
-intersectionFeSets (MkFeSet xs1) (MkFeSet xs2)
-   = MkFeSet (f xs1 xs2)
-     where
-        f [] bs = []
-        f as [] = []
-        f (a:as) (b:bs)
-           | a < b      = f as (b:bs)
-           | a > b      = f (a:as) bs
-           | otherwise  = a : f as bs
-
-\end{code}
diff --git a/ghc/compiler/nativeGen/MachCode.lhs b/ghc/compiler/nativeGen/MachCode.lhs
deleted file mode 100644 (file)
index 2876efd..0000000
+++ /dev/null
@@ -1,4628 +0,0 @@
-%
-% (c) The AQUA Project, Glasgow University, 1996-1998
-%
-\section[MachCode]{Generating machine code}
-
-This is a big module, but, if you pay attention to
-(a) the sectioning, (b) the type signatures, and
-(c) the \tr{#if blah_TARGET_ARCH} things, the
-structure should not be too overwhelming.
-
-\begin{code}
-module MachCode ( stmtsToInstrs, InstrBlock ) where
-
-#include "HsVersions.h"
-#include "nativeGen/NCG.h"
-
-import MachMisc                -- may differ per-platform
-import MachRegs
-import OrdList         ( OrdList, nilOL, isNilOL, unitOL, appOL, toOL,
-                         snocOL, consOL, concatOL )
-import MachOp          ( MachOp(..), pprMachOp )
-import AbsCUtils       ( magicIdPrimRep )
-import PprAbsC         ( pprMagicId )
-import ForeignCall     ( CCallConv(..) )
-import CLabel          ( CLabel, labelDynamic )
-#if sparc_TARGET_ARCH || alpha_TARGET_ARCH
-import CLabel          ( isAsmTemp )
-#endif
-import Maybes          ( maybeToBool )
-import PrimRep         ( isFloatingRep, is64BitRep, PrimRep(..),
-#if powerpc_TARGET_ARCH
-                         getPrimRepSize,
-#endif
-                         getPrimRepSizeInBytes )
-import Stix            ( getNatLabelNCG, StixStmt(..), StixExpr(..),
-                         StixReg(..), pprStixReg, StixVReg(..), CodeSegment(..), 
-                          DestInfo, hasDestInfo,
-                          pprStixExpr, repOfStixExpr,
-                          NatM, thenNat, returnNat, mapNat, 
-                          mapAndUnzipNat, mapAccumLNat,
-                          getDeltaNat, setDeltaNat, 
-                         IF_ARCH_powerpc(addImportNat COMMA,)
-                          ncgPrimopMoan,
-                         ncg_target_is_32bit
-                       )
-import Pretty
-import Outputable      ( panic, pprPanic, showSDoc )
-import qualified Outputable
-import CmdLineOpts     ( opt_Static )
-import Stix            ( pprStixStmt )
-
-import Maybe           ( fromMaybe )
-
--- DEBUGGING ONLY
-import Outputable      ( assertPanic )
-import FastString
-import TRACE           ( trace )
-
-infixr 3 `bind`
-\end{code}
-
-@InstrBlock@s are the insn sequences generated by the insn selectors.
-They are really trees of insns to facilitate fast appending, where a
-left-to-right traversal (pre-order?) yields the insns in the correct
-order.
-
-\begin{code}
-type InstrBlock = OrdList Instr
-
-x `bind` f = f x
-
-isLeft (Left _)  = True
-isLeft (Right _) = False
-
-unLeft (Left x) = x
-\end{code}
-
-Code extractor for an entire stix tree---stix statement level.
-
-\begin{code}
-stmtsToInstrs :: [StixStmt] -> NatM InstrBlock
-stmtsToInstrs stmts
-   = mapNat stmtToInstrs stmts         `thenNat` \ instrss ->
-     returnNat (concatOL instrss)
-
-
-stmtToInstrs :: StixStmt -> NatM InstrBlock
-stmtToInstrs stmt = case stmt of
-    StComment s    -> returnNat (unitOL (COMMENT s))
-    StSegment seg  -> returnNat (unitOL (SEGMENT seg))
-
-    StFunBegin lab -> returnNat (unitOL (IF_ARCH_alpha(FUNBEGIN lab,
-                                                       LABEL lab)))
-    StFunEnd lab   -> IF_ARCH_alpha(returnNat (unitOL (FUNEND lab)),
-                                    returnNat nilOL)
-
-    StLabel lab           -> returnNat (unitOL (LABEL lab))
-
-    StJump dsts arg       -> genJump dsts (derefDLL arg)
-    StCondJump lab arg    -> genCondJump lab (derefDLL arg)
-
-    -- A call returning void, ie one done for its side-effects.  Note
-    -- that this is the only StVoidable we handle.
-    StVoidable (StCall fn cconv VoidRep args) 
-       -> genCCall fn cconv VoidRep (map derefDLL args)
-
-    StAssignMem pk addr src
-      | isFloatingRep pk -> assignMem_FltCode pk (derefDLL addr) (derefDLL src)
-      | ncg_target_is_32bit
-        && is64BitRep pk -> assignMem_I64Code    (derefDLL addr) (derefDLL src)
-      | otherwise       -> assignMem_IntCode pk (derefDLL addr) (derefDLL src)
-    StAssignReg pk reg src
-      | isFloatingRep pk -> assignReg_FltCode pk reg (derefDLL src)
-      | ncg_target_is_32bit
-        && is64BitRep pk -> assignReg_I64Code    reg (derefDLL src)
-      | otherwise       -> assignReg_IntCode pk reg (derefDLL src)
-
-    StFallThrough lbl
-       -- When falling through on the Alpha, we still have to load pv
-       -- with the address of the next routine, so that it can load gp.
-      -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
-       ,returnNat nilOL)
-
-    StData kind args
-      -> mapAndUnzipNat getData args `thenNat` \ (codes, imms) ->
-        returnNat (DATA (primRepToSize kind) imms  
-                    `consOL`  concatOL codes)
-      where
-       getData :: StixExpr -> NatM (InstrBlock, Imm)
-       getData (StInt i)        = returnNat (nilOL, ImmInteger i)
-       getData (StDouble d)     = returnNat (nilOL, ImmDouble d)
-       getData (StFloat d)      = returnNat (nilOL, ImmFloat d)
-       getData (StCLbl l)       = returnNat (nilOL, ImmCLbl l)
-       getData (StString s)     = panic "MachCode.stmtToInstrs: unlifted StString"
-       -- the linker can handle simple arithmetic...
-       getData (StIndex rep (StCLbl lbl) (StInt off)) =
-               returnNat (nilOL,
-                           ImmIndex lbl (fromInteger off * getPrimRepSizeInBytes rep))
-
-    -- Top-level lifted-out string.  The segment will already have been set
-    -- (see Stix.liftStrings).
-    StDataString str
-      -> returnNat (unitOL (ASCII True (unpackFS str)))
-
-#ifdef DEBUG
-    other -> pprPanic "stmtToInstrs" (pprStixStmt other)
-#endif
-
--- Walk a Stix tree, and insert dereferences to CLabels which are marked
--- as labelDynamic.  stmt2Instrs calls derefDLL selectively, because
--- not all such CLabel occurrences need this dereferencing -- SRTs don't
--- for one.
-derefDLL :: StixExpr -> StixExpr
-derefDLL tree
-   | opt_Static   -- short out the entire deal if not doing DLLs
-   = tree
-   | otherwise
-   = qq tree
-     where
-        qq t
-           = case t of
-                StCLbl lbl -> if   labelDynamic lbl
-                              then StInd PtrRep (StCLbl lbl)
-                              else t
-                -- all the rest are boring
-                StIndex pk base offset -> StIndex pk (qq base) (qq offset)
-                StMachOp mop args      -> StMachOp mop (map qq args)
-                StInd pk addr          -> StInd pk (qq addr)
-                StCall (Left nm) cc pk args -> StCall (Left nm) cc pk (map qq args)
-                StCall (Right f) cc pk args -> StCall (Right (qq f)) cc pk (map qq args)
-                StInt    _             -> t
-                StFloat  _             -> t
-                StDouble _             -> t
-                StString _             -> t
-                StReg    _             -> t
-                _                      -> pprPanic "derefDLL: unhandled case" 
-                                                   (pprStixExpr t)
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{General things for putting together code sequences}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-mangleIndexTree :: StixExpr -> StixExpr
-
-mangleIndexTree (StIndex pk base (StInt i))
-  = StMachOp MO_Nat_Add [base, off]
-  where
-    off = StInt (i * toInteger (getPrimRepSizeInBytes pk))
-
-mangleIndexTree (StIndex pk base off)
-  = StMachOp MO_Nat_Add [
-       base,
-       let s = shift pk
-       in  if s == 0 then off 
-                     else StMachOp MO_Nat_Shl [off, StInt (toInteger s)]
-    ]
-  where
-    shift :: PrimRep -> Int
-    shift rep = case getPrimRepSizeInBytes rep of
-                   1 -> 0
-                   2 -> 1
-                   4 -> 2
-                   8 -> 3
-                   other -> pprPanic "MachCode.mangleIndexTree.shift: unhandled rep size" 
-                                     (Outputable.int other)
-\end{code}
-
-\begin{code}
-maybeImm :: StixExpr -> Maybe Imm
-
-maybeImm (StCLbl l)       
-   = Just (ImmCLbl l)
-maybeImm (StIndex rep (StCLbl l) (StInt off)) 
-   = Just (ImmIndex l (fromInteger off * getPrimRepSizeInBytes rep))
-maybeImm (StInt i)
-  | i >= toInteger (minBound::Int) && i <= toInteger (maxBound::Int)
-  = Just (ImmInt (fromInteger i))
-  | otherwise
-  = Just (ImmInteger i)
-
-maybeImm _ = Nothing
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{The @Register64@ type}
-%*                                                                     *
-%************************************************************************
-
-Simple support for generating 64-bit code (ie, 64 bit values and 64
-bit assignments) on 32-bit platforms.  Unlike the main code generator
-we merely shoot for generating working code as simply as possible, and
-pay little attention to code quality.  Specifically, there is no
-attempt to deal cleverly with the fixed-vs-floating register
-distinction; all values are generated into (pairs of) floating
-registers, even if this would mean some redundant reg-reg moves as a
-result.  Only one of the VRegUniques is returned, since it will be
-of the VRegUniqueLo form, and the upper-half VReg can be determined
-by applying getHiVRegFromLo to it.
-
-\begin{code}
-
-data ChildCode64       -- a.k.a "Register64"
-   = ChildCode64 
-        InstrBlock     -- code
-        VRegUnique     -- unique for the lower 32-bit temporary
-       -- which contains the result; use getHiVRegFromLo to find
-       -- the other VRegUnique.
-       -- Rules of this simplified insn selection game are
-       -- therefore that the returned VRegUnique may be modified
-
-assignMem_I64Code :: StixExpr -> StixExpr -> NatM InstrBlock
-assignReg_I64Code :: StixReg  -> StixExpr -> NatM InstrBlock
-iselExpr64        :: StixExpr -> NatM ChildCode64
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if i386_TARGET_ARCH
-
-assignMem_I64Code addrTree valueTree
-   = iselExpr64 valueTree              `thenNat` \ (ChildCode64 vcode vrlo) ->
-     getRegister addrTree              `thenNat` \ register_addr ->
-     getNewRegNCG IntRep               `thenNat` \ t_addr ->
-     let rlo = VirtualRegI vrlo
-         rhi = getHiVRegFromLo rlo
-         code_addr = registerCode register_addr t_addr
-         reg_addr  = registerName register_addr t_addr
-         -- Little-endian store
-         mov_lo = MOV L (OpReg rlo)
-                        (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 0)))
-         mov_hi = MOV L (OpReg rhi)
-                        (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 4)))
-     in
-         returnNat (vcode `appOL` code_addr `snocOL` mov_lo `snocOL` mov_hi)
-
-assignReg_I64Code (StixTemp (StixVReg u_dst pk)) valueTree
-   = iselExpr64 valueTree              `thenNat` \ (ChildCode64 vcode vr_src_lo) ->
-     let 
-         r_dst_lo = mkVReg u_dst IntRep
-         r_src_lo = VirtualRegI vr_src_lo
-         r_dst_hi = getHiVRegFromLo r_dst_lo
-         r_src_hi = getHiVRegFromLo r_src_lo
-         mov_lo = MOV L (OpReg r_src_lo) (OpReg r_dst_lo)
-         mov_hi = MOV L (OpReg r_src_hi) (OpReg r_dst_hi)
-     in
-         returnNat (
-            vcode `snocOL` mov_lo `snocOL` mov_hi
-         )
-
-assignReg_I64Code lvalue valueTree
-   = pprPanic "assignReg_I64Code(i386): invalid lvalue"
-              (pprStixReg lvalue)
-
-
-
-iselExpr64 (StInd pk addrTree)
-   | is64BitRep pk
-   = getRegister addrTree              `thenNat` \ register_addr ->
-     getNewRegNCG IntRep               `thenNat` \ t_addr ->
-     getNewRegNCG IntRep               `thenNat` \ rlo ->
-     let rhi = getHiVRegFromLo rlo
-         code_addr = registerCode register_addr t_addr
-         reg_addr  = registerName register_addr t_addr
-         mov_lo = MOV L (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 0)))
-                        (OpReg rlo)
-         mov_hi = MOV L (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 4)))
-                        (OpReg rhi)
-     in
-         returnNat (
-            ChildCode64 (code_addr `snocOL` mov_lo `snocOL` mov_hi) 
-                        (getVRegUnique rlo)
-         )
-
-iselExpr64 (StReg (StixTemp (StixVReg vu pk)))
-   | is64BitRep pk
-   = getNewRegNCG IntRep               `thenNat` \ r_dst_lo ->
-     let r_dst_hi = getHiVRegFromLo r_dst_lo
-         r_src_lo = mkVReg vu IntRep
-         r_src_hi = getHiVRegFromLo r_src_lo
-         mov_lo = MOV L (OpReg r_src_lo) (OpReg r_dst_lo)
-         mov_hi = MOV L (OpReg r_src_hi) (OpReg r_dst_hi)
-     in
-         returnNat (
-            ChildCode64 (toOL [mov_lo, mov_hi]) (getVRegUnique r_dst_lo)
-         )
-         
-iselExpr64 (StCall fn cconv kind args)
-  | is64BitRep kind
-  = genCCall fn cconv kind args                        `thenNat` \ call ->
-    getNewRegNCG IntRep                                `thenNat` \ r_dst_lo ->
-    let r_dst_hi = getHiVRegFromLo r_dst_lo
-        mov_lo = MOV L (OpReg eax) (OpReg r_dst_lo)
-        mov_hi = MOV L (OpReg edx) (OpReg r_dst_hi)
-    in
-    returnNat (
-       ChildCode64 (call `snocOL` mov_lo `snocOL` mov_hi) 
-                   (getVRegUnique r_dst_lo)
-    )
-
-iselExpr64 expr
-   = pprPanic "iselExpr64(i386)" (pprStixExpr expr)
-
-#endif /* i386_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if sparc_TARGET_ARCH
-
-assignMem_I64Code addrTree valueTree
-   = iselExpr64 valueTree              `thenNat` \ (ChildCode64 vcode vrlo) ->
-     getRegister addrTree              `thenNat` \ register_addr ->
-     getNewRegNCG IntRep               `thenNat` \ t_addr ->
-     let rlo = VirtualRegI vrlo
-         rhi = getHiVRegFromLo rlo
-         code_addr = registerCode register_addr t_addr
-         reg_addr  = registerName register_addr t_addr
-         -- Big-endian store
-         mov_hi = ST W rhi (AddrRegImm reg_addr (ImmInt 0))
-         mov_lo = ST W rlo (AddrRegImm reg_addr (ImmInt 4))
-     in
-         returnNat (vcode `appOL` code_addr `snocOL` mov_hi `snocOL` mov_lo)
-
-
-assignReg_I64Code (StixTemp (StixVReg u_dst pk)) valueTree
-   = iselExpr64 valueTree              `thenNat` \ (ChildCode64 vcode vr_src_lo) ->
-     let 
-         r_dst_lo = mkVReg u_dst IntRep
-         r_src_lo = VirtualRegI vr_src_lo
-         r_dst_hi = getHiVRegFromLo r_dst_lo
-         r_src_hi = getHiVRegFromLo r_src_lo
-         mov_lo = mkMOV r_src_lo r_dst_lo
-         mov_hi = mkMOV r_src_hi r_dst_hi
-         mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
-     in
-         returnNat (
-            vcode `snocOL` mov_hi `snocOL` mov_lo
-         )
-assignReg_I64Code lvalue valueTree
-   = pprPanic "assignReg_I64Code(sparc): invalid lvalue"
-              (pprStixReg lvalue)
-
-
--- Don't delete this -- it's very handy for debugging.
---iselExpr64 expr 
---   | trace ("iselExpr64: " ++ showSDoc (pprStixExpr expr)) False
---   = panic "iselExpr64(???)"
-
-iselExpr64 (StInd pk addrTree)
-   | is64BitRep pk
-   = getRegister addrTree              `thenNat` \ register_addr ->
-     getNewRegNCG IntRep               `thenNat` \ t_addr ->
-     getNewRegNCG IntRep               `thenNat` \ rlo ->
-     let rhi = getHiVRegFromLo rlo
-         code_addr = registerCode register_addr t_addr
-         reg_addr  = registerName register_addr t_addr
-         mov_hi = LD W (AddrRegImm reg_addr (ImmInt 0)) rhi
-         mov_lo = LD W (AddrRegImm reg_addr (ImmInt 4)) rlo
-     in
-         returnNat (
-            ChildCode64 (code_addr `snocOL` mov_hi `snocOL` mov_lo) 
-                        (getVRegUnique rlo)
-         )
-
-iselExpr64 (StReg (StixTemp (StixVReg vu pk)))
-   | is64BitRep pk
-   = getNewRegNCG IntRep               `thenNat` \ r_dst_lo ->
-     let r_dst_hi = getHiVRegFromLo r_dst_lo
-         r_src_lo = mkVReg vu IntRep
-         r_src_hi = getHiVRegFromLo r_src_lo
-         mov_lo = mkMOV r_src_lo r_dst_lo
-         mov_hi = mkMOV r_src_hi r_dst_hi
-         mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
-     in
-         returnNat (
-            ChildCode64 (toOL [mov_hi, mov_lo]) (getVRegUnique r_dst_lo)
-         )
-
-iselExpr64 (StCall fn cconv kind args)
-  | is64BitRep kind
-  = genCCall fn cconv kind args                        `thenNat` \ call ->
-    getNewRegNCG IntRep                                `thenNat` \ r_dst_lo ->
-    let r_dst_hi = getHiVRegFromLo r_dst_lo
-        mov_lo = mkMOV o0 r_dst_lo
-        mov_hi = mkMOV o1 r_dst_hi
-        mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
-    in
-    returnNat (
-       ChildCode64 (call `snocOL` mov_hi `snocOL` mov_lo) 
-                   (getVRegUnique r_dst_lo)
-    )
-
-iselExpr64 expr
-   = pprPanic "iselExpr64(sparc)" (pprStixExpr expr)
-
-#endif /* sparc_TARGET_ARCH */
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if powerpc_TARGET_ARCH
-
-assignMem_I64Code addrTree valueTree
-   = iselExpr64 valueTree              `thenNat` \ (ChildCode64 vcode vrlo) ->
-     getRegister addrTree              `thenNat` \ register_addr ->
-     getNewRegNCG IntRep               `thenNat` \ t_addr ->
-     let rlo = VirtualRegI vrlo
-         rhi = getHiVRegFromLo rlo
-         code_addr = registerCode register_addr t_addr
-         reg_addr  = registerName register_addr t_addr
-         -- Big-endian store
-         mov_hi = ST W rhi (AddrRegImm reg_addr (ImmInt 0))
-         mov_lo = ST W rlo (AddrRegImm reg_addr (ImmInt 4))
-     in
-         returnNat (vcode `appOL` code_addr `snocOL` mov_hi `snocOL` mov_lo)
-
-
-assignReg_I64Code (StixTemp (StixVReg u_dst pk)) valueTree
-   = iselExpr64 valueTree              `thenNat` \ (ChildCode64 vcode vr_src_lo) ->
-     let 
-         r_dst_lo = mkVReg u_dst IntRep
-         r_src_lo = VirtualRegI vr_src_lo
-         r_dst_hi = getHiVRegFromLo r_dst_lo
-         r_src_hi = getHiVRegFromLo r_src_lo
-         mov_lo = MR r_dst_lo r_src_lo
-         mov_hi = MR r_dst_hi r_src_hi
-     in
-         returnNat (
-            vcode `snocOL` mov_hi `snocOL` mov_lo
-         )
-assignReg_I64Code lvalue valueTree
-   = pprPanic "assignReg_I64Code(powerpc): invalid lvalue"
-              (pprStixReg lvalue)
-
-
--- Don't delete this -- it's very handy for debugging.
---iselExpr64 expr 
---   | trace ("iselExpr64: " ++ showSDoc (pprStixExpr expr)) False
---   = panic "iselExpr64(???)"
-
-iselExpr64 (StInd pk addrTree)
-   | is64BitRep pk
-   = getRegister addrTree              `thenNat` \ register_addr ->
-     getNewRegNCG IntRep               `thenNat` \ t_addr ->
-     getNewRegNCG IntRep               `thenNat` \ rlo ->
-     let rhi = getHiVRegFromLo rlo
-         code_addr = registerCode register_addr t_addr
-         reg_addr  = registerName register_addr t_addr
-         mov_hi = LD W rhi (AddrRegImm reg_addr (ImmInt 0))
-         mov_lo = LD W rlo (AddrRegImm reg_addr (ImmInt 4))
-     in
-         returnNat (
-            ChildCode64 (code_addr `snocOL` mov_hi `snocOL` mov_lo) 
-                        (getVRegUnique rlo)
-         )
-
-iselExpr64 (StReg (StixTemp (StixVReg vu pk)))
-   | is64BitRep pk
-   = getNewRegNCG IntRep               `thenNat` \ r_dst_lo ->
-     let r_dst_hi = getHiVRegFromLo r_dst_lo
-         r_src_lo = mkVReg vu IntRep
-         r_src_hi = getHiVRegFromLo r_src_lo
-         mov_lo = MR r_dst_lo r_src_lo
-         mov_hi = MR r_dst_hi r_src_hi
-     in
-         returnNat (
-            ChildCode64 (toOL [mov_hi, mov_lo]) (getVRegUnique r_dst_lo)
-         )
-
-iselExpr64 (StCall fn cconv kind args)
-  | is64BitRep kind
-  = genCCall fn cconv kind args                        `thenNat` \ call ->
-    getNewRegNCG IntRep                                `thenNat` \ r_dst_lo ->
-    let r_dst_hi = getHiVRegFromLo r_dst_lo
-        mov_lo = MR r_dst_lo r4
-        mov_hi = MR r_dst_hi r3
-    in
-    returnNat (
-       ChildCode64 (call `snocOL` mov_hi `snocOL` mov_lo) 
-                   (getVRegUnique r_dst_lo)
-    )
-
-iselExpr64 expr
-   = pprPanic "iselExpr64(powerpc)" (pprStixExpr expr)
-
-#endif /* powerpc_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{The @Register@ type}
-%*                                                                     *
-%************************************************************************
-
-@Register@s passed up the tree.  If the stix code forces the register
-to live in a pre-decided machine register, it comes out as @Fixed@;
-otherwise, it comes out as @Any@, and the parent can decide which
-register to put it in.
-
-\begin{code}
-data Register
-  = Fixed   PrimRep Reg InstrBlock
-  | Any            PrimRep (Reg -> InstrBlock)
-
-registerCode :: Register -> Reg -> InstrBlock
-registerCode (Fixed _ _ code) reg = code
-registerCode (Any _ code) reg = code reg
-
-registerCodeF (Fixed _ _ code) = code
-registerCodeF (Any _ _)        = panic "registerCodeF"
-
-registerCodeA (Any _ code)  = code
-registerCodeA (Fixed _ _ _) = panic "registerCodeA"
-
-registerName :: Register -> Reg -> Reg
-registerName (Fixed _ reg _) _ = reg
-registerName (Any _ _)   reg   = reg
-
-registerNameF (Fixed _ reg _) = reg
-registerNameF (Any _ _)       = panic "registerNameF"
-
-registerRep :: Register -> PrimRep
-registerRep (Fixed pk _ _) = pk
-registerRep (Any   pk _) = pk
-
-swizzleRegisterRep :: Register -> PrimRep -> Register
-swizzleRegisterRep (Fixed _ reg code) rep = Fixed rep reg code
-swizzleRegisterRep (Any _ codefn)     rep = Any rep codefn
-
-{-# INLINE registerCode  #-}
-{-# INLINE registerCodeF #-}
-{-# INLINE registerName  #-}
-{-# INLINE registerNameF #-}
-{-# INLINE registerRep   #-}
-{-# INLINE isFixed       #-}
-{-# INLINE isAny         #-}
-
-isFixed, isAny :: Register -> Bool
-isFixed (Fixed _ _ _) = True
-isFixed (Any _ _)     = False
-
-isAny = not . isFixed
-\end{code}
-
-Generate code to get a subtree into a @Register@:
-\begin{code}
-
-getRegisterReg :: StixReg -> NatM Register
-getRegister :: StixExpr -> NatM Register
-
-
-getRegisterReg (StixMagicId mid)
-  = case get_MagicId_reg_or_addr mid of
-       Left (RealReg rrno) 
-          -> let pk = magicIdPrimRep mid
-             in  returnNat (Fixed pk (RealReg rrno) nilOL)
-       Right baseRegAddr 
-          -- By this stage, the only MagicIds remaining should be the
-          -- ones which map to a real machine register on this platform.  Hence ...
-          -> pprPanic "getRegisterReg-memory" (pprMagicId mid)
-
-getRegisterReg (StixTemp (StixVReg u pk))
-  = returnNat (Fixed pk (mkVReg u pk) nilOL)
-
--------------
-
--- Don't delete this -- it's very handy for debugging.
---getRegister expr 
---   | trace ("getRegiste: " ++ showSDoc (pprStixExpr expr)) False
---   = panic "getRegister(???)"
-
-getRegister (StReg reg) 
-  = getRegisterReg reg
-
-getRegister tree@(StIndex _ _ _) 
-  = getRegister (mangleIndexTree tree)
-
-getRegister (StCall fn cconv kind args)
-  | not (ncg_target_is_32bit && is64BitRep kind)
-  = genCCall fn cconv kind args            `thenNat` \ call ->
-    returnNat (Fixed kind reg call)
-  where
-    reg = if isFloatingRep kind
-         then IF_ARCH_alpha( f0, IF_ARCH_i386( fake0, IF_ARCH_sparc( f0, IF_ARCH_powerpc( f1,))))
-         else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0, IF_ARCH_powerpc( r3,))))
-
-getRegister (StString s)
-  = getNatLabelNCG                 `thenNat` \ lbl ->
-    let
-       imm_lbl = ImmCLbl lbl
-
-       code dst = toOL [
-           SEGMENT RoDataSegment,
-           LABEL lbl,
-           ASCII True (unpackFS s),
-           SEGMENT TextSegment,
-#if alpha_TARGET_ARCH
-           LDA dst (AddrImm imm_lbl)
-#endif
-#if i386_TARGET_ARCH
-           MOV L (OpImm imm_lbl) (OpReg dst)
-#endif
-#if sparc_TARGET_ARCH
-           SETHI (HI imm_lbl) dst,
-           OR False dst (RIImm (LO imm_lbl)) dst
-#endif
-#if powerpc_TARGET_ARCH
-           LIS dst (HI imm_lbl),
-           OR dst dst (RIImm (LO imm_lbl))
-#endif
-           ]
-    in
-    returnNat (Any PtrRep code)
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--- end of machine-"independent" bit; here we go on the rest...
-
-#if alpha_TARGET_ARCH
-
-getRegister (StDouble d)
-  = getNatLabelNCG                 `thenNat` \ lbl ->
-    getNewRegNCG PtrRep            `thenNat` \ tmp ->
-    let code dst = mkSeqInstrs [
-           SEGMENT DataSegment,
-           LABEL lbl,
-           DATA TF [ImmLab (rational d)],
-           SEGMENT TextSegment,
-           LDA tmp (AddrImm (ImmCLbl lbl)),
-           LD TF dst (AddrReg tmp)]
-    in
-       returnNat (Any DoubleRep code)
-
-getRegister (StPrim primop [x]) -- unary PrimOps
-  = case primop of
-      IntNegOp -> trivialUCode (NEG Q False) x
-
-      NotOp    -> trivialUCode NOT x
-
-      FloatNegOp  -> trivialUFCode FloatRep  (FNEG TF) x
-      DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
-
-      OrdOp -> coerceIntCode IntRep x
-      ChrOp -> chrCode x
-
-      Float2IntOp  -> coerceFP2Int    x
-      Int2FloatOp  -> coerceInt2FP pr x
-      Double2IntOp -> coerceFP2Int    x
-      Int2DoubleOp -> coerceInt2FP pr x
-
-      Double2FloatOp -> coerceFltCode x
-      Float2DoubleOp -> coerceFltCode x
-
-      other_op -> getRegister (StCall fn CCallConv DoubleRep [x])
-       where
-         fn = case other_op of
-                FloatExpOp    -> FSLIT("exp")
-                FloatLogOp    -> FSLIT("log")
-                FloatSqrtOp   -> FSLIT("sqrt")
-                FloatSinOp    -> FSLIT("sin")
-                FloatCosOp    -> FSLIT("cos")
-                FloatTanOp    -> FSLIT("tan")
-                FloatAsinOp   -> FSLIT("asin")
-                FloatAcosOp   -> FSLIT("acos")
-                FloatAtanOp   -> FSLIT("atan")
-                FloatSinhOp   -> FSLIT("sinh")
-                FloatCoshOp   -> FSLIT("cosh")
-                FloatTanhOp   -> FSLIT("tanh")
-                DoubleExpOp   -> FSLIT("exp")
-                DoubleLogOp   -> FSLIT("log")
-                DoubleSqrtOp  -> FSLIT("sqrt")
-                DoubleSinOp   -> FSLIT("sin")
-                DoubleCosOp   -> FSLIT("cos")
-                DoubleTanOp   -> FSLIT("tan")
-                DoubleAsinOp  -> FSLIT("asin")
-                DoubleAcosOp  -> FSLIT("acos")
-                DoubleAtanOp  -> FSLIT("atan")
-                DoubleSinhOp  -> FSLIT("sinh")
-                DoubleCoshOp  -> FSLIT("cosh")
-                DoubleTanhOp  -> FSLIT("tanh")
-  where
-    pr = panic "MachCode.getRegister: no primrep needed for Alpha"
-
-getRegister (StPrim primop [x, y]) -- dyadic PrimOps
-  = case primop of
-      CharGtOp -> trivialCode (CMP LTT) y x
-      CharGeOp -> trivialCode (CMP LE) y x
-      CharEqOp -> trivialCode (CMP EQQ) x y
-      CharNeOp -> int_NE_code x y
-      CharLtOp -> trivialCode (CMP LTT) x y
-      CharLeOp -> trivialCode (CMP LE) x y
-
-      IntGtOp  -> trivialCode (CMP LTT) y x
-      IntGeOp  -> trivialCode (CMP LE) y x
-      IntEqOp  -> trivialCode (CMP EQQ) x y
-      IntNeOp  -> int_NE_code x y
-      IntLtOp  -> trivialCode (CMP LTT) x y
-      IntLeOp  -> trivialCode (CMP LE) x y
-
-      WordGtOp -> trivialCode (CMP ULT) y x
-      WordGeOp -> trivialCode (CMP ULE) x y
-      WordEqOp -> trivialCode (CMP EQQ)  x y
-      WordNeOp -> int_NE_code x y
-      WordLtOp -> trivialCode (CMP ULT) x y
-      WordLeOp -> trivialCode (CMP ULE) x y
-
-      AddrGtOp -> trivialCode (CMP ULT) y x
-      AddrGeOp -> trivialCode (CMP ULE) y x
-      AddrEqOp -> trivialCode (CMP EQQ)  x y
-      AddrNeOp -> int_NE_code x y
-      AddrLtOp -> trivialCode (CMP ULT) x y
-      AddrLeOp -> trivialCode (CMP ULE) x y
-       
-      FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
-      FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
-      FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
-      FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
-      FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
-      FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
-
-      DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
-      DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
-      DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
-      DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
-      DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
-      DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
-
-      IntAddOp  -> trivialCode (ADD Q False) x y
-      IntSubOp  -> trivialCode (SUB Q False) x y
-      IntMulOp  -> trivialCode (MUL Q False) x y
-      IntQuotOp -> trivialCode (DIV Q False) x y
-      IntRemOp  -> trivialCode (REM Q False) x y
-
-      WordAddOp  -> trivialCode (ADD Q False) x y
-      WordSubOp  -> trivialCode (SUB Q False) x y
-      WordMulOp  -> trivialCode (MUL Q False) x y
-      WordQuotOp -> trivialCode (DIV Q True) x y
-      WordRemOp  -> trivialCode (REM Q True) x y
-
-      FloatAddOp -> trivialFCode  FloatRep (FADD TF) x y
-      FloatSubOp -> trivialFCode  FloatRep (FSUB TF) x y
-      FloatMulOp -> trivialFCode  FloatRep (FMUL TF) x y
-      FloatDivOp -> trivialFCode  FloatRep (FDIV TF) x y
-
-      DoubleAddOp -> trivialFCode  DoubleRep (FADD TF) x y
-      DoubleSubOp -> trivialFCode  DoubleRep (FSUB TF) x y
-      DoubleMulOp -> trivialFCode  DoubleRep (FMUL TF) x y
-      DoubleDivOp -> trivialFCode  DoubleRep (FDIV TF) x y
-
-      AddrAddOp  -> trivialCode (ADD Q False) x y
-      AddrSubOp  -> trivialCode (SUB Q False) x y
-      AddrRemOp  -> trivialCode (REM Q True) x y
-
-      AndOp  -> trivialCode AND x y
-      OrOp   -> trivialCode OR  x y
-      XorOp  -> trivialCode XOR x y
-      SllOp  -> trivialCode SLL x y
-      SrlOp  -> trivialCode SRL x y
-
-      ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
-      ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
-      ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
-
-      FloatPowerOp  -> getRegister (StCall FSLIT("pow") CCallConv DoubleRep [x,y])
-      DoublePowerOp -> getRegister (StCall FSLIT("pow") CCallConv DoubleRep [x,y])
-  where
-    {- ------------------------------------------------------------
-       Some bizarre special code for getting condition codes into
-       registers.  Integer non-equality is a test for equality
-       followed by an XOR with 1.  (Integer comparisons always set
-       the result register to 0 or 1.)  Floating point comparisons of
-       any kind leave the result in a floating point register, so we
-       need to wrangle an integer register out of things.
-    -}
-    int_NE_code :: StixTree -> StixTree -> NatM Register
-
-    int_NE_code x y
-      = trivialCode (CMP EQQ) x y      `thenNat` \ register ->
-       getNewRegNCG IntRep             `thenNat` \ tmp ->
-       let
-           code = registerCode register tmp
-           src  = registerName register tmp
-           code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
-       in
-       returnNat (Any IntRep code__2)
-
-    {- ------------------------------------------------------------
-       Comments for int_NE_code also apply to cmpF_code
-    -}
-    cmpF_code
-       :: (Reg -> Reg -> Reg -> Instr)
-       -> Cond
-       -> StixTree -> StixTree
-       -> NatM Register
-
-    cmpF_code instr cond x y
-      = trivialFCode pr instr x y      `thenNat` \ register ->
-       getNewRegNCG DoubleRep          `thenNat` \ tmp ->
-       getNatLabelNCG                  `thenNat` \ lbl ->
-       let
-           code = registerCode register tmp
-           result  = registerName register tmp
-
-           code__2 dst = code . mkSeqInstrs [
-               OR zeroh (RIImm (ImmInt 1)) dst,
-               BF cond  result (ImmCLbl lbl),
-               OR zeroh (RIReg zeroh) dst,
-               LABEL lbl]
-       in
-       returnNat (Any IntRep code__2)
-      where
-       pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
-      ------------------------------------------------------------
-
-getRegister (StInd pk mem)
-  = getAmode mem                   `thenNat` \ amode ->
-    let
-       code = amodeCode amode
-       src   = amodeAddr amode
-       size = primRepToSize pk
-       code__2 dst = code . mkSeqInstr (LD size dst src)
-    in
-    returnNat (Any pk code__2)
-
-getRegister (StInt i)
-  | fits8Bits i
-  = let
-       code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
-    in
-    returnNat (Any IntRep code)
-  | otherwise
-  = let
-       code dst = mkSeqInstr (LDI Q dst src)
-    in
-    returnNat (Any IntRep code)
-  where
-    src = ImmInt (fromInteger i)
-
-getRegister leaf
-  | maybeToBool imm
-  = let
-       code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
-    in
-    returnNat (Any PtrRep code)
-  where
-    imm = maybeImm leaf
-    imm__2 = case imm of Just x -> x
-
-#endif /* alpha_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if i386_TARGET_ARCH
-
-getRegister (StFloat f)
-  = getNatLabelNCG                 `thenNat` \ lbl ->
-    let code dst = toOL [
-           SEGMENT DataSegment,
-           LABEL lbl,
-           DATA F [ImmFloat f],
-           SEGMENT TextSegment,
-           GLD F (ImmAddr (ImmCLbl lbl) 0) dst
-           ]
-    in
-    returnNat (Any FloatRep code)
-
-
-getRegister (StDouble d)
-
-  | d == 0.0
-  = let code dst = unitOL (GLDZ dst)
-    in  returnNat (Any DoubleRep code)
-
-  | d == 1.0
-  = let code dst = unitOL (GLD1 dst)
-    in  returnNat (Any DoubleRep code)
-
-  | otherwise
-  = getNatLabelNCG                 `thenNat` \ lbl ->
-    let code dst = toOL [
-           SEGMENT DataSegment,
-           LABEL lbl,
-           DATA DF [ImmDouble d],
-           SEGMENT TextSegment,
-           GLD DF (ImmAddr (ImmCLbl lbl) 0) dst
-           ]
-    in
-    returnNat (Any DoubleRep code)
-
-
-getRegister (StMachOp mop [x]) -- unary MachOps
-  = case mop of
-      MO_NatS_Neg  -> trivialUCode (NEGI L) x
-      MO_Nat_Not   -> trivialUCode (NOT L) x
-      MO_32U_to_8U -> trivialUCode (AND L (OpImm (ImmInt 255))) x
-
-      MO_Flt_Neg  -> trivialUFCode FloatRep  (GNEG F) x
-      MO_Dbl_Neg  -> trivialUFCode DoubleRep (GNEG DF) x
-
-      MO_Flt_Sqrt -> trivialUFCode FloatRep  (GSQRT F) x
-      MO_Dbl_Sqrt -> trivialUFCode DoubleRep (GSQRT DF) x
-
-      MO_Flt_Sin  -> trivialUFCode FloatRep  (GSIN F) x
-      MO_Dbl_Sin  -> trivialUFCode DoubleRep (GSIN DF) x
-
-      MO_Flt_Cos  -> trivialUFCode FloatRep  (GCOS F) x
-      MO_Dbl_Cos  -> trivialUFCode DoubleRep (GCOS DF) x
-
-      MO_Flt_Tan  -> trivialUFCode FloatRep  (GTAN F) x
-      MO_Dbl_Tan  -> trivialUFCode DoubleRep (GTAN DF) x
-
-      MO_Flt_to_NatS -> coerceFP2Int FloatRep x
-      MO_NatS_to_Flt -> coerceInt2FP FloatRep x
-      MO_Dbl_to_NatS -> coerceFP2Int DoubleRep x
-      MO_NatS_to_Dbl -> coerceInt2FP DoubleRep x
-
-      -- Conversions which are a nop on x86
-      MO_32U_to_NatS  -> conversionNop IntRep    x
-      MO_32S_to_NatS  -> conversionNop IntRep    x
-      MO_NatS_to_32U  -> conversionNop WordRep   x
-      MO_32U_to_NatU  -> conversionNop WordRep   x
-
-      MO_NatU_to_NatS -> conversionNop IntRep    x
-      MO_NatS_to_NatU -> conversionNop WordRep   x
-      MO_NatP_to_NatU -> conversionNop WordRep   x
-      MO_NatU_to_NatP -> conversionNop PtrRep    x
-      MO_NatS_to_NatP -> conversionNop PtrRep    x
-      MO_NatP_to_NatS -> conversionNop IntRep    x
-
-      MO_Dbl_to_Flt   -> conversionNop FloatRep  x
-      MO_Flt_to_Dbl   -> conversionNop DoubleRep x
-
-      -- sign-extending widenings
-      MO_8U_to_NatU   -> integerExtend False 24 x
-      MO_8S_to_NatS   -> integerExtend True  24 x
-      MO_16U_to_NatU  -> integerExtend False 16 x
-      MO_16S_to_NatS  -> integerExtend True  16 x
-      MO_8U_to_32U    -> integerExtend False 24 x
-
-      other_op 
-         -> getRegister (
-               (if is_float_op then demote else id)
-               (StCall (Left fn) CCallConv DoubleRep 
-                       [(if is_float_op then promote else id) x])
-            )
-      where
-        integerExtend signed nBits x
-           = getRegister (
-                StMachOp (if signed then MO_Nat_Sar else MO_Nat_Shr) 
-                         [StMachOp MO_Nat_Shl [x, StInt nBits], StInt nBits]
-             )
-
-        conversionNop new_rep expr
-            = getRegister expr         `thenNat` \ e_code ->
-              returnNat (swizzleRegisterRep e_code new_rep)
-
-        promote x = StMachOp MO_Flt_to_Dbl [x]
-        demote  x = StMachOp MO_Dbl_to_Flt [x]
-       (is_float_op, fn)
-         = case mop of
-             MO_Flt_Exp   -> (True,  FSLIT("exp"))
-             MO_Flt_Log   -> (True,  FSLIT("log"))
-
-             MO_Flt_Asin  -> (True,  FSLIT("asin"))
-             MO_Flt_Acos  -> (True,  FSLIT("acos"))
-             MO_Flt_Atan  -> (True,  FSLIT("atan"))
-
-             MO_Flt_Sinh  -> (True,  FSLIT("sinh"))
-             MO_Flt_Cosh  -> (True,  FSLIT("cosh"))
-             MO_Flt_Tanh  -> (True,  FSLIT("tanh"))
-
-             MO_Dbl_Exp   -> (False, FSLIT("exp"))
-             MO_Dbl_Log   -> (False, FSLIT("log"))
-
-             MO_Dbl_Asin  -> (False, FSLIT("asin"))
-             MO_Dbl_Acos  -> (False, FSLIT("acos"))
-             MO_Dbl_Atan  -> (False, FSLIT("atan"))
-
-             MO_Dbl_Sinh  -> (False, FSLIT("sinh"))
-             MO_Dbl_Cosh  -> (False, FSLIT("cosh"))
-             MO_Dbl_Tanh  -> (False, FSLIT("tanh"))
-
-              other -> pprPanic "getRegister(x86) - binary StMachOp (2)" 
-                                (pprMachOp mop)
-
-
-getRegister (StMachOp mop [x, y]) -- dyadic MachOps
-  = case mop of
-      MO_32U_Gt  -> condIntReg GTT x y
-      MO_32U_Ge  -> condIntReg GE x y
-      MO_32U_Eq  -> condIntReg EQQ x y
-      MO_32U_Ne  -> condIntReg NE x y
-      MO_32U_Lt  -> condIntReg LTT x y
-      MO_32U_Le  -> condIntReg LE x y
-
-      MO_Nat_Eq   -> condIntReg EQQ x y
-      MO_Nat_Ne   -> condIntReg NE x y
-
-      MO_NatS_Gt  -> condIntReg GTT x y
-      MO_NatS_Ge  -> condIntReg GE x y
-      MO_NatS_Lt  -> condIntReg LTT x y
-      MO_NatS_Le  -> condIntReg LE x y
-
-      MO_NatU_Gt  -> condIntReg GU  x y
-      MO_NatU_Ge  -> condIntReg GEU x y
-      MO_NatU_Lt  -> condIntReg LU  x y
-      MO_NatU_Le  -> condIntReg LEU x y
-
-      MO_Flt_Gt -> condFltReg GTT x y
-      MO_Flt_Ge -> condFltReg GE x y
-      MO_Flt_Eq -> condFltReg EQQ x y
-      MO_Flt_Ne -> condFltReg NE x y
-      MO_Flt_Lt -> condFltReg LTT x y
-      MO_Flt_Le -> condFltReg LE x y
-
-      MO_Dbl_Gt -> condFltReg GTT x y
-      MO_Dbl_Ge -> condFltReg GE x y
-      MO_Dbl_Eq -> condFltReg EQQ x y
-      MO_Dbl_Ne -> condFltReg NE x y
-      MO_Dbl_Lt -> condFltReg LTT x y
-      MO_Dbl_Le -> condFltReg LE x y
-
-      MO_Nat_Add   -> add_code L x y
-      MO_Nat_Sub   -> sub_code L x y
-      MO_NatS_Quot -> trivialCode (IQUOT L) Nothing x y
-      MO_NatS_Rem  -> trivialCode (IREM L) Nothing x y
-      MO_NatU_Quot -> trivialCode (QUOT L) Nothing x y
-      MO_NatU_Rem  -> trivialCode (REM L) Nothing x y
-      MO_NatS_Mul  -> let op = IMUL L in trivialCode op (Just op) x y
-      MO_NatU_Mul  -> let op = MUL L in trivialCode op (Just op) x y
-      MO_NatS_MulMayOflo -> imulMayOflo x y
-
-      MO_Flt_Add -> trivialFCode  FloatRep  GADD x y
-      MO_Flt_Sub -> trivialFCode  FloatRep  GSUB x y
-      MO_Flt_Mul -> trivialFCode  FloatRep  GMUL x y
-      MO_Flt_Div -> trivialFCode  FloatRep  GDIV x y
-
-      MO_Dbl_Add -> trivialFCode DoubleRep GADD x y
-      MO_Dbl_Sub -> trivialFCode DoubleRep GSUB x y
-      MO_Dbl_Mul -> trivialFCode DoubleRep GMUL x y
-      MO_Dbl_Div -> trivialFCode DoubleRep GDIV x y
-
-      MO_Nat_And -> let op = AND L in trivialCode op (Just op) x y
-      MO_Nat_Or  -> let op = OR  L in trivialCode op (Just op) x y
-      MO_Nat_Xor -> let op = XOR L in trivialCode op (Just op) x y
-
-       {- Shift ops on x86s have constraints on their source, it
-          either has to be Imm, CL or 1
-           => trivialCode's is not restrictive enough (sigh.)
-       -}         
-      MO_Nat_Shl  -> shift_code (SHL L) x y {-False-}
-      MO_Nat_Shr  -> shift_code (SHR L) x y {-False-}
-      MO_Nat_Sar  -> shift_code (SAR L) x y {-False-}
-
-      MO_Flt_Pwr  -> getRegister (demote 
-                                 (StCall (Left FSLIT("pow")) CCallConv DoubleRep 
-                                         [promote x, promote y])
-                                 )
-      MO_Dbl_Pwr -> getRegister (StCall (Left FSLIT("pow")) CCallConv DoubleRep 
-                                        [x, y])
-      other -> pprPanic "getRegister(x86) - binary StMachOp (1)" (pprMachOp mop)
-  where
-    promote x = StMachOp MO_Flt_to_Dbl [x]
-    demote x  = StMachOp MO_Dbl_to_Flt [x]
-
-    --------------------
-    imulMayOflo :: StixExpr -> StixExpr -> NatM Register
-    imulMayOflo a1 a2
-       = getNewRegNCG IntRep           `thenNat` \ t1 ->
-         getNewRegNCG IntRep           `thenNat` \ t2 ->
-         getNewRegNCG IntRep           `thenNat` \ res_lo ->
-         getNewRegNCG IntRep           `thenNat` \ res_hi ->
-         getRegister a1                        `thenNat` \ reg1 ->
-         getRegister a2                `thenNat` \ reg2 ->
-         let code1 = registerCode reg1 t1
-             code2 = registerCode reg2 t2
-             src1  = registerName reg1 t1
-             src2  = registerName reg2 t2
-             code dst = code1 `appOL` code2 `appOL`
-                        toOL [
-                           MOV L (OpReg src1) (OpReg res_hi),
-                           MOV L (OpReg src2) (OpReg res_lo),
-                           IMUL64 res_hi res_lo,               -- result in res_hi:res_lo
-                           SAR L (ImmInt 31) (OpReg res_lo),   -- sign extend lower part
-                           SUB L (OpReg res_hi) (OpReg res_lo),        -- compare against upper
-                           MOV L (OpReg res_lo) (OpReg dst)
-                           -- dst==0 if high part == sign extended low part
-                        ]
-         in
-            returnNat (Any IntRep code)
-
-    --------------------
-    shift_code :: (Imm -> Operand -> Instr)
-              -> StixExpr
-              -> StixExpr
-              -> NatM Register
-
-      {- Case1: shift length as immediate -}
-      -- Code is the same as the first eq. for trivialCode -- sigh.
-    shift_code instr x y{-amount-}
-      | maybeToBool imm
-      = getRegister x                     `thenNat` \ regx ->
-        let mkcode dst
-              = if   isAny regx
-                then registerCodeA regx dst  `bind` \ code_x ->
-                     code_x `snocOL`
-                     instr imm__2 (OpReg dst)
-                else registerCodeF regx      `bind` \ code_x ->
-                     registerNameF regx      `bind` \ r_x ->
-                     code_x `snocOL`
-                     MOV L (OpReg r_x) (OpReg dst) `snocOL`
-                     instr imm__2 (OpReg dst)
-        in
-        returnNat (Any IntRep mkcode)        
-      where
-       imm = maybeImm y
-       imm__2 = case imm of Just x -> x
-
-      {- Case2: shift length is complex (non-immediate) -}
-      -- Since ECX is always used as a spill temporary, we can't
-      -- use it here to do non-immediate shifts.  No big deal --
-      -- they are only very rare, and we can use an equivalent
-      -- test-and-jump sequence which doesn't use ECX.
-      -- DO NOT REPLACE THIS CODE WITH THE "OBVIOUS" shl/shr/sar CODE, 
-      -- SINCE IT WILL CAUSE SERIOUS PROBLEMS WITH THE SPILLER
-    shift_code instr x y{-amount-}
-     = getRegister x   `thenNat` \ register1 ->
-       getRegister y   `thenNat` \ register2 ->
-       getNatLabelNCG  `thenNat` \ lbl_test3 ->
-       getNatLabelNCG  `thenNat` \ lbl_test2 ->
-       getNatLabelNCG  `thenNat` \ lbl_test1 ->
-       getNatLabelNCG  `thenNat` \ lbl_test0 ->
-       getNatLabelNCG  `thenNat` \ lbl_after ->
-       getNewRegNCG IntRep   `thenNat` \ tmp ->
-       let code__2 dst
-              = let src_val  = registerName register1 dst
-                    code_val = registerCode register1 dst
-                    src_amt  = registerName register2 tmp
-                    code_amt = registerCode register2 tmp
-                    r_dst    = OpReg dst
-                    r_tmp    = OpReg tmp
-                in
-                    code_amt `snocOL`
-                    MOV L (OpReg src_amt) r_tmp `appOL`
-                    code_val `snocOL`
-                    MOV L (OpReg src_val) r_dst `appOL`
-                    toOL [
-                       COMMENT (mkFastString "begin shift sequence"),
-                       MOV L (OpReg src_val) r_dst,
-                       MOV L (OpReg src_amt) r_tmp,
-
-                       BT L (ImmInt 4) r_tmp,
-                       JXX GEU lbl_test3,
-                       instr (ImmInt 16) r_dst,
-
-                       LABEL lbl_test3,
-                       BT L (ImmInt 3) r_tmp,
-                       JXX GEU lbl_test2,
-                       instr (ImmInt 8) r_dst,
-
-                       LABEL lbl_test2,
-                       BT L (ImmInt 2) r_tmp,
-                       JXX GEU lbl_test1,
-                       instr (ImmInt 4) r_dst,
-
-                       LABEL lbl_test1,
-                       BT L (ImmInt 1) r_tmp,
-                       JXX GEU lbl_test0,
-                       instr (ImmInt 2) r_dst,
-
-                       LABEL lbl_test0,
-                       BT L (ImmInt 0) r_tmp,
-                       JXX GEU lbl_after,
-                       instr (ImmInt 1) r_dst,
-                       LABEL lbl_after,
-                                           
-                       COMMENT (mkFastString "end shift sequence")
-                    ]
-       in
-       returnNat (Any IntRep code__2)
-
-    --------------------
-    add_code :: Size -> StixExpr -> StixExpr -> NatM Register
-
-    add_code sz x (StInt y)
-      = getRegister x          `thenNat` \ register ->
-       getNewRegNCG IntRep     `thenNat` \ tmp ->
-       let
-           code = registerCode register tmp
-           src1 = registerName register tmp
-           src2 = ImmInt (fromInteger y)
-           code__2 dst 
-               = code `snocOL`
-                LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
-                        (OpReg dst)
-       in
-       returnNat (Any IntRep code__2)
-
-    add_code sz x y = trivialCode (ADD sz) (Just (ADD sz)) x y
-
-    --------------------
-    sub_code :: Size -> StixExpr -> StixExpr -> NatM Register
-
-    sub_code sz x (StInt y)
-      = getRegister x          `thenNat` \ register ->
-       getNewRegNCG IntRep     `thenNat` \ tmp ->
-       let
-           code = registerCode register tmp
-           src1 = registerName register tmp
-           src2 = ImmInt (-(fromInteger y))
-           code__2 dst 
-               = code `snocOL`
-                LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
-                        (OpReg dst)
-       in
-       returnNat (Any IntRep code__2)
-
-    sub_code sz x y = trivialCode (SUB sz) Nothing x y
-
-getRegister (StInd pk mem)
-  | not (is64BitRep pk)
-  = getAmode mem                   `thenNat` \ amode ->
-    let
-       code = amodeCode amode
-       src  = amodeAddr amode
-       size = primRepToSize pk
-       code__2 dst = code `snocOL`
-                     if   pk == DoubleRep || pk == FloatRep
-                     then GLD size src dst
-                     else (case size of
-                               B  -> MOVSxL B
-                               Bu -> MOVZxL Bu
-                               W  -> MOVSxL W
-                               Wu -> MOVZxL Wu
-                               L  -> MOV L
-                               Lu -> MOV L)
-                               (OpAddr src) (OpReg dst)
-    in
-       returnNat (Any pk code__2)
-
-getRegister (StInt i)
-  = let
-       src = ImmInt (fromInteger i)
-       code dst 
-           | i == 0
-           = unitOL (XOR L (OpReg dst) (OpReg dst))
-           | otherwise
-           = unitOL (MOV L (OpImm src) (OpReg dst))
-    in
-       returnNat (Any IntRep code)
-
-getRegister leaf
-  | maybeToBool imm
-  = let code dst = unitOL (MOV L (OpImm imm__2) (OpReg dst))
-    in
-       returnNat (Any PtrRep code)
-  | otherwise
-  = ncgPrimopMoan "getRegister(x86)" (pprStixExpr leaf)
-  where
-    imm = maybeImm leaf
-    imm__2 = case imm of Just x -> x
-
-#endif /* i386_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if sparc_TARGET_ARCH
-
-getRegister (StFloat d)
-  = getNatLabelNCG                 `thenNat` \ lbl ->
-    getNewRegNCG PtrRep            `thenNat` \ tmp ->
-    let code dst = toOL [
-           SEGMENT DataSegment,
-           LABEL lbl,
-           DATA F [ImmFloat d],
-           SEGMENT TextSegment,
-           SETHI (HI (ImmCLbl lbl)) tmp,
-           LD F (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
-    in
-       returnNat (Any FloatRep code)
-
-getRegister (StDouble d)
-  = getNatLabelNCG                 `thenNat` \ lbl ->
-    getNewRegNCG PtrRep            `thenNat` \ tmp ->
-    let code dst = toOL [
-           SEGMENT DataSegment,
-           LABEL lbl,
-           DATA DF [ImmDouble d],
-           SEGMENT TextSegment,
-           SETHI (HI (ImmCLbl lbl)) tmp,
-           LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
-    in
-       returnNat (Any DoubleRep code)
-
-
-getRegister (StMachOp mop [x]) -- unary PrimOps
-  = case mop of
-      MO_NatS_Neg      -> trivialUCode (SUB False False g0) x
-      MO_Nat_Not       -> trivialUCode (XNOR False g0) x
-      MO_32U_to_8U     -> trivialCode (AND False) x (StInt 255)
-
-      MO_Flt_Neg       -> trivialUFCode FloatRep (FNEG F) x
-      MO_Dbl_Neg       -> trivialUFCode DoubleRep (FNEG DF) x
-
-      MO_Dbl_to_Flt    -> coerceDbl2Flt x
-      MO_Flt_to_Dbl    -> coerceFlt2Dbl x
-
-      MO_Flt_to_NatS   -> coerceFP2Int FloatRep x
-      MO_NatS_to_Flt   -> coerceInt2FP FloatRep x
-      MO_Dbl_to_NatS   -> coerceFP2Int DoubleRep x
-      MO_NatS_to_Dbl   -> coerceInt2FP DoubleRep x
-
-      -- Conversions which are a nop on sparc
-      MO_32U_to_NatS   -> conversionNop IntRep   x
-      MO_32S_to_NatS  -> conversionNop IntRep   x
-      MO_NatS_to_32U   -> conversionNop WordRep  x
-      MO_32U_to_NatU   -> conversionNop WordRep  x
-
-      MO_NatU_to_NatS -> conversionNop IntRep    x
-      MO_NatS_to_NatU -> conversionNop WordRep   x
-      MO_NatP_to_NatU -> conversionNop WordRep   x
-      MO_NatU_to_NatP -> conversionNop PtrRep    x
-      MO_NatS_to_NatP -> conversionNop PtrRep    x
-      MO_NatP_to_NatS -> conversionNop IntRep    x
-
-      -- sign-extending widenings
-      MO_8U_to_32U    -> integerExtend False 24 x
-      MO_8U_to_NatU   -> integerExtend False 24 x
-      MO_8S_to_NatS   -> integerExtend True  24 x
-      MO_16U_to_NatU  -> integerExtend False 16 x
-      MO_16S_to_NatS  -> integerExtend True  16 x
-
-      other_op ->
-        let fixed_x = if   is_float_op  -- promote to double
-                      then StMachOp MO_Flt_to_Dbl [x]
-                      else x
-       in
-       getRegister (StCall (Left fn) CCallConv DoubleRep [fixed_x])
-    where
-        integerExtend signed nBits x
-           = getRegister (
-                StMachOp (if signed then MO_Nat_Sar else MO_Nat_Shr) 
-                         [StMachOp MO_Nat_Shl [x, StInt nBits], StInt nBits]
-             )
-        conversionNop new_rep expr
-            = getRegister expr         `thenNat` \ e_code ->
-              returnNat (swizzleRegisterRep e_code new_rep)
-
-       (is_float_op, fn)
-         = case mop of
-             MO_Flt_Exp    -> (True,  FSLIT("exp"))
-             MO_Flt_Log    -> (True,  FSLIT("log"))
-             MO_Flt_Sqrt   -> (True,  FSLIT("sqrt"))
-
-             MO_Flt_Sin    -> (True,  FSLIT("sin"))
-             MO_Flt_Cos    -> (True,  FSLIT("cos"))
-             MO_Flt_Tan    -> (True,  FSLIT("tan"))
-
-             MO_Flt_Asin   -> (True,  FSLIT("asin"))
-             MO_Flt_Acos   -> (True,  FSLIT("acos"))
-             MO_Flt_Atan   -> (True,  FSLIT("atan"))
-
-             MO_Flt_Sinh   -> (True,  FSLIT("sinh"))
-             MO_Flt_Cosh   -> (True,  FSLIT("cosh"))
-             MO_Flt_Tanh   -> (True,  FSLIT("tanh"))
-
-             MO_Dbl_Exp    -> (False, FSLIT("exp"))
-             MO_Dbl_Log    -> (False, FSLIT("log"))
-             MO_Dbl_Sqrt   -> (False, FSLIT("sqrt"))
-
-             MO_Dbl_Sin    -> (False, FSLIT("sin"))
-             MO_Dbl_Cos    -> (False, FSLIT("cos"))
-             MO_Dbl_Tan    -> (False, FSLIT("tan"))
-
-             MO_Dbl_Asin   -> (False, FSLIT("asin"))
-             MO_Dbl_Acos   -> (False, FSLIT("acos"))
-             MO_Dbl_Atan   -> (False, FSLIT("atan"))
-
-             MO_Dbl_Sinh   -> (False, FSLIT("sinh"))
-             MO_Dbl_Cosh   -> (False, FSLIT("cosh"))
-             MO_Dbl_Tanh   -> (False, FSLIT("tanh"))
-
-              other -> pprPanic "getRegister(sparc) - binary StMachOp (2)" 
-                                (pprMachOp mop)
-
-
-getRegister (StMachOp mop [x, y]) -- dyadic PrimOps
-  = case mop of
-      MO_32U_Gt  -> condIntReg GTT x y
-      MO_32U_Ge  -> condIntReg GE x y
-      MO_32U_Eq  -> condIntReg EQQ x y
-      MO_32U_Ne  -> condIntReg NE x y
-      MO_32U_Lt  -> condIntReg LTT x y
-      MO_32U_Le  -> condIntReg LE x y
-
-      MO_Nat_Eq   -> condIntReg EQQ x y
-      MO_Nat_Ne   -> condIntReg NE x y
-
-      MO_NatS_Gt  -> condIntReg GTT x y
-      MO_NatS_Ge  -> condIntReg GE x y
-      MO_NatS_Lt  -> condIntReg LTT x y
-      MO_NatS_Le  -> condIntReg LE x y
-
-      MO_NatU_Gt  -> condIntReg GU  x y
-      MO_NatU_Ge  -> condIntReg GEU x y
-      MO_NatU_Lt  -> condIntReg LU  x y
-      MO_NatU_Le  -> condIntReg LEU x y
-
-      MO_Flt_Gt -> condFltReg GTT x y
-      MO_Flt_Ge -> condFltReg GE x y
-      MO_Flt_Eq -> condFltReg EQQ x y
-      MO_Flt_Ne -> condFltReg NE x y
-      MO_Flt_Lt -> condFltReg LTT x y
-      MO_Flt_Le -> condFltReg LE x y
-
-      MO_Dbl_Gt -> condFltReg GTT x y
-      MO_Dbl_Ge -> condFltReg GE x y
-      MO_Dbl_Eq -> condFltReg EQQ x y
-      MO_Dbl_Ne -> condFltReg NE x y
-      MO_Dbl_Lt -> condFltReg LTT x y
-      MO_Dbl_Le -> condFltReg LE x y
-
-      MO_Nat_Add -> trivialCode (ADD False False) x y
-      MO_Nat_Sub -> trivialCode (SUB False False) x y
-
-      MO_NatS_Mul  -> trivialCode (SMUL False) x y
-      MO_NatU_Mul  -> trivialCode (UMUL False) x y
-      MO_NatS_MulMayOflo -> imulMayOflo x y
-
-      -- ToDo: teach about V8+ SPARC div instructions
-      MO_NatS_Quot -> idiv FSLIT(".div")  x y
-      MO_NatS_Rem  -> idiv FSLIT(".rem")  x y
-      MO_NatU_Quot -> idiv FSLIT(".udiv")  x y
-      MO_NatU_Rem  -> idiv FSLIT(".urem")  x y
-
-      MO_Flt_Add   -> trivialFCode FloatRep  FADD x y
-      MO_Flt_Sub   -> trivialFCode FloatRep  FSUB x y
-      MO_Flt_Mul   -> trivialFCode FloatRep  FMUL x y
-      MO_Flt_Div   -> trivialFCode FloatRep  FDIV x y
-
-      MO_Dbl_Add   -> trivialFCode DoubleRep FADD x y
-      MO_Dbl_Sub   -> trivialFCode DoubleRep FSUB x y
-      MO_Dbl_Mul   -> trivialFCode DoubleRep FMUL x y
-      MO_Dbl_Div   -> trivialFCode DoubleRep FDIV x y
-
-      MO_Nat_And   -> trivialCode (AND False) x y
-      MO_Nat_Or    -> trivialCode (OR  False) x y
-      MO_Nat_Xor   -> trivialCode (XOR False) x y
-
-      MO_Nat_Shl   -> trivialCode SLL x y
-      MO_Nat_Shr   -> trivialCode SRL x y
-      MO_Nat_Sar   -> trivialCode SRA x y
-
-      MO_Flt_Pwr  -> getRegister (StCall (Left FSLIT("pow")) CCallConv DoubleRep 
-                                         [promote x, promote y])
-                      where promote x = StMachOp MO_Flt_to_Dbl [x]
-      MO_Dbl_Pwr -> getRegister (StCall (Left FSLIT("pow")) CCallConv DoubleRep 
-                                        [x, y])
-
-      other -> pprPanic "getRegister(sparc) - binary StMachOp (1)" (pprMachOp mop)
-  where
-    idiv fn x y = getRegister (StCall (Left fn) CCallConv IntRep [x, y])
-
-    --------------------
-    imulMayOflo :: StixExpr -> StixExpr -> NatM Register
-    imulMayOflo a1 a2
-       = getNewRegNCG IntRep           `thenNat` \ t1 ->
-         getNewRegNCG IntRep           `thenNat` \ t2 ->
-         getNewRegNCG IntRep           `thenNat` \ res_lo ->
-         getNewRegNCG IntRep           `thenNat` \ res_hi ->
-         getRegister a1                        `thenNat` \ reg1 ->
-         getRegister a2                `thenNat` \ reg2 ->
-         let code1 = registerCode reg1 t1
-             code2 = registerCode reg2 t2
-             src1  = registerName reg1 t1
-             src2  = registerName reg2 t2
-             code dst = code1 `appOL` code2 `appOL`
-                        toOL [
-                           SMUL False src1 (RIReg src2) res_lo,
-                           RDY res_hi,
-                           SRA res_lo (RIImm (ImmInt 31)) res_lo,
-                           SUB False False res_lo (RIReg res_hi) dst
-                        ]
-         in
-            returnNat (Any IntRep code)
-
-getRegister (StInd pk mem)
-  = getAmode mem                   `thenNat` \ amode ->
-    let
-       code = amodeCode amode
-       src   = amodeAddr amode
-       size = primRepToSize pk
-       code__2 dst = code `snocOL` LD size src dst
-    in
-       returnNat (Any pk code__2)
-
-getRegister (StInt i)
-  | fits13Bits i
-  = let
-       src = ImmInt (fromInteger i)
-       code dst = unitOL (OR False g0 (RIImm src) dst)
-    in
-       returnNat (Any IntRep code)
-
-getRegister leaf
-  | maybeToBool imm
-  = let
-       code dst = toOL [
-           SETHI (HI imm__2) dst,
-           OR False dst (RIImm (LO imm__2)) dst]
-    in
-       returnNat (Any PtrRep code)
-  | otherwise
-  = ncgPrimopMoan "getRegister(sparc)" (pprStixExpr leaf)
-  where
-    imm = maybeImm leaf
-    imm__2 = case imm of Just x -> x
-
-#endif /* sparc_TARGET_ARCH */
-
-#if powerpc_TARGET_ARCH
-getRegister (StMachOp mop [x]) -- unary MachOps
-  = case mop of
-      MO_NatS_Neg  -> trivialUCode NEG x
-      MO_Nat_Not   -> trivialUCode NOT x
-      MO_32U_to_8U     -> trivialCode AND x (StInt 255)
-
-      MO_Flt_to_NatS -> coerceFP2Int FloatRep x
-      MO_NatS_to_Flt -> coerceInt2FP FloatRep x
-      MO_Dbl_to_NatS -> coerceFP2Int DoubleRep x
-      MO_NatS_to_Dbl -> coerceInt2FP DoubleRep x
-
-      -- Conversions which are a nop on PPC
-      MO_NatS_to_32U  -> conversionNop WordRep   x
-      MO_32U_to_NatS  -> conversionNop IntRep    x
-      MO_32U_to_NatU  -> conversionNop WordRep   x
-
-      MO_NatU_to_NatS -> conversionNop IntRep    x
-      MO_NatS_to_NatU -> conversionNop WordRep   x
-      MO_NatP_to_NatU -> conversionNop WordRep   x
-      MO_NatU_to_NatP -> conversionNop PtrRep    x
-      MO_NatS_to_NatP -> conversionNop PtrRep    x
-      MO_NatP_to_NatS -> conversionNop IntRep    x
-
-      MO_Dbl_to_Flt   -> conversionNop FloatRep  x
-      MO_Flt_to_Dbl   -> conversionNop DoubleRep x
-
-      -- sign-extending widenings      ###PPC This is inefficient: use ext* instructions
-      MO_8U_to_NatU   -> integerExtend False 24 x
-      MO_8S_to_NatS   -> integerExtend True  24 x
-      MO_16U_to_NatU  -> integerExtend False 16 x
-      MO_16S_to_NatS  -> integerExtend True  16 x
-      MO_8U_to_32U    -> integerExtend False 24 x
-
-      MO_Flt_Neg      -> trivialUFCode FloatRep FNEG x
-      MO_Dbl_Neg      -> trivialUFCode FloatRep FNEG x
-
-      other_op -> getRegister (StCall (Left fn) CCallConv DoubleRep [x])
-    where
-        integerExtend signed nBits x
-           = getRegister (
-                StMachOp (if signed then MO_Nat_Sar else MO_Nat_Shr) 
-                         [StMachOp MO_Nat_Shl [x, StInt nBits], StInt nBits]
-             )
-        conversionNop new_rep expr
-            = getRegister expr         `thenNat` \ e_code ->
-              returnNat (swizzleRegisterRep e_code new_rep)
-
-       (is_float_op, fn)
-         = case mop of
-             MO_Flt_Exp    -> (True,  FSLIT("exp"))
-             MO_Flt_Log    -> (True,  FSLIT("log"))
-             MO_Flt_Sqrt   -> (True,  FSLIT("sqrt"))
-
-             MO_Flt_Sin    -> (True,  FSLIT("sin"))
-             MO_Flt_Cos    -> (True,  FSLIT("cos"))
-             MO_Flt_Tan    -> (True,  FSLIT("tan"))
-
-             MO_Flt_Asin   -> (True,  FSLIT("asin"))
-             MO_Flt_Acos   -> (True,  FSLIT("acos"))
-             MO_Flt_Atan   -> (True,  FSLIT("atan"))
-
-             MO_Flt_Sinh   -> (True,  FSLIT("sinh"))
-             MO_Flt_Cosh   -> (True,  FSLIT("cosh"))
-             MO_Flt_Tanh   -> (True,  FSLIT("tanh"))
-
-             MO_Dbl_Exp    -> (False, FSLIT("exp"))
-             MO_Dbl_Log    -> (False, FSLIT("log"))
-             MO_Dbl_Sqrt   -> (False, FSLIT("sqrt"))
-
-             MO_Dbl_Sin    -> (False, FSLIT("sin"))
-             MO_Dbl_Cos    -> (False, FSLIT("cos"))
-             MO_Dbl_Tan    -> (False, FSLIT("tan"))
-
-             MO_Dbl_Asin   -> (False, FSLIT("asin"))
-             MO_Dbl_Acos   -> (False, FSLIT("acos"))
-             MO_Dbl_Atan   -> (False, FSLIT("atan"))
-
-             MO_Dbl_Sinh   -> (False, FSLIT("sinh"))
-             MO_Dbl_Cosh   -> (False, FSLIT("cosh"))
-             MO_Dbl_Tanh   -> (False, FSLIT("tanh"))
-             
-             other -> pprPanic "getRegister(powerpc) - unary StMachOp" 
-                                (pprMachOp mop)
-
-
-getRegister (StMachOp mop [x, y]) -- dyadic PrimOps
-  = case mop of
-      MO_32U_Gt  -> condIntReg GTT x y
-      MO_32U_Ge  -> condIntReg GE x y
-      MO_32U_Eq  -> condIntReg EQQ x y
-      MO_32U_Ne  -> condIntReg NE x y
-      MO_32U_Lt  -> condIntReg LTT x y
-      MO_32U_Le  -> condIntReg LE x y
-
-      MO_Nat_Eq   -> condIntReg EQQ x y
-      MO_Nat_Ne   -> condIntReg NE x y
-
-      MO_NatS_Gt  -> condIntReg GTT x y
-      MO_NatS_Ge  -> condIntReg GE x y
-      MO_NatS_Lt  -> condIntReg LTT x y
-      MO_NatS_Le  -> condIntReg LE x y
-
-      MO_NatU_Gt  -> condIntReg GU  x y
-      MO_NatU_Ge  -> condIntReg GEU x y
-      MO_NatU_Lt  -> condIntReg LU  x y
-      MO_NatU_Le  -> condIntReg LEU x y
-
-      MO_Flt_Gt -> condFltReg GTT x y
-      MO_Flt_Ge -> condFltReg GE x y
-      MO_Flt_Eq -> condFltReg EQQ x y
-      MO_Flt_Ne -> condFltReg NE x y
-      MO_Flt_Lt -> condFltReg LTT x y
-      MO_Flt_Le -> condFltReg LE x y
-
-      MO_Dbl_Gt -> condFltReg GTT x y
-      MO_Dbl_Ge -> condFltReg GE x y
-      MO_Dbl_Eq -> condFltReg EQQ x y
-      MO_Dbl_Ne -> condFltReg NE x y
-      MO_Dbl_Lt -> condFltReg LTT x y
-      MO_Dbl_Le -> condFltReg LE x y
-
-      MO_Nat_Add -> trivialCode ADD x y
-      MO_Nat_Sub -> fromMaybe (trivialCode2 SUBF y x) $
-        case y of    -- subfi ('substract from' with immediate) doesn't exist
-          StInt imm -> if fits16Bits imm && imm /= (-32768)
-            then Just $ trivialCode ADD x (StInt (-imm))
-            else Nothing
-          _ -> Nothing
-
-      MO_NatS_Mul -> trivialCode MULLW x y
-      MO_NatU_Mul -> trivialCode MULLW x y
-      -- MO_NatS_MulMayOflo -> 
-
-      MO_NatS_Quot -> trivialCode2 DIVW x y
-      MO_NatU_Quot -> trivialCode2 DIVWU x y
-      
-      MO_NatS_Rem  -> remainderCode DIVW x y
-      MO_NatU_Rem  -> remainderCode DIVWU x y
-      
-      MO_Nat_And   -> trivialCode AND x y
-      MO_Nat_Or    -> trivialCode OR x y
-      MO_Nat_Xor   -> trivialCode XOR x y
-
-      MO_Nat_Shl   -> trivialCode SLW x y
-      MO_Nat_Shr   -> trivialCode SRW x y
-      MO_Nat_Sar   -> trivialCode SRAW x y
-                           
-      MO_Flt_Add   -> trivialFCode FloatRep  FADD x y
-      MO_Flt_Sub   -> trivialFCode FloatRep  FSUB x y
-      MO_Flt_Mul   -> trivialFCode FloatRep  FMUL x y
-      MO_Flt_Div   -> trivialFCode FloatRep  FDIV x y
-
-      MO_Dbl_Add   -> trivialFCode DoubleRep FADD x y
-      MO_Dbl_Sub   -> trivialFCode DoubleRep FSUB x y
-      MO_Dbl_Mul   -> trivialFCode DoubleRep FMUL x y
-      MO_Dbl_Div   -> trivialFCode DoubleRep FDIV x y
-
-      MO_Flt_Pwr  -> getRegister (StCall (Left FSLIT("pow")) CCallConv DoubleRep 
-                                         [x, y])
-      MO_Dbl_Pwr -> getRegister (StCall (Left FSLIT("pow")) CCallConv DoubleRep 
-                                        [x, y])
-       
-      other -> pprPanic "getRegister(powerpc) - binary StMachOp (1)" (pprMachOp mop)
-
-getRegister (StInd pk mem)
-  = getAmode mem                   `thenNat` \ amode ->
-    let
-       code = amodeCode amode
-       src   = amodeAddr amode
-       size = primRepToSize pk
-       code__2 dst = code `snocOL` LD size dst src
-    in
-       returnNat (Any pk code__2)
-
-getRegister (StInt i)
-  | fits16Bits i
-  = let
-       src = ImmInt (fromInteger i)
-       code dst = unitOL (LI dst src)
-    in
-       returnNat (Any IntRep code)
-
-getRegister (StFloat d)
-  = getNatLabelNCG                 `thenNat` \ lbl ->
-    getNewRegNCG PtrRep            `thenNat` \ tmp ->
-    let code dst = toOL [
-           SEGMENT RoDataSegment,
-           LABEL lbl,
-           DATA F [ImmFloat d],
-           SEGMENT TextSegment,
-           LIS tmp (HA (ImmCLbl lbl)),
-           LD F dst (AddrRegImm tmp (LO (ImmCLbl lbl)))]
-    in
-       returnNat (Any FloatRep code)
-
-getRegister (StDouble d)
-  = getNatLabelNCG                 `thenNat` \ lbl ->
-    getNewRegNCG PtrRep            `thenNat` \ tmp ->
-    let code dst = toOL [
-           SEGMENT RoDataSegment,
-           LABEL lbl,
-           DATA DF [ImmDouble d],
-           SEGMENT TextSegment,
-           LIS tmp (HA (ImmCLbl lbl)),
-           LD DF dst (AddrRegImm tmp (LO (ImmCLbl lbl)))]
-    in
-       returnNat (Any DoubleRep code)
-
-getRegister leaf
-  | maybeToBool imm
-  = let
-       code dst = toOL [
-           LIS dst (HI imm__2),
-           OR dst dst (RIImm (LO imm__2))]
-    in
-       returnNat (Any PtrRep code)
-  | otherwise
-  = ncgPrimopMoan "getRegister(powerpc)" (pprStixExpr leaf)
-  where
-    imm = maybeImm leaf
-    imm__2 = case imm of Just x -> x
-#endif /* powerpc_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{The @Amode@ type}
-%*                                                                     *
-%************************************************************************
-
-@Amode@s: Memory addressing modes passed up the tree.
-\begin{code}
-data Amode = Amode MachRegsAddr InstrBlock
-
-amodeAddr (Amode addr _) = addr
-amodeCode (Amode _ code) = code
-\end{code}
-
-Now, given a tree (the argument to an StInd) that references memory,
-produce a suitable addressing mode.
-
-A Rule of the Game (tm) for Amodes: use of the addr bit must
-immediately follow use of the code part, since the code part puts
-values in registers which the addr then refers to.  So you can't put
-anything in between, lest it overwrite some of those registers.  If
-you need to do some other computation between the code part and use of
-the addr bit, first store the effective address from the amode in a
-temporary, then do the other computation, and then use the temporary:
-
-    code
-    LEA amode, tmp
-    ... other computation ...
-    ... (tmp) ...
-
-\begin{code}
-getAmode :: StixExpr -> NatM Amode
-
-getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if alpha_TARGET_ARCH
-
-getAmode (StPrim IntSubOp [x, StInt i])
-  = getNewRegNCG PtrRep                `thenNat` \ tmp ->
-    getRegister x              `thenNat` \ register ->
-    let
-       code = registerCode register tmp
-       reg  = registerName register tmp
-       off  = ImmInt (-(fromInteger i))
-    in
-    returnNat (Amode (AddrRegImm reg off) code)
-
-getAmode (StPrim IntAddOp [x, StInt i])
-  = getNewRegNCG PtrRep                `thenNat` \ tmp ->
-    getRegister x              `thenNat` \ register ->
-    let
-       code = registerCode register tmp
-       reg  = registerName register tmp
-       off  = ImmInt (fromInteger i)
-    in
-    returnNat (Amode (AddrRegImm reg off) code)
-
-getAmode leaf
-  | maybeToBool imm
-  = returnNat (Amode (AddrImm imm__2) id)
-  where
-    imm = maybeImm leaf
-    imm__2 = case imm of Just x -> x
-
-getAmode other
-  = getNewRegNCG PtrRep                `thenNat` \ tmp ->
-    getRegister other          `thenNat` \ register ->
-    let
-       code = registerCode register tmp
-       reg  = registerName register tmp
-    in
-    returnNat (Amode (AddrReg reg) code)
-
-#endif /* alpha_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if i386_TARGET_ARCH
-
--- This is all just ridiculous, since it carefully undoes 
--- what mangleIndexTree has just done.
-getAmode (StMachOp MO_Nat_Sub [x, StInt i])
-  = getNewRegNCG PtrRep                `thenNat` \ tmp ->
-    getRegister x              `thenNat` \ register ->
-    let
-       code = registerCode register tmp
-       reg  = registerName register tmp
-       off  = ImmInt (-(fromInteger i))
-    in
-    returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
-
-getAmode (StMachOp MO_Nat_Add [x, StInt i])
-  | maybeToBool imm
-  = returnNat (Amode (ImmAddr imm__2 (fromInteger i)) nilOL)
-  where
-    imm    = maybeImm x
-    imm__2 = case imm of Just x -> x
-
-getAmode (StMachOp MO_Nat_Add [x, StInt i])
-  = getNewRegNCG PtrRep                `thenNat` \ tmp ->
-    getRegister x              `thenNat` \ register ->
-    let
-       code = registerCode register tmp
-       reg  = registerName register tmp
-       off  = ImmInt (fromInteger i)
-    in
-    returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
-
-getAmode (StMachOp MO_Nat_Add [x, StMachOp MO_Nat_Shl [y, StInt shift]])
-  | shift == 0 || shift == 1 || shift == 2 || shift == 3
-  = getNewRegNCG PtrRep                `thenNat` \ tmp1 ->
-    getNewRegNCG IntRep        `thenNat` \ tmp2 ->
-    getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    let
-       code1 = registerCode register1 tmp1
-       reg1  = registerName register1 tmp1
-       code2 = registerCode register2 tmp2
-       reg2  = registerName register2 tmp2
-       code__2 = code1 `appOL` code2
-        base = case shift of 0 -> 1 ; 1 -> 2; 2 -> 4; 3 -> 8
-    in
-    returnNat (Amode (AddrBaseIndex (Just reg1) (Just (reg2,base)) (ImmInt 0))
-               code__2)
-
-getAmode leaf
-  | maybeToBool imm
-  = returnNat (Amode (ImmAddr imm__2 0) nilOL)
-  where
-    imm    = maybeImm leaf
-    imm__2 = case imm of Just x -> x
-
-getAmode other
-  = getNewRegNCG PtrRep                `thenNat` \ tmp ->
-    getRegister other          `thenNat` \ register ->
-    let
-       code = registerCode register tmp
-       reg  = registerName register tmp
-    in
-    returnNat (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
-
-#endif /* i386_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if sparc_TARGET_ARCH
-
-getAmode (StMachOp MO_Nat_Sub [x, StInt i])
-  | fits13Bits (-i)
-  = getNewRegNCG PtrRep                `thenNat` \ tmp ->
-    getRegister x              `thenNat` \ register ->
-    let
-       code = registerCode register tmp
-       reg  = registerName register tmp
-       off  = ImmInt (-(fromInteger i))
-    in
-    returnNat (Amode (AddrRegImm reg off) code)
-
-
-getAmode (StMachOp MO_Nat_Add [x, StInt i])
-  | fits13Bits i
-  = getNewRegNCG PtrRep                `thenNat` \ tmp ->
-    getRegister x              `thenNat` \ register ->
-    let
-       code = registerCode register tmp
-       reg  = registerName register tmp
-       off  = ImmInt (fromInteger i)
-    in
-    returnNat (Amode (AddrRegImm reg off) code)
-
-getAmode (StMachOp MO_Nat_Add [x, y])
-  = getNewRegNCG PtrRep        `thenNat` \ tmp1 ->
-    getNewRegNCG IntRep        `thenNat` \ tmp2 ->
-    getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    let
-       code1 = registerCode register1 tmp1
-       reg1  = registerName register1 tmp1
-       code2 = registerCode register2 tmp2
-       reg2  = registerName register2 tmp2
-       code__2 = code1 `appOL` code2
-    in
-    returnNat (Amode (AddrRegReg reg1 reg2) code__2)
-
-getAmode leaf
-  | maybeToBool imm
-  = getNewRegNCG PtrRep            `thenNat` \ tmp ->
-    let
-       code = unitOL (SETHI (HI imm__2) tmp)
-    in
-    returnNat (Amode (AddrRegImm tmp (LO imm__2)) code)
-  where
-    imm    = maybeImm leaf
-    imm__2 = case imm of Just x -> x
-
-getAmode other
-  = getNewRegNCG PtrRep                `thenNat` \ tmp ->
-    getRegister other          `thenNat` \ register ->
-    let
-       code = registerCode register tmp
-       reg  = registerName register tmp
-       off  = ImmInt 0
-    in
-    returnNat (Amode (AddrRegImm reg off) code)
-
-#endif /* sparc_TARGET_ARCH */
-
-#ifdef powerpc_TARGET_ARCH
-getAmode (StMachOp MO_Nat_Sub [x, StInt i])
-  | fits16Bits (-i)
-  = getNewRegNCG PtrRep                `thenNat` \ tmp ->
-    getRegister x              `thenNat` \ register ->
-    let
-       code = registerCode register tmp
-       reg  = registerName register tmp
-       off  = ImmInt (-(fromInteger i))
-    in
-    returnNat (Amode (AddrRegImm reg off) code)
-
-
-getAmode (StMachOp MO_Nat_Add [x, StInt i])
-  | fits16Bits i
-  = getNewRegNCG PtrRep                `thenNat` \ tmp ->
-    getRegister x              `thenNat` \ register ->
-    let
-       code = registerCode register tmp
-       reg  = registerName register tmp
-       off  = ImmInt (fromInteger i)
-    in
-    returnNat (Amode (AddrRegImm reg off) code)
-
-getAmode leaf
-  | maybeToBool imm
-  = getNewRegNCG PtrRep            `thenNat` \ tmp ->
-    let
-       code = unitOL (LIS tmp (HA imm__2))
-    in
-    returnNat (Amode (AddrRegImm tmp (LO imm__2)) code)
-  where
-    imm    = maybeImm leaf
-    imm__2 = case imm of Just x -> x
-
-getAmode other
-  = getNewRegNCG PtrRep                `thenNat` \ tmp ->
-    getRegister other          `thenNat` \ register ->
-    let
-       code = registerCode register tmp
-       reg  = registerName register tmp
-       off  = ImmInt 0
-    in
-    returnNat (Amode (AddrRegImm reg off) code)
-#endif /* powerpc_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{The @CondCode@ type}
-%*                                                                     *
-%************************************************************************
-
-Condition codes passed up the tree.
-\begin{code}
-data CondCode = CondCode Bool Cond InstrBlock
-
-condName  (CondCode _ cond _)    = cond
-condFloat (CondCode is_float _ _) = is_float
-condCode  (CondCode _ _ code)    = code
-\end{code}
-
-Set up a condition code for a conditional branch.
-
-\begin{code}
-getCondCode :: StixExpr -> NatM CondCode
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if alpha_TARGET_ARCH
-getCondCode = panic "MachCode.getCondCode: not on Alphas"
-#endif /* alpha_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if i386_TARGET_ARCH || sparc_TARGET_ARCH || powerpc_TARGET_ARCH
--- yes, they really do seem to want exactly the same!
-
-getCondCode (StMachOp mop [x, y])
-  = case mop of
-      MO_32U_Gt -> condIntCode GTT  x y
-      MO_32U_Ge -> condIntCode GE   x y
-      MO_32U_Eq -> condIntCode EQQ  x y
-      MO_32U_Ne -> condIntCode NE   x y
-      MO_32U_Lt -> condIntCode LTT  x y
-      MO_32U_Le -> condIntCode LE   x y
-      MO_Nat_Eq  -> condIntCode EQQ  x y
-      MO_Nat_Ne  -> condIntCode NE   x y
-
-      MO_NatS_Gt -> condIntCode GTT  x y
-      MO_NatS_Ge -> condIntCode GE   x y
-      MO_NatS_Lt -> condIntCode LTT  x y
-      MO_NatS_Le -> condIntCode LE   x y
-
-      MO_NatU_Gt -> condIntCode GU   x y
-      MO_NatU_Ge -> condIntCode GEU  x y
-      MO_NatU_Lt -> condIntCode LU   x y
-      MO_NatU_Le -> condIntCode LEU  x y
-
-      MO_Flt_Gt -> condFltCode GTT x y
-      MO_Flt_Ge -> condFltCode GE  x y
-      MO_Flt_Eq -> condFltCode EQQ x y
-      MO_Flt_Ne -> condFltCode NE  x y
-      MO_Flt_Lt -> condFltCode LTT x y
-      MO_Flt_Le -> condFltCode LE  x y
-
-      MO_Dbl_Gt -> condFltCode GTT x y
-      MO_Dbl_Ge -> condFltCode GE  x y
-      MO_Dbl_Eq -> condFltCode EQQ x y
-      MO_Dbl_Ne -> condFltCode NE  x y
-      MO_Dbl_Lt -> condFltCode LTT x y
-      MO_Dbl_Le -> condFltCode LE  x y
-
-      other -> pprPanic "getCondCode(x86,sparc,powerpc)" (pprMachOp mop)
-
-getCondCode other =  pprPanic "getCondCode(2)(x86,sparc,powerpc)" (pprStixExpr other)
-
-#endif /* i386_TARGET_ARCH || sparc_TARGET_ARCH || powerpc_TARGET_ARCH */
-
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-\end{code}
-
-% -----------------
-
-@cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
-passed back up the tree.
-
-\begin{code}
-condIntCode, condFltCode :: Cond -> StixExpr -> StixExpr -> NatM CondCode
-
-#if alpha_TARGET_ARCH
-condIntCode = panic "MachCode.condIntCode: not on Alphas"
-condFltCode = panic "MachCode.condFltCode: not on Alphas"
-#endif /* alpha_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-#if i386_TARGET_ARCH
-
--- memory vs immediate
-condIntCode cond (StInd pk x) y
-  | Just i <- maybeImm y
-  = getAmode x                 `thenNat` \ amode ->
-    let
-       code1 = amodeCode amode
-       x__2  = amodeAddr amode
-        sz    = primRepToSize pk
-       code__2 = code1 `snocOL`
-                 CMP sz (OpImm i) (OpAddr x__2)
-    in
-    returnNat (CondCode False cond code__2)
-
--- anything vs zero
-condIntCode cond x (StInt 0)
-  = getRegister x              `thenNat` \ register1 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp1 ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-       code__2 = code1 `snocOL`
-                 TEST L (OpReg src1) (OpReg src1)
-    in
-    returnNat (CondCode False cond code__2)
-
--- anything vs immediate
-condIntCode cond x y
-  | Just i <- maybeImm y
-  = getRegister x              `thenNat` \ register1 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp1 ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-       code__2 = code1 `snocOL`
-                  CMP L (OpImm i) (OpReg src1)
-    in
-    returnNat (CondCode False cond code__2)
-
--- memory vs anything
-condIntCode cond (StInd pk x) y
-  = getAmode x                 `thenNat` \ amode_x ->
-    getRegister y              `thenNat` \ reg_y ->
-    getNewRegNCG IntRep                `thenNat` \ tmp ->
-    let
-       c_x   = amodeCode amode_x
-       am_x  = amodeAddr amode_x
-       c_y   = registerCode reg_y tmp
-       r_y   = registerName reg_y tmp
-        sz    = primRepToSize pk
-
-        -- optimisation: if there's no code for x, just an amode,
-        -- use whatever reg y winds up in.  Assumes that c_y doesn't
-        -- clobber any regs in the amode am_x, which I'm not sure is
-        -- justified.  The otherwise clause makes the same assumption.
-       code__2 | isNilOL c_x 
-                = c_y `snocOL`
-                  CMP sz (OpReg r_y) (OpAddr am_x)
-
-                | otherwise
-                = c_y `snocOL` 
-                  MOV L (OpReg r_y) (OpReg tmp) `appOL`
-                  c_x `snocOL`
-                 CMP sz (OpReg tmp) (OpAddr am_x)
-    in
-    returnNat (CondCode False cond code__2)
-
--- anything vs memory
--- 
-condIntCode cond y (StInd pk x)
-  = getAmode x                 `thenNat` \ amode_x ->
-    getRegister y              `thenNat` \ reg_y ->
-    getNewRegNCG IntRep                `thenNat` \ tmp ->
-    let
-       c_x   = amodeCode amode_x
-       am_x  = amodeAddr amode_x
-       c_y   = registerCode reg_y tmp
-       r_y   = registerName reg_y tmp
-        sz    = primRepToSize pk
-        -- same optimisation and nagging doubts as previous clause
-       code__2 | isNilOL c_x
-                = c_y `snocOL`
-                  CMP sz (OpAddr am_x) (OpReg r_y)
-
-                | otherwise
-                = c_y `snocOL` 
-                  MOV L (OpReg r_y) (OpReg tmp) `appOL`
-                  c_x `snocOL`
-                 CMP sz (OpAddr am_x) (OpReg tmp)
-    in
-    returnNat (CondCode False cond code__2)
-
--- anything vs anything
-condIntCode cond x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp1 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp2 ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-       code__2 = code1 `snocOL`
-                  MOV L (OpReg src1) (OpReg tmp1) `appOL`
-                  code2 `snocOL`
-                 CMP L (OpReg src2) (OpReg tmp1)
-    in
-    returnNat (CondCode False cond code__2)
-
------------
-condFltCode cond x y
-  = ASSERT(cond `elem` ([EQQ, NE, LE, LTT, GE, GTT]))
-    getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG (registerRep register1)
-                               `thenNat` \ tmp1 ->
-    getNewRegNCG (registerRep register2)
-                               `thenNat` \ tmp2 ->
-    getNewRegNCG DoubleRep     `thenNat` \ tmp ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-
-       code__2 | isAny register1
-                = code1 `appOL`   -- result in tmp1
-                  code2 `snocOL`
-                 GCMP cond tmp1 src2
-                  
-                | otherwise
-                = code1 `snocOL` 
-                  GMOV src1 tmp1 `appOL`
-                  code2 `snocOL`
-                 GCMP cond tmp1 src2
-    in
-    -- The GCMP insn does the test and sets the zero flag if comparable
-    -- and true.  Hence we always supply EQQ as the condition to test.
-    returnNat (CondCode True EQQ code__2)
-
-#endif /* i386_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if sparc_TARGET_ARCH
-
-condIntCode cond x (StInt y)
-  | fits13Bits y
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG IntRep                `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src1 = registerName register tmp
-       src2 = ImmInt (fromInteger y)
-       code__2 = code `snocOL` SUB False True src1 (RIImm src2) g0
-    in
-    returnNat (CondCode False cond code__2)
-
-condIntCode cond x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp1 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp2 ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-       code__2 = code1 `appOL` code2 `snocOL`
-                 SUB False True src1 (RIReg src2) g0
-    in
-    returnNat (CondCode False cond code__2)
-
------------
-condFltCode cond x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG (registerRep register1)
-                               `thenNat` \ tmp1 ->
-    getNewRegNCG (registerRep register2)
-                               `thenNat` \ tmp2 ->
-    getNewRegNCG DoubleRep     `thenNat` \ tmp ->
-    let
-       promote x = FxTOy F DF x tmp
-
-       pk1   = registerRep register1
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-
-       pk2   = registerRep register2
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-
-       code__2 =
-               if pk1 == pk2 then
-                   code1 `appOL` code2 `snocOL`
-                   FCMP True (primRepToSize pk1) src1 src2
-               else if pk1 == FloatRep then
-                   code1 `snocOL` promote src1 `appOL` code2 `snocOL`
-                   FCMP True DF tmp src2
-               else
-                   code1 `appOL` code2 `snocOL` promote src2 `snocOL`
-                   FCMP True DF src1 tmp
-    in
-    returnNat (CondCode True cond code__2)
-
-#endif /* sparc_TARGET_ARCH */
-
-#if powerpc_TARGET_ARCH
-
-condIntCode cond x (StInt y)
-  | fits16Bits y
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG IntRep                `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src1 = registerName register tmp
-       src2 = ImmInt (fromInteger y)
-       code__2 = code `snocOL` 
-           (if condUnsigned cond then CMPL else CMP) W src1 (RIImm src2)
-    in
-    returnNat (CondCode False cond code__2)
-
-condIntCode cond x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp1 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp2 ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-       code__2 = code1 `appOL` code2 `snocOL`
-                 (if condUnsigned cond then CMPL else CMP) W src1 (RIReg src2)
-    in
-    returnNat (CondCode False cond code__2)
-
-condFltCode cond x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG (registerRep register1)
-                               `thenNat` \ tmp1 ->
-    getNewRegNCG (registerRep register2)
-                               `thenNat` \ tmp2 ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-       code__2 = code1 `appOL` code2 `snocOL`
-                 FCMP src1 src2
-    in
-    returnNat (CondCode False cond code__2)
-
-#endif /* powerpc_TARGET_ARCH */
-
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{Generating assignments}
-%*                                                                     *
-%************************************************************************
-
-Assignments are really at the heart of the whole code generation
-business.  Almost all top-level nodes of any real importance are
-assignments, which correspond to loads, stores, or register transfers.
-If we're really lucky, some of the register transfers will go away,
-because we can use the destination register to complete the code
-generation for the right hand side.  This only fails when the right
-hand side is forced into a fixed register (e.g. the result of a call).
-
-\begin{code}
-assignMem_IntCode :: PrimRep -> StixExpr -> StixExpr -> NatM InstrBlock
-assignReg_IntCode :: PrimRep -> StixReg  -> StixExpr -> NatM InstrBlock
-
-assignMem_FltCode :: PrimRep -> StixExpr -> StixExpr -> NatM InstrBlock
-assignReg_FltCode :: PrimRep -> StixReg  -> StixExpr -> NatM InstrBlock
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if alpha_TARGET_ARCH
-
-assignIntCode pk (StInd _ dst) src
-  = getNewRegNCG IntRep            `thenNat` \ tmp ->
-    getAmode dst                   `thenNat` \ amode ->
-    getRegister src                `thenNat` \ register ->
-    let
-       code1   = amodeCode amode []
-       dst__2  = amodeAddr amode
-       code2   = registerCode register tmp []
-       src__2  = registerName register tmp
-       sz      = primRepToSize pk
-       code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
-    in
-    returnNat code__2
-
-assignIntCode pk dst src
-  = getRegister dst                        `thenNat` \ register1 ->
-    getRegister src                        `thenNat` \ register2 ->
-    let
-       dst__2  = registerName register1 zeroh
-       code    = registerCode register2 dst__2
-       src__2  = registerName register2 dst__2
-       code__2 = if isFixed register2
-                 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
-                 else code
-    in
-    returnNat code__2
-
-#endif /* alpha_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if i386_TARGET_ARCH
-
--- non-FP assignment to memory
-assignMem_IntCode pk addr src
-  = getAmode addr              `thenNat` \ amode ->
-    get_op_RI src              `thenNat` \ (codesrc, opsrc) ->
-    getNewRegNCG PtrRep         `thenNat` \ tmp ->
-    let
-        -- In general, if the address computation for dst may require
-        -- some insns preceding the addressing mode itself.  So there's
-        -- no guarantee that the code for dst and the code for src won't
-        -- write the same register.  This means either the address or 
-        -- the value needs to be copied into a temporary.  We detect the
-        -- common case where the amode has no code, and elide the copy.
-       codea   = amodeCode amode
-       dst__a  = amodeAddr amode
-
-       code    | isNilOL codea
-                = codesrc `snocOL`
-                 MOV (primRepToSize pk) opsrc (OpAddr dst__a)
-                | otherwise
-                = codea `snocOL` 
-                  LEA L (OpAddr dst__a) (OpReg tmp) `appOL`
-                  codesrc `snocOL`
-                  MOV (primRepToSize pk) opsrc 
-                      (OpAddr (AddrBaseIndex (Just tmp) Nothing (ImmInt 0)))
-    in
-    returnNat code
-  where
-    get_op_RI
-       :: StixExpr
-       -> NatM (InstrBlock,Operand)    -- code, operator
-
-    get_op_RI op
-      | Just x <- maybeImm op
-      = returnNat (nilOL, OpImm x)
-
-    get_op_RI op
-      = getRegister op                 `thenNat` \ register ->
-       getNewRegNCG (registerRep register)
-                                       `thenNat` \ tmp ->
-       let code = registerCode register tmp
-           reg  = registerName register tmp
-       in
-       returnNat (code, OpReg reg)
-
--- Assign; dst is a reg, rhs is mem
-assignReg_IntCode pk reg (StInd pks src)
-  = getNewRegNCG PtrRep            `thenNat` \ tmp ->
-    getAmode src                   `thenNat` \ amode ->
-    getRegisterReg reg             `thenNat` \ reg_dst ->
-    let
-       c_addr  = amodeCode amode
-       am_addr = amodeAddr amode
-       r_dst = registerName reg_dst tmp
-       szs   = primRepToSize pks
-        opc   = case szs of
-            B  -> MOVSxL B
-            Bu -> MOVZxL Bu
-            W  -> MOVSxL W
-            Wu -> MOVZxL Wu
-            L  -> MOV L
-            Lu -> MOV L
-
-       code  = c_addr `snocOL`
-                opc (OpAddr am_addr) (OpReg r_dst)
-    in
-    returnNat code
-
--- dst is a reg, but src could be anything
-assignReg_IntCode pk reg src
-  = getRegisterReg reg             `thenNat` \ registerd ->
-    getRegister src                `thenNat` \ registers ->
-    getNewRegNCG IntRep            `thenNat` \ tmp ->
-    let 
-        r_dst = registerName registerd tmp
-        r_src = registerName registers r_dst
-        c_src = registerCode registers r_dst
-         
-        code = c_src `snocOL` 
-               MOV L (OpReg r_src) (OpReg r_dst)
-    in
-    returnNat code
-
-#endif /* i386_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if sparc_TARGET_ARCH
-
-assignMem_IntCode pk addr src
-  = getNewRegNCG IntRep                    `thenNat` \ tmp ->
-    getAmode addr                          `thenNat` \ amode ->
-    getRegister src                        `thenNat` \ register ->
-    let
-       code1   = amodeCode amode
-       dst__2  = amodeAddr amode
-       code2   = registerCode register tmp
-       src__2  = registerName register tmp
-       sz      = primRepToSize pk
-       code__2 = code1 `appOL` code2 `snocOL` ST sz src__2 dst__2
-    in
-    returnNat code__2
-
-assignReg_IntCode pk reg src
-  = getRegister src                        `thenNat` \ register2 ->
-    getRegisterReg reg                     `thenNat` \ register1 ->
-    getNewRegNCG IntRep                    `thenNat` \ tmp ->
-    let
-       dst__2  = registerName register1 tmp
-       code    = registerCode register2 dst__2
-       src__2  = registerName register2 dst__2
-       code__2 = if isFixed register2
-                 then code `snocOL` OR False g0 (RIReg src__2) dst__2
-                 else code
-    in
-    returnNat code__2
-
-#endif /* sparc_TARGET_ARCH */
-
-#if powerpc_TARGET_ARCH
-
-assignMem_IntCode pk addr src
-  = getNewRegNCG IntRep                    `thenNat` \ tmp ->
-    getAmode addr                          `thenNat` \ amode ->
-    getRegister src                        `thenNat` \ register ->
-    let
-       code1   = amodeCode amode
-       dst__2  = amodeAddr amode
-       code2   = registerCode register tmp
-       src__2  = registerName register tmp
-       sz      = primRepToSize pk
-       code__2 = code1 `appOL` code2 `snocOL` ST sz src__2 dst__2
-    in
-    returnNat code__2
-
-assignReg_IntCode pk reg src
-  = getRegister src                        `thenNat` \ register2 ->
-    getRegisterReg reg                     `thenNat` \ register1 ->
-    let
-       dst__2  = registerName register1 (panic "###PPC where are we assigning this int???")
-       code    = registerCode register2 dst__2
-       src__2  = registerName register2 dst__2
-       code__2 = if isFixed register2
-                 then code `snocOL` MR dst__2 src__2
-                 else code
-    in
-    returnNat code__2
-
-#endif /* powerpc_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-\end{code}
-
-% --------------------------------
-Floating-point assignments:
-% --------------------------------
-
-\begin{code}
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-#if alpha_TARGET_ARCH
-
-assignFltCode pk (StInd _ dst) src
-  = getNewRegNCG pk                `thenNat` \ tmp ->
-    getAmode dst                   `thenNat` \ amode ->
-    getRegister src                        `thenNat` \ register ->
-    let
-       code1   = amodeCode amode []
-       dst__2  = amodeAddr amode
-       code2   = registerCode register tmp []
-       src__2  = registerName register tmp
-       sz      = primRepToSize pk
-       code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
-    in
-    returnNat code__2
-
-assignFltCode pk dst src
-  = getRegister dst                        `thenNat` \ register1 ->
-    getRegister src                        `thenNat` \ register2 ->
-    let
-       dst__2  = registerName register1 zeroh
-       code    = registerCode register2 dst__2
-       src__2  = registerName register2 dst__2
-       code__2 = if isFixed register2
-                 then code . mkSeqInstr (FMOV src__2 dst__2)
-                 else code
-    in
-    returnNat code__2
-
-#endif /* alpha_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if i386_TARGET_ARCH
-
--- Floating point assignment to memory
-assignMem_FltCode pk addr src
-   = getRegister src      `thenNat`  \ reg_src  ->
-     getRegister addr     `thenNat`  \ reg_addr ->
-     getNewRegNCG pk      `thenNat`  \ tmp_src  ->
-     getNewRegNCG PtrRep  `thenNat`  \ tmp_addr ->
-     let r_src  = registerName reg_src tmp_src
-         c_src  = registerCode reg_src tmp_src
-         r_addr = registerName reg_addr tmp_addr
-         c_addr = registerCode reg_addr tmp_addr
-         sz     = primRepToSize pk
-
-         code = c_src  `appOL`
-                -- no need to preserve r_src across the addr computation,
-                -- since r_src must be a float reg 
-                -- whilst r_addr is an int reg
-                c_addr `snocOL`
-                GST sz r_src 
-                       (AddrBaseIndex (Just r_addr) Nothing (ImmInt 0))
-     in
-     returnNat code
-
--- Floating point assignment to a register/temporary
-assignReg_FltCode pk reg src
-  = getRegisterReg reg             `thenNat` \ reg_dst ->
-    getRegister src                `thenNat` \ reg_src ->
-    getNewRegNCG pk                 `thenNat` \ tmp ->
-    let
-       r_dst = registerName reg_dst tmp
-       r_src = registerName reg_src r_dst
-       c_src = registerCode reg_src r_dst
-
-       code = if   isFixed reg_src
-               then c_src `snocOL` GMOV r_src r_dst
-               else c_src
-    in
-    returnNat code
-
-
-#endif /* i386_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if sparc_TARGET_ARCH
-
--- Floating point assignment to memory
-assignMem_FltCode pk addr src
-  = getNewRegNCG pk                `thenNat` \ tmp1 ->
-    getAmode addr                  `thenNat` \ amode ->
-    getRegister src                `thenNat` \ register ->
-    let
-       sz      = primRepToSize pk
-       dst__2  = amodeAddr amode
-
-       code1   = amodeCode amode
-       code2   = registerCode register tmp1
-
-       src__2  = registerName register tmp1
-       pk__2   = registerRep register
-       sz__2   = primRepToSize pk__2
-
-       code__2 = code1 `appOL` code2 `appOL`
-           if   pk == pk__2 
-            then unitOL (ST sz src__2 dst__2)
-           else toOL [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
-    in
-    returnNat code__2
-
--- Floating point assignment to a register/temporary
--- Why is this so bizarrely ugly?
-assignReg_FltCode pk reg src
-  = getRegisterReg reg                     `thenNat` \ register1 ->
-    getRegister src                        `thenNat` \ register2 ->
-    let 
-        pk__2   = registerRep register2 
-        sz__2   = primRepToSize pk__2
-    in
-    getNewRegNCG pk__2                      `thenNat` \ tmp ->
-    let
-       sz      = primRepToSize pk
-       dst__2  = registerName register1 g0    -- must be Fixed
-       reg__2  = if pk /= pk__2 then tmp else dst__2
-       code    = registerCode register2 reg__2
-       src__2  = registerName register2 reg__2
-       code__2 = 
-               if pk /= pk__2 then
-                    code `snocOL` FxTOy sz__2 sz src__2 dst__2
-               else if isFixed register2 then
-                    code `snocOL` FMOV sz src__2 dst__2
-               else
-                    code
-    in
-    returnNat code__2
-
-#endif /* sparc_TARGET_ARCH */
-
-#if powerpc_TARGET_ARCH
-
--- Floating point assignment to memory
-assignMem_FltCode pk addr src
-  = getNewRegNCG pk                `thenNat` \ tmp1 ->
-    getAmode addr                  `thenNat` \ amode ->
-    getRegister src                `thenNat` \ register ->
-    let
-       sz      = primRepToSize pk
-       dst__2  = amodeAddr amode
-
-       code1   = amodeCode amode
-       code2   = registerCode register tmp1
-
-       src__2  = registerName register tmp1
-       pk__2   = registerRep register
-
-       code__2 = code1 `appOL` code2 `snocOL` ST sz src__2 dst__2
-    in
-    returnNat code__2
-
--- Floating point assignment to a register/temporary
-assignReg_FltCode pk reg src
-  = getRegisterReg reg             `thenNat` \ reg_dst ->
-    getRegister src                `thenNat` \ reg_src ->
-    getNewRegNCG pk                 `thenNat` \ tmp ->
-    let
-       r_dst = registerName reg_dst tmp
-       r_src = registerName reg_src r_dst
-       c_src = registerCode reg_src r_dst
-
-       code = if   isFixed reg_src
-               then c_src `snocOL` MR r_dst r_src
-               else c_src
-    in
-    returnNat code
-#endif /* powerpc_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{Generating an unconditional branch}
-%*                                                                     *
-%************************************************************************
-
-We accept two types of targets: an immediate CLabel or a tree that
-gets evaluated into a register.  Any CLabels which are AsmTemporaries
-are assumed to be in the local block of code, close enough for a
-branch instruction.  Other CLabels are assumed to be far away.
-
-(If applicable) Do not fill the delay slots here; you will confuse the
-register allocator.
-
-\begin{code}
-genJump :: DestInfo -> StixExpr{-the branch target-} -> NatM InstrBlock
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if alpha_TARGET_ARCH
-
-genJump (StCLbl lbl)
-  | isAsmTemp lbl = returnInstr (BR target)
-  | otherwise     = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
-  where
-    target = ImmCLbl lbl
-
-genJump tree
-  = getRegister tree               `thenNat` \ register ->
-    getNewRegNCG PtrRep            `thenNat` \ tmp ->
-    let
-       dst    = registerName register pv
-       code   = registerCode register pv
-       target = registerName register pv
-    in
-    if isFixed register then
-       returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
-    else
-    returnNat (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
-
-#endif /* alpha_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if i386_TARGET_ARCH
-
-genJump dsts (StInd pk mem)
-  = getAmode mem                   `thenNat` \ amode ->
-    let
-       code   = amodeCode amode
-       target = amodeAddr amode
-    in
-    returnNat (code `snocOL` JMP dsts (OpAddr target))
-
-genJump dsts tree
-  | maybeToBool imm
-  = returnNat (unitOL (JMP dsts (OpImm target)))
-
-  | otherwise
-  = getRegister tree               `thenNat` \ register ->
-    getNewRegNCG PtrRep            `thenNat` \ tmp ->
-    let
-       code   = registerCode register tmp
-       target = registerName register tmp
-    in
-    returnNat (code `snocOL` JMP dsts (OpReg target))
-  where
-    imm    = maybeImm tree
-    target = case imm of Just x -> x
-
-#endif /* i386_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if sparc_TARGET_ARCH
-
-genJump dsts (StCLbl lbl)
-  | hasDestInfo dsts = panic "genJump(sparc): CLbl and dsts"
-  | isAsmTemp lbl    = returnNat (toOL [BI ALWAYS False target, NOP])
-  | otherwise        = returnNat (toOL [CALL (Left target) 0 True, NOP])
-  where
-    target = ImmCLbl lbl
-
-genJump dsts tree
-  = getRegister tree                       `thenNat` \ register ->
-    getNewRegNCG PtrRep            `thenNat` \ tmp ->
-    let
-       code   = registerCode register tmp
-       target = registerName register tmp
-    in
-    returnNat (code `snocOL` JMP dsts (AddrRegReg target g0) `snocOL` NOP)
-
-#endif /* sparc_TARGET_ARCH */
-
-#if powerpc_TARGET_ARCH
-genJump dsts (StCLbl lbl)
-  | hasDestInfo dsts = panic "genJump(powerpc): CLbl and dsts"
-  | otherwise        = returnNat (toOL [BCC ALWAYS lbl])
-
-genJump dsts tree
-  = getRegister tree                       `thenNat` \ register ->
-    getNewRegNCG PtrRep            `thenNat` \ tmp ->
-    let
-       code   = registerCode register tmp
-       target = registerName register tmp
-    in
-    returnNat (code `snocOL` MTCTR target `snocOL` BCTR dsts)
-#endif /* sparc_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{Conditional jumps}
-%*                                                                     *
-%************************************************************************
-
-Conditional jumps are always to local labels, so we can use branch
-instructions.  We peek at the arguments to decide what kind of
-comparison to do.
-
-ALPHA: For comparisons with 0, we're laughing, because we can just do
-the desired conditional branch.
-
-I386: First, we have to ensure that the condition
-codes are set according to the supplied comparison operation.
-
-SPARC: First, we have to ensure that the condition codes are set
-according to the supplied comparison operation.  We generate slightly
-different code for floating point comparisons, because a floating
-point operation cannot directly precede a @BF@.  We assume the worst
-and fill that slot with a @NOP@.
-
-SPARC: Do not fill the delay slots here; you will confuse the register
-allocator.
-
-\begin{code}
-genCondJump
-    :: CLabel      -- the branch target
-    -> StixExpr     -- the condition on which to branch
-    -> NatM InstrBlock
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if alpha_TARGET_ARCH
-
-genCondJump lbl (StPrim op [x, StInt 0])
-  = getRegister x                          `thenNat` \ register ->
-    getNewRegNCG (registerRep register)
-                                   `thenNat` \ tmp ->
-    let
-       code   = registerCode register tmp
-       value  = registerName register tmp
-       pk     = registerRep register
-       target = ImmCLbl lbl
-    in
-    returnSeq code [BI (cmpOp op) value target]
-  where
-    cmpOp CharGtOp = GTT
-    cmpOp CharGeOp = GE
-    cmpOp CharEqOp = EQQ
-    cmpOp CharNeOp = NE
-    cmpOp CharLtOp = LTT
-    cmpOp CharLeOp = LE
-    cmpOp IntGtOp = GTT
-    cmpOp IntGeOp = GE
-    cmpOp IntEqOp = EQQ
-    cmpOp IntNeOp = NE
-    cmpOp IntLtOp = LTT
-    cmpOp IntLeOp = LE
-    cmpOp WordGtOp = NE
-    cmpOp WordGeOp = ALWAYS
-    cmpOp WordEqOp = EQQ
-    cmpOp WordNeOp = NE
-    cmpOp WordLtOp = NEVER
-    cmpOp WordLeOp = EQQ
-    cmpOp AddrGtOp = NE
-    cmpOp AddrGeOp = ALWAYS
-    cmpOp AddrEqOp = EQQ
-    cmpOp AddrNeOp = NE
-    cmpOp AddrLtOp = NEVER
-    cmpOp AddrLeOp = EQQ
-
-genCondJump lbl (StPrim op [x, StDouble 0.0])
-  = getRegister x                          `thenNat` \ register ->
-    getNewRegNCG (registerRep register)
-                                   `thenNat` \ tmp ->
-    let
-       code   = registerCode register tmp
-       value  = registerName register tmp
-       pk     = registerRep register
-       target = ImmCLbl lbl
-    in
-    returnNat (code . mkSeqInstr (BF (cmpOp op) value target))
-  where
-    cmpOp FloatGtOp = GTT
-    cmpOp FloatGeOp = GE
-    cmpOp FloatEqOp = EQQ
-    cmpOp FloatNeOp = NE
-    cmpOp FloatLtOp = LTT
-    cmpOp FloatLeOp = LE
-    cmpOp DoubleGtOp = GTT
-    cmpOp DoubleGeOp = GE
-    cmpOp DoubleEqOp = EQQ
-    cmpOp DoubleNeOp = NE
-    cmpOp DoubleLtOp = LTT
-    cmpOp DoubleLeOp = LE
-
-genCondJump lbl (StPrim op [x, y])
-  | fltCmpOp op
-  = trivialFCode pr instr x y      `thenNat` \ register ->
-    getNewRegNCG DoubleRep         `thenNat` \ tmp ->
-    let
-       code   = registerCode register tmp
-       result = registerName register tmp
-       target = ImmCLbl lbl
-    in
-    returnNat (code . mkSeqInstr (BF cond result target))
-  where
-    pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
-
-    fltCmpOp op = case op of
-       FloatGtOp -> True
-       FloatGeOp -> True
-       FloatEqOp -> True
-       FloatNeOp -> True
-       FloatLtOp -> True
-       FloatLeOp -> True
-       DoubleGtOp -> True
-       DoubleGeOp -> True
-       DoubleEqOp -> True
-       DoubleNeOp -> True
-       DoubleLtOp -> True
-       DoubleLeOp -> True
-       _ -> False
-    (instr, cond) = case op of
-       FloatGtOp -> (FCMP TF LE, EQQ)
-       FloatGeOp -> (FCMP TF LTT, EQQ)
-       FloatEqOp -> (FCMP TF EQQ, NE)
-       FloatNeOp -> (FCMP TF EQQ, EQQ)
-       FloatLtOp -> (FCMP TF LTT, NE)
-       FloatLeOp -> (FCMP TF LE, NE)
-       DoubleGtOp -> (FCMP TF LE, EQQ)
-       DoubleGeOp -> (FCMP TF LTT, EQQ)
-       DoubleEqOp -> (FCMP TF EQQ, NE)
-       DoubleNeOp -> (FCMP TF EQQ, EQQ)
-       DoubleLtOp -> (FCMP TF LTT, NE)
-       DoubleLeOp -> (FCMP TF LE, NE)
-
-genCondJump lbl (StPrim op [x, y])
-  = trivialCode instr x y          `thenNat` \ register ->
-    getNewRegNCG IntRep            `thenNat` \ tmp ->
-    let
-       code   = registerCode register tmp
-       result = registerName register tmp
-       target = ImmCLbl lbl
-    in
-    returnNat (code . mkSeqInstr (BI cond result target))
-  where
-    (instr, cond) = case op of
-       CharGtOp -> (CMP LE, EQQ)
-       CharGeOp -> (CMP LTT, EQQ)
-       CharEqOp -> (CMP EQQ, NE)
-       CharNeOp -> (CMP EQQ, EQQ)
-       CharLtOp -> (CMP LTT, NE)
-       CharLeOp -> (CMP LE, NE)
-       IntGtOp -> (CMP LE, EQQ)
-       IntGeOp -> (CMP LTT, EQQ)
-       IntEqOp -> (CMP EQQ, NE)
-       IntNeOp -> (CMP EQQ, EQQ)
-       IntLtOp -> (CMP LTT, NE)
-       IntLeOp -> (CMP LE, NE)
-       WordGtOp -> (CMP ULE, EQQ)
-       WordGeOp -> (CMP ULT, EQQ)
-       WordEqOp -> (CMP EQQ, NE)
-       WordNeOp -> (CMP EQQ, EQQ)
-       WordLtOp -> (CMP ULT, NE)
-       WordLeOp -> (CMP ULE, NE)
-       AddrGtOp -> (CMP ULE, EQQ)
-       AddrGeOp -> (CMP ULT, EQQ)
-       AddrEqOp -> (CMP EQQ, NE)
-       AddrNeOp -> (CMP EQQ, EQQ)
-       AddrLtOp -> (CMP ULT, NE)
-       AddrLeOp -> (CMP ULE, NE)
-
-#endif /* alpha_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if i386_TARGET_ARCH
-
-genCondJump lbl bool
-  = getCondCode bool               `thenNat` \ condition ->
-    let
-       code   = condCode condition
-       cond   = condName condition
-    in
-    returnNat (code `snocOL` JXX cond lbl)
-
-#endif /* i386_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if sparc_TARGET_ARCH
-
-genCondJump lbl bool
-  = getCondCode bool               `thenNat` \ condition ->
-    let
-       code   = condCode condition
-       cond   = condName condition
-       target = ImmCLbl lbl
-    in
-    returnNat (
-       code `appOL` 
-       toOL (
-         if   condFloat condition 
-         then [NOP, BF cond False target, NOP]
-         else [BI cond False target, NOP]
-       )
-    )
-
-#endif /* sparc_TARGET_ARCH */
-
-#if powerpc_TARGET_ARCH
-
-genCondJump lbl bool
-  = getCondCode bool               `thenNat` \ condition ->
-    let
-       code   = condCode condition
-       cond   = condName condition
-       target = ImmCLbl lbl
-    in
-    returnNat (
-       code `snocOL` BCC cond lbl    )
-
-#endif /* powerpc_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{Generating C calls}
-%*                                                                     *
-%************************************************************************
-
-Now the biggest nightmare---calls.  Most of the nastiness is buried in
-@get_arg@, which moves the arguments to the correct registers/stack
-locations.  Apart from that, the code is easy.
-
-(If applicable) Do not fill the delay slots here; you will confuse the
-register allocator.
-
-\begin{code}
-genCCall
-    :: (Either FastString StixExpr)    -- function to call
-    -> CCallConv
-    -> PrimRep         -- type of the result
-    -> [StixExpr]      -- arguments (of mixed type)
-    -> NatM InstrBlock
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if alpha_TARGET_ARCH
-
-genCCall fn cconv kind args
-  = mapAccumLNat get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
-                         `thenNat` \ ((unused,_), argCode) ->
-    let
-       nRegs = length allArgRegs - length unused
-       code = asmSeqThen (map ($ []) argCode)
-    in
-       returnSeq code [
-           LDA pv (AddrImm (ImmLab (ptext fn))),
-           JSR ra (AddrReg pv) nRegs,
-           LDGP gp (AddrReg ra)]
-  where
-    ------------------------
-    {- Try to get a value into a specific register (or registers) for
-       a call.  The first 6 arguments go into the appropriate
-       argument register (separate registers for integer and floating
-       point arguments, but used in lock-step), and the remaining
-       arguments are dumped to the stack, beginning at 0(sp).  Our
-       first argument is a pair of the list of remaining argument
-       registers to be assigned for this call and the next stack
-       offset to use for overflowing arguments.  This way,
-       @get_Arg@ can be applied to all of a call's arguments using
-       @mapAccumLNat@.
-    -}
-    get_arg
-       :: ([(Reg,Reg)], Int)   -- Argument registers and stack offset (accumulator)
-       -> StixTree             -- Current argument
-       -> NatM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
-
-    -- We have to use up all of our argument registers first...
-
-    get_arg ((iDst,fDst):dsts, offset) arg
-      = getRegister arg                            `thenNat` \ register ->
-       let
-           reg  = if isFloatingRep pk then fDst else iDst
-           code = registerCode register reg
-           src  = registerName register reg
-           pk   = registerRep register
-       in
-       returnNat (
-           if isFloatingRep pk then
-               ((dsts, offset), if isFixed register then
-                   code . mkSeqInstr (FMOV src fDst)
-                   else code)
-           else
-               ((dsts, offset), if isFixed register then
-                   code . mkSeqInstr (OR src (RIReg src) iDst)
-                   else code))
-
-    -- Once we have run out of argument registers, we move to the
-    -- stack...
-
-    get_arg ([], offset) arg
-      = getRegister arg                        `thenNat` \ register ->
-       getNewRegNCG (registerRep register)
-                                       `thenNat` \ tmp ->
-       let
-           code = registerCode register tmp
-           src  = registerName register tmp
-           pk   = registerRep register
-           sz   = primRepToSize pk
-       in
-       returnNat (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
-
-#endif /* alpha_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if i386_TARGET_ARCH
-
-genCCall fn cconv ret_rep args
-  = mapNat push_arg
-           (reverse args)      `thenNat` \ sizes_n_codes ->
-    getDeltaNat                `thenNat` \ delta ->
-    let (sizes, push_codes) = unzip sizes_n_codes
-        tot_arg_size        = sum sizes
-    in
-    -- deal with static vs dynamic call targets
-    (case fn of
-        Left t_static 
-           -> returnNat (unitOL (CALL (Left (fn__2 tot_arg_size))))
-        Right dyn 
-           -> get_op dyn `thenNat` \ (dyn_c, dyn_r, dyn_rep) ->
-              ASSERT(case dyn_rep of { L -> True; _ -> False})
-              returnNat (dyn_c `snocOL` CALL (Right dyn_r))
-    ) 
-                               `thenNat` \ callinsns ->
-    let        push_code = concatOL push_codes
-       call = callinsns `appOL`
-               toOL (
-                       -- Deallocate parameters after call for ccall;
-                       -- but not for stdcall (callee does it)
-                  (if cconv == StdCallConv then [] else 
-                  [ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp)])
-                  ++
-                  [DELTA (delta + tot_arg_size)]
-               )
-    in
-    setDeltaNat (delta + tot_arg_size) `thenNat` \ _ ->
-    returnNat (push_code `appOL` call)
-
-  where
-    -- function names that begin with '.' are assumed to be special
-    -- internally generated names like '.mul,' which don't get an
-    -- underscore prefix
-    -- ToDo:needed (WDP 96/03) ???
-    fn_u  = unpackFS (unLeft fn)
-    fn__2 tot_arg_size
-       | head fn_u == '.'
-       = ImmLit (text (fn_u ++ stdcallsize tot_arg_size))
-       | otherwise     -- General case
-       = ImmLab False (text (fn_u ++ stdcallsize tot_arg_size))
-
-    stdcallsize tot_arg_size
-       | cconv == StdCallConv = '@':show tot_arg_size
-       | otherwise            = ""
-
-    arg_size DF = 8
-    arg_size F  = 4
-    arg_size _  = 4
-
-    ------------
-    push_arg :: StixExpr{-current argument-}
-                    -> NatM (Int, InstrBlock)  -- argsz, code
-
-    push_arg arg
-      | is64BitRep arg_rep
-      = iselExpr64 arg                 `thenNat` \ (ChildCode64 code vr_lo) ->
-        getDeltaNat                    `thenNat` \ delta ->
-        setDeltaNat (delta - 8)                `thenNat` \ _ ->
-        let r_lo = VirtualRegI vr_lo
-            r_hi = getHiVRegFromLo r_lo
-        in  returnNat (8,
-                       code `appOL`
-                       toOL [PUSH L (OpReg r_hi), DELTA (delta - 4),
-                             PUSH L (OpReg r_lo), DELTA (delta - 8)]
-            )
-      | otherwise
-      = get_op arg                     `thenNat` \ (code, reg, sz) ->
-        getDeltaNat                    `thenNat` \ delta ->
-        arg_size sz                    `bind`    \ size ->
-        setDeltaNat (delta-size)       `thenNat` \ _ ->
-        if   (case sz of DF -> True; F -> True; _ -> False)
-        then returnNat (size,
-                        code `appOL`
-                        toOL [SUB L (OpImm (ImmInt size)) (OpReg esp),
-                              DELTA (delta-size),
-                              GST sz reg (AddrBaseIndex (Just esp) 
-                                                        Nothing 
-                                                        (ImmInt 0))]
-                       )
-        else returnNat (size,
-                        code `snocOL`
-                        PUSH L (OpReg reg) `snocOL`
-                        DELTA (delta-size)
-                       )
-      where
-         arg_rep = repOfStixExpr arg
-
-    ------------
-    get_op
-       :: StixExpr
-       -> NatM (InstrBlock, Reg, Size) -- code, reg, size
-
-    get_op op
-      = getRegister op         `thenNat` \ register ->
-       getNewRegNCG (registerRep register)
-                               `thenNat` \ tmp ->
-       let
-           code = registerCode register tmp
-           reg  = registerName register tmp
-           pk   = registerRep  register
-           sz   = primRepToSize pk
-       in
-       returnNat (code, reg, sz)
-
-#endif /* i386_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if sparc_TARGET_ARCH
-{- 
-   The SPARC calling convention is an absolute
-   nightmare.  The first 6x32 bits of arguments are mapped into
-   %o0 through %o5, and the remaining arguments are dumped to the
-   stack, beginning at [%sp+92].  (Note that %o6 == %sp.)
-
-   If we have to put args on the stack, move %o6==%sp down by
-   the number of words to go on the stack, to ensure there's enough space.
-
-   According to Fraser and Hanson's lcc book, page 478, fig 17.2,
-   16 words above the stack pointer is a word for the address of
-   a structure return value.  I use this as a temporary location
-   for moving values from float to int regs.  Certainly it isn't
-   safe to put anything in the 16 words starting at %sp, since
-   this area can get trashed at any time due to window overflows
-   caused by signal handlers.
-
-   A final complication (if the above isn't enough) is that 
-   we can't blithely calculate the arguments one by one into
-   %o0 .. %o5.  Consider the following nested calls:
-
-       fff a (fff b c)
-
-   Naive code moves a into %o0, and (fff b c) into %o1.  Unfortunately
-   the inner call will itself use %o0, which trashes the value put there
-   in preparation for the outer call.  Upshot: we need to calculate the
-   args into temporary regs, and move those to arg regs or onto the
-   stack only immediately prior to the call proper.  Sigh.
--}
-
-genCCall fn cconv kind args
-  = mapNat arg_to_int_vregs args `thenNat` \ argcode_and_vregs ->
-    let 
-        (argcodes, vregss) = unzip argcode_and_vregs
-        n_argRegs          = length allArgRegs
-        n_argRegs_used     = min (length vregs) n_argRegs
-        vregs              = concat vregss
-    in
-    -- deal with static vs dynamic call targets
-    (case fn of
-        Left t_static
-           -> returnNat (unitOL (CALL (Left fn__2) n_argRegs_used False))
-        Right dyn
-           -> arg_to_int_vregs dyn `thenNat` \ (dyn_c, [dyn_r]) ->
-              returnNat (dyn_c `snocOL` CALL (Right dyn_r) n_argRegs_used False)
-    )
-                               `thenNat` \ callinsns ->
-    let
-        argcode = concatOL argcodes
-        (move_sp_down, move_sp_up)
-           = let diff = length vregs - n_argRegs
-                 nn   = if odd diff then diff + 1 else diff -- keep 8-byte alignment
-             in  if   nn <= 0
-                 then (nilOL, nilOL)
-                 else (unitOL (moveSp (-1*nn)), unitOL (moveSp (1*nn)))
-        transfer_code
-           = toOL (move_final vregs allArgRegs eXTRA_STK_ARGS_HERE)
-    in
-        returnNat (argcode       `appOL`
-                   move_sp_down  `appOL`
-                   transfer_code `appOL`
-                   callinsns     `appOL`
-                   unitOL NOP    `appOL`
-                   move_sp_up)
-  where
-     -- function names that begin with '.' are assumed to be special
-     -- internally generated names like '.mul,' which don't get an
-     -- underscore prefix
-     -- ToDo:needed (WDP 96/03) ???
-     fn_static = unLeft fn
-     fn__2 = case (headFS fn_static) of
-               '.' -> ImmLit (ftext fn_static)
-               _   -> ImmLab False (ftext fn_static)
-
-     -- move args from the integer vregs into which they have been 
-     -- marshalled, into %o0 .. %o5, and the rest onto the stack.
-     move_final :: [Reg] -> [Reg] -> Int -> [Instr]
-
-     move_final [] _ offset          -- all args done
-        = []
-
-     move_final (v:vs) [] offset     -- out of aregs; move to stack
-        = ST W v (spRel offset)
-          : move_final vs [] (offset+1)
-
-     move_final (v:vs) (a:az) offset -- move into an arg (%o[0..5]) reg
-        = OR False g0 (RIReg v) a
-          : move_final vs az offset
-
-     -- generate code to calculate an argument, and move it into one
-     -- or two integer vregs.
-     arg_to_int_vregs :: StixExpr -> NatM (OrdList Instr, [Reg])
-     arg_to_int_vregs arg
-        | is64BitRep (repOfStixExpr arg)
-        = iselExpr64 arg               `thenNat` \ (ChildCode64 code vr_lo) ->
-          let r_lo = VirtualRegI vr_lo
-              r_hi = getHiVRegFromLo r_lo
-          in  returnNat (code, [r_hi, r_lo])
-        | otherwise
-        = getRegister arg                     `thenNat` \ register ->
-          getNewRegNCG (registerRep register) `thenNat` \ tmp ->
-          let code = registerCode register tmp
-              src  = registerName register tmp
-              pk   = registerRep register
-          in
-          -- the value is in src.  Get it into 1 or 2 int vregs.
-          case pk of
-             DoubleRep -> 
-                getNewRegNCG WordRep  `thenNat` \ v1 ->
-                getNewRegNCG WordRep  `thenNat` \ v2 ->
-                returnNat (
-                   code                          `snocOL`
-                   FMOV DF src f0                `snocOL`
-                   ST   F  f0 (spRel 16)         `snocOL`
-                   LD   W  (spRel 16) v1         `snocOL`
-                   ST   F  (fPair f0) (spRel 16) `snocOL`
-                   LD   W  (spRel 16) v2
-                   ,
-                   [v1,v2]
-                )
-             FloatRep -> 
-                getNewRegNCG WordRep  `thenNat` \ v1 ->
-                returnNat (
-                   code                    `snocOL`
-                   ST   F  src (spRel 16)  `snocOL`
-                   LD   W  (spRel 16) v1
-                   ,
-                   [v1]
-                )
-             other ->
-                getNewRegNCG WordRep  `thenNat` \ v1 ->
-                returnNat (
-                   code `snocOL` OR False g0 (RIReg src) v1
-                   , 
-                   [v1]
-                )
-#endif /* sparc_TARGET_ARCH */
-
-#if powerpc_TARGET_ARCH
-
-#if darwin_TARGET_OS
-{-
-    The PowerPC calling convention for Darwin/Mac OS X
-    is described in Apple's document
-    "Inside Mac OS X - Mach-O Runtime Architecture".
-    Parameters may be passed in general-purpose registers, in
-    floating point registers, or on the stack. Stack space is
-    always reserved for parameters, even if they are passed in registers.
-    The called routine may choose to save parameters from registers
-    to the corresponding space on the stack.
-    The parameter area should be part of the caller's stack frame,
-    allocated in the caller's prologue code (large enough to hold
-    the parameter lists for all called routines). The NCG already
-    uses the space that we should use as a parameter area for register
-    spilling, so we allocate a new stack frame just before ccalling.
-    That way we don't need to decide beforehand how much space to
-    reserve for parameters.
--}
-
-genCCall fn cconv kind args
-  = mapNat prepArg args `thenNat` \ preppedArgs ->
-    let
-       (argReps,argCodes,vregs) = unzip3 preppedArgs
-
-           -- size of linkage area + size of arguments, in bytes
-       stackDelta = roundTo16 $ (24 +) $ max 32 $ (4 *) $ sum $ map getPrimRepSize argReps
-       roundTo16 x | x `mod` 16 == 0 = x
-                   | otherwise = x + 16 - (x `mod` 16)
-
-       move_sp_down = toOL [STU W sp (AddrRegImm sp (ImmInt (-stackDelta))), DELTA (-stackDelta)]
-       move_sp_up = toOL [ADD sp sp (RIImm (ImmInt stackDelta)), DELTA 0]
-
-       (moveFinalCode,usedRegs) = move_final
-                                       (zip vregs argReps)
-                                       allArgRegs allFPArgRegs
-                                       eXTRA_STK_ARGS_HERE
-                                       (toOL []) []
-
-       passArguments = concatOL argCodes
-           `appOL` move_sp_down
-           `appOL` moveFinalCode
-    in 
-       case fn of
-           Left lbl ->
-               addImportNat lbl                        `thenNat` \ _ ->
-               returnNat (passArguments
-                           `snocOL`    BL (ImmLit $ ftext 
-                                            (FSLIT("L_")
-                                            `appendFS` lbl
-                                            `appendFS` FSLIT("$stub")))
-                                          usedRegs
-                           `appOL`     move_sp_up)
-           Right dyn ->
-               getRegister dyn                         `thenNat` \ dynReg ->
-               getNewRegNCG (registerRep dynReg)       `thenNat` \ tmp ->
-               returnNat (registerCode dynReg tmp
-                           `appOL`     passArguments
-                           `snocOL`    MTCTR (registerName dynReg tmp)
-                           `snocOL`    BCTRL usedRegs
-                           `appOL`     move_sp_up)
-    where
-    prepArg arg
-        | is64BitRep (repOfStixExpr arg)
-        = iselExpr64 arg               `thenNat` \ (ChildCode64 code vr_lo) ->
-          let r_lo = VirtualRegI vr_lo
-              r_hi = getHiVRegFromLo r_lo
-          in  returnNat (repOfStixExpr arg, code, Right (r_hi,r_lo))
-       | otherwise
-       = getRegister arg                       `thenNat` \ register ->
-         getNewRegNCG (registerRep register)   `thenNat` \ tmp ->
-         returnNat (registerRep register, registerCode register tmp, Left (registerName register tmp))
-    move_final [] _ _ _ accumCode accumUsed = (accumCode, accumUsed)
-    move_final ((Left vr,rep):vregs) gprs fprs stackOffset accumCode accumUsed
-       | not (is64BitRep rep) =
-       case rep of
-           FloatRep ->
-               move_final vregs (drop 1 gprs) (drop 1 fprs) (stackOffset+4)
-                   (accumCode `snocOL`
-                       (case fprs of
-                           fpr : fprs -> MR fpr vr
-                           [] -> ST F vr (AddrRegImm sp (ImmInt stackOffset))))
-                   ((take 1 fprs) ++ accumUsed)
-           DoubleRep ->
-               move_final vregs (drop 2 gprs) (drop 1 fprs) (stackOffset+8)
-                   (accumCode `snocOL`
-                       (case fprs of
-                           fpr : fprs -> MR fpr vr
-                           [] -> ST DF vr (AddrRegImm sp (ImmInt stackOffset))))
-                   ((take 1 fprs) ++ accumUsed)
-           VoidRep -> panic "MachCode.genCCall(powerpc): void parameter"
-           _ ->
-               move_final vregs (drop 1 gprs) fprs (stackOffset+4)
-                   (accumCode `snocOL`
-                       (case gprs of
-                           gpr : gprs -> MR gpr vr
-                           [] -> ST W vr (AddrRegImm sp (ImmInt stackOffset))))
-                   ((take 1 gprs) ++ accumUsed)
-               
-    move_final ((Right (vr_hi,vr_lo),rep):vregs) gprs fprs stackOffset accumCode accumUsed
-       | is64BitRep rep =
-       let
-           storeWord vr (gpr:_) offset = MR gpr vr
-           storeWord vr [] offset = ST W vr (AddrRegImm sp (ImmInt offset))
-       in
-           move_final vregs (drop 2 gprs) fprs (stackOffset+8)
-               (accumCode
-                   `snocOL` storeWord vr_hi gprs stackOffset
-                   `snocOL` storeWord vr_lo (drop 1 gprs) (stackOffset+4))
-               ((take 2 gprs) ++ accumUsed)
-#else
-
-{-
-    PowerPC Linux uses the System V Release 4 Calling Convention
-    for PowerPC. It is described in the
-    "System V Application Binary Interface PowerPC Processor Supplement".
-    
-    Like the Darwin/Mac OS X code above, this allocates a new stack frame
-    so that the parameter area doesn't conflict with the spill slots.
--}
-
-genCCall fn cconv kind args
-  = mapNat prepArg args `thenNat` \ preppedArgs ->
-    let
-       (argReps,argCodes,vregs) = unzip3 preppedArgs
-
-           -- size of linkage area + size of arguments, in bytes
-       stackDelta = roundTo16 finalStack
-       roundTo16 x | x `mod` 16 == 0 = x
-                   | otherwise = x + 16 - (x `mod` 16)
-
-       move_sp_down = toOL [STU W sp (AddrRegImm sp (ImmInt (-stackDelta))), DELTA (-stackDelta)]
-       move_sp_up = toOL [ADD sp sp (RIImm (ImmInt stackDelta)), DELTA 0]
-
-       (moveFinalCode,usedRegs,finalStack) =
-            move_final (zip vregs argReps)
-                      allArgRegs allFPArgRegs
-                      eXTRA_STK_ARGS_HERE
-                      (toOL []) []
-
-       passArguments = concatOL argCodes
-           `appOL` move_sp_down
-           `appOL` moveFinalCode
-    in 
-       case fn of
-           Left lbl ->
-               addImportNat lbl                        `thenNat` \ _ ->
-               returnNat (passArguments
-                           `snocOL`    BL (ImmLit $ ftext  lbl)
-                                          usedRegs
-                           `appOL`     move_sp_up)
-           Right dyn ->
-               getRegister dyn                         `thenNat` \ dynReg ->
-               getNewRegNCG (registerRep dynReg)       `thenNat` \ tmp ->
-               returnNat (registerCode dynReg tmp
-                           `appOL`     passArguments
-                           `snocOL`    MTCTR (registerName dynReg tmp)
-                           `snocOL`    BCTRL usedRegs
-                           `appOL`     move_sp_up)
-    where
-    prepArg arg
-        | is64BitRep (repOfStixExpr arg)
-        = iselExpr64 arg               `thenNat` \ (ChildCode64 code vr_lo) ->
-          let r_lo = VirtualRegI vr_lo
-              r_hi = getHiVRegFromLo r_lo
-          in  returnNat (repOfStixExpr arg, code, Right (r_hi,r_lo))
-       | otherwise
-       = getRegister arg                       `thenNat` \ register ->
-         getNewRegNCG (registerRep register)   `thenNat` \ tmp ->
-         returnNat (registerRep register, registerCode register tmp, Left (registerName register tmp))
-    move_final [] _ _ stackOffset accumCode accumUsed = (accumCode, accumUsed, stackOffset)
-    move_final ((Left vr,rep):vregs) gprs fprs stackOffset accumCode accumUsed
-       | not (is64BitRep rep) =
-       case rep of
-           FloatRep ->
-                case fprs of
-                    fpr : fprs' -> move_final vregs gprs fprs' stackOffset
-                                              (accumCode `snocOL` MR fpr vr)
-                                              (fpr : accumUsed)
-                    [] -> move_final vregs gprs fprs (stackOffset+4)
-                                     (accumCode `snocOL`
-                                        ST F vr (AddrRegImm sp (ImmInt stackOffset)))
-                                     accumUsed
-           DoubleRep ->
-                case fprs of
-                    fpr : fprs' -> move_final vregs gprs fprs' stackOffset
-                                              (accumCode `snocOL` MR fpr vr)
-                                              (fpr : accumUsed)
-                    [] -> move_final vregs gprs fprs (stackOffset+8)
-                                     (accumCode `snocOL`
-                                        ST DF vr (AddrRegImm sp (ImmInt stackOffset)))
-                                     accumUsed
-           VoidRep -> panic "MachCode.genCCall(powerpc): void parameter"
-           _ ->
-                case gprs of
-                    gpr : gprs' -> move_final vregs gprs' fprs stackOffset
-                                              (accumCode `snocOL` MR gpr vr)
-                                              (gpr : accumUsed)
-                    [] -> move_final vregs gprs fprs (stackOffset+4)
-                                     (accumCode `snocOL`
-                                        ST W vr (AddrRegImm sp (ImmInt stackOffset)))
-                                     accumUsed
-               
-    move_final ((Right (vr_hi,vr_lo),rep):vregs) gprs fprs stackOffset accumCode accumUsed
-       | is64BitRep rep =
-            case gprs of
-                hireg : loreg : regs | even (length gprs) ->
-                    move_final vregs regs fprs stackOffset
-                               (regCode hireg loreg) accumUsed
-                _skipped : hireg : loreg : regs ->
-                    move_final vregs regs fprs stackOffset
-                               (regCode hireg loreg) accumUsed
-                _ -> -- only one or no regs left
-                    move_final vregs [] fprs (stackOffset+8)
-                               stackCode accumUsed
-       where
-            stackCode =
-                accumCode
-                    `snocOL` ST W vr_hi (AddrRegImm sp (ImmInt stackOffset))
-                    `snocOL` ST W vr_lo (AddrRegImm sp (ImmInt (stackOffset+4)))
-            regCode hireg loreg =
-                accumCode
-                    `snocOL` MR hireg vr_hi
-                    `snocOL` MR loreg vr_lo
-
-#endif                
-                
-#endif /* powerpc_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{Support bits}
-%*                                                                     *
-%************************************************************************
-
-%************************************************************************
-%*                                                                     *
-\subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
-%*                                                                     *
-%************************************************************************
-
-Turn those condition codes into integers now (when they appear on
-the right hand side of an assignment).
-
-(If applicable) Do not fill the delay slots here; you will confuse the
-register allocator.
-
-\begin{code}
-condIntReg, condFltReg :: Cond -> StixExpr -> StixExpr -> NatM Register
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if alpha_TARGET_ARCH
-condIntReg = panic "MachCode.condIntReg (not on Alpha)"
-condFltReg = panic "MachCode.condFltReg (not on Alpha)"
-#endif /* alpha_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if i386_TARGET_ARCH
-
-condIntReg cond x y
-  = condIntCode cond x y       `thenNat` \ condition ->
-    getNewRegNCG IntRep                `thenNat` \ tmp ->
-    let
-       code = condCode condition
-       cond = condName condition
-       code__2 dst = code `appOL` toOL [
-           SETCC cond (OpReg tmp),
-           AND L (OpImm (ImmInt 1)) (OpReg tmp),
-           MOV L (OpReg tmp) (OpReg dst)]
-    in
-    returnNat (Any IntRep code__2)
-
-condFltReg cond x y
-  = getNatLabelNCG             `thenNat` \ lbl1 ->
-    getNatLabelNCG             `thenNat` \ lbl2 ->
-    condFltCode cond x y       `thenNat` \ condition ->
-    let
-       code = condCode condition
-       cond = condName condition
-       code__2 dst = code `appOL` toOL [
-           JXX cond lbl1,
-           MOV L (OpImm (ImmInt 0)) (OpReg dst),
-           JXX ALWAYS lbl2,
-           LABEL lbl1,
-           MOV L (OpImm (ImmInt 1)) (OpReg dst),
-           LABEL lbl2]
-    in
-    returnNat (Any IntRep code__2)
-
-#endif /* i386_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if sparc_TARGET_ARCH
-
-condIntReg EQQ x (StInt 0)
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG IntRep                `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src  = registerName register tmp
-       code__2 dst = code `appOL` toOL [
-           SUB False True g0 (RIReg src) g0,
-           SUB True False g0 (RIImm (ImmInt (-1))) dst]
-    in
-    returnNat (Any IntRep code__2)
-
-condIntReg EQQ x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp1 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp2 ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-       code__2 dst = code1 `appOL` code2 `appOL` toOL [
-           XOR False src1 (RIReg src2) dst,
-           SUB False True g0 (RIReg dst) g0,
-           SUB True False g0 (RIImm (ImmInt (-1))) dst]
-    in
-    returnNat (Any IntRep code__2)
-
-condIntReg NE x (StInt 0)
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG IntRep        `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src  = registerName register tmp
-       code__2 dst = code `appOL` toOL [
-           SUB False True g0 (RIReg src) g0,
-           ADD True False g0 (RIImm (ImmInt 0)) dst]
-    in
-    returnNat (Any IntRep code__2)
-
-condIntReg NE x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp1 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp2 ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-       code__2 dst = code1 `appOL` code2 `appOL` toOL [
-           XOR False src1 (RIReg src2) dst,
-           SUB False True g0 (RIReg dst) g0,
-           ADD True False g0 (RIImm (ImmInt 0)) dst]
-    in
-    returnNat (Any IntRep code__2)
-
-condIntReg cond x y
-  = getNatLabelNCG             `thenNat` \ lbl1 ->
-    getNatLabelNCG             `thenNat` \ lbl2 ->
-    condIntCode cond x y       `thenNat` \ condition ->
-    let
-       code = condCode condition
-       cond = condName condition
-       code__2 dst = code `appOL` toOL [
-           BI cond False (ImmCLbl lbl1), NOP,
-           OR False g0 (RIImm (ImmInt 0)) dst,
-           BI ALWAYS False (ImmCLbl lbl2), NOP,
-           LABEL lbl1,
-           OR False g0 (RIImm (ImmInt 1)) dst,
-           LABEL lbl2]
-    in
-    returnNat (Any IntRep code__2)
-
-condFltReg cond x y
-  = getNatLabelNCG             `thenNat` \ lbl1 ->
-    getNatLabelNCG             `thenNat` \ lbl2 ->
-    condFltCode cond x y       `thenNat` \ condition ->
-    let
-       code = condCode condition
-       cond = condName condition
-       code__2 dst = code `appOL` toOL [
-           NOP,
-           BF cond False (ImmCLbl lbl1), NOP,
-           OR False g0 (RIImm (ImmInt 0)) dst,
-           BI ALWAYS False (ImmCLbl lbl2), NOP,
-           LABEL lbl1,
-           OR False g0 (RIImm (ImmInt 1)) dst,
-           LABEL lbl2]
-    in
-    returnNat (Any IntRep code__2)
-
-#endif /* sparc_TARGET_ARCH */
-
-#if powerpc_TARGET_ARCH
-condIntReg cond x y
-  = getNatLabelNCG             `thenNat` \ lbl ->
-    condIntCode cond x y       `thenNat` \ condition ->
-    let
-       code = condCode condition
-       cond = condName condition
-       code__2 dst = (LI dst (ImmInt 1) `consOL` code) `appOL` toOL [
-           BCC cond lbl,
-           LI dst (ImmInt 0),
-           LABEL lbl]
-    in
-    returnNat (Any IntRep code__2)
-
-condFltReg cond x y
-  = getNatLabelNCG             `thenNat` \ lbl ->
-    condFltCode cond x y       `thenNat` \ condition ->
-    let
-       code = condCode condition
-       cond = condName condition
-       code__2 dst = (LI dst (ImmInt 1) `consOL` code) `appOL` toOL [
-           BCC cond lbl,
-           LI dst (ImmInt 0),
-           LABEL lbl]
-    in
-    returnNat (Any IntRep code__2)
-#endif /* powerpc_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsubsection{@trivial*Code@: deal with trivial instructions}
-%*                                                                     *
-%************************************************************************
-
-Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
-@trivialUCode@, unary fl-pt:@trivialUFCode@) instructions.  Only look
-for constants on the right hand side, because that's where the generic
-optimizer will have put them.
-
-Similarly, for unary instructions, we don't have to worry about
-matching an StInt as the argument, because genericOpt will already
-have handled the constant-folding.
-
-\begin{code}
-trivialCode
-    :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
-      ,IF_ARCH_i386 ((Operand -> Operand -> Instr) 
-                     -> Maybe (Operand -> Operand -> Instr)
-      ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
-      ,IF_ARCH_powerpc((Reg -> Reg -> RI -> Instr)
-      ,))))
-    -> StixExpr -> StixExpr -- the two arguments
-    -> NatM Register
-
-trivialFCode
-    :: PrimRep
-    -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
-      ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
-      ,IF_ARCH_i386 ((Size -> Reg -> Reg -> Reg -> Instr)
-      ,IF_ARCH_powerpc((Size -> Reg -> Reg -> Reg -> Instr)
-      ,))))
-    -> StixExpr -> StixExpr -- the two arguments
-    -> NatM Register
-
-trivialUCode
-    :: IF_ARCH_alpha((RI -> Reg -> Instr)
-      ,IF_ARCH_i386 ((Operand -> Instr)
-      ,IF_ARCH_sparc((RI -> Reg -> Instr)
-      ,IF_ARCH_powerpc((Reg -> Reg -> Instr)
-      ,))))
-    -> StixExpr        -- the one argument
-    -> NatM Register
-
-trivialUFCode
-    :: PrimRep
-    -> IF_ARCH_alpha((Reg -> Reg -> Instr)
-      ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
-      ,IF_ARCH_sparc((Reg -> Reg -> Instr)
-      ,IF_ARCH_powerpc((Reg -> Reg -> Instr)
-      ,))))
-    -> StixExpr -- the one argument
-    -> NatM Register
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if alpha_TARGET_ARCH
-
-trivialCode instr x (StInt y)
-  | fits8Bits y
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG IntRep                `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src1 = registerName register tmp
-       src2 = ImmInt (fromInteger y)
-       code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
-    in
-    returnNat (Any IntRep code__2)
-
-trivialCode instr x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp1 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp2 ->
-    let
-       code1 = registerCode register1 tmp1 []
-       src1  = registerName register1 tmp1
-       code2 = registerCode register2 tmp2 []
-       src2  = registerName register2 tmp2
-       code__2 dst = asmSeqThen [code1, code2] .
-                    mkSeqInstr (instr src1 (RIReg src2) dst)
-    in
-    returnNat (Any IntRep code__2)
-
-------------
-trivialUCode instr x
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG IntRep                `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src  = registerName register tmp
-       code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
-    in
-    returnNat (Any IntRep code__2)
-
-------------
-trivialFCode _ instr x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG DoubleRep     `thenNat` \ tmp1 ->
-    getNewRegNCG DoubleRep     `thenNat` \ tmp2 ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-
-       code__2 dst = asmSeqThen [code1 [], code2 []] .
-                     mkSeqInstr (instr src1 src2 dst)
-    in
-    returnNat (Any DoubleRep code__2)
-
-trivialUFCode _ instr x
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG DoubleRep     `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src  = registerName register tmp
-       code__2 dst = code . mkSeqInstr (instr src dst)
-    in
-    returnNat (Any DoubleRep code__2)
-
-#endif /* alpha_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if i386_TARGET_ARCH
-\end{code}
-The Rules of the Game are:
-
-* You cannot assume anything about the destination register dst;
-  it may be anything, including a fixed reg.
-
-* You may compute an operand into a fixed reg, but you may not 
-  subsequently change the contents of that fixed reg.  If you
-  want to do so, first copy the value either to a temporary
-  or into dst.  You are free to modify dst even if it happens
-  to be a fixed reg -- that's not your problem.
-
-* You cannot assume that a fixed reg will stay live over an
-  arbitrary computation.  The same applies to the dst reg.
-
-* Temporary regs obtained from getNewRegNCG are distinct from 
-  each other and from all other regs, and stay live over 
-  arbitrary computations.
-
-\begin{code}
-
-trivialCode instr maybe_revinstr a b
-
-  | is_imm_b
-  = getRegister a                         `thenNat` \ rega ->
-    let mkcode dst
-          = if   isAny rega 
-            then registerCode rega dst      `bind` \ code_a ->
-                 code_a `snocOL`
-                 instr (OpImm imm_b) (OpReg dst)
-            else registerCodeF rega         `bind` \ code_a ->
-                 registerNameF rega         `bind` \ r_a ->
-                 code_a `snocOL`
-                 MOV L (OpReg r_a) (OpReg dst) `snocOL`
-                 instr (OpImm imm_b) (OpReg dst)
-    in
-    returnNat (Any IntRep mkcode)
-              
-  | is_imm_a
-  = getRegister b                         `thenNat` \ regb ->
-    getNewRegNCG IntRep                   `thenNat` \ tmp ->
-    let revinstr_avail = maybeToBool maybe_revinstr
-        revinstr       = case maybe_revinstr of Just ri -> ri
-        mkcode dst
-          | revinstr_avail
-          = if   isAny regb
-            then registerCode regb dst      `bind` \ code_b ->
-                 code_b `snocOL`
-                 revinstr (OpImm imm_a) (OpReg dst)
-            else registerCodeF regb         `bind` \ code_b ->
-                 registerNameF regb         `bind` \ r_b ->
-                 code_b `snocOL`
-                 MOV L (OpReg r_b) (OpReg dst) `snocOL`
-                 revinstr (OpImm imm_a) (OpReg dst)
-          
-          | otherwise
-          = if   isAny regb
-            then registerCode regb tmp      `bind` \ code_b ->
-                 code_b `snocOL`
-                 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
-                 instr (OpReg tmp) (OpReg dst)
-            else registerCodeF regb         `bind` \ code_b ->
-                 registerNameF regb         `bind` \ r_b ->
-                 code_b `snocOL`
-                 MOV L (OpReg r_b) (OpReg tmp) `snocOL`
-                 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
-                 instr (OpReg tmp) (OpReg dst)
-    in
-    returnNat (Any IntRep mkcode)
-
-  | otherwise
-  = getRegister a                         `thenNat` \ rega ->
-    getRegister b                         `thenNat` \ regb ->
-    getNewRegNCG IntRep                   `thenNat` \ tmp ->
-    let mkcode dst
-          = case (isAny rega, isAny regb) of
-              (True, True) 
-                 -> registerCode regb tmp   `bind` \ code_b ->
-                    registerCode rega dst   `bind` \ code_a ->
-                    code_b `appOL`
-                    code_a `snocOL`
-                    instr (OpReg tmp) (OpReg dst)
-              (True, False)
-                 -> registerCode  rega tmp  `bind` \ code_a ->
-                    registerCodeF regb      `bind` \ code_b ->
-                    registerNameF regb      `bind` \ r_b ->
-                    code_a `appOL`
-                    code_b `snocOL`
-                    instr (OpReg r_b) (OpReg tmp) `snocOL`
-                    MOV L (OpReg tmp) (OpReg dst)
-              (False, True)
-                 -> registerCode  regb tmp  `bind` \ code_b ->
-                    registerCodeF rega      `bind` \ code_a ->
-                    registerNameF rega      `bind` \ r_a ->
-                    code_b `appOL`
-                    code_a `snocOL`
-                    MOV L (OpReg r_a) (OpReg dst) `snocOL`
-                    instr (OpReg tmp) (OpReg dst)
-              (False, False)
-                 -> registerCodeF  rega     `bind` \ code_a ->
-                    registerNameF  rega     `bind` \ r_a ->
-                    registerCodeF  regb     `bind` \ code_b ->
-                    registerNameF  regb     `bind` \ r_b ->
-                    code_a `snocOL`
-                    MOV L (OpReg r_a) (OpReg tmp) `appOL`
-                    code_b `snocOL`
-                    instr (OpReg r_b) (OpReg tmp) `snocOL`
-                    MOV L (OpReg tmp) (OpReg dst)
-    in
-    returnNat (Any IntRep mkcode)
-
-    where
-       maybe_imm_a = maybeImm a
-       is_imm_a    = maybeToBool maybe_imm_a
-       imm_a       = case maybe_imm_a of Just imm -> imm
-
-       maybe_imm_b = maybeImm b
-       is_imm_b    = maybeToBool maybe_imm_b
-       imm_b       = case maybe_imm_b of Just imm -> imm
-
-
------------
-trivialUCode instr x
-  = getRegister x              `thenNat` \ register ->
-    let
-       code__2 dst = let code = registerCode register dst
-                         src  = registerName register dst
-                     in code `appOL`
-                         if   isFixed register && dst /= src
-                        then toOL [MOV L (OpReg src) (OpReg dst),
-                                   instr (OpReg dst)]
-                        else unitOL (instr (OpReg src))
-    in
-    returnNat (Any IntRep code__2)
-
------------
-trivialFCode pk instr x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG DoubleRep     `thenNat` \ tmp1 ->
-    getNewRegNCG DoubleRep     `thenNat` \ tmp2 ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-
-       code__2 dst
-           -- treat the common case specially: both operands in
-           -- non-fixed regs.
-           | isAny register1 && isAny register2
-           = code1 `appOL` 
-             code2 `snocOL`
-            instr (primRepToSize pk) src1 src2 dst
-
-           -- be paranoid (and inefficient)
-           | otherwise
-           = code1 `snocOL` GMOV src1 tmp1  `appOL`
-             code2 `snocOL`
-             instr (primRepToSize pk) tmp1 src2 dst
-    in
-    returnNat (Any pk code__2)
-
-
--------------
-trivialUFCode pk instr x
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG pk            `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src  = registerName register tmp
-       code__2 dst = code `snocOL` instr src dst
-    in
-    returnNat (Any pk code__2)
-
-#endif /* i386_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if sparc_TARGET_ARCH
-
-trivialCode instr x (StInt y)
-  | fits13Bits y
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG IntRep                `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src1 = registerName register tmp
-       src2 = ImmInt (fromInteger y)
-       code__2 dst = code `snocOL` instr src1 (RIImm src2) dst
-    in
-    returnNat (Any IntRep code__2)
-
-trivialCode instr x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp1 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp2 ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-       code__2 dst = code1 `appOL` code2 `snocOL`
-                     instr src1 (RIReg src2) dst
-    in
-    returnNat (Any IntRep code__2)
-
-------------
-trivialFCode pk instr x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG (registerRep register1)
-                               `thenNat` \ tmp1 ->
-    getNewRegNCG (registerRep register2)
-                               `thenNat` \ tmp2 ->
-    getNewRegNCG DoubleRep     `thenNat` \ tmp ->
-    let
-       promote x = FxTOy F DF x tmp
-
-       pk1   = registerRep register1
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-
-       pk2   = registerRep register2
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-
-       code__2 dst =
-               if pk1 == pk2 then
-                   code1 `appOL` code2 `snocOL`
-                   instr (primRepToSize pk) src1 src2 dst
-               else if pk1 == FloatRep then
-                   code1 `snocOL` promote src1 `appOL` code2 `snocOL`
-                   instr DF tmp src2 dst
-               else
-                   code1 `appOL` code2 `snocOL` promote src2 `snocOL`
-                   instr DF src1 tmp dst
-    in
-    returnNat (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
-
-------------
-trivialUCode instr x
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG IntRep                `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src  = registerName register tmp
-       code__2 dst = code `snocOL` instr (RIReg src) dst
-    in
-    returnNat (Any IntRep code__2)
-
--------------
-trivialUFCode pk instr x
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG pk            `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src  = registerName register tmp
-       code__2 dst = code `snocOL` instr src dst
-    in
-    returnNat (Any pk code__2)
-
-#endif /* sparc_TARGET_ARCH */
-
-#if powerpc_TARGET_ARCH
-trivialCode instr x (StInt y)
-  | fits16Bits y
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG IntRep                `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src1 = registerName register tmp
-       src2 = ImmInt (fromInteger y)
-       code__2 dst = code `snocOL` instr dst src1 (RIImm src2)
-    in
-    returnNat (Any IntRep code__2)
-
-trivialCode instr x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp1 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp2 ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-       code__2 dst = code1 `appOL` code2 `snocOL`
-                     instr dst src1 (RIReg src2)
-    in
-    returnNat (Any IntRep code__2)
-
-trivialCode2 :: (Reg -> Reg -> Reg -> Instr)
-    -> StixExpr -> StixExpr -> NatM Register
-trivialCode2 instr x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp1 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp2 ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-       code__2 dst = code1 `appOL` code2 `snocOL`
-                     instr dst src1 src2
-    in
-    returnNat (Any IntRep code__2)
-    
-trivialFCode pk instr x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG (registerRep register1)
-                               `thenNat` \ tmp1 ->
-    getNewRegNCG (registerRep register2)
-                               `thenNat` \ tmp2 ->
-    -- getNewRegNCG DoubleRep          `thenNat` \ tmp ->
-    let
-       -- promote x = FxTOy F DF x tmp
-
-       pk1   = registerRep register1
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-
-       pk2   = registerRep register2
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-
-       dstRep = if pk1 == FloatRep && pk2 == FloatRep then FloatRep else DoubleRep
-
-       code__2 dst =
-                   code1 `appOL` code2 `snocOL`
-                   instr (primRepToSize dstRep) dst src1 src2
-    in
-    returnNat (Any dstRep code__2)
-
-trivialUCode instr x
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG IntRep                `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src  = registerName register tmp
-       code__2 dst = code `snocOL` instr dst src
-    in
-    returnNat (Any IntRep code__2)
-trivialUFCode pk instr x
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG (registerRep register)
-                               `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src  = registerName register tmp
-       code__2 dst = code `snocOL` instr dst src
-    in
-    returnNat (Any pk code__2)
-  
--- There is no "remainder" instruction on the PPC, so we have to do
--- it the hard way.
--- The "div" parameter is the division instruction to use (DIVW or DIVWU)
-
-remainderCode :: (Reg -> Reg -> Reg -> Instr)
-    -> StixExpr -> StixExpr -> NatM Register
-remainderCode div x y
-  = getRegister x              `thenNat` \ register1 ->
-    getRegister y              `thenNat` \ register2 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp1 ->
-    getNewRegNCG IntRep                `thenNat` \ tmp2 ->
-    let
-       code1 = registerCode register1 tmp1
-       src1  = registerName register1 tmp1
-       code2 = registerCode register2 tmp2
-       src2  = registerName register2 tmp2
-       code__2 dst = code1 `appOL` code2 `appOL` toOL [
-               div dst src1 src2,
-               MULLW dst dst (RIReg src2),
-               SUBF dst dst src1
-           ]
-    in
-    returnNat (Any IntRep code__2)
-
-#endif /* powerpc_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsubsection{Coercing to/from integer/floating-point...}
-%*                                                                     *
-%************************************************************************
-
-@coerce(Int2FP|FP2Int)@ are more complicated integer/float
-conversions.  We have to store temporaries in memory to move
-between the integer and the floating point register sets.
-
-@coerceDbl2Flt@ and @coerceFlt2Dbl@ are done this way because we
-pretend, on sparc at least, that double and float regs are seperate
-kinds, so the value has to be computed into one kind before being
-explicitly "converted" to live in the other kind.
-
-\begin{code}
-coerceInt2FP :: PrimRep -> StixExpr -> NatM Register
-coerceFP2Int :: PrimRep -> StixExpr -> NatM Register
-
-coerceDbl2Flt :: StixExpr -> NatM Register
-coerceFlt2Dbl :: StixExpr -> NatM Register
-\end{code}
-
-\begin{code}
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if alpha_TARGET_ARCH
-
-coerceInt2FP _ x
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG IntRep                `thenNat` \ reg ->
-    let
-       code = registerCode register reg
-       src  = registerName register reg
-
-       code__2 dst = code . mkSeqInstrs [
-           ST Q src (spRel 0),
-           LD TF dst (spRel 0),
-           CVTxy Q TF dst dst]
-    in
-    returnNat (Any DoubleRep code__2)
-
--------------
-coerceFP2Int x
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG DoubleRep     `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src  = registerName register tmp
-
-       code__2 dst = code . mkSeqInstrs [
-           CVTxy TF Q src tmp,
-           ST TF tmp (spRel 0),
-           LD Q dst (spRel 0)]
-    in
-    returnNat (Any IntRep code__2)
-
-#endif /* alpha_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if i386_TARGET_ARCH
-
-coerceInt2FP pk x
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG IntRep                `thenNat` \ reg ->
-    let
-       code = registerCode register reg
-       src  = registerName register reg
-        opc  = case pk of FloatRep -> GITOF ; DoubleRep -> GITOD
-        code__2 dst = code `snocOL` opc src dst
-    in
-    returnNat (Any pk code__2)
-
-------------
-coerceFP2Int fprep x
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG DoubleRep     `thenNat` \ tmp ->
-    let
-       code = registerCode register tmp
-       src  = registerName register tmp
-       pk   = registerRep register
-
-        opc  = case pk of FloatRep -> GFTOI ; DoubleRep -> GDTOI
-        code__2 dst = code `snocOL` opc src dst
-    in
-    returnNat (Any IntRep code__2)
-
-------------
-coerceDbl2Flt x = panic "MachCode.coerceDbl2Flt: unused on x86"
-coerceFlt2Dbl x = panic "MachCode.coerceFlt2Dbl: unused on x86"
-
-#endif /* i386_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#if sparc_TARGET_ARCH
-
-coerceInt2FP pk x
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG IntRep                `thenNat` \ reg ->
-    let
-       code = registerCode register reg
-       src  = registerName register reg
-
-       code__2 dst = code `appOL` toOL [
-           ST W src (spRel (-2)),
-           LD W (spRel (-2)) dst,
-           FxTOy W (primRepToSize pk) dst dst]
-    in
-    returnNat (Any pk code__2)
-
-------------
-coerceFP2Int fprep x
-  = ASSERT(fprep == DoubleRep || fprep == FloatRep)
-    getRegister x              `thenNat` \ register ->
-    getNewRegNCG fprep         `thenNat` \ reg ->
-    getNewRegNCG FloatRep      `thenNat` \ tmp ->
-    let
-       code = registerCode register reg
-       src  = registerName register reg
-       code__2 dst = code `appOL` toOL [
-           FxTOy (primRepToSize fprep) W src tmp,
-           ST W tmp (spRel (-2)),
-           LD W (spRel (-2)) dst]
-    in
-    returnNat (Any IntRep code__2)
-
-------------
-coerceDbl2Flt x
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG DoubleRep     `thenNat` \ tmp ->
-    let code = registerCode register tmp
-        src  = registerName register tmp
-    in
-        returnNat (Any FloatRep 
-                       (\dst -> code `snocOL` FxTOy DF F src dst)) 
-
-------------
-coerceFlt2Dbl x
-  = getRegister x              `thenNat` \ register ->
-    getNewRegNCG FloatRep      `thenNat` \ tmp ->
-    let code = registerCode register tmp
-        src  = registerName register tmp
-    in
-        returnNat (Any DoubleRep
-                       (\dst -> code `snocOL` FxTOy F DF src dst)) 
-
-#endif /* sparc_TARGET_ARCH */
-
-#if powerpc_TARGET_ARCH
-coerceInt2FP pk x
-  = ASSERT(pk == DoubleRep)
-    getRegister x                  `thenNat` \ register ->
-    getNewRegNCG IntRep                    `thenNat` \ reg ->
-    getNatLabelNCG                 `thenNat` \ lbl ->
-    getNewRegNCG PtrRep            `thenNat` \ itmp ->
-    getNewRegNCG DoubleRep         `thenNat` \ ftmp ->
-    let
-        code = registerCode register reg
-       src  = registerName register reg
-       code__2 dst = code `appOL` toOL [
-               SEGMENT RoDataSegment,
-               LABEL lbl,
-               DATA W [ImmInt 0x43300000, ImmInt 0x80000000],
-               SEGMENT TextSegment,
-               XORIS itmp src (ImmInt 0x8000),
-               ST W itmp (spRel (-1)),
-               LIS itmp (ImmInt 0x4330),
-               ST W itmp (spRel (-2)),
-               LD DF ftmp (spRel (-2)),
-               LIS itmp (HA (ImmCLbl lbl)),
-               LD DF dst (AddrRegImm itmp (LO (ImmCLbl lbl))),
-               FSUB DF dst ftmp dst
-           ]
-    in
-       returnNat (Any DoubleRep code__2)
-
-coerceFP2Int fprep x
-  = ASSERT(fprep == DoubleRep || fprep == FloatRep)
-    getRegister x              `thenNat` \ register ->
-    getNewRegNCG fprep         `thenNat` \ reg ->
-    getNewRegNCG DoubleRep     `thenNat` \ tmp ->
-    let
-       code = registerCode register reg
-       src  = registerName register reg
-       code__2 dst = code `appOL` toOL [
-               -- convert to int in FP reg
-           FCTIWZ tmp src,
-               -- store value (64bit) from FP to stack
-           ST DF tmp (spRel (-2)),
-               -- read low word of value (high word is undefined)
-           LD W dst (spRel (-1))]      
-    in
-    returnNat (Any IntRep code__2)
-coerceDbl2Flt x                = panic "###PPC MachCode.coerceDbl2Flt"
-coerceFlt2Dbl x                = panic "###PPC MachCode.coerceFlt2Dbl"
-#endif /* powerpc_TARGET_ARCH */
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-\end{code}
diff --git a/ghc/compiler/nativeGen/MachCodeGen.hs b/ghc/compiler/nativeGen/MachCodeGen.hs
new file mode 100644 (file)
index 0000000..9285518
--- /dev/null
@@ -0,0 +1,4203 @@
+-----------------------------------------------------------------------------
+--
+-- Generating machine code (instruction selection)
+--
+-- (c) The University of Glasgow 1996-2004
+--
+-----------------------------------------------------------------------------
+
+-- This is a big module, but, if you pay attention to
+-- (a) the sectioning, (b) the type signatures, and
+-- (c) the #if blah_TARGET_ARCH} things, the
+-- structure should not be too overwhelming.
+
+module MachCodeGen ( cmmTopCodeGen, InstrBlock ) where
+
+#include "HsVersions.h"
+#include "nativeGen/NCG.h"
+
+-- NCG stuff:
+import MachInstrs
+import MachRegs
+import NCGMonad
+
+-- Our intermediate code:
+import PprCmm          ( pprExpr )
+import Cmm
+import MachOp
+import CLabel
+
+-- The rest:
+import CmdLineOpts     ( opt_Static )
+import ForeignCall     ( CCallConv(..) )
+import OrdList
+import Pretty
+import Outputable
+import qualified Outputable
+import FastString
+import FastTypes       ( isFastTrue )
+
+#ifdef DEBUG
+import Outputable      ( assertPanic )
+import TRACE           ( trace )
+#endif
+
+import Control.Monad   ( mapAndUnzipM )
+import Maybe           ( fromJust )
+import DATA_BITS
+import DATA_WORD
+
+-- -----------------------------------------------------------------------------
+-- Top-level of the instruction selector
+
+-- | 'InstrBlock's are the insn sequences generated by the insn selectors.
+-- They are really trees of insns to facilitate fast appending, where a
+-- left-to-right traversal (pre-order?) yields the insns in the correct
+-- order.
+
+type InstrBlock = OrdList Instr
+
+cmmTopCodeGen :: CmmTop -> NatM [NatCmmTop]
+cmmTopCodeGen (CmmProc info lab params blocks) = do
+  (nat_blocks,statics) <- mapAndUnzipM basicBlockCodeGen blocks
+  return (CmmProc info lab params (concat nat_blocks) : concat statics)
+cmmTopCodeGen (CmmData sec dat) = do
+  return [CmmData sec dat]  -- no translation, we just use CmmStatic
+
+basicBlockCodeGen :: CmmBasicBlock -> NatM ([NatBasicBlock],[NatCmmTop])
+basicBlockCodeGen (BasicBlock id stmts) = do
+  instrs <- stmtsToInstrs stmts
+  -- code generation may introduce new basic block boundaries, which
+  -- are indicated by the NEWBLOCK instruction.  We must split up the
+  -- instruction stream into basic blocks again.  Also, we extract
+  -- LDATAs here too.
+  let
+       (top,other_blocks,statics) = foldrOL mkBlocks ([],[],[]) instrs
+       
+       mkBlocks (NEWBLOCK id) (instrs,blocks,statics) 
+         = ([], BasicBlock id instrs : blocks, statics)
+       mkBlocks (LDATA sec dat) (instrs,blocks,statics) 
+         = (instrs, blocks, CmmData sec dat:statics)
+       mkBlocks instr (instrs,blocks,statics)
+         = (instr:instrs, blocks, statics)
+  -- in
+  return (BasicBlock id top : other_blocks, statics)
+
+stmtsToInstrs :: [CmmStmt] -> NatM InstrBlock
+stmtsToInstrs stmts
+   = do instrss <- mapM stmtToInstrs stmts
+        return (concatOL instrss)
+
+stmtToInstrs :: CmmStmt -> NatM InstrBlock
+stmtToInstrs stmt = case stmt of
+    CmmNop        -> return nilOL
+    CmmComment s   -> return (unitOL (COMMENT s))
+
+    CmmAssign reg src
+      | isFloatingRep kind -> assignReg_FltCode kind reg src
+      | wordRep == I32 && kind == I64
+                          -> assignReg_I64Code      reg src
+      | otherwise         -> assignReg_IntCode kind reg src
+       where kind = cmmRegRep reg
+
+    CmmStore addr src
+      | isFloatingRep kind -> assignMem_FltCode kind addr src
+      | wordRep == I32 && kind == I64
+                        -> assignMem_I64Code      addr src
+      | otherwise       -> assignMem_IntCode kind addr src
+       where kind = cmmExprRep src
+
+    CmmCall target result_regs args vols
+       -> genCCall target result_regs args vols
+
+    CmmBranch id         -> genBranch id
+    CmmCondBranch arg id  -> genCondJump id arg
+    CmmSwitch arg ids     -> genSwitch arg ids
+    CmmJump arg params   -> genJump arg
+
+-- -----------------------------------------------------------------------------
+-- General things for putting together code sequences
+
+-- Expand CmmRegOff.  ToDo: should we do it this way around, or convert
+-- CmmExprs into CmmRegOff?
+mangleIndexTree :: CmmExpr -> CmmExpr
+mangleIndexTree (CmmRegOff reg off)
+  = CmmMachOp (MO_Add rep) [CmmReg reg, CmmLit (CmmInt (fromIntegral off) rep)]
+  where rep = cmmRegRep reg
+
+-- -----------------------------------------------------------------------------
+--  Code gen for 64-bit arithmetic on 32-bit platforms
+
+{-
+Simple support for generating 64-bit code (ie, 64 bit values and 64
+bit assignments) on 32-bit platforms.  Unlike the main code generator
+we merely shoot for generating working code as simply as possible, and
+pay little attention to code quality.  Specifically, there is no
+attempt to deal cleverly with the fixed-vs-floating register
+distinction; all values are generated into (pairs of) floating
+registers, even if this would mean some redundant reg-reg moves as a
+result.  Only one of the VRegUniques is returned, since it will be
+of the VRegUniqueLo form, and the upper-half VReg can be determined
+by applying getHiVRegFromLo to it.
+-}
+
+data ChildCode64       -- a.k.a "Register64"
+   = ChildCode64 
+        InstrBlock     -- code
+        Reg            -- the lower 32-bit temporary which contains the
+                       -- result; use getHiVRegFromLo to find the other
+                       -- VRegUnique.  Rules of this simplified insn
+                       -- selection game are therefore that the returned
+                       -- Reg may be modified
+
+assignMem_I64Code :: CmmExpr -> CmmExpr -> NatM InstrBlock
+assignReg_I64Code :: CmmReg  -> CmmExpr -> NatM InstrBlock
+iselExpr64        :: CmmExpr -> NatM ChildCode64
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if i386_TARGET_ARCH
+
+assignMem_I64Code addrTree valueTree = do
+  Amode addr addr_code <- getAmode addrTree
+  ChildCode64 vcode rlo <- iselExpr64 valueTree
+  let 
+        rhi = getHiVRegFromLo rlo
+
+        -- Little-endian store
+        mov_lo = MOV I32 (OpReg rlo) (OpAddr addr)
+        mov_hi = MOV I32 (OpReg rhi) (OpAddr (fromJust (addrOffset addr 4)))
+  -- in
+  return (vcode `appOL` addr_code `snocOL` mov_lo `snocOL` mov_hi)
+
+
+assignReg_I64Code (CmmLocal (LocalReg u_dst pk)) valueTree = do
+   ChildCode64 vcode r_src_lo <- iselExpr64 valueTree
+   let 
+         r_dst_lo = mkVReg u_dst I32
+         r_dst_hi = getHiVRegFromLo r_dst_lo
+         r_src_hi = getHiVRegFromLo r_src_lo
+         mov_lo = MOV I32 (OpReg r_src_lo) (OpReg r_dst_lo)
+         mov_hi = MOV I32 (OpReg r_src_hi) (OpReg r_dst_hi)
+   -- in
+   return (
+        vcode `snocOL` mov_lo `snocOL` mov_hi
+     )
+
+assignReg_I64Code lvalue valueTree
+   = panic "assignReg_I64Code(i386): invalid lvalue"
+
+------------
+
+iselExpr64 (CmmLit (CmmInt i _)) = do
+  (rlo,rhi) <- getNewRegPairNat I32
+  let
+       r = fromIntegral (fromIntegral i :: Word32)
+       q = fromIntegral ((fromIntegral i `shiftR` 32) :: Word32)
+       code = toOL [
+               MOV I32 (OpImm (ImmInteger r)) (OpReg rlo),
+               MOV I32 (OpImm (ImmInteger q)) (OpReg rhi)
+               ]
+  -- in
+  return (ChildCode64 code rlo)
+
+iselExpr64 (CmmLoad addrTree I64) = do
+   Amode addr addr_code <- getAmode addrTree
+   (rlo,rhi) <- getNewRegPairNat I32
+   let 
+        mov_lo = MOV I32 (OpAddr addr) (OpReg rlo)
+        mov_hi = MOV I32 (OpAddr (fromJust (addrOffset addr 4))) (OpReg rhi)
+   -- in
+   return (
+            ChildCode64 (addr_code `snocOL` mov_lo `snocOL` mov_hi) 
+                        rlo
+     )
+
+iselExpr64 (CmmReg (CmmLocal (LocalReg vu I64)))
+   = return (ChildCode64 nilOL (mkVReg vu I32))
+         
+-- we handle addition, but rather badly
+iselExpr64 (CmmMachOp (MO_Add _) [e1, CmmLit (CmmInt i _)]) = do
+   ChildCode64 code1 r1lo <- iselExpr64 e1
+   (rlo,rhi) <- getNewRegPairNat I32
+   let
+       r = fromIntegral (fromIntegral i :: Word32)
+       q = fromIntegral ((fromIntegral i `shiftR` 32) :: Word32)
+       r1hi = getHiVRegFromLo r1lo
+       code =  code1 `appOL`
+               toOL [ MOV I32 (OpReg r1lo) (OpReg rlo),
+                      ADD I32 (OpImm (ImmInteger r)) (OpReg rlo),
+                      MOV I32 (OpReg r1hi) (OpReg rhi),
+                      ADC I32 (OpImm (ImmInteger q)) (OpReg rhi) ]
+   -- in
+   return (ChildCode64 code rlo)
+
+iselExpr64 (CmmMachOp (MO_Add _) [e1,e2]) = do
+   ChildCode64 code1 r1lo <- iselExpr64 e1
+   ChildCode64 code2 r2lo <- iselExpr64 e2
+   (rlo,rhi) <- getNewRegPairNat I32
+   let
+       r1hi = getHiVRegFromLo r1lo
+       r2hi = getHiVRegFromLo r2lo
+       code =  code1 `appOL`
+               code2 `appOL`
+               toOL [ MOV I32 (OpReg r1lo) (OpReg rlo),
+                      ADD I32 (OpReg r2lo) (OpReg rlo),
+                      MOV I32 (OpReg r1hi) (OpReg rhi),
+                      ADC I32 (OpReg r2hi) (OpReg rhi) ]
+   -- in
+   return (ChildCode64 code rlo)
+
+iselExpr64 expr
+   = pprPanic "iselExpr64(i386)" (ppr expr)
+
+#endif /* i386_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if sparc_TARGET_ARCH
+
+assignMem_I64Code addrTree valueTree
+   = iselExpr64 valueTree              `thenNat` \ (ChildCode64 vcode vrlo) ->
+     getRegister addrTree              `thenNat` \ register_addr ->
+     getNewRegNat IntRep               `thenNat` \ t_addr ->
+     let rlo = VirtualRegI vrlo
+         rhi = getHiVRegFromLo rlo
+         code_addr = registerCode register_addr t_addr
+         reg_addr  = registerName register_addr t_addr
+         -- Big-endian store
+         mov_hi = ST W rhi (AddrRegImm reg_addr (ImmInt 0))
+         mov_lo = ST W rlo (AddrRegImm reg_addr (ImmInt 4))
+     in
+         return (vcode `appOL` code_addr `snocOL` mov_hi `snocOL` mov_lo)
+
+
+assignReg_I64Code (StixTemp (StixVReg u_dst pk)) valueTree
+   = iselExpr64 valueTree              `thenNat` \ (ChildCode64 vcode vr_src_lo) ->
+     let 
+         r_dst_lo = mkVReg u_dst IntRep
+         r_src_lo = VirtualRegI vr_src_lo
+         r_dst_hi = getHiVRegFromLo r_dst_lo
+         r_src_hi = getHiVRegFromLo r_src_lo
+         mov_lo = mkMOV r_src_lo r_dst_lo
+         mov_hi = mkMOV r_src_hi r_dst_hi
+         mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
+     in
+         return (
+            vcode `snocOL` mov_hi `snocOL` mov_lo
+         )
+assignReg_I64Code lvalue valueTree
+   = pprPanic "assignReg_I64Code(sparc): invalid lvalue"
+              (pprStixReg lvalue)
+
+
+-- Don't delete this -- it's very handy for debugging.
+--iselExpr64 expr 
+--   | trace ("iselExpr64: " ++ showSDoc (pprCmmExpr expr)) False
+--   = panic "iselExpr64(???)"
+
+iselExpr64 (CmmLoad I64 addrTree)
+   = getRegister addrTree              `thenNat` \ register_addr ->
+     getNewRegNat IntRep               `thenNat` \ t_addr ->
+     getNewRegNat IntRep               `thenNat` \ rlo ->
+     let rhi = getHiVRegFromLo rlo
+         code_addr = registerCode register_addr t_addr
+         reg_addr  = registerName register_addr t_addr
+         mov_hi = LD W (AddrRegImm reg_addr (ImmInt 0)) rhi
+         mov_lo = LD W (AddrRegImm reg_addr (ImmInt 4)) rlo
+     in
+         return (
+            ChildCode64 (code_addr `snocOL` mov_hi `snocOL` mov_lo) 
+                        (getVRegUnique rlo)
+         )
+
+iselExpr64 (CmmReg (CmmLocal (LocalReg uq I64)))
+   = getNewRegNat IntRep               `thenNat` \ r_dst_lo ->
+     let r_dst_hi = getHiVRegFromLo r_dst_lo
+         r_src_lo = mkVReg vu IntRep
+         r_src_hi = getHiVRegFromLo r_src_lo
+         mov_lo = mkMOV r_src_lo r_dst_lo
+         mov_hi = mkMOV r_src_hi r_dst_hi
+         mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
+     in
+         return (
+            ChildCode64 (toOL [mov_hi, mov_lo]) (getVRegUnique r_dst_lo)
+         )
+
+iselExpr64 (StCall fn cconv I64 args)
+  = genCCall fn cconv kind args                        `thenNat` \ call ->
+    getNewRegNat IntRep                                `thenNat` \ r_dst_lo ->
+    let r_dst_hi = getHiVRegFromLo r_dst_lo
+        mov_lo = mkMOV o0 r_dst_lo
+        mov_hi = mkMOV o1 r_dst_hi
+        mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
+    in
+    return (
+       ChildCode64 (call `snocOL` mov_hi `snocOL` mov_lo) 
+                   (getVRegUnique r_dst_lo)
+    )
+
+iselExpr64 expr
+   = pprPanic "iselExpr64(sparc)" (pprCmmExpr expr)
+
+#endif /* sparc_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if powerpc_TARGET_ARCH
+
+getI64Amodes :: CmmExpr -> NatM (AddrMode, AddrMode, InstrBlock)
+getI64Amodes addrTree = do
+    Amode hi_addr addr_code <- getAmode addrTree
+    case addrOffset hi_addr 4 of
+        Just lo_addr -> return (hi_addr, lo_addr, addr_code)
+        Nothing      -> do (hi_ptr, code) <- getSomeReg addrTree
+                           return (AddrRegImm hi_ptr (ImmInt 0),
+                                   AddrRegImm hi_ptr (ImmInt 4),
+                                   code)
+
+assignMem_I64Code addrTree valueTree = do
+        (hi_addr, lo_addr, addr_code) <- getI64Amodes addrTree
+       ChildCode64 vcode rlo <- iselExpr64 valueTree
+       let 
+               rhi = getHiVRegFromLo rlo
+
+               -- Big-endian store
+               mov_hi = ST I32 rhi hi_addr
+               mov_lo = ST I32 rlo lo_addr
+       -- in
+       return (vcode `appOL` addr_code `snocOL` mov_lo `snocOL` mov_hi)
+
+assignReg_I64Code (CmmLocal (LocalReg u_dst pk)) valueTree = do
+   ChildCode64 vcode r_src_lo <- iselExpr64 valueTree
+   let 
+         r_dst_lo = mkVReg u_dst I32
+         r_dst_hi = getHiVRegFromLo r_dst_lo
+         r_src_hi = getHiVRegFromLo r_src_lo
+         mov_lo = MR r_dst_lo r_src_lo
+         mov_hi = MR r_dst_hi r_src_hi
+   -- in
+   return (
+        vcode `snocOL` mov_lo `snocOL` mov_hi
+     )
+
+assignReg_I64Code lvalue valueTree
+   = panic "assignReg_I64Code(powerpc): invalid lvalue"
+
+
+-- Don't delete this -- it's very handy for debugging.
+--iselExpr64 expr 
+--   | trace ("iselExpr64: " ++ showSDoc (pprCmmExpr expr)) False
+--   = panic "iselExpr64(???)"
+
+iselExpr64 (CmmLoad addrTree I64) = do
+    (hi_addr, lo_addr, addr_code) <- getI64Amodes addrTree
+    (rlo, rhi) <- getNewRegPairNat I32
+    let mov_hi = LD I32 rhi hi_addr
+        mov_lo = LD I32 rlo lo_addr
+    return $ ChildCode64 (addr_code `snocOL` mov_lo `snocOL` mov_hi) 
+                         rlo
+
+iselExpr64 (CmmReg (CmmLocal (LocalReg vu I64)))
+   = return (ChildCode64 nilOL (mkVReg vu I32))
+
+iselExpr64 (CmmLit (CmmInt i _)) = do
+  (rlo,rhi) <- getNewRegPairNat I32
+  let
+       half0 = fromIntegral (fromIntegral i :: Word16)
+       half1 = fromIntegral ((fromIntegral i `shiftR` 16) :: Word16)
+       half2 = fromIntegral ((fromIntegral i `shiftR` 32) :: Word16)
+       half3 = fromIntegral ((fromIntegral i `shiftR` 48) :: Word16)
+       
+       code = toOL [
+               LIS rlo (ImmInt half1),
+               OR rlo rlo (RIImm $ ImmInt half0),
+               LIS rhi (ImmInt half3),
+               OR rlo rlo (RIImm $ ImmInt half2)
+               ]
+  -- in
+  return (ChildCode64 code rlo)
+
+iselExpr64 (CmmMachOp (MO_Add _) [e1,e2]) = do
+   ChildCode64 code1 r1lo <- iselExpr64 e1
+   ChildCode64 code2 r2lo <- iselExpr64 e2
+   (rlo,rhi) <- getNewRegPairNat I32
+   let
+       r1hi = getHiVRegFromLo r1lo
+       r2hi = getHiVRegFromLo r2lo
+       code =  code1 `appOL`
+               code2 `appOL`
+               toOL [ ADDC rlo r1lo r2lo,
+                      ADDE rhi r1hi r2hi ]
+   -- in
+   return (ChildCode64 code rlo)
+
+iselExpr64 expr
+   = pprPanic "iselExpr64(powerpc)" (ppr expr)
+
+#endif /* powerpc_TARGET_ARCH */
+
+
+-- -----------------------------------------------------------------------------
+-- The 'Register' type
+
+-- 'Register's passed up the tree.  If the stix code forces the register
+-- to live in a pre-decided machine register, it comes out as @Fixed@;
+-- otherwise, it comes out as @Any@, and the parent can decide which
+-- register to put it in.
+
+data Register
+  = Fixed   MachRep Reg InstrBlock
+  | Any            MachRep (Reg -> InstrBlock)
+
+swizzleRegisterRep :: Register -> MachRep -> Register
+swizzleRegisterRep (Fixed _ reg code) rep = Fixed rep reg code
+swizzleRegisterRep (Any _ codefn)     rep = Any rep codefn
+
+
+-- -----------------------------------------------------------------------------
+-- Grab the Reg for a CmmReg
+
+getRegisterReg :: CmmReg -> Reg
+
+getRegisterReg (CmmLocal (LocalReg u pk))
+  = mkVReg u pk
+
+getRegisterReg (CmmGlobal mid)
+  = case get_GlobalReg_reg_or_addr mid of
+       Left (RealReg rrno) -> RealReg rrno
+       _other -> pprPanic "getRegisterReg-memory" (ppr $ CmmGlobal mid)
+          -- By this stage, the only MagicIds remaining should be the
+          -- ones which map to a real machine register on this
+          -- platform.  Hence ...
+
+
+-- -----------------------------------------------------------------------------
+-- Generate code to get a subtree into a Register
+
+-- Don't delete this -- it's very handy for debugging.
+--getRegister expr 
+--   | trace ("getRegister: " ++ showSDoc (pprCmmExpr expr)) False
+--   = panic "getRegister(???)"
+
+getRegister :: CmmExpr -> NatM Register
+
+getRegister (CmmReg reg) 
+  = return (Fixed (cmmRegRep reg) (getRegisterReg reg) nilOL)
+
+getRegister tree@(CmmRegOff _ _) 
+  = getRegister (mangleIndexTree tree)
+
+-- end of machine-"independent" bit; here we go on the rest...
+
+#if alpha_TARGET_ARCH
+
+getRegister (StDouble d)
+  = getBlockIdNat                  `thenNat` \ lbl ->
+    getNewRegNat PtrRep            `thenNat` \ tmp ->
+    let code dst = mkSeqInstrs [
+           LDATA RoDataSegment lbl [
+                   DATA TF [ImmLab (rational d)]
+               ],
+           LDA tmp (AddrImm (ImmCLbl lbl)),
+           LD TF dst (AddrReg tmp)]
+    in
+       return (Any F64 code)
+
+getRegister (StPrim primop [x]) -- unary PrimOps
+  = case primop of
+      IntNegOp -> trivialUCode (NEG Q False) x
+
+      NotOp    -> trivialUCode NOT x
+
+      FloatNegOp  -> trivialUFCode FloatRep  (FNEG TF) x
+      DoubleNegOp -> trivialUFCode F64 (FNEG TF) x
+
+      OrdOp -> coerceIntCode IntRep x
+      ChrOp -> chrCode x
+
+      Float2IntOp  -> coerceFP2Int    x
+      Int2FloatOp  -> coerceInt2FP pr x
+      Double2IntOp -> coerceFP2Int    x
+      Int2DoubleOp -> coerceInt2FP pr x
+
+      Double2FloatOp -> coerceFltCode x
+      Float2DoubleOp -> coerceFltCode x
+
+      other_op -> getRegister (StCall fn CCallConv F64 [x])
+       where
+         fn = case other_op of
+                FloatExpOp    -> FSLIT("exp")
+                FloatLogOp    -> FSLIT("log")
+                FloatSqrtOp   -> FSLIT("sqrt")
+                FloatSinOp    -> FSLIT("sin")
+                FloatCosOp    -> FSLIT("cos")
+                FloatTanOp    -> FSLIT("tan")
+                FloatAsinOp   -> FSLIT("asin")
+                FloatAcosOp   -> FSLIT("acos")
+                FloatAtanOp   -> FSLIT("atan")
+                FloatSinhOp   -> FSLIT("sinh")
+                FloatCoshOp   -> FSLIT("cosh")
+                FloatTanhOp   -> FSLIT("tanh")
+                DoubleExpOp   -> FSLIT("exp")
+                DoubleLogOp   -> FSLIT("log")
+                DoubleSqrtOp  -> FSLIT("sqrt")
+                DoubleSinOp   -> FSLIT("sin")
+                DoubleCosOp   -> FSLIT("cos")
+                DoubleTanOp   -> FSLIT("tan")
+                DoubleAsinOp  -> FSLIT("asin")
+                DoubleAcosOp  -> FSLIT("acos")
+                DoubleAtanOp  -> FSLIT("atan")
+                DoubleSinhOp  -> FSLIT("sinh")
+                DoubleCoshOp  -> FSLIT("cosh")
+                DoubleTanhOp  -> FSLIT("tanh")
+  where
+    pr = panic "MachCode.getRegister: no primrep needed for Alpha"
+
+getRegister (StPrim primop [x, y]) -- dyadic PrimOps
+  = case primop of
+      CharGtOp -> trivialCode (CMP LTT) y x
+      CharGeOp -> trivialCode (CMP LE) y x
+      CharEqOp -> trivialCode (CMP EQQ) x y
+      CharNeOp -> int_NE_code x y
+      CharLtOp -> trivialCode (CMP LTT) x y
+      CharLeOp -> trivialCode (CMP LE) x y
+
+      IntGtOp  -> trivialCode (CMP LTT) y x
+      IntGeOp  -> trivialCode (CMP LE) y x
+      IntEqOp  -> trivialCode (CMP EQQ) x y
+      IntNeOp  -> int_NE_code x y
+      IntLtOp  -> trivialCode (CMP LTT) x y
+      IntLeOp  -> trivialCode (CMP LE) x y
+
+      WordGtOp -> trivialCode (CMP ULT) y x
+      WordGeOp -> trivialCode (CMP ULE) x y
+      WordEqOp -> trivialCode (CMP EQQ)  x y
+      WordNeOp -> int_NE_code x y
+      WordLtOp -> trivialCode (CMP ULT) x y
+      WordLeOp -> trivialCode (CMP ULE) x y
+
+      AddrGtOp -> trivialCode (CMP ULT) y x
+      AddrGeOp -> trivialCode (CMP ULE) y x
+      AddrEqOp -> trivialCode (CMP EQQ)  x y
+      AddrNeOp -> int_NE_code x y
+      AddrLtOp -> trivialCode (CMP ULT) x y
+      AddrLeOp -> trivialCode (CMP ULE) x y
+       
+      FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
+      FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
+      FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
+      FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
+      FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
+      FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
+
+      DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
+      DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
+      DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
+      DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
+      DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
+      DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
+
+      IntAddOp  -> trivialCode (ADD Q False) x y
+      IntSubOp  -> trivialCode (SUB Q False) x y
+      IntMulOp  -> trivialCode (MUL Q False) x y
+      IntQuotOp -> trivialCode (DIV Q False) x y
+      IntRemOp  -> trivialCode (REM Q False) x y
+
+      WordAddOp  -> trivialCode (ADD Q False) x y
+      WordSubOp  -> trivialCode (SUB Q False) x y
+      WordMulOp  -> trivialCode (MUL Q False) x y
+      WordQuotOp -> trivialCode (DIV Q True) x y
+      WordRemOp  -> trivialCode (REM Q True) x y
+
+      FloatAddOp -> trivialFCode  FloatRep (FADD TF) x y
+      FloatSubOp -> trivialFCode  FloatRep (FSUB TF) x y
+      FloatMulOp -> trivialFCode  FloatRep (FMUL TF) x y
+      FloatDivOp -> trivialFCode  FloatRep (FDIV TF) x y
+
+      DoubleAddOp -> trivialFCode  F64 (FADD TF) x y
+      DoubleSubOp -> trivialFCode  F64 (FSUB TF) x y
+      DoubleMulOp -> trivialFCode  F64 (FMUL TF) x y
+      DoubleDivOp -> trivialFCode  F64 (FDIV TF) x y
+
+      AddrAddOp  -> trivialCode (ADD Q False) x y
+      AddrSubOp  -> trivialCode (SUB Q False) x y
+      AddrRemOp  -> trivialCode (REM Q True) x y
+
+      AndOp  -> trivialCode AND x y
+      OrOp   -> trivialCode OR  x y
+      XorOp  -> trivialCode XOR x y
+      SllOp  -> trivialCode SLL x y
+      SrlOp  -> trivialCode SRL x y
+
+      ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
+      ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
+      ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
+
+      FloatPowerOp  -> getRegister (StCall FSLIT("pow") CCallConv F64 [x,y])
+      DoublePowerOp -> getRegister (StCall FSLIT("pow") CCallConv F64 [x,y])
+  where
+    {- ------------------------------------------------------------
+       Some bizarre special code for getting condition codes into
+       registers.  Integer non-equality is a test for equality
+       followed by an XOR with 1.  (Integer comparisons always set
+       the result register to 0 or 1.)  Floating point comparisons of
+       any kind leave the result in a floating point register, so we
+       need to wrangle an integer register out of things.
+    -}
+    int_NE_code :: StixTree -> StixTree -> NatM Register
+
+    int_NE_code x y
+      = trivialCode (CMP EQQ) x y      `thenNat` \ register ->
+       getNewRegNat IntRep             `thenNat` \ tmp ->
+       let
+           code = registerCode register tmp
+           src  = registerName register tmp
+           code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
+       in
+       return (Any IntRep code__2)
+
+    {- ------------------------------------------------------------
+       Comments for int_NE_code also apply to cmpF_code
+    -}
+    cmpF_code
+       :: (Reg -> Reg -> Reg -> Instr)
+       -> Cond
+       -> StixTree -> StixTree
+       -> NatM Register
+
+    cmpF_code instr cond x y
+      = trivialFCode pr instr x y      `thenNat` \ register ->
+       getNewRegNat F64                `thenNat` \ tmp ->
+       getBlockIdNat                   `thenNat` \ lbl ->
+       let
+           code = registerCode register tmp
+           result  = registerName register tmp
+
+           code__2 dst = code . mkSeqInstrs [
+               OR zeroh (RIImm (ImmInt 1)) dst,
+               BF cond  result (ImmCLbl lbl),
+               OR zeroh (RIReg zeroh) dst,
+               NEWBLOCK lbl]
+       in
+       return (Any IntRep code__2)
+      where
+       pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
+      ------------------------------------------------------------
+
+getRegister (CmmLoad pk mem)
+  = getAmode mem                   `thenNat` \ amode ->
+    let
+       code = amodeCode amode
+       src   = amodeAddr amode
+       size = primRepToSize pk
+       code__2 dst = code . mkSeqInstr (LD size dst src)
+    in
+    return (Any pk code__2)
+
+getRegister (StInt i)
+  | fits8Bits i
+  = let
+       code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
+    in
+    return (Any IntRep code)
+  | otherwise
+  = let
+       code dst = mkSeqInstr (LDI Q dst src)
+    in
+    return (Any IntRep code)
+  where
+    src = ImmInt (fromInteger i)
+
+getRegister leaf
+  | isJust imm
+  = let
+       code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
+    in
+    return (Any PtrRep code)
+  where
+    imm = maybeImm leaf
+    imm__2 = case imm of Just x -> x
+
+#endif /* alpha_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if i386_TARGET_ARCH
+
+getRegister (CmmLit (CmmFloat f F32)) = do
+    lbl <- getNewLabelNat
+    let code dst = toOL [
+           LDATA ReadOnlyData
+                       [CmmDataLabel lbl,
+                        CmmStaticLit (CmmFloat f F32)],
+           GLD F32 (ImmAddr (ImmCLbl lbl) 0) dst
+           ]
+    -- in
+    return (Any F32 code)
+
+
+getRegister (CmmLit (CmmFloat d F64))
+  | d == 0.0
+  = let code dst = unitOL (GLDZ dst)
+    in  return (Any F64 code)
+
+  | d == 1.0
+  = let code dst = unitOL (GLD1 dst)
+    in  return (Any F64 code)
+
+  | otherwise = do
+    lbl <- getNewLabelNat
+    let code dst = toOL [
+           LDATA ReadOnlyData
+                       [CmmDataLabel lbl,
+                        CmmStaticLit (CmmFloat d F64)],
+           GLD F64 (ImmAddr (ImmCLbl lbl) 0) dst
+           ]
+    -- in
+    return (Any F64 code)
+
+
+-- catch simple cases of zero- or sign-extended load
+getRegister (CmmMachOp (MO_U_Conv I8 I32) [CmmLoad addr _]) = do
+  code <- intLoadCode (MOVZxL I8) addr
+  return (Any I32 code)
+
+getRegister (CmmMachOp (MO_S_Conv I8 I32) [CmmLoad addr _]) = do
+  code <- intLoadCode (MOVSxL I8) addr
+  return (Any I32 code)
+
+getRegister (CmmMachOp (MO_U_Conv I16 I32) [CmmLoad addr _]) = do
+  code <- intLoadCode (MOVZxL I16) addr
+  return (Any I32 code)
+
+getRegister (CmmMachOp (MO_S_Conv I16 I32) [CmmLoad addr _]) = do
+  code <- intLoadCode (MOVSxL I16) addr
+  return (Any I32 code)
+
+
+getRegister (CmmMachOp mop [x]) -- unary MachOps
+  = case mop of
+      MO_S_Neg F32 -> trivialUFCode F32 (GNEG F32) x
+      MO_S_Neg F64 -> trivialUFCode F64 (GNEG F64) x
+
+      MO_S_Neg rep -> trivialUCode rep (NEGI rep) x
+      MO_Not rep   -> trivialUCode rep (NOT  rep) x
+
+      -- Nop conversions
+      -- TODO: these are only nops if the arg is not a fixed register that
+      -- can't be byte-addressed.
+      MO_U_Conv I32 I8  -> conversionNop I32 x
+      MO_S_Conv I32 I8  -> conversionNop I32 x
+      MO_U_Conv I16 I8  -> conversionNop I16 x
+      MO_S_Conv I16 I8  -> conversionNop I16 x
+      MO_U_Conv I32 I16 -> conversionNop I32 x
+      MO_S_Conv I32 I16 -> conversionNop I32 x
+      MO_U_Conv rep1 rep2 | rep1 == rep2 -> conversionNop rep1 x
+      MO_S_Conv rep1 rep2 | rep1 == rep2 -> conversionNop rep1 x
+
+      -- widenings
+      MO_U_Conv I8  I32 -> integerExtend I8  I32 MOVZxL x
+      MO_U_Conv I16 I32 -> integerExtend I16 I32 MOVZxL x
+      MO_U_Conv I8  I16 -> integerExtend I8  I16 MOVZxL x
+
+      MO_S_Conv I8  I32 -> integerExtend I8  I32 MOVSxL x
+      MO_S_Conv I16 I32 -> integerExtend I16 I32 MOVSxL x
+      MO_S_Conv I8  I16 -> integerExtend I8  I16 MOVSxL x
+
+      MO_S_Conv F32 F64 -> conversionNop F64 x
+      MO_S_Conv F64 F32 -> conversionNop F32 x
+      MO_S_Conv from to
+       | isFloatingRep from -> coerceFP2Int from to x
+       | isFloatingRep to   -> coerceInt2FP from to x
+
+   where
+       -- signed or unsigned extension.
+       integerExtend from to instr expr = do
+           (reg,e_code) <- if from == I8 then getByteReg expr
+                                         else getSomeReg expr
+           let 
+               code dst = 
+                 e_code `snocOL`
+                 instr from (OpReg reg) (OpReg dst)
+           return (Any to code)
+
+        conversionNop new_rep expr
+            = do e_code <- getRegister expr
+                 return (swizzleRegisterRep e_code new_rep)
+
+
+getRegister e@(CmmMachOp mop [x, y]) -- dyadic MachOps
+  = ASSERT2(cmmExprRep x /= I8, pprExpr e)
+    case mop of
+      MO_Eq F32   -> condFltReg EQQ x y
+      MO_Ne F32   -> condFltReg NE x y
+      MO_S_Gt F32 -> condFltReg GTT x y
+      MO_S_Ge F32 -> condFltReg GE x y
+      MO_S_Lt F32 -> condFltReg LTT x y
+      MO_S_Le F32 -> condFltReg LE x y
+
+      MO_Eq F64   -> condFltReg EQQ x y
+      MO_Ne F64   -> condFltReg NE x y
+      MO_S_Gt F64 -> condFltReg GTT x y
+      MO_S_Ge F64 -> condFltReg GE x y
+      MO_S_Lt F64 -> condFltReg LTT x y
+      MO_S_Le F64 -> condFltReg LE x y
+
+      MO_Eq rep   -> condIntReg EQQ x y
+      MO_Ne rep   -> condIntReg NE x y
+
+      MO_S_Gt rep -> condIntReg GTT x y
+      MO_S_Ge rep -> condIntReg GE x y
+      MO_S_Lt rep -> condIntReg LTT x y
+      MO_S_Le rep -> condIntReg LE x y
+
+      MO_U_Gt rep -> condIntReg GU  x y
+      MO_U_Ge rep -> condIntReg GEU x y
+      MO_U_Lt rep -> condIntReg LU  x y
+      MO_U_Le rep -> condIntReg LEU x y
+
+      MO_Add F32 -> trivialFCode F32  GADD x y
+      MO_Sub F32 -> trivialFCode F32  GSUB x y
+
+      MO_Add F64 -> trivialFCode F64 GADD x y
+      MO_Sub F64 -> trivialFCode F64 GSUB x y
+
+      MO_S_Quot F32 -> trivialFCode  F32  GDIV x y
+      MO_S_Quot F64 -> trivialFCode F64 GDIV x y
+
+      MO_Add rep -> add_code rep x y
+      MO_Sub rep -> sub_code rep x y
+
+      MO_S_Quot rep -> div_code rep True  True  x y
+      MO_S_Rem  rep -> div_code rep True  False x y
+      MO_U_Quot rep -> div_code rep False True  x y
+      MO_U_Rem  rep -> div_code rep False False x y
+
+      MO_Mul   F32 -> trivialFCode F32 GMUL x y
+      MO_Mul   F64 -> trivialFCode F64 GMUL x y
+      MO_Mul   rep -> let op = IMUL rep in 
+                     trivialCode rep op (Just op) x y
+
+      MO_S_MulMayOflo rep -> imulMayOflo rep x y
+
+      MO_And rep -> let op = AND rep in 
+                   trivialCode rep op (Just op) x y
+      MO_Or  rep -> let op = OR  rep in
+                   trivialCode rep op (Just op) x y
+      MO_Xor rep -> let op = XOR rep in
+                   trivialCode rep op (Just op) x y
+
+       {- Shift ops on x86s have constraints on their source, it
+          either has to be Imm, CL or 1
+           => trivialCode is not restrictive enough (sigh.)
+       -}         
+      MO_Shl rep   -> shift_code rep (SHL rep) x y {-False-}
+      MO_U_Shr rep -> shift_code rep (SHR rep) x y {-False-}
+      MO_S_Shr rep -> shift_code rep (SAR rep) x y {-False-}
+
+      other -> pprPanic "getRegister(x86) - binary CmmMachOp (1)" (pprMachOp mop)
+  where
+    --------------------
+    imulMayOflo :: MachRep -> CmmExpr -> CmmExpr -> NatM Register
+    imulMayOflo I32 a b = do
+         res_lo <- getNewRegNat I32
+         res_hi <- getNewRegNat I32
+         (a_reg, a_code) <- getNonClobberedReg a
+         (b_reg, b_code) <- getSomeReg   b
+         let 
+             code dst = a_code `appOL` b_code `appOL`
+                        toOL [
+                           MOV I32 (OpReg a_reg) (OpReg res_hi),
+                           MOV I32 (OpReg b_reg) (OpReg res_lo),
+                           IMUL64 res_hi res_lo,               -- result in res_hi:res_lo
+                           SAR I32 (OpImm (ImmInt 31)) (OpReg res_lo), -- sign extend lower part
+                           SUB I32 (OpReg res_hi) (OpReg res_lo),      -- compare against upper
+                           MOV I32 (OpReg res_lo) (OpReg dst)
+                           -- dst==0 if high part == sign extended low part
+                        ]
+         -- in
+        return (Any I32 code)
+
+    --------------------
+    shift_code :: MachRep
+              -> (Operand -> Operand -> Instr)
+              -> CmmExpr
+              -> CmmExpr
+              -> NatM Register
+
+    {- Case1: shift length as immediate -}
+    shift_code rep instr x y@(CmmLit lit) = do
+         x_code <- getAnyReg x
+         let
+              code dst
+                 = x_code dst `snocOL` 
+                   instr (OpImm (litToImm lit)) (OpReg dst)
+         -- in
+         return (Any rep code)
+        
+    {- Case2: shift length is complex (non-immediate) -}
+    shift_code rep instr x y{-amount-} = do
+        (x_reg, x_code) <- getNonClobberedReg x
+        y_code <- getAnyReg y
+       let 
+          code = x_code `appOL`
+                 y_code ecx `snocOL`
+                 instr (OpReg ecx) (OpReg x_reg)
+        -- in
+        return (Fixed rep x_reg code)
+
+    --------------------
+    add_code :: MachRep -> CmmExpr -> CmmExpr -> NatM Register
+    add_code rep x (CmmLit (CmmInt y _)) = add_int rep x y
+    add_code rep x y = trivialCode rep (ADD rep) (Just (ADD rep)) x y
+
+    --------------------
+    sub_code :: MachRep -> CmmExpr -> CmmExpr -> NatM Register
+    sub_code rep x (CmmLit (CmmInt y _)) = add_int rep x (-y)
+    sub_code rep x y = trivialCode rep (SUB rep) Nothing x y
+
+    -- our three-operand add instruction:
+    add_int rep x y = do
+       (x_reg, x_code) <- getSomeReg x
+       let
+           imm = ImmInt (fromInteger y)
+           code dst
+               = x_code `snocOL`
+                LEA rep
+                       (OpAddr (AddrBaseIndex (Just x_reg) Nothing imm))
+                        (OpReg dst)
+       -- 
+       return (Any rep code)
+
+    ----------------------
+    div_code rep signed quotient x y = do
+          (y_op, y_code) <- getOperand y -- cannot be clobbered
+          x_code <- getAnyReg x
+          let
+            widen | signed    = CLTD
+                  | otherwise = XOR rep (OpReg edx) (OpReg edx)
+
+            instr | signed    = IDIV
+                  | otherwise = DIV
+
+            code = y_code `appOL`
+                   x_code eax `appOL`
+                   toOL [widen, instr rep y_op]
+
+            result | quotient  = eax
+                   | otherwise = edx
+
+          -- in
+           return (Fixed rep result code)
+
+
+
+getRegister (CmmLoad mem pk)
+  | isFloatingRep pk
+  = do
+    Amode src mem_code <- getAmode mem
+    let
+       code dst = mem_code `snocOL` 
+                  GLD pk src dst
+    --
+    return (Any pk code)
+
+getRegister (CmmLoad mem pk)
+  | pk /= I64
+  = do 
+    code <- intLoadCode (instr pk) mem
+    return (Any pk code)
+  where
+       instr I8  = MOVZxL pk
+       instr I16 = MOV I16
+       instr I32 = MOV I32
+       -- we always zero-extend 8-bit loads, if we
+       -- can't think of anything better.  This is because
+       -- we can't guarantee access to an 8-bit variant of every register
+       -- (esi and edi don't have 8-bit variants), so to make things
+       -- simpler we do our 8-bit arithmetic with full 32-bit registers.
+
+getRegister (CmmLit (CmmInt 0 rep))
+  = let
+       code dst 
+           = unitOL (XOR rep (OpReg dst) (OpReg dst))
+    in
+       return (Any rep code)
+
+getRegister (CmmLit lit)
+  = let 
+       rep = cmmLitRep lit
+       imm = litToImm lit
+       code dst = unitOL (MOV rep (OpImm imm) (OpReg dst))
+    in
+       return (Any rep code)
+
+getRegister other = panic "getRegister(x86)"
+
+
+intLoadCode :: (Operand -> Operand -> Instr) -> CmmExpr
+   -> NatM (Reg -> InstrBlock)
+intLoadCode instr mem = do
+  Amode src mem_code <- getAmode mem
+  return (\dst -> mem_code `snocOL` instr (OpAddr src) (OpReg dst))
+
+-- Compute an expression into *any* register, adding the appropriate
+-- move instruction if necessary.
+getAnyReg :: CmmExpr -> NatM (Reg -> InstrBlock)
+getAnyReg expr = do
+  r <- getRegister expr
+  anyReg r
+
+anyReg :: Register -> NatM (Reg -> InstrBlock)
+anyReg (Any _ code)          = return code
+anyReg (Fixed rep reg fcode) = return (\dst -> fcode `snocOL` reg2reg rep reg dst)
+
+-- The dual to getAnyReg: compute an expression into a register, but
+-- we don't mind which one it is.
+getSomeReg :: CmmExpr -> NatM (Reg, InstrBlock)
+getSomeReg expr = do
+  r <- getRegister expr
+  case r of
+    Any rep code -> do
+       tmp <- getNewRegNat rep
+       return (tmp, code tmp)
+    Fixed _ reg code -> 
+       return (reg, code)
+
+-- A bit like getSomeReg, but we want a reg that can be byte-addressed.
+-- Fixed registers might not be byte-addressable, so we make sure we've
+-- got a temporary, inserting an extra reg copy if necessary.
+getByteReg :: CmmExpr -> NatM (Reg, InstrBlock)
+getByteReg expr = do
+  r <- getRegister expr
+  case r of
+    Any rep code -> do
+       tmp <- getNewRegNat rep
+       return (tmp, code tmp)
+    Fixed rep reg code 
+       | isVirtualReg reg -> return (reg,code)
+       | otherwise -> do
+           tmp <- getNewRegNat rep
+           return (tmp, code `snocOL` reg2reg rep reg tmp)
+       -- ToDo: could optimise slightly by checking for byte-addressable
+       -- real registers, but that will happen very rarely if at all.
+
+-- Another variant: this time we want the result in a register that cannot
+-- be modified by code to evaluate an arbitrary expression.
+getNonClobberedReg :: CmmExpr -> NatM (Reg, InstrBlock)
+getNonClobberedReg expr = do
+  r <- getRegister expr
+  case r of
+    Any rep code -> do
+       tmp <- getNewRegNat rep
+       return (tmp, code tmp)
+    Fixed rep reg code
+       -- only free regs can be clobbered
+       | RealReg rr <- reg, isFastTrue (freeReg rr) -> do
+               tmp <- getNewRegNat rep
+               return (tmp, code `snocOL` reg2reg rep reg tmp)
+       | otherwise -> 
+               return (reg, code)
+
+reg2reg :: MachRep -> Reg -> Reg -> Instr
+reg2reg rep src dst 
+  | isFloatingRep rep = GMOV src dst
+  | otherwise        = MOV rep (OpReg src) (OpReg dst)
+
+#endif /* i386_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if sparc_TARGET_ARCH
+
+getRegister (StFloat d)
+  = getBlockIdNat                  `thenNat` \ lbl ->
+    getNewRegNat PtrRep            `thenNat` \ tmp ->
+    let code dst = toOL [
+           SEGMENT DataSegment,
+           NEWBLOCK lbl,
+           DATA F [ImmFloat d],
+           SEGMENT TextSegment,
+           SETHI (HI (ImmCLbl lbl)) tmp,
+           LD F (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
+    in
+       return (Any F32 code)
+
+getRegister (StDouble d)
+  = getBlockIdNat                  `thenNat` \ lbl ->
+    getNewRegNat PtrRep            `thenNat` \ tmp ->
+    let code dst = toOL [
+           SEGMENT DataSegment,
+           NEWBLOCK lbl,
+           DATA DF [ImmDouble d],
+           SEGMENT TextSegment,
+           SETHI (HI (ImmCLbl lbl)) tmp,
+           LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
+    in
+       return (Any F64 code)
+
+
+getRegister (CmmMachOp mop [x]) -- unary PrimOps
+  = case mop of
+      MO_NatS_Neg      -> trivialUCode (SUB False False g0) x
+      MO_Nat_Not       -> trivialUCode (XNOR False g0) x
+      MO_32U_to_8U     -> trivialCode (AND False) x (StInt 255)
+
+      MO_F32_Neg       -> trivialUFCode F32 (FNEG F) x
+      MO_F64_Neg       -> trivialUFCode F64 (FNEG DF) x
+
+      MO_F64_to_Flt    -> coerceDbl2Flt x
+      MO_F32_to_Dbl    -> coerceFlt2Dbl x
+
+      MO_F32_to_NatS   -> coerceFP2Int F32 x
+      MO_NatS_to_Flt   -> coerceInt2FP F32 x
+      MO_F64_to_NatS   -> coerceFP2Int F64 x
+      MO_NatS_to_Dbl   -> coerceInt2FP F64 x
+
+      -- Conversions which are a nop on sparc
+      MO_32U_to_NatS   -> conversionNop IntRep   x
+      MO_32S_to_NatS  -> conversionNop IntRep   x
+      MO_NatS_to_32U   -> conversionNop WordRep  x
+      MO_32U_to_NatU   -> conversionNop WordRep  x
+
+      MO_NatU_to_NatS -> conversionNop IntRep    x
+      MO_NatS_to_NatU -> conversionNop WordRep   x
+      MO_NatP_to_NatU -> conversionNop WordRep   x
+      MO_NatU_to_NatP -> conversionNop PtrRep    x
+      MO_NatS_to_NatP -> conversionNop PtrRep    x
+      MO_NatP_to_NatS -> conversionNop IntRep    x
+
+      -- sign-extending widenings
+      MO_8U_to_32U    -> integerExtend False 24 x
+      MO_8U_to_NatU   -> integerExtend False 24 x
+      MO_8S_to_NatS   -> integerExtend True  24 x
+      MO_16U_to_NatU  -> integerExtend False 16 x
+      MO_16S_to_NatS  -> integerExtend True  16 x
+
+      other_op ->
+        let fixed_x = if   is_float_op  -- promote to double
+                      then CmmMachOp MO_F32_to_Dbl [x]
+                      else x
+       in
+       getRegister (StCall (Left fn) CCallConv F64 [fixed_x])
+    where
+        integerExtend signed nBits x
+           = getRegister (
+                CmmMachOp (if signed then MO_Nat_Sar else MO_Nat_Shr) 
+                         [CmmMachOp MO_Nat_Shl [x, StInt nBits], StInt nBits]
+             )
+        conversionNop new_rep expr
+            = getRegister expr         `thenNat` \ e_code ->
+              return (swizzleRegisterRep e_code new_rep)
+
+       (is_float_op, fn)
+         = case mop of
+             MO_F32_Exp    -> (True,  FSLIT("exp"))
+             MO_F32_Log    -> (True,  FSLIT("log"))
+             MO_F32_Sqrt   -> (True,  FSLIT("sqrt"))
+
+             MO_F32_Sin    -> (True,  FSLIT("sin"))
+             MO_F32_Cos    -> (True,  FSLIT("cos"))
+             MO_F32_Tan    -> (True,  FSLIT("tan"))
+
+             MO_F32_Asin   -> (True,  FSLIT("asin"))
+             MO_F32_Acos   -> (True,  FSLIT("acos"))
+             MO_F32_Atan   -> (True,  FSLIT("atan"))
+
+             MO_F32_Sinh   -> (True,  FSLIT("sinh"))
+             MO_F32_Cosh   -> (True,  FSLIT("cosh"))
+             MO_F32_Tanh   -> (True,  FSLIT("tanh"))
+
+             MO_F64_Exp    -> (False, FSLIT("exp"))
+             MO_F64_Log    -> (False, FSLIT("log"))
+             MO_F64_Sqrt   -> (False, FSLIT("sqrt"))
+
+             MO_F64_Sin    -> (False, FSLIT("sin"))
+             MO_F64_Cos    -> (False, FSLIT("cos"))
+             MO_F64_Tan    -> (False, FSLIT("tan"))
+
+             MO_F64_Asin   -> (False, FSLIT("asin"))
+             MO_F64_Acos   -> (False, FSLIT("acos"))
+             MO_F64_Atan   -> (False, FSLIT("atan"))
+
+             MO_F64_Sinh   -> (False, FSLIT("sinh"))
+             MO_F64_Cosh   -> (False, FSLIT("cosh"))
+             MO_F64_Tanh   -> (False, FSLIT("tanh"))
+
+              other -> pprPanic "getRegister(sparc) - binary CmmMachOp (2)" 
+                                (pprMachOp mop)
+
+
+getRegister (CmmMachOp mop [x, y]) -- dyadic PrimOps
+  = case mop of
+      MO_32U_Gt  -> condIntReg GTT x y
+      MO_32U_Ge  -> condIntReg GE x y
+      MO_32U_Eq  -> condIntReg EQQ x y
+      MO_32U_Ne  -> condIntReg NE x y
+      MO_32U_Lt  -> condIntReg LTT x y
+      MO_32U_Le  -> condIntReg LE x y
+
+      MO_Nat_Eq   -> condIntReg EQQ x y
+      MO_Nat_Ne   -> condIntReg NE x y
+
+      MO_NatS_Gt  -> condIntReg GTT x y
+      MO_NatS_Ge  -> condIntReg GE x y
+      MO_NatS_Lt  -> condIntReg LTT x y
+      MO_NatS_Le  -> condIntReg LE x y
+
+      MO_NatU_Gt  -> condIntReg GU  x y
+      MO_NatU_Ge  -> condIntReg GEU x y
+      MO_NatU_Lt  -> condIntReg LU  x y
+      MO_NatU_Le  -> condIntReg LEU x y
+
+      MO_F32_Gt -> condFltReg GTT x y
+      MO_F32_Ge -> condFltReg GE x y
+      MO_F32_Eq -> condFltReg EQQ x y
+      MO_F32_Ne -> condFltReg NE x y
+      MO_F32_Lt -> condFltReg LTT x y
+      MO_F32_Le -> condFltReg LE x y
+
+      MO_F64_Gt -> condFltReg GTT x y
+      MO_F64_Ge -> condFltReg GE x y
+      MO_F64_Eq -> condFltReg EQQ x y
+      MO_F64_Ne -> condFltReg NE x y
+      MO_F64_Lt -> condFltReg LTT x y
+      MO_F64_Le -> condFltReg LE x y
+
+      MO_Nat_Add -> trivialCode (ADD False False) x y
+      MO_Nat_Sub -> trivialCode (SUB False False) x y
+
+      MO_NatS_Mul  -> trivialCode (SMUL False) x y
+      MO_NatU_Mul  -> trivialCode (UMUL False) x y
+      MO_NatS_MulMayOflo -> imulMayOflo x y
+
+      -- ToDo: teach about V8+ SPARC div instructions
+      MO_NatS_Quot -> idiv FSLIT(".div")  x y
+      MO_NatS_Rem  -> idiv FSLIT(".rem")  x y
+      MO_NatU_Quot -> idiv FSLIT(".udiv")  x y
+      MO_NatU_Rem  -> idiv FSLIT(".urem")  x y
+
+      MO_F32_Add   -> trivialFCode F32  FADD x y
+      MO_F32_Sub   -> trivialFCode F32  FSUB x y
+      MO_F32_Mul   -> trivialFCode F32  FMUL x y
+      MO_F32_Div   -> trivialFCode F32  FDIV x y
+
+      MO_F64_Add   -> trivialFCode F64 FADD x y
+      MO_F64_Sub   -> trivialFCode F64 FSUB x y
+      MO_F64_Mul   -> trivialFCode F64 FMUL x y
+      MO_F64_Div   -> trivialFCode F64 FDIV x y
+
+      MO_Nat_And   -> trivialCode (AND False) x y
+      MO_Nat_Or    -> trivialCode (OR  False) x y
+      MO_Nat_Xor   -> trivialCode (XOR False) x y
+
+      MO_Nat_Shl   -> trivialCode SLL x y
+      MO_Nat_Shr   -> trivialCode SRL x y
+      MO_Nat_Sar   -> trivialCode SRA x y
+
+      MO_F32_Pwr  -> getRegister (StCall (Left FSLIT("pow")) CCallConv F64 
+                                         [promote x, promote y])
+                      where promote x = CmmMachOp MO_F32_to_Dbl [x]
+      MO_F64_Pwr -> getRegister (StCall (Left FSLIT("pow")) CCallConv F64 
+                                        [x, y])
+
+      other -> pprPanic "getRegister(sparc) - binary CmmMachOp (1)" (pprMachOp mop)
+  where
+    idiv fn x y = getRegister (StCall (Left fn) CCallConv IntRep [x, y])
+
+    --------------------
+    imulMayOflo :: CmmExpr -> CmmExpr -> NatM Register
+    imulMayOflo a1 a2
+       = getNewRegNat IntRep           `thenNat` \ t1 ->
+         getNewRegNat IntRep           `thenNat` \ t2 ->
+         getNewRegNat IntRep           `thenNat` \ res_lo ->
+         getNewRegNat IntRep           `thenNat` \ res_hi ->
+         getRegister a1                        `thenNat` \ reg1 ->
+         getRegister a2                `thenNat` \ reg2 ->
+         let code1 = registerCode reg1 t1
+             code2 = registerCode reg2 t2
+             src1  = registerName reg1 t1
+             src2  = registerName reg2 t2
+             code dst = code1 `appOL` code2 `appOL`
+                        toOL [
+                           SMUL False src1 (RIReg src2) res_lo,
+                           RDY res_hi,
+                           SRA res_lo (RIImm (ImmInt 31)) res_lo,
+                           SUB False False res_lo (RIReg res_hi) dst
+                        ]
+         in
+            return (Any IntRep code)
+
+getRegister (CmmLoad pk mem) = do
+    Amode src code <- getAmode mem
+    let
+       size = primRepToSize pk
+       code__2 dst = code `snocOL` LD size src dst
+    --
+    return (Any pk code__2)
+
+getRegister (StInt i)
+  | fits13Bits i
+  = let
+       src = ImmInt (fromInteger i)
+       code dst = unitOL (OR False g0 (RIImm src) dst)
+    in
+       return (Any IntRep code)
+
+getRegister leaf
+  | isJust imm
+  = let
+       code dst = toOL [
+           SETHI (HI imm__2) dst,
+           OR False dst (RIImm (LO imm__2)) dst]
+    in
+       return (Any PtrRep code)
+  | otherwise
+  = ncgPrimopMoan "getRegister(sparc)" (pprCmmExpr leaf)
+  where
+    imm = maybeImm leaf
+    imm__2 = case imm of Just x -> x
+
+#endif /* sparc_TARGET_ARCH */
+
+#if powerpc_TARGET_ARCH
+getRegister (CmmLoad mem pk)
+  | pk /= I64
+  = do
+        Amode addr addr_code <- getAmode mem
+        let code dst = ASSERT((regClass dst == RcDouble) == isFloatingRep pk)
+                       addr_code `snocOL` LD pk dst addr
+        return (Any pk code)
+
+-- catch simple cases of zero- or sign-extended load
+getRegister (CmmMachOp (MO_U_Conv I8 I32) [CmmLoad mem _]) = do
+    Amode addr addr_code <- getAmode mem
+    return (Any I32 (\dst -> addr_code `snocOL` LD I8 dst addr))
+
+-- Note: there is no Load Byte Arithmetic instruction, so no signed case here
+
+getRegister (CmmMachOp (MO_U_Conv I16 I32) [CmmLoad mem _]) = do
+    Amode addr addr_code <- getAmode mem
+    return (Any I32 (\dst -> addr_code `snocOL` LD I16 dst addr))
+
+getRegister (CmmMachOp (MO_S_Conv I16 I32) [CmmLoad mem _]) = do
+    Amode addr addr_code <- getAmode mem
+    return (Any I32 (\dst -> addr_code `snocOL` LA I16 dst addr))
+
+getRegister (CmmMachOp mop [x]) -- unary MachOps
+  = case mop of
+      MO_Not rep   -> trivialUCode rep NOT x
+
+      MO_S_Conv F64 F32 -> trivialUCode F32 FRSP x
+      MO_S_Conv F32 F64 -> conversionNop F64 x
+
+      MO_S_Conv from to
+        | from == to         -> conversionNop to x
+       | isFloatingRep from -> coerceFP2Int from to x
+       | isFloatingRep to   -> coerceInt2FP from to x
+
+        -- narrowing is a nop: we treat the high bits as undefined
+      MO_S_Conv I32 to -> conversionNop to x
+      MO_S_Conv I16 I8 -> conversionNop I8 x
+      MO_S_Conv I8 to -> trivialUCode to (EXTS I8) x
+      MO_S_Conv I16 to -> trivialUCode to (EXTS I16) x
+
+      MO_U_Conv from to
+        | from == to -> conversionNop to x
+        -- narrowing is a nop: we treat the high bits as undefined
+      MO_U_Conv I32 to -> conversionNop to x
+      MO_U_Conv I16 I8 -> conversionNop I8 x
+      MO_U_Conv I8 to -> trivialCode to False AND x (CmmLit (CmmInt 255 I32))
+      MO_U_Conv I16 to -> trivialCode to False AND x (CmmLit (CmmInt 65535 I32)) 
+
+      MO_S_Neg F32      -> trivialUCode F32 FNEG x
+      MO_S_Neg F64      -> trivialUCode F64 FNEG x
+      MO_S_Neg rep      -> trivialUCode rep NEG x
+      
+    where
+        conversionNop new_rep expr
+            = do e_code <- getRegister expr
+                 return (swizzleRegisterRep e_code new_rep)
+
+getRegister (CmmMachOp mop [x, y]) -- dyadic PrimOps
+  = case mop of
+      MO_Eq F32 -> condFltReg EQQ x y
+      MO_Ne F32 -> condFltReg NE  x y
+
+      MO_S_Gt F32 -> condFltReg GTT x y
+      MO_S_Ge F32 -> condFltReg GE  x y
+      MO_S_Lt F32 -> condFltReg LTT x y
+      MO_S_Le F32 -> condFltReg LE  x y
+
+      MO_Eq F64 -> condFltReg EQQ x y
+      MO_Ne F64 -> condFltReg NE  x y
+
+      MO_S_Gt F64 -> condFltReg GTT x y
+      MO_S_Ge F64 -> condFltReg GE  x y
+      MO_S_Lt F64 -> condFltReg LTT x y
+      MO_S_Le F64 -> condFltReg LE  x y
+
+      MO_Eq rep -> condIntReg EQQ  (extendUExpr rep x) (extendUExpr rep y)
+      MO_Ne rep -> condIntReg NE   (extendUExpr rep x) (extendUExpr rep y)
+
+      MO_S_Gt rep -> condIntReg GTT  (extendSExpr rep x) (extendSExpr rep y)
+      MO_S_Ge rep -> condIntReg GE   (extendSExpr rep x) (extendSExpr rep y)
+      MO_S_Lt rep -> condIntReg LTT  (extendSExpr rep x) (extendSExpr rep y)
+      MO_S_Le rep -> condIntReg LE   (extendSExpr rep x) (extendSExpr rep y)
+
+      MO_U_Gt rep -> condIntReg GU   (extendUExpr rep x) (extendUExpr rep y)
+      MO_U_Ge rep -> condIntReg GEU  (extendUExpr rep x) (extendUExpr rep y)
+      MO_U_Lt rep -> condIntReg LU   (extendUExpr rep x) (extendUExpr rep y)
+      MO_U_Le rep -> condIntReg LEU  (extendUExpr rep x) (extendUExpr rep y)
+
+      MO_Add F32   -> trivialCodeNoImm F32 (FADD F32) x y
+      MO_Sub F32   -> trivialCodeNoImm F32 (FSUB F32) x y
+      MO_Mul F32   -> trivialCodeNoImm F32 (FMUL F32) x y
+      MO_S_Quot F32   -> trivialCodeNoImm F32 (FDIV F32) x y
+      
+      MO_Add F64   -> trivialCodeNoImm F64 (FADD F64) x y
+      MO_Sub F64   -> trivialCodeNoImm F64 (FSUB F64) x y
+      MO_Mul F64   -> trivialCodeNoImm F64 (FMUL F64) x y
+      MO_S_Quot F64   -> trivialCodeNoImm F64 (FDIV F64) x y
+
+      MO_Add rep -> trivialCode rep True ADD x y
+      MO_Sub rep ->
+        case y of    -- subfi ('substract from' with immediate) doesn't exist
+          CmmLit (CmmInt imm immrep) | Just _ <- makeImmediate rep True (-imm)
+            -> trivialCode rep True ADD x (CmmLit $ CmmInt (-imm) immrep)
+          _ -> trivialCodeNoImm rep SUBF y x
+
+      MO_Mul rep -> trivialCode rep True MULLW x y
+
+      MO_S_MulMayOflo I32 -> trivialCodeNoImm I32 MULLW_MayOflo x y
+      
+      MO_S_MulMayOflo rep -> panic "S_MulMayOflo (rep /= I32): not implemented"
+      MO_U_MulMayOflo rep -> panic "U_MulMayOflo: not implemented"
+
+      MO_S_Quot rep -> trivialCodeNoImm rep DIVW (extendSExpr rep x) (extendSExpr rep y)
+      MO_U_Quot rep -> trivialCodeNoImm rep DIVWU (extendUExpr rep x) (extendUExpr rep y)
+      
+      MO_S_Rem rep -> remainderCode rep DIVW (extendSExpr rep x) (extendSExpr rep y)
+      MO_U_Rem rep -> remainderCode rep DIVWU (extendUExpr rep x) (extendUExpr rep y)
+      
+      MO_And rep   -> trivialCode rep False AND x y
+      MO_Or rep    -> trivialCode rep False OR x y
+      MO_Xor rep   -> trivialCode rep False XOR x y
+
+      MO_Shl rep   -> trivialCode rep False SLW x y
+      MO_S_Shr rep -> trivialCode rep False SRAW (extendSExpr rep x) y
+      MO_U_Shr rep -> trivialCode rep False SRW (extendUExpr rep x) y
+
+getRegister (CmmLit (CmmInt i rep))
+  | Just imm <- makeImmediate rep True i
+  = let
+       code dst = unitOL (LI dst imm)
+    in
+       return (Any rep code)
+
+getRegister (CmmLit (CmmFloat f F32)) = do
+    lbl <- getNewLabelNat
+    tmp <- getNewRegNat I32
+    let code dst = toOL [
+           LDATA ReadOnlyData  [CmmDataLabel lbl,
+                                CmmStaticLit (CmmFloat f F32)],
+           LIS tmp (HA (ImmCLbl lbl)),
+           LD F32 dst (AddrRegImm tmp (LO (ImmCLbl lbl)))
+           ]
+    -- in
+    return (Any F32 code)
+
+getRegister (CmmLit (CmmFloat d F64)) = do
+    lbl <- getNewLabelNat
+    tmp <- getNewRegNat I32
+    let code dst = toOL [
+           LDATA ReadOnlyData  [CmmDataLabel lbl,
+                                CmmStaticLit (CmmFloat d F64)],
+           LIS tmp (HA (ImmCLbl lbl)),
+           LD F64 dst (AddrRegImm tmp (LO (ImmCLbl lbl)))
+           ]
+    -- in
+    return (Any F32 code)
+
+#if darwin_TARGET_OS
+getRegister (CmmLit (CmmLabel lbl))
+    | labelCouldBeDynamic lbl
+    = do
+        addImportNat False lbl
+       let imm = ImmDyldNonLazyPtr lbl
+           code dst = toOL [
+                    LIS dst (HA imm),
+                    LD  I32 dst (AddrRegImm dst (LO imm))
+                ]
+        return (Any I32 code)
+#endif
+
+getRegister (CmmLit lit)
+  = let 
+       rep = cmmLitRep lit
+       imm = litToImm lit
+       code dst = toOL [
+                LIS dst (HI imm),
+                OR dst dst (RIImm (LO imm))
+            ]
+    in
+       return (Any rep code)
+getRegister other = pprPanic "getRegister(ppc)" (pprExpr other)
+    
+    -- extend?Rep: wrap integer expression of type rep
+    -- in a conversion to I32
+extendSExpr I32 x = x
+extendSExpr rep x = CmmMachOp (MO_S_Conv rep I32) [x]
+extendUExpr I32 x = x
+extendUExpr rep x = CmmMachOp (MO_U_Conv rep I32) [x]
+
+-- ###FIXME: exact code duplication from x86 case
+-- The dual to getAnyReg: compute an expression into a register, but
+-- we don't mind which one it is.
+getSomeReg :: CmmExpr -> NatM (Reg, InstrBlock)
+getSomeReg expr = do
+  r <- getRegister expr
+  case r of
+    Any rep code -> do
+       tmp <- getNewRegNat rep
+       return (tmp, code tmp)
+    Fixed _ reg code -> 
+       return (reg, code)
+
+#endif /* powerpc_TARGET_ARCH */
+
+
+-- -----------------------------------------------------------------------------
+--  The 'Amode' type: Memory addressing modes passed up the tree.
+
+data Amode = Amode AddrMode InstrBlock
+
+{-
+Now, given a tree (the argument to an CmmLoad) that references memory,
+produce a suitable addressing mode.
+
+A Rule of the Game (tm) for Amodes: use of the addr bit must
+immediately follow use of the code part, since the code part puts
+values in registers which the addr then refers to.  So you can't put
+anything in between, lest it overwrite some of those registers.  If
+you need to do some other computation between the code part and use of
+the addr bit, first store the effective address from the amode in a
+temporary, then do the other computation, and then use the temporary:
+
+    code
+    LEA amode, tmp
+    ... other computation ...
+    ... (tmp) ...
+-}
+
+getAmode :: CmmExpr -> NatM Amode
+getAmode tree@(CmmRegOff _ _) = getAmode (mangleIndexTree tree)
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if alpha_TARGET_ARCH
+
+getAmode (StPrim IntSubOp [x, StInt i])
+  = getNewRegNat PtrRep                `thenNat` \ tmp ->
+    getRegister x              `thenNat` \ register ->
+    let
+       code = registerCode register tmp
+       reg  = registerName register tmp
+       off  = ImmInt (-(fromInteger i))
+    in
+    return (Amode (AddrRegImm reg off) code)
+
+getAmode (StPrim IntAddOp [x, StInt i])
+  = getNewRegNat PtrRep                `thenNat` \ tmp ->
+    getRegister x              `thenNat` \ register ->
+    let
+       code = registerCode register tmp
+       reg  = registerName register tmp
+       off  = ImmInt (fromInteger i)
+    in
+    return (Amode (AddrRegImm reg off) code)
+
+getAmode leaf
+  | isJust imm
+  = return (Amode (AddrImm imm__2) id)
+  where
+    imm = maybeImm leaf
+    imm__2 = case imm of Just x -> x
+
+getAmode other
+  = getNewRegNat PtrRep                `thenNat` \ tmp ->
+    getRegister other          `thenNat` \ register ->
+    let
+       code = registerCode register tmp
+       reg  = registerName register tmp
+    in
+    return (Amode (AddrReg reg) code)
+
+#endif /* alpha_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if i386_TARGET_ARCH
+
+-- This is all just ridiculous, since it carefully undoes 
+-- what mangleIndexTree has just done.
+getAmode (CmmMachOp (MO_Sub rep) [x, CmmLit (CmmInt i _)])
+  -- ASSERT(rep == I32)???
+  = do (x_reg, x_code) <- getSomeReg x
+       let off = ImmInt (-(fromInteger i))
+       return (Amode (AddrBaseIndex (Just x_reg) Nothing off) x_code)
+  
+getAmode (CmmMachOp (MO_Add rep) [x, CmmLit (CmmInt i _)])
+  -- ASSERT(rep == I32)???
+  = do (x_reg, x_code) <- getSomeReg x
+       let off = ImmInt (fromInteger i)
+       return (Amode (AddrBaseIndex (Just x_reg) Nothing off) x_code)
+
+-- Turn (lit1 << n  + lit2) into  (lit2 + lit1 << n) so it will be 
+-- recognised by the next rule.
+getAmode (CmmMachOp (MO_Add rep) [a@(CmmMachOp (MO_Shl _) _),
+                                 b@(CmmLit _)])
+  = getAmode (CmmMachOp (MO_Add rep) [b,a])
+
+getAmode (CmmMachOp (MO_Add rep) [x, CmmMachOp (MO_Shl _) 
+                                       [y, CmmLit (CmmInt shift _)]])
+  | shift == 0 || shift == 1 || shift == 2 || shift == 3
+  = do (x_reg, x_code) <- getNonClobberedReg x
+       -- x must be in a temp, because it has to stay live over y_code
+       -- we could compre x_reg and y_reg and do something better here...
+       (y_reg, y_code) <- getSomeReg y
+       let
+          code = x_code `appOL` y_code
+           base = case shift of 0 -> 1; 1 -> 2; 2 -> 4; 3 -> 8
+       return (Amode (AddrBaseIndex (Just x_reg) (Just (y_reg,base)) (ImmInt 0))
+               code)
+
+getAmode (CmmLit lit)
+  = return (Amode (ImmAddr (litToImm lit) 0) nilOL)
+
+getAmode expr = do
+  (reg,code) <- getSomeReg expr
+  return (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
+
+#endif /* i386_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if sparc_TARGET_ARCH
+
+getAmode (CmmMachOp MO_Nat_Sub [x, StInt i])
+  | fits13Bits (-i)
+  = getNewRegNat PtrRep                `thenNat` \ tmp ->
+    getRegister x              `thenNat` \ register ->
+    let
+       code = registerCode register tmp
+       reg  = registerName register tmp
+       off  = ImmInt (-(fromInteger i))
+    in
+    return (Amode (AddrRegImm reg off) code)
+
+
+getAmode (CmmMachOp MO_Nat_Add [x, StInt i])
+  | fits13Bits i
+  = getNewRegNat PtrRep                `thenNat` \ tmp ->
+    getRegister x              `thenNat` \ register ->
+    let
+       code = registerCode register tmp
+       reg  = registerName register tmp
+       off  = ImmInt (fromInteger i)
+    in
+    return (Amode (AddrRegImm reg off) code)
+
+getAmode (CmmMachOp MO_Nat_Add [x, y])
+  = getNewRegNat PtrRep        `thenNat` \ tmp1 ->
+    getNewRegNat IntRep        `thenNat` \ tmp2 ->
+    getRegister x              `thenNat` \ register1 ->
+    getRegister y              `thenNat` \ register2 ->
+    let
+       code1 = registerCode register1 tmp1
+       reg1  = registerName register1 tmp1
+       code2 = registerCode register2 tmp2
+       reg2  = registerName register2 tmp2
+       code__2 = code1 `appOL` code2
+    in
+    return (Amode (AddrRegReg reg1 reg2) code__2)
+
+getAmode leaf
+  | isJust imm
+  = getNewRegNat PtrRep            `thenNat` \ tmp ->
+    let
+       code = unitOL (SETHI (HI imm__2) tmp)
+    in
+    return (Amode (AddrRegImm tmp (LO imm__2)) code)
+  where
+    imm    = maybeImm leaf
+    imm__2 = case imm of Just x -> x
+
+getAmode other
+  = getNewRegNat PtrRep                `thenNat` \ tmp ->
+    getRegister other          `thenNat` \ register ->
+    let
+       code = registerCode register tmp
+       reg  = registerName register tmp
+       off  = ImmInt 0
+    in
+    return (Amode (AddrRegImm reg off) code)
+
+#endif /* sparc_TARGET_ARCH */
+
+#ifdef powerpc_TARGET_ARCH
+getAmode (CmmMachOp (MO_Sub I32) [x, CmmLit (CmmInt i _)])
+  | Just off <- makeImmediate I32 True (-i)
+  = do
+        (reg, code) <- getSomeReg x
+        return (Amode (AddrRegImm reg off) code)
+
+
+getAmode (CmmMachOp (MO_Add I32) [x, CmmLit (CmmInt i _)])
+  | Just off <- makeImmediate I32 True i
+  = do
+        (reg, code) <- getSomeReg x
+        return (Amode (AddrRegImm reg off) code)
+
+getAmode (CmmLit lit)
+  = do
+        tmp <- getNewRegNat I32
+        let
+            code = unitOL (LIS tmp (HA imm))
+        return (Amode (AddrRegImm tmp (LO imm)) code)
+    where
+        imm = litToImm lit
+    
+getAmode (CmmMachOp (MO_Add I32) [x, y])
+  = do
+        (regX, codeX) <- getSomeReg x
+        (regY, codeY) <- getSomeReg y
+        return (Amode (AddrRegReg regX regY) (codeX `appOL` codeY))
+    
+getAmode other
+  = do
+        (reg, code) <- getSomeReg other
+        let
+            off  = ImmInt 0
+        return (Amode (AddrRegImm reg off) code)
+#endif /* powerpc_TARGET_ARCH */
+
+-- -----------------------------------------------------------------------------
+-- getOperand: sometimes any operand will do.
+
+-- getOperand gets a *safe* operand; that is, the value of the operand
+-- will remain valid across the computation of an arbitrary expression,
+-- unless the expression is computed directly into a register which
+-- the operand refers to (see trivialCode where this function is used
+-- for an example).
+
+#ifdef i386_TARGET_ARCH
+
+getOperand :: CmmExpr -> NatM (Operand, InstrBlock)
+getOperand (CmmLoad mem pk) 
+  | not (isFloatingRep pk) && pk /= I64 = do
+    Amode src mem_code <- getAmode mem
+    (src',save_code) <- 
+       if (amodeCouldBeClobbered src) 
+               then do
+                  tmp <- getNewRegNat wordRep
+                  return (AddrBaseIndex (Just tmp) Nothing (ImmInt 0),
+                          unitOL (LEA I32 (OpAddr src) (OpReg tmp)))
+               else
+                  return (src, nilOL)
+    return (OpAddr src', save_code `appOL` mem_code)
+
+getOperand e = do
+    (reg, code) <- getNonClobberedReg e
+    return (OpReg reg, code)
+
+amodeCouldBeClobbered :: AddrMode -> Bool
+amodeCouldBeClobbered amode = any regClobbered (addrModeRegs amode)
+
+regClobbered (RealReg rr) = isFastTrue (freeReg rr)
+regClobbered _ = False
+
+#endif
+
+-- -----------------------------------------------------------------------------
+--  The 'CondCode' type:  Condition codes passed up the tree.
+
+data CondCode = CondCode Bool Cond InstrBlock
+
+-- Set up a condition code for a conditional branch.
+
+getCondCode :: CmmExpr -> NatM CondCode
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if alpha_TARGET_ARCH
+getCondCode = panic "MachCode.getCondCode: not on Alphas"
+#endif /* alpha_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if i386_TARGET_ARCH || sparc_TARGET_ARCH
+-- yes, they really do seem to want exactly the same!
+
+getCondCode (CmmMachOp mop [x, y])
+  = ASSERT (cmmExprRep x /= I8) -- tmp, not set up to handle 8-bit comparisons
+    case mop of
+      MO_Eq F32 -> condFltCode EQQ x y
+      MO_Ne F32 -> condFltCode NE  x y
+
+      MO_S_Gt F32 -> condFltCode GTT x y
+      MO_S_Ge F32 -> condFltCode GE  x y
+      MO_S_Lt F32 -> condFltCode LTT x y
+      MO_S_Le F32 -> condFltCode LE  x y
+
+      MO_Eq F64 -> condFltCode EQQ x y
+      MO_Ne F64 -> condFltCode NE  x y
+
+      MO_S_Gt F64 -> condFltCode GTT x y
+      MO_S_Ge F64 -> condFltCode GE  x y
+      MO_S_Lt F64 -> condFltCode LTT x y
+      MO_S_Le F64 -> condFltCode LE  x y
+
+      MO_Eq rep -> condIntCode EQQ  x y
+      MO_Ne rep -> condIntCode NE   x y
+
+      MO_S_Gt rep -> condIntCode GTT  x y
+      MO_S_Ge rep -> condIntCode GE   x y
+      MO_S_Lt rep -> condIntCode LTT  x y
+      MO_S_Le rep -> condIntCode LE   x y
+
+      MO_U_Gt rep -> condIntCode GU   x y
+      MO_U_Ge rep -> condIntCode GEU  x y
+      MO_U_Lt rep -> condIntCode LU   x y
+      MO_U_Le rep -> condIntCode LEU  x y
+
+      other -> pprPanic "getCondCode(x86,sparc)" (pprMachOp mop)
+
+getCondCode other =  pprPanic "getCondCode(2)(x86,sparc)" (ppr other)
+
+#elif powerpc_TARGET_ARCH
+
+-- almost the same as everywhere else - but we need to
+-- extend small integers to 32 bit first
+
+getCondCode (CmmMachOp mop [x, y])
+  = case mop of
+      MO_Eq F32 -> condFltCode EQQ x y
+      MO_Ne F32 -> condFltCode NE  x y
+
+      MO_S_Gt F32 -> condFltCode GTT x y
+      MO_S_Ge F32 -> condFltCode GE  x y
+      MO_S_Lt F32 -> condFltCode LTT x y
+      MO_S_Le F32 -> condFltCode LE  x y
+
+      MO_Eq F64 -> condFltCode EQQ x y
+      MO_Ne F64 -> condFltCode NE  x y
+
+      MO_S_Gt F64 -> condFltCode GTT x y
+      MO_S_Ge F64 -> condFltCode GE  x y
+      MO_S_Lt F64 -> condFltCode LTT x y
+      MO_S_Le F64 -> condFltCode LE  x y
+
+      MO_Eq rep -> condIntCode EQQ  (extendUExpr rep x) (extendUExpr rep y)
+      MO_Ne rep -> condIntCode NE   (extendUExpr rep x) (extendUExpr rep y)
+
+      MO_S_Gt rep -> condIntCode GTT  (extendSExpr rep x) (extendSExpr rep y)
+      MO_S_Ge rep -> condIntCode GE   (extendSExpr rep x) (extendSExpr rep y)
+      MO_S_Lt rep -> condIntCode LTT  (extendSExpr rep x) (extendSExpr rep y)
+      MO_S_Le rep -> condIntCode LE   (extendSExpr rep x) (extendSExpr rep y)
+
+      MO_U_Gt rep -> condIntCode GU   (extendUExpr rep x) (extendUExpr rep y)
+      MO_U_Ge rep -> condIntCode GEU  (extendUExpr rep x) (extendUExpr rep y)
+      MO_U_Lt rep -> condIntCode LU   (extendUExpr rep x) (extendUExpr rep y)
+      MO_U_Le rep -> condIntCode LEU  (extendUExpr rep x) (extendUExpr rep y)
+
+      other -> pprPanic "getCondCode(powerpc)" (pprMachOp mop)
+
+getCondCode other =  panic "getCondCode(2)(powerpc)"
+
+
+#endif
+
+
+-- @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
+-- passed back up the tree.
+
+condIntCode, condFltCode :: Cond -> CmmExpr -> CmmExpr -> NatM CondCode
+
+#if alpha_TARGET_ARCH
+condIntCode = panic "MachCode.condIntCode: not on Alphas"
+condFltCode = panic "MachCode.condFltCode: not on Alphas"
+#endif /* alpha_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+-- memory vs immediate
+condIntCode cond (CmmLoad x pk) (CmmLit lit) = do
+    Amode x_addr x_code <- getAmode x
+    let
+       imm  = litToImm lit
+       code = x_code `snocOL`
+                 CMP pk (OpImm imm) (OpAddr x_addr)
+    --
+    return (CondCode False cond code)
+
+-- anything vs zero
+condIntCode cond x (CmmLit (CmmInt 0 pk)) = do
+    (x_reg, x_code) <- getSomeReg x
+    let
+       code = x_code `snocOL`
+                 TEST pk (OpReg x_reg) (OpReg x_reg)
+    --
+    return (CondCode False cond code)
+
+-- anything vs immediate
+condIntCode cond x (CmmLit lit) = do
+    (x_reg, x_code) <- getSomeReg x
+    let
+       imm  = litToImm lit
+       code = x_code `snocOL`
+                  CMP (cmmLitRep lit) (OpImm imm) (OpReg x_reg)
+    -- in
+    return (CondCode False cond code)
+
+-- memory vs anything
+condIntCode cond (CmmLoad x pk) y = do
+    (y_reg, y_code) <- getNonClobberedReg y
+    Amode x_addr x_code <- getAmode x
+    let
+       code = y_code `appOL`
+               x_code `snocOL`
+                 CMP pk (OpReg y_reg) (OpAddr x_addr)
+    -- in
+    return (CondCode False cond code)
+
+-- anything vs memory
+condIntCode cond y (CmmLoad x pk) = do
+    (y_reg, y_code) <- getNonClobberedReg y
+    Amode x_addr x_code <- getAmode x
+    let
+       code = y_code `appOL`
+               x_code `snocOL`
+                 CMP pk (OpAddr x_addr) (OpReg y_reg)
+    -- in
+    return (CondCode False cond code)
+
+-- anything vs anything
+condIntCode cond x y = do
+  (x_op, x_code) <- getOperand x
+  (y_reg, y_code) <- getSomeReg y
+  let
+       code = x_code `appOL`
+              y_code `snocOL`
+                 CMP (cmmExprRep x) (OpReg y_reg) x_op
+  -- in
+  return (CondCode False cond code)
+
+-----------
+condFltCode cond x y 
+  = ASSERT(cond `elem` ([EQQ, NE, LE, LTT, GE, GTT])) do
+  (x_reg, x_code) <- getNonClobberedReg x
+  (y_reg, y_code) <- getSomeReg y
+  let
+       code = x_code `appOL` y_code `snocOL`
+               GCMP cond x_reg y_reg
+  -- The GCMP insn does the test and sets the zero flag if comparable
+  -- and true.  Hence we always supply EQQ as the condition to test.
+  return (CondCode True EQQ code)
+
+#endif /* i386_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if sparc_TARGET_ARCH
+
+condIntCode cond x (StInt y)
+  | fits13Bits y
+  = getRegister x              `thenNat` \ register ->
+    getNewRegNat IntRep                `thenNat` \ tmp ->
+    let
+       code = registerCode register tmp
+       src1 = registerName register tmp
+       src2 = ImmInt (fromInteger y)
+       code__2 = code `snocOL` SUB False True src1 (RIImm src2) g0
+    in
+    return (CondCode False cond code__2)
+
+condIntCode cond x y
+  = getRegister x              `thenNat` \ register1 ->
+    getRegister y              `thenNat` \ register2 ->
+    getNewRegNat IntRep                `thenNat` \ tmp1 ->
+    getNewRegNat IntRep                `thenNat` \ tmp2 ->
+    let
+       code1 = registerCode register1 tmp1
+       src1  = registerName register1 tmp1
+       code2 = registerCode register2 tmp2
+       src2  = registerName register2 tmp2
+       code__2 = code1 `appOL` code2 `snocOL`
+                 SUB False True src1 (RIReg src2) g0
+    in
+    return (CondCode False cond code__2)
+
+-----------
+condFltCode cond x y
+  = getRegister x              `thenNat` \ register1 ->
+    getRegister y              `thenNat` \ register2 ->
+    getNewRegNat (registerRep register1)
+                               `thenNat` \ tmp1 ->
+    getNewRegNat (registerRep register2)
+                               `thenNat` \ tmp2 ->
+    getNewRegNat F64   `thenNat` \ tmp ->
+    let
+       promote x = FxTOy F DF x tmp
+
+       pk1   = registerRep register1
+       code1 = registerCode register1 tmp1
+       src1  = registerName register1 tmp1
+
+       pk2   = registerRep register2
+       code2 = registerCode register2 tmp2
+       src2  = registerName register2 tmp2
+
+       code__2 =
+               if pk1 == pk2 then
+                   code1 `appOL` code2 `snocOL`
+                   FCMP True (primRepToSize pk1) src1 src2
+               else if pk1 == F32 then
+                   code1 `snocOL` promote src1 `appOL` code2 `snocOL`
+                   FCMP True DF tmp src2
+               else
+                   code1 `appOL` code2 `snocOL` promote src2 `snocOL`
+                   FCMP True DF src1 tmp
+    in
+    return (CondCode True cond code__2)
+
+#endif /* sparc_TARGET_ARCH */
+
+#if powerpc_TARGET_ARCH
+-- ###FIXME: I16 and I8!
+condIntCode cond x (CmmLit (CmmInt y rep))
+  | Just src2 <- makeImmediate rep (not $ condUnsigned cond) y
+  = do
+        (src1, code) <- getSomeReg x
+        let
+            code' = code `snocOL` 
+                (if condUnsigned cond then CMPL else CMP) I32 src1 (RIImm src2)
+        return (CondCode False cond code')
+
+condIntCode cond x y = do
+    (src1, code1) <- getSomeReg x
+    (src2, code2) <- getSomeReg y
+    let
+       code' = code1 `appOL` code2 `snocOL`
+                 (if condUnsigned cond then CMPL else CMP) I32 src1 (RIReg src2)
+    return (CondCode False cond code')
+
+condFltCode cond x y = do
+    (src1, code1) <- getSomeReg x
+    (src2, code2) <- getSomeReg y
+    let
+       code'  = code1 `appOL` code2 `snocOL` FCMP src1 src2
+       code'' = case cond of -- twiddle CR to handle unordered case
+                    GE -> code' `snocOL` CRNOR ltbit eqbit gtbit
+                   LE -> code' `snocOL` CRNOR gtbit eqbit ltbit
+                   _ -> code'
+                 where
+                    ltbit = 0 ; eqbit = 2 ; gtbit = 1
+    return (CondCode True cond code'')
+
+#endif /* powerpc_TARGET_ARCH */
+
+-- -----------------------------------------------------------------------------
+-- Generating assignments
+
+-- Assignments are really at the heart of the whole code generation
+-- business.  Almost all top-level nodes of any real importance are
+-- assignments, which correspond to loads, stores, or register
+-- transfers.  If we're really lucky, some of the register transfers
+-- will go away, because we can use the destination register to
+-- complete the code generation for the right hand side.  This only
+-- fails when the right hand side is forced into a fixed register
+-- (e.g. the result of a call).
+
+assignMem_IntCode :: MachRep -> CmmExpr -> CmmExpr -> NatM InstrBlock
+assignReg_IntCode :: MachRep -> CmmReg  -> CmmExpr -> NatM InstrBlock
+
+assignMem_FltCode :: MachRep -> CmmExpr -> CmmExpr -> NatM InstrBlock
+assignReg_FltCode :: MachRep -> CmmReg  -> CmmExpr -> NatM InstrBlock
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if alpha_TARGET_ARCH
+
+assignIntCode pk (CmmLoad dst _) src
+  = getNewRegNat IntRep            `thenNat` \ tmp ->
+    getAmode dst                   `thenNat` \ amode ->
+    getRegister src                `thenNat` \ register ->
+    let
+       code1   = amodeCode amode []
+       dst__2  = amodeAddr amode
+       code2   = registerCode register tmp []
+       src__2  = registerName register tmp
+       sz      = primRepToSize pk
+       code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
+    in
+    return code__2
+
+assignIntCode pk dst src
+  = getRegister dst                        `thenNat` \ register1 ->
+    getRegister src                        `thenNat` \ register2 ->
+    let
+       dst__2  = registerName register1 zeroh
+       code    = registerCode register2 dst__2
+       src__2  = registerName register2 dst__2
+       code__2 = if isFixed register2
+                 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
+                 else code
+    in
+    return code__2
+
+#endif /* alpha_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if i386_TARGET_ARCH
+
+-- integer assignment to memory
+assignMem_IntCode pk addr src = do
+    Amode addr code_addr <- getAmode addr
+    (code_src, op_src)   <- get_op_RI src
+    let
+       code = code_src `appOL`
+              code_addr `snocOL`
+                  MOV pk op_src (OpAddr addr)
+       -- NOTE: op_src is stable, so it will still be valid
+       -- after code_addr.  This may involve the introduction 
+       -- of an extra MOV to a temporary register, but we hope
+       -- the register allocator will get rid of it.
+    --
+    return code
+  where
+    get_op_RI :: CmmExpr -> NatM (InstrBlock,Operand)  -- code, operator
+    get_op_RI (CmmLit lit)
+      = return (nilOL, OpImm (litToImm lit))
+    get_op_RI op
+      = do (reg,code) <- getNonClobberedReg op
+          return (code, OpReg reg)
+
+
+-- Assign; dst is a reg, rhs is mem
+assignReg_IntCode pk reg (CmmLoad src _) = do
+  load_code <- intLoadCode (MOV pk) src
+  return (load_code (getRegisterReg reg))
+
+-- dst is a reg, but src could be anything
+assignReg_IntCode pk reg src = do
+  code <- getAnyReg src
+  return (code (getRegisterReg reg))
+
+#endif /* i386_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if sparc_TARGET_ARCH
+
+assignMem_IntCode pk addr src
+  = getNewRegNat IntRep                    `thenNat` \ tmp ->
+    getAmode addr                          `thenNat` \ amode ->
+    getRegister src                        `thenNat` \ register ->
+    let
+       code1   = amodeCode amode
+       dst__2  = amodeAddr amode
+       code2   = registerCode register tmp
+       src__2  = registerName register tmp
+       sz      = primRepToSize pk
+       code__2 = code1 `appOL` code2 `snocOL` ST sz src__2 dst__2
+    in
+    return code__2
+
+assignReg_IntCode pk reg src
+  = getRegister src                        `thenNat` \ register2 ->
+    getRegisterReg reg                     `thenNat` \ register1 ->
+    getNewRegNat IntRep                    `thenNat` \ tmp ->
+    let
+       dst__2  = registerName register1 tmp
+       code    = registerCode register2 dst__2
+       src__2  = registerName register2 dst__2
+       code__2 = if isFixed register2
+                 then code `snocOL` OR False g0 (RIReg src__2) dst__2
+                 else code
+    in
+    return code__2
+
+#endif /* sparc_TARGET_ARCH */
+
+#if powerpc_TARGET_ARCH
+
+assignMem_IntCode pk addr src = do
+    (srcReg, code) <- getSomeReg src
+    Amode dstAddr addr_code <- getAmode addr
+    return $ code `appOL` addr_code `snocOL` ST pk srcReg dstAddr
+
+-- dst is a reg, but src could be anything
+assignReg_IntCode pk reg src
+    = do
+        r <- getRegister src
+        return $ case r of
+            Any _ code         -> code dst
+            Fixed _ freg fcode -> fcode `snocOL` MR dst freg
+    where
+        dst = getRegisterReg reg
+
+#endif /* powerpc_TARGET_ARCH */
+
+
+-- -----------------------------------------------------------------------------
+-- Floating-point assignments
+
+#if alpha_TARGET_ARCH
+
+assignFltCode pk (CmmLoad dst _) src
+  = getNewRegNat pk                `thenNat` \ tmp ->
+    getAmode dst                   `thenNat` \ amode ->
+    getRegister src                        `thenNat` \ register ->
+    let
+       code1   = amodeCode amode []
+       dst__2  = amodeAddr amode
+       code2   = registerCode register tmp []
+       src__2  = registerName register tmp
+       sz      = primRepToSize pk
+       code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
+    in
+    return code__2
+
+assignFltCode pk dst src
+  = getRegister dst                        `thenNat` \ register1 ->
+    getRegister src                        `thenNat` \ register2 ->
+    let
+       dst__2  = registerName register1 zeroh
+       code    = registerCode register2 dst__2
+       src__2  = registerName register2 dst__2
+       code__2 = if isFixed register2
+                 then code . mkSeqInstr (FMOV src__2 dst__2)
+                 else code
+    in
+    return code__2
+
+#endif /* alpha_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if i386_TARGET_ARCH
+
+-- Floating point assignment to memory
+assignMem_FltCode pk addr src = do
+  (src_reg, src_code) <- getNonClobberedReg src
+  Amode addr addr_code <- getAmode addr
+  let
+       code = src_code `appOL`
+              addr_code `snocOL`
+                GST pk src_reg addr
+  return code
+
+-- Floating point assignment to a register/temporary
+assignReg_FltCode pk reg src = do
+  src_code <- getAnyReg src
+  return (src_code (getRegisterReg reg))
+
+#endif /* i386_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if sparc_TARGET_ARCH
+
+-- Floating point assignment to memory
+assignMem_FltCode pk addr src
+  = getNewRegNat pk                `thenNat` \ tmp1 ->
+    getAmode addr                  `thenNat` \ amode ->
+    getRegister src                `thenNat` \ register ->
+    let
+       sz      = primRepToSize pk
+       dst__2  = amodeAddr amode
+
+       code1   = amodeCode amode
+       code2   = registerCode register tmp1
+
+       src__2  = registerName register tmp1
+       pk__2   = registerRep register
+       sz__2   = primRepToSize pk__2
+
+       code__2 = code1 `appOL` code2 `appOL`
+           if   pk == pk__2 
+            then unitOL (ST sz src__2 dst__2)
+           else toOL [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
+    in
+    return code__2
+
+-- Floating point assignment to a register/temporary
+-- Why is this so bizarrely ugly?
+assignReg_FltCode pk reg src
+  = getRegisterReg reg                     `thenNat` \ register1 ->
+    getRegister src                        `thenNat` \ register2 ->
+    let 
+        pk__2   = registerRep register2 
+        sz__2   = primRepToSize pk__2
+    in
+    getNewRegNat pk__2                      `thenNat` \ tmp ->
+    let
+       sz      = primRepToSize pk
+       dst__2  = registerName register1 g0    -- must be Fixed
+       reg__2  = if pk /= pk__2 then tmp else dst__2
+       code    = registerCode register2 reg__2
+       src__2  = registerName register2 reg__2
+       code__2 = 
+               if pk /= pk__2 then
+                    code `snocOL` FxTOy sz__2 sz src__2 dst__2
+               else if isFixed register2 then
+                    code `snocOL` FMOV sz src__2 dst__2
+               else
+                    code
+    in
+    return code__2
+
+#endif /* sparc_TARGET_ARCH */
+
+#if powerpc_TARGET_ARCH
+
+-- Easy, isn't it?
+assignMem_FltCode = assignMem_IntCode
+assignReg_FltCode = assignReg_IntCode
+
+#endif /* powerpc_TARGET_ARCH */
+
+
+-- -----------------------------------------------------------------------------
+-- Generating an non-local jump
+
+-- (If applicable) Do not fill the delay slots here; you will confuse the
+-- register allocator.
+
+genJump :: CmmExpr{-the branch target-} -> NatM InstrBlock
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if alpha_TARGET_ARCH
+
+genJump (CmmLabel lbl)
+  | isAsmTemp lbl = returnInstr (BR target)
+  | otherwise     = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
+  where
+    target = ImmCLbl lbl
+
+genJump tree
+  = getRegister tree               `thenNat` \ register ->
+    getNewRegNat PtrRep            `thenNat` \ tmp ->
+    let
+       dst    = registerName register pv
+       code   = registerCode register pv
+       target = registerName register pv
+    in
+    if isFixed register then
+       returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
+    else
+    return (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
+
+#endif /* alpha_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if i386_TARGET_ARCH
+
+genJump (CmmLoad mem pk) = do
+  Amode target code <- getAmode mem
+  return (code `snocOL` JMP (OpAddr target))
+
+genJump (CmmLit lit) = do
+  return (unitOL (JMP (OpImm (litToImm lit))))
+
+genJump expr = do
+  (reg,code) <- getSomeReg expr
+  return (code `snocOL` JMP (OpReg reg))
+
+#endif /* i386_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if sparc_TARGET_ARCH
+
+genJump (CmmLabel lbl)
+  = return (toOL [CALL (Left target) 0 True, NOP])
+  where
+    target = ImmCLbl lbl
+
+genJump tree
+  = getRegister tree                       `thenNat` \ register ->
+    getNewRegNat PtrRep            `thenNat` \ tmp ->
+    let
+       code   = registerCode register tmp
+       target = registerName register tmp
+    in
+    return (code `snocOL` JMP dsts (AddrRegReg target g0) `snocOL` NOP)
+
+#endif /* sparc_TARGET_ARCH */
+
+#if powerpc_TARGET_ARCH
+genJump (CmmLit (CmmLabel lbl))
+  = return (unitOL $ JMP lbl)
+
+genJump tree
+  = do
+        (target,code) <- getSomeReg tree
+        return (code `snocOL` MTCTR target `snocOL` BCTR [])
+#endif /* powerpc_TARGET_ARCH */
+
+
+-- -----------------------------------------------------------------------------
+--  Unconditional branches
+
+genBranch :: BlockId -> NatM InstrBlock
+
+#if alpha_TARGET_ARCH
+genBranch id = return (unitOL (BR id))
+#endif
+
+#if i386_TARGET_ARCH
+genBranch id = return (unitOL (JXX ALWAYS id))
+#endif
+
+#if sparc_TARGET_ARCH
+genBranch id = return (toOL [BI ALWAYS False id, NOP])
+#endif
+
+#if powerpc_TARGET_ARCH
+genBranch id = return (unitOL (BCC ALWAYS id))
+#endif
+
+
+-- -----------------------------------------------------------------------------
+--  Conditional jumps
+
+{-
+Conditional jumps are always to local labels, so we can use branch
+instructions.  We peek at the arguments to decide what kind of
+comparison to do.
+
+ALPHA: For comparisons with 0, we're laughing, because we can just do
+the desired conditional branch.
+
+I386: First, we have to ensure that the condition
+codes are set according to the supplied comparison operation.
+
+SPARC: First, we have to ensure that the condition codes are set
+according to the supplied comparison operation.  We generate slightly
+different code for floating point comparisons, because a floating
+point operation cannot directly precede a @BF@.  We assume the worst
+and fill that slot with a @NOP@.
+
+SPARC: Do not fill the delay slots here; you will confuse the register
+allocator.
+-}
+
+
+genCondJump
+    :: BlockId     -- the branch target
+    -> CmmExpr      -- the condition on which to branch
+    -> NatM InstrBlock
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if alpha_TARGET_ARCH
+
+genCondJump id (StPrim op [x, StInt 0])
+  = getRegister x                          `thenNat` \ register ->
+    getNewRegNat (registerRep register)
+                                   `thenNat` \ tmp ->
+    let
+       code   = registerCode register tmp
+       value  = registerName register tmp
+       pk     = registerRep register
+       target = ImmCLbl lbl
+    in
+    returnSeq code [BI (cmpOp op) value target]
+  where
+    cmpOp CharGtOp = GTT
+    cmpOp CharGeOp = GE
+    cmpOp CharEqOp = EQQ
+    cmpOp CharNeOp = NE
+    cmpOp CharLtOp = LTT
+    cmpOp CharLeOp = LE
+    cmpOp IntGtOp = GTT
+    cmpOp IntGeOp = GE
+    cmpOp IntEqOp = EQQ
+    cmpOp IntNeOp = NE
+    cmpOp IntLtOp = LTT
+    cmpOp IntLeOp = LE
+    cmpOp WordGtOp = NE
+    cmpOp WordGeOp = ALWAYS
+    cmpOp WordEqOp = EQQ
+    cmpOp WordNeOp = NE
+    cmpOp WordLtOp = NEVER
+    cmpOp WordLeOp = EQQ
+    cmpOp AddrGtOp = NE
+    cmpOp AddrGeOp = ALWAYS
+    cmpOp AddrEqOp = EQQ
+    cmpOp AddrNeOp = NE
+    cmpOp AddrLtOp = NEVER
+    cmpOp AddrLeOp = EQQ
+
+genCondJump lbl (StPrim op [x, StDouble 0.0])
+  = getRegister x                          `thenNat` \ register ->
+    getNewRegNat (registerRep register)
+                                   `thenNat` \ tmp ->
+    let
+       code   = registerCode register tmp
+       value  = registerName register tmp
+       pk     = registerRep register
+       target = ImmCLbl lbl
+    in
+    return (code . mkSeqInstr (BF (cmpOp op) value target))
+  where
+    cmpOp FloatGtOp = GTT
+    cmpOp FloatGeOp = GE
+    cmpOp FloatEqOp = EQQ
+    cmpOp FloatNeOp = NE
+    cmpOp FloatLtOp = LTT
+    cmpOp FloatLeOp = LE
+    cmpOp DoubleGtOp = GTT
+    cmpOp DoubleGeOp = GE
+    cmpOp DoubleEqOp = EQQ
+    cmpOp DoubleNeOp = NE
+    cmpOp DoubleLtOp = LTT
+    cmpOp DoubleLeOp = LE
+
+genCondJump lbl (StPrim op [x, y])
+  | fltCmpOp op
+  = trivialFCode pr instr x y      `thenNat` \ register ->
+    getNewRegNat F64               `thenNat` \ tmp ->
+    let
+       code   = registerCode register tmp
+       result = registerName register tmp
+       target = ImmCLbl lbl
+    in
+    return (code . mkSeqInstr (BF cond result target))
+  where
+    pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
+
+    fltCmpOp op = case op of
+       FloatGtOp -> True
+       FloatGeOp -> True
+       FloatEqOp -> True
+       FloatNeOp -> True
+       FloatLtOp -> True
+       FloatLeOp -> True
+       DoubleGtOp -> True
+       DoubleGeOp -> True
+       DoubleEqOp -> True
+       DoubleNeOp -> True
+       DoubleLtOp -> True
+       DoubleLeOp -> True
+       _ -> False
+    (instr, cond) = case op of
+       FloatGtOp -> (FCMP TF LE, EQQ)
+       FloatGeOp -> (FCMP TF LTT, EQQ)
+       FloatEqOp -> (FCMP TF EQQ, NE)
+       FloatNeOp -> (FCMP TF EQQ, EQQ)
+       FloatLtOp -> (FCMP TF LTT, NE)
+       FloatLeOp -> (FCMP TF LE, NE)
+       DoubleGtOp -> (FCMP TF LE, EQQ)
+       DoubleGeOp -> (FCMP TF LTT, EQQ)
+       DoubleEqOp -> (FCMP TF EQQ, NE)
+       DoubleNeOp -> (FCMP TF EQQ, EQQ)
+       DoubleLtOp -> (FCMP TF LTT, NE)
+       DoubleLeOp -> (FCMP TF LE, NE)
+
+genCondJump lbl (StPrim op [x, y])
+  = trivialCode instr x y          `thenNat` \ register ->
+    getNewRegNat IntRep            `thenNat` \ tmp ->
+    let
+       code   = registerCode register tmp
+       result = registerName register tmp
+       target = ImmCLbl lbl
+    in
+    return (code . mkSeqInstr (BI cond result target))
+  where
+    (instr, cond) = case op of
+       CharGtOp -> (CMP LE, EQQ)
+       CharGeOp -> (CMP LTT, EQQ)
+       CharEqOp -> (CMP EQQ, NE)
+       CharNeOp -> (CMP EQQ, EQQ)
+       CharLtOp -> (CMP LTT, NE)
+       CharLeOp -> (CMP LE, NE)
+       IntGtOp -> (CMP LE, EQQ)
+       IntGeOp -> (CMP LTT, EQQ)
+       IntEqOp -> (CMP EQQ, NE)
+       IntNeOp -> (CMP EQQ, EQQ)
+       IntLtOp -> (CMP LTT, NE)
+       IntLeOp -> (CMP LE, NE)
+       WordGtOp -> (CMP ULE, EQQ)
+       WordGeOp -> (CMP ULT, EQQ)
+       WordEqOp -> (CMP EQQ, NE)
+       WordNeOp -> (CMP EQQ, EQQ)
+       WordLtOp -> (CMP ULT, NE)
+       WordLeOp -> (CMP ULE, NE)
+       AddrGtOp -> (CMP ULE, EQQ)
+       AddrGeOp -> (CMP ULT, EQQ)
+       AddrEqOp -> (CMP EQQ, NE)
+       AddrNeOp -> (CMP EQQ, EQQ)
+       AddrLtOp -> (CMP ULT, NE)
+       AddrLeOp -> (CMP ULE, NE)
+
+#endif /* alpha_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if i386_TARGET_ARCH
+
+genCondJump id bool = do
+  CondCode _ cond code <- getCondCode bool
+  return (code `snocOL` JXX cond id)
+
+#endif /* i386_TARGET_ARCH */
+
+
+#if sparc_TARGET_ARCH
+
+genCondJump id bool = do
+  CondCode is_float cond code <- getCondCode bool
+  return (
+       code `appOL` 
+       toOL (
+         if   is_float
+         then [NOP, BF cond False id, NOP]
+         else [BI cond False id, NOP]
+       )
+    )
+
+#endif /* sparc_TARGET_ARCH */
+
+
+#if powerpc_TARGET_ARCH
+
+genCondJump id bool = do
+  CondCode is_float cond code <- getCondCode bool
+  return (code `snocOL` BCC cond id)
+
+#endif /* powerpc_TARGET_ARCH */
+
+
+-- -----------------------------------------------------------------------------
+--  Generating C calls
+
+-- Now the biggest nightmare---calls.  Most of the nastiness is buried in
+-- @get_arg@, which moves the arguments to the correct registers/stack
+-- locations.  Apart from that, the code is easy.
+-- 
+-- (If applicable) Do not fill the delay slots here; you will confuse the
+-- register allocator.
+
+genCCall
+    :: CmmCallTarget           -- function to call
+    -> [(CmmReg,MachHint)]     -- where to put the result
+    -> [(CmmExpr,MachHint)]    -- arguments (of mixed type)
+    -> Maybe [GlobalReg]       -- volatile regs to save
+    -> NatM InstrBlock
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if alpha_TARGET_ARCH
+
+ccallResultRegs = 
+
+genCCall fn cconv result_regs args
+  = mapAccumLNat get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
+                         `thenNat` \ ((unused,_), argCode) ->
+    let
+       nRegs = length allArgRegs - length unused
+       code = asmSeqThen (map ($ []) argCode)
+    in
+       returnSeq code [
+           LDA pv (AddrImm (ImmLab (ptext fn))),
+           JSR ra (AddrReg pv) nRegs,
+           LDGP gp (AddrReg ra)]
+  where
+    ------------------------
+    {- Try to get a value into a specific register (or registers) for
+       a call.  The first 6 arguments go into the appropriate
+       argument register (separate registers for integer and floating
+       point arguments, but used in lock-step), and the remaining
+       arguments are dumped to the stack, beginning at 0(sp).  Our
+       first argument is a pair of the list of remaining argument
+       registers to be assigned for this call and the next stack
+       offset to use for overflowing arguments.  This way,
+       @get_Arg@ can be applied to all of a call's arguments using
+       @mapAccumLNat@.
+    -}
+    get_arg
+       :: ([(Reg,Reg)], Int)   -- Argument registers and stack offset (accumulator)
+       -> StixTree             -- Current argument
+       -> NatM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
+
+    -- We have to use up all of our argument registers first...
+
+    get_arg ((iDst,fDst):dsts, offset) arg
+      = getRegister arg                            `thenNat` \ register ->
+       let
+           reg  = if isFloatingRep pk then fDst else iDst
+           code = registerCode register reg
+           src  = registerName register reg
+           pk   = registerRep register
+       in
+       return (
+           if isFloatingRep pk then
+               ((dsts, offset), if isFixed register then
+                   code . mkSeqInstr (FMOV src fDst)
+                   else code)
+           else
+               ((dsts, offset), if isFixed register then
+                   code . mkSeqInstr (OR src (RIReg src) iDst)
+                   else code))
+
+    -- Once we have run out of argument registers, we move to the
+    -- stack...
+
+    get_arg ([], offset) arg
+      = getRegister arg                        `thenNat` \ register ->
+       getNewRegNat (registerRep register)
+                                       `thenNat` \ tmp ->
+       let
+           code = registerCode register tmp
+           src  = registerName register tmp
+           pk   = registerRep register
+           sz   = primRepToSize pk
+       in
+       return (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
+
+#endif /* alpha_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if i386_TARGET_ARCH
+
+-- we only cope with a single result for foreign calls
+genCCall (CmmPrim op) [(r,_)] args vols = do
+  case op of
+       MO_F32_Sqrt -> actuallyInlineFloatOp F32  (GSQRT F32) args
+       MO_F64_Sqrt -> actuallyInlineFloatOp F64 (GSQRT F64) args
+       
+       MO_F32_Sin  -> actuallyInlineFloatOp F32  (GSIN F32) args
+       MO_F64_Sin  -> actuallyInlineFloatOp F64 (GSIN F64) args
+       
+       MO_F32_Cos  -> actuallyInlineFloatOp F32  (GCOS F32) args
+       MO_F64_Cos  -> actuallyInlineFloatOp F64 (GCOS F64) args
+       
+       MO_F32_Tan  -> actuallyInlineFloatOp F32  (GTAN F32) args
+       MO_F64_Tan  -> actuallyInlineFloatOp F64 (GTAN F64) args
+       
+       other_op    -> outOfLineFloatOp op r args vols
+ where
+  actuallyInlineFloatOp rep instr [(x,_)]
+       = do res <- trivialUFCode rep instr x
+            any <- anyReg res
+            return (any (getRegisterReg r))
+
+genCCall target dest_regs args vols = do
+    sizes_n_codes <- mapM push_arg (reverse args)
+    delta <- getDeltaNat
+    let 
+       (sizes, push_codes) = unzip sizes_n_codes
+        tot_arg_size        = sum sizes
+    -- in
+    -- deal with static vs dynamic call targets
+    (callinsns,cconv) <-
+      case target of
+       -- CmmPrim -> ...
+        CmmForeignCall (CmmLit (CmmLabel lbl)) conv
+           -> -- ToDo: stdcall arg sizes
+             return (unitOL (CALL (Left fn_imm)), conv)
+          where fn_imm = ImmCLbl lbl
+        CmmForeignCall expr conv
+           -> do (dyn_c, dyn_r, dyn_rep) <- get_op expr
+                 ASSERT(dyn_rep == I32)
+                  return (dyn_c `snocOL` CALL (Right dyn_r), conv)
+
+    let        push_code = concatOL push_codes
+       call = callinsns `appOL`
+               toOL (
+                       -- Deallocate parameters after call for ccall;
+                       -- but not for stdcall (callee does it)
+                  (if cconv == StdCallConv then [] else 
+                  [ADD I32 (OpImm (ImmInt tot_arg_size)) (OpReg esp)])
+                  ++
+                  [DELTA (delta + tot_arg_size)]
+               )
+    -- in
+    setDeltaNat (delta + tot_arg_size)
+
+    let
+       -- assign the results, if necessary
+       assign_code []     = nilOL
+       assign_code [(dest,_hint)] = 
+         case rep of
+               I64 -> toOL [MOV I32 (OpReg eax) (OpReg r_dest),
+                            MOV I32 (OpReg edx) (OpReg r_dest_hi)]
+               F32 -> unitOL (GMOV fake0 r_dest)
+               F64 -> unitOL (GMOV fake0 r_dest)
+               rep -> unitOL (MOV rep (OpReg eax) (OpReg r_dest))
+         where 
+               r_dest_hi = getHiVRegFromLo r_dest
+               rep = cmmRegRep dest
+               r_dest = getRegisterReg dest
+       assign_code many = panic "genCCall.assign_code many"
+
+    return (push_code `appOL` 
+           call `appOL` 
+           assign_code dest_regs)
+
+  where
+    arg_size F64 = 8
+    arg_size F32 = 4
+    arg_size _   = 4
+
+    push_arg :: (CmmExpr,MachHint){-current argument-}
+                    -> NatM (Int, InstrBlock)  -- argsz, code
+
+    push_arg (arg,_hint) -- we don't need the hints on x86
+      | arg_rep == I64 = do
+        ChildCode64 code r_lo <- iselExpr64 arg
+        delta <- getDeltaNat
+        setDeltaNat (delta - 8)
+        let 
+            r_hi = getHiVRegFromLo r_lo
+        -- in
+       return (8,     code `appOL`
+                       toOL [PUSH I32 (OpReg r_hi), DELTA (delta - 4),
+                             PUSH I32 (OpReg r_lo), DELTA (delta - 8),
+                            DELTA (delta-8)]
+            )
+
+      | otherwise = do
+        (code, reg, sz) <- get_op arg
+        delta <- getDeltaNat
+        let size = arg_size sz
+        setDeltaNat (delta-size)
+        if (case sz of F64 -> True; F32 -> True; _ -> False)
+           then return (size,
+                        code `appOL`
+                        toOL [SUB I32 (OpImm (ImmInt size)) (OpReg esp),
+                              DELTA (delta-size),
+                              GST sz reg (AddrBaseIndex (Just esp) 
+                                                        Nothing 
+                                                        (ImmInt 0))]
+                       )
+           else return (size,
+                        code `snocOL`
+                        PUSH I32 (OpReg reg) `snocOL`
+                        DELTA (delta-size)
+                       )
+      where
+         arg_rep = cmmExprRep arg
+
+    ------------
+    get_op :: CmmExpr -> NatM (InstrBlock, Reg, MachRep) -- code, reg, size
+    get_op op = do
+        (reg,code) <- getSomeReg op
+       return (code, reg, cmmExprRep op)
+
+
+outOfLineFloatOp :: CallishMachOp -> CmmReg -> [(CmmExpr,MachHint)]
+  -> Maybe [GlobalReg] -> NatM InstrBlock
+outOfLineFloatOp mop res args vols
+  | cmmRegRep res == F64
+  = stmtToInstrs (CmmCall target [(res,FloatHint)] args vols)
+
+  | otherwise
+  = do uq <- getUniqueNat
+       let 
+        tmp = CmmLocal (LocalReg uq F64)
+       -- in
+       code1 <- stmtToInstrs (CmmCall target [(tmp,FloatHint)] (map promote args) vols)
+       code2 <- stmtToInstrs (CmmAssign res (demote (CmmReg tmp)))
+       return (code1 `appOL` code2)
+  where
+        promote (x,hint) = (CmmMachOp (MO_S_Conv F32 F64) [x], hint)
+        demote  x = CmmMachOp (MO_S_Conv F64 F32) [x]
+
+       target = CmmForeignCall (CmmLit lbl) CCallConv
+       lbl = CmmLabel (mkForeignLabel fn Nothing False)
+
+       fn = case mop of
+             MO_F32_Exp   -> FSLIT("exp")
+             MO_F32_Log   -> FSLIT("log")
+
+             MO_F32_Asin  -> FSLIT("asin")
+             MO_F32_Acos  -> FSLIT("acos")
+             MO_F32_Atan  -> FSLIT("atan")
+
+             MO_F32_Sinh  -> FSLIT("sinh")
+             MO_F32_Cosh  -> FSLIT("cosh")
+             MO_F32_Tanh  -> FSLIT("tanh")
+             MO_F32_Pwr   -> FSLIT("pow")
+
+             MO_F64_Exp   -> FSLIT("exp")
+             MO_F64_Log   -> FSLIT("log")
+
+             MO_F64_Asin  -> FSLIT("asin")
+             MO_F64_Acos  -> FSLIT("acos")
+             MO_F64_Atan  -> FSLIT("atan")
+
+             MO_F64_Sinh  -> FSLIT("sinh")
+             MO_F64_Cosh  -> FSLIT("cosh")
+             MO_F64_Tanh  -> FSLIT("tanh")
+             MO_F64_Pwr   -> FSLIT("pow")
+
+              other -> pprPanic "outOfLineFloatOp" (pprCallishMachOp mop)
+
+#endif /* i386_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if sparc_TARGET_ARCH
+{- 
+   The SPARC calling convention is an absolute
+   nightmare.  The first 6x32 bits of arguments are mapped into
+   %o0 through %o5, and the remaining arguments are dumped to the
+   stack, beginning at [%sp+92].  (Note that %o6 == %sp.)
+
+   If we have to put args on the stack, move %o6==%sp down by
+   the number of words to go on the stack, to ensure there's enough space.
+
+   According to Fraser and Hanson's lcc book, page 478, fig 17.2,
+   16 words above the stack pointer is a word for the address of
+   a structure return value.  I use this as a temporary location
+   for moving values from float to int regs.  Certainly it isn't
+   safe to put anything in the 16 words starting at %sp, since
+   this area can get trashed at any time due to window overflows
+   caused by signal handlers.
+
+   A final complication (if the above isn't enough) is that 
+   we can't blithely calculate the arguments one by one into
+   %o0 .. %o5.  Consider the following nested calls:
+
+       fff a (fff b c)
+
+   Naive code moves a into %o0, and (fff b c) into %o1.  Unfortunately
+   the inner call will itself use %o0, which trashes the value put there
+   in preparation for the outer call.  Upshot: we need to calculate the
+   args into temporary regs, and move those to arg regs or onto the
+   stack only immediately prior to the call proper.  Sigh.
+-}
+
+genCCall fn cconv kind args
+  = mapNat arg_to_int_vregs args `thenNat` \ argcode_and_vregs ->
+    let 
+        (argcodes, vregss) = unzip argcode_and_vregs
+        n_argRegs          = length allArgRegs
+        n_argRegs_used     = min (length vregs) n_argRegs
+        vregs              = concat vregss
+    in
+    -- deal with static vs dynamic call targets
+    (case fn of
+        Left t_static
+           -> return (unitOL (CALL (Left fn__2) n_argRegs_used False))
+        Right dyn
+           -> arg_to_int_vregs dyn `thenNat` \ (dyn_c, [dyn_r]) ->
+              return (dyn_c `snocOL` CALL (Right dyn_r) n_argRegs_used False)
+    )
+                               `thenNat` \ callinsns ->
+    let
+        argcode = concatOL argcodes
+        (move_sp_down, move_sp_up)
+           = let diff = length vregs - n_argRegs
+                 nn   = if odd diff then diff + 1 else diff -- keep 8-byte alignment
+             in  if   nn <= 0
+                 then (nilOL, nilOL)
+                 else (unitOL (moveSp (-1*nn)), unitOL (moveSp (1*nn)))
+        transfer_code
+           = toOL (move_final vregs allArgRegs eXTRA_STK_ARGS_HERE)
+    in
+        return (argcode       `appOL`
+                   move_sp_down  `appOL`
+                   transfer_code `appOL`
+                   callinsns     `appOL`
+                   unitOL NOP    `appOL`
+                   move_sp_up)
+  where
+     -- function names that begin with '.' are assumed to be special
+     -- internally generated names like '.mul,' which don't get an
+     -- underscore prefix
+     -- ToDo:needed (WDP 96/03) ???
+     fn_static = unLeft fn
+     fn__2 = case (headFS fn_static) of
+               '.' -> ImmLit (ftext fn_static)
+               _   -> ImmCLbl (mkForeignLabel fn_static False)
+
+     -- move args from the integer vregs into which they have been 
+     -- marshalled, into %o0 .. %o5, and the rest onto the stack.
+     move_final :: [Reg] -> [Reg] -> Int -> [Instr]
+
+     move_final [] _ offset          -- all args done
+        = []
+
+     move_final (v:vs) [] offset     -- out of aregs; move to stack
+        = ST W v (spRel offset)
+          : move_final vs [] (offset+1)
+
+     move_final (v:vs) (a:az) offset -- move into an arg (%o[0..5]) reg
+        = OR False g0 (RIReg v) a
+          : move_final vs az offset
+
+     -- generate code to calculate an argument, and move it into one
+     -- or two integer vregs.
+     arg_to_int_vregs :: CmmExpr -> NatM (OrdList Instr, [Reg])
+     arg_to_int_vregs arg
+        | is64BitRep (repOfCmmExpr arg)
+        = iselExpr64 arg               `thenNat` \ (ChildCode64 code vr_lo) ->
+          let r_lo = VirtualRegI vr_lo
+              r_hi = getHiVRegFromLo r_lo
+          in  return (code, [r_hi, r_lo])
+        | otherwise
+        = getRegister arg                     `thenNat` \ register ->
+          getNewRegNat (registerRep register) `thenNat` \ tmp ->
+          let code = registerCode register tmp
+              src  = registerName register tmp
+              pk   = registerRep register
+          in
+          -- the value is in src.  Get it into 1 or 2 int vregs.
+          case pk of
+             F64 -> 
+                getNewRegNat WordRep  `thenNat` \ v1 ->
+                getNewRegNat WordRep  `thenNat` \ v2 ->
+                return (
+                   code                          `snocOL`
+                   FMOV DF src f0                `snocOL`
+                   ST   F  f0 (spRel 16)         `snocOL`
+                   LD   W  (spRel 16) v1         `snocOL`
+                   ST   F  (fPair f0) (spRel 16) `snocOL`
+                   LD   W  (spRel 16) v2
+                   ,
+                   [v1,v2]
+                )
+             F32 -> 
+                getNewRegNat WordRep  `thenNat` \ v1 ->
+                return (
+                   code                    `snocOL`
+                   ST   F  src (spRel 16)  `snocOL`
+                   LD   W  (spRel 16) v1
+                   ,
+                   [v1]
+                )
+             other ->
+                getNewRegNat WordRep  `thenNat` \ v1 ->
+                return (
+                   code `snocOL` OR False g0 (RIReg src) v1
+                   , 
+                   [v1]
+                )
+#endif /* sparc_TARGET_ARCH */
+
+#if powerpc_TARGET_ARCH
+
+#if darwin_TARGET_OS || linux_TARGET_OS
+{-
+    The PowerPC calling convention for Darwin/Mac OS X
+    is described in Apple's document
+    "Inside Mac OS X - Mach-O Runtime Architecture".
+    
+    PowerPC Linux uses the System V Release 4 Calling Convention
+    for PowerPC. It is described in the
+    "System V Application Binary Interface PowerPC Processor Supplement".
+
+    Both conventions are similar:
+    Parameters may be passed in general-purpose registers starting at r3, in
+    floating point registers starting at f1, or on the stack. 
+    
+    But there are substantial differences:
+    * The number of registers used for parameter passing and the exact set of
+      nonvolatile registers differs (see MachRegs.lhs).
+    * On Darwin, stack space is always reserved for parameters, even if they are
+      passed in registers. The called routine may choose to save parameters from
+      registers to the corresponding space on the stack.
+    * On Darwin, a corresponding amount of GPRs is skipped when a floating point
+      parameter is passed in an FPR.
+    * SysV insists on either passing I64 arguments on the stack, or in two GPRs,
+      starting with an odd-numbered GPR. It may skip a GPR to achieve this.
+      Darwin just treats an I64 like two separate I32s (high word first).
+      
+    According to both conventions, The parameter area should be part of the
+    caller's stack frame, allocated in the caller's prologue code (large enough
+    to hold the parameter lists for all called routines). The NCG already
+    uses the stack for register spilling, leaving 64 bytes free at the top.
+    If we need a larger parameter area than that, we just allocate a new stack
+    frame just before ccalling.
+-}
+
+genCCall target dest_regs argsAndHints vols
+  = ASSERT (not $ any (`elem` [I8,I16]) argReps)
+        -- we rely on argument promotion in the codeGen
+    do
+        (finalStack,passArgumentsCode,usedRegs) <- passArguments
+                                                        (zip args argReps)
+                                                        allArgRegs allFPArgRegs
+                                                        initialStackOffset
+                                                        (toOL []) []
+                                                
+        let codeBefore = move_sp_down finalStack `appOL` passArgumentsCode
+            codeAfter = move_sp_up finalStack `appOL` moveResult
+
+        case labelOrExpr of
+            Left lbl -> do
+               addImportNat True lbl
+               return (         codeBefore
+                        `snocOL` BL lbl usedRegs
+                        `appOL`         codeAfter)
+            Right dyn -> do
+               (dynReg, dynCode) <- getSomeReg dyn
+               return (         dynCode
+                       `snocOL` MTCTR dynReg
+                        `appOL`         codeBefore
+                        `snocOL` BCTRL usedRegs
+                        `appOL`         codeAfter)
+    where
+#if darwin_TARGET_OS
+        initialStackOffset = 24
+           -- size of linkage area + size of arguments, in bytes       
+       stackDelta _finalStack = roundTo16 $ (24 +) $ max 32 $ sum $
+                                      map machRepByteWidth argReps
+#elif linux_TARGET_OS
+        initialStackOffset = 8
+        stackDelta finalStack = roundTo16 finalStack
+#endif
+       args = map fst argsAndHints
+       argReps = map cmmExprRep args
+
+       roundTo16 x | x `mod` 16 == 0 = x
+                   | otherwise = x + 16 - (x `mod` 16)
+
+        move_sp_down finalStack
+               | delta > 64 =
+                        toOL [STU I32 sp (AddrRegImm sp (ImmInt (-delta))),
+                             DELTA (-delta)]
+              | otherwise = nilOL
+              where delta = stackDelta finalStack
+       move_sp_up finalStack
+              | delta > 64 =
+                        toOL [ADD sp sp (RIImm (ImmInt delta)),
+                              DELTA 0]
+              | otherwise = nilOL
+              where delta = stackDelta finalStack
+              
+
+        passArguments [] _ _ stackOffset accumCode accumUsed = return (stackOffset, accumCode, accumUsed)
+        passArguments ((arg,I64):args) gprs fprs stackOffset
+               accumCode accumUsed =
+            do
+                ChildCode64 code vr_lo <- iselExpr64 arg
+                let vr_hi = getHiVRegFromLo vr_lo
+
+#if darwin_TARGET_OS                
+                passArguments args
+                              (drop 2 gprs)
+                              fprs
+                              (stackOffset+8)
+                              (accumCode `appOL` code
+                                    `snocOL` storeWord vr_hi gprs stackOffset
+                                    `snocOL` storeWord vr_lo (drop 1 gprs) (stackOffset+4))
+                              ((take 2 gprs) ++ accumUsed)
+            where
+                storeWord vr (gpr:_) offset = MR gpr vr
+                storeWord vr [] offset = ST I32 vr (AddrRegImm sp (ImmInt offset))
+                
+#elif linux_TARGET_OS
+                let stackCode = accumCode `appOL` code
+                        `snocOL` ST I32 vr_hi (AddrRegImm sp (ImmInt stackOffset))
+                        `snocOL` ST I32 vr_lo (AddrRegImm sp (ImmInt (stackOffset+4)))
+                    regCode hireg loreg =
+                        accumCode `appOL` code
+                            `snocOL` MR hireg vr_hi
+                            `snocOL` MR loreg vr_lo
+                                        
+                case gprs of
+                    hireg : loreg : regs | even (length gprs) ->
+                        passArguments args regs fprs stackOffset
+                                      (regCode hireg loreg) (hireg : loreg : accumUsed)
+                    _skipped : hireg : loreg : regs ->
+                        passArguments args regs fprs stackOffset
+                                      (regCode hireg loreg) (hireg : loreg : accumUsed)
+                    _ -> -- only one or no regs left
+                        passArguments args [] fprs (stackOffset+8)
+                                      stackCode accumUsed
+#endif
+        
+        passArguments ((arg,rep):args) gprs fprs stackOffset accumCode accumUsed
+            | reg : _ <- regs = do
+                register <- getRegister arg
+                let code = case register of
+                            Fixed _ freg fcode -> fcode `snocOL` MR reg freg
+                            Any _ acode -> acode reg
+                passArguments args
+                              (drop nGprs gprs)
+                              (drop nFprs fprs)
+#if darwin_TARGET_OS
+        -- The Darwin ABI requires that we reserve stack slots for register parameters
+                              (stackOffset + stackBytes)
+#elif linux_TARGET_OS
+        -- ... the SysV ABI doesn't.
+                              stackOffset
+#endif
+                              (accumCode `appOL` code)
+                              (reg : accumUsed)
+            | otherwise = do
+                (vr, code) <- getSomeReg arg
+                passArguments args
+                              (drop nGprs gprs)
+                              (drop nFprs fprs)
+                              (stackOffset + stackBytes)
+                              (accumCode `appOL` code `snocOL` ST rep vr stackSlot)
+                              accumUsed
+            where
+                stackSlot = AddrRegImm sp (ImmInt stackOffset)
+                (nGprs, nFprs, stackBytes, regs) = case rep of
+                    I32 -> (1, 0, 4, gprs)
+#if darwin_TARGET_OS
+        -- The Darwin ABI requires that we skip a corresponding number of GPRs when
+        -- we use the FPRs.
+                    F32 -> (1, 1, 4, fprs)
+                    F64 -> (2, 1, 8, fprs)
+#elif linux_TARGET_OS
+        -- ... the SysV ABI doesn't.
+                    F32 -> (0, 1, 4, fprs)
+                    F64 -> (0, 1, 8, fprs)
+#endif
+        
+        moveResult =
+            case dest_regs of
+                [] -> nilOL
+                [(dest, _hint)]
+                    | reduceToF32 && rep == F32 -> unitOL (FRSP r_dest f1)
+                    | rep == F32 || rep == F64 -> unitOL (MR r_dest f1)
+                    | rep == I64 -> toOL [MR (getHiVRegFromLo r_dest) r3,
+                                          MR r_dest r4]
+                    | otherwise -> unitOL (MR r_dest r3)
+                    where rep = cmmRegRep dest
+                          r_dest = getRegisterReg dest
+                          
+        (labelOrExpr, reduceToF32) = case target of
+            CmmForeignCall (CmmLit (CmmLabel lbl)) conv -> (Left lbl, False)
+            CmmForeignCall expr conv -> (Right expr, False)
+            CmmPrim mop -> (Left $ mkForeignLabel label Nothing False, reduce)
+                where
+                    (label, reduce) = case mop of
+                        MO_F32_Exp   -> (FSLIT("exp"), True)
+                        MO_F32_Log   -> (FSLIT("log"), True)
+                        MO_F32_Sqrt  -> (FSLIT("sqrt"), True)
+                        
+                        MO_F32_Sin   -> (FSLIT("sin"), True)
+                        MO_F32_Cos   -> (FSLIT("cos"), True)
+                        MO_F32_Tan   -> (FSLIT("tan"), True)
+                        
+                        MO_F32_Asin  -> (FSLIT("asin"), True)
+                        MO_F32_Acos  -> (FSLIT("acos"), True)
+                        MO_F32_Atan  -> (FSLIT("atan"), True)
+                        
+                        MO_F32_Sinh  -> (FSLIT("sinh"), True)
+                        MO_F32_Cosh  -> (FSLIT("cosh"), True)
+                        MO_F32_Tanh  -> (FSLIT("tanh"), True)
+                        MO_F32_Pwr   -> (FSLIT("pow"), True)
+                        
+                        MO_F64_Exp   -> (FSLIT("exp"), False)
+                        MO_F64_Log   -> (FSLIT("log"), False)
+                        MO_F64_Sqrt  -> (FSLIT("sqrt"), False)
+                        
+                        MO_F64_Sin   -> (FSLIT("sin"), False)
+                        MO_F64_Cos   -> (FSLIT("cos"), False)
+                        MO_F64_Tan   -> (FSLIT("tan"), False)
+                        
+                        MO_F64_Asin  -> (FSLIT("asin"), False)
+                        MO_F64_Acos  -> (FSLIT("acos"), False)
+                        MO_F64_Atan  -> (FSLIT("atan"), False)
+                        
+                        MO_F64_Sinh  -> (FSLIT("sinh"), False)
+                        MO_F64_Cosh  -> (FSLIT("cosh"), False)
+                        MO_F64_Tanh  -> (FSLIT("tanh"), False)
+                        MO_F64_Pwr   -> (FSLIT("pow"), False)
+                        other -> pprPanic "genCCall(ppc): unknown callish op"
+                                        (pprCallishMachOp other)
+
+#endif /* darwin_TARGET_OS || linux_TARGET_OS */
+                
+#endif /* powerpc_TARGET_ARCH */
+
+
+-- -----------------------------------------------------------------------------
+-- Generating a table-branch
+
+genSwitch :: CmmExpr -> [Maybe BlockId] -> NatM InstrBlock
+
+#if i386_TARGET_ARCH
+genSwitch expr ids = do
+  (reg,e_code) <- getSomeReg expr
+  lbl <- getNewLabelNat
+  let
+       jumpTable = map jumpTableEntry ids
+       op = OpAddr (AddrBaseIndex Nothing (Just (reg,4)) (ImmCLbl lbl))
+       code = e_code `appOL` toOL [
+               LDATA ReadOnlyData (CmmDataLabel lbl : jumpTable),
+               JMP_TBL op [ id | Just id <- ids ]
+            ]
+  -- in
+  return code
+#elif powerpc_TARGET_ARCH
+genSwitch expr ids = do
+  (reg,e_code) <- getSomeReg expr
+  tmp <- getNewRegNat I32
+  lbl <- getNewLabelNat
+  let
+       jumpTable = map jumpTableEntry ids
+
+        code = e_code `appOL` toOL [
+                        LDATA ReadOnlyData (CmmDataLabel lbl : jumpTable),
+                        SLW tmp reg (RIImm (ImmInt 2)),
+                        ADDIS tmp tmp (HA (ImmCLbl lbl)),
+                        LD I32 tmp (AddrRegImm tmp (LO (ImmCLbl lbl))),
+                        MTCTR tmp,
+                        BCTR [ id | Just id <- ids ]
+                ]
+  -- in
+  return code
+#else
+genSwitch expr ids = panic "ToDo: genSwitch"
+#endif
+
+jumpTableEntry Nothing = CmmStaticLit (CmmInt 0 wordRep)
+jumpTableEntry (Just (BlockId id)) = CmmStaticLit (CmmLabel blockLabel)
+    where blockLabel = mkAsmTempLabel id
+
+-- -----------------------------------------------------------------------------
+-- Support bits
+-- -----------------------------------------------------------------------------
+
+
+-- -----------------------------------------------------------------------------
+-- 'condIntReg' and 'condFltReg': condition codes into registers
+
+-- Turn those condition codes into integers now (when they appear on
+-- the right hand side of an assignment).
+-- 
+-- (If applicable) Do not fill the delay slots here; you will confuse the
+-- register allocator.
+
+condIntReg, condFltReg :: Cond -> CmmExpr -> CmmExpr -> NatM Register
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if alpha_TARGET_ARCH
+condIntReg = panic "MachCode.condIntReg (not on Alpha)"
+condFltReg = panic "MachCode.condFltReg (not on Alpha)"
+#endif /* alpha_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if i386_TARGET_ARCH
+
+condIntReg cond x y = do
+  CondCode _ cond cond_code <- condIntCode cond x y
+  tmp <- getNewRegNat I8
+  let 
+       code dst = cond_code `appOL` toOL [
+                   SETCC cond (OpReg tmp),
+                   MOV I32 (OpReg tmp) (OpReg dst),
+                   AND I32 (OpImm (ImmInt 1)) (OpReg dst)
+                 ]
+                  -- NB. (1) Tha AND is needed here because the x86 only
+                  -- sets the low byte in the SETCC instruction.
+                  -- NB. (2) The extra temporary register is a hack to
+                  -- work around the fact that the setcc instructions only
+                  -- accept byte registers.  dst might not be a byte-able reg,
+                  -- but currently all free registers are byte-able, so we're
+                  -- guaranteed that a new temporary is byte-able.
+  -- in
+  return (Any I32 code)
+
+
+condFltReg cond x y = do
+  lbl1 <- getBlockIdNat
+  lbl2 <- getBlockIdNat
+  CondCode _ cond cond_code <- condFltCode cond x y
+  let
+       code dst = cond_code `appOL` toOL [
+           JXX cond lbl1,
+           MOV I32 (OpImm (ImmInt 0)) (OpReg dst),
+           JXX ALWAYS lbl2,
+           NEWBLOCK lbl1,
+           MOV I32 (OpImm (ImmInt 1)) (OpReg dst),
+           JXX ALWAYS lbl2,
+           NEWBLOCK lbl2]
+               -- SIGH, have to split up this block somehow...
+  -- in
+  return (Any I32 code)
+
+#endif /* i386_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if sparc_TARGET_ARCH
+
+condIntReg EQQ x (StInt 0)
+  = getRegister x              `thenNat` \ register ->
+    getNewRegNat IntRep                `thenNat` \ tmp ->
+    let
+       code = registerCode register tmp
+       src  = registerName register tmp
+       code__2 dst = code `appOL` toOL [
+           SUB False True g0 (RIReg src) g0,
+           SUB True False g0 (RIImm (ImmInt (-1))) dst]
+    in
+    return (Any IntRep code__2)
+
+condIntReg EQQ x y
+  = getRegister x              `thenNat` \ register1 ->
+    getRegister y              `thenNat` \ register2 ->
+    getNewRegNat IntRep                `thenNat` \ tmp1 ->
+    getNewRegNat IntRep                `thenNat` \ tmp2 ->
+    let
+       code1 = registerCode register1 tmp1
+       src1  = registerName register1 tmp1
+       code2 = registerCode register2 tmp2
+       src2  = registerName register2 tmp2
+       code__2 dst = code1 `appOL` code2 `appOL` toOL [
+           XOR False src1 (RIReg src2) dst,
+           SUB False True g0 (RIReg dst) g0,
+           SUB True False g0 (RIImm (ImmInt (-1))) dst]
+    in
+    return (Any IntRep code__2)
+
+condIntReg NE x (StInt 0)
+  = getRegister x              `thenNat` \ register ->
+    getNewRegNat IntRep        `thenNat` \ tmp ->
+    let
+       code = registerCode register tmp
+       src  = registerName register tmp
+       code__2 dst = code `appOL` toOL [
+           SUB False True g0 (RIReg src) g0,
+           ADD True False g0 (RIImm (ImmInt 0)) dst]
+    in
+    return (Any IntRep code__2)
+
+condIntReg NE x y
+  = getRegister x              `thenNat` \ register1 ->
+    getRegister y              `thenNat` \ register2 ->
+    getNewRegNat IntRep                `thenNat` \ tmp1 ->
+    getNewRegNat IntRep                `thenNat` \ tmp2 ->
+    let
+       code1 = registerCode register1 tmp1
+       src1  = registerName register1 tmp1
+       code2 = registerCode register2 tmp2
+       src2  = registerName register2 tmp2
+       code__2 dst = code1 `appOL` code2 `appOL` toOL [
+           XOR False src1 (RIReg src2) dst,
+           SUB False True g0 (RIReg dst) g0,
+           ADD True False g0 (RIImm (ImmInt 0)) dst]
+    in
+    return (Any IntRep code__2)
+
+condIntReg cond x y
+  = getBlockIdNat              `thenNat` \ lbl1 ->
+    getBlockIdNat              `thenNat` \ lbl2 ->
+    condIntCode cond x y       `thenNat` \ condition ->
+    let
+       code = condCode condition
+       cond = condName condition
+       code__2 dst = code `appOL` toOL [
+           BI cond False (ImmCLbl lbl1), NOP,
+           OR False g0 (RIImm (ImmInt 0)) dst,
+           BI ALWAYS False (ImmCLbl lbl2), NOP,
+           NEWBLOCK lbl1,
+           OR False g0 (RIImm (ImmInt 1)) dst,
+           NEWBLOCK lbl2]
+    in
+    return (Any IntRep code__2)
+
+condFltReg cond x y
+  = getBlockIdNat              `thenNat` \ lbl1 ->
+    getBlockIdNat              `thenNat` \ lbl2 ->
+    condFltCode cond x y       `thenNat` \ condition ->
+    let
+       code = condCode condition
+       cond = condName condition
+       code__2 dst = code `appOL` toOL [
+           NOP,
+           BF cond False (ImmCLbl lbl1), NOP,
+           OR False g0 (RIImm (ImmInt 0)) dst,
+           BI ALWAYS False (ImmCLbl lbl2), NOP,
+           NEWBLOCK lbl1,
+           OR False g0 (RIImm (ImmInt 1)) dst,
+           NEWBLOCK lbl2]
+    in
+    return (Any IntRep code__2)
+
+#endif /* sparc_TARGET_ARCH */
+
+#if powerpc_TARGET_ARCH
+condReg getCond = do
+    lbl1 <- getBlockIdNat
+    lbl2 <- getBlockIdNat
+    CondCode _ cond cond_code <- getCond
+    let
+{-        code dst = cond_code `appOL` toOL [
+                BCC cond lbl1,
+                LI dst (ImmInt 0),
+                BCC ALWAYS lbl2,
+                NEWBLOCK lbl1,
+                LI dst (ImmInt 1),
+                BCC ALWAYS lbl2,
+                NEWBLOCK lbl2
+            ]-}
+        code dst = cond_code
+            `appOL` negate_code
+            `appOL` toOL [
+                MFCR dst,
+                RLWINM dst dst (bit + 1) 31 31
+            ]
+        
+        negate_code | do_negate = unitOL (CRNOR bit bit bit)
+                    | otherwise = nilOL
+                    
+        (bit, do_negate) = case cond of
+            LTT -> (0, False)
+            LE  -> (1, True)
+            EQQ -> (2, False)
+            GE  -> (0, True)
+            GTT -> (1, False)
+            
+            NE  -> (2, True)
+            
+            LU  -> (0, False)
+            LEU -> (1, True)
+            GEU -> (0, True)
+            GU  -> (1, False)
+                
+    return (Any I32 code)
+    
+condIntReg cond x y = condReg (condIntCode cond x y)
+condFltReg cond x y = condReg (condFltCode cond x y)
+#endif /* powerpc_TARGET_ARCH */
+
+
+-- -----------------------------------------------------------------------------
+-- 'trivial*Code': deal with trivial instructions
+
+-- Trivial (dyadic: 'trivialCode', floating-point: 'trivialFCode',
+-- unary: 'trivialUCode', unary fl-pt:'trivialUFCode') instructions.
+-- Only look for constants on the right hand side, because that's
+-- where the generic optimizer will have put them.
+
+-- Similarly, for unary instructions, we don't have to worry about
+-- matching an StInt as the argument, because genericOpt will already
+-- have handled the constant-folding.
+
+trivialCode
+    :: MachRep 
+    -> IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
+      ,IF_ARCH_i386 ((Operand -> Operand -> Instr) 
+                     -> Maybe (Operand -> Operand -> Instr)
+      ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
+      ,IF_ARCH_powerpc(Bool -> (Reg -> Reg -> RI -> Instr)
+      ,))))
+    -> CmmExpr -> CmmExpr -- the two arguments
+    -> NatM Register
+
+#ifndef powerpc_TARGET_ARCH
+trivialFCode
+    :: MachRep
+    -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
+      ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
+      ,IF_ARCH_i386 ((MachRep -> Reg -> Reg -> Reg -> Instr)
+      ,)))
+    -> CmmExpr -> CmmExpr -- the two arguments
+    -> NatM Register
+#endif
+
+trivialUCode
+    :: MachRep 
+    -> IF_ARCH_alpha((RI -> Reg -> Instr)
+      ,IF_ARCH_i386 ((Operand -> Instr)
+      ,IF_ARCH_sparc((RI -> Reg -> Instr)
+      ,IF_ARCH_powerpc((Reg -> Reg -> Instr)
+      ,))))
+    -> CmmExpr -- the one argument
+    -> NatM Register
+
+#ifndef powerpc_TARGET_ARCH
+trivialUFCode
+    :: MachRep
+    -> IF_ARCH_alpha((Reg -> Reg -> Instr)
+      ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
+      ,IF_ARCH_sparc((Reg -> Reg -> Instr)
+      ,)))
+    -> CmmExpr -- the one argument
+    -> NatM Register
+#endif
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if alpha_TARGET_ARCH
+
+trivialCode instr x (StInt y)
+  | fits8Bits y
+  = getRegister x              `thenNat` \ register ->
+    getNewRegNat IntRep                `thenNat` \ tmp ->
+    let
+       code = registerCode register tmp
+       src1 = registerName register tmp
+       src2 = ImmInt (fromInteger y)
+       code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
+    in
+    return (Any IntRep code__2)
+
+trivialCode instr x y
+  = getRegister x              `thenNat` \ register1 ->
+    getRegister y              `thenNat` \ register2 ->
+    getNewRegNat IntRep                `thenNat` \ tmp1 ->
+    getNewRegNat IntRep                `thenNat` \ tmp2 ->
+    let
+       code1 = registerCode register1 tmp1 []
+       src1  = registerName register1 tmp1
+       code2 = registerCode register2 tmp2 []
+       src2  = registerName register2 tmp2
+       code__2 dst = asmSeqThen [code1, code2] .
+                    mkSeqInstr (instr src1 (RIReg src2) dst)
+    in
+    return (Any IntRep code__2)
+
+------------
+trivialUCode instr x
+  = getRegister x              `thenNat` \ register ->
+    getNewRegNat IntRep                `thenNat` \ tmp ->
+    let
+       code = registerCode register tmp
+       src  = registerName register tmp
+       code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
+    in
+    return (Any IntRep code__2)
+
+------------
+trivialFCode _ instr x y
+  = getRegister x              `thenNat` \ register1 ->
+    getRegister y              `thenNat` \ register2 ->
+    getNewRegNat F64   `thenNat` \ tmp1 ->
+    getNewRegNat F64   `thenNat` \ tmp2 ->
+    let
+       code1 = registerCode register1 tmp1
+       src1  = registerName register1 tmp1
+
+       code2 = registerCode register2 tmp2
+       src2  = registerName register2 tmp2
+
+       code__2 dst = asmSeqThen [code1 [], code2 []] .
+                     mkSeqInstr (instr src1 src2 dst)
+    in
+    return (Any F64 code__2)
+
+trivialUFCode _ instr x
+  = getRegister x              `thenNat` \ register ->
+    getNewRegNat F64   `thenNat` \ tmp ->
+    let
+       code = registerCode register tmp
+       src  = registerName register tmp
+       code__2 dst = code . mkSeqInstr (instr src dst)
+    in
+    return (Any F64 code__2)
+
+#endif /* alpha_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if i386_TARGET_ARCH
+
+{-
+The Rules of the Game are:
+
+* You cannot assume anything about the destination register dst;
+  it may be anything, including a fixed reg.
+
+* You may compute an operand into a fixed reg, but you may not 
+  subsequently change the contents of that fixed reg.  If you
+  want to do so, first copy the value either to a temporary
+  or into dst.  You are free to modify dst even if it happens
+  to be a fixed reg -- that's not your problem.
+
+* You cannot assume that a fixed reg will stay live over an
+  arbitrary computation.  The same applies to the dst reg.
+
+* Temporary regs obtained from getNewRegNat are distinct from 
+  each other and from all other regs, and stay live over 
+  arbitrary computations.
+
+--------------------
+
+SDM's version of The Rules:
+
+* If getRegister returns Any, that means it can generate correct
+  code which places the result in any register, period.  Even if that
+  register happens to be read during the computation.
+
+  Corollary #1: this means that if you are generating code for an
+  operation with two arbitrary operands, you cannot assign the result
+  of the first operand into the destination register before computing
+  the second operand.  The second operand might require the old value
+  of the destination register.
+
+  Corollary #2: A function might be able to generate more efficient
+  code if it knows the destination register is a new temporary (and
+  therefore not read by any of the sub-computations).
+
+* If getRegister returns Any, then the code it generates may modify only:
+       (a) fresh temporaries
+       (b) the destination register
+       (c) known registers (eg. %ecx is used by shifts)
+  In particular, it may *not* modify global registers, unless the global
+  register happens to be the destination register.
+-}
+
+trivialCode rep instr maybe_revinstr a (CmmLit lit_b) = do
+  a_code <- getAnyReg a
+  let
+       code dst
+          = a_code dst `snocOL` 
+           instr (OpImm (litToImm lit_b)) (OpReg dst)
+  -- in
+  return (Any rep code)
+              
+trivialCode rep instr (Just revinstr) (CmmLit lit_a) b = do
+  b_code <- getAnyReg b
+  let
+       code dst 
+        = b_code dst `snocOL`
+           revinstr (OpImm (litToImm lit_a)) (OpReg dst)
+  -- in
+  return (Any rep code)
+
+trivialCode rep instr maybe_revinstr a b = do
+  (b_op, b_code) <- getOperand b
+  a_code <- getAnyReg a
+  tmp <- getNewRegNat rep
+  let
+     -- We want the value of b to stay alive across the computation of a.
+     -- But, we want to calculate a straight into the destination register,
+     -- because the instruction only has two operands (dst := dst `op` src).
+     -- The troublesome case is when the result of b is in the same register
+     -- as the destination reg.  In this case, we have to save b in a
+     -- new temporary across the computation of a.
+     code dst
+       | dst `clashesWith` b_op =
+               b_code `appOL`
+               unitOL (MOV rep b_op (OpReg tmp)) `appOL`
+               a_code dst `snocOL`
+               instr (OpReg tmp) (OpReg dst)
+       | otherwise =
+               b_code `appOL`
+               a_code dst `snocOL`
+               instr b_op (OpReg dst)
+  -- in
+  return (Any rep code)
+ where
+  reg `clashesWith` OpReg reg2   = reg == reg2
+  reg `clashesWith` OpAddr amode = any (==reg) (addrModeRegs amode)
+
+-----------
+
+trivialUCode rep instr x = do
+  x_code <- getAnyReg x
+  let
+     code dst =
+       x_code dst `snocOL`
+       instr (OpReg dst)
+  -- in
+  return (Any rep code)
+
+-----------
+
+trivialFCode pk instr x y = do
+  (x_reg, x_code) <- getNonClobberedReg x -- these work for float regs too
+  (y_reg, y_code) <- getSomeReg y
+  let
+     code dst =
+       x_code `appOL`
+       y_code `snocOL`
+       instr pk x_reg y_reg dst
+  -- in
+  return (Any pk code)
+
+-------------
+
+trivialUFCode rep instr x = do
+  (x_reg, x_code) <- getSomeReg x
+  let
+     code dst =
+       x_code `snocOL`
+       instr x_reg dst
+  -- in
+  return (Any rep code)
+
+#endif /* i386_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if sparc_TARGET_ARCH
+
+trivialCode instr x (StInt y)
+  | fits13Bits y
+  = getRegister x              `thenNat` \ register ->
+    getNewRegNat IntRep                `thenNat` \ tmp ->
+    let
+       code = registerCode register tmp
+       src1 = registerName register tmp
+       src2 = ImmInt (fromInteger y)
+       code__2 dst = code `snocOL` instr src1 (RIImm src2) dst
+    in
+    return (Any IntRep code__2)
+
+trivialCode instr x y
+  = getRegister x              `thenNat` \ register1 ->
+    getRegister y              `thenNat` \ register2 ->
+    getNewRegNat IntRep                `thenNat` \ tmp1 ->
+    getNewRegNat IntRep                `thenNat` \ tmp2 ->
+    let
+       code1 = registerCode register1 tmp1
+       src1  = registerName register1 tmp1
+       code2 = registerCode register2 tmp2
+       src2  = registerName register2 tmp2
+       code__2 dst = code1 `appOL` code2 `snocOL`
+                     instr src1 (RIReg src2) dst
+    in
+    return (Any IntRep code__2)
+
+------------
+trivialFCode pk instr x y
+  = getRegister x              `thenNat` \ register1 ->
+    getRegister y              `thenNat` \ register2 ->
+    getNewRegNat (registerRep register1)
+                               `thenNat` \ tmp1 ->
+    getNewRegNat (registerRep register2)
+                               `thenNat` \ tmp2 ->
+    getNewRegNat F64           `thenNat` \ tmp ->
+    let
+       promote x = FxTOy F DF x tmp
+
+       pk1   = registerRep register1
+       code1 = registerCode register1 tmp1
+       src1  = registerName register1 tmp1
+
+       pk2   = registerRep register2
+       code2 = registerCode register2 tmp2
+       src2  = registerName register2 tmp2
+
+       code__2 dst =
+               if pk1 == pk2 then
+                   code1 `appOL` code2 `snocOL`
+                   instr (primRepToSize pk) src1 src2 dst
+               else if pk1 == F32 then
+                   code1 `snocOL` promote src1 `appOL` code2 `snocOL`
+                   instr DF tmp src2 dst
+               else
+                   code1 `appOL` code2 `snocOL` promote src2 `snocOL`
+                   instr DF src1 tmp dst
+    in
+    return (Any (if pk1 == pk2 then pk1 else F64) code__2)
+
+------------
+trivialUCode instr x
+  = getRegister x              `thenNat` \ register ->
+    getNewRegNat IntRep                `thenNat` \ tmp ->
+    let
+       code = registerCode register tmp
+       src  = registerName register tmp
+       code__2 dst = code `snocOL` instr (RIReg src) dst
+    in
+    return (Any IntRep code__2)
+
+-------------
+trivialUFCode pk instr x
+  = getRegister x              `thenNat` \ register ->
+    getNewRegNat pk            `thenNat` \ tmp ->
+    let
+       code = registerCode register tmp
+       src  = registerName register tmp
+       code__2 dst = code `snocOL` instr src dst
+    in
+    return (Any pk code__2)
+
+#endif /* sparc_TARGET_ARCH */
+
+#if powerpc_TARGET_ARCH
+
+{-
+Wolfgang's PowerPC version of The Rules:
+
+A slightly modified version of The Rules to take advantage of the fact
+that PowerPC instructions work on all registers and don't implicitly
+clobber any fixed registers.
+
+* The only expression for which getRegister returns Fixed is (CmmReg reg).
+
+* If getRegister returns Any, then the code it generates may modify only:
+       (a) fresh temporaries
+       (b) the destination register
+  It may *not* modify global registers, unless the global
+  register happens to be the destination register.
+  It may not clobber any other registers. In fact, only ccalls clobber any
+  fixed registers.
+  Also, it may not modify the counter register (used by genCCall).
+  
+  Corollary: If a getRegister for a subexpression returns Fixed, you need
+  not move it to a fresh temporary before evaluating the next subexpression.
+  The Fixed register won't be modified.
+  Therefore, we don't need a counterpart for the x86's getStableReg on PPC.
+  
+* SDM's First Rule is valid for PowerPC, too: subexpressions can depend on
+  the value of the destination register.
+-}
+
+trivialCode rep signed instr x (CmmLit (CmmInt y _))
+    | Just imm <- makeImmediate rep signed y 
+    = do
+        (src1, code1) <- getSomeReg x
+        let code dst = code1 `snocOL` instr dst src1 (RIImm imm)
+        return (Any rep code)
+  
+trivialCode rep signed instr x y = do
+    (src1, code1) <- getSomeReg x
+    (src2, code2) <- getSomeReg y
+    let code dst = code1 `appOL` code2 `snocOL` instr dst src1 (RIReg src2)
+    return (Any rep code)
+
+trivialCodeNoImm :: MachRep -> (Reg -> Reg -> Reg -> Instr)
+    -> CmmExpr -> CmmExpr -> NatM Register
+trivialCodeNoImm rep instr x y = do
+    (src1, code1) <- getSomeReg x
+    (src2, code2) <- getSomeReg y
+    let code dst = code1 `appOL` code2 `snocOL` instr dst src1 src2
+    return (Any rep code)
+    
+trivialUCode rep instr x = do
+    (src, code) <- getSomeReg x
+    let code' dst = code `snocOL` instr dst src
+    return (Any rep code')
+    
+-- There is no "remainder" instruction on the PPC, so we have to do
+-- it the hard way.
+-- The "div" parameter is the division instruction to use (DIVW or DIVWU)
+
+remainderCode :: MachRep -> (Reg -> Reg -> Reg -> Instr)
+    -> CmmExpr -> CmmExpr -> NatM Register
+remainderCode rep div x y = do
+    (src1, code1) <- getSomeReg x
+    (src2, code2) <- getSomeReg y
+    let code dst = code1 `appOL` code2 `appOL` toOL [
+                div dst src1 src2,
+                MULLW dst dst (RIReg src2),
+                SUBF dst dst src1
+            ]
+    return (Any rep code)
+
+#endif /* powerpc_TARGET_ARCH */
+
+
+-- -----------------------------------------------------------------------------
+--  Coercing to/from integer/floating-point...
+
+-- @coerce(Int2FP|FP2Int)@ are more complicated integer/float
+-- conversions.  We have to store temporaries in memory to move
+-- between the integer and the floating point register sets.
+
+-- @coerceDbl2Flt@ and @coerceFlt2Dbl@ are done this way because we
+-- pretend, on sparc at least, that double and float regs are seperate
+-- kinds, so the value has to be computed into one kind before being
+-- explicitly "converted" to live in the other kind.
+
+coerceInt2FP :: MachRep -> MachRep -> CmmExpr -> NatM Register
+coerceFP2Int :: MachRep -> MachRep -> CmmExpr -> NatM Register
+
+#ifdef sparc_TARGET_ARCH
+coerceDbl2Flt :: CmmExpr -> NatM Register
+coerceFlt2Dbl :: CmmExpr -> NatM Register
+#endif
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if alpha_TARGET_ARCH
+
+coerceInt2FP _ x
+  = getRegister x              `thenNat` \ register ->
+    getNewRegNat IntRep                `thenNat` \ reg ->
+    let
+       code = registerCode register reg
+       src  = registerName register reg
+
+       code__2 dst = code . mkSeqInstrs [
+           ST Q src (spRel 0),
+           LD TF dst (spRel 0),
+           CVTxy Q TF dst dst]
+    in
+    return (Any F64 code__2)
+
+-------------
+coerceFP2Int x
+  = getRegister x              `thenNat` \ register ->
+    getNewRegNat F64   `thenNat` \ tmp ->
+    let
+       code = registerCode register tmp
+       src  = registerName register tmp
+
+       code__2 dst = code . mkSeqInstrs [
+           CVTxy TF Q src tmp,
+           ST TF tmp (spRel 0),
+           LD Q dst (spRel 0)]
+    in
+    return (Any IntRep code__2)
+
+#endif /* alpha_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if i386_TARGET_ARCH
+
+coerceInt2FP from to x = do
+  (x_reg, x_code) <- getSomeReg x
+  let
+        opc  = case to of F32 -> GITOF; F64 -> GITOD
+        code dst = x_code `snocOL` opc x_reg dst
+       -- ToDo: works for non-I32 reps?
+  -- in
+  return (Any to code)
+
+------------
+
+coerceFP2Int from to x = do
+  (x_reg, x_code) <- getSomeReg x
+  let
+        opc  = case from of F32 -> GFTOI; F64 -> GDTOI
+        code dst = x_code `snocOL` opc x_reg dst
+       -- ToDo: works for non-I32 reps?
+  -- in
+  return (Any to code)
+
+#endif /* i386_TARGET_ARCH */
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if sparc_TARGET_ARCH
+
+coerceInt2FP pk x
+  = getRegister x              `thenNat` \ register ->
+    getNewRegNat IntRep                `thenNat` \ reg ->
+    let
+       code = registerCode register reg
+       src  = registerName register reg
+
+       code__2 dst = code `appOL` toOL [
+           ST W src (spRel (-2)),
+           LD W (spRel (-2)) dst,
+           FxTOy W (primRepToSize pk) dst dst]
+    in
+    return (Any pk code__2)
+
+------------
+coerceFP2Int fprep x
+  = ASSERT(fprep == F64 || fprep == F32)
+    getRegister x              `thenNat` \ register ->
+    getNewRegNat fprep         `thenNat` \ reg ->
+    getNewRegNat F32   `thenNat` \ tmp ->
+    let
+       code = registerCode register reg
+       src  = registerName register reg
+       code__2 dst = code `appOL` toOL [
+           FxTOy (primRepToSize fprep) W src tmp,
+           ST W tmp (spRel (-2)),
+           LD W (spRel (-2)) dst]
+    in
+    return (Any IntRep code__2)
+
+------------
+coerceDbl2Flt x
+  = getRegister x              `thenNat` \ register ->
+    getNewRegNat F64   `thenNat` \ tmp ->
+    let code = registerCode register tmp
+        src  = registerName register tmp
+    in
+        return (Any F32 
+                       (\dst -> code `snocOL` FxTOy DF F src dst)) 
+
+------------
+coerceFlt2Dbl x
+  = getRegister x              `thenNat` \ register ->
+    getNewRegNat F32   `thenNat` \ tmp ->
+    let code = registerCode register tmp
+        src  = registerName register tmp
+    in
+        return (Any F64
+                       (\dst -> code `snocOL` FxTOy F DF src dst)) 
+
+#endif /* sparc_TARGET_ARCH */
+
+#if powerpc_TARGET_ARCH
+coerceInt2FP fromRep toRep x = do
+    (src, code) <- getSomeReg x
+    lbl <- getNewLabelNat
+    itmp <- getNewRegNat I32
+    ftmp <- getNewRegNat F64
+    let
+       code' dst = code `appOL` maybe_exts `appOL` toOL [
+               LDATA ReadOnlyData
+                               [CmmDataLabel lbl,
+                                CmmStaticLit (CmmInt 0x43300000 I32),
+                                CmmStaticLit (CmmInt 0x80000000 I32)],
+               XORIS itmp src (ImmInt 0x8000),
+               ST I32 itmp (spRel 3),
+               LIS itmp (ImmInt 0x4330),
+               ST I32 itmp (spRel 2),
+               LD F64 ftmp (spRel 2),
+               LIS itmp (HA (ImmCLbl lbl)),
+               LD F64 dst (AddrRegImm itmp (LO (ImmCLbl lbl))),
+               FSUB F64 dst ftmp dst
+           ] `appOL` maybe_frsp dst
+            
+        maybe_exts = case fromRep of
+                        I8 ->  unitOL $ EXTS I8 src src
+                        I16 -> unitOL $ EXTS I16 src src
+                        I32 -> nilOL
+        maybe_frsp dst = case toRep of
+                        F32 -> unitOL $ FRSP dst dst
+                        F64 -> nilOL
+    return (Any toRep code')
+
+coerceFP2Int fromRep toRep x = do
+    -- the reps don't really matter: F*->F64 and I32->I* are no-ops
+    (src, code) <- getSomeReg x
+    tmp <- getNewRegNat F64
+    let
+       code' dst = code `appOL` toOL [
+               -- convert to int in FP reg
+           FCTIWZ tmp src,
+               -- store value (64bit) from FP to stack
+           ST F64 tmp (spRel 2),
+               -- read low word of value (high word is undefined)
+           LD I32 dst (spRel 3)]       
+    return (Any toRep code')
+#endif /* powerpc_TARGET_ARCH */
+
+
+-- -----------------------------------------------------------------------------
+-- eXTRA_STK_ARGS_HERE
+
+-- We (allegedly) put the first six C-call arguments in registers;
+-- where do we start putting the rest of them?
+
+-- Moved from MachInstrs (SDM):
+
+#if alpha_TARGET_ARCH || sparc_TARGET_ARCH
+eXTRA_STK_ARGS_HERE :: Int
+eXTRA_STK_ARGS_HERE
+  = IF_ARCH_alpha(0, IF_ARCH_sparc(23, ???))
+#endif
diff --git a/ghc/compiler/nativeGen/MachInstrs.hs b/ghc/compiler/nativeGen/MachInstrs.hs
new file mode 100644 (file)
index 0000000..b0b68e4
--- /dev/null
@@ -0,0 +1,693 @@
+-----------------------------------------------------------------------------
+--
+-- Machine-dependent assembly language
+--
+-- (c) The University of Glasgow 1993-2004
+--
+-----------------------------------------------------------------------------
+
+#include "nativeGen/NCG.h"
+
+module MachInstrs (
+       -- * Cmm instantiations
+       NatCmm, NatCmmTop, NatBasicBlock,       
+
+       -- * Machine instructions
+       Instr(..),
+       Cond(..),
+#if !powerpc_TARGET_ARCH && !i386_TARGET_ARCH
+       Size(..), machRepSize,
+#endif
+       RI(..),
+
+#if i386_TARGET_ARCH
+       Operand(..),
+       i386_insert_ffrees,
+#endif
+#if sparc_TARGET_ARCH
+       riZero, fpRelEA, moveSp, fPair,
+#endif
+#if powerpc_TARGET_ARCH
+       condUnsigned, condToSigned,
+#endif
+       DestInfo(..), hasDestInfo, pprDests,
+
+    ) where
+
+#include "HsVersions.h"
+#include "../includes/ghcconfig.h"
+
+import MachRegs
+import Cmm
+import MachOp          ( MachRep(..) )
+import CLabel           ( CLabel, pprCLabel )
+import Panic           ( panic )
+import Outputable
+import Config           ( cLeadingUnderscore )
+import FastString
+
+import GLAEXTS
+
+
+-- -----------------------------------------------------------------------------
+-- Our flavours of the Cmm types
+
+-- Type synonyms for Cmm populated with native code
+type NatCmm        = GenCmm CmmStatic Instr
+type NatCmmTop     = GenCmmTop CmmStatic Instr
+type NatBasicBlock = GenBasicBlock Instr
+
+-- -----------------------------------------------------------------------------
+-- Conditions on this architecture
+
+data Cond
+#if alpha_TARGET_ARCH
+  = ALWAYS     -- For BI (same as BR)
+  | EQQ                -- For CMP and BI (NB: "EQ" is a 1.3 Prelude name)
+  | GE         -- For BI only
+  | GTT                -- For BI only (NB: "GT" is a 1.3 Prelude name)
+  | LE         -- For CMP and BI
+  | LTT                -- For CMP and BI (NB: "LT" is a 1.3 Prelude name)
+  | NE         -- For BI only
+  | NEVER      -- For BI (null instruction)
+  | ULE                -- For CMP only
+  | ULT                -- For CMP only
+#endif
+#if i386_TARGET_ARCH
+  = ALWAYS     -- What's really used? ToDo
+  | EQQ
+  | GE
+  | GEU
+  | GTT
+  | GU
+  | LE
+  | LEU
+  | LTT
+  | LU
+  | NE
+  | NEG
+  | POS
+  | CARRY
+  | OFLO
+#endif
+#if sparc_TARGET_ARCH
+  = ALWAYS     -- What's really used? ToDo
+  | EQQ
+  | GE
+  | GEU
+  | GTT
+  | GU
+  | LE
+  | LEU
+  | LTT
+  | LU
+  | NE
+  | NEG
+  | NEVER
+  | POS
+  | VC
+  | VS
+#endif
+#if powerpc_TARGET_ARCH
+  = ALWAYS
+  | EQQ
+  | GE
+  | GEU
+  | GTT
+  | GU
+  | LE
+  | LEU
+  | LTT
+  | LU
+  | NE
+#endif
+    deriving Eq  -- to make an assertion work
+
+
+-- -----------------------------------------------------------------------------
+-- Sizes on this architecture
+
+-- ToDo: it's not clear to me that we need separate signed-vs-unsigned sizes
+-- here.  I've removed them from the x86 version, we'll see what happens --SDM
+
+#if !powerpc_TARGET_ARCH && !i386_TARGET_ARCH
+data Size
+#if alpha_TARGET_ARCH
+    = B            -- byte
+    | Bu
+--  | W            -- word (2 bytes): UNUSED
+--  | Wu    -- : UNUSED
+    | L            -- longword (4 bytes)
+    | Q            -- quadword (8 bytes)
+--  | FF    -- VAX F-style floating pt: UNUSED
+--  | GF    -- VAX G-style floating pt: UNUSED
+--  | DF    -- VAX D-style floating pt: UNUSED
+--  | SF    -- IEEE single-precision floating pt: UNUSED
+    | TF    -- IEEE double-precision floating pt
+#endif
+#if sparc_TARGET_ARCH || powerpc_TARGET_ARCH
+    = B     -- byte (signed)
+    | Bu    -- byte (unsigned)
+    | H     -- halfword (signed, 2 bytes)
+    | Hu    -- halfword (unsigned, 2 bytes)
+    | W            -- word (4 bytes)
+    | F            -- IEEE single-precision floating pt
+    | DF    -- IEEE single-precision floating pt
+#endif
+  deriving Eq
+
+machRepSize :: MachRep -> Size
+machRepSize I8    = IF_ARCH_alpha(Bu, IF_ARCH_sparc(Bu, ))
+machRepSize I16   = IF_ARCH_alpha(err,IF_ARCH_sparc(Hu, ))
+machRepSize I32   = IF_ARCH_alpha(L,  IF_ARCH_sparc(W,  ))
+machRepSize I64          = panic "machRepSize: I64"
+machRepSize I128  = panic "machRepSize: I128"
+machRepSize F32   = IF_ARCH_alpha(TF, IF_ARCH_sparc(F, ))
+machRepSize F64   = IF_ARCH_alpha(TF, IF_ARCH_sparc(DF,))
+#endif
+
+-- -----------------------------------------------------------------------------
+-- Register or immediate (a handy type on some platforms)
+
+data RI = RIReg Reg
+       | RIImm Imm
+
+
+-- -----------------------------------------------------------------------------
+-- Machine's assembly language
+
+-- We have a few common "instructions" (nearly all the pseudo-ops) but
+-- mostly all of 'Instr' is machine-specific.
+
+data Instr
+  = COMMENT FastString         -- comment pseudo-op
+
+  | LDATA   Section [CmmStatic]        -- some static data spat out during code
+                               -- generation.  Will be extracted before
+                               -- pretty-printing.
+
+  | NEWBLOCK BlockId           -- start a new basic block.  Useful during
+                               -- codegen, removed later.  Preceding 
+                               -- instruction should be a jump, as per the
+                               -- invariants for a BasicBlock (see Cmm).
+
+  | DELTA   Int                 -- specify current stack offset for
+                                -- benefit of subsequent passes
+
+-- -----------------------------------------------------------------------------
+-- Alpha instructions
+
+#if alpha_TARGET_ARCH
+
+-- data Instr continues...
+
+-- Loads and stores.
+             | LD            Size Reg AddrMode -- size, dst, src
+             | LDA           Reg AddrMode      -- dst, src
+             | LDAH          Reg AddrMode      -- dst, src
+             | LDGP          Reg AddrMode      -- dst, src
+             | LDI           Size Reg Imm     -- size, dst, src
+             | ST            Size Reg AddrMode -- size, src, dst
+
+-- Int Arithmetic.
+             | CLR           Reg                   -- dst
+             | ABS           Size RI Reg           -- size, src, dst
+             | NEG           Size Bool RI Reg      -- size, overflow, src, dst
+             | ADD           Size Bool Reg RI Reg  -- size, overflow, src, src, dst
+             | SADD          Size Size Reg RI Reg  -- size, scale, src, src, dst
+             | SUB           Size Bool Reg RI Reg  -- size, overflow, src, src, dst
+             | SSUB          Size Size Reg RI Reg  -- size, scale, src, src, dst
+             | MUL           Size Bool Reg RI Reg  -- size, overflow, src, src, dst
+             | DIV           Size Bool Reg RI Reg  -- size, unsigned, src, src, dst
+             | REM           Size Bool Reg RI Reg  -- size, unsigned, src, src, dst
+
+-- Simple bit-twiddling.
+             | NOT           RI Reg
+             | AND           Reg RI Reg
+             | ANDNOT        Reg RI Reg
+             | OR            Reg RI Reg
+             | ORNOT         Reg RI Reg
+             | XOR           Reg RI Reg
+             | XORNOT        Reg RI Reg
+             | SLL           Reg RI Reg
+             | SRL           Reg RI Reg
+             | SRA           Reg RI Reg
+
+             | ZAP           Reg RI Reg
+             | ZAPNOT        Reg RI Reg
+
+             | NOP
+
+-- Comparison
+             | CMP           Cond Reg RI Reg
+
+-- Float Arithmetic.
+             | FCLR          Reg
+             | FABS          Reg Reg
+             | FNEG          Size Reg Reg
+             | FADD          Size Reg Reg Reg
+             | FDIV          Size Reg Reg Reg
+             | FMUL          Size Reg Reg Reg
+             | FSUB          Size Reg Reg Reg
+             | CVTxy         Size Size Reg Reg
+             | FCMP          Size Cond Reg Reg Reg
+             | FMOV          Reg Reg
+
+-- Jumping around.
+             | BI            Cond Reg Imm
+             | BF            Cond Reg Imm
+             | BR            Imm
+             | JMP           Reg AddrMode Int
+             | BSR           Imm Int
+             | JSR           Reg AddrMode Int
+
+-- Alpha-specific pseudo-ops.
+             | FUNBEGIN CLabel
+             | FUNEND CLabel
+
+data RI
+  = RIReg Reg
+  | RIImm Imm
+
+#endif /* alpha_TARGET_ARCH */
+
+
+-- -----------------------------------------------------------------------------
+-- Intel x86 instructions
+
+{-
+Intel, in their infinite wisdom, selected a stack model for floating
+point registers on x86.  That might have made sense back in 1979 --
+nowadays we can see it for the nonsense it really is.  A stack model
+fits poorly with the existing nativeGen infrastructure, which assumes
+flat integer and FP register sets.  Prior to this commit, nativeGen
+could not generate correct x86 FP code -- to do so would have meant
+somehow working the register-stack paradigm into the register
+allocator and spiller, which sounds very difficult.
+  
+We have decided to cheat, and go for a simple fix which requires no
+infrastructure modifications, at the expense of generating ropey but
+correct FP code.  All notions of the x86 FP stack and its insns have
+been removed.  Instead, we pretend (to the instruction selector and
+register allocator) that x86 has six floating point registers, %fake0
+.. %fake5, which can be used in the usual flat manner.  We further
+claim that x86 has floating point instructions very similar to SPARC
+and Alpha, that is, a simple 3-operand register-register arrangement.
+Code generation and register allocation proceed on this basis.
+  
+When we come to print out the final assembly, our convenient fiction
+is converted to dismal reality.  Each fake instruction is
+independently converted to a series of real x86 instructions.
+%fake0 .. %fake5 are mapped to %st(0) .. %st(5).  To do reg-reg
+arithmetic operations, the two operands are pushed onto the top of the
+FP stack, the operation done, and the result copied back into the
+relevant register.  There are only six %fake registers because 2 are
+needed for the translation, and x86 has 8 in total.
+
+The translation is inefficient but is simple and it works.  A cleverer
+translation would handle a sequence of insns, simulating the FP stack
+contents, would not impose a fixed mapping from %fake to %st regs, and
+hopefully could avoid most of the redundant reg-reg moves of the
+current translation.
+
+We might as well make use of whatever unique FP facilities Intel have
+chosen to bless us with (let's not be churlish, after all).
+Hence GLDZ and GLD1.  Bwahahahahahahaha!
+-}
+
+{-
+MORE FLOATING POINT MUSINGS...
+
+Intel's internal floating point registers are by default 80 bit
+extended precision.  This means that all operations done on values in
+registers are done at 80 bits, and unless the intermediate values are
+truncated to the appropriate size (32 or 64 bits) by storing in
+memory, calculations in registers will give different results from
+calculations which pass intermediate values in memory (eg. via
+function calls).
+
+One solution is to set the FPU into 64 bit precision mode.  Some OSs
+do this (eg. FreeBSD) and some don't (eg. Linux).  The problem here is
+that this will only affect 64-bit precision arithmetic; 32-bit
+calculations will still be done at 64-bit precision in registers.  So
+it doesn't solve the whole problem.  
+
+There's also the issue of what the C library is expecting in terms of
+precision.  It seems to be the case that glibc on Linux expects the
+FPU to be set to 80 bit precision, so setting it to 64 bit could have
+unexpected effects.  Changing the default could have undesirable
+effects on other 3rd-party library code too, so the right thing would
+be to save/restore the FPU control word across Haskell code if we were
+to do this.
+
+gcc's -ffloat-store gives consistent results by always storing the
+results of floating-point calculations in memory, which works for both
+32 and 64-bit precision.  However, it only affects the values of
+user-declared floating point variables in C, not intermediate results.
+GHC in -fvia-C mode uses -ffloat-store (see the -fexcess-precision
+flag).
+
+Another problem is how to spill floating point registers in the
+register allocator.  Should we spill the whole 80 bits, or just 64?
+On an OS which is set to 64 bit precision, spilling 64 is fine.  On
+Linux, spilling 64 bits will round the results of some operations.
+This is what gcc does.  Spilling at 80 bits requires taking up a full
+128 bit slot (so we get alignment).  We spill at 80-bits and ignore
+the alignment problems.
+
+In the future, we'll use the SSE registers for floating point.  This
+requires a CPU that supports SSE2 (ordinary SSE only supports 32 bit
+precision float ops), which means P4 or Xeon and above.  Using SSE
+will solve all these problems, because the SSE registers use fixed 32
+bit or 64 bit precision.
+
+--SDM 1/2003
+-}
+
+#if i386_TARGET_ARCH
+
+-- data Instr continues...
+
+-- Moves.
+       | MOV         MachRep Operand Operand
+       | MOVZxL      MachRep Operand Operand -- size is the size of operand 1
+       | MOVSxL      MachRep Operand Operand -- size is the size of operand 1
+
+-- Load effective address (also a very useful three-operand add instruction :-)
+       | LEA         MachRep Operand Operand
+
+-- Int Arithmetic.
+       | ADD         MachRep Operand Operand
+       | ADC         MachRep Operand Operand
+       | SUB         MachRep Operand Operand
+       | IMUL        MachRep Operand Operand   -- signed int mul
+       | MUL         MachRep Operand Operand   -- unsigned int mul
+
+        | IMUL64      Reg Reg
+       -- operand1:operand2 := (operand1[31:0] *signed operand2[31:0])
+
+       | DIV         MachRep Operand   -- eax := eax:edx/op, edx := eax:edx%op
+       | IDIV        MachRep Operand   -- ditto, but signed
+
+-- Simple bit-twiddling.
+       | AND         MachRep Operand Operand
+       | OR          MachRep Operand Operand
+       | XOR         MachRep Operand Operand
+       | NOT         MachRep Operand
+       | NEGI        MachRep Operand -- NEG instruction (name clash with Cond)
+
+-- Shifts (amount may be immediate or %cl only)
+       | SHL         MachRep Operand{-amount-} Operand
+       | SAR         MachRep Operand{-amount-} Operand
+       | SHR         MachRep Operand{-amount-} Operand
+
+        | BT          MachRep Imm Operand
+       | NOP
+
+-- Float Arithmetic.
+
+-- Note that we cheat by treating G{ABS,MOV,NEG} of doubles 
+-- as single instructions right up until we spit them out.
+        -- all the 3-operand fake fp insns are src1 src2 dst
+        -- and furthermore are constrained to be fp regs only.
+        -- IMPORTANT: keep is_G_insn up to date with any changes here
+       | GMOV        Reg Reg -- src(fpreg), dst(fpreg)
+        | GLD         MachRep AddrMode Reg -- src, dst(fpreg)
+        | GST         MachRep Reg AddrMode -- src(fpreg), dst
+                     
+        | GLDZ        Reg -- dst(fpreg)
+        | GLD1        Reg -- dst(fpreg)
+                     
+        | GFTOI       Reg Reg -- src(fpreg), dst(intreg)
+        | GDTOI       Reg Reg -- src(fpreg), dst(intreg)
+                     
+        | GITOF       Reg Reg -- src(intreg), dst(fpreg)
+        | GITOD       Reg Reg -- src(intreg), dst(fpreg)
+       
+       | GADD        MachRep Reg Reg Reg -- src1, src2, dst
+       | GDIV        MachRep Reg Reg Reg -- src1, src2, dst
+       | GSUB        MachRep Reg Reg Reg -- src1, src2, dst
+       | GMUL        MachRep Reg Reg Reg -- src1, src2, dst
+       
+               -- FP compare.  Cond must be `elem` [EQQ, NE, LE, LTT, GE, GTT]
+               -- Compare src1 with src2; set the Zero flag iff the numbers are
+               -- comparable and the comparison is True.  Subsequent code must
+               -- test the %eflags zero flag regardless of the supplied Cond.
+       | GCMP        Cond Reg Reg -- src1, src2
+       
+       | GABS        MachRep Reg Reg -- src, dst
+       | GNEG        MachRep Reg Reg -- src, dst
+       | GSQRT       MachRep Reg Reg -- src, dst
+       | GSIN        MachRep Reg Reg -- src, dst
+       | GCOS        MachRep Reg Reg -- src, dst
+       | GTAN        MachRep Reg Reg -- src, dst
+       
+        | GFREE         -- do ffree on all x86 regs; an ugly hack
+
+-- Comparison
+       | TEST          MachRep Operand Operand
+       | CMP           MachRep Operand Operand
+       | SETCC         Cond Operand
+
+-- Stack Operations.
+       | PUSH          MachRep Operand
+       | POP           MachRep Operand
+       -- both unused (SDM):
+       -- | PUSHA
+       -- | POPA
+
+-- Jumping around.
+       | JMP         Operand
+       | JXX         Cond BlockId  -- includes unconditional branches
+       | JMP_TBL     Operand [BlockId]  -- table jump
+       | CALL        (Either Imm Reg)
+
+-- Other things.
+       | CLTD -- sign extend %eax into %edx:%eax
+
+data Operand
+  = OpReg  Reg         -- register
+  | OpImm  Imm         -- immediate value
+  | OpAddr AddrMode    -- memory reference
+
+
+i386_insert_ffrees :: [Instr] -> [Instr]
+i386_insert_ffrees insns
+   | any is_G_instr insns
+   = concatMap ffree_before_nonlocal_transfers insns
+   | otherwise
+   = insns
+
+ffree_before_nonlocal_transfers insn
+   = case insn of
+        CALL _  -> [GFREE, insn]
+        JMP _   -> [GFREE, insn]
+        other   -> [insn]
+
+
+-- if you ever add a new FP insn to the fake x86 FP insn set,
+-- you must update this too
+is_G_instr :: Instr -> Bool
+is_G_instr instr
+   = case instr of
+        GMOV _ _ -> True; GLD _ _ _ -> True; GST _ _ _ -> True;
+        GLDZ _ -> True; GLD1 _ -> True;
+        GFTOI _ _ -> True; GDTOI _ _ -> True;
+        GITOF _ _ -> True; GITOD _ _ -> True;
+       GADD _ _ _ _ -> True; GDIV _ _ _ _ -> True
+       GSUB _ _ _ _ -> True; GMUL _ _ _ _ -> True
+       GCMP _ _ _ -> True; GABS _ _ _ -> True
+       GNEG _ _ _ -> True; GSQRT _ _ _ -> True
+        GSIN _ _ _ -> True; GCOS _ _ _ -> True; GTAN _ _ _ -> True;
+        GFREE -> panic "is_G_instr: GFREE (!)"
+        other -> False
+
+#endif /* i386_TARGET_ARCH */
+
+
+-- -----------------------------------------------------------------------------
+-- Sparc instructions
+
+#if sparc_TARGET_ARCH
+
+-- data Instr continues...
+
+-- Loads and stores.
+             | LD            MachRep AddrMode Reg -- size, src, dst
+             | ST            MachRep Reg AddrMode -- size, src, dst
+
+-- Int Arithmetic.
+             | ADD           Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
+             | SUB           Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
+             | UMUL               Bool Reg RI Reg --     cc?, src1, src2, dst
+             | SMUL               Bool Reg RI Reg --     cc?, src1, src2, dst
+              | RDY           Reg      -- move contents of Y register to reg
+
+-- Simple bit-twiddling.
+             | AND           Bool Reg RI Reg -- cc?, src1, src2, dst
+             | ANDN          Bool Reg RI Reg -- cc?, src1, src2, dst
+             | OR            Bool Reg RI Reg -- cc?, src1, src2, dst
+             | ORN           Bool Reg RI Reg -- cc?, src1, src2, dst
+             | XOR           Bool Reg RI Reg -- cc?, src1, src2, dst
+             | XNOR          Bool Reg RI Reg -- cc?, src1, src2, dst
+             | SLL           Reg RI Reg -- src1, src2, dst
+             | SRL           Reg RI Reg -- src1, src2, dst
+             | SRA           Reg RI Reg -- src1, src2, dst
+             | SETHI         Imm Reg -- src, dst
+             | NOP           -- Really SETHI 0, %g0, but worth an alias
+
+-- Float Arithmetic.
+
+-- Note that we cheat by treating F{ABS,MOV,NEG} of doubles as single
+-- instructions right up until we spit them out.
+             | FABS          MachRep Reg Reg      -- src dst
+             | FADD          MachRep Reg Reg Reg  -- src1, src2, dst
+             | FCMP          Bool MachRep Reg Reg -- exception?, src1, src2, dst
+             | FDIV          MachRep Reg Reg Reg -- src1, src2, dst
+             | FMOV          MachRep Reg Reg     -- src, dst
+             | FMUL          MachRep Reg Reg Reg -- src1, src2, dst
+             | FNEG          MachRep Reg Reg     -- src, dst
+             | FSQRT         MachRep Reg Reg     -- src, dst
+             | FSUB          MachRep Reg Reg Reg -- src1, src2, dst
+             | FxTOy         MachRep MachRep Reg Reg -- src, dst
+
+-- Jumping around.
+             | BI            Cond Bool Imm -- cond, annul?, target
+             | BF            Cond Bool Imm -- cond, annul?, target
+
+             | JMP           DestInfo AddrMode      -- target
+             | CALL          (Either Imm Reg) Int Bool -- target, args, terminal
+
+data RI = RIReg Reg
+       | RIImm Imm
+
+riZero :: RI -> Bool
+
+riZero (RIImm (ImmInt 0))          = True
+riZero (RIImm (ImmInteger 0))      = True
+riZero (RIReg (RealReg 0))          = True
+riZero _                           = False
+
+-- Calculate the effective address which would be used by the
+-- corresponding fpRel sequence.  fpRel is in MachRegs.lhs,
+-- alas -- can't have fpRelEA here because of module dependencies.
+fpRelEA :: Int -> Reg -> Instr
+fpRelEA n dst
+   = ADD False False fp (RIImm (ImmInt (n * BYTES_PER_WORD))) dst
+
+-- Code to shift the stack pointer by n words.
+moveSp :: Int -> Instr
+moveSp n
+   = ADD False False sp (RIImm (ImmInt (n * BYTES_PER_WORD))) sp
+
+-- Produce the second-half-of-a-double register given the first half.
+fPair :: Reg -> Reg
+fPair (RealReg n) | n >= 32 && n `mod` 2 == 0  = RealReg (n+1)
+fPair other = pprPanic "fPair(sparc NCG)" (ppr other)
+#endif /* sparc_TARGET_ARCH */
+
+
+-- -----------------------------------------------------------------------------
+-- PowerPC instructions
+
+#ifdef powerpc_TARGET_ARCH
+-- data Instr continues...
+
+-- Loads and stores.
+             | LD      MachRep Reg AddrMode -- Load size, dst, src
+             | LA      MachRep Reg AddrMode -- Load arithmetic size, dst, src
+             | ST      MachRep Reg AddrMode -- Store size, src, dst 
+             | STU     MachRep Reg AddrMode -- Store with Update size, src, dst 
+             | LIS     Reg Imm -- Load Immediate Shifted dst, src
+             | LI      Reg Imm -- Load Immediate dst, src
+             | MR      Reg Reg -- Move Register dst, src -- also for fmr
+             
+             | CMP     MachRep Reg RI --- size, src1, src2
+             | CMPL    MachRep Reg RI --- size, src1, src2
+             
+             | BCC     Cond BlockId
+              | JMP     CLabel          -- same as branch,
+                                        -- but with CLabel instead of block ID
+             | MTCTR   Reg
+             | BCTR    [BlockId]       -- with list of local destinations
+             | BL      CLabel [Reg]    -- with list of argument regs
+             | BCTRL   [Reg]
+             
+             | ADD     Reg Reg RI -- dst, src1, src2
+             | ADDC    Reg Reg Reg -- (carrying) dst, src1, src2
+             | ADDE    Reg Reg Reg -- (extend) dst, src1, src2
+             | ADDIS   Reg Reg Imm -- Add Immediate Shifted dst, src1, src2
+             | SUBF    Reg Reg Reg -- dst, src1, src2 ; dst = src2 - src1  
+             | MULLW   Reg Reg RI
+             | DIVW    Reg Reg Reg
+             | DIVWU   Reg Reg Reg
+
+             | MULLW_MayOflo Reg Reg Reg
+                        -- dst = 1 if src1 * src2 overflows
+                        -- pseudo-instruction; pretty-printed as:
+                        -- mullwo. dst, src1, src2
+                        -- mfxer dst
+                        -- rlwinm dst, dst, 2, 31,31
+             
+             | AND     Reg Reg RI -- dst, src1, src2
+             | OR      Reg Reg RI -- dst, src1, src2
+             | XOR     Reg Reg RI -- dst, src1, src2
+             | XORIS   Reg Reg Imm -- XOR Immediate Shifted dst, src1, src2
+             
+              | EXTS    MachRep Reg Reg
+                 
+             | NEG     Reg Reg
+             | NOT     Reg Reg
+             
+             | SLW     Reg Reg RI      -- shift left word
+             | SRW     Reg Reg RI      -- shift right word
+             | SRAW    Reg Reg RI      -- shift right arithmetic word
+             
+                       -- Rotate Left Word Immediate then AND with Mask
+             | RLWINM  Reg Reg Int Int Int
+             
+             | FADD    MachRep Reg Reg Reg
+             | FSUB    MachRep Reg Reg Reg
+             | FMUL    MachRep Reg Reg Reg
+             | FDIV    MachRep Reg Reg Reg
+             | FNEG    Reg Reg  -- negate is the same for single and double prec.
+             
+             | FCMP    Reg Reg
+             
+             | FCTIWZ  Reg Reg         -- convert to integer word
+              | FRSP    Reg Reg                -- reduce to single precision
+                                       -- (but destination is a FP register)
+             
+             | CRNOR   Int Int Int    -- condition register nor
+             | MFCR    Reg            -- move from condition register
+             
+condUnsigned GU = True
+condUnsigned LU = True
+condUnsigned GEU = True
+condUnsigned LEU = True
+condUnsigned _ = False
+
+condToSigned GU = GTT
+condToSigned LU = LTT
+condToSigned GEU = GE
+condToSigned LEU = LE
+condToSigned x = x
+#endif /* powerpc_TARGET_ARCH */
+
+
+-- -----------------------------------------------------------------------------
+-- DestInfo
+
+-- ToDo: might not be needed anymore --SDM
+
+-- used by insnFuture in RegAllocInfo.lhs
+data DestInfo
+   = NoDestInfo             -- no supplied dests; infer from context
+   | DestInfo [CLabel]      -- precisely these dests and no others
+
+hasDestInfo NoDestInfo   = False
+hasDestInfo (DestInfo _) = True
+
+pprDests :: DestInfo -> SDoc
+pprDests NoDestInfo      = text "NoDestInfo"
+pprDests (DestInfo dsts) = brackets (hsep (map pprCLabel dsts))
diff --git a/ghc/compiler/nativeGen/MachMisc.hi-boot b/ghc/compiler/nativeGen/MachMisc.hi-boot
deleted file mode 100644 (file)
index 1c7bef4..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-_interface_ MachMisc 1
-_exports_
-MachMisc Instr fixedHdrSize fmtAsmLbl underscorePrefix;
-_declarations_
-1 fixedHdrSize _:_ PrelBase.Int ;;
-2 fmtAsmLbl _:_ PrelBase.String -> PrelBase.String ;;
-1 underscorePrefix _:_ PrelBase.Bool ;;
-1 data Instr ;;
\ No newline at end of file
diff --git a/ghc/compiler/nativeGen/MachMisc.hi-boot-5 b/ghc/compiler/nativeGen/MachMisc.hi-boot-5
deleted file mode 100644 (file)
index 8c2a6f2..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-__interface MachMisc 1 0 where
-__export MachMisc Instr fixedHdrSize fmtAsmLbl underscorePrefix;
-1 fixedHdrSize :: PrelBase.Int ;
-2 fmtAsmLbl :: PrelBase.String -> PrelBase.String ;
-1 underscorePrefix :: PrelBase.Bool ;
-1 data Instr ;
diff --git a/ghc/compiler/nativeGen/MachMisc.hi-boot-6 b/ghc/compiler/nativeGen/MachMisc.hi-boot-6
deleted file mode 100644 (file)
index 404ab2b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-module MachMisc where
-
-data Instr
-
-fixedHdrSize :: GHC.Base.Int
-fmtAsmLbl :: GHC.Base.String -> GHC.Base.String
-underscorePrefix :: GHC.Base.Bool
diff --git a/ghc/compiler/nativeGen/MachMisc.lhs b/ghc/compiler/nativeGen/MachMisc.lhs
deleted file mode 100644 (file)
index a641a8a..0000000
+++ /dev/null
@@ -1,789 +0,0 @@
-%
-% (c) The AQUA Project, Glasgow University, 1993-1998
-%
-\section[MachMisc]{Description of various machine-specific things}
-
-\begin{code}
-#include "nativeGen/NCG.h"
-
-module MachMisc (
-
-       primRepToSize,
-
-       eXTRA_STK_ARGS_HERE,
-
-       volatileSaves, volatileRestores,
-
-       targetMaxDouble, targetMaxInt, targetMinDouble, targetMinInt,
-
-       underscorePrefix,
-       fmtAsmLbl,
-       exactLog2,
-
-       Instr(..),  IF_ARCH_i386(Operand(..) COMMA,)
-       Cond(..),
-       Size(..),
-        IF_ARCH_i386(i386_insert_ffrees COMMA,)        
-
-#if alpha_TARGET_ARCH
-       , RI(..)
-#endif
-#if i386_TARGET_ARCH
-#endif
-#if sparc_TARGET_ARCH
-       RI(..), riZero, fpRelEA, moveSp, fPair
-#endif
-#if powerpc_TARGET_ARCH
-       , RI(..)
-       , condUnsigned, condToSigned
-#endif
-    ) where
-
-#include "HsVersions.h"
-#include "../includes/config.h"
-
-import AbsCSyn         ( MagicId(..) ) 
-import AbsCUtils       ( magicIdPrimRep )
-import CLabel           ( CLabel, isAsmTemp )
-import Literal         ( mkMachInt, Literal(..) )
-import MachRegs                ( callerSaves,
-                          get_MagicId_addr, get_MagicId_reg_or_addr,
-                         Imm(..), Reg(..), MachRegsAddr(..)
-#                         if sparc_TARGET_ARCH
-                          ,fp, sp
-#                         endif
-                       )
-import PrimRep         ( PrimRep(..) )
-import Stix            ( StixStmt(..), StixExpr(..), StixReg(..), 
-                          CodeSegment, DestInfo(..) )
-import Panic           ( panic )
-import Outputable      ( pprPanic, ppr, showSDoc )
-import Config           ( cLeadingUnderscore )
-import FastTypes
-import FastString
-
-import GLAEXTS
-import TRACE           ( trace )
-
-import Maybes          ( mapCatMaybes )
-\end{code}
-
-\begin{code}
-underscorePrefix :: Bool   -- leading underscore on assembler labels?
-underscorePrefix = (cLeadingUnderscore == "YES")
-
----------------------------
-fmtAsmLbl :: String -> String  -- for formatting labels
-
-fmtAsmLbl s
-     {- The alpha assembler likes temporary labels to look like $L123
-       instead of L123.  (Don't toss the L, because then Lf28
-       turns into $f28.)
-     -}
-  =  IF_ARCH_alpha(
-     '$' : s
-     ,{-otherwise-}
-     '.':'L':s
-     )
-\end{code}
-
-% ----------------------------------------------------------------
-
-We (allegedly) put the first six C-call arguments in registers;
-where do we start putting the rest of them?
-\begin{code}
-eXTRA_STK_ARGS_HERE :: Int
-eXTRA_STK_ARGS_HERE
-  = IF_ARCH_alpha(0, IF_ARCH_i386(23{-6x4bytes-}, IF_ARCH_sparc(23,
-    IF_ARCH_powerpc( IF_OS_darwin(24,8{-SVR4 ABI: Linux-}), ???))))
-\end{code}
-
-% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-Now the volatile saves and restores.  We add the basic guys to the
-list of ``user'' registers provided.  Note that there are more basic
-registers on the restore list, because some are reloaded from
-constants.
-
-(@volatileRestores@ used only for wrapper-hungry PrimOps.)
-
-\begin{code}
-volatileSaves, volatileRestores :: [MagicId] -> [StixStmt]
-
-volatileSaves    = volatileSavesOrRestores True
-volatileRestores = volatileSavesOrRestores False
-
-save_cands    = [BaseReg,Sp,SpLim,Hp,HpLim]
-restore_cands = save_cands
-
-volatileSavesOrRestores do_saves vols
-   = mapCatMaybes mkCode vols
-     where
-        mkCode mid
-           | case mid of { BaseReg -> True; _ -> False } 
-           = panic "volatileSavesOrRestores:BaseReg" 
-           | not (callerSaves mid)
-           = Nothing
-           | otherwise -- must be callee-saves ...
-           = case get_MagicId_reg_or_addr mid of
-                -- If stored in BaseReg, we ain't interested
-                Right baseRegAddr 
-                   -> Nothing
-                Left (RealReg rrno)
-                   -- OK, it's callee-saves, and in a real reg (rrno).
-                   -- We have to cook up some transfer code.
-                   {- Note that the use of (StixMagicId mid) here is a bit subtle.  
-                      Here, we only create those for MagicIds which are stored in 
-                      a real reg on this arch -- the preceding case on the result 
-                      of get_MagicId_reg_or_addr guarantees this.  Later, when 
-                      selecting insns, that means these assignments are sure to turn 
-                      into real reg-to-mem or mem-to-reg moves, rather than being 
-                      pointless moves from some address in the reg-table 
-                      back to itself.-}
-                   |  do_saves
-                   -> Just (StAssignMem rep addr 
-                                            (StReg (StixMagicId mid)))
-                   |  otherwise
-                   -> Just (StAssignReg rep (StixMagicId mid)
-                                            (StInd rep addr))
-                      where
-                         rep  = magicIdPrimRep mid
-                         addr = get_MagicId_addr mid
-\end{code}
-
-% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-Obviously slightly weedy
-(Note that the floating point values aren't terribly important.)
-ToDo: Fix!(JSM)
-\begin{code}
-targetMinDouble = MachDouble (-1.7976931348623157e+308)
-targetMaxDouble = MachDouble (1.7976931348623157e+308)
-targetMinInt = mkMachInt (-2147483648)
-targetMaxInt = mkMachInt 2147483647
-\end{code}
-
-% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-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.
-
-\begin{code}
-w2i x = word2Int# x
-i2w x = int2Word# x
-
-exactLog2 :: Integer -> Maybe Integer
-exactLog2 x
-  = if (x <= 0 || x >= 2147483648) then
-       Nothing
-    else
-       case iUnbox (fromInteger x) of { x# ->
-       if (w2i ((i2w x#) `and#` (i2w (0# -# x#))) /=# x#) then
-         Nothing
-       else
-         Just (toInteger (iBox (pow2 x#)))
-       }
-  where
-    pow2 x# | x# ==# 1# = 0#
-            | otherwise = 1# +# pow2 (w2i (i2w x# `shiftRL#` 1#))
-\end{code}
-
-% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-\begin{code}
-data Cond
-#if alpha_TARGET_ARCH
-  = ALWAYS     -- For BI (same as BR)
-  | EQQ                -- For CMP and BI (NB: "EQ" is a 1.3 Prelude name)
-  | GE         -- For BI only
-  | GTT                -- For BI only (NB: "GT" is a 1.3 Prelude name)
-  | LE         -- For CMP and BI
-  | LTT                -- For CMP and BI (NB: "LT" is a 1.3 Prelude name)
-  | NE         -- For BI only
-  | NEVER      -- For BI (null instruction)
-  | ULE                -- For CMP only
-  | ULT                -- For CMP only
-#endif
-#if i386_TARGET_ARCH
-  = ALWAYS     -- What's really used? ToDo
-  | EQQ
-  | GE
-  | GEU
-  | GTT
-  | GU
-  | LE
-  | LEU
-  | LTT
-  | LU
-  | NE
-  | NEG
-  | POS
-  | CARRY
-  | OFLO
-#endif
-#if sparc_TARGET_ARCH
-  = ALWAYS     -- What's really used? ToDo
-  | EQQ
-  | GE
-  | GEU
-  | GTT
-  | GU
-  | LE
-  | LEU
-  | LTT
-  | LU
-  | NE
-  | NEG
-  | NEVER
-  | POS
-  | VC
-  | VS
-#endif
-#if powerpc_TARGET_ARCH
-  = ALWAYS
-  | EQQ
-  | GE
-  | GEU
-  | GTT
-  | GU
-  | LE
-  | LEU
-  | LTT
-  | LU
-  | NE
-#endif
-    deriving Eq  -- to make an assertion work
-\end{code}
-
-\begin{code}
-data Size
-#if alpha_TARGET_ARCH
-    = B            -- byte
-    | Bu
---  | W            -- word (2 bytes): UNUSED
---  | Wu    -- : UNUSED
-    | L            -- longword (4 bytes)
-    | Q            -- quadword (8 bytes)
---  | FF    -- VAX F-style floating pt: UNUSED
---  | GF    -- VAX G-style floating pt: UNUSED
---  | DF    -- VAX D-style floating pt: UNUSED
---  | SF    -- IEEE single-precision floating pt: UNUSED
-    | TF    -- IEEE double-precision floating pt
-#endif
-#if i386_TARGET_ARCH
-    = B            -- byte (signed)
-    | Bu    -- byte (unsigned)
-    | W     -- word (signed)
-    | Wu    -- word (unsigned)
-    | L     -- longword (signed)
-    | Lu    -- longword (unsigned)
-    | F            -- IEEE single-precision floating pt
-    | DF    -- IEEE single-precision floating pt
-    | F80   -- Intel 80-bit internal FP format; only used for spilling
-#endif
-#if sparc_TARGET_ARCH || powerpc_TARGET_ARCH
-    = B     -- byte (signed)
-    | Bu    -- byte (unsigned)
-    | H     -- halfword (signed, 2 bytes)
-    | Hu    -- halfword (unsigned, 2 bytes)
-    | W            -- word (4 bytes)
-    | F            -- IEEE single-precision floating pt
-    | DF    -- IEEE single-precision floating pt
-#endif
-
-primRepToSize :: PrimRep -> Size
-
-primRepToSize PtrRep       = IF_ARCH_alpha(Q,  IF_ARCH_i386(L,  IF_ARCH_sparc(W,  IF_ARCH_powerpc(W,  ))))
-primRepToSize CodePtrRep    = IF_ARCH_alpha(Q,  IF_ARCH_i386(L,  IF_ARCH_sparc(W,  IF_ARCH_powerpc(W,  ))))
-primRepToSize DataPtrRep    = IF_ARCH_alpha(Q,  IF_ARCH_i386(L,  IF_ARCH_sparc(W,  IF_ARCH_powerpc(W,  ))))
-primRepToSize RetRep       = IF_ARCH_alpha(Q,  IF_ARCH_i386(L,  IF_ARCH_sparc(W,  IF_ARCH_powerpc(W,  ))))
-primRepToSize CostCentreRep = IF_ARCH_alpha(Q,  IF_ARCH_i386(L,  IF_ARCH_sparc(W,  IF_ARCH_powerpc(W,  ))))
-primRepToSize CharRep      = IF_ARCH_alpha(L,  IF_ARCH_i386(L,  IF_ARCH_sparc(W,  IF_ARCH_powerpc(W,  ))))
-
-primRepToSize Int8Rep      = IF_ARCH_alpha(B,  IF_ARCH_i386(B,  IF_ARCH_sparc(B,  IF_ARCH_powerpc(B,  ))))
-primRepToSize Int16Rep     = IF_ARCH_alpha(err,IF_ARCH_i386(W,  IF_ARCH_sparc(H,  IF_ARCH_powerpc(H,  ))))
-    where err = primRepToSize_fail "Int16Rep"
-primRepToSize Int32Rep     = IF_ARCH_alpha(L,  IF_ARCH_i386(L,  IF_ARCH_sparc(W,  IF_ARCH_powerpc(W,  ))))
-primRepToSize Word8Rep     = IF_ARCH_alpha(Bu, IF_ARCH_i386(Bu, IF_ARCH_sparc(Bu, IF_ARCH_powerpc(Bu, ))))
-primRepToSize Word16Rep            = IF_ARCH_alpha(err,IF_ARCH_i386(Wu, IF_ARCH_sparc(Hu, IF_ARCH_powerpc(Hu, ))))
-    where err = primRepToSize_fail "Word16Rep"
-primRepToSize Word32Rep            = IF_ARCH_alpha(L,  IF_ARCH_i386(Lu, IF_ARCH_sparc(W,  IF_ARCH_powerpc(W,  ))))
-
-primRepToSize IntRep       = IF_ARCH_alpha(Q,  IF_ARCH_i386(L,  IF_ARCH_sparc(W,  IF_ARCH_powerpc(W,  ))))
-primRepToSize WordRep      = IF_ARCH_alpha(Q,  IF_ARCH_i386(L,  IF_ARCH_sparc(W,  IF_ARCH_powerpc(W,  ))))
-primRepToSize AddrRep      = IF_ARCH_alpha(Q,  IF_ARCH_i386(L,  IF_ARCH_sparc(W,  IF_ARCH_powerpc(W,  ))))
-primRepToSize FloatRep     = IF_ARCH_alpha(TF, IF_ARCH_i386(F,  IF_ARCH_sparc(F,  IF_ARCH_powerpc(F,  ))))
-primRepToSize DoubleRep            = IF_ARCH_alpha(TF, IF_ARCH_i386(DF, IF_ARCH_sparc(DF, IF_ARCH_powerpc(DF, ))))
-primRepToSize StablePtrRep  = IF_ARCH_alpha(Q,  IF_ARCH_i386(L,  IF_ARCH_sparc(W,  IF_ARCH_powerpc(W,  ))))
-
-primRepToSize Word64Rep     = primRepToSize_fail "Word64Rep"
-primRepToSize Int64Rep      = primRepToSize_fail "Int64Rep"
-primRepToSize other         = primRepToSize_fail (showSDoc (ppr other))
-
-primRepToSize_fail str
-   = error ("ERROR: MachMisc.primRepToSize: cannot handle `" ++ str ++ "'.\n\t" 
-            ++ "Workaround: use -fvia-C.\n\t" 
-            ++ "Perhaps you should report it as a GHC bug,\n\t" 
-            ++ "to glasgow-haskell-bugs@haskell.org.")
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{Machine's assembly language}
-%*                                                                     *
-%************************************************************************
-
-We have a few common ``instructions'' (nearly all the pseudo-ops) but
-mostly all of @Instr@ is machine-specific.
-
-\begin{code}
-data Instr
-  = COMMENT FastString         -- comment pseudo-op
-  | SEGMENT CodeSegment                -- {data,text} segment pseudo-op
-  | LABEL   CLabel             -- global label pseudo-op
-  | ASCII   Bool               -- True <=> needs backslash conversion
-           String              -- the literal string
-  | DATA    Size
-           [Imm]
-  | DELTA   Int                 -- specify current stack offset for
-                                -- benefit of subsequent passes
-\end{code}
-
-\begin{code}
-#if alpha_TARGET_ARCH
-
--- data Instr continues...
-
--- Loads and stores.
-
-             | LD            Size Reg MachRegsAddr -- size, dst, src
-             | LDA           Reg MachRegsAddr      -- dst, src
-             | LDAH          Reg MachRegsAddr      -- dst, src
-             | LDGP          Reg MachRegsAddr      -- dst, src
-             | LDI           Size Reg Imm     -- size, dst, src
-             | ST            Size Reg MachRegsAddr -- size, src, dst
-
--- Int Arithmetic.
-
-             | CLR           Reg                   -- dst
-             | ABS           Size RI Reg           -- size, src, dst
-             | NEG           Size Bool RI Reg      -- size, overflow, src, dst
-             | ADD           Size Bool Reg RI Reg  -- size, overflow, src, src, dst
-             | SADD          Size Size Reg RI Reg  -- size, scale, src, src, dst
-             | SUB           Size Bool Reg RI Reg  -- size, overflow, src, src, dst
-             | SSUB          Size Size Reg RI Reg  -- size, scale, src, src, dst
-             | MUL           Size Bool Reg RI Reg  -- size, overflow, src, src, dst
-             | DIV           Size Bool Reg RI Reg  -- size, unsigned, src, src, dst
-             | REM           Size Bool Reg RI Reg  -- size, unsigned, src, src, dst
-
--- Simple bit-twiddling.
-
-             | NOT           RI Reg
-             | AND           Reg RI Reg
-             | ANDNOT        Reg RI Reg
-             | OR            Reg RI Reg
-             | ORNOT         Reg RI Reg
-             | XOR           Reg RI Reg
-             | XORNOT        Reg RI Reg
-             | SLL           Reg RI Reg
-             | SRL           Reg RI Reg
-             | SRA           Reg RI Reg
-
-             | ZAP           Reg RI Reg
-             | ZAPNOT        Reg RI Reg
-
-             | NOP
-
--- Comparison
-
-             | CMP           Cond Reg RI Reg
-
--- Float Arithmetic.
-
-             | FCLR          Reg
-             | FABS          Reg Reg
-             | FNEG          Size Reg Reg
-             | FADD          Size Reg Reg Reg
-             | FDIV          Size Reg Reg Reg
-             | FMUL          Size Reg Reg Reg
-             | FSUB          Size Reg Reg Reg
-             | CVTxy         Size Size Reg Reg
-             | FCMP          Size Cond Reg Reg Reg
-             | FMOV          Reg Reg
-
--- Jumping around.
-
-             | BI            Cond Reg Imm
-             | BF            Cond Reg Imm
-             | BR            Imm
-             | JMP           Reg MachRegsAddr Int
-             | BSR           Imm Int
-             | JSR           Reg MachRegsAddr Int
-
--- Alpha-specific pseudo-ops.
-
-             | FUNBEGIN CLabel
-             | FUNEND CLabel
-
-data RI
-  = RIReg Reg
-  | RIImm Imm
-
-#endif /* alpha_TARGET_ARCH */
-\end{code}
-
-Intel, in their infinite wisdom, selected a stack model for floating
-point registers on x86.  That might have made sense back in 1979 --
-nowadays we can see it for the nonsense it really is.  A stack model
-fits poorly with the existing nativeGen infrastructure, which assumes
-flat integer and FP register sets.  Prior to this commit, nativeGen
-could not generate correct x86 FP code -- to do so would have meant
-somehow working the register-stack paradigm into the register
-allocator and spiller, which sounds very difficult.
-  
-We have decided to cheat, and go for a simple fix which requires no
-infrastructure modifications, at the expense of generating ropey but
-correct FP code.  All notions of the x86 FP stack and its insns have
-been removed.  Instead, we pretend (to the instruction selector and
-register allocator) that x86 has six floating point registers, %fake0
-.. %fake5, which can be used in the usual flat manner.  We further
-claim that x86 has floating point instructions very similar to SPARC
-and Alpha, that is, a simple 3-operand register-register arrangement.
-Code generation and register allocation proceed on this basis.
-  
-When we come to print out the final assembly, our convenient fiction
-is converted to dismal reality.  Each fake instruction is
-independently converted to a series of real x86 instructions.
-%fake0 .. %fake5 are mapped to %st(0) .. %st(5).  To do reg-reg
-arithmetic operations, the two operands are pushed onto the top of the
-FP stack, the operation done, and the result copied back into the
-relevant register.  There are only six %fake registers because 2 are
-needed for the translation, and x86 has 8 in total.
-
-The translation is inefficient but is simple and it works.  A cleverer
-translation would handle a sequence of insns, simulating the FP stack
-contents, would not impose a fixed mapping from %fake to %st regs, and
-hopefully could avoid most of the redundant reg-reg moves of the
-current translation.
-
-We might as well make use of whatever unique FP facilities Intel have
-chosen to bless us with (let's not be churlish, after all).
-Hence GLDZ and GLD1.  Bwahahahahahahaha!
-
-LATER (10 Nov 2000): idiv gives problems with the register spiller,
-because the spiller is simpleminded and because idiv has fixed uses of
-%eax and %edx.  Rather than make the spiller cleverer, we do away with
-idiv, and instead have iquot and irem fake (integer) insns, which have
-no operand register constraints -- ie, they behave like add, sub, mul.
-The printer-outer transforms them to a sequence of real insns which does
-the Right Thing (tm).  As with the FP stuff, this gives ropey code, 
-but we don't care, since it doesn't get used much.  We hope.
-
-\begin{code}
-#if i386_TARGET_ARCH
-
--- data Instr continues...
-
--- Moves.
-
-             | MOV           Size Operand Operand
-             | MOVZxL        Size Operand Operand -- size is the size of operand 1
-             | MOVSxL        Size Operand Operand -- size is the size of operand 1
-
--- Load effective address (also a very useful three-operand add instruction :-)
-
-             | LEA           Size Operand Operand
-
--- Int Arithmetic.
-
-             | ADD           Size Operand Operand
-             | SUB           Size Operand Operand
-             | IMUL          Size Operand Operand      -- signed int mul
-             | MUL           Size Operand Operand      -- unsigned int mul
-              | IMUL64       Reg Reg                   -- 32 x 32 -> 64 signed mul
-               -- operand1:operand2 := (operand1[31:0] *signed operand2[31:0])
-
--- Quotient and remainder.  SEE comment above -- these are not
--- real x86 insns; instead they are expanded when printed
--- into a sequence of real insns.
-
-              | IQUOT         Size Operand Operand     -- signed quotient
-              | IREM          Size Operand Operand     -- signed remainder
-              | QUOT          Size Operand Operand     -- unsigned quotient
-              | REM           Size Operand Operand     -- unsigned remainder
-
--- Simple bit-twiddling.
-
-             | AND           Size Operand Operand
-             | OR            Size Operand Operand
-             | XOR           Size Operand Operand
-             | NOT           Size Operand
-             | NEGI          Size Operand -- NEG instruction (name clash with Cond)
-             | SHL           Size Imm Operand -- Only immediate shifts allowed
-             | SAR           Size Imm Operand -- Only immediate shifts allowed
-             | SHR           Size Imm Operand -- Only immediate shifts allowed
-              | BT            Size Imm Operand
-             | NOP
-
--- Float Arithmetic.
-
--- Note that we cheat by treating G{ABS,MOV,NEG} of doubles 
--- as single instructions right up until we spit them out.
-
-              -- all the 3-operand fake fp insns are src1 src2 dst
-              -- and furthermore are constrained to be fp regs only.
-              -- IMPORTANT: keep is_G_insn up to date with any changes here
-             | GMOV          Reg Reg -- src(fpreg), dst(fpreg)
-              | GLD           Size MachRegsAddr Reg -- src, dst(fpreg)
-              | GST           Size Reg MachRegsAddr -- src(fpreg), dst
-
-              | GLDZ          Reg -- dst(fpreg)
-              | GLD1          Reg -- dst(fpreg)
-
-              | GFTOI         Reg Reg -- src(fpreg), dst(intreg)
-              | GDTOI         Reg Reg -- src(fpreg), dst(intreg)
-
-              | GITOF         Reg Reg -- src(intreg), dst(fpreg)
-              | GITOD         Reg Reg -- src(intreg), dst(fpreg)
-
-             | GADD          Size Reg Reg Reg -- src1, src2, dst
-             | GDIV          Size Reg Reg Reg -- src1, src2, dst
-             | GSUB          Size Reg Reg Reg -- src1, src2, dst
-             | GMUL          Size Reg Reg Reg -- src1, src2, dst
-
-               -- FP compare.  Cond must be `elem` [EQQ, NE, LE, LTT, GE, GTT]
-               -- Compare src1 with src2; set the Zero flag iff the numbers are
-               -- comparable and the comparison is True.  Subsequent code must
-               -- test the %eflags zero flag regardless of the supplied Cond.
-             | GCMP          Cond Reg Reg -- src1, src2
-
-             | GABS          Size Reg Reg -- src, dst
-             | GNEG          Size Reg Reg -- src, dst
-             | GSQRT         Size Reg Reg -- src, dst
-             | GSIN          Size Reg Reg -- src, dst
-             | GCOS          Size Reg Reg -- src, dst
-             | GTAN          Size Reg Reg -- src, dst
-
-              | GFREE         -- do ffree on all x86 regs; an ugly hack
--- Comparison
-
-             | TEST          Size Operand Operand
-             | CMP           Size Operand Operand
-             | SETCC         Cond Operand
-
--- Stack Operations.
-
-             | PUSH          Size Operand
-             | POP           Size Operand
-             | PUSHA
-             | POPA
-
--- Jumping around.
-
-             | JMP           DestInfo Operand -- possible dests, target
-             | JXX           Cond CLabel -- target
-             | CALL          (Either Imm Reg)
-
--- Other things.
-
-             | CLTD -- sign extend %eax into %edx:%eax
-
-data Operand
-  = OpReg  Reg         -- register
-  | OpImm  Imm         -- immediate value
-  | OpAddr MachRegsAddr        -- memory reference
-
-
-i386_insert_ffrees :: [Instr] -> [Instr]
-i386_insert_ffrees insns
-   | any is_G_instr insns
-   = concatMap ffree_before_nonlocal_transfers insns
-   | otherwise
-   = insns
-
-ffree_before_nonlocal_transfers insn
-   = case insn of
-        CALL _                                        -> [GFREE, insn]
-        -- Jumps to immediate labels are local
-        JMP _ (OpImm (ImmCLbl clbl)) | isAsmTemp clbl -> [insn]
-        -- If a jump mentions dests, it is a local jump thru
-        -- a case table.
-        JMP (DestInfo _) _                            -> [insn]
-        JMP _ _                                       -> [GFREE, insn]
-        other                                         -> [insn]
-
-
--- if you ever add a new FP insn to the fake x86 FP insn set,
--- you must update this too
-is_G_instr :: Instr -> Bool
-is_G_instr instr
-   = case instr of
-        GMOV _ _ -> True; GLD _ _ _ -> True; GST _ _ _ -> True;
-        GLDZ _ -> True; GLD1 _ -> True;
-        GFTOI _ _ -> True; GDTOI _ _ -> True;
-        GITOF _ _ -> True; GITOD _ _ -> True;
-       GADD _ _ _ _ -> True; GDIV _ _ _ _ -> True
-       GSUB _ _ _ _ -> True; GMUL _ _ _ _ -> True
-       GCMP _ _ _ -> True; GABS _ _ _ -> True
-       GNEG _ _ _ -> True; GSQRT _ _ _ -> True
-        GSIN _ _ _ -> True; GCOS _ _ _ -> True; GTAN _ _ _ -> True;
-        GFREE -> panic "is_G_instr: GFREE (!)"
-        other -> False
-
-#endif /* i386_TARGET_ARCH */
-\end{code}
-
-\begin{code}
-#if sparc_TARGET_ARCH
-
--- data Instr continues...
-
--- Loads and stores.
-
-             | LD            Size MachRegsAddr Reg -- size, src, dst
-             | ST            Size Reg MachRegsAddr -- size, src, dst
-
--- Int Arithmetic.
-
-             | ADD           Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
-             | SUB           Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
-             | UMUL               Bool Reg RI Reg --     cc?, src1, src2, dst
-             | SMUL               Bool Reg RI Reg --     cc?, src1, src2, dst
-              | RDY           Reg      -- move contents of Y register to reg
-
--- Simple bit-twiddling.
-
-             | AND           Bool Reg RI Reg -- cc?, src1, src2, dst
-             | ANDN          Bool Reg RI Reg -- cc?, src1, src2, dst
-             | OR            Bool Reg RI Reg -- cc?, src1, src2, dst
-             | ORN           Bool Reg RI Reg -- cc?, src1, src2, dst
-             | XOR           Bool Reg RI Reg -- cc?, src1, src2, dst
-             | XNOR          Bool Reg RI Reg -- cc?, src1, src2, dst
-             | SLL           Reg RI Reg -- src1, src2, dst
-             | SRL           Reg RI Reg -- src1, src2, dst
-             | SRA           Reg RI Reg -- src1, src2, dst
-             | SETHI         Imm Reg -- src, dst
-             | NOP           -- Really SETHI 0, %g0, but worth an alias
-
--- Float Arithmetic.
-
--- Note that we cheat by treating F{ABS,MOV,NEG} of doubles as single instructions
--- right up until we spit them out.
-
-             | FABS          Size Reg Reg -- src dst
-             | FADD          Size Reg Reg Reg -- src1, src2, dst
-             | FCMP          Bool Size Reg Reg -- exception?, src1, src2, dst
-             | FDIV          Size Reg Reg Reg -- src1, src2, dst
-             | FMOV          Size Reg Reg -- src, dst
-             | FMUL          Size Reg Reg Reg -- src1, src2, dst
-             | FNEG          Size Reg Reg -- src, dst
-             | FSQRT         Size Reg Reg -- src, dst
-             | FSUB          Size Reg Reg Reg -- src1, src2, dst
-             | FxTOy         Size Size Reg Reg -- src, dst
-
--- Jumping around.
-
-             | BI            Cond Bool Imm -- cond, annul?, target
-             | BF            Cond Bool Imm -- cond, annul?, target
-
-             | JMP           DestInfo MachRegsAddr      -- target
-             | CALL          (Either Imm Reg) Int Bool -- target, args, terminal
-
-data RI = RIReg Reg
-       | RIImm Imm
-
-riZero :: RI -> Bool
-
-riZero (RIImm (ImmInt 0))          = True
-riZero (RIImm (ImmInteger 0))      = True
-riZero (RIReg (RealReg 0))          = True
-riZero _                           = False
-
--- Calculate the effective address which would be used by the
--- corresponding fpRel sequence.  fpRel is in MachRegs.lhs,
--- alas -- can't have fpRelEA here because of module dependencies.
-fpRelEA :: Int -> Reg -> Instr
-fpRelEA n dst
-   = ADD False False fp (RIImm (ImmInt (n * BYTES_PER_WORD))) dst
-
--- Code to shift the stack pointer by n words.
-moveSp :: Int -> Instr
-moveSp n
-   = ADD False False sp (RIImm (ImmInt (n * BYTES_PER_WORD))) sp
-
--- Produce the second-half-of-a-double register given the first half.
-fPair :: Reg -> Reg
-fPair (RealReg n) | n >= 32 && n `mod` 2 == 0  = RealReg (n+1)
-fPair other = pprPanic "fPair(sparc NCG)" (ppr other)
-#endif /* sparc_TARGET_ARCH */
-\end{code}
-
-\begin{code}
-#ifdef powerpc_TARGET_ARCH
--- data Instr continues...
-
--- Loads and stores.
-
-             | LD      Size Reg MachRegsAddr -- Load size, dst, src
-             | ST      Size Reg MachRegsAddr -- Store size, src, dst 
-             | STU     Size Reg MachRegsAddr -- Store with Update size, src, dst 
-             | LIS     Reg Imm -- Load Immediate Shifted dst, src
-             | LI      Reg Imm -- Load Immediate dst, src
-             | MR      Reg Reg -- Move Register dst, src -- also for fmr
-             
-             | CMP     Size Reg RI --- size, src1, src2
-             | CMPL    Size Reg RI --- size, src1, src2
-             
-             | BCC     Cond CLabel
-             | MTCTR   Reg
-             | BCTR    DestInfo
-             | BL      Imm [Reg]       -- with list of argument regs
-             | BCTRL   [Reg]
-             
-             | ADD     Reg Reg RI -- dst, src1, src2    
-             | SUBF    Reg Reg Reg -- dst, src1, src2 ; dst = src2 - src1  
-             | MULLW   Reg Reg RI
-             | DIVW    Reg Reg Reg
-             | DIVWU   Reg Reg Reg
-             
-             | AND     Reg Reg RI -- dst, src1, src2
-             | OR      Reg Reg RI -- dst, src1, src2
-             | XOR     Reg Reg RI -- dst, src1, src2
-             | XORIS   Reg Reg Imm -- XOR Immediate Shifted dst, src1, src2
-             
-             | NEG     Reg Reg
-             | NOT     Reg Reg
-             
-             | SLW     Reg Reg RI      -- shift left word
-             | SRW     Reg Reg RI      -- shift right word
-             | SRAW    Reg Reg RI      -- shift right arithmetic word
-             
-             | FADD    Size Reg Reg Reg
-             | FSUB    Size Reg Reg Reg
-             | FMUL    Size Reg Reg Reg
-             | FDIV    Size Reg Reg Reg
-             | FNEG    Reg Reg  -- negate is the same for single and double prec.
-             
-             | FCMP    Reg Reg
-             
-             | FCTIWZ  Reg Reg         -- convert to integer word
-                                       -- (but destination is a FP register)
-             
-data RI = RIReg Reg
-       | RIImm Imm
-
-condUnsigned GU = True
-condUnsigned LU = True
-condUnsigned GEU = True
-condUnsigned LEU = True
-condUnsigned _ = False
-
-condToSigned GU = GTT
-condToSigned LU = LTT
-condToSigned GEU = GE
-condToSigned LEU = LE
-condToSigned x = x
-#endif /* powerpc_TARGET_ARCH */
-\end{code}
-
index b7c1680..e94086d 100644 (file)
-%
-% (c) The AQUA Project, Glasgow University, 1996-1998
-%
-\section[MachRegs]{Machine-specific info about registers}
-
-Also includes stuff about immediate operands, which are
-often/usually quite entangled with registers.
-
-(Immediates could be untangled from registers at some cost in tangled
-modules --- the pleasure has been foregone.)
+-- -----------------------------------------------------------------------------
+--
+-- (c) The University of Glasgow 1994-2004
+-- 
+-- Machine-specific info about registers.
+-- 
+-- Also includes stuff about immediate operands, which are
+-- often/usually quite entangled with registers.
+-- 
+-- (Immediates could be untangled from registers at some cost in tangled
+-- modules --- the pleasure has been foregone.)
+-- 
+-- -----------------------------------------------------------------------------
 
 \begin{code}
 #include "nativeGen/NCG.h"
 
 module MachRegs (
 
-        RegClass(..), regClass,
-       VRegUnique(..), pprVRegUnique, getHiVRegFromLo, 
-       Reg(..), isRealReg, isVirtualReg, getVRegUnique,
-        allocatableRegs, argRegs, allArgRegs, callClobberedRegs,
-
-       Imm(..),
-       MachRegsAddr(..),
+       -- * Immediate values
+       Imm(..), strImmLit, litToImm,
 
+       -- * Addressing modes
+       AddrMode(..),
        addrOffset,
-       baseRegOffset,
+
+       -- * The 'Reg' type
+       RegNo,
+       Reg(..), isRealReg, isVirtualReg,
+        RegClass(..), regClass,
+       getHiVRegFromLo, 
+       mkVReg,
+
+       -- * Global registers
+        get_GlobalReg_reg_or_addr,
        callerSaves,
+
+       -- * Machine-dependent register-related stuff
+        allocatableRegs, argRegs, allArgRegs, callClobberedRegs,
        freeReg,
-       getNewRegNCG,
-       mkVReg,
-        get_MagicId_reg_or_addr,
-        get_MagicId_addr,
-        get_Regtable_addr_from_offset,
        spRel,
-       strImmLit
 
 #if alpha_TARGET_ARCH
-       , allArgRegs
-       , fits8Bits
-       , fReg
-       , gp, pv, ra, sp, t9, t10, t11, t12, v0, f0, zeroh
+       allArgRegs,
+       fits8Bits,
+       fReg,
+       gp, pv, ra, sp, t9, t10, t11, t12, v0, f0, zeroh,
 #endif
 #if i386_TARGET_ARCH
-       , eax, ebx, ecx, edx, esi, esp
-       , fake0, fake1, fake2, fake3, fake4, fake5
+       eax, ebx, ecx, edx, esi, edi, ebp, esp,
+       fake0, fake1, fake2, fake3, fake4, fake5,
+       addrModeRegs,
 #endif
 #if sparc_TARGET_ARCH
-       , fits13Bits
-       , fpRel, gReg, iReg, lReg, oReg, largeOffsetError
-       , fp, sp, g0, g1, g2, o0, o1, f0, f6, f8, f26, f27
-       
+       fits13Bits,
+       fpRel, gReg, iReg, lReg, oReg, largeOffsetError,
+       fp, sp, g0, g1, g2, o0, o1, f0, f6, f8, f26, f27,
 #endif
 #if powerpc_TARGET_ARCH
-       , allFPArgRegs
-       , fits16Bits
-       , sp
-       , r3, r4, r27, r28
-       , f1, f20, f21
+       allFPArgRegs,
+       makeImmediate,
+       sp,
+       r3, r4, r27, r28,
+       f1, f20, f21,
 #endif
     ) where
 
 #include "HsVersions.h"
 
-import AbsCSyn         ( MagicId(..) )
+#if i386_TARGET_ARCH
+# define STOLEN_X86_REGS 4
+-- HACK: go for the max
+#endif
+
+#include "../includes/MachRegs.h"
+
+import Cmm
+import MachOp          ( MachRep(..) )
+
 import CLabel           ( CLabel, mkMainCapabilityLabel )
-import PrimRep         ( PrimRep(..), isFloatingRep )
-import Stix            ( StixExpr(..), StixReg(..),
-                          getUniqueNat, returnNat, thenNat, NatM )
 import Unique          ( Unique )
 import Pretty
 import Outputable      ( Outputable(..), pprPanic, panic )
 import qualified Outputable
+import Unique
+import Constants
 import FastTypes
-\end{code}
 
-% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if powerpc_TARGET_ARCH
+#if __GLASGOW_HASKELL__ >= 504
+import Data.Word       ( Word8, Word16, Word32 )
+import Data.Int        ( Int8, Int16, Int32 )
+#else
+import Word            ( Word8, Word16, Word32 )
+import Int             ( Int8, Int16, Int32 )
+#endif
+#endif
+
+-- -----------------------------------------------------------------------------
+-- Immediates
 
-\begin{code}
 data Imm
   = ImmInt     Int
   | ImmInteger Integer     -- Sigh.
   | ImmCLbl    CLabel      -- AbstractC Label (with baggage)
-  | ImmLab     Bool Doc    -- Simple string label (underscore-able)
-                             -- Bool==True ==> in a different DLL
-  | ImmLit     Doc    -- Simple string
+  | ImmLit     Doc         -- Simple string
   | ImmIndex    CLabel Int
   | ImmFloat   Rational
   | ImmDouble  Rational
-  IF_ARCH_sparc(
+#if sparc_TARGET_ARCH
   | LO Imm                 {- Possible restrictions... -}
   | HI Imm
-  ,IF_ARCH_powerpc(
+#endif
+#if powerpc_TARGET_ARCH
   | LO Imm
   | HI Imm
   | HA Imm     {- high halfword adjusted -}
-  ,))
+#if darwin_TARGET_OS
+        -- special dyld (dynamic linker) things
+  | ImmDyldNonLazyPtr CLabel  -- Llabel$non_lazy_ptr
+#endif
+#endif
 strImmLit s = ImmLit (text s)
-\end{code}
 
-% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+litToImm :: CmmLit -> Imm
+litToImm (CmmInt i _)        = ImmInteger i
+litToImm (CmmFloat f F32)    = ImmFloat f
+litToImm (CmmFloat f F64)    = ImmDouble f
+litToImm (CmmLabel l)        = ImmCLbl l
+litToImm (CmmLabelOff l off) = ImmIndex l off
 
-\begin{code}
-data MachRegsAddr
+-- -----------------------------------------------------------------------------
+-- Addressing modes
+
+data AddrMode
 #if alpha_TARGET_ARCH
   = AddrImm    Imm
   | AddrReg    Reg
@@ -126,7 +158,17 @@ type Displacement = Imm
   | AddrRegImm Reg Imm
 #endif
 
-addrOffset :: MachRegsAddr -> Int -> Maybe MachRegsAddr
+#if i386_TARGET_ARCH
+addrModeRegs :: AddrMode -> [Reg]
+addrModeRegs (AddrBaseIndex b i _) =  b_regs ++ i_regs
+  where
+   b_regs = case b of { Just r -> [r]; _ -> [] }
+   i_regs = case i of { Just (r,_) -> [r]; _ -> [] }
+addrModeRegs _ = []
+#endif
+
+
+addrOffset :: AddrMode -> Int -> Maybe AddrMode
 
 addrOffset addr off
   = case addr of
@@ -135,10 +177,18 @@ addrOffset addr off
 #endif
 #if i386_TARGET_ARCH
       ImmAddr i off0     -> Just (ImmAddr i (off0 + off))
+
       AddrBaseIndex r i (ImmInt n) -> Just (AddrBaseIndex r i (ImmInt (n + off)))
       AddrBaseIndex r i (ImmInteger n)
        -> Just (AddrBaseIndex r i (ImmInt (fromInteger (n + toInteger off))))
-      _ -> Nothing
+
+      AddrBaseIndex r i (ImmCLbl lbl)
+       -> Just (AddrBaseIndex r i (ImmIndex lbl off))
+
+      AddrBaseIndex r i (ImmIndex lbl ix)
+       -> Just (AddrBaseIndex r i (ImmIndex lbl (ix+off)))
+
+      _ -> Nothing  -- in theory, shouldn't happen
 #endif
 #if sparc_TARGET_ARCH
       AddrRegImm r (ImmInt n)
@@ -156,7 +206,6 @@ addrOffset addr off
        | otherwise     -> Nothing
        
       _ -> Nothing
-
 #endif /* sparc */
 #if powerpc_TARGET_ARCH
       AddrRegImm r (ImmInt n)
@@ -168,10 +217,6 @@ addrOffset addr off
        | fits16Bits n2 -> Just (AddrRegImm r (ImmInt (fromInteger n2)))
        | otherwise     -> Nothing
        where n2 = n + toInteger off
-
-      AddrRegReg r (RealReg 0)
-       | fits16Bits off -> Just (AddrRegImm r (ImmInt off))
-       | otherwise     -> Nothing
        
       _ -> Nothing
 #endif /* powerpc */
@@ -201,118 +246,110 @@ largeOffsetError i
 #if powerpc_TARGET_ARCH
 fits16Bits :: Integral a => a -> Bool
 fits16Bits x = x >= -32768 && x < 32768
-#endif
-\end{code}
-
-% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-@stgReg@: we map STG registers onto appropriate Stix Trees.  Either
-they map to real machine registers or stored as offsets from BaseReg.
-Given a MagicId, get_MagicId_reg_or_addr produces either the real
-register it is in, on this platform, or a StixExpr denoting the
-address in the register table holding it.  get_MagicId_addr always
-produces the register table address for it.
-
-\begin{code}
-get_MagicId_reg_or_addr       :: MagicId -> Either Reg StixExpr
-get_MagicId_addr              :: MagicId -> StixExpr
-get_Regtable_addr_from_offset :: Int -> StixExpr
-
-get_MagicId_reg_or_addr mid
-   = case magicIdRegMaybe mid of
-        Just rr -> Left rr
-        Nothing -> Right (get_MagicId_addr mid)
-
-get_MagicId_addr BaseReg
-   = -- This arch doesn't have BaseReg in a register, so we have to 
-     -- use &MainRegTable.r instead.
-     StIndex PtrRep (StCLbl mkMainCapabilityLabel)
-                    (StInt (toInteger OFFW_Capability_r))
-get_MagicId_addr mid
-   = get_Regtable_addr_from_offset (baseRegOffset mid)
-
-get_Regtable_addr_from_offset offset_in_words
-   = let ptr_to_RegTable
-            = case magicIdRegMaybe BaseReg of
-                 Nothing 
-                    -> -- This arch doesn't have BaseReg in a register, so we have to 
-                       -- use &MainRegTable.r instead.
-                       StIndex PtrRep (StCLbl mkMainCapabilityLabel)
-                                      (StInt (toInteger OFFW_Capability_r))
-                 Just _
-                    -> -- It's in a reg, so leave it as it is
-                       StReg (StixMagicId BaseReg)
-     in
-         StIndex PtrRep ptr_to_RegTable (StInt (toInteger offset_in_words))
-\end{code}
-
-% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
-@spRel@ gives us a stack relative addressing mode for volatile
-temporaries and for excess call arguments.  @fpRel@, where
-applicable, is the same but for the frame pointer.
+makeImmediate :: Integral a => MachRep -> Bool -> a -> Maybe Imm
+
+makeImmediate rep signed x = fmap ImmInt (toI16 rep signed)
+    where
+        narrow I32 False = fromIntegral (fromIntegral x :: Word32)
+        narrow I16 False = fromIntegral (fromIntegral x :: Word16)
+        narrow I8  False = fromIntegral (fromIntegral x :: Word8)
+        narrow I32 True  = fromIntegral (fromIntegral x :: Int32)
+        narrow I16 True  = fromIntegral (fromIntegral x :: Int16)
+        narrow I8  True  = fromIntegral (fromIntegral x :: Int8)
+        
+        narrowed = narrow rep signed
+        
+        toI16 I32 True
+            | narrowed >= -32768 && narrowed < 32768 = Just narrowed
+            | otherwise = Nothing
+        toI16 I32 False
+            | narrowed >= 0 && narrowed < 65536 = Just narrowed
+            | otherwise = Nothing
+        toI16 _ _  = Just narrowed
+#endif
+
+
+-- @spRel@ gives us a stack relative addressing mode for volatile
+-- temporaries and for excess call arguments.  @fpRel@, where
+-- applicable, is the same but for the frame pointer.
 
-\begin{code}
 spRel :: Int   -- desired stack offset in words, positive or negative
-      -> MachRegsAddr
+      -> AddrMode
 
 spRel n
 #if i386_TARGET_ARCH
-  = AddrBaseIndex (Just esp) Nothing (ImmInt (n * BYTES_PER_WORD))
+  = AddrBaseIndex (Just esp) Nothing (ImmInt (n * wORD_SIZE))
 #else
-  = AddrRegImm sp (ImmInt (n * BYTES_PER_WORD))
+  = AddrRegImm sp (ImmInt (n * wORD_SIZE))
 #endif
 
 #if sparc_TARGET_ARCH
-fpRel :: Int -> MachRegsAddr
+fpRel :: Int -> AddrMode
     -- Duznae work for offsets greater than 13 bits; we just hope for
     -- the best
 fpRel n
-  = AddrRegImm fp (ImmInt (n * BYTES_PER_WORD))
+  = AddrRegImm fp (ImmInt (n * wORD_SIZE))
 #endif
-\end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection[Reg]{Real registers}
-%*                                                                     *
-%************************************************************************
 
-RealRegs are machine regs which are available for allocation, in the
-usual way.  We know what class they are, because that's part of the
-processor's architecture.
+-- -----------------------------------------------------------------------------
+-- Global registers
 
-VirtualRegs are virtual registers.  The register allocator will
-eventually have to map them into RealRegs, or into spill slots.
-VirtualRegs are allocated on the fly, usually to represent a single
-value in the abstract assembly code (i.e. dynamic registers are
-usually single assignment).  With the new register allocator, the
-single assignment restriction isn't necessary to get correct code,
-although a better register allocation will result if single assignment
-is used -- because the allocator maps a VirtualReg into a single
-RealReg, even if the VirtualReg has multiple live ranges.
+-- We map STG registers onto appropriate CmmExprs.  Either they map
+-- to real machine registers or stored as offsets from BaseReg.  Given
+-- a GlobalReg, get_GlobalReg_reg_or_addr produces either the real
+-- register it is in, on this platform, or a StixExpr denoting the
+-- address in the register table holding it.  get_MagicId_addr always
+-- produces the register table address for it.
 
-Virtual regs can be of either class, so that info is attached.
+get_GlobalReg_reg_or_addr       :: GlobalReg -> Either Reg CmmExpr
+get_GlobalReg_addr              :: GlobalReg -> CmmExpr
+get_Regtable_addr_from_offset   :: MachRep -> Int -> CmmExpr
 
-\begin{code}
+get_GlobalReg_reg_or_addr mid
+   = case globalRegMaybe mid of
+        Just rr -> Left rr
+        Nothing -> Right (get_GlobalReg_addr mid)
+
+get_GlobalReg_addr BaseReg = regTableOffset 0
+get_GlobalReg_addr mid     = get_Regtable_addr_from_offset 
+                               (globalRegRep mid) (baseRegOffset mid)
+
+-- Calculate a literal representing an offset into the register table.
+-- Used when we don't have an actual BaseReg to offset from.
+regTableOffset n = 
+  CmmLit (CmmLabelOff mkMainCapabilityLabel (oFFSET_Capability_r + n))
 
-data VRegUnique
-   = VRegUniqueLo Unique               -- lower part of a split quantity
-   | VRegUniqueHi Unique               -- upper part thereof
-     deriving (Eq, Ord)
+get_Regtable_addr_from_offset rep offset
+   = case globalRegMaybe BaseReg of
+                 Nothing -> regTableOffset offset
+                 Just _  -> CmmRegOff (CmmGlobal BaseReg) offset
 
-instance Show VRegUnique where
-   show (VRegUniqueLo u) = show u
-   show (VRegUniqueHi u) = "_hi_" ++ show u
+-- ---------------------------------------------------------------------------
+-- Registers
 
-pprVRegUnique :: VRegUnique -> Outputable.SDoc
-pprVRegUnique 
-   = Outputable.text . show
+-- RealRegs are machine regs which are available for allocation, in
+-- the usual way.  We know what class they are, because that's part of
+-- the processor's architecture.
+
+-- VirtualRegs are virtual registers.  The register allocator will
+-- eventually have to map them into RealRegs, or into spill slots.
+-- VirtualRegs are allocated on the fly, usually to represent a single
+-- value in the abstract assembly code (i.e. dynamic registers are
+-- usually single assignment).  With the new register allocator, the
+-- single assignment restriction isn't necessary to get correct code,
+-- although a better register allocation will result if single
+-- assignment is used -- because the allocator maps a VirtualReg into
+-- a single RealReg, even if the VirtualReg has multiple live ranges.
+
+-- Virtual regs can be of either class, so that info is attached.
 
 -- Determine the upper-half vreg for a 64-bit quantity on a 32-bit platform
 -- when supplied with the vreg for the lower-half of the quantity.
-getHiVRegFromLo (VirtualRegI (VRegUniqueLo u)) 
-   = VirtualRegI (VRegUniqueHi u)
+-- (NB. Not reversible).
+getHiVRegFromLo (VirtualRegI u) 
+   = VirtualRegHi (newTagUnique u 'H') -- makes a pseudo-unique with tag 'H'
 getHiVRegFromLo other 
    = pprPanic "getHiVRegFromLo" (ppr other)
 
@@ -322,90 +359,66 @@ data RegClass
    | RcDouble
      deriving Eq
 
+type RegNo = Int
+
 data Reg
-   = RealReg     Int
-   | VirtualRegI VRegUnique
-   | VirtualRegF VRegUnique
-   | VirtualRegD VRegUnique
-
-unRealReg (RealReg i) = i
-unRealReg vreg        = pprPanic "unRealReg on VirtualReg" (ppr vreg)
-
-getVRegUnique :: Reg -> VRegUnique
-getVRegUnique (VirtualRegI vu) = vu
-getVRegUnique (VirtualRegF vu) = vu
-getVRegUnique (VirtualRegD vu) = vu
-getVRegUnique rreg             = pprPanic "getVRegUnique on RealReg" (ppr rreg)
-
-mkVReg :: Unique -> PrimRep -> Reg
-mkVReg u pk
+   = RealReg      {-# UNPACK #-} !RegNo
+   | VirtualRegI  {-# UNPACK #-} !Unique
+   | VirtualRegHi {-# UNPACK #-} !Unique  -- High part of 2-word register
+   | VirtualRegF  {-# UNPACK #-} !Unique
+   | VirtualRegD  {-# UNPACK #-} !Unique
+   deriving (Eq,Ord)
+
+-- We like to have Uniques for Reg so that we can make UniqFM and UniqSets 
+-- in the register allocator.
+instance Uniquable Reg where
+   getUnique (RealReg i)      = mkUnique 'C' i
+   getUnique (VirtualRegI u)  = u
+   getUnique (VirtualRegHi u) = u
+   getUnique (VirtualRegF u)  = u
+   getUnique (VirtualRegD u)  = u
+
+mkVReg :: Unique -> MachRep -> Reg
+mkVReg u rep
+   = case rep of
 #if sparc_TARGET_ARCH
-   = case pk of
-        FloatRep  -> VirtualRegF (VRegUniqueLo u)
-        DoubleRep -> VirtualRegD (VRegUniqueLo u)
-        other     -> VirtualRegI (VRegUniqueLo u)
+        F32   -> VirtualRegF u
 #else
-   = if isFloatingRep pk then VirtualRegD (VRegUniqueLo u) 
-                         else VirtualRegI (VRegUniqueLo u)
+        F32   -> VirtualRegD u
 #endif
+        F64   -> VirtualRegD u
+        other -> VirtualRegI u
 
-isVirtualReg (RealReg _)     = False
-isVirtualReg (VirtualRegI _) = True
-isVirtualReg (VirtualRegF _) = True
-isVirtualReg (VirtualRegD _) = True
-isRealReg = not . isVirtualReg
-
-getNewRegNCG :: PrimRep -> NatM Reg
-getNewRegNCG pk
-   = getUniqueNat `thenNat` \ u -> returnNat (mkVReg u pk)
-
-instance Eq Reg where
-   (==) (RealReg i1)     (RealReg i2)     = i1 == i2
-   (==) (VirtualRegI u1) (VirtualRegI u2) = u1 == u2
-   (==) (VirtualRegF u1) (VirtualRegF u2) = u1 == u2
-   (==) (VirtualRegD u1) (VirtualRegD u2) = u1 == u2
-   (==) reg1             reg2             = False
-
-instance Ord Reg where
-   compare (RealReg i1)     (RealReg i2)     = compare i1 i2
-   compare (RealReg _)      (VirtualRegI _)  = LT
-   compare (RealReg _)      (VirtualRegF _)  = LT
-   compare (RealReg _)      (VirtualRegD _)  = LT
-
-   compare (VirtualRegI _)  (RealReg _)      = GT
-   compare (VirtualRegI u1) (VirtualRegI u2) = compare u1 u2
-   compare (VirtualRegI _)  (VirtualRegF _)  = LT
-   compare (VirtualRegI _)  (VirtualRegD _)  = LT
-
-   compare (VirtualRegF _)  (RealReg _)      = GT
-   compare (VirtualRegF _)  (VirtualRegI _)  = GT
-   compare (VirtualRegF u1) (VirtualRegF u2) = compare u1 u2
-   compare (VirtualRegF _)  (VirtualRegD _)  = LT
-
-   compare (VirtualRegD _)  (RealReg _)      = GT
-   compare (VirtualRegD _)  (VirtualRegI _)  = GT
-   compare (VirtualRegD _)  (VirtualRegF _)  = GT
-   compare (VirtualRegD u1) (VirtualRegD u2) = compare u1 u2
+isVirtualReg :: Reg -> Bool
+isVirtualReg (RealReg _)      = False
+isVirtualReg (VirtualRegI _)  = True
+isVirtualReg (VirtualRegHi _) = True
+isVirtualReg (VirtualRegF _)  = True
+isVirtualReg (VirtualRegD _)  = True
 
+isRealReg :: Reg -> Bool
+isRealReg = not . isVirtualReg
 
 instance Show Reg where
-    show (RealReg i)     = showReg i
-    show (VirtualRegI u) = "%vI_" ++ show u
-    show (VirtualRegF u) = "%vF_" ++ show u
-    show (VirtualRegD u) = "%vD_" ++ show u
+    show (RealReg i)      = showReg i
+    show (VirtualRegI u)  = "%vI_" ++ show u
+    show (VirtualRegHi u) = "%vHi_" ++ show u
+    show (VirtualRegF u)  = "%vF_" ++ show u
+    show (VirtualRegD u)  = "%vD_" ++ show u
 
 instance Outputable Reg where
     ppr r = Outputable.text (show r)
-\end{code}
 
-** Machine-specific Reg stuff: **
 
-The Alpha has 64 registers of interest; 32 integer registers and 32 floating
-point registers.  The mapping of STG registers to alpha machine registers
-is defined in StgRegs.h.  We are, of course, prepared for any eventuality.
-\begin{code}
+-- -----------------------------------------------------------------------------
+-- Machine-specific register stuff
+
+-- The Alpha has 64 registers of interest; 32 integer registers and 32 floating
+-- point registers.  The mapping of STG registers to alpha machine registers
+-- is defined in StgRegs.h.  We are, of course, prepared for any eventuality.
+
 #if alpha_TARGET_ARCH
-fReg :: Int -> Int
+fReg :: Int -> RegNo
 fReg x = (32 + x)
 
 v0, f0, ra, pv, gp, sp, zeroh :: Reg
@@ -423,8 +436,8 @@ t10 = realReg 24
 t11 = realReg 25
 t12 = realReg 27
 #endif
-\end{code}
 
+{-
 Intel x86 architecture:
 - All registers except 7 (esp) are available for use.
 - Only ebx, esi, edi and esp are available across a C call (they are callee-saves).
@@ -437,8 +450,8 @@ Intel x86 architecture:
 The fp registers are all Double registers; we don't have any RcFloat class
 regs.  @regClass@ barfs if you give it a VirtualRegF, and mkVReg above should
 never generate them.
+-}
 
-\begin{code}
 #if i386_TARGET_ARCH
 
 fake0, fake1, fake2, fake3, fake4, fake5, 
@@ -458,25 +471,30 @@ fake3 = RealReg 11
 fake4 = RealReg 12
 fake5 = RealReg 13
 
+-- On x86, we might want to have an 8-bit RegClass, which would
+-- contain just regs 1-4 (the others don't have 8-bit versions).
+-- However, we can get away without this at the moment because the
+-- only allocatable integer regs are also 8-bit compatible (1, 3, 4).
 regClass (RealReg i)     = if i < 8 then RcInteger else RcDouble
-regClass (VirtualRegI u) = RcInteger
-regClass (VirtualRegD u) = RcDouble
-regClass (VirtualRegF u) = pprPanic "regClass(x86):VirtualRegF" 
+regClass (VirtualRegI  u) = RcInteger
+regClass (VirtualRegHi u) = RcInteger
+regClass (VirtualRegD  u) = RcDouble
+regClass (VirtualRegF  u) = pprPanic "regClass(x86):VirtualRegF" 
                                     (ppr (VirtualRegF u))
 
 regNames 
    = ["%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp", "%esp", 
       "%fake0", "%fake1", "%fake2", "%fake3", "%fake4", "%fake5", "%fake6"]
 
-showReg :: Int -> String
+showReg :: RegNo -> String
 showReg n
    = if   n >= 0 && n < 14
      then regNames !! n
      else "%unknown_x86_real_reg_" ++ show n
 
 #endif
-\end{code}
 
+{-
 The SPARC has 64 registers of interest; 32 integer registers and 32
 floating point registers.  The mapping of STG registers to SPARC
 machine registers is defined in StgRegs.h.  We are, of course,
@@ -485,18 +503,18 @@ prepared for any eventuality.
 The whole fp-register pairing thing on sparcs is a huge nuisance.  See
 fptools/ghc/includes/MachRegs.h for a description of what's going on
 here.
+-}
 
-\begin{code}
 #if sparc_TARGET_ARCH
 
-gReg,lReg,iReg,oReg,fReg :: Int -> Int
+gReg,lReg,iReg,oReg,fReg :: Int -> RegNo
 gReg x = x
 oReg x = (8 + x)
 lReg x = (16 + x)
 iReg x = (24 + x)
 fReg x = (32 + x)
 
-nCG_FirstFloatReg :: Int
+nCG_FirstFloatReg :: RegNo
 nCG_FirstFloatReg = unRealReg NCG_FirstFloatReg
 
 regClass (VirtualRegI u) = RcInteger
@@ -506,7 +524,7 @@ regClass (RealReg i) | i < 32                = RcInteger
                      | i < nCG_FirstFloatReg = RcDouble
                      | otherwise             = RcFloat
 
-showReg :: Int -> String
+showReg :: RegNo -> String
 showReg n
    | n >= 0  && n < 8   = "%g" ++ show n
    | n >= 8  && n < 16  = "%o" ++ show (n-8)
@@ -538,24 +556,25 @@ f0  = RealReg (fReg 0)
 f1  = RealReg (fReg 1)
 
 #endif
-\end{code}
 
+{-
 The PowerPC has 64 registers of interest; 32 integer registers and 32 floating
 point registers.
-\begin{code}
+-}
+
 #if powerpc_TARGET_ARCH
-fReg :: Int -> Int
+fReg :: Int -> RegNo
 fReg x = (32 + x)
 
-regClass (VirtualRegI u) = RcInteger
-regClass (VirtualRegF u) = RcFloat
+regClass (VirtualRegI  u) = RcInteger
+regClass (VirtualRegHi u) = RcInteger
+regClass (VirtualRegF  u) = pprPanic "regClass(ppc):VirtualRegF" 
+                                    (ppr (VirtualRegF u))
 regClass (VirtualRegD u) = RcDouble
 regClass (RealReg i) | i < 32                = RcInteger 
                     | otherwise             = RcDouble
-                  --   | i < nCG_FirstFloatReg = RcDouble
-                  --   | otherwise             = RcFloat
 
-showReg :: Int -> String
+showReg :: RegNo -> String
 showReg n
     | n >= 0 && n <= 31          = "%r" ++ show n
     | n >= 32 && n <= 63  = "%f" ++ show (n - 32)
@@ -570,11 +589,12 @@ f1 = RealReg $ fReg 1
 f20 = RealReg $ fReg 20
 f21 = RealReg $ fReg 21
 #endif
-\end{code}
 
+{-
 Redefine the literals used for machine-registers with non-numeric
 names in the header files.  Gag me with a spoon, eh?
-\begin{code}
+-}
+
 #if alpha_TARGET_ARCH
 #define f0 32
 #define f1 33
@@ -795,201 +815,10 @@ names in the header files.  Gag me with a spoon, eh?
 #define fr31 63
 #endif
 #endif
-\end{code}
-
-\begin{code}
-baseRegOffset :: MagicId -> Int
-
-baseRegOffset (VanillaReg _ 1#)      = OFFSET_R1
-baseRegOffset (VanillaReg _ 2#)      = OFFSET_R2
-baseRegOffset (VanillaReg _ 3#)      = OFFSET_R3
-baseRegOffset (VanillaReg _ 4#)      = OFFSET_R4
-baseRegOffset (VanillaReg _ 5#)      = OFFSET_R5
-baseRegOffset (VanillaReg _ 6#)      = OFFSET_R6
-baseRegOffset (VanillaReg _ 7#)      = OFFSET_R7
-baseRegOffset (VanillaReg _ 8#)      = OFFSET_R8
-baseRegOffset (VanillaReg _ 9#)      = OFFSET_R9
-baseRegOffset (VanillaReg _ 10#)     = OFFSET_R10
-baseRegOffset (FloatReg  1#)         = OFFSET_F1
-baseRegOffset (FloatReg  2#)         = OFFSET_F2
-baseRegOffset (FloatReg  3#)         = OFFSET_F3
-baseRegOffset (FloatReg  4#)         = OFFSET_F4
-baseRegOffset (DoubleReg 1#)         = OFFSET_D1
-baseRegOffset (DoubleReg 2#)         = OFFSET_D2
-baseRegOffset Sp                    = OFFSET_Sp
-baseRegOffset SpLim                 = OFFSET_SpLim
-#ifdef OFFSET_L1
-baseRegOffset (LongReg _ 1#)         = OFFSET_L1
-#endif
-baseRegOffset Hp                    = OFFSET_Hp
-baseRegOffset HpLim                 = OFFSET_HpLim
-baseRegOffset CurrentTSO            = OFFSET_CurrentTSO
-baseRegOffset CurrentNursery        = OFFSET_CurrentNursery
-baseRegOffset HpAlloc               = OFFSET_HpAlloc
-#ifdef NCG_DEBUG
-baseRegOffset BaseReg               = panic "baseRegOffset:BaseReg"
-baseRegOffset CurCostCentre         = panic "baseRegOffset:CurCostCentre"
-baseRegOffset VoidReg               = panic "baseRegOffset:VoidReg"
-#endif
-\end{code}
-
-\begin{code}
-callerSaves :: MagicId -> Bool
-
-#ifdef CALLER_SAVES_Base
-callerSaves BaseReg                    = True
-#endif
-#ifdef CALLER_SAVES_R1
-callerSaves (VanillaReg _ ILIT(1))     = True
-#endif
-#ifdef CALLER_SAVES_R2
-callerSaves (VanillaReg _ ILIT(2))     = True
-#endif
-#ifdef CALLER_SAVES_R3
-callerSaves (VanillaReg _ ILIT(3))     = True
-#endif
-#ifdef CALLER_SAVES_R4
-callerSaves (VanillaReg _ ILIT(4))     = True
-#endif
-#ifdef CALLER_SAVES_R5
-callerSaves (VanillaReg _ ILIT(5))     = True
-#endif
-#ifdef CALLER_SAVES_R6
-callerSaves (VanillaReg _ ILIT(6))     = True
-#endif
-#ifdef CALLER_SAVES_R7
-callerSaves (VanillaReg _ ILIT(7))     = True
-#endif
-#ifdef CALLER_SAVES_R8
-callerSaves (VanillaReg _ ILIT(8))     = True
-#endif
-#ifdef CALLER_SAVES_F1
-callerSaves (FloatReg 1#)              = True
-#endif
-#ifdef CALLER_SAVES_F2
-callerSaves (FloatReg 2#)              = True
-#endif
-#ifdef CALLER_SAVES_F3
-callerSaves (FloatReg 3#)              = True
-#endif
-#ifdef CALLER_SAVES_F4
-callerSaves (FloatReg 4#)              = True
-#endif
-#ifdef CALLER_SAVES_D1
-callerSaves (DoubleReg 1#)             = True
-#endif
-#ifdef CALLER_SAVES_D2
-callerSaves (DoubleReg 2#)             = True
-#endif
-#ifdef CALLER_SAVES_L1
-callerSaves (LongReg _ ILIT(1))                = True
-#endif
-#ifdef CALLER_SAVES_Sp
-callerSaves Sp                         = True
-#endif
-#ifdef CALLER_SAVES_SpLim
-callerSaves SpLim                      = True
-#endif
-#ifdef CALLER_SAVES_Hp
-callerSaves Hp                         = True
-#endif
-#ifdef CALLER_SAVES_HpLim
-callerSaves HpLim                      = True
-#endif
-#ifdef CALLER_SAVES_CurrentTSO
-callerSaves CurrentTSO                 = True
-#endif
-#ifdef CALLER_SAVES_CurrentNursery
-callerSaves CurrentNursery             = True
-#endif
-callerSaves _                          = False
-\end{code}
-
-\begin{code}
-magicIdRegMaybe :: MagicId -> Maybe Reg
 
-#ifdef REG_Base
-magicIdRegMaybe BaseReg                        = Just (RealReg REG_Base)
-#endif
-#ifdef REG_R1
-magicIdRegMaybe (VanillaReg _ 1#)      = Just (RealReg REG_R1)
-#endif 
-#ifdef REG_R2 
-magicIdRegMaybe (VanillaReg _ 2#)      = Just (RealReg REG_R2)
-#endif 
-#ifdef REG_R3 
-magicIdRegMaybe (VanillaReg _ 3#)      = Just (RealReg REG_R3)
-#endif 
-#ifdef REG_R4 
-magicIdRegMaybe (VanillaReg _ 4#)      = Just (RealReg REG_R4)
-#endif 
-#ifdef REG_R5 
-magicIdRegMaybe (VanillaReg _ 5#)      = Just (RealReg REG_R5)
-#endif 
-#ifdef REG_R6 
-magicIdRegMaybe (VanillaReg _ 6#)      = Just (RealReg REG_R6)
-#endif 
-#ifdef REG_R7 
-magicIdRegMaybe (VanillaReg _ 7#)      = Just (RealReg REG_R7)
-#endif 
-#ifdef REG_R8 
-magicIdRegMaybe (VanillaReg _ 8#)      = Just (RealReg REG_R8)
-#endif
-#ifdef REG_R9 
-magicIdRegMaybe (VanillaReg _ 9#)      = Just (RealReg REG_R9)
-#endif
-#ifdef REG_R10 
-magicIdRegMaybe (VanillaReg _ 10#)     = Just (RealReg REG_R10)
-#endif
-#ifdef REG_F1
-magicIdRegMaybe (FloatReg 1#)  = Just (RealReg REG_F1)
-#endif                                 
-#ifdef REG_F2                          
-magicIdRegMaybe (FloatReg 2#)  = Just (RealReg REG_F2)
-#endif                                 
-#ifdef REG_F3                          
-magicIdRegMaybe (FloatReg 3#)  = Just (RealReg REG_F3)
-#endif                                 
-#ifdef REG_F4                          
-magicIdRegMaybe (FloatReg 4#)  = Just (RealReg REG_F4)
-#endif                                 
-#ifdef REG_D1                          
-magicIdRegMaybe (DoubleReg 1#) = Just (RealReg REG_D1)
-#endif                                 
-#ifdef REG_D2                          
-magicIdRegMaybe (DoubleReg 2#) = Just (RealReg REG_D2)
-#endif
-#ifdef REG_Sp      
-magicIdRegMaybe Sp                     = Just (RealReg REG_Sp)
-#endif
-#ifdef REG_Lng1                                
-magicIdRegMaybe (LongReg _ ILIT(1))    = Just (RealReg REG_Lng1)
-#endif                                 
-#ifdef REG_Lng2                                
-magicIdRegMaybe (LongReg _ ILIT(2))    = Just (RealReg REG_Lng2)
-#endif
-#ifdef REG_SpLim                               
-magicIdRegMaybe SpLim                  = Just (RealReg REG_SpLim)
-#endif                                 
-#ifdef REG_Hp                          
-magicIdRegMaybe Hp                     = Just (RealReg REG_Hp)
-#endif                                 
-#ifdef REG_HpLim                       
-magicIdRegMaybe HpLim                  = Just (RealReg REG_HpLim)
-#endif                                 
-#ifdef REG_CurrentTSO                          
-magicIdRegMaybe CurrentTSO             = Just (RealReg REG_CurrentTSO)
-#endif                                 
-#ifdef REG_CurrentNursery                              
-magicIdRegMaybe CurrentNursery         = Just (RealReg REG_CurrentNursery)
-#endif                                 
-magicIdRegMaybe _                      = Nothing
-\end{code}
 
-\begin{code}
--------------------------------
 -- allMachRegs is the complete set of machine regs.
-allMachRegNos :: [Int]
+allMachRegNos :: [RegNo]
 allMachRegNos
    = IF_ARCH_alpha( [0..63],
      IF_ARCH_i386(  [0..13],
@@ -998,15 +827,15 @@ allMachRegNos
                      ++ [nCG_FirstFloatReg .. f31]),
      IF_ARCH_powerpc([0..63],
                    ))))
+
 -- allocatableRegs is allMachRegNos with the fixed-use regs removed.
 -- i.e., these are the regs for which we are prepared to allow the
 -- register allocator to attempt to map VRegs to.
-allocatableRegs :: [Reg]
+allocatableRegs :: [RegNo]
 allocatableRegs
    = let isFree i = isFastTrue (freeReg i)
-     in  map RealReg (filter isFree allMachRegNos)
+     in  filter isFree allMachRegNos
 
--------------------------------
 -- these are the regs which we cannot assume stay alive over a
 -- C call.  
 callClobberedRegs :: [Reg]
@@ -1031,15 +860,19 @@ callClobberedRegs
           [fReg i | i <- [0..31]] )
 #endif /* sparc_TARGET_ARCH */
 #if powerpc_TARGET_ARCH
-    map RealReg ([0..12] ++ map fReg [0..13])
+#if darwin_TARGET_OS
+    map RealReg (0:[2..12] ++ map fReg [0..13])
+#elif linux_TARGET_OS
+    map RealReg (0:[2..13] ++ map fReg [0..13])
+#endif
 #endif /* powerpc_TARGET_ARCH */
 
--------------------------------
+
 -- argRegs is the set of regs which are read for an n-argument call to C.
 -- For archs which pass all args on the stack (x86), is empty.
 -- Sparc passes up to the first 6 args in regs.
 -- Dunno about Alpha.
-argRegs :: Int -> [Reg]
+argRegs :: RegNo -> [Reg]
 
 #if i386_TARGET_ARCH
 argRegs _ = panic "MachRegs.argRegs(x86): should not be used!"
@@ -1080,7 +913,7 @@ argRegs 8 = map RealReg [3..10]
 argRegs _ = panic "MachRegs.argRegs(powerpc): don't know about >8 arguments!"
 #endif /* powerpc_TARGET_ARCH */
 
--------------------------------
+
 -- all of the arg regs ??
 #if alpha_TARGET_ARCH
 allArgRegs :: [(Reg, Reg)]
@@ -1101,12 +934,16 @@ allArgRegs = panic "MachRegs.allArgRegs(x86): should not be used!"
 allArgRegs :: [Reg]
 allArgRegs = map RealReg [3..10]
 allFPArgRegs :: [Reg]
+#if darwin_TARGET_OS
 allFPArgRegs = map (RealReg . fReg) [1..13]
+#elif linux_TARGET_OS
+allFPArgRegs = map (RealReg . fReg) [1..8]
+#endif
 #endif /* powerpc_TARGET_ARCH */
 \end{code}
 
 \begin{code}
-freeReg :: Int -> FastBool
+freeReg :: RegNo -> FastBool
 
 #if alpha_TARGET_ARCH
 freeReg 26 = fastBool False  -- return address (ra)
@@ -1204,4 +1041,201 @@ freeReg REG_Hp   = fastBool False
 freeReg REG_HpLim = fastBool False
 #endif
 freeReg n               = fastBool True
+
+
+-- -----------------------------------------------------------------------------
+-- Information about global registers
+
+baseRegOffset :: GlobalReg -> Int
+
+baseRegOffset (VanillaReg 1)      = oFFSET_StgRegTable_rR1
+baseRegOffset (VanillaReg 2)      = oFFSET_StgRegTable_rR2
+baseRegOffset (VanillaReg 3)      = oFFSET_StgRegTable_rR3
+baseRegOffset (VanillaReg 4)      = oFFSET_StgRegTable_rR4
+baseRegOffset (VanillaReg 5)      = oFFSET_StgRegTable_rR5
+baseRegOffset (VanillaReg 6)      = oFFSET_StgRegTable_rR6
+baseRegOffset (VanillaReg 7)      = oFFSET_StgRegTable_rR7
+baseRegOffset (VanillaReg 8)      = oFFSET_StgRegTable_rR8
+baseRegOffset (VanillaReg 9)      = oFFSET_StgRegTable_rR9
+baseRegOffset (VanillaReg 10)     = oFFSET_StgRegTable_rR10
+baseRegOffset (FloatReg  1)       = oFFSET_StgRegTable_rF1
+baseRegOffset (FloatReg  2)       = oFFSET_StgRegTable_rF2
+baseRegOffset (FloatReg  3)       = oFFSET_StgRegTable_rF3
+baseRegOffset (FloatReg  4)       = oFFSET_StgRegTable_rF4
+baseRegOffset (DoubleReg 1)       = oFFSET_StgRegTable_rD1
+baseRegOffset (DoubleReg 2)       = oFFSET_StgRegTable_rD2
+baseRegOffset Sp                 = oFFSET_StgRegTable_rSp
+baseRegOffset SpLim              = oFFSET_StgRegTable_rSpLim
+baseRegOffset (LongReg 1)         = oFFSET_StgRegTable_rL1
+baseRegOffset Hp                 = oFFSET_StgRegTable_rHp
+baseRegOffset HpLim              = oFFSET_StgRegTable_rHpLim
+baseRegOffset CurrentTSO         = oFFSET_StgRegTable_rCurrentTSO
+baseRegOffset CurrentNursery     = oFFSET_StgRegTable_rCurrentNursery
+baseRegOffset HpAlloc            = oFFSET_StgRegTable_rHpAlloc
+baseRegOffset GCEnter1           = oFFSET_stgGCEnter1
+baseRegOffset GCFun              = oFFSET_stgGCFun
+#ifdef DEBUG
+baseRegOffset BaseReg            = panic "baseRegOffset:BaseReg"
+baseRegOffset _                          = panic "baseRegOffset:other"
+#endif
+
+
+-- | Returns 'True' if this global register is stored in a caller-saves
+-- machine register.
+
+callerSaves :: GlobalReg -> Bool
+
+#ifdef CALLER_SAVES_Base
+callerSaves BaseReg                    = True
+#endif
+#ifdef CALLER_SAVES_R1
+callerSaves (VanillaReg _ ILIT(1))     = True
+#endif
+#ifdef CALLER_SAVES_R2
+callerSaves (VanillaReg _ ILIT(2))     = True
+#endif
+#ifdef CALLER_SAVES_R3
+callerSaves (VanillaReg _ ILIT(3))     = True
+#endif
+#ifdef CALLER_SAVES_R4
+callerSaves (VanillaReg _ ILIT(4))     = True
+#endif
+#ifdef CALLER_SAVES_R5
+callerSaves (VanillaReg _ ILIT(5))     = True
+#endif
+#ifdef CALLER_SAVES_R6
+callerSaves (VanillaReg _ ILIT(6))     = True
+#endif
+#ifdef CALLER_SAVES_R7
+callerSaves (VanillaReg _ ILIT(7))     = True
+#endif
+#ifdef CALLER_SAVES_R8
+callerSaves (VanillaReg _ ILIT(8))     = True
+#endif
+#ifdef CALLER_SAVES_F1
+callerSaves (FloatReg 1#)              = True
+#endif
+#ifdef CALLER_SAVES_F2
+callerSaves (FloatReg 2#)              = True
+#endif
+#ifdef CALLER_SAVES_F3
+callerSaves (FloatReg 3#)              = True
+#endif
+#ifdef CALLER_SAVES_F4
+callerSaves (FloatReg 4#)              = True
+#endif
+#ifdef CALLER_SAVES_D1
+callerSaves (DoubleReg 1#)             = True
+#endif
+#ifdef CALLER_SAVES_D2
+callerSaves (DoubleReg 2#)             = True
+#endif
+#ifdef CALLER_SAVES_L1
+callerSaves (LongReg _ ILIT(1))                = True
+#endif
+#ifdef CALLER_SAVES_Sp
+callerSaves Sp                         = True
+#endif
+#ifdef CALLER_SAVES_SpLim
+callerSaves SpLim                      = True
+#endif
+#ifdef CALLER_SAVES_Hp
+callerSaves Hp                         = True
+#endif
+#ifdef CALLER_SAVES_HpLim
+callerSaves HpLim                      = True
+#endif
+#ifdef CALLER_SAVES_CurrentTSO
+callerSaves CurrentTSO                 = True
+#endif
+#ifdef CALLER_SAVES_CurrentNursery
+callerSaves CurrentNursery             = True
+#endif
+callerSaves _                          = False
+
+
+-- | Returns 'Nothing' if this global register is not stored
+-- in a real machine register, otherwise returns @'Just' reg@, where
+-- reg is the machine register it is stored in.
+
+globalRegMaybe :: GlobalReg -> Maybe Reg
+
+#ifdef REG_Base
+globalRegMaybe BaseReg                 = Just (RealReg REG_Base)
+#endif
+#ifdef REG_R1
+globalRegMaybe (VanillaReg 1)          = Just (RealReg REG_R1)
+#endif 
+#ifdef REG_R2 
+globalRegMaybe (VanillaReg 2)          = Just (RealReg REG_R2)
+#endif 
+#ifdef REG_R3 
+globalRegMaybe (VanillaReg 3)          = Just (RealReg REG_R3)
+#endif 
+#ifdef REG_R4 
+globalRegMaybe (VanillaReg 4)          = Just (RealReg REG_R4)
+#endif 
+#ifdef REG_R5 
+globalRegMaybe (VanillaReg 5)          = Just (RealReg REG_R5)
+#endif 
+#ifdef REG_R6 
+globalRegMaybe (VanillaReg 6)          = Just (RealReg REG_R6)
+#endif 
+#ifdef REG_R7 
+globalRegMaybe (VanillaReg 7)          = Just (RealReg REG_R7)
+#endif 
+#ifdef REG_R8 
+globalRegMaybe (VanillaReg 8)          = Just (RealReg REG_R8)
+#endif
+#ifdef REG_R9 
+globalRegMaybe (VanillaReg 9)          = Just (RealReg REG_R9)
+#endif
+#ifdef REG_R10 
+globalRegMaybe (VanillaReg 10)         = Just (RealReg REG_R10)
+#endif
+#ifdef REG_F1
+globalRegMaybe (FloatReg 1)            = Just (RealReg REG_F1)
+#endif                                 
+#ifdef REG_F2                          
+globalRegMaybe (FloatReg 2)            = Just (RealReg REG_F2)
+#endif                                 
+#ifdef REG_F3                          
+globalRegMaybe (FloatReg 3)            = Just (RealReg REG_F3)
+#endif                                 
+#ifdef REG_F4                          
+globalRegMaybe (FloatReg 4)            = Just (RealReg REG_F4)
+#endif                                 
+#ifdef REG_D1                          
+globalRegMaybe (DoubleReg 1)           = Just (RealReg REG_D1)
+#endif                                 
+#ifdef REG_D2                          
+globalRegMaybe (DoubleReg 2)           = Just (RealReg REG_D2)
+#endif
+#ifdef REG_Sp      
+globalRegMaybe Sp                      = Just (RealReg REG_Sp)
+#endif
+#ifdef REG_Lng1                                
+globalRegMaybe (LongReg 1)             = Just (RealReg REG_Lng1)
+#endif                                 
+#ifdef REG_Lng2                                
+globalRegMaybe (LongReg 2)             = Just (RealReg REG_Lng2)
+#endif
+#ifdef REG_SpLim                               
+globalRegMaybe SpLim                   = Just (RealReg REG_SpLim)
+#endif                                 
+#ifdef REG_Hp                          
+globalRegMaybe Hp                      = Just (RealReg REG_Hp)
+#endif                                 
+#ifdef REG_HpLim                       
+globalRegMaybe HpLim                   = Just (RealReg REG_HpLim)
+#endif                                 
+#ifdef REG_CurrentTSO                          
+globalRegMaybe CurrentTSO              = Just (RealReg REG_CurrentTSO)
+#endif                                 
+#ifdef REG_CurrentNursery                              
+globalRegMaybe CurrentNursery          = Just (RealReg REG_CurrentNursery)
+#endif                                 
+globalRegMaybe _                       = Nothing
+
+
 \end{code}
index a5c5d3e..48c1c79 100644 (file)
@@ -1,85 +1,25 @@
-#define COMMA ,
-
-#ifndef NCG_H
-#define NCG_H
-#if 0
- COMPILING_NCG is used to control the visibility of 
- relevant information from the GHC header files when
- compiling the native code generator modules.
-#endif
+/* -----------------------------------------------------------------------------
 
-#ifndef COMPILING_NCG
-#define COMPILING_NCG
-#endif
+   (c) The University of Glasgow, 1994-2004
 
-#if 0
-
-IMPORTANT!  If you put extra tabs/spaces in these macro definitions,
-you will screw up the layout where they are used in case expressions!
-
-(This is cpp-dependent, of course)
-
-** Convenience macros for writing the native-code generator **
-
-#endif
+   Native-code generator header file - just useful macros for now.
 
-#include "../includes/config.h"
-
-#if 0
-{-testing only-}
-#undef sparc_TARGET_ARCH
-#undef sunos4_TARGET_OS
-#undef i386_TARGET_ARCH
-#define i386_TARGET_ARCH 1
-#undef linuxaout_TARGET_OS
-#define linuxaout_TARGET_OS 1
-#endif
-#if 0
-{-testing only-}
-#undef sparc_TARGET_ARCH
-#undef sunos4_TARGET_OS
-#undef alpha_TARGET_ARCH
-#define alpha_TARGET_ARCH 1
-#endif
-
-#if i386_TARGET_ARCH
-# define STOLEN_X86_REGS 4
--- HACK: go for the max
-#endif
-
-#include "../includes/MachRegs.h"
-#include "../includes/NativeDefs.h"
-
-#if alpha_TARGET_ARCH
-# define BYTES_PER_WORD 8
-# define BYTES_PER_WORD_STR "8"
-#endif
+   -------------------------------------------------------------------------- */
 
-#if i386_TARGET_ARCH
-# define BYTES_PER_WORD 4
-# define BYTES_PER_WORD_STR "4"
-#endif
-
-#if sparc_TARGET_ARCH
-# define BYTES_PER_WORD 4
-# define BYTES_PER_WORD_STR "4"
-#endif
+#ifndef NCG_H
+#define NCG_H
 
-#if powerpc_TARGET_ARCH
-# define BYTES_PER_WORD 4
-# define BYTES_PER_WORD_STR "4"
-#endif
+#include "../includes/ghcconfig.h"
 
----------------------------------------------
+#define COMMA ,
 
+-- - - - - - - - - - - - - - - - - - - - - - 
 #if alpha_TARGET_ARCH
 # define IF_ARCH_alpha(x,y) x
 #else
 # define IF_ARCH_alpha(x,y) y
 #endif
-
----------------------------------------------
-
+-- - - - - - - - - - - - - - - - - - - - - - 
 #if i386_TARGET_ARCH
 # define IF_ARCH_i386(x,y) x
 #else
@@ -127,7 +67,7 @@ you will screw up the layout where they are used in case expressions!
 #else
 # define IF_OS_cygwin32(x,y) y
 #endif
----------------------------------------------
+-- - - - - - - - - - - - - - - - - - - - - - 
 #if sparc_TARGET_ARCH
 # define IF_ARCH_sparc(x,y) x
 #else
@@ -146,7 +86,7 @@ you will screw up the layout where they are used in case expressions!
 #else
 # define IF_OS_solaris2(x,y) y
 #endif
----------------------------------------------
+-- - - - - - - - - - - - - - - - - - - - - - 
 #if powerpc_TARGET_ARCH
 # define IF_ARCH_powerpc(x,y) x
 #else
diff --git a/ghc/compiler/nativeGen/NCGMonad.hs b/ghc/compiler/nativeGen/NCGMonad.hs
new file mode 100644 (file)
index 0000000..271828f
--- /dev/null
@@ -0,0 +1,98 @@
+-- -----------------------------------------------------------------------------
+--
+-- (c) The University of Glasgow 1993-2004
+-- 
+-- The native code generator's monad.
+--
+-- -----------------------------------------------------------------------------
+
+module NCGMonad (
+       NatM_State(..), mkNatM_State,
+
+       NatM, -- instance Monad
+       initNat, addImportNat, getUniqueNat,
+       mapAccumLNat, setDeltaNat, getDeltaNat,
+       getBlockIdNat, getNewLabelNat, getNewRegNat, getNewRegPairNat,
+ ) where
+  
+#include "HsVersions.h"
+
+import Cmm             ( BlockId(..) )
+import CLabel          ( CLabel, mkAsmTempLabel )
+import MachRegs
+import MachOp          ( MachRep )
+import UniqSupply
+import Unique          ( Unique )
+
+
+data NatM_State = NatM_State {
+                       natm_us      :: UniqSupply,
+                       natm_delta   :: Int,
+                       natm_imports :: [(Bool,CLabel)]
+               }
+
+newtype NatM result = NatM (NatM_State -> (result, NatM_State))
+
+unNat (NatM a) = a
+
+mkNatM_State :: UniqSupply -> Int -> NatM_State
+mkNatM_State us delta = NatM_State us delta []
+
+initNat :: NatM_State -> NatM a -> (a, NatM_State)
+initNat init_st m = case unNat m init_st of { (r,st) -> (r,st) }
+
+instance Monad NatM where
+  (>>=) = thenNat
+  return = returnNat
+
+thenNat :: NatM a -> (a -> NatM b) -> NatM b
+thenNat expr cont
+  = NatM $ \st -> case unNat expr st of
+                       (result, st') -> unNat (cont result) st'
+
+returnNat :: a -> NatM a
+returnNat result = NatM $ \st ->  (result, st)
+
+mapAccumLNat :: (acc -> x -> NatM (acc, y))
+                -> acc
+               -> [x]
+               -> NatM (acc, [y])
+
+mapAccumLNat f b []
+  = return (b, [])
+mapAccumLNat f b (x:xs)
+  = do (b__2, x__2)  <- f b x
+       (b__3, xs__2) <- mapAccumLNat f b__2 xs
+       return (b__3, x__2:xs__2)
+
+getUniqueNat :: NatM Unique
+getUniqueNat = NatM $ \ (NatM_State us delta imports) ->
+    case splitUniqSupply us of
+         (us1,us2) -> (uniqFromSupply us1, (NatM_State us2 delta imports))
+
+getDeltaNat :: NatM Int
+getDeltaNat = NatM $ \ st -> (natm_delta st, st)
+
+setDeltaNat :: Int -> NatM ()
+setDeltaNat delta = NatM $ \ (NatM_State us _ imports) ->
+   ((), NatM_State us delta imports)
+
+addImportNat :: Bool -> CLabel -> NatM ()
+addImportNat is_code imp = NatM $ \ (NatM_State us delta imports) -> 
+   ((), NatM_State us delta ((is_code,imp):imports))
+
+getBlockIdNat :: NatM BlockId
+getBlockIdNat = do u <- getUniqueNat; return (BlockId u)
+
+getNewLabelNat :: NatM CLabel
+getNewLabelNat = do u <- getUniqueNat; return (mkAsmTempLabel u)
+
+getNewRegNat :: MachRep -> NatM Reg
+getNewRegNat rep = do u <- getUniqueNat; return (mkVReg u rep)
+
+getNewRegPairNat :: MachRep -> NatM (Reg,Reg)
+getNewRegPairNat rep = do 
+  u <- getUniqueNat
+  let lo = mkVReg u rep; hi = getHiVRegFromLo lo
+  return (lo,hi)
+
index 437e220..9068a7f 100644 (file)
@@ -1,21 +1,41 @@
+TODO in new NCG
+~~~~~~~~~~~~~~~
 
-Known bugs/issues in nativeGen, 000228 (JRS)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+- Are we being careful enough about narrowing those out-of-range CmmInts?
 
--- absC -> stix translation for GET_TAG and in fact anything
-   to do with the packed-halfword layout info itbl field is
-   pretty dubious.  I think I have it fixed for big and little
-   endian 32-bit, but it won't work at all on a 64 bit platform.
+- Register allocator:
+    - fixup code
+    - keep track of free stack slots
 
--- There may or may not be bugs in some of the x86 insn selector 
-   code in MachCode.lhs.  I have checked all of it against the 
-   Rules of the Game (+ Rules of the game for Amodes) recorded in 
-   that file, but am not 100% convinced that it is all correct.
-   I think most of it is, tho.
+    Optimisations:
 
--- It won't compile on Solaris or Alphas because the insn selectors
-   are not up-to-date.
+    - picking the assignment on entry to a block: better to defer this
+      until we know all the assignments.  In a loop, we should pick
+      the assignment from the looping jump (fixpointing?), so that any
+      fixup code ends up *outside* the loop.  Otherwise, we should
+      pick the assignment that results in the least fixup code.
+
+- splitting?
+
+-- -----------------------------------------------------------------------------
+-- x86 ToDos
+
+- x86 genCCall needs to tack on the @size for stdcalls (might not be in the
+  foreignlabel).
+
+- x86: should really clean up that IMUL64 stuff, and tell the code gen about
+  Intel imul instructions.
+
+- x86: we're not careful enough about making sure that we only use
+  byte-addressable registers in byte instructions.  Should we do it this
+  way, or stick to using 32-bit registers everywhere?
+
+- Use SSE for floating point, optionally.
+
+------------------------------------------------------------------------------
+-- Further optimisations:
+
+- We might be able to extend the scope of the inlining phase so it can
+  skip over more statements that don't affect the value of the inlined
+  expr.
 
--- NCG introduces a massive space leak; I think it generates all the
-   assembly code before printing any of it out (a depressingly 
-   familiar story ...).  Fixing this will await a working heap profiler.
similarity index 77%
rename from ghc/compiler/nativeGen/PprMach.lhs
rename to ghc/compiler/nativeGen/PprMach.hs
index 0a6b136..64ee5c6 100644 (file)
-%
-% (c) The AQUA Project, Glasgow University, 1996-1998
-%
-\section[PprMach]{Pretty-printing assembly language}
+-----------------------------------------------------------------------------
+--
+-- Pretty-printing assembly language
+--
+        -- (c) The University of Glasgow 1993-2004
+        --
+-----------------------------------------------------------------------------
 
-We start with the @pprXXX@s with some cross-platform commonality
-(e.g., @pprReg@); we conclude with the no-commonality monster,
-@pprInstr@.
+-- We start with the @pprXXX@s with some cross-platform commonality
+-- (e.g., 'pprReg'); we conclude with the no-commonality monster,
+-- 'pprInstr'.
 
-\begin{code}
 #include "nativeGen/NCG.h"
 
-module PprMach ( pprInstr, pprSize, pprUserReg IF_OS_darwin(COMMA pprDyldSymbolStub, ) ) where
+module PprMach ( 
+       pprNatCmmTop, pprBasicBlock,
+       pprInstr, pprSize, pprUserReg,
+#if darwin_TARGET_OS
+       pprDyldSymbolStub,
+#endif
+  ) where
+
 
 #include "HsVersions.h"
 
+import Cmm
+import MachOp          ( MachRep(..) )
 import MachRegs                -- may differ per-platform
-import MachMisc
+import MachInstrs
+
+import CLabel          ( CLabel, pprCLabel, externallyVisibleCLabel,
+                         labelDynamic, mkAsmTempLabel, entryLblToInfoLbl )
 
-import CLabel          ( pprCLabel, externallyVisibleCLabel, labelDynamic )
-import Stix            ( CodeSegment(..) )
 import Panic           ( panic )
+import Unique          ( pprUnique )
 import Pretty
 import FastString
 import qualified Outputable
 
 #if __GLASGOW_HASKELL__ >= 504
 import Data.Array.ST
-import Data.Word       ( Word8, Word16 )
+import Data.Word       ( Word8 )
 #else
 import MutableArray
-import Word             ( Word16 )
 #endif
 
 import MONAD_ST
-
 import Char            ( chr, ord )
-import Maybe           ( isJust )
+
+#if powerpc_TARGET_ARCH
+import DATA_WORD(Word32)
+import DATA_BITS
+#endif
+
+-- -----------------------------------------------------------------------------
+-- Printing this stuff out
 
 asmSDoc d = Outputable.withPprStyleDoc (
              Outputable.mkCodeStyle Outputable.AsmStyle) d
 pprCLabel_asm l = asmSDoc (pprCLabel l)
-\end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection{@pprReg@: print a @Reg@}
-%*                                                                     *
-%************************************************************************
+pprNatCmmTop :: NatCmmTop -> Doc
+pprNatCmmTop (CmmData section dats) = 
+  pprSectionHeader section $$ vcat (map pprData dats)
+
+ -- special case for split markers:
+pprNatCmmTop (CmmProc [] lbl _ []) = pprLabel lbl
+
+pprNatCmmTop (CmmProc info lbl params blocks) = 
+  pprSectionHeader Text $$
+  (if not (null info)
+       then vcat (map pprData info) 
+               $$ pprLabel (entryLblToInfoLbl lbl)
+       else empty) $$
+  (case blocks of
+       [] -> empty
+       (BasicBlock _ instrs : rest) -> 
+               (if null info then pprLabel lbl else empty) $$
+               -- the first block doesn't get a label:
+               vcat (map pprInstr instrs) $$
+               vcat (map pprBasicBlock rest))
+
+
+pprBasicBlock :: NatBasicBlock -> Doc
+pprBasicBlock (BasicBlock (BlockId id) instrs) =
+  pprLabel (mkAsmTempLabel id) $$
+  vcat (map pprInstr instrs)
+
+-- -----------------------------------------------------------------------------
+-- pprReg: print a 'Reg'
+
+-- For x86, the way we print a register name depends
+-- on which bit of it we care about.  Yurgh.
 
-For x86, the way we print a register name depends
-on which bit of it we care about.  Yurgh.
-\begin{code}
 pprUserReg :: Reg -> Doc
-pprUserReg = pprReg IF_ARCH_i386(L,)
+pprUserReg = pprReg IF_ARCH_i386(I32,)
 
-pprReg :: IF_ARCH_i386(Size ->,) Reg -> Doc
+pprReg :: IF_ARCH_i386(MachRep ->,) Reg -> Doc
 
 pprReg IF_ARCH_i386(s,) r
   = case r of
       RealReg i      -> ppr_reg_no IF_ARCH_i386(s,) i
-      VirtualRegI u  -> text "%vI_" <> asmSDoc (pprVRegUnique u)
-      VirtualRegF u  -> text "%vF_" <> asmSDoc (pprVRegUnique u)
+      VirtualRegI  u  -> text "%vI_" <> asmSDoc (pprUnique u)
+      VirtualRegHi u  -> text "%vHi_" <> asmSDoc (pprUnique u)
+      VirtualRegF  u  -> text "%vF_" <> asmSDoc (pprUnique u)
+      VirtualRegD  u  -> text "%vD_" <> asmSDoc (pprUnique u)
   where
 #if alpha_TARGET_ARCH
     ppr_reg_no :: Int -> Doc
@@ -102,12 +145,10 @@ pprReg IF_ARCH_i386(s,) r
       })
 #endif
 #if i386_TARGET_ARCH
-    ppr_reg_no :: Size -> Int -> Doc
-    ppr_reg_no B  = ppr_reg_byte
-    ppr_reg_no Bu = ppr_reg_byte
-    ppr_reg_no W  = ppr_reg_word
-    ppr_reg_no Wu = ppr_reg_word
-    ppr_reg_no _  = ppr_reg_long
+    ppr_reg_no :: MachRep -> Int -> Doc
+    ppr_reg_no I8   = ppr_reg_byte
+    ppr_reg_no I16  = ppr_reg_word
+    ppr_reg_no _    = ppr_reg_long
 
     ppr_reg_byte i = ptext
       (case i of {
@@ -222,16 +263,16 @@ pprReg IF_ARCH_i386(s,) r
                 | otherwise = ptext SLIT("very naughty powerpc register")
 #endif
 #endif
-\end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection{@pprSize@: print a @Size@}
-%*                                                                     *
-%************************************************************************
 
-\begin{code}
+-- -----------------------------------------------------------------------------
+-- pprSize: print a 'Size'
+
+#if powerpc_TARGET_ARCH || i386_TARGET_ARCH
+pprSize :: MachRep -> Doc
+#else
 pprSize :: Size -> Doc
+#endif
 
 pprSize x = ptext (case x of
 #if alpha_TARGET_ARCH
@@ -248,15 +289,12 @@ pprSize x = ptext (case x of
         TF -> SLIT("t")
 #endif
 #if i386_TARGET_ARCH
-       B   -> SLIT("b")
-       Bu  -> SLIT("b")
-       W   -> SLIT("w")
-       Wu  -> SLIT("w")
-       L   -> SLIT("l")
-       Lu  -> SLIT("l")
-       F   -> SLIT("s")
-       DF  -> SLIT("l")
-       F80 -> SLIT("t")
+       I8   -> SLIT("b")
+       I16  -> SLIT("w")
+       I32  -> SLIT("l")
+       F32  -> SLIT("s")
+       F64  -> SLIT("l")
+       F80  -> SLIT("t")
 #endif
 #if sparc_TARGET_ARCH
        B   -> SLIT("sb")
@@ -278,24 +316,17 @@ pprStSize x = ptext (case x of
        DF  -> SLIT("d")
 #endif
 #if powerpc_TARGET_ARCH
-       B   -> SLIT("b")
-       Bu  -> SLIT("b")
-        H   -> SLIT("h")
-        Hu  -> SLIT("h")
-       W   -> SLIT("w")
-       F   -> SLIT("fs")
-       DF  -> SLIT("fd")
+       I8   -> SLIT("b")
+        I16  -> SLIT("h")
+       I32  -> SLIT("w")
+       F32  -> SLIT("fs")
+       F64  -> SLIT("fd")
 #endif
     )
-\end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection{@pprCond@: print a @Cond@}
-%*                                                                     *
-%************************************************************************
+-- -----------------------------------------------------------------------------
+-- pprCond: print a 'Cond'
 
-\begin{code}
 pprCond :: Cond -> Doc
 
 pprCond c = ptext (case c of {
@@ -338,15 +369,11 @@ pprCond c = ptext (case c of {
        GU      -> SLIT("gt");  LEU   -> SLIT("le");
 #endif
     })
-\end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection{@pprImm@: print an @Imm@}
-%*                                                                     *
-%************************************************************************
 
-\begin{code}
+-- -----------------------------------------------------------------------------
+-- pprImm: print an 'Imm'
+
 pprImm :: Imm -> Doc
 
 pprImm (ImmInt i)     = int i
@@ -357,9 +384,8 @@ pprImm (ImmIndex l i) = (if labelDynamic l then text "__imp_" else empty)
                         <> pprCLabel_asm l <> char '+' <> int i
 pprImm (ImmLit s)     = s
 
-pprImm (ImmLab dll s) = (if underscorePrefix then char '_' else empty)
-                        <> (if dll then text "_imp__" else empty)
-                        <> s
+pprImm (ImmFloat _) = panic "pprImm:ImmFloat"
+pprImm (ImmDouble _) = panic "pprImm:ImmDouble"
 
 #if sparc_TARGET_ARCH
 pprImm (LO i)
@@ -388,6 +414,10 @@ pprImm (HA i)
   = hcat [ pp_ha, pprImm i, rparen ]
   where
     pp_ha = text "ha16("
+    
+pprImm (ImmDyldNonLazyPtr lbl)
+  = ptext SLIT("L") <> pprCLabel_asm lbl <> ptext SLIT("$non_lazy_ptr")
+  
 #else
 pprImm (LO i)
   = pprImm i <> text "@l"
@@ -399,16 +429,12 @@ pprImm (HA i)
   = pprImm i <> text "@ha"
 #endif
 #endif
-\end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection{@pprAddr@: print an @Addr@}
-%*                                                                     *
-%************************************************************************
 
-\begin{code}
-pprAddr :: MachRegsAddr -> Doc
+-- -----------------------------------------------------------------------------
+-- @pprAddr: print an 'AddrMode'
+
+pprAddr :: AddrMode -> Doc
 
 #if alpha_TARGET_ARCH
 pprAddr (AddrReg r) = parens (pprReg r)
@@ -434,12 +460,12 @@ pprAddr (AddrBaseIndex base index displacement)
   = let
        pp_disp  = ppr_disp displacement
        pp_off p = pp_disp <> char '(' <> p <> char ')'
-       pp_reg r = pprReg L r
+       pp_reg r = pprReg I32 r
     in
     case (base,index) of
       (Nothing, Nothing)    -> pp_disp
       (Just b,  Nothing)    -> pp_off (pp_reg b)
-      (Nothing, Just (r,i)) -> pp_off (pp_reg r <> comma <> int i)
+      (Nothing, Just (r,i)) -> pp_off (comma <> pp_reg r <> comma <> int i)
       (Just b,  Just (r,i)) -> pp_off (pp_reg b <> comma <> pp_reg r 
                                        <> comma <> int i)
   where
@@ -465,8 +491,6 @@ pprAddr (AddrRegImm r1 (ImmInt i))
 pprAddr (AddrRegImm r1 (ImmInteger i))
   | i == 0 = pprReg r1
   | not (fits13Bits i) = largeOffsetError i
--------------------
-
   | otherwise  = hcat [ pprReg r1, pp_sign, integer i ]
   where
     pp_sign = if i > 0 then char '+' else empty
@@ -474,52 +498,37 @@ pprAddr (AddrRegImm r1 (ImmInteger i))
 pprAddr (AddrRegImm r1 imm)
   = hcat [ pprReg r1, char '+', pprImm imm ]
 #endif
+
+-------------------
+
 #if powerpc_TARGET_ARCH
 pprAddr (AddrRegReg r1 r2)
-  = error "PprMach.pprAddr (AddrRegReg) unimplemented"
+  = pprReg r1 <+> ptext SLIT(", ") <+> pprReg r2
 
 pprAddr (AddrRegImm r1 (ImmInt i)) = hcat [ int i, char '(', pprReg r1, char ')' ]
 pprAddr (AddrRegImm r1 (ImmInteger i)) = hcat [ integer i, char '(', pprReg r1, char ')' ]
 pprAddr (AddrRegImm r1 imm) = hcat [ pprImm imm, char '(', pprReg r1, char ')' ]
 #endif
-\end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection{@pprInstr@: print an @Instr@}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-pprInstr :: Instr -> Doc
-
---pprInstr (COMMENT s) = empty -- nuke 'em
-pprInstr (COMMENT s)
-   =  IF_ARCH_alpha( ((<>) (ptext SLIT("\t# ")) (ftext s))
-     ,IF_ARCH_sparc( ((<>) (ptext SLIT("! "))   (ftext s))
-     ,IF_ARCH_i386( ((<>) (ptext SLIT("# "))   (ftext s))
-     ,IF_ARCH_powerpc( ((<>) (ptext SLIT("; ")) (ftext s))
-     ,))))
-
-pprInstr (DELTA d)
-   = pprInstr (COMMENT (mkFastString ("\tdelta = " ++ show d)))
 
-pprInstr (SEGMENT TextSegment)
-    =  IF_ARCH_alpha(ptext SLIT("\t.text\n\t.align 3") {-word boundary-}
-      ,IF_ARCH_sparc(ptext SLIT(".text\n\t.align 4") {-word boundary-}
-      ,IF_ARCH_i386((text ".text\n\t.align 4,0x90") {-needs per-OS variation!-}
-      ,IF_ARCH_powerpc(ptext SLIT(".text\n.align 2")
-      ,))))
+-- -----------------------------------------------------------------------------
+-- pprData: print a 'CmmStatic'
 
-pprInstr (SEGMENT DataSegment)
+pprSectionHeader Text
+    = ptext
+       IF_ARCH_alpha(SLIT("\t.text\n\t.align 3") {-word boundary-}
+       ,IF_ARCH_sparc(SLIT(".text\n\t.align 4") {-word boundary-}
+       ,IF_ARCH_i386(SLIT(".text\n\t.align 4,0x90") {-needs per-OS variation!-}
+       ,IF_ARCH_powerpc(SLIT(".text\n.align 2")
+       ,))))
+pprSectionHeader Data
     = ptext
         IF_ARCH_alpha(SLIT("\t.data\n\t.align 3")
        ,IF_ARCH_sparc(SLIT(".data\n\t.align 8") {-<8 will break double constants -}
        ,IF_ARCH_i386(SLIT(".data\n\t.align 4")
         ,IF_ARCH_powerpc(SLIT(".data\n.align 2")
        ,))))
-
-pprInstr (SEGMENT RoDataSegment)
+pprSectionHeader ReadOnlyData
     = ptext
         IF_ARCH_alpha(SLIT("\t.data\n\t.align 3")
        ,IF_ARCH_sparc(SLIT(".data\n\t.align 8") {-<8 will break double constants -}
@@ -527,30 +536,40 @@ pprInstr (SEGMENT RoDataSegment)
         ,IF_ARCH_powerpc(IF_OS_darwin(SLIT(".const_data\n.align 2"),
                                       SLIT(".section .rodata\n\t.align 2"))
        ,))))
-
-pprInstr (LABEL clab)
-  = let
-       pp_lab = pprCLabel_asm clab
-    in
-    hcat [
-       if not (externallyVisibleCLabel clab) then
-           empty
-       else
-           hcat [ptext
-                        IF_ARCH_alpha(SLIT("\t.globl\t")
+pprSectionHeader UninitialisedData
+    = ptext
+        IF_ARCH_alpha(SLIT("\t.bss\n\t.align 3")
+       ,IF_ARCH_sparc(SLIT(".bss\n\t.align 8") {-<8 will break double constants -}
+       ,IF_ARCH_i386(SLIT(".section .bss\n\t.align 4")
+        ,IF_ARCH_powerpc(IF_OS_darwin(SLIT(".const_data\n.align 2"),
+                                      SLIT(".section .bss\n\t.align 2"))
+       ,))))
+pprSectionHeader (OtherSection sec)
+    = panic "PprMach.pprSectionHeader: unknown section"
+
+pprData :: CmmStatic -> Doc
+pprData (CmmAlign bytes)         = pprAlign bytes
+pprData (CmmDataLabel lbl)       = pprLabel lbl
+pprData (CmmString str)          = pprASCII str
+pprData (CmmUninitialised bytes) = ptext SLIT(".space ") <> int bytes
+pprData (CmmStaticLit lit)       = pprDataItem lit
+
+pprGloblDecl :: CLabel -> Doc
+pprGloblDecl lbl
+  | not (externallyVisibleCLabel lbl) = empty
+  | otherwise = ptext IF_ARCH_alpha(SLIT(".globl ")
                        ,IF_ARCH_i386(SLIT(".globl ")
-                       ,IF_ARCH_sparc(SLIT(".global\t")
+                       ,IF_ARCH_sparc(SLIT(".global ")
                        ,IF_ARCH_powerpc(SLIT(".globl ")
-                       ,))))
-                       , pp_lab, char '\n'],
-       pp_lab,
-       char ':'
-    ]
+                       ,)))) <>
+               pprCLabel_asm lbl
 
-pprInstr (ASCII False{-no backslash conversion-} str)
-  = hcat [ ptext SLIT("\t.asciz "), char '\"', text str, char '"' ]
+pprLabel :: CLabel -> Doc
+pprLabel lbl = pprGloblDecl lbl $$ (pprCLabel_asm lbl <> char ':')
 
-pprInstr (ASCII True str)
+
+-- Assume we want to backslash-convert the string
+pprASCII str
   = vcat (map do1 (str ++ [chr 0]))
     where
        do1 :: Char -> Doc
@@ -561,59 +580,84 @@ pprInstr (ASCII True str)
                = char (tab !! (n `div` 16)) <> char (tab !! (n `mod` 16))
        tab = "0123456789ABCDEF"
 
+pprAlign bytes =
+       IF_ARCH_alpha(ptextSLIT(".align ") <> int pow2,
+       IF_ARCH_i386(ptext SLIT(".align ") <> int bytes,
+       IF_ARCH_sparc(ptext SLIT(".align ") <> int bytes,
+       IF_ARCH_powerpc(ptext SLIT(".align ") <> int pow2,))))
+  where
+       pow2 = log2 bytes
+       
+       log2 :: Int -> Int  -- cache the common ones
+       log2 1 = 0 
+       log2 2 = 1
+       log2 4 = 2
+       log2 8 = 3
+       log2 n = 1 + log2 (n `quot` 2)
 
-pprInstr (DATA s xs)
-  = vcat (concatMap (ppr_item s) xs)
+
+pprDataItem :: CmmLit -> Doc
+pprDataItem lit
+  = vcat (ppr_item (cmmLitRep lit) lit)
     where
+       imm = litToImm lit
 
-#if alpha_TARGET_ARCH
-            ppr_item = error "ppr_item on Alpha"
-#endif
-#if sparc_TARGET_ARCH
-        -- copy n paste of x86 version
-       ppr_item B  x = [ptext SLIT("\t.byte\t") <> pprImm x]
-       ppr_item W  x = [ptext SLIT("\t.long\t") <> pprImm x]
-       ppr_item F  (ImmFloat r)
+       -- These seem to be common:
+       ppr_item I8   x = [ptext SLIT("\t.byte\t") <> pprImm imm]
+       ppr_item I32  x = [ptext SLIT("\t.long\t") <> pprImm imm]
+       ppr_item F32  (CmmFloat r _)
            = let bs = floatToBytes (fromRational r)
              in  map (\b -> ptext SLIT("\t.byte\t") <> pprImm (ImmInt b)) bs
-       ppr_item DF (ImmDouble r)
+       ppr_item F64 (CmmFloat r _)
            = let bs = doubleToBytes (fromRational r)
              in  map (\b -> ptext SLIT("\t.byte\t") <> pprImm (ImmInt b)) bs
+
+#if sparc_TARGET_ARCH
+        -- copy n paste of x86 version
+       ppr_item I16  x = [ptext SLIT("\t.short\t") <> pprImm imm]
+       ppr_item I64  x = [ptext SLIT("\t.quad\t") <> pprImm imm]
 #endif
 #if i386_TARGET_ARCH
-       ppr_item B  x = [ptext SLIT("\t.byte\t") <> pprImm x]
-       ppr_item L  x = [ptext SLIT("\t.long\t") <> pprImm x]
-       ppr_item F  (ImmFloat r)
-           = let bs = floatToBytes (fromRational r)
-             in  map (\b -> ptext SLIT("\t.byte\t") <> pprImm (ImmInt b)) bs
-       ppr_item DF (ImmDouble r)
-           = let bs = doubleToBytes (fromRational r)
-             in  map (\b -> ptext SLIT("\t.byte\t") <> pprImm (ImmInt b)) bs
+       ppr_item I16  x = [ptext SLIT("\t.word\t") <> pprImm imm]
+       ppr_item I64  x = [ptext SLIT("\t.quad\t") <> pprImm imm]
 #endif
 #if powerpc_TARGET_ARCH
-       ppr_item B  x = [ptext SLIT("\t.byte\t") <> pprImm x]
-       ppr_item Bu  x = [ptext SLIT("\t.byte\t") <> pprImm x]
-       ppr_item H  x = [ptext SLIT("\t.short\t") <> pprImm x]
-       ppr_item Hu  x = [ptext SLIT("\t.short\t") <> pprImm x]
-       ppr_item W  x = [ptext SLIT("\t.long\t") <> pprImm x]
-       ppr_item F  (ImmFloat r)
-           = let bs = floatToBytes (fromRational r)
-             in  map (\b -> ptext SLIT("\t.byte\t") <> pprImm (ImmInt b)) bs
-       ppr_item DF (ImmDouble r)
-           = let bs = doubleToBytes (fromRational r)
-             in  map (\b -> ptext SLIT("\t.byte\t") <> pprImm (ImmInt b)) bs
+       ppr_item I16 x = [ptext SLIT("\t.short\t") <> pprImm imm]
+        ppr_item I64 (CmmInt x _)  =
+                [ptext SLIT("\t.long\t")
+                    <> int (fromIntegral 
+                        (fromIntegral (x `shiftR` 32) :: Word32)),
+                 ptext SLIT("\t.long\t")
+                    <> int (fromIntegral (fromIntegral x :: Word32))]
 #endif
 
 -- fall through to rest of (machine-specific) pprInstr...
-\end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsubsection{@pprInstr@ for an Alpha}
-%*                                                                     *
-%************************************************************************
+-- -----------------------------------------------------------------------------
+-- pprInstr: print an 'Instr'
+
+pprInstr :: Instr -> Doc
+
+--pprInstr (COMMENT s) = empty -- nuke 'em
+pprInstr (COMMENT s)
+   =  IF_ARCH_alpha( ((<>) (ptext SLIT("\t# ")) (ftext s))
+     ,IF_ARCH_sparc( ((<>) (ptext SLIT("! "))   (ftext s))
+     ,IF_ARCH_i386( ((<>) (ptext SLIT("# "))   (ftext s))
+     ,IF_ARCH_powerpc( ((<>) (ptext SLIT("; ")) (ftext s))
+     ,))))
+
+pprInstr (DELTA d)
+   = pprInstr (COMMENT (mkFastString ("\tdelta = " ++ show d)))
+
+pprInstr (NEWBLOCK _)
+   = panic "PprMach.pprInstr: NEWBLOCK"
+
+pprInstr (LDATA _ _)
+   = panic "PprMach.pprInstr: LDATA"
+
+-- -----------------------------------------------------------------------------
+-- pprInstr for an Alpha
 
-\begin{code}
 #if alpha_TARGET_ARCH
 
 pprInstr (LD size reg addr)
@@ -991,15 +1035,11 @@ pprSizeRegRegReg name size reg1 reg2 reg3
     ]
 
 #endif /* alpha_TARGET_ARCH */
-\end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsubsection{@pprInstr@ for an I386}
-%*                                                                     *
-%************************************************************************
 
-\begin{code}
+-- -----------------------------------------------------------------------------
+-- pprInstr for an x86
+
 #if i386_TARGET_ARCH
 
 pprInstr v@(MOV size s@(OpReg src) d@(OpReg dst)) -- hack
@@ -1012,8 +1052,8 @@ pprInstr v@(MOV size s@(OpReg src) d@(OpReg dst)) -- hack
 #endif
 pprInstr (MOV size src dst)
   = pprSizeOpOp SLIT("mov") size src dst
-pprInstr (MOVZxL sizes src dst) = pprSizeOpOpCoerce SLIT("movz") sizes L src dst
-pprInstr (MOVSxL sizes src dst) = pprSizeOpOpCoerce SLIT("movs") sizes L src dst
+pprInstr (MOVZxL sizes src dst) = pprSizeOpOpCoerce SLIT("movz") sizes I32 src dst
+pprInstr (MOVSxL sizes src dst) = pprSizeOpOpCoerce SLIT("movs") sizes I32 src dst
 
 -- here we do some patching, since the physical registers are only set late
 -- in the code generation.
@@ -1034,6 +1074,8 @@ pprInstr (ADD size (OpImm (ImmInt 1)) dst)
   = pprSizeOp SLIT("inc") size dst
 pprInstr (ADD size src dst)
   = pprSizeOpOp SLIT("add") size src dst
+pprInstr (ADC size src dst)
+  = pprSizeOpOp SLIT("adc") size src dst
 pprInstr (SUB size src dst) = pprSizeOpOp SLIT("sub") size src dst
 pprInstr (IMUL size op1 op2) = pprSizeOpOp SLIT("imul") size op1 op2
 
@@ -1052,36 +1094,38 @@ pprInstr (XOR size src dst) = pprSizeOpOp SLIT("xor")  size src dst
 pprInstr (NOT size op) = pprSizeOp SLIT("not") size op
 pprInstr (NEGI size op) = pprSizeOp SLIT("neg") size op
 
-pprInstr (SHL size imm dst) = pprSizeImmOp SLIT("shl") size imm dst
-pprInstr (SAR size imm dst) = pprSizeImmOp SLIT("sar") size imm dst
-pprInstr (SHR size imm dst) = pprSizeImmOp SLIT("shr") size imm dst
-pprInstr (BT  size imm src) = pprSizeImmOp SLIT("bt")  size imm src
+pprInstr (SHL size src dst) = pprShift SLIT("shl") size src dst
+pprInstr (SAR size src dst) = pprShift SLIT("sar") size src dst
+pprInstr (SHR size src dst) = pprShift SLIT("shr") size src dst
+
+pprInstr (BT  size imm src) = pprSizeImmOp SLIT("bt") size imm src
 
 pprInstr (CMP size src dst) = pprSizeOpOp SLIT("cmp")  size src dst
 pprInstr (TEST size src dst) = pprSizeOpOp SLIT("test")  size src dst
 pprInstr (PUSH size op) = pprSizeOp SLIT("push") size op
 pprInstr (POP size op) = pprSizeOp SLIT("pop") size op
-pprInstr PUSHA = ptext SLIT("\tpushal")
-pprInstr POPA = ptext SLIT("\tpopal")
+
+-- both unused (SDM):
+-- pprInstr PUSHA = ptext SLIT("\tpushal")
+-- pprInstr POPA = ptext SLIT("\tpopal")
 
 pprInstr NOP = ptext SLIT("\tnop")
 pprInstr CLTD = ptext SLIT("\tcltd")
 
-pprInstr (SETCC cond op) = pprCondInstr SLIT("set") cond (pprOperand B op)
+pprInstr (SETCC cond op) = pprCondInstr SLIT("set") cond (pprOperand I8 op)
 
-pprInstr (JXX cond lab) = pprCondInstr SLIT("j") cond (pprCLabel_asm lab)
+pprInstr (JXX cond (BlockId id)) 
+  = pprCondInstr SLIT("j") cond (pprCLabel_asm lab)
+  where lab = mkAsmTempLabel id
 
-pprInstr (JMP dsts (OpImm imm)) = (<>) (ptext SLIT("\tjmp ")) (pprImm imm)
-pprInstr (JMP dsts op)          = (<>) (ptext SLIT("\tjmp *")) (pprOperand L op)
+pprInstr (JMP (OpImm imm)) = (<>) (ptext SLIT("\tjmp ")) (pprImm imm)
+pprInstr (JMP op)          = (<>) (ptext SLIT("\tjmp *")) (pprOperand I32 op)
+pprInstr (JMP_TBL op ids)  = pprInstr (JMP op)
 pprInstr (CALL (Left imm))      = (<>) (ptext SLIT("\tcall ")) (pprImm imm)
-pprInstr (CALL (Right reg))     = (<>) (ptext SLIT("\tcall *")) (pprReg L reg)
-
--- First bool indicates signedness; second whether quot or rem
-pprInstr (IQUOT sz src dst) = pprInstr_quotRem True True sz src dst
-pprInstr (IREM  sz src dst) = pprInstr_quotRem True False sz src dst
+pprInstr (CALL (Right reg))     = (<>) (ptext SLIT("\tcall *")) (pprReg I32 reg)
 
-pprInstr (QUOT sz src dst) = pprInstr_quotRem False True sz src dst
-pprInstr (REM  sz src dst) = pprInstr_quotRem False False sz src dst
+pprInstr (IDIV sz op)  = pprSizeOp SLIT("idiv") sz op
+pprInstr (DIV sz op)    = pprSizeOp SLIT("div")  sz op
 
 pprInstr (IMUL64 sd_hi sd_lo) = pprInstr_imul64 sd_hi sd_lo
 
@@ -1115,12 +1159,12 @@ pprInstr g@(GFTOI src dst)
 pprInstr g@(GDTOI src dst) 
    = pprG g (hcat [gtab, text "subl $4, %esp ; ", 
                    gpush src 0, gsemi, text "fistpl 0(%esp) ; popl ", 
-                   pprReg L dst])
+                   pprReg I32 dst])
 
 pprInstr g@(GITOF src dst) 
    = pprInstr (GITOD src dst)
 pprInstr g@(GITOD src dst) 
-   = pprG g (hcat [gtab, text "pushl ", pprReg L src, 
+   = pprG g (hcat [gtab, text "pushl ", pprReg I32 src, 
                    text " ; ffree %st(7); fildl (%esp) ; ",
                    gpop dst 1, text " ; addl $4,%esp"])
 
@@ -1283,33 +1327,11 @@ pprInstr GFREE
           ]
 
 
-pprInstr_quotRem signed isQuot sz src dst
-   | case sz of L -> False; _ -> True
-   = panic "pprInstr_quotRem: dunno how to do non-32bit operands"
-   | otherwise
-   = vcat [
-     (text "\t# BEGIN " <> fakeInsn),
-     (text "\tpushl $0;  pushl %eax;  pushl %edx;  pushl " <> pprOperand sz src),
-     (text "\tmovl " <> pprOperand sz dst <> text ",%eax;  " <> widen_to_64),
-     (x86op <> text " 0(%esp);  movl " <> text resReg <> text ",12(%esp)"),
-     (text "\tpopl %edx;  popl %edx;  popl %eax;  popl " <> pprOperand sz dst),
-     (text "\t# END   " <> fakeInsn)
-     ]
-     where
-        widen_to_64 | signed     = text "cltd"
-                    | not signed = text "xorl %edx,%edx"
-        x86op = if signed then text "\tidivl" else text "\tdivl"
-        resReg = if isQuot then "%eax" else "%edx"
-        opStr  | signed     = if isQuot then "IQUOT" else "IREM"
-               | not signed = if isQuot then "QUOT"  else "REM"
-        fakeInsn = text opStr <+> pprOperand sz src 
-                              <> char ',' <+> pprOperand sz dst
-
 -- Emit code to make hi_reg:lo_reg be the 64-bit product of hi_reg and lo_reg
 pprInstr_imul64 hi_reg lo_reg
    = let fakeInsn = text "imul64" <+> pp_hi_reg <> comma <+> pp_lo_reg
-         pp_hi_reg = pprReg L hi_reg
-         pp_lo_reg = pprReg L lo_reg
+         pp_hi_reg = pprReg I32 hi_reg
+         pp_lo_reg = pprReg I32 lo_reg
      in     
          vcat [
             text "\t# BEGIN " <> fakeInsn,
@@ -1326,15 +1348,14 @@ pprInstr_imul64 hi_reg lo_reg
 --------------------------
 
 -- coerce %st(0) to the specified size
-gcoerceto DF = empty
-gcoerceto  F = empty --text "subl $4,%esp ; fstps (%esp) ; flds (%esp) ; addl $4,%esp ; "
+gcoerceto F64 = empty
+gcoerceto F32 = empty --text "subl $4,%esp ; fstps (%esp) ; flds (%esp) ; addl $4,%esp ; "
 
 gpush reg offset
    = hcat [text "ffree %st(7) ; fld ", greg reg offset]
 gpop reg offset
    = hcat [text "fstp ", greg reg offset]
 
-bogus = text "\tbogus"
 greg reg offset = text "%st(" <> int (gregno reg - 8+offset) <> char ')'
 gsemi = text " ; "
 gtab  = char '\t'
@@ -1348,20 +1369,20 @@ pprG :: Instr -> Doc -> Doc
 pprG fake actual
    = (char '#' <> pprGInstr fake) $$ actual
 
-pprGInstr (GMOV src dst)   = pprSizeRegReg SLIT("gmov") DF src dst
+pprGInstr (GMOV src dst)   = pprSizeRegReg SLIT("gmov") F64 src dst
 pprGInstr (GLD sz src dst) = pprSizeAddrReg SLIT("gld") sz src dst
 pprGInstr (GST sz src dst) = pprSizeRegAddr SLIT("gst") sz src dst
 
-pprGInstr (GLDZ dst) = pprSizeReg SLIT("gldz") DF dst
-pprGInstr (GLD1 dst) = pprSizeReg SLIT("gld1") DF dst
+pprGInstr (GLDZ dst) = pprSizeReg SLIT("gldz") F64 dst
+pprGInstr (GLD1 dst) = pprSizeReg SLIT("gld1") F64 dst
 
-pprGInstr (GFTOI src dst) = pprSizeSizeRegReg SLIT("gftoi") F L  src dst
-pprGInstr (GDTOI src dst) = pprSizeSizeRegReg SLIT("gdtoi") DF L src dst
+pprGInstr (GFTOI src dst) = pprSizeSizeRegReg SLIT("gftoi") F32 I32  src dst
+pprGInstr (GDTOI src dst) = pprSizeSizeRegReg SLIT("gdtoi") F64 I32 src dst
 
-pprGInstr (GITOF src dst) = pprSizeSizeRegReg SLIT("gitof") L F  src dst
-pprGInstr (GITOD src dst) = pprSizeSizeRegReg SLIT("gitod") L DF src dst
+pprGInstr (GITOF src dst) = pprSizeSizeRegReg SLIT("gitof") I32 F32  src dst
+pprGInstr (GITOD src dst) = pprSizeSizeRegReg SLIT("gitod") I32 F64 src dst
 
-pprGInstr (GCMP co src dst) = pprCondRegReg SLIT("gcmp_") DF co src dst
+pprGInstr (GCMP co src dst) = pprCondRegReg SLIT("gcmp_") F64 co src dst
 pprGInstr (GABS sz src dst) = pprSizeRegReg SLIT("gabs") sz src dst
 pprGInstr (GNEG sz src dst) = pprSizeRegReg SLIT("gneg") sz src dst
 pprGInstr (GSQRT sz src dst) = pprSizeRegReg SLIT("gsqrt") sz src dst
@@ -1373,101 +1394,65 @@ pprGInstr (GADD sz src1 src2 dst) = pprSizeRegRegReg SLIT("gadd") sz src1 src2 d
 pprGInstr (GSUB sz src1 src2 dst) = pprSizeRegRegReg SLIT("gsub") sz src1 src2 dst
 pprGInstr (GMUL sz src1 src2 dst) = pprSizeRegRegReg SLIT("gmul") sz src1 src2 dst
 pprGInstr (GDIV sz src1 src2 dst) = pprSizeRegRegReg SLIT("gdiv") sz src1 src2 dst
-\end{code}
 
-Continue with I386-only printing bits and bobs:
-\begin{code}
+-- Continue with I386-only printing bits and bobs:
+
 pprDollImm :: Imm -> Doc
 
 pprDollImm i =  ptext SLIT("$") <> pprImm i
 
-pprOperand :: Size -> Operand -> Doc
+pprOperand :: MachRep -> Operand -> Doc
 pprOperand s (OpReg r)   = pprReg s r
 pprOperand s (OpImm i)   = pprDollImm i
 pprOperand s (OpAddr ea) = pprAddr ea
 
-pprSizeImmOp :: LitString -> Size -> Imm -> Operand -> Doc
+pprMnemonic  :: LitString -> MachRep -> Doc
+pprMnemonic name size = 
+   char '\t' <> ptext name <> pprSize size <> space
+
+pprSizeImmOp :: LitString -> MachRep -> Imm -> Operand -> Doc
 pprSizeImmOp name size imm op1
   = hcat [
-        char '\t',
-       ptext name,
-       pprSize size,
-       space,
+       pprMnemonic name size,
        char '$',
        pprImm imm,
        comma,
        pprOperand size op1
     ]
        
-pprSizeOp :: LitString -> Size -> Operand -> Doc
+pprSizeOp :: LitString -> MachRep -> Operand -> Doc
 pprSizeOp name size op1
   = hcat [
-       char '\t',
-       ptext name,
-       pprSize size,
-       space,
+       pprMnemonic name size,
        pprOperand size op1
     ]
 
-pprSizeOpOp :: LitString -> Size -> Operand -> Operand -> Doc
+pprSizeOpOp :: LitString -> MachRep -> Operand -> Operand -> Doc
 pprSizeOpOp name size op1 op2
   = hcat [
-       char '\t',
-       ptext name,
-       pprSize size,
-       space,
+       pprMnemonic name size,
        pprOperand size op1,
        comma,
        pprOperand size op2
     ]
 
-pprSizeByteOpOp :: LitString -> Size -> Operand -> Operand -> Doc
-pprSizeByteOpOp name size op1 op2
-  = hcat [
-       char '\t',
-       ptext name,
-       pprSize size,
-       space,
-       pprOperand B op1,
-       comma,
-       pprOperand size op2
-    ]
-
-pprSizeOpReg :: LitString -> Size -> Operand -> Reg -> Doc
-pprSizeOpReg name size op1 reg
-  = hcat [
-       char '\t',
-       ptext name,
-       pprSize size,
-       space,
-       pprOperand size op1,
-       comma,
-       pprReg size reg
-    ]
-
-pprSizeReg :: LitString -> Size -> Reg -> Doc
+pprSizeReg :: LitString -> MachRep -> Reg -> Doc
 pprSizeReg name size reg1
   = hcat [
-       char '\t',
-       ptext name,
-       pprSize size,
-       space,
+       pprMnemonic name size,
        pprReg size reg1
     ]
 
-pprSizeRegReg :: LitString -> Size -> Reg -> Reg -> Doc
+pprSizeRegReg :: LitString -> MachRep -> Reg -> Reg -> Doc
 pprSizeRegReg name size reg1 reg2
   = hcat [
-       char '\t',
-       ptext name,
-       pprSize size,
-       space,
+       pprMnemonic name size,
        pprReg size reg1,
         comma,
         pprReg size reg2
     ]
 
-pprCondRegReg :: LitString -> Size -> Cond -> Reg -> Reg -> Doc
+pprCondRegReg :: LitString -> MachRep -> Cond -> Reg -> Reg -> Doc
 pprCondRegReg name size cond reg1 reg2
   = hcat [
        char '\t',
@@ -1479,7 +1464,7 @@ pprCondRegReg name size cond reg1 reg2
         pprReg size reg2
     ]
 
-pprSizeSizeRegReg :: LitString -> Size -> Size -> Reg -> Reg -> Doc
+pprSizeSizeRegReg :: LitString -> MachRep -> MachRep -> Reg -> Reg -> Doc
 pprSizeSizeRegReg name size1 size2 reg1 reg2
   = hcat [
        char '\t',
@@ -1493,13 +1478,10 @@ pprSizeSizeRegReg name size1 size2 reg1 reg2
         pprReg size2 reg2
     ]
 
-pprSizeRegRegReg :: LitString -> Size -> Reg -> Reg -> Reg -> Doc
+pprSizeRegRegReg :: LitString -> MachRep -> Reg -> Reg -> Reg -> Doc
 pprSizeRegRegReg name size reg1 reg2 reg3
   = hcat [
-       char '\t',
-       ptext name,
-       pprSize size,
-       space,
+       pprMnemonic name size,
        pprReg size reg1,
         comma,
         pprReg size reg2,
@@ -1507,51 +1489,34 @@ pprSizeRegRegReg name size reg1 reg2 reg3
         pprReg size reg3
     ]
 
-pprSizeAddr :: LitString -> Size -> MachRegsAddr -> Doc
-pprSizeAddr name size op
-  = hcat [
-       char '\t',
-       ptext name,
-       pprSize size,
-       space,
-       pprAddr op
-    ]
-
-pprSizeAddrReg :: LitString -> Size -> MachRegsAddr -> Reg -> Doc
+pprSizeAddrReg :: LitString -> MachRep -> AddrMode -> Reg -> Doc
 pprSizeAddrReg name size op dst
   = hcat [
-       char '\t',
-       ptext name,
-       pprSize size,
-       space,
+       pprMnemonic name size,
        pprAddr op,
        comma,
        pprReg size dst
     ]
 
-pprSizeRegAddr :: LitString -> Size -> Reg -> MachRegsAddr -> Doc
+pprSizeRegAddr :: LitString -> MachRep -> Reg -> AddrMode -> Doc
 pprSizeRegAddr name size src op
   = hcat [
-       char '\t',
-       ptext name,
-       pprSize size,
-       space,
+       pprMnemonic name size,
        pprReg size src,
        comma,
        pprAddr op
     ]
 
-pprOpOp :: LitString -> Size -> Operand -> Operand -> Doc
-pprOpOp name size op1 op2
+pprShift :: LitString -> MachRep -> Operand -> Operand -> Doc
+pprShift name size src dest
   = hcat [
-       char '\t',
-       ptext name, space,
-       pprOperand size op1,
+       pprMnemonic name size,
+       pprOperand I8 src,  -- src is 8-bit sized
        comma,
-       pprOperand size op2
+       pprOperand size dest
     ]
 
-pprSizeOpOpCoerce :: LitString -> Size -> Size -> Operand -> Operand -> Doc
+pprSizeOpOpCoerce :: LitString -> MachRep -> MachRep -> Operand -> Operand -> Doc
 pprSizeOpOpCoerce name size1 size2 op1 op2
   = hcat [ char '\t', ptext name, pprSize size1, pprSize size2, space,
        pprOperand size1 op1,
@@ -1564,15 +1529,10 @@ pprCondInstr name cond arg
   = hcat [ char '\t', ptext name, pprCond cond, space, arg]
 
 #endif /* i386_TARGET_ARCH */
-\end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsubsection{@pprInstr@ for a SPARC}
-%*                                                                     *
-%************************************************************************
 
-\begin{code}
+-- ------------------------------------------------------------------------------- pprInstr for a SPARC
+
 #if sparc_TARGET_ARCH
 
 -- a clumsy hack for now, to handle possible double alignment problems
@@ -1851,27 +1811,39 @@ pp_comma_lbracket = text ",["
 pp_comma_a       = text ",a"
 
 #endif /* sparc_TARGET_ARCH */
-\end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsubsection{@pprInstr@ for PowerPC}
-%*                                                                     *
-%************************************************************************
 
-\begin{code}
+-- -----------------------------------------------------------------------------
+-- pprInstr for PowerPC
+
 #if powerpc_TARGET_ARCH
 pprInstr (LD sz reg addr) = hcat [
        char '\t',
        ptext SLIT("l"),
        ptext (case sz of
-           B   -> SLIT("ba")
-           Bu  -> SLIT("bz")
-           H   -> SLIT("ha")
-           Hu  -> SLIT("hz")
-           W   -> SLIT("wz")
-           F   -> SLIT("fs")
-           DF  -> SLIT("fd")),
+           I8  -> SLIT("bz")
+           I16 -> SLIT("hz")
+           I32 -> SLIT("wz")
+           F32 -> SLIT("fs")
+           F64 -> SLIT("fd")),
+        case addr of AddrRegImm _ _ -> empty
+                     AddrRegReg _ _ -> char 'x',
+       char '\t',
+       pprReg reg,
+       ptext SLIT(", "),
+       pprAddr addr
+    ]
+pprInstr (LA sz reg addr) = hcat [
+       char '\t',
+       ptext SLIT("l"),
+       ptext (case sz of
+           I8  -> SLIT("ba")
+           I16 -> SLIT("ha")
+           I32 -> SLIT("wa")
+           F32 -> SLIT("fs")
+           F64 -> SLIT("fd")),
+        case addr of AddrRegImm _ _ -> empty
+                     AddrRegReg _ _ -> char 'x',
        char '\t',
        pprReg reg,
        ptext SLIT(", "),
@@ -1881,6 +1853,8 @@ pprInstr (ST sz reg addr) = hcat [
        char '\t',
        ptext SLIT("st"),
        pprSize sz,
+        case addr of AddrRegImm _ _ -> empty
+                     AddrRegReg _ _ -> char 'x',
        char '\t',
        pprReg reg,
        ptext SLIT(", "),
@@ -1891,6 +1865,8 @@ pprInstr (STU sz reg addr) = hcat [
        ptext SLIT("st"),
        pprSize sz,
        ptext SLIT("u\t"),
+        case addr of AddrRegImm _ _ -> empty
+                     AddrRegReg _ _ -> char 'x',
        pprReg reg,
        ptext SLIT(", "),
        pprAddr addr
@@ -1955,13 +1931,21 @@ pprInstr (CMPL sz reg ri) = hcat [
                    RIReg _ -> empty
                    RIImm _ -> char 'i'
            ]
-pprInstr (BCC cond lbl) = hcat [
+pprInstr (BCC cond (BlockId id)) = hcat [
        char '\t',
        ptext SLIT("b"),
        pprCond cond,
        char '\t',
        pprCLabel_asm lbl
     ]
+    where lbl = mkAsmTempLabel id
+
+pprInstr (JMP lbl) = hcat [ -- an alias for b that takes a CLabel
+       char '\t',
+       ptext SLIT("b"),
+       char '\t',
+       pprCLabel_asm lbl
+    ]
 
 pprInstr (MTCTR reg) = hcat [
        char '\t',
@@ -1973,23 +1957,45 @@ pprInstr (BCTR _) = hcat [
        char '\t',
        ptext SLIT("bctr")
     ]
-pprInstr (BL imm _) = hcat [
-       char '\t',
-       ptext SLIT("bl"),
-       char '\t',
-       pprImm imm
+pprInstr (BL lbl _) = hcat [
+       ptext SLIT("\tbl\tL"),
+        pprCLabel_asm lbl,
+       ptext SLIT("$stub")
     ]
 pprInstr (BCTRL _) = hcat [
        char '\t',
        ptext SLIT("bctrl")
     ]
 pprInstr (ADD reg1 reg2 ri) = pprLogic SLIT("add") reg1 reg2 ri
+pprInstr (ADDIS reg1 reg2 imm) = hcat [
+       char '\t',
+       ptext SLIT("addis"),
+       char '\t',
+       pprReg reg1,
+       ptext SLIT(", "),
+       pprReg reg2,
+       ptext SLIT(", "),
+       pprImm imm
+    ]
+
+pprInstr (ADDC reg1 reg2 reg3) = pprLogic SLIT("addc") reg1 reg2 (RIReg reg3)
+pprInstr (ADDE reg1 reg2 reg3) = pprLogic SLIT("adde") reg1 reg2 (RIReg reg3)
 pprInstr (SUBF reg1 reg2 reg3) = pprLogic SLIT("subf") reg1 reg2 (RIReg reg3)
 pprInstr (MULLW reg1 reg2 ri@(RIReg _)) = pprLogic SLIT("mullw") reg1 reg2 ri
 pprInstr (MULLW reg1 reg2 ri@(RIImm _)) = pprLogic SLIT("mull") reg1 reg2 ri
 pprInstr (DIVW reg1 reg2 reg3) = pprLogic SLIT("divw") reg1 reg2 (RIReg reg3)
 pprInstr (DIVWU reg1 reg2 reg3) = pprLogic SLIT("divwu") reg1 reg2 (RIReg reg3)
 
+pprInstr (MULLW_MayOflo reg1 reg2 reg3) = vcat [
+         hcat [ ptext SLIT("\tmullwo\t"), pprReg reg1, ptext SLIT(", "),
+                                          pprReg reg2, ptext SLIT(", "),
+                                          pprReg reg3 ],
+         hcat [ ptext SLIT("\tmfxer\t"),  pprReg reg1 ],
+         hcat [ ptext SLIT("\trlwinm\t"), pprReg reg1, ptext SLIT(", "),
+                                          pprReg reg1, ptext SLIT(", "),
+                                          ptext SLIT("2, 31, 31") ]
+    ]
+
        -- for some reason, "andi" doesn't exist.
        -- we'll use "andi." instead.
 pprInstr (AND reg1 reg2 (RIImm imm)) = hcat [
@@ -2002,10 +2008,10 @@ pprInstr (AND reg1 reg2 (RIImm imm)) = hcat [
        ptext SLIT(", "),
        pprImm imm
     ]
-pprInstr (AND reg1 reg2 ri) = pprLogic SLIT("and") reg1 reg2 (toUI16 ri)
+pprInstr (AND reg1 reg2 ri) = pprLogic SLIT("and") reg1 reg2 ri
 
-pprInstr (OR reg1 reg2 ri) = pprLogic SLIT("or") reg1 reg2 (toUI16 ri)
-pprInstr (XOR reg1 reg2 ri) = pprLogic SLIT("xor") reg1 reg2 (toUI16 ri)
+pprInstr (OR reg1 reg2 ri) = pprLogic SLIT("or") reg1 reg2 ri
+pprInstr (XOR reg1 reg2 ri) = pprLogic SLIT("xor") reg1 reg2 ri
 
 pprInstr (XORIS reg1 reg2 imm) = hcat [
        char '\t',
@@ -2018,12 +2024,35 @@ pprInstr (XORIS reg1 reg2 imm) = hcat [
        pprImm imm
     ]
 
-pprInstr (SLW reg1 reg2 ri) = pprLogic SLIT("slw") reg1 reg2 ri
-pprInstr (SRW reg1 reg2 ri) = pprLogic SLIT("srw") reg1 reg2 ri
-pprInstr (SRAW reg1 reg2 ri) = pprLogic SLIT("sraw") reg1 reg2 ri
+pprInstr (EXTS sz reg1 reg2) = hcat [
+       char '\t',
+       ptext SLIT("exts"),
+       pprSize sz,
+       char '\t',
+       pprReg reg1,
+       ptext SLIT(", "),
+       pprReg reg2
+    ]
+
 pprInstr (NEG reg1 reg2) = pprUnary SLIT("neg") reg1 reg2
 pprInstr (NOT reg1 reg2) = pprUnary SLIT("not") reg1 reg2
 
+pprInstr (SLW reg1 reg2 ri) = pprLogic SLIT("slw") reg1 reg2 (limitShiftRI ri)
+pprInstr (SRW reg1 reg2 ri) = pprLogic SLIT("srw") reg1 reg2 (limitShiftRI ri)
+pprInstr (SRAW reg1 reg2 ri) = pprLogic SLIT("sraw") reg1 reg2 (limitShiftRI ri)
+pprInstr (RLWINM reg1 reg2 sh mb me) = hcat [
+        ptext SLIT("\trlwinm\t"),
+        pprReg reg1,
+        ptext SLIT(", "),
+        pprReg reg2,
+        ptext SLIT(", "),
+        int sh,
+        ptext SLIT(", "),
+        int mb,
+        ptext SLIT(", "),
+        int me
+    ]
+    
 pprInstr (FADD sz reg1 reg2 reg3) = pprBinaryF SLIT("fadd") sz reg1 reg2 reg3
 pprInstr (FSUB sz reg1 reg2 reg3) = pprBinaryF SLIT("fsub") sz reg1 reg2 reg3
 pprInstr (FMUL sz reg1 reg2 reg3) = pprBinaryF SLIT("fmul") sz reg1 reg2 reg3
@@ -2042,8 +2071,25 @@ pprInstr (FCMP reg1 reg2) = hcat [
     ]
 
 pprInstr (FCTIWZ reg1 reg2) = pprUnary SLIT("fctiwz") reg1 reg2
+pprInstr (FRSP reg1 reg2) = pprUnary SLIT("frsp") reg1 reg2
+
+pprInstr (CRNOR dst src1 src2) = hcat [
+        ptext SLIT("\tcrnor\t"),
+        int dst,
+        ptext SLIT(", "),
+        int src1,
+        ptext SLIT(", "),
+        int src2
+    ]
 
-pprInstr _ = ptext SLIT("something")
+pprInstr (MFCR reg) = hcat [
+       char '\t',
+       ptext SLIT("mfcr"),
+       char '\t',
+       pprReg reg
+    ]
+
+pprInstr _ = panic "pprInstr (ppc)"
 
 pprLogic op reg1 reg2 ri = hcat [
        char '\t',
@@ -2084,18 +2130,14 @@ pprRI :: RI -> Doc
 pprRI (RIReg r) = pprReg r
 pprRI (RIImm r) = pprImm r
 
-pprFSize DF = empty
-pprFSize F = char 's'
+pprFSize F64 = empty
+pprFSize F32 = char 's'
 
--- hack to ensure that negative vals come out in non-negative form
--- (assuming that fromIntegral{Int->Word16} will do a 'c-style'
--- conversion, and not throw a fit/exception.)
-toUI16 :: RI -> RI
-toUI16 (RIImm (ImmInt x)) 
-  | x < 0 = RIImm (ImmInt (fromIntegral ((fromIntegral x) :: Word16)))
-toUI16 (RIImm (ImmInteger x)) 
-  | x < 0 = RIImm (ImmInt (fromIntegral ((fromIntegral x) :: Word16)))
-toUI16 x = x
+    -- limit immediate argument for shift instruction to range 0..32
+    -- (yes, the maximum is really 32, not 31)
+limitShiftRI :: RI -> RI
+limitShiftRI (RIImm (ImmInt i)) | i > 32 || i < 0 = RIImm (ImmInt 32)
+limitShiftRI x = x
 
 {-
   The Mach-O object file format used in Darwin/Mac OS X needs a so-called
@@ -2107,28 +2149,39 @@ toUI16 x = x
 -}
 
 #if darwin_TARGET_OS
-pprDyldSymbolStub fn =
+pprDyldSymbolStub (True, lbl) =
     vcat [
        ptext SLIT(".symbol_stub"),
-       ptext SLIT("L_") <> ftext fn <> ptext SLIT("$stub:"),
-           ptext SLIT("\t.indirect_symbol _") <> ftext fn,
-           ptext SLIT("\tlis r11,ha16(L_") <> ftext fn <> ptext SLIT("$lazy_ptr)"),
-           ptext SLIT("\tlwz r12,lo16(L_") <> ftext fn <> ptext SLIT("$lazy_ptr)(r11)"),
+       ptext SLIT("L") <> pprLbl <> ptext SLIT("$stub:"),
+           ptext SLIT("\t.indirect_symbol") <+> pprLbl,
+           ptext SLIT("\tlis r11,ha16(L") <> pprLbl <> ptext SLIT("$lazy_ptr)"),
+           ptext SLIT("\tlwz r12,lo16(L") <> pprLbl <> ptext SLIT("$lazy_ptr)(r11)"),
            ptext SLIT("\tmtctr r12"),
-           ptext SLIT("\taddi r11,r11,lo16(L_") <> ftext fn <> ptext SLIT("$lazy_ptr)"),
+           ptext SLIT("\taddi r11,r11,lo16(L") <> pprLbl <> ptext SLIT("$lazy_ptr)"),
            ptext SLIT("\tbctr"),
        ptext SLIT(".lazy_symbol_pointer"),
-       ptext SLIT("L_") <> ftext fn <> ptext SLIT("$lazy_ptr:"),
-           ptext SLIT("\t.indirect_symbol _") <> ftext fn,
+       ptext SLIT("L") <> pprLbl <> ptext SLIT("$lazy_ptr:"),
+           ptext SLIT("\t.indirect_symbol") <+> pprLbl,
            ptext SLIT("\t.long dyld_stub_binding_helper")
     ]
+    where pprLbl = pprCLabel_asm lbl
+    
+pprDyldSymbolStub (False, lbl) =
+    vcat [
+        ptext SLIT(".non_lazy_symbol_pointer"),
+        char 'L' <> pprLbl <> ptext SLIT("$non_lazy_ptr:"),
+           ptext SLIT("\t.indirect_symbol") <+> pprLbl,
+            ptext SLIT("\t.long\t0")
+    ]
+    where pprLbl = pprCLabel_asm lbl
 #endif
 
-
 #endif /* powerpc_TARGET_ARCH */
-\end{code}
 
-\begin{code}
+
+-- -----------------------------------------------------------------------------
+-- Converting floating-point literals to integrals for printing
+
 #if __GLASGOW_HASKELL__ >= 504
 newFloatArray :: (Int,Int) -> ST s (STUArray s Int Float)
 newFloatArray = newArray_
@@ -2202,4 +2255,3 @@ doubleToBytes d
         i7 <- readCharArray arr 7
         return (map ord [i0,i1,i2,i3,i4,i5,i6,i7])
      )
-\end{code}
similarity index 58%
rename from ghc/compiler/nativeGen/RegAllocInfo.lhs
rename to ghc/compiler/nativeGen/RegAllocInfo.hs
index a3c9321..da2727b 100644 (file)
-%
-% (c) The AQUA Project, Glasgow University, 1996-1998
-%
-\section[RegAllocInfo]{Machine-specific info used for register allocation}
+-----------------------------------------------------------------------------
+--
+-- Machine-specific parts of the register allocator
+--
+-- (c) The University of Glasgow 1996-2004
+--
+-----------------------------------------------------------------------------
 
-The (machine-independent) allocator itself is in @AsmRegAlloc@.
-
-\begin{code}
 #include "nativeGen/NCG.h"
 
 module RegAllocInfo (
        RegUsage(..),
        noUsage,
        regUsage,
-        InsnFuture(..),
-        insnFuture,
-
-       loadReg,
        patchRegs,
-       spillReg,
-       findReservedRegs,
-
-       RegSet,
-        regSetFromList,
-        regSetToList,
-        isEmptyRegSet,
-        emptyRegSet,
-       eqRegSets,
-       filterRegSet,
-        unitRegSet,
-        elemRegSet,
-        unionRegSets,
-        minusRegSets,
-        intersectionRegSets
+       jumpDests,
+       isRegRegMove,
+
+       maxSpillSlots,
+       mkSpillInstr,
+       mkLoadInstr,
     ) where
 
 #include "HsVersions.h"
 
-import List            ( sort )
-import MachMisc
+import Cmm             ( BlockId )
+#if powerpc_TARGET_ARCH || i386_TARGET_ARCH
+import MachOp           ( MachRep(..) )
+#endif
+import MachInstrs
 import MachRegs
-import Stix            ( DestInfo(..) )
-import CLabel          ( isAsmTemp, CLabel{-instance Ord-} )
-import FiniteMap       ( addToFM, lookupFM, FiniteMap )
 import Outputable
 import Constants       ( rESERVED_C_STACK_BYTES )
-import Unique          ( Unique, Uniquable(..) )
 import FastTypes
 
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{Sets of registers}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-
--- Blargh.  Use ghc stuff soon!  Or: perhaps that's not such a good
--- idea.  Most of these sets are either empty or very small, and it
--- might be that the overheads of the FiniteMap based set implementation
--- is a net loss.  The same might be true of FeSets.
-
-newtype RegSet = MkRegSet [Reg]
-
-regSetFromList xs 
-   = MkRegSet (nukeDups (sort xs))
-     where nukeDups :: [Reg] -> [Reg]
-           nukeDups []  = []
-           nukeDups [x] = [x]
-           nukeDups (x:y:xys)
-              = if x == y then nukeDups (y:xys)
-                          else x : nukeDups (y:xys)
-
-regSetToList   (MkRegSet xs)                 = xs
-isEmptyRegSet  (MkRegSet xs)                 = null xs
-emptyRegSet                                  = MkRegSet []
-eqRegSets      (MkRegSet xs1) (MkRegSet xs2) = xs1 == xs2
-unitRegSet x                                 = MkRegSet [x]
-filterRegSet p (MkRegSet xs)                 = MkRegSet (filter p xs)
-
-elemRegSet x (MkRegSet xs) 
-   = f xs
-     where
-        f []     = False
-        f (y:ys) | x == y    = True
-                 | x < y     = False
-                 | otherwise = f ys
-
-unionRegSets (MkRegSet xs1) (MkRegSet xs2)
-   = MkRegSet (f xs1 xs2)
-     where
-        f [] bs = bs
-        f as [] = as
-        f (a:as) (b:bs)
-           | a < b      = a : f as (b:bs)
-           | a > b      = b : f (a:as) bs
-           | otherwise  = a : f as bs
-
-minusRegSets (MkRegSet xs1) (MkRegSet xs2)
-   = MkRegSet (f xs1 xs2)
-     where
-        f [] bs = []
-        f as [] = as
-        f (a:as) (b:bs)
-           | a < b      = a : f as (b:bs)
-           | a > b      = f (a:as) bs
-           | otherwise  = f as bs
-
-intersectionRegSets (MkRegSet xs1) (MkRegSet xs2)
-   = MkRegSet (f xs1 xs2)
-     where
-        f [] bs = []
-        f as [] = []
-        f (a:as) (b:bs)
-           | a < b      = f as (b:bs)
-           | a > b      = f (a:as) bs
-           | otherwise  = a : f as bs
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{@RegUsage@ type; @noUsage@ and @regUsage@ functions}
-%*                                                                     *
-%************************************************************************
-
-@regUsage@ returns the sets of src and destination registers used by a
-particular instruction.  Machine registers that are pre-allocated to
-stgRegs are filtered out, because they are uninteresting from a
-register allocation standpoint.  (We wouldn't want them to end up on
-the free list!)  As far as we are concerned, the fixed registers
-simply don't exist (for allocation purposes, anyway).
-
-regUsage doesn't need to do any trickery for jumps and such.  Just
-state precisely the regs read and written by that insn.  The
-consequences of control flow transfers, as far as register allocation
-goes, are taken care of by @insnFuture@.
-
-\begin{code}
-data RegUsage = RU RegSet RegSet
+-- -----------------------------------------------------------------------------
+-- RegUsage type
+
+-- @regUsage@ returns the sets of src and destination registers used
+-- by a particular instruction.  Machine registers that are
+-- pre-allocated to stgRegs are filtered out, because they are
+-- uninteresting from a register allocation standpoint.  (We wouldn't
+-- want them to end up on the free list!)  As far as we are concerned,
+-- the fixed registers simply don't exist (for allocation purposes,
+-- anyway).
+
+-- regUsage doesn't need to do any trickery for jumps and such.  Just
+-- state precisely the regs read and written by that insn.  The
+-- consequences of control flow transfers, as far as register
+-- allocation goes, are taken care of by the register allocator.
+
+data RegUsage = RU [Reg] [Reg]
 
 noUsage :: RegUsage
-noUsage  = RU emptyRegSet emptyRegSet
+noUsage  = RU [] []
 
 regUsage :: Instr -> RegUsage
 
-interesting (VirtualRegI _)  = True
-interesting (VirtualRegF _)  = True
-interesting (VirtualRegD _)  = True
-interesting (RealReg i)      = isFastTrue (freeReg i)
+interesting (VirtualRegI  _)  = True
+interesting (VirtualRegHi _)  = True
+interesting (VirtualRegF  _)  = True
+interesting (VirtualRegD  _)  = True
+interesting (RealReg i)       = isFastTrue (freeReg i)
 
-#if alpha_TARGET_ARCH
 
+#if alpha_TARGET_ARCH
 regUsage instr = case instr of
     LD B reg addr      -> usage (regAddr addr, [reg, t9])
     LD Bu reg addr     -> usage (regAddr addr, [reg, t9])
@@ -234,22 +146,21 @@ regUsage instr = case instr of
     MOVSxL sz src dst  -> usageRW src dst
     LEA    sz src dst  -> usageRW src dst
     ADD    sz src dst  -> usageRM src dst
+    ADC    sz src dst  -> usageRM src dst
     SUB    sz src dst  -> usageRM src dst
     IMUL   sz src dst  -> usageRM src dst
     IMUL64    sd1 sd2   -> mkRU [sd1,sd2] [sd1,sd2]
     MUL    sz src dst  -> usageRM src dst
-    IQUOT  sz src dst  -> usageRM src dst
-    IREM   sz src dst  -> usageRM src dst
-    QUOT   sz src dst  -> usageRM src dst
-    REM    sz src dst  -> usageRM src dst
+    DIV    sz op       -> mkRU (eax:edx:use_R op) [eax,edx]
+    IDIV   sz op       -> mkRU (eax:edx:use_R op) [eax,edx]
     AND    sz src dst  -> usageRM src dst
     OR     sz src dst  -> usageRM src dst
     XOR    sz src dst  -> usageRM src dst
     NOT    sz op       -> usageM op
     NEGI   sz op       -> usageM op
-    SHL    sz imm dst  -> usageM dst
-    SAR    sz imm dst  -> usageM dst
-    SHR    sz imm dst  -> usageM dst
+    SHL    sz imm dst  -> usageRM imm dst
+    SAR    sz imm dst  -> usageRM imm dst
+    SHR    sz imm dst  -> usageRM imm dst
     BT     sz imm src  -> mkRU (use_R src) []
 
     PUSH   sz op       -> mkRU (use_R op) []
@@ -258,7 +169,8 @@ regUsage instr = case instr of
     CMP    sz src dst  -> mkRU (use_R src ++ use_R dst) []
     SETCC  cond op     -> mkRU [] (def_W op)
     JXX    cond lbl    -> mkRU [] []
-    JMP    dsts op     -> mkRU (use_R op) []
+    JMP    op          -> mkRU (use_R op) []
+    JMP_TBL op ids      -> mkRU (use_R op) []
     CALL   (Left imm)  -> mkRU [] callClobberedRegs
     CALL   (Right reg) -> mkRU [reg] callClobberedRegs
     CLTD               -> mkRU [eax] [edx]
@@ -291,12 +203,9 @@ regUsage instr = case instr of
     GTAN   sz src dst  -> mkRU [src] [dst]
 
     COMMENT _          -> noUsage
-    SEGMENT _          -> noUsage
-    LABEL   _          -> noUsage
-    ASCII   _ _                -> noUsage
-    DATA    _ _                -> noUsage
     DELTA   _           -> noUsage
-    _                  -> pprPanic "regUsage(x86)" empty
+
+    _other             -> panic "regUsage: unrecognised instr"
 
  where
     -- 2 operand form; first operand Read; second Written
@@ -330,8 +239,8 @@ regUsage instr = case instr of
     use_EA (AddrBaseIndex Nothing  (Just (i,_)) _) = [i]
     use_EA (AddrBaseIndex (Just b) (Just (i,_)) _) = [b,i]
 
-    mkRU src dst = RU (regSetFromList (filter interesting src))
-                     (regSetFromList (filter interesting dst))
+    mkRU src dst = RU (filter interesting src)
+                     (filter interesting dst)
 
 #endif /* i386_TARGET_ARCH */
 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -391,6 +300,7 @@ regUsage instr = case instr of
 
 regUsage instr = case instr of
     LD    sz reg addr          -> usage (regAddr addr, [reg])
+    LA    sz reg addr          -> usage (regAddr addr, [reg])
     ST    sz reg addr          -> usage (reg : regAddr addr, [])
     STU    sz reg addr  -> usage (reg : regAddr addr, [])
     LIS   reg imm      -> usage ([], [reg])
@@ -400,23 +310,31 @@ regUsage instr = case instr of
     CMPL  sz reg ri    -> usage (reg : regRI ri,[])
     BCC          cond lbl      -> noUsage
     MTCTR reg          -> usage ([reg],[])
-    BCTR  dsts         -> noUsage
+    BCTR  targets      -> noUsage
     BL    imm params   -> usage (params, callClobberedRegs)
     BCTRL params       -> usage (params, callClobberedRegs)
     ADD          reg1 reg2 ri  -> usage (reg2 : regRI ri, [reg1])
+    ADDC  reg1 reg2 reg3-> usage ([reg2,reg3], [reg1])
+    ADDE  reg1 reg2 reg3-> usage ([reg2,reg3], [reg1])
+    ADDIS reg1 reg2 imm -> usage ([reg2], [reg1])
     SUBF  reg1 reg2 reg3-> usage ([reg2,reg3], [reg1])
     MULLW reg1 reg2 ri  -> usage (reg2 : regRI ri, [reg1])
     DIVW  reg1 reg2 reg3-> usage ([reg2,reg3], [reg1])
     DIVWU reg1 reg2 reg3-> usage ([reg2,reg3], [reg1])
+    MULLW_MayOflo reg1 reg2 reg3        
+                        -> usage ([reg2,reg3], [reg1])
     AND          reg1 reg2 ri  -> usage (reg2 : regRI ri, [reg1])
     OR   reg1 reg2 ri  -> usage (reg2 : regRI ri, [reg1])
     XOR          reg1 reg2 ri  -> usage (reg2 : regRI ri, [reg1])
     XORIS reg1 reg2 imm -> usage ([reg2], [reg1])
+    EXTS  siz reg1 reg2 -> usage ([reg2], [reg1])
     NEG          reg1 reg2     -> usage ([reg2], [reg1])
     NOT          reg1 reg2     -> usage ([reg2], [reg1])
     SLW          reg1 reg2 ri  -> usage (reg2 : regRI ri, [reg1])
     SRW          reg1 reg2 ri  -> usage (reg2 : regRI ri, [reg1])
     SRAW  reg1 reg2 ri  -> usage (reg2 : regRI ri, [reg1])
+    RLWINM reg1 reg2 sh mb me
+                        -> usage ([reg2], [reg1])
     FADD  sz r1 r2 r3   -> usage ([r2,r3], [r1])
     FSUB  sz r1 r2 r3   -> usage ([r2,r3], [r1])
     FMUL  sz r1 r2 r3   -> usage ([r2,r3], [r1])
@@ -424,210 +342,46 @@ regUsage instr = case instr of
     FNEG  r1 r2                -> usage ([r2], [r1])
     FCMP  r1 r2                -> usage ([r1,r2], [])
     FCTIWZ r1 r2       -> usage ([r2], [r1])
+    FRSP r1 r2         -> usage ([r2], [r1])
+    MFCR reg            -> usage ([], [reg])
     _                  -> noUsage
   where
-    usage (src, dst) = RU (regSetFromList (filter interesting src))
-                         (regSetFromList (filter interesting dst))
+    usage (src, dst) = RU (filter interesting src)
+                         (filter interesting dst)
     regAddr (AddrRegReg r1 r2) = [r1, r2]
     regAddr (AddrRegImm r1 _)  = [r1]
 
     regRI (RIReg r) = [r]
     regRI  _   = []
 #endif /* powerpc_TARGET_ARCH */
-\end{code}
-
-
-%************************************************************************
-%*                                                                     *
-\subsection{Free, reserved, call-clobbered, and argument registers}
-%*                                                                     *
-%************************************************************************
-
-@freeRegs@ is the list of registers we can use in register allocation.
-@freeReg@ (below) says if a particular register is free.
-
-With a per-instruction clobber list, we might be able to get some of
-these back, but it's probably not worth the hassle.
-
-@callClobberedRegs@ ... the obvious.
-
-@argRegs@: assuming a call with N arguments, what registers will be
-used to hold arguments?  (NB: it doesn't know whether the arguments
-are integer or floating-point...)
-
-findReservedRegs tells us which regs can be used as spill temporaries.
-The list of instructions for which we are attempting allocation is
-supplied.  This is so that we can (at least for x86) examine it to
-discover which registers are being used in a fixed way -- for example,
-%eax and %edx are used by integer division, so they can't be used as
-spill temporaries.  However, most instruction lists don't do integer
-division, so we don't want to rule them out altogether.
-
-findReservedRegs returns not a list of spill temporaries, but a list
-of list of them.  This is so that the allocator can attempt allocating
-with at first no spill temps, then if that fails, increasing numbers.
-For x86 it is important that we minimise the number of regs reserved
-as spill temporaries, since there are so few.  For Alpha and Sparc
-this isn't a concern; we just ignore the supplied code list and return
-a singleton list which we know will satisfy all spill demands.
-
-\begin{code}
-findReservedRegs :: [Instr] -> [[Reg]]
-findReservedRegs instrs
-#if alpha_TARGET_ARCH
-  = --[[NCG_Reserved_I1, NCG_Reserved_I2,
-    --  NCG_Reserved_F1, NCG_Reserved_F2]]
-    error "findReservedRegs: alpha"
-#endif
-#if sparc_TARGET_ARCH
-  = [[NCG_SpillTmp_I1, NCG_SpillTmp_I2, 
-      NCG_SpillTmp_D1, NCG_SpillTmp_D2,
-      NCG_SpillTmp_F1, NCG_SpillTmp_F2]]
-#endif
-#if i386_TARGET_ARCH
-  -- We can use %fake4 and %fake5 safely for float temps.
-  -- Int regs are more troublesome.  Only %ecx and %edx are
-  -- definitely.  At a pinch, we also could bag %eax if there 
-  -- are no ccalls, but so far we've never encountered
-  -- a situation where three integer temporaries are necessary.
-  -- 
-  -- Because registers are in short supply on x86, we give the
-  -- allocator a whole bunch of possibilities, starting with zero
-  -- temporaries and working up to all that are available.  This
-  -- is inefficient, but spills are pretty rare, so we don't care
-  -- if the register allocator has to try half a dozen or so possibilities
-  -- before getting to one that works.
-  = let f1 = fake5
-        f2 = fake4
-        intregs_avail
-           = [ecx, edx]
-        possibilities
-           = case intregs_avail of
-                [i1] -> [ [], [i1], [f1], [i1,f1], [f1,f2], 
-                          [i1,f1,f2] ]
-
-                [i1,i2] -> [ [], [i1], [f1], [i1,i2], [i1,f1], [f1,f2],
-                             [i1,i2,f1], [i1,f1,f2], [i1,i2,f1,f2] ]
-    in
-        possibilities
-#endif
-#if powerpc_TARGET_ARCH
-  = [[NCG_SpillTmp_I1, NCG_SpillTmp_I2, 
-      NCG_SpillTmp_D1, NCG_SpillTmp_D2]]
-#endif
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{@InsnFuture@ type; @insnFuture@ function}
-%*                                                                     *
-%************************************************************************
 
-@insnFuture@ indicates the places we could get to following the
-current instruction.  This is used by the register allocator to
-compute the flow edges between instructions.
 
-\begin{code}
-data InsnFuture 
-   = NoFuture              -- makes a non-local jump; for the purposes of
-                           -- register allocation, it exits our domain
-   | Next                  -- falls through to next insn
-   | Branch CLabel         -- unconditional branch to the label
-   | NextOrBranch CLabel   -- conditional branch to the label
-   | MultiFuture [CLabel]  -- multiple specific futures
+-- -----------------------------------------------------------------------------
+-- Determine the possible destinations from the current instruction.
 
---instance Outputable InsnFuture where
---   ppr NoFuture            = text "NoFuture"
---   ppr Next                = text "Next"
---   ppr (Branch clbl)       = text "(Branch " <> ppr clbl <> char ')'
---   ppr (NextOrBranch clbl) = text "(NextOrBranch " <> ppr clbl <> char ')'
+-- (we always assume that the next instruction is also a valid destination;
+-- if this isn't the case then the jump should be at the end of the basic
+-- block).
 
-
-insnFuture insn
- = case insn of
-
-#if alpha_TARGET_ARCH
-
-    -- We assume that all local jumps will be BI/BF.  JMP must be out-of-line.
-
-    BR (ImmCLbl lbl)    -> RL (lookup lbl) future
-    BI _ _ (ImmCLbl lbl) -> RL (lookup lbl `unionRegSets` live) future
-    BF _ _ (ImmCLbl lbl) -> RL (lookup lbl `unionRegSets` live) future
-    JMP _ _ _           -> RL emptyRegSet future
-    BSR _ _             -> RL live future
-    JSR _ _ _           -> RL live future
-    LABEL lbl           -> RL live (FL (all `unionRegSets` live) (addToFM env lbl live))
-    _                   -> info
-
-#endif /* alpha_TARGET_ARCH */
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+jumpDests :: Instr -> [BlockId] -> [BlockId]
+jumpDests insn acc
+  = case insn of
 #if i386_TARGET_ARCH
+       JXX _ id        -> id : acc
+       JMP_TBL _ ids   -> ids ++ acc
+#elif powerpc_TARGET_ARCH
+        BCC _ id        -> id : acc
+        BCTR targets    -> targets ++ acc
+#endif
+       _other          -> acc
 
-    -- conditional jump
-    JXX _ clbl | isAsmTemp clbl -> NextOrBranch clbl
-    JXX _ _ -> panic "insnFuture: conditional jump to non-local label"
-
-    -- If the insn says what its dests are, use em!
-    JMP (DestInfo dsts) _ -> MultiFuture dsts
-
-    -- unconditional jump to local label
-    JMP NoDestInfo (OpImm (ImmCLbl clbl)) | isAsmTemp clbl -> Branch clbl
-    
-    -- unconditional jump to non-local label
-    JMP NoDestInfo lbl -> NoFuture
-
-    -- be extra-paranoid
-    JMP _ _ -> panic "insnFuture(x86): JMP wierdness"
-
-    boring     -> Next
-
-#endif /* i386_TARGET_ARCH */
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-#if sparc_TARGET_ARCH
-
-    -- We assume that all local jumps will be BI/BF.
-    BI ALWAYS _ (ImmCLbl clbl) -> Branch clbl
-    BI other  _ (ImmCLbl clbl) -> NextOrBranch clbl
-    BI other  _ _ -> panic "nativeGen(sparc):insnFuture(BI)"
-
-    BF ALWAYS _ (ImmCLbl clbl) -> Branch clbl
-    BF other  _ (ImmCLbl clbl) -> NextOrBranch clbl
-    BF other  _ _ -> panic "nativeGen(sparc):insnFuture(BF)"
-
-    -- CALL(terminal) must be out-of-line.  JMP is not out-of-line
-    -- iff it specifies its destinations.
-    JMP NoDestInfo _      -> NoFuture  -- n.b. NoFuture == MultiFuture []
-    JMP (DestInfo dsts) _ -> MultiFuture dsts
-
-    CALL _ _ True         -> NoFuture
-
-    boring -> Next
 
-#endif /* sparc_TARGET_ARCH */
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-#if powerpc_TARGET_ARCH
-    BCC ALWAYS clbl | isAsmTemp clbl -> Branch clbl
-                   | otherwise -> NoFuture
-    BCC _ clbl             | isAsmTemp clbl -> NextOrBranch clbl
-    BCC _ _ -> panic "insnFuture: conditional jump to non-local label"
-    
-    BCTR (DestInfo dsts) -> MultiFuture dsts
-    BCTR NoDestInfo -> NoFuture
-    boring     -> Next
-#endif /* powerpc_TARGET_ARCH */
-\end{code}
+-- -----------------------------------------------------------------------------
+-- 'patchRegs' function
 
-%************************************************************************
-%*                                                                     *
-\subsection{@patchRegs@ function}
-%*                                                                     *
-%************************************************************************
+-- 'patchRegs' takes an instruction and applies the given mapping to
+-- all the register references.
 
-@patchRegs@ takes an instruction (possibly with
-MemoryReg/UnmappedReg registers) and changes all register references
-according to the supplied environment.
-
-\begin{code}
 patchRegs :: Instr -> (Reg -> Reg) -> Instr
 
 #if alpha_TARGET_ARCH
@@ -695,14 +449,13 @@ patchRegs instr env = case instr of
     MOVSxL sz src dst  -> patch2 (MOVSxL sz) src dst
     LEA  sz src dst    -> patch2 (LEA  sz) src dst
     ADD  sz src dst    -> patch2 (ADD  sz) src dst
+    ADC  sz src dst    -> patch2 (ADC  sz) src dst
     SUB  sz src dst    -> patch2 (SUB  sz) src dst
     IMUL sz src dst    -> patch2 (IMUL sz) src dst
     IMUL64  sd1 sd2     -> IMUL64 (env sd1) (env sd2)
     MUL sz src dst     -> patch2 (MUL sz) src dst
-    IQUOT sz src dst   -> patch2 (IQUOT sz) src dst
-    IREM sz src dst    -> patch2 (IREM sz) src dst
-    QUOT sz src dst    -> patch2 (QUOT sz) src dst
-    REM sz src dst     -> patch2 (REM sz) src dst
+    IDIV sz op         -> patch1 (IDIV sz) op
+    DIV sz op          -> patch1 (DIV sz) op
     AND  sz src dst    -> patch2 (AND  sz) src dst
     OR   sz src dst    -> patch2 (OR   sz) src dst
     XOR  sz src dst    -> patch2 (XOR  sz) src dst
@@ -717,7 +470,8 @@ patchRegs instr env = case instr of
     PUSH sz op         -> patch1 (PUSH sz) op
     POP  sz op         -> patch1 (POP  sz) op
     SETCC cond op      -> patch1 (SETCC cond) op
-    JMP dsts op                -> patch1 (JMP dsts) op
+    JMP op             -> patch1 JMP op
+    JMP_TBL op ids      -> patch1 JMP_TBL op $ ids
 
     GMOV src dst       -> GMOV (env src) (env dst)
     GLD sz src dst     -> GLD sz (lookupAddr src) (env dst)
@@ -748,19 +502,17 @@ patchRegs instr env = case instr of
     CALL (Left imm)    -> instr
     CALL (Right reg)   -> CALL (Right (env reg))
 
+    NOP                        -> instr
     COMMENT _          -> instr
-    SEGMENT _          -> instr
-    LABEL _            -> instr
-    ASCII _ _          -> instr
-    DATA _ _           -> instr
     DELTA _            -> instr
     JXX _ _            -> instr
     CLTD               -> instr
-    _                  -> pprPanic "patchRegs(x86)" empty
+
+    _other             -> panic "patchRegs: unrecognised instr"
 
   where
-    patch1 insn op      = insn (patchOp op)
-    patch2 insn src dst = insn (patchOp src) (patchOp dst)
+    patch1 insn op      = insn $! patchOp op
+    patch2 insn src dst = (insn $! patchOp src) $! patchOp dst
 
     patchOp (OpReg  reg) = OpReg (env reg)
     patchOp (OpImm  imm) = OpImm imm
@@ -825,6 +577,7 @@ patchRegs instr env = case instr of
 
 patchRegs instr env = case instr of
     LD    sz reg addr   -> LD sz (env reg) (fixAddr addr)
+    LA    sz reg addr   -> LA sz (env reg) (fixAddr addr)
     ST    sz reg addr   -> ST sz (env reg) (fixAddr addr)
     STU    sz reg addr  -> STU sz (env reg) (fixAddr addr)
     LIS   reg imm      -> LIS (env reg) imm
@@ -834,23 +587,31 @@ patchRegs instr env = case instr of
     CMPL  sz reg ri    -> CMPL sz (env reg) (fixRI ri)
     BCC          cond lbl      -> BCC cond lbl
     MTCTR reg          -> MTCTR (env reg)
-    BCTR  dsts         -> BCTR dsts
+    BCTR  targets      -> BCTR targets
     BL    imm argRegs  -> BL imm argRegs       -- argument regs
     BCTRL argRegs      -> BCTRL argRegs        -- cannot be remapped
     ADD          reg1 reg2 ri  -> ADD (env reg1) (env reg2) (fixRI ri)
+    ADDC  reg1 reg2 reg3-> ADDC (env reg1) (env reg2) (env reg3)
+    ADDE  reg1 reg2 reg3-> ADDE (env reg1) (env reg2) (env reg3)
+    ADDIS reg1 reg2 imm -> ADDIS (env reg1) (env reg2) imm
     SUBF  reg1 reg2 reg3-> SUBF (env reg1) (env reg2) (env reg3)
     MULLW reg1 reg2 ri -> MULLW (env reg1) (env reg2) (fixRI ri)
     DIVW  reg1 reg2 reg3-> DIVW (env reg1) (env reg2) (env reg3)
     DIVWU reg1 reg2 reg3-> DIVWU (env reg1) (env reg2) (env reg3)
+    MULLW_MayOflo reg1 reg2 reg3
+                        -> MULLW_MayOflo (env reg1) (env reg2) (env reg3)
     AND          reg1 reg2 ri  -> AND (env reg1) (env reg2) (fixRI ri)
     OR           reg1 reg2 ri  -> OR  (env reg1) (env reg2) (fixRI ri)
     XOR          reg1 reg2 ri  -> XOR (env reg1) (env reg2) (fixRI ri)
     XORIS reg1 reg2 imm -> XORIS (env reg1) (env reg2) imm
+    EXTS  sz reg1 reg2 -> EXTS sz (env reg1) (env reg2)
     NEG          reg1 reg2     -> NEG (env reg1) (env reg2)
     NOT          reg1 reg2     -> NOT (env reg1) (env reg2)
     SLW          reg1 reg2 ri  -> SLW (env reg1) (env reg2) (fixRI ri)
     SRW          reg1 reg2 ri  -> SRW (env reg1) (env reg2) (fixRI ri)
     SRAW  reg1 reg2 ri -> SRAW (env reg1) (env reg2) (fixRI ri)
+    RLWINM reg1 reg2 sh mb me
+                        -> RLWINM (env reg1) (env reg2) sh mb me
     FADD  sz r1 r2 r3   -> FADD sz (env r1) (env r2) (env r3)
     FSUB  sz r1 r2 r3   -> FSUB sz (env r1) (env r2) (env r3)
     FMUL  sz r1 r2 r3   -> FMUL sz (env r1) (env r2) (env r3)
@@ -858,6 +619,8 @@ patchRegs instr env = case instr of
     FNEG  r1 r2                -> FNEG (env r1) (env r2)
     FCMP  r1 r2                -> FCMP (env r1) (env r2)
     FCTIWZ r1 r2       -> FCTIWZ (env r1) (env r2)
+    FRSP r1 r2         -> FRSP (env r1) (env r2)
+    MFCR reg            -> MFCR (env reg)
     _ -> instr
   where
     fixAddr (AddrRegReg r1 r2) = AddrRegReg (env r1) (env r2)
@@ -866,23 +629,101 @@ patchRegs instr env = case instr of
     fixRI (RIReg r) = RIReg (env r)
     fixRI other        = other
 #endif /* powerpc_TARGET_ARCH */
-\end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection{@spillReg@ and @loadReg@ functions}
-%*                                                                     *
-%************************************************************************
+-- -----------------------------------------------------------------------------
+-- Detecting reg->reg moves
+
+-- The register allocator attempts to eliminate reg->reg moves whenever it can,
+-- by assigning the src and dest temporaries to the same real register.
+
+isRegRegMove :: Instr -> Maybe (Reg,Reg)
+#ifdef i386_TARGET_ARCH
+-- TMP:
+isRegRegMove (MOV _ (OpReg r1) (OpReg r2)) = Just (r1,r2)
+#elif powerpc_TARGET_ARCH
+isRegRegMove (MR dst src) = Just (src,dst)
+#else
+#warning ToDo: isRegRegMove
+#endif
+isRegRegMove _ = Nothing
+
+-- -----------------------------------------------------------------------------
+-- Generating spill instructions
+
+mkSpillInstr
+   :: Reg              -- register to spill (should be a real)
+   -> Int              -- current stack delta
+   -> Int              -- spill slot to use
+   -> Instr
+mkSpillInstr reg delta slot
+  = ASSERT(isRealReg reg)
+    let        
+        off     = spillSlotToOffset slot
+    in
+#ifdef alpha_TARGET_ARCH
+    {-Alpha: spill below the stack pointer (?)-}
+    ST sz dyn (spRel (- (off `div` 8)))
+#endif
+#ifdef i386_TARGET_ARCH
+    let off_w = (off-delta) `div` 4
+    in case regClass reg of
+          RcInteger -> MOV I32 (OpReg reg) (OpAddr (spRel off_w))
+          _         -> GST F80 reg (spRel off_w) {- RcFloat/RcDouble -}
+#endif
+#ifdef sparc_TARGET_ARCH
+       {-SPARC: spill below frame pointer leaving 2 words/spill-}
+                        let{off_w = 1 + (off `div` 4);
+                            sz = case regClass vreg of {
+                                    RcInteger -> W;
+                                    RcFloat   -> F;
+                                    RcDouble  -> DF}}
+                        in ST sz dyn (fpRel (- off_w))
+#endif
+#ifdef powerpc_TARGET_ARCH
+    let sz = case regClass reg of
+                RcInteger -> I32
+                RcDouble -> F64
+    in ST sz reg (AddrRegImm sp (ImmInt (off-delta)))
+#endif
+
 
-Spill to memory, and load it back...
+mkLoadInstr
+   :: Reg              -- register to load (should be a real)
+   -> Int              -- current stack delta
+   -> Int              -- spill slot to use
+   -> Instr
+mkLoadInstr reg delta slot
+  = ASSERT(isRealReg reg)
+    let
+        off     = spillSlotToOffset slot
+    in
+#ifdef alpha_TARGET_ARCH
+        LD  sz dyn (spRel (- (off `div` 8)))
+#endif
+#ifdef i386_TARGET_ARCH
+       let off_w = (off-delta) `div` 4
+        in case regClass reg of {
+              RcInteger -> MOV I32 (OpAddr (spRel off_w)) (OpReg reg);
+              _         -> GLD F80 (spRel off_w) reg} {- RcFloat/RcDouble -}
+#endif
+#ifdef sparc_TARGET_ARCH
+        let{off_w = 1 + (off `div` 4);
+            sz = case regClass vreg of {
+                   RcInteger -> W;
+                   RcFloat   -> F;
+                   RcDouble  -> DF}}
+        in LD sz (fpRel (- off_w)) dyn
+#endif
+#ifdef powerpc_TARGET_ARCH
+    let sz = case regClass reg of
+                RcInteger -> I32
+                RcDouble -> F64
+    in LD sz reg (AddrRegImm sp (ImmInt (off-delta)))
+#endif
 
-JRS, 000122: on x86, don't spill directly above the stack pointer,
-since some insn sequences (int <-> conversions) use this as a temp
-location.  Leave 8 words (ie, 64 bytes for a 64-bit arch) of slop.
 
-\begin{code}
 spillSlotSize :: Int
-spillSlotSize = IF_ARCH_alpha( 8, IF_ARCH_sparc( 8, IF_ARCH_i386( 12, IF_ARCH_powerpc( 8, ))))
+spillSlotSize = IF_ARCH_i386(12, 8)
 
 maxSpillSlots :: Int
 maxSpillSlots = ((rESERVED_C_STACK_BYTES - 64) `div` spillSlotSize) - 1
@@ -897,71 +738,3 @@ spillSlotToOffset slot
    | otherwise
    = pprPanic "spillSlotToOffset:" 
               (text "invalid spill location: " <> int slot)
-
-vregToSpillSlot :: FiniteMap VRegUnique Int -> VRegUnique -> Int
-vregToSpillSlot vreg_to_slot_map u
-   = case lookupFM vreg_to_slot_map u of
-        Just xx -> xx
-        Nothing -> pprPanic "vregToSpillSlot: unmapped vreg" (pprVRegUnique u)
-
-
-spillReg, loadReg :: FiniteMap VRegUnique Int -> Int -> Reg -> Reg -> Instr
-
-spillReg vreg_to_slot_map delta dyn vreg
-  | isVirtualReg vreg
-  = let        slot_no = vregToSpillSlot vreg_to_slot_map (getVRegUnique vreg)
-        off     = spillSlotToOffset slot_no
-    in
-       {-Alpha: spill below the stack pointer (?)-}
-        IF_ARCH_alpha( ST sz dyn (spRel (- (off `div` 8)))
-
-       {-I386: spill above stack pointer leaving 3 words/spill-}
-       ,IF_ARCH_i386 ( let off_w = (off-delta) `div` 4
-                        in case regClass vreg of {
-                              RcInteger -> MOV L (OpReg dyn) (OpAddr (spRel off_w));
-                              _         -> GST F80 dyn (spRel off_w)} {- RcFloat/RcDouble -}
-
-       {-SPARC: spill below frame pointer leaving 2 words/spill-}
-       ,IF_ARCH_sparc( 
-                        let{off_w = 1 + (off `div` 4);
-                            sz = case regClass vreg of {
-                                    RcInteger -> W;
-                                    RcFloat   -> F;
-                                    RcDouble  -> DF}}
-                        in ST sz dyn (fpRel (- off_w))
-        ,IF_ARCH_powerpc(
-                       let{sz = case regClass vreg of {
-                                    RcInteger -> W;
-                                    RcFloat   -> F;
-                                    RcDouble  -> DF}}
-                       in ST sz dyn (AddrRegImm sp (ImmInt (off-delta)))
-       ,))))
-
-   
-loadReg vreg_to_slot_map delta vreg dyn
-  | isVirtualReg vreg
-  = let        slot_no = vregToSpillSlot vreg_to_slot_map (getVRegUnique vreg)
-        off     = spillSlotToOffset slot_no
-    in
-        IF_ARCH_alpha( LD  sz dyn (spRel (- (off `div` 8)))
-
-       ,IF_ARCH_i386 ( let off_w = (off-delta) `div` 4
-                        in case regClass vreg of {
-                              RcInteger -> MOV L (OpAddr (spRel off_w)) (OpReg dyn);
-                              _         -> GLD F80 (spRel off_w) dyn} {- RcFloat/RcDouble -}
-
-       ,IF_ARCH_sparc( 
-                        let{off_w = 1 + (off `div` 4);
-                            sz = case regClass vreg of {
-                                   RcInteger -> W;
-                                   RcFloat   -> F;
-                                   RcDouble  -> DF}}
-                        in LD sz (fpRel (- off_w)) dyn
-        ,IF_ARCH_powerpc(
-                       let{sz = case regClass vreg of {
-                                    RcInteger -> W;
-                                    RcFloat   -> F;
-                                    RcDouble  -> DF}}
-                       in LD sz dyn (AddrRegImm sp (ImmInt (off-delta)))
-       ,))))
-\end{code}
diff --git a/ghc/compiler/nativeGen/RegisterAlloc.hs b/ghc/compiler/nativeGen/RegisterAlloc.hs
new file mode 100644 (file)
index 0000000..1c58cdb
--- /dev/null
@@ -0,0 +1,812 @@
+-----------------------------------------------------------------------------
+--
+-- The register allocator
+--
+-- (c) The University of Glasgow 2004
+--
+-----------------------------------------------------------------------------
+
+{-
+The algorithm is roughly:
+  1) Compute strongly connected components of the basic block list.
+
+  2) Compute liveness (mapping from pseudo register to
+     point(s) of death?).
+
+  3) Walk instructions in each basic block.  We keep track of
+       (a) Free real registers (a bitmap?)
+       (b) Current assignment of temporaries to machine registers and/or
+           spill slots (call this the "assignment").
+       (c) Partial mapping from basic block ids to a virt-to-loc mapping.
+           When we first encounter a branch to a basic block,
+           we fill in its entry in this table with the current mapping.
+
+     For each instruction:
+       (a) For each real register clobbered by this instruction:
+           If a temporary resides in it,
+               If the temporary is live after this instruction,
+                   Move the temporary to another (non-clobbered & free) reg,
+                   or spill it to memory.  Mark the temporary as residing
+                   in both memory and a register if it was spilled (it might
+                   need to be read by this instruction).
+           (ToDo: this is wrong for jump instructions?)
+
+       (b) For each temporary *read* by the instruction:
+           If the temporary does not have a real register allocation:
+               - Allocate a real register from the free list.  If
+                 the list is empty:
+                 - Find a temporary to spill.  Pick one that is
+                   not used in this instruction (ToDo: not
+                   used for a while...)
+                 - generate a spill instruction
+               - If the temporary was previously spilled,
+                 generate an instruction to read the temp from its spill loc.
+           (optimisation: if we can see that a real register is going to
+            be used soon, then don't use it for allocation).
+
+       (c) Update the current assignment
+
+       (d) If the intstruction is a branch:
+             if the destination block already has a register assignment,
+               Generate a new block with fixup code and redirect the
+               jump to the new block.
+             else,
+               Update the block id->assignment mapping with the current
+               assignment.
+
+       (e) Delete all register assignments for temps which are read
+           (only) and die here.  Update the free register list.
+
+       (f) Mark all registers clobbered by this instruction as not free,
+           and mark temporaries which have been spilled due to clobbering
+           as in memory (step (a) marks then as in both mem & reg).
+
+       (g) For each temporary *written* (only) by this instruction:
+           Allocate a real register as for (b), spilling something
+           else if necessary.
+
+       (h) Delete all register assignments for temps which are
+           written and die here (there should rarely be any).  Update
+           the free register list.
+
+       (i) Rewrite the instruction with the new mapping.
+
+       (j) For each spilled reg known to be now dead, re-add its stack slot
+           to the free list.
+
+-}
+
+module RegisterAlloc (
+       regAlloc
+  ) where
+
+#include "HsVersions.h"
+#include "../includes/ghcconfig.h"
+
+import PprMach
+import MachRegs
+import MachInstrs
+import RegAllocInfo
+import Cmm
+
+import Digraph
+import Unique          ( Uniquable(..), Unique, getUnique )
+import UniqSet
+import UniqFM
+import Outputable
+
+#ifndef DEBUG
+import Maybe           ( fromJust )
+#endif
+import List            ( nub, partition )
+import Monad           ( when )
+import DATA_WORD
+import DATA_BITS
+
+-- -----------------------------------------------------------------------------
+-- Some useful types
+
+type RegSet = UniqSet Reg
+
+type RegMap a = UniqFM a
+emptyRegMap = emptyUFM
+
+type BlockMap a = UniqFM a
+emptyBlockMap = emptyUFM
+
+-- A basic block where the isntructions are annotated with the registers
+-- which are no longer live in the *next* instruction in this sequence.
+-- (NB. if the instruction is a jump, these registers might still be live
+-- at the jump target(s) - you have to check the liveness at the destination
+-- block to find out).
+type AnnBasicBlock 
+       = GenBasicBlock (Instr,
+                        [Reg],         -- registers read (only) which die
+                        [Reg])         -- registers written which die
+
+-- -----------------------------------------------------------------------------
+-- The free register set
+
+-- This needs to be *efficient*
+
+{- Here's an inefficient 'executable specification' of the FreeRegs data type:
+type FreeRegs = [RegNo]
+
+noFreeRegs = 0
+releaseReg n f = if n `elem` f then f else (n : f)
+initFreeRegs = allocatableRegs
+getFreeRegs cls f = filter ( (==cls) . regClass . RealReg ) f
+allocateReg f r = filter (/= r) f
+-}
+
+#if defined(powerpc_TARGET_ARCH)
+
+-- The PowerPC has 32 integer and 32 floating point registers.
+-- This is 32bit PowerPC, so Word64 is inefficient - two Word32s are much
+-- better.
+-- Note that when getFreeRegs scans for free registers, it starts at register
+-- 31 and counts down. This is a hack for the PowerPC - the higher-numbered
+-- registers are callee-saves, while the lower regs are caller-saves, so it
+-- makes sense to start at the high end.
+-- Apart from that, the code does nothing PowerPC-specific, so feel free to
+-- add your favourite platform to the #if (if you have 64 registers but only
+-- 32-bit words).
+
+data FreeRegs = FreeRegs !Word32 !Word32
+
+noFreeRegs = FreeRegs 0 0
+releaseReg r (FreeRegs g f)
+    | r > 31    = FreeRegs g (f .|. (1 `shiftL` (fromIntegral r - 32)))
+    | otherwise = FreeRegs (g .|. (1 `shiftL` fromIntegral r)) f
+    
+initFreeRegs :: FreeRegs
+initFreeRegs = foldr releaseReg noFreeRegs allocatableRegs
+
+getFreeRegs cls (FreeRegs g f)
+    | RcDouble <- cls = go f (0x80000000) 63
+    | RcInteger <- cls = go g (0x80000000) 31
+    where
+        go x 0 i = []
+        go x m i | x .&. m /= 0 = i : (go x (m `shiftR` 1) $! i-1)
+                 | otherwise    = go x (m `shiftR` 1) $! i-1
+
+allocateReg (FreeRegs g f) r
+    | r > 31    = FreeRegs g (f .&. complement (1 `shiftL` (fromIntegral r - 32)))
+    | otherwise = FreeRegs (g .&. complement (1 `shiftL` fromIntegral r)) f
+
+#else
+
+-- If we have less than 32 registers, or if we have efficient 64-bit words,
+-- we will just use a single bitfield.
+
+#if defined(alpha_TARGET_ARCH)
+type FreeRegs = Word64
+#else
+type FreeRegs = Word32
+#endif
+
+noFreeRegs :: FreeRegs
+noFreeRegs = 0
+
+releaseReg :: RegNo -> FreeRegs -> FreeRegs
+releaseReg n f = f .|. (1 `shiftL` n)
+
+initFreeRegs :: FreeRegs
+initFreeRegs = foldr releaseReg noFreeRegs allocatableRegs
+
+getFreeRegs :: RegClass -> FreeRegs -> [RegNo] -- lazilly
+getFreeRegs cls f = go f 0
+  where go 0 m = []
+        go n m 
+         | n .&. 1 /= 0 && regClass (RealReg m) == cls
+         = m : (go (n `shiftR` 1) $! (m+1))
+         | otherwise
+         = go (n `shiftR` 1) $! (m+1)
+       -- ToDo: there's no point looking through all the integer registers
+       -- in order to find a floating-point one.
+
+allocateReg :: FreeRegs -> RegNo -> FreeRegs
+allocateReg f r = f .&. complement (1 `shiftL` fromIntegral r)
+#endif
+
+-- -----------------------------------------------------------------------------
+-- The free list of stack slots
+
+-- This doesn't need to be so efficient.  It also doesn't really need to be
+-- maintained as a set, so we just use an ordinary list (lazy, because it
+-- contains all the possible stack slots and there are lots :-).
+
+type StackSlot = Int
+type FreeStack = [StackSlot]
+
+completelyFreeStack :: FreeStack
+completelyFreeStack = [0..maxSpillSlots]
+
+getFreeStackSlot :: FreeStack -> (FreeStack,Int)
+getFreeStackSlot (slot:stack) = (stack,slot)
+
+freeStackSlot :: FreeStack -> Int -> FreeStack
+freeStackSlot stack slot = slot:stack
+
+
+-- -----------------------------------------------------------------------------
+-- Top level of the register allocator
+
+regAlloc :: NatCmmTop -> NatCmmTop
+regAlloc (CmmData sec d) = CmmData sec d
+regAlloc (CmmProc info lbl params [])
+  = CmmProc info lbl params []  -- no blocks to run the regalloc on
+regAlloc (CmmProc info lbl params blocks@(first:rest))
+  = -- pprTrace "Liveness" (ppr block_live) $
+    CmmProc info lbl params (first':rest')
+  where
+    first_id               = blockId first
+    sccs                  = sccBlocks blocks
+    (ann_sccs, block_live) = computeLiveness sccs
+    final_blocks          = linearRegAlloc block_live ann_sccs
+    ((first':_),rest')    = partition ((== first_id) . blockId) final_blocks
+
+
+sccBlocks :: [NatBasicBlock] -> [SCC NatBasicBlock]
+sccBlocks blocks = stronglyConnComp graph
+  where
+       getOutEdges :: [Instr] -> [BlockId]
+       getOutEdges instrs = foldr jumpDests [] instrs
+
+       graph = [ (block, getUnique id, map getUnique (getOutEdges instrs))
+               | block@(BasicBlock id instrs) <- blocks ]
+
+
+-- -----------------------------------------------------------------------------
+-- Computing liveness
+
+computeLiveness
+   :: [SCC NatBasicBlock]
+   -> ([SCC AnnBasicBlock],    -- instructions annotated with list of registers
+                               -- which are "dead after this instruction".
+       BlockMap RegSet)                -- blocks annontated with set of live registers
+                               -- on entry to the block.
+
+  -- NOTE: on entry, the SCCs are in "reverse" order: later blocks may transfer
+  -- control to earlier ones only.  The SCCs returned are in the *opposite* 
+  -- order, which is exactly what we want for the next pass.
+       
+computeLiveness sccs
+  = livenessSCCs emptyBlockMap [] sccs
+  where
+  livenessSCCs 
+        :: BlockMap RegSet 
+        -> [SCC AnnBasicBlock]         -- accum
+        -> [SCC NatBasicBlock]
+        -> ([SCC AnnBasicBlock], BlockMap RegSet)
+
+  livenessSCCs blockmap done [] = (done, blockmap)
+  livenessSCCs blockmap done
+       (AcyclicSCC (BasicBlock block_id instrs) : sccs) =
+         {- pprTrace "live instrs" (ppr (getUnique block_id) $$
+                                 vcat (map (\(instr,regs) -> docToSDoc (pprInstr instr) $$ ppr regs) instrs')) $ 
+         -}
+         livenessSCCs blockmap'
+               (AcyclicSCC (BasicBlock block_id instrs'):done) sccs
+       where (live,instrs') = liveness emptyUniqSet blockmap []
+                                       (reverse instrs)
+             blockmap' = addToUFM blockmap block_id live
+       -- TODO: cope with recursive blocks
+  
+  liveness :: RegSet                   -- live regs
+          -> BlockMap RegSet           -- live regs on entry to other BBs
+          -> [(Instr,[Reg],[Reg])]     -- instructions (accum)
+          -> [Instr]                   -- instructions
+          -> (RegSet, [(Instr,[Reg],[Reg])])
+
+  liveness liveregs blockmap done []  = (liveregs, done)
+  liveness liveregs blockmap done (instr:instrs) 
+       = liveness liveregs2 blockmap ((instr,r_dying,w_dying):done) instrs
+       where 
+             RU read written = regUsage instr
+
+             -- registers that were written here are dead going backwards.
+             -- registers that were read here are live going backwards.
+             liveregs1 = (liveregs `delListFromUniqSet` written)
+                                   `addListToUniqSet` read
+
+             -- union in the live regs from all the jump destinations of this
+             -- instruction.
+             targets = jumpDests instr [] -- where we go from here
+             liveregs2 = unionManyUniqSets 
+                           (liveregs1 : map (lookItUp "liveness" blockmap) 
+                                               targets)
+
+             -- registers that are not live beyond this point, are recorded
+             --  as dying here.
+             r_dying  = [ reg | reg <- read, reg `notElem` written,
+                                not (elementOfUniqSet reg liveregs) ]
+
+             w_dying = [ reg | reg <- written,
+                               not (elementOfUniqSet reg liveregs) ]
+
+-- -----------------------------------------------------------------------------
+-- Linear sweep to allocate registers
+
+data Loc = InReg   {-# UNPACK #-} !RegNo
+        | InMem   {-# UNPACK #-} !Int          -- stack slot
+        | InBoth  {-# UNPACK #-} !RegNo
+                  {-# UNPACK #-} !Int          -- stack slot
+  deriving (Eq, Show)
+
+{- 
+A temporary can be marked as living in both a register and memory
+(InBoth), for example if it was recently loaded from a spill location.
+This makes it cheap to spill (no save instruction required), but we
+have to be careful to turn this into InReg if the value in the
+register is changed.
+
+This is also useful when a temporary is about to be clobbered.  We
+save it in a spill location, but mark it as InBoth because the current
+instruction might still want to read it.
+-}
+
+#ifdef DEBUG
+instance Outputable Loc where
+  ppr l = text (show l)
+#endif
+
+linearRegAlloc
+   :: BlockMap RegSet          -- live regs on entry to each basic block
+   -> [SCC AnnBasicBlock]      -- instructions annotated with "deaths"
+   -> [NatBasicBlock]
+linearRegAlloc block_live sccs = linearRA_SCCs emptyBlockMap sccs
+  where
+  linearRA_SCCs
+       :: BlockAssignment
+       -> [SCC AnnBasicBlock]
+       -> [NatBasicBlock]
+  linearRA_SCCs block_assig [] = []
+  linearRA_SCCs block_assig 
+       (AcyclicSCC (BasicBlock id instrs) : sccs) 
+       = BasicBlock id instrs' : linearRA_SCCs block_assig' sccs
+    where
+       (block_assig',(instrs',fixups)) = 
+          case lookupUFM block_assig id of
+               -- no prior info about this block: assume everything is
+               -- free and the assignment is empty.
+               Nothing -> 
+                  runR block_assig initFreeRegs 
+                               emptyRegMap completelyFreeStack $
+                       linearRA [] [] instrs 
+               Just (freeregs,stack,assig) -> 
+                  runR block_assig freeregs assig stack $
+                       linearRA [] [] instrs 
+
+  linearRA :: [Instr] -> [NatBasicBlock] -> [(Instr,[Reg],[Reg])]
+       -> RegM ([Instr], [NatBasicBlock])
+  linearRA instr_acc fixups [] = 
+    return (reverse instr_acc, fixups)
+  linearRA instr_acc fixups (instr:instrs) = do
+    (instr_acc', new_fixups) <- raInsn block_live instr_acc instr
+    linearRA instr_acc' (new_fixups++fixups) instrs
+
+-- -----------------------------------------------------------------------------
+-- Register allocation for a single instruction
+
+type BlockAssignment = BlockMap (FreeRegs, FreeStack, RegMap Loc)
+
+raInsn  :: BlockMap RegSet             -- Live temporaries at each basic block
+       -> [Instr]                      -- new instructions (accum.)
+       -> (Instr,[Reg],[Reg])          -- the instruction (with "deaths")
+       -> RegM (
+            [Instr],                   -- new instructions
+            [NatBasicBlock]            -- extra fixup blocks
+          )
+
+raInsn block_live new_instrs (instr@(DELTA n), _, _) = do
+    setDeltaR n
+    return (new_instrs, [])
+
+raInsn block_live new_instrs (instr, r_dying, w_dying) = do
+    assig    <- getAssigR
+
+    -- If we have a reg->reg move between virtual registers, where the
+    -- src register is not live after this instruction, and the dst
+    -- register does not already have an assignment, then we can
+    -- eliminate the instruction.
+    case isRegRegMove instr of
+       Just (src,dst)
+               | src `elem` r_dying, 
+                 isVirtualReg dst,
+                 Just loc <- lookupUFM assig src,
+                 not (dst `elemUFM` assig) -> do
+                       setAssigR (addToUFM (delFromUFM assig src) dst loc)
+                       return (new_instrs, [])
+
+       other -> genRaInsn block_live new_instrs instr r_dying w_dying
+
+
+genRaInsn block_live new_instrs instr r_dying w_dying = do
+    let 
+       RU read written = regUsage instr
+
+        -- we're not interested in regs written if they're also read.
+       written' = nub (filter (`notElem` read) written)
+
+       (real_written1,virt_written) = partition isRealReg written'
+
+       real_written = [ r | RealReg r <- real_written1 ]
+
+       -- we don't need to do anything with real registers that are
+       -- only read by this instr.  (the list is typically ~2 elements,
+       -- so using nub isn't a problem).
+       virt_read = nub (filter isVirtualReg read)
+    -- in
+
+    -- (a) save any temporaries which will be clobbered by this instruction
+    (clobber_saves, assig_adj) <- saveClobberedTemps real_written r_dying
+
+    -- freeregs <- getFreeRegsR
+    -- assig <- getAssigR
+    -- pprTrace "raInsn" (docToSDoc (pprInstr instr) $$ ppr r_dying <+> ppr w_dying $$ ppr virt_read <+> ppr virt_written $$ text (show freeregs) $$ ppr assig) $ do
+
+    -- (b), (c) allocate real regs for all regs read by this instruction.
+    (r_spills, r_allocd) <- 
+       allocateRegsAndSpill True{-reading-} virt_read [] [] virt_read
+
+    -- (d) Update block map for new destinations
+    -- NB. do this before removing dead regs from the assignment, because
+    -- these dead regs might in fact be live in the jump targets (they're
+    -- only dead in the code that follows in the current basic block).
+    (fixup_blocks, adjusted_instr)
+       <- joinToTargets block_live [] instr (jumpDests instr [])
+
+    -- (e) Delete all register assignments for temps which are read
+    --     (only) and die here.  Update the free register list.
+    releaseRegs r_dying
+
+    -- (f) Mark regs which are clobbered as unallocatable
+    clobberRegs real_written assig_adj
+
+    -- (g) Allocate registers for temporaries *written* (only)
+    (w_spills, w_allocd) <- 
+       allocateRegsAndSpill False{-writing-} virt_written [] [] virt_written
+
+    -- (h) Release registers for temps which are written here and not
+    -- used again.
+    releaseRegs w_dying
+
+    let
+       -- (i) Patch the instruction
+       patch_map = listToUFM   [ (t,RealReg r) | 
+                                 (t,r) <- zip virt_read r_allocd
+                                         ++ zip virt_written w_allocd ]
+
+       patched_instr = patchRegs adjusted_instr patchLookup
+       patchLookup x = case lookupUFM patch_map x of
+                               Nothing -> x
+                               Just y  -> y
+    -- in
+
+    -- pprTrace "patched" (docToSDoc (pprInstr patched_instr)) $ do
+
+    -- (j) free up stack slots for dead spilled regs
+    -- TODO (can't be bothered right now)
+
+    return (patched_instr : w_spills ++ reverse r_spills
+                ++ clobber_saves ++ new_instrs,
+           fixup_blocks)
+
+-- -----------------------------------------------------------------------------
+-- releaseRegs
+
+releaseRegs regs = do
+  assig <- getAssigR
+  free <- getFreeRegsR
+  loop assig free regs 
+ where
+  loop assig free [] = do setAssigR assig; setFreeRegsR free; return ()
+  loop assig free (RealReg r : rs) = loop assig (releaseReg r free) rs
+  loop assig free (r:rs) = 
+     case lookupUFM assig r of
+       Just (InBoth real _) -> loop (delFromUFM assig r) (releaseReg real free) rs
+       Just (InReg real) -> loop (delFromUFM assig r) (releaseReg real free) rs
+       _other            -> loop (delFromUFM assig r) free rs
+
+-- -----------------------------------------------------------------------------
+-- Clobber real registers
+
+{-
+For each temp in a register that is going to be clobbered:
+  - if the temp dies after this instruction, do nothing
+  - otherwise, put it somewhere safe (another reg if possible,
+    otherwise spill and record InBoth in the assignment).
+
+for allocateRegs on the temps *read*,
+  - clobbered regs are allocatable.
+
+for allocateRegs on the temps *written*, 
+  - clobbered regs are not allocatable.
+-}
+
+saveClobberedTemps
+   :: [RegNo]             -- real registers clobbered by this instruction
+   -> [Reg]               -- registers which are no longer live after this insn
+   -> RegM ( 
+       [Instr],           -- return: instructions to spill any temps that will
+       [(Unique,Loc)]     -- be clobbered, and adjustments to make to the 
+        )                 -- assignment after reading has taken place.
+
+saveClobberedTemps [] _ = return ([],[]) -- common case
+saveClobberedTemps clobbered dying =  do
+  assig <- getAssigR
+  let
+       to_spill  = [ (temp,reg) | (temp, InReg reg) <- ufmToList assig,
+                                  reg `elem` clobbered,
+                                  temp `notElem` map getUnique dying  ]
+  -- in
+  (instrs,assig_adj,assig') <- clobber assig [] [] to_spill
+  setAssigR assig'
+  return (instrs,assig_adj)
+ where
+  clobber assig instrs adj [] = return (instrs,adj,assig)
+  clobber assig instrs adj ((temp,reg):rest)
+    = do
+      (spill,slot) <- spillR (RealReg reg)
+      clobber (addToUFM assig temp (InBoth reg slot)) 
+        (spill:instrs) ((temp,InMem slot):adj) rest
+       --ToDo: copy it to another register if possible
+
+
+clobberRegs :: [RegNo] -> [(Unique,Loc)] -> RegM ()
+clobberRegs [] _ = return () -- common case
+clobberRegs clobbered assig_adj = do
+  freeregs <- getFreeRegsR
+  setFreeRegsR (foldl allocateReg freeregs clobbered)
+  assig <- getAssigR
+  setAssigR (addListToUFM assig assig_adj)
+
+-- -----------------------------------------------------------------------------
+-- allocateRegsAndSpill
+
+-- This function does several things:
+--   For each temporary referred to by this instruction,
+--   we allocate a real register (spilling another temporary if necessary).
+--   We load the temporary up from memory if necessary.
+--   We also update the register assignment in the process, and
+--   the list of free registers and free stack slots.
+
+allocateRegsAndSpill
+       :: Bool                 -- True <=> reading (load up spilled regs)
+       -> [Reg]                -- don't push these out
+       -> [Instr]              -- spill insns
+       -> [RegNo]              -- real registers allocated (accum.)
+       -> [Reg]                -- temps to allocate
+       -> RegM ([Instr], [RegNo])
+
+allocateRegsAndSpill reading keep spills alloc []
+  = return (spills,reverse alloc)
+
+allocateRegsAndSpill reading keep spills alloc (r:rs) = do
+  assig <- getAssigR
+  case lookupUFM assig r of
+  -- case (1a): already in a register
+     Just (InReg my_reg) ->
+       allocateRegsAndSpill reading keep spills (my_reg:alloc) rs
+
+  -- case (1b): already in a register (and memory)
+  -- NB. if we're writing this register, update its assignemnt to be
+  -- InReg, because the memory value is no longer valid.
+     Just (InBoth my_reg mem) -> do
+       when (not reading) (setAssigR (addToUFM assig my_reg (InReg my_reg)))
+       allocateRegsAndSpill reading keep spills (my_reg:alloc) rs
+
+  -- Not already in a register, so we need to find a free one...
+     loc -> do
+       freeregs <- getFreeRegsR
+
+        case getFreeRegs (regClass r) freeregs of
+
+       -- case (2): we have a free register
+         my_reg:_ -> do
+           spills'   <- do_load reading loc my_reg spills
+           let new_loc = case loc of
+                               Just (InMem slot) -> InBoth my_reg slot
+                               _other            -> InReg my_reg
+           setAssigR (addToUFM assig r $! new_loc)
+           setFreeRegsR (allocateReg freeregs my_reg)
+           allocateRegsAndSpill reading keep spills' (my_reg:alloc) rs
+
+        -- case (3): we need to push something out to free up a register
+          [] -> do
+           let
+             keep' = map getUnique keep
+             candidates1 = [ (temp,reg,mem)
+                           | (temp, InBoth reg mem) <- ufmToList assig,
+                             temp `notElem` keep', regClass (RealReg reg) == regClass r ]
+             candidates2 = [ (temp,reg)
+                           | (temp, InReg reg) <- ufmToList assig,
+                             temp `notElem` keep', regClass (RealReg reg) == regClass r  ]
+           -- in
+           ASSERT2(not (null candidates1 && null candidates2), ppr assig) do
+
+           case candidates1 of
+
+            -- we have a temporary that is in both register and mem,
+            -- just free up its register for use.
+            -- 
+            (temp,my_reg,slot):_ -> do
+               spills' <- do_load reading loc my_reg spills
+               let     
+                 assig1  = addToUFM assig temp (InMem slot)
+                 assig2  = addToUFM assig1 r (InReg my_reg)
+               -- in
+               setAssigR assig2
+               allocateRegsAndSpill reading keep spills' (my_reg:alloc) rs
+
+            -- otherwise, we need to spill a temporary that currently
+            -- resides in a register.
+            [] -> do
+               let
+                 (temp_to_push_out, my_reg) = head candidates2
+                 -- TODO: plenty of room for optimisation in choosing which temp
+                 -- to spill.  We just pick the first one that isn't used in 
+                 -- the current instruction for now.
+               -- in
+               (spill_insn,slot) <- spillR (RealReg my_reg)
+               let     
+                 assig1  = addToUFM assig temp_to_push_out (InMem slot)
+                 assig2  = addToUFM assig1 r (InReg my_reg)
+               -- in
+               setAssigR assig2
+               spills' <- do_load reading loc my_reg spills
+               allocateRegsAndSpill reading keep (spill_insn:spills')
+                       (my_reg:alloc) rs
+  where
+       -- load up a spilled temporary if we need to
+       do_load True (Just (InMem slot)) reg spills = do
+           insn <- loadR (RealReg reg) slot
+          return (insn : spills)
+       do_load _ _ _ spills = 
+          return spills
+
+-- -----------------------------------------------------------------------------
+-- Joining a jump instruction to its targets
+
+-- The first time we encounter a jump to a particular basic block, we
+-- record the assignment of temporaries.  The next time we encounter a
+-- jump to the same block, we compare our current assignment to the
+-- stored one.  They might be different if spilling has occrred in one
+-- branch; so some fixup code will be required to match up the
+-- assignments.
+
+joinToTargets
+       :: BlockMap RegSet
+       -> [NatBasicBlock]
+       -> Instr
+       -> [BlockId]
+       -> RegM ([NatBasicBlock], Instr)
+
+joinToTargets block_live new_blocks instr []
+  = return (new_blocks, instr)
+joinToTargets block_live new_blocks instr (dest:dests) = do
+  block_assig <- getBlockAssigR
+  assig <- getAssigR
+  let
+       -- adjust the assignment to remove any registers which are not
+       -- live on entry to the destination block.
+       adjusted_assig = 
+         listToUFM [ (reg,loc) | reg <- live, 
+                                 Just loc <- [lookupUFM assig reg] ]
+  -- in
+  case lookupUFM block_assig dest of
+       -- Nothing <=> this is the first time we jumped to this
+       -- block.
+       Nothing -> do
+         freeregs <- getFreeRegsR
+         stack <- getStackR
+         setBlockAssigR (addToUFM block_assig dest 
+                               (freeregs,stack,adjusted_assig))
+         joinToTargets block_live new_blocks instr dests
+
+       Just (freeregs,stack,dest_assig)
+          | ufmToList dest_assig == ufmToList adjusted_assig
+          -> -- ok, the assignments match
+            joinToTargets block_live new_blocks instr dests
+          | otherwise
+          -> -- need fixup code
+            panic "joinToTargets: ToDo: need fixup code"
+  where
+       live = uniqSetToList (lookItUp "joinToTargets" block_live dest)
+
+-- -----------------------------------------------------------------------------
+-- The register allocator's monad.  
+
+-- Here we keep all the state that the register allocator keeps track
+-- of as it walks the instructions in a basic block.
+
+data RA_State 
+  = RA_State {
+       ra_blockassig :: BlockAssignment,
+               -- The current mapping from basic blocks to 
+               -- the register assignments at the beginning of that block.
+       ra_freeregs   :: FreeRegs,      -- free machine registers
+       ra_assig      :: RegMap Loc,    -- assignment of temps to locations
+       ra_delta      :: Int,           -- current stack delta
+       ra_stack      :: FreeStack      -- free stack slots for spilling
+  }
+
+newtype RegM a = RegM { unReg :: RA_State -> (# RA_State, a #) }
+
+instance Monad RegM where
+  m >>= k   =  RegM $ \s -> case unReg m s of { (# s, a #) -> unReg (k a) s }
+  return a  =  RegM $ \s -> (# s, a #)
+
+runR :: BlockAssignment -> FreeRegs -> RegMap Loc -> FreeStack -> RegM a ->
+  (BlockAssignment, a)
+runR block_assig freeregs assig stack thing =
+  case unReg thing (RA_State{ ra_blockassig=block_assig, ra_freeregs=freeregs,
+                       ra_assig=assig, ra_delta=0{-???-}, ra_stack=stack }) of
+       (# RA_State{ ra_blockassig=block_assig }, returned_thing #)
+               -> (block_assig, returned_thing)
+
+spillR :: Reg -> RegM (Instr, Int)
+spillR reg = RegM $ \ s@RA_State{ra_delta=delta, ra_stack=stack} ->
+  let (stack',slot) = getFreeStackSlot stack
+      instr  = mkSpillInstr reg delta slot
+  in
+  (# s{ra_stack=stack'}, (instr,slot) #)
+
+loadR :: Reg -> Int -> RegM Instr
+loadR reg slot = RegM $ \ s@RA_State{ra_delta=delta, ra_stack=stack} ->
+  (# s, mkLoadInstr reg delta slot #)
+
+freeSlotR :: Int -> RegM ()
+freeSlotR slot = RegM $ \ s@RA_State{ra_stack=stack} ->
+  (# s{ra_stack=freeStackSlot stack slot}, () #)
+
+getFreeRegsR :: RegM FreeRegs
+getFreeRegsR = RegM $ \ s@RA_State{ra_freeregs = freeregs} ->
+  (# s, freeregs #)
+
+setFreeRegsR :: FreeRegs -> RegM ()
+setFreeRegsR regs = RegM $ \ s ->
+  (# s{ra_freeregs = regs}, () #)
+
+getAssigR :: RegM (RegMap Loc)
+getAssigR = RegM $ \ s@RA_State{ra_assig = assig} ->
+  (# s, assig #)
+
+setAssigR :: RegMap Loc -> RegM ()
+setAssigR assig = RegM $ \ s ->
+  (# s{ra_assig=assig}, () #)
+
+getStackR :: RegM FreeStack
+getStackR = RegM $ \ s@RA_State{ra_stack = stack} ->
+  (# s, stack #)
+
+setStackR :: FreeStack -> RegM ()
+setStackR stack = RegM $ \ s ->
+  (# s{ra_stack=stack}, () #)
+
+getBlockAssigR :: RegM BlockAssignment
+getBlockAssigR = RegM $ \ s@RA_State{ra_blockassig = assig} ->
+  (# s, assig #)
+
+setBlockAssigR :: BlockAssignment -> RegM ()
+setBlockAssigR assig = RegM $ \ s ->
+  (# s{ra_blockassig = assig}, () #)
+
+setDeltaR :: Int -> RegM ()
+setDeltaR n = RegM $ \ s ->
+  (# s{ra_delta = n}, () #)
+
+-- -----------------------------------------------------------------------------
+-- Utils
+
+#ifdef DEBUG
+my_fromJust s p Nothing  = pprPanic ("fromJust: " ++ s) p
+my_fromJust s p (Just x) = x
+#else
+my_fromJust _ _ = fromJust
+#endif
+
+lookItUp :: Uniquable b => String -> UniqFM a -> b -> a
+lookItUp str fm x = my_fromJust str (ppr (getUnique x)) (lookupUFM fm x)
diff --git a/ghc/compiler/nativeGen/Stix.hi-boot b/ghc/compiler/nativeGen/Stix.hi-boot
deleted file mode 100644 (file)
index 76cfdab..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-_interface_ Stix 1
-_exports_
-Stix StixTree;
-_declarations_
-1 data StixTree;
diff --git a/ghc/compiler/nativeGen/Stix.lhs b/ghc/compiler/nativeGen/Stix.lhs
deleted file mode 100644 (file)
index 9f4a5ea..0000000
+++ /dev/null
@@ -1,629 +0,0 @@
-%
-% (c) The AQUA Project, Glasgow University, 1993-1998
-%
-
-\begin{code}
-module Stix (
-       CodeSegment(..), StixReg(..), StixExpr(..), StixVReg(..),
-        StixStmt(..), mkStAssign, StixStmtList,
-       pprStixStmts, pprStixStmt, pprStixExpr, pprStixReg,
-        stixStmt_CountTempUses, stixStmt_Subst,
-        liftStrings, repOfStixExpr,
-       DestInfo(..), hasDestInfo,
-
-       stgBaseReg, stgNode, stgSp, stgSpLim, 
-        stgHp, stgHpLim, stgHpAlloc, stgTagReg, stgR9, stgR10, 
-       stgCurrentTSO, stgCurrentNursery,
-
-       fixedHS, arrWordsHS, arrPtrsHS,
-
-        NatM, initNat, thenNat, returnNat, 
-        mapNat, mapAndUnzipNat, mapAccumLNat,
-        getUniqueNat, getDeltaNat, setDeltaNat,
-        NatM_State, mkNatM_State,
-        uniqOfNatM_State, deltaOfNatM_State, importsOfNatM_State,
-       addImportNat,
-
-       getUniqLabelNCG, getNatLabelNCG,
-        ncgPrimopMoan,
-
-       -- Information about the target arch
-        ncg_target_is_32bit
-    ) where
-
-#include "HsVersions.h"
-
-import AbsCSyn         ( node, tagreg, MagicId(..) )
-import AbsCUtils       ( magicIdPrimRep )
-import ForeignCall     ( CCallConv )
-import CLabel          ( mkAsmTempLabel, CLabel, pprCLabel )
-import PrimRep          ( PrimRep(..) )
-import MachOp          ( MachOp(..), pprMachOp, resultRepOfMachOp )
-import Unique           ( Unique )
-import SMRep           ( fixedHdrSize, arrWordsHdrSize, arrPtrsHdrSize )
-import UniqSupply      ( UniqSupply, splitUniqSupply, uniqFromSupply,
-                          UniqSM, thenUs, returnUs, getUniqueUs )
-import Constants       ( wORD_SIZE )
-import Outputable
-import FastTypes
-import FastString
-
-import UNSAFE_IO       ( unsafePerformIO )
-
-import Ratio           ( Rational )
-import IO              ( hPutStrLn, stderr )
-\end{code}
-
-Two types, StixStmt and StixValue, define Stix.
-
-\begin{code}
-
--- Non-value trees; ones executed for their side-effect.
-data StixStmt
-
-  = -- Directive for the assembler to change segment
-    StSegment CodeSegment
-
-    -- Assembly-language comments
-  | StComment FastString
-
-    -- Assignments are typed to determine size and register placement.
-    -- Assign a value to a StixReg
-  | StAssignReg PrimRep StixReg StixExpr
-
-    -- Assign a value to memory.  First tree indicates the address to be
-    -- assigned to, so there is an implicit dereference here.
-  | StAssignMem PrimRep StixExpr StixExpr -- dst, src
-
-    -- A simple assembly label that we might jump to.
-  | StLabel CLabel
-
-    -- A function header and footer
-  | StFunBegin CLabel
-  | StFunEnd CLabel
-
-    -- An unconditional jump. This instruction may or may not jump
-    -- out of the register allocation domain (basic block, more or
-    -- less).  For correct register allocation when this insn is used
-    -- to jump through a jump table, we optionally allow a list of
-    -- the exact targets to be attached, so that the allocator can
-    -- easily construct the exact flow edges leaving this insn.
-    -- Dynamic targets are allowed.
-  | StJump DestInfo StixExpr
-
-    -- A fall-through, from slow to fast
-  | StFallThrough CLabel
-
-    -- A conditional jump. This instruction can be non-terminal :-)
-    -- Only static, local, forward labels are allowed
-  | StCondJump CLabel StixExpr
-
-    -- Raw data (as in an info table).
-  | StData PrimRep [StixExpr]
-    -- String which has been lifted to the top level (sigh).
-  | StDataString FastString
-
-    -- A value computed only for its side effects; result is discarded
-    -- (A handy trapdoor to allow CCalls with no results to appear as
-    -- statements).
-  | StVoidable StixExpr
-
-
--- Helper fn to make Stix assignment statements where the 
--- lvalue masquerades as a StixExpr.  A kludge that should
--- be done away with.
-mkStAssign :: PrimRep -> StixExpr -> StixExpr -> StixStmt
-mkStAssign rep (StReg reg) rhs  
-   = StAssignReg rep reg rhs
-mkStAssign rep (StInd rep' addr) rhs 
-   | rep `isCloseEnoughTo` rep'
-   = StAssignMem rep addr rhs
-   | otherwise
-   = --pprPanic "Stix.mkStAssign: mismatched reps" (ppr rep <+> ppr rep')
-     --trace ("Stix.mkStAssign: mismatched reps: " ++ showSDoc (ppr rep <+> ppr rep')) (
-     StAssignMem rep addr rhs
-     --)
-     where
-        isCloseEnoughTo r1 r2
-           = r1 == r2 || (wordIsh r1 && wordIsh r2)
-        wordIsh rep
-           = rep `elem` [IntRep, WordRep, PtrRep, AddrRep, CodePtrRep, RetRep ]
-                        -- determined by looking at PrimRep.showPrimRep
-
--- Stix trees which denote a value.
-data StixExpr
-  = -- Literals
-    StInt      Integer     -- ** add Kind at some point
-  | StFloat    Rational
-  | StDouble   Rational
-  | StString   FastString
-  | StCLbl     CLabel      -- labels that we might index into
-
-    -- Abstract registers of various kinds
-  | StReg StixReg
-
-    -- A typed offset from a base location
-  | StIndex PrimRep StixExpr StixExpr -- kind, base, offset
-
-    -- An indirection from an address to its contents.
-  | StInd PrimRep StixExpr
-
-    -- Primitive Operations
-  | StMachOp MachOp [StixExpr]
-
-    -- Calls to C functions
-  | StCall (Either FastString StixExpr) -- Left: static, Right: dynamic
-           CCallConv PrimRep [StixExpr]
-
-
--- What's the PrimRep of the value denoted by this StixExpr?
-repOfStixExpr :: StixExpr -> PrimRep
-repOfStixExpr (StInt _)       = IntRep
-repOfStixExpr (StFloat _)     = FloatRep
-repOfStixExpr (StDouble _)    = DoubleRep
-repOfStixExpr (StString _)    = PtrRep
-repOfStixExpr (StCLbl _)      = PtrRep
-repOfStixExpr (StReg reg)     = repOfStixReg reg
-repOfStixExpr (StIndex _ _ _) = PtrRep
-repOfStixExpr (StInd rep _)   = rep
-repOfStixExpr (StCall target conv retrep args) = retrep
-repOfStixExpr (StMachOp mop args) = resultRepOfMachOp mop
-
-
--- used by insnFuture in RegAllocInfo.lhs
-data DestInfo
-   = NoDestInfo             -- no supplied dests; infer from context
-   | DestInfo [CLabel]      -- precisely these dests and no others
-
-hasDestInfo NoDestInfo   = False
-hasDestInfo (DestInfo _) = True
-
-pprDests :: DestInfo -> SDoc
-pprDests NoDestInfo      = text "NoDestInfo"
-pprDests (DestInfo dsts) = brackets (hsep (map pprCLabel dsts))
-
-
-pprStixStmts :: [StixStmt] -> SDoc
-pprStixStmts ts 
-  = vcat [
-       vcat (map pprStixStmt ts),
-       char ' ',
-       char ' '
-    ]
-
-
-pprStixExpr :: StixExpr -> SDoc
-pprStixExpr t 
-   = case t of
-       StCLbl lbl       -> pprCLabel lbl
-       StInt i          -> (if i < 0 then parens else id) (integer i)
-       StFloat rat      -> parens (text "Float" <+> rational rat)
-       StDouble        rat     -> parens (text "Double" <+> rational rat)
-       StString str     -> parens (text "Str `" <> ftext str <> char '\'')
-       StIndex k b o    -> parens (pprStixExpr b <+> char '+' <> 
-                                   ppr k <+> pprStixExpr o)
-       StInd k t        -> ppr k <> char '[' <> pprStixExpr t <> char ']'
-       StReg reg        -> pprStixReg reg
-       StMachOp op args -> pprMachOp op 
-                           <> parens (hsep (punctuate comma (map pprStixExpr args)))
-       StCall fn cc k args
-                        -> parens (text "Call" <+> targ <+>
-                                   ppr cc <+> ppr k <+> 
-                                   hsep (map pprStixExpr args))
-                           where
-                              targ = case fn of
-                                        Left  t_static -> ftext t_static
-                                        Right t_dyn    -> parens (pprStixExpr t_dyn)
-
-pprStixStmt :: StixStmt -> SDoc
-pprStixStmt t 
-   = case t of
-       StSegment cseg   -> parens (ppCodeSegment cseg)
-       StComment str    -> parens (text "Comment" <+> ftext str)
-       StAssignReg pr reg rhs
-                        -> pprStixReg reg <> text "  :=" <> ppr pr
-                                          <> text "  " <> pprStixExpr rhs
-       StAssignMem pr addr rhs
-                        -> ppr pr <> char '[' <> pprStixExpr addr <> char ']'
-                                  <> text "  :=" <> ppr pr
-                                  <> text "  " <> pprStixExpr rhs
-       StLabel ll       -> pprCLabel ll <+> char ':'
-       StFunBegin ll    -> char ' ' $$ parens (text "FunBegin" <+> pprCLabel ll)
-       StFunEnd ll      -> parens (text "FunEnd" <+> pprCLabel ll)
-       StJump dsts t    -> parens (text "Jump" <+> pprDests dsts <+> pprStixExpr t)
-       StFallThrough ll -> parens (text "FallThru" <+> pprCLabel ll)
-       StCondJump l t   -> parens (text "JumpC" <+> pprCLabel l 
-                                                <+> pprStixExpr t)
-       StData k ds      -> parens (text "Data" <+> ppr k <+>
-                                   hsep (map pprStixExpr ds))
-       StDataString str -> parens (text "DataString" <+> ppr str)
-       StVoidable expr  -> text "(void)" <+> pprStixExpr expr
-\end{code}
-
-Stix registers can have two forms.  They {\em may} or {\em may not}
-map to real, machine-level registers.
-
-\begin{code}
-data StixReg
-  = StixMagicId MagicId        -- Regs which are part of the abstract machine model
-
-  | StixTemp StixVReg   -- "Regs" which model local variables (CTemps) in
-                       -- the abstract C.
-
-pprStixReg (StixMagicId mid)  = ppMId mid
-pprStixReg (StixTemp temp)    = pprStixVReg temp
-
-repOfStixReg (StixTemp (StixVReg u pr)) = pr
-repOfStixReg (StixMagicId mid)          = magicIdPrimRep mid
-
-data StixVReg
-   = StixVReg Unique PrimRep
-
-pprStixVReg (StixVReg u pr) = hcat [text "VReg(", ppr u, colon, ppr pr, char ')']
-
-
-
-ppMId BaseReg              = text "BaseReg"
-ppMId (VanillaReg kind n)  = hcat [ppr kind, text "IntReg(", 
-                                   int (iBox n), char ')']
-ppMId (FloatReg n)         = hcat [text "FltReg(", int (iBox n), char ')']
-ppMId (DoubleReg n)        = hcat [text "DblReg(", int (iBox n), char ')']
-ppMId (LongReg kind n)     = hcat [ppr kind, text "LongReg(", 
-                                   int (iBox n), char ')']
-ppMId Sp                   = text "Sp"
-ppMId SpLim                = text "SpLim"
-ppMId Hp                   = text "Hp"
-ppMId HpLim                = text "HpLim"
-ppMId CurCostCentre        = text "CCC"
-ppMId VoidReg              = text "VoidReg"
-\end{code}
-
-We hope that every machine supports the idea of data segment and text
-segment (or that it has no segments at all, and we can lump these
-together).
-
-\begin{code}
-data CodeSegment 
-   = DataSegment 
-   | TextSegment 
-   | RoDataSegment 
-     deriving (Eq, Show)
-
-ppCodeSegment = text . show
-
-type StixStmtList = [StixStmt] -> [StixStmt]
-\end{code}
-
-Stix Trees for STG registers:
-\begin{code}
-stgBaseReg, stgNode, stgSp, stgSpLim, stgHp, stgHpLim :: StixReg
-
-stgBaseReg         = StixMagicId BaseReg
-stgNode            = StixMagicId node
-stgTagReg          = StixMagicId tagreg
-stgSp              = StixMagicId Sp
-stgSpLim           = StixMagicId SpLim
-stgHp              = StixMagicId Hp
-stgHpLim           = StixMagicId HpLim
-stgHpAlloc         = StixMagicId HpAlloc
-stgCurrentTSO      = StixMagicId CurrentTSO
-stgCurrentNursery   = StixMagicId CurrentNursery
-stgR9               = StixMagicId (VanillaReg WordRep (_ILIT 9))
-stgR10              = StixMagicId (VanillaReg WordRep (_ILIT 10))
-
-getNatLabelNCG :: NatM CLabel
-getNatLabelNCG
-  = getUniqueNat `thenNat` \ u ->
-    returnNat (mkAsmTempLabel u)
-
-getUniqLabelNCG :: UniqSM CLabel
-getUniqLabelNCG
-  = getUniqueUs `thenUs` \ u ->
-    returnUs (mkAsmTempLabel u)
-
-fixedHS     = StInt (toInteger fixedHdrSize)
-arrWordsHS  = StInt (toInteger arrWordsHdrSize)
-arrPtrsHS   = StInt (toInteger arrPtrsHdrSize)
-\end{code}
-
-Stix optimisation passes may wish to find out how many times a
-given temporary appears in a tree, so as to be able to decide
-whether or not to inline the assignment's RHS at usage site(s).
-
-\begin{code}
-stixExpr_CountTempUses :: Unique -> StixExpr -> Int
-stixExpr_CountTempUses u t 
-   = let qs = stixStmt_CountTempUses u
-         qe = stixExpr_CountTempUses u
-         qr = stixReg_CountTempUses u
-     in
-     case t of
-        StReg      reg            -> qr reg
-        StIndex    pk t1 t2       -> qe t1 + qe t2
-        StInd      pk t1          -> qe t1
-        StMachOp   mop ts         -> sum (map qe ts)
-        StCall     (Left nm) cconv pk ts -> sum (map qe ts)
-        StCall     (Right f) cconv pk ts -> sum (map qe ts) + qe f
-        StInt _          -> 0
-        StFloat _        -> 0
-        StDouble _       -> 0
-        StString _       -> 0
-        StCLbl _         -> 0
-
-stixStmt_CountTempUses :: Unique -> StixStmt -> Int
-stixStmt_CountTempUses u t 
-   = let qe = stixExpr_CountTempUses u
-         qr = stixReg_CountTempUses u
-         qv = stixVReg_CountTempUses u
-     in
-     case t of
-        StAssignReg pk reg rhs  -> qr reg + qe rhs
-        StAssignMem pk addr rhs -> qe addr + qe rhs
-        StJump     dsts t1      -> qe t1
-        StCondJump lbl t1       -> qe t1
-        StData     pk ts        -> sum (map qe ts)
-        StVoidable expr  -> qe expr
-        StSegment _      -> 0
-        StFunBegin _     -> 0
-        StFunEnd _       -> 0
-        StFallThrough _  -> 0
-        StComment _      -> 0
-        StLabel _        -> 0
-        StDataString _   -> 0
-
-stixReg_CountTempUses u reg
-   = case reg of 
-        StixTemp vreg    -> stixVReg_CountTempUses u vreg
-        StixMagicId mid  -> 0
-
-stixVReg_CountTempUses u (StixVReg uu pr)
-   = if u == uu then 1 else 0
-\end{code}
-
-If we do decide to inline a temporary binding, the following functions
-do the biz.
-
-\begin{code}
-stixStmt_Subst :: Unique -> StixExpr -> StixStmt -> StixStmt
-stixStmt_Subst u new_u in_this_tree
-   = stixStmt_MapUniques f in_this_tree
-     where
-        f :: Unique -> Maybe StixExpr
-        f uu = if uu == u then Just new_u else Nothing
-
-
-stixExpr_MapUniques :: (Unique -> Maybe StixExpr) -> StixExpr -> StixExpr
-stixExpr_MapUniques f t
-   = let qe = stixExpr_MapUniques f
-         qs = stixStmt_MapUniques f
-         qr = stixReg_MapUniques f
-     in
-     case t of
-        StReg reg -> case qr reg of
-                     Nothing -> StReg reg
-                     Just xx -> xx
-        StIndex    pk t1 t2       -> StIndex    pk (qe t1) (qe t2)
-        StInd      pk t1          -> StInd      pk (qe t1)
-        StMachOp   mop args       -> StMachOp   mop (map qe args)
-        StCall     (Left nm) cconv pk ts -> StCall (Left nm) cconv pk (map qe ts)
-        StCall     (Right f) cconv pk ts -> StCall (Right (qe f)) cconv pk (map qe ts)
-        StInt _          -> t
-        StFloat _        -> t
-        StDouble _       -> t
-        StString _       -> t
-        StCLbl _         -> t
-
-stixStmt_MapUniques :: (Unique -> Maybe StixExpr) -> StixStmt -> StixStmt
-stixStmt_MapUniques f t
-   = let qe = stixExpr_MapUniques f
-         qs = stixStmt_MapUniques f
-         qr = stixReg_MapUniques f
-         qv = stixVReg_MapUniques f
-     in
-     case t of
-        StAssignReg pk reg rhs
-           -> case qr reg of
-                 Nothing -> StAssignReg pk reg (qe rhs)
-                 Just xx -> panic "stixStmt_MapUniques:StAssignReg"
-        StAssignMem pk addr rhs   -> StAssignMem pk (qe addr) (qe rhs)
-        StJump     dsts t1        -> StJump     dsts (qe t1)
-        StCondJump lbl t1         -> StCondJump lbl (qe t1)
-        StData     pk ts          -> StData     pk (map qe ts)
-        StVoidable expr           -> StVoidable (qe expr)
-        StSegment _      -> t
-        StLabel _        -> t
-        StFunBegin _     -> t
-        StFunEnd _       -> t
-        StFallThrough _  -> t
-        StComment _      -> t
-        StDataString _   -> t
-
-
-stixReg_MapUniques :: (Unique -> Maybe StixExpr) -> StixReg -> Maybe StixExpr
-stixReg_MapUniques f reg
-   = case reg of
-        StixMagicId mid -> Nothing
-        StixTemp vreg   -> stixVReg_MapUniques f vreg
-
-stixVReg_MapUniques :: (Unique -> Maybe StixExpr) -> StixVReg -> Maybe StixExpr
-stixVReg_MapUniques f (StixVReg uu pr)
-   = f uu
-\end{code}
-
-\begin{code}
--- Lift StStrings out of top-level StDatas, putting them at the end of
--- the block, and replacing them with StCLbls which refer to the lifted-out strings. 
-{- Motivation for this hackery provided by the following bug:
-   Stix:
-      (DataSegment)
-      Bogon.ping_closure :
-      (Data P_ Addr.A#_static_info)
-      (Data StgAddr (Str `alalal'))
-      (Data P_ (0))
-   results in:
-      .data
-              .align 8
-      .global Bogon_ping_closure
-      Bogon_ping_closure:
-              .long   Addr_Azh_static_info
-              .long   .Ln1a8
-      .Ln1a8:
-              .byte   0x61
-              .byte   0x6C
-              .byte   0x61
-              .byte   0x6C
-              .byte   0x61
-              .byte   0x6C
-              .byte   0x00
-              .long   0
-   ie, the Str is planted in-line, when what we really meant was to place
-   a _reference_ to the string there.  liftStrings will lift out all such
-   strings in top-level data and place them at the end of the block.
-
-   This is still a rather half-baked solution -- to do the job entirely right
-   would mean a complete traversal of all the Stixes, but there's currently no
-   real need for it, and it would be slow.  Also, potentially there could be
-   literal types other than strings which need lifting out?
--}
-
-liftStrings :: [StixStmt] -> UniqSM [StixStmt]
-liftStrings stmts
-   = liftStrings_wrk stmts [] []
-
-liftStrings_wrk :: [StixStmt]    -- originals
-                -> [StixStmt]    -- (reverse) originals with strings lifted out
-                -> [(CLabel, FastString)]   -- lifted strs, and their new labels
-                -> UniqSM [StixStmt]
-
--- First, examine the original trees and lift out strings in top-level StDatas.
-liftStrings_wrk (st:sts) acc_stix acc_strs
-   = case st of
-        StData sz datas
-           -> lift datas acc_strs      `thenUs` \ (datas_done, acc_strs1) ->
-              liftStrings_wrk sts ((StData sz datas_done):acc_stix) acc_strs1
-        other 
-           -> liftStrings_wrk sts (other:acc_stix) acc_strs
-     where
-        -- Handle a top-level StData
-        lift []     acc_strs = returnUs ([], acc_strs)
-        lift (d:ds) acc_strs
-           = lift ds acc_strs          `thenUs` \ (ds_done, acc_strs1) ->
-             case d of
-                StString s 
-                   -> getUniqueUs      `thenUs` \ unq ->
-                      let lbl = mkAsmTempLabel unq in
-                      returnUs ((StCLbl lbl):ds_done, ((lbl,s):acc_strs1))
-                other
-                   -> returnUs (other:ds_done, acc_strs1)
-
--- When we've run out of original trees, emit the lifted strings.
-liftStrings_wrk [] acc_stix acc_strs
-   = returnUs (reverse acc_stix ++ concatMap f acc_strs)
-     where
-        f (lbl,str) = [StSegment RoDataSegment, 
-                       StLabel lbl, 
-                       StDataString str, 
-                       StSegment TextSegment]
-\end{code}
-
-The NCG's monad.
-
-The monad keeps a UniqSupply, the current stack delta and
-a list of imported entities, which is only used for
-Darwin (Mac OS X).
-
-\begin{code}
-data NatM_State = NatM_State UniqSupply Int [FastString]
-type NatM result = NatM_State -> (result, NatM_State)
-
-mkNatM_State :: UniqSupply -> Int -> NatM_State
-mkNatM_State us delta = NatM_State us delta []
-
-uniqOfNatM_State  (NatM_State us delta imports) = us
-deltaOfNatM_State (NatM_State us delta imports) = delta
-importsOfNatM_State (NatM_State us delta imports) = imports
-
-initNat :: NatM_State -> NatM a -> (a, NatM_State)
-initNat init_st m = case m init_st of { (r,st) -> (r,st) }
-
-thenNat :: NatM a -> (a -> NatM b) -> NatM b
-thenNat expr cont st
-  = case expr st of { (result, st') -> cont result st' }
-
-returnNat :: a -> NatM a
-returnNat result st = (result, st)
-
-mapNat :: (a -> NatM b) -> [a] -> NatM [b]
-mapNat f []     = returnNat []
-mapNat f (x:xs)
-  = f x          `thenNat` \ r  ->
-    mapNat f xs  `thenNat` \ rs ->
-    returnNat (r:rs)
-
-mapAndUnzipNat :: (a -> NatM (b,c))   -> [a] -> NatM ([b],[c])
-mapAndUnzipNat f [] = returnNat ([],[])
-mapAndUnzipNat f (x:xs)
-  = f x                        `thenNat` \ (r1,  r2)  ->
-    mapAndUnzipNat f xs        `thenNat` \ (rs1, rs2) ->
-    returnNat (r1:rs1, r2:rs2)
-
-mapAccumLNat :: (acc -> x -> NatM (acc, y))
-                -> acc
-               -> [x]
-               -> NatM (acc, [y])
-
-mapAccumLNat f b []
-  = returnNat (b, [])
-mapAccumLNat f b (x:xs)
-  = f b x                          `thenNat` \ (b__2, x__2) ->
-    mapAccumLNat f b__2 xs         `thenNat` \ (b__3, xs__2) ->
-    returnNat (b__3, x__2:xs__2)
-
-
-getUniqueNat :: NatM Unique
-getUniqueNat (NatM_State us delta imports)
-    = case splitUniqSupply us of
-         (us1,us2) -> (uniqFromSupply us1, (NatM_State us2 delta imports))
-
-getDeltaNat :: NatM Int
-getDeltaNat st@(NatM_State us delta imports)
-   = (delta, st)
-
-setDeltaNat :: Int -> NatM ()
-setDeltaNat delta (NatM_State us _ imports)
-   = ((), NatM_State us delta imports)
-
-addImportNat :: FastString -> NatM ()
-addImportNat imp (NatM_State us delta imports)
-   = ((), NatM_State us delta (imp:imports))
-\end{code}
-
-Giving up in a not-too-inelegant way.
-
-\begin{code}
-ncgPrimopMoan :: String -> SDoc -> a
-ncgPrimopMoan msg pp_rep
-   = unsafePerformIO (
-        hPutStrLn stderr (
-        "\n" ++
-        "You've fallen across an unimplemented case in GHC's native code generation\n" ++
-        "machinery.  You can work around this for the time being by compiling\n" ++ 
-        "this module via the C route, by giving the flag -fvia-C.\n" ++
-        "The panic below contains information, intended for the GHC implementors,\n" ++
-        "about the exact place where GHC gave up.  Please send it to us\n" ++
-        "at glasgow-haskell-bugs@haskell.org, so as to encourage us to fix this.\n"
-        )
-     )
-     `seq`
-     pprPanic msg pp_rep
-\end{code}
-
-Information about the target.
-
-\begin{code}
-
-ncg_target_is_32bit :: Bool
-ncg_target_is_32bit | wORD_SIZE == 4 = True
-                    | wORD_SIZE == 8 = False
-
-\end{code}
diff --git a/ghc/compiler/nativeGen/StixMacro.lhs b/ghc/compiler/nativeGen/StixMacro.lhs
deleted file mode 100644 (file)
index be32d65..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-%
-% (c) The AQUA Project, Glasgow University, 1993-1998
-%
-
-\begin{code}
-module StixMacro ( macroCode, checkCode ) where
-
-#include "HsVersions.h"
-#include "nativeGen/NCG.h"
-
-import {-# SOURCE #-} StixPrim ( amodeToStix )
-
-import MachRegs
-import AbsCSyn         ( CStmtMacro(..), CAddrMode, tagreg, CCheckMacro(..) )
-import Constants       ( uF_RET, uF_UPDATEE, uF_SIZE )
-import ForeignCall     ( CCallConv(..) )
-import MachOp          ( MachOp(..) )
-import PrimRep         ( PrimRep(..) )
-import Stix
-import Panic           ( panic )
-import UniqSupply      ( returnUs, thenUs, UniqSM )
-import CLabel          ( mkBlackHoleInfoTableLabel, mkIndStaticInfoLabel,
-                         mkIndInfoLabel, mkUpdInfoLabel, mkRtsGCEntryLabel )
-\end{code}
---------------------------------------------------------------------------------
-The @ARGS_CHK_A{_LOAD_NODE}@ macros check for sufficient arguments on
-the A stack, and perform a tail call to @UpdatePAP@ if the arguments are
-not there.  The @_LOAD_NODE@ version also loads R1 with an appropriate
-closure address.
-
-\begin{code}
-macroCode
-    :: CStmtMacro          -- statement macro
-    -> [StixExpr]          -- args
-    -> UniqSM StixStmtList
-\end{code}
-
------------------------------------------------------------------------------
-Updating a CAF
-
-@UPD_CAF@ involves changing the info pointer of the closure, and
-adding an indirection.
-
-\begin{code}
-macroCode UPD_CAF [cafptr,bhptr]
-  = let
-       new_caf = StVoidable (StCall (Left FSLIT("newCAF")) CCallConv VoidRep [cafptr])
-       a1 = StAssignMem PtrRep (StIndex PtrRep cafptr fixedHS) bhptr
-       a2 = StAssignMem PtrRep cafptr ind_static_info
-    in
-    returnUs (\xs -> new_caf : a1 : a2 : xs)
-\end{code}
-
------------------------------------------------------------------------------
-Blackholing
-
-We do lazy blackholing: no need to overwrite thunks with blackholes
-the minute they're entered, as long as we do it before a context
-switch or garbage collection, that's ok.
-
-Don't blackhole single entry closures, for the following reasons:
-       
-       - if the compiler has decided that they won't be entered again,
-         that probably means that nothing has a pointer to it
-         (not necessarily true, but...)
-
-       - no need to blackhole for concurrency reasons, because nothing
-         can block on the result of this computation.
-
-\begin{code}
-macroCode UPD_BH_UPDATABLE args = returnUs id
-
-macroCode UPD_BH_SINGLE_ENTRY args = returnUs id
-{-
-  = let
-       update = StAssign PtrRep (StInd PtrRep arg) bh_info
-    in
-    returnUs (\xs -> update : xs)
--}
-\end{code}
-
------------------------------------------------------------------------------
-Update frames
-
-Push an update frame on the stack.
-
-\begin{code}
-macroCode PUSH_UPD_FRAME [bhptr, _{-0-}]
-  = let
-       frame n = StIndex PtrRep (StReg stgSp) (StInt (toInteger (n-uF_SIZE)))
-
-        -- HWL: these values are *wrong* in a GranSim setup; ToDo: fix
-       a1 = StAssignMem PtrRep (frame uF_RET)     upd_frame_info
-       a4 = StAssignMem PtrRep (frame uF_UPDATEE) bhptr
-    in
-    returnUs (\xs -> a1 : a4 : xs)
-\end{code}
-
------------------------------------------------------------------------------
-Setting the tag register
-
-This one only applies if we have a machine register devoted to TagReg.
-
-\begin{code}
-macroCode SET_TAG [tag]
-  = case get_MagicId_reg_or_addr tagreg of
-       Right baseRegAddr 
-          -> returnUs id
-       Left  realreg 
-          -> let a1 = StAssignReg IntRep (StixMagicId tagreg) tag
-             in returnUs ( \xs -> a1 : xs )
-\end{code}
-
------------------------------------------------------------------------------
-
-\begin{code}
-macroCode REGISTER_IMPORT [arg]
-   = returnUs (
-       \xs -> StAssignMem WordRep (StReg stgSp) arg
-            : StAssignReg PtrRep  stgSp (StMachOp MO_Nat_Add [StReg stgSp, StInt 4])
-            : xs
-     )
-
-macroCode REGISTER_FOREIGN_EXPORT [arg]
-   = returnUs (
-       \xs -> StVoidable (
-                  StCall (Left FSLIT("getStablePtr")) CCallConv VoidRep 
-                         [arg]
-               )
-            : xs
-     )
-
-macroCode other args
-   = panic "StixMacro.macroCode"
-\end{code}
-
-Do the business for a @HEAP_CHK@, having converted the args to Trees
-of StixOp.
-
------------------------------------------------------------------------------
-Let's make sure that these CAFs are lifted out, shall we?
-
-\begin{code}
--- Some common labels
-
-bh_info, ind_static_info :: StixExpr
-
-bh_info        = StCLbl mkBlackHoleInfoTableLabel
-ind_static_info        = StCLbl mkIndStaticInfoLabel
-upd_frame_info = StCLbl mkUpdInfoLabel
-
--- Some common call trees
-\end{code}
-
------------------------------------------------------------------------------
-Heap/Stack checks
-
-\begin{code}
-checkCode :: CCheckMacro -> [CAddrMode] -> StixStmtList -> UniqSM StixStmtList
-checkCode macro args assts
-  = getUniqLabelNCG            `thenUs` \ ulbl_fail ->
-    getUniqLabelNCG            `thenUs` \ ulbl_pass ->
-
-    let        args_stix        = map amodeToStix args
-       newHp wds        = StIndex PtrRep (StReg stgHp) wds
-       assign_hp wds    = StAssignReg PtrRep stgHp (newHp wds)
-       hp_alloc wds     = StAssignReg IntRep stgHpAlloc wds
-       test_hp          = StMachOp MO_NatU_Le [StReg stgHp, StReg stgHpLim]
-       cjmp_hp          = StCondJump ulbl_pass test_hp
-       newSp wds        = StIndex PtrRep (StReg stgSp) (StMachOp MO_NatS_Neg [wds])
-       test_sp_pass wds = StMachOp MO_NatU_Ge [newSp wds, StReg stgSpLim]
-       test_sp_fail wds = StMachOp MO_NatU_Lt [newSp wds, StReg stgSpLim]
-       cjmp_sp_pass wds = StCondJump ulbl_pass (test_sp_pass wds)
-       cjmp_sp_fail wds = StCondJump ulbl_fail (test_sp_fail wds)
-       assign_ret r ret = mkStAssign CodePtrRep r ret
-
-       fail = StLabel ulbl_fail
-       join = StLabel ulbl_pass
-
-        -- see includes/StgMacros.h for explaination of these magic consts
-        aLL_NON_PTRS = 0xff
-
-        assign_liveness ptr_regs 
-           = StAssignReg WordRep stgR9
-                         (StMachOp MO_Nat_Xor [StInt aLL_NON_PTRS, ptr_regs])
-        assign_reentry reentry 
-           = StAssignReg WordRep stgR10 reentry
-    in 
-
-    returnUs (
-    case macro of
-       HP_CHK_NP      -> 
-               let [words] = args_stix
-               in  (\xs -> assign_hp words : cjmp_hp : 
-                           assts (hp_alloc words : gc_enter : join : xs))
-
-       STK_CHK_NP     -> 
-               let [words] = args_stix
-               in  (\xs -> cjmp_sp_pass words :
-                           assts (gc_enter : join : xs))
-
-       HP_STK_CHK_NP  -> 
-               let [sp_words,hp_words] = args_stix
-               in  (\xs -> cjmp_sp_fail sp_words : 
-                           assign_hp hp_words : cjmp_hp :
-                           fail :
-                           assts (hp_alloc hp_words : gc_enter
-                                  : join : xs))
-
-       HP_CHK_FUN       -> 
-               let [words] = args_stix
-               in  (\xs -> assign_hp words : cjmp_hp :
-                           assts (hp_alloc words : gc_fun : join : xs))
-
-       STK_CHK_FUN       -> 
-               let [words] = args_stix
-               in  (\xs -> cjmp_sp_pass words :
-                           assts (gc_fun : join : xs))
-
-       HP_STK_CHK_FUN    -> 
-               let [sp_words,hp_words] = args_stix
-               in  (\xs -> cjmp_sp_fail sp_words :
-                           assign_hp hp_words : cjmp_hp :
-                           fail :
-                           assts (hp_alloc hp_words
-                                 : gc_fun : join : xs))
-
-       HP_CHK_NOREGS  -> 
-               let [words] = args_stix
-               in  (\xs -> assign_hp words : cjmp_hp : 
-                           assts (hp_alloc words : gc_noregs : join : xs))
-
-       HP_CHK_UNPT_R1 -> 
-               let [words] = args_stix
-               in  (\xs -> assign_hp words : cjmp_hp : 
-                           assts (hp_alloc words : gc_unpt_r1 : join : xs))
-
-       HP_CHK_UNBX_R1 -> 
-               let [words] = args_stix
-               in  (\xs -> assign_hp words : cjmp_hp : 
-                           assts (hp_alloc words : gc_unbx_r1 : join : xs))
-
-       HP_CHK_F1      -> 
-               let [words] = args_stix
-               in  (\xs -> assign_hp words : cjmp_hp : 
-                           assts (hp_alloc words : gc_f1 : join : xs))
-
-       HP_CHK_D1      -> 
-               let [words] = args_stix
-               in  (\xs -> assign_hp words : cjmp_hp : 
-                           assts (hp_alloc words : gc_d1 : join : xs))
-
-       HP_CHK_L1      -> 
-               let [words] = args_stix
-               in  (\xs -> assign_hp words : cjmp_hp : 
-                           assts (hp_alloc words : gc_l1 : join : xs))
-
-       HP_CHK_UNBX_TUPLE  -> 
-                let [words,liveness] = args_stix
-                in (\xs -> assign_hp words : cjmp_hp :
-                           assts (hp_alloc words : assign_liveness liveness :
-                                  gc_ut : join : xs))
-    )
-
--- Various canned heap-check routines
-
-mkStJump_to_GCentry_name :: String -> StixStmt
-mkStJump_to_GCentry_name gcname
---   | opt_Static
-   = StJump NoDestInfo (StCLbl (mkRtsGCEntryLabel gcname))
---   | otherwise -- it's in a different DLL
---   = StJump (StInd PtrRep (StLitLbl True sdoc))
-
-mkStJump_to_RegTable_offw :: Int -> StixStmt
-mkStJump_to_RegTable_offw regtable_offw
---   | opt_Static
-   = StJump NoDestInfo (StInd PtrRep (get_Regtable_addr_from_offset regtable_offw))
---   | otherwise
---   do something plausible for cross-DLL jump
-
-gc_enter = mkStJump_to_RegTable_offw OFFSET_stgGCEnter1
-gc_fun   = mkStJump_to_RegTable_offw OFFSET_stgGCFun
-
-gc_noregs          = mkStJump_to_GCentry_name "stg_gc_noregs"
-gc_unpt_r1         = mkStJump_to_GCentry_name "stg_gc_unpt_r1"
-gc_unbx_r1         = mkStJump_to_GCentry_name "stg_gc_unbx_r1"
-gc_f1              = mkStJump_to_GCentry_name "stg_gc_f1"
-gc_d1              = mkStJump_to_GCentry_name "stg_gc_d1"
-gc_l1              = mkStJump_to_GCentry_name "stg_gc_l1"
-gc_ut              = mkStJump_to_GCentry_name "stg_gc_ut"
-\end{code}
diff --git a/ghc/compiler/nativeGen/StixPrim.hi-boot b/ghc/compiler/nativeGen/StixPrim.hi-boot
deleted file mode 100644 (file)
index 7997542..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-_interface_ StixPrim 1
-_exports_
-StixPrim amodeToStix;
-_declarations_
-1 amodeToStix _:_ AbsCSyn.CAddrMode -> Stix.StixExpr ;;
diff --git a/ghc/compiler/nativeGen/StixPrim.hi-boot-5 b/ghc/compiler/nativeGen/StixPrim.hi-boot-5
deleted file mode 100644 (file)
index f1b3b9e..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-__interface StixPrim 1 0 where
-__export StixPrim amodeToStix;
-1 amodeToStix :: AbsCSyn.CAddrMode -> Stix.StixExpr ;
diff --git a/ghc/compiler/nativeGen/StixPrim.hi-boot-6 b/ghc/compiler/nativeGen/StixPrim.hi-boot-6
deleted file mode 100644 (file)
index dcf9cc9..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-module StixPrim where
-
-amodeToStix :: AbsCSyn.CAddrMode -> Stix.StixExpr
diff --git a/ghc/compiler/nativeGen/StixPrim.lhs b/ghc/compiler/nativeGen/StixPrim.lhs
deleted file mode 100644 (file)
index 8df7812..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-%
-% (c) The AQUA Project, Glasgow University, 1993-1998
-%
-
-\begin{code}
-module StixPrim ( amodeToStix, amodeToStix', foreignCallCode )
-where
-
-#include "HsVersions.h"
-
--- import MachMisc
-import Stix
-
-import PprAbsC         ( pprAmode )
-import AbsCSyn                 hiding ( spRel )
-import AbsCUtils       ( getAmodeRep, mixedTypeLocn )
-import SMRep           ( fixedHdrSize )
-import Literal         ( Literal(..), word2IntLit )
-import MachOp          ( MachOp(..) )
-import PrimRep         ( PrimRep(..), getPrimRepSizeInBytes )
-import UniqSupply      ( returnUs, thenUs, getUniqueUs, UniqSM )
-import Constants       ( mIN_INTLIKE, mIN_CHARLIKE, bLOCK_SIZE,
-                         rESERVED_STACK_WORDS )
-import CLabel          ( mkIntlikeClosureLabel, mkCharlikeClosureLabel,
-                         mkForeignLabel )
-import ForeignCall     ( ForeignCall(..), CCallSpec(..), CCallTarget(..),
-                         CCallConv(..), playSafe, playThreadSafe )
-import Outputable
-import Util             ( notNull )
-import FastString
-import FastTypes
-import Char
-
-#include "NCG.h"
-\end{code}
-
-The main honchos here are primCode and foreignCallCode, which handle the guts of COpStmts.
-
-\begin{code}
-foreignCallCode
-    :: [CAddrMode]     -- results
-    -> ForeignCall     -- op
-    -> [CAddrMode]     -- args
-    -> UniqSM StixStmtList
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsubsection{Code for foreign calls}
-%*                                                                     *
-%************************************************************************
-
-First, the dreaded @ccall@.
-
-Usually, this compiles to an assignment, but when the left-hand side
-is empty, we just perform the call and ignore the result.
-
-ToDo: saving/restoring of volatile regs around ccalls.
-
-JRS, 001113: always do the call of suspendThread and resumeThread as a ccall
-rather than inheriting the calling convention of the thing which we're really
-calling.
-
-\begin{code}
-foreignCallCode lhs call@(CCall (CCallSpec ctarget cconv safety)) rhs
-
-  | not (playSafe safety) 
-  = returnUs (\xs -> ccall : xs)
-
-  | otherwise
-  = save_thread_state `thenUs` \ save ->
-    load_thread_state `thenUs` \ load -> 
-    getUniqueUs              `thenUs` \ uniq -> 
-    let
-       id  = StixTemp (StixVReg uniq IntRep)
-       
-       is_threadSafe
-        | playThreadSafe safety = 1
-       | otherwise             = 0
-    
-       suspend = StAssignReg IntRep id 
-                (StCall (Left FSLIT("suspendThread")) {-no:cconv-} CCallConv
-                         IntRep [StReg stgBaseReg, StInt is_threadSafe ])
-       resume  = StVoidable 
-                 (StCall (Left FSLIT("resumeThread")) {-no:cconv-} CCallConv
-                         VoidRep [StReg id, StInt is_threadSafe ])
-    in
-    returnUs (\xs -> save (suspend : ccall : resume : load xs))
-
-  where
-    (cargs, stix_target)
-        = case ctarget of
-             StaticTarget nm -> (rhs, Left nm)
-             DynamicTarget |  notNull rhs -- an assertion
-                           -> (tail rhs, Right (amodeToStix (head rhs)))
-
-    stix_args = map amodeToStix' cargs
-
-    ccall = case lhs of
-      []    -> StVoidable (StCall stix_target cconv VoidRep stix_args)
-      [lhs] -> mkStAssign pk lhs' (StCall stix_target cconv pk stix_args)
-           where
-              lhs' = amodeToStix lhs
-              pk   = case getAmodeRep lhs of
-                        FloatRep  -> FloatRep
-                        DoubleRep -> DoubleRep
-                        Int64Rep  -> Int64Rep
-                        Word64Rep -> Word64Rep
-                        other     -> IntRep
-
--- a bit late to catch this here..
-foreignCallCode _ DNCall{} _
- = panic "foreignCallCode: .NET interop not supported via NCG; compile with -fvia-C"
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsubsection{Code for @CAddrMode@s}
-%*                                                                     *
-%************************************************************************
-
-When a character is fetched from a mixed type location, we have to do
-an extra cast.  This is reflected in amodeCode', which is for rhs
-amodes that might possibly need the extra cast.
-
-\begin{code}
-amodeToStix, amodeToStix' :: CAddrMode -> StixExpr
-
-amodeToStix'{-'-} am@(CVal rr CharRep)
-  | mixedTypeLocn am = StMachOp MO_NatS_to_32U [amodeToStix am]
-  | otherwise        = amodeToStix am
-amodeToStix' am 
-  = amodeToStix am
-
------------
-amodeToStix am@(CVal rr CharRep)
-  | mixedTypeLocn am
-  = StInd IntRep (amodeToStix (CAddr rr))
-
-amodeToStix (CVal rr pk) = StInd pk (amodeToStix (CAddr rr))
-
-amodeToStix (CAddr (SpRel off))
-  = StIndex PtrRep (StReg stgSp) (StInt (toInteger (iBox off)))
-
-amodeToStix (CAddr (HpRel off))
-  = StIndex IntRep (StReg stgHp) (StInt (toInteger (- (iBox off))))
-
-amodeToStix (CAddr (NodeRel off))
-  = StIndex IntRep (StReg stgNode) (StInt (toInteger (iBox off)))
-
-amodeToStix (CAddr (CIndex base off pk))
-  = StIndex pk (amodeToStix base) (amodeToStix off)
-
-amodeToStix (CReg magic)    = StReg (StixMagicId magic)
-amodeToStix (CTemp uniq pk) = StReg (StixTemp (StixVReg uniq pk))
-
-amodeToStix (CLbl      lbl _) = StCLbl lbl
-
- -- For CharLike and IntLike, we attempt some trivial constant-folding here.
-
-amodeToStix (CCharLike (CLit (MachChar c)))
-  = StIndex Word8Rep cHARLIKE_closure (StInt (toInteger off))
-  where
-    off = charLikeSize * (ord c - mIN_CHARLIKE)
-
-amodeToStix (CCharLike x)
-  = panic "amodeToStix.CCharLike"
-
-amodeToStix (CIntLike (CLit (MachInt i)))
-  = StIndex Word8Rep iNTLIKE_closure (StInt (toInteger off))
-  where
-    off = intLikeSize * (fromInteger (i - mIN_INTLIKE))
-
-amodeToStix (CIntLike x)
-  = panic "amodeToStix.CIntLike"
-
-amodeToStix (CLit core)
-  = case core of
-      MachChar c     -> StInt (toInteger (ord c))
-      MachStr s             -> StString s
-      MachNullAddr   -> StInt 0
-      MachInt i      -> StInt i
-      MachWord w     -> case word2IntLit core of MachInt iw -> StInt iw
-                                                       -- dreadful, but rare.
-      MachLabel l (Just x) -> StCLbl (mkForeignLabel (mkFastString (unpackFS l ++ '@':show x)) False)
-      MachLabel l _        -> StCLbl (mkForeignLabel l False{-ToDo: dynamic-})
-      MachFloat d    -> StFloat d
-      MachDouble d   -> StDouble d
-      _ -> panic "amodeToStix:core literal"
-
-amodeToStix (CMacroExpr _ macro [arg])
-  = let 
-       arg_amode = amodeToStix arg
-    in 
-    case macro of
-      ENTRY_CODE -> arg_amode
-      ARG_TAG    -> arg_amode -- just an integer no. of words
-      GET_TAG    -> 
-#ifdef WORDS_BIGENDIAN
-                    StMachOp MO_Nat_And
-                       [StInd WordRep (StIndex PtrRep arg_amode
-                                                (StInt (toInteger (-1)))),
-                        StInt 65535]
-#else
-                    StMachOp MO_Nat_Shr
-                       [StInd WordRep (StIndex PtrRep arg_amode
-                                                (StInt (toInteger (-1)))),
-                        StInt 16]
-#endif
-      BYTE_ARR_CTS -> StIndex IntRep arg_amode arrWordsHS
-      PTRS_ARR_CTS -> StIndex PtrRep arg_amode arrPtrsHS
-      ForeignObj_CLOSURE_DATA -> StInd PtrRep (StIndex PtrRep arg_amode fixedHS)
-
-
-amodeToStix other
-   = pprPanic "StixPrim.amodeToStix" (pprAmode other)
-\end{code}
-
-Sizes of the CharLike and IntLike closures that are arranged as arrays
-in the data segment.  (These are in bytes.)
-
-\begin{code}
--- The INTLIKE base pointer
-
-iNTLIKE_closure :: StixExpr
-iNTLIKE_closure = StCLbl mkIntlikeClosureLabel
-
--- The CHARLIKE base
-
-cHARLIKE_closure :: StixExpr
-cHARLIKE_closure = StCLbl mkCharlikeClosureLabel
-
--- these are the sizes of charLike and intLike closures, in _bytes_.
-charLikeSize = (fixedHdrSize + 1) * (getPrimRepSizeInBytes PtrRep)
-intLikeSize  = (fixedHdrSize + 1) * (getPrimRepSizeInBytes PtrRep)
-\end{code}
-
-
-\begin{code}
-save_thread_state 
-   = getUniqueUs   `thenUs` \ tso_uq -> 
-     let tso = StixTemp (StixVReg tso_uq PtrRep) in
-     returnUs (\xs ->
-       StAssignReg PtrRep tso (StReg stgCurrentTSO)
-       : StAssignMem PtrRep
-             (StMachOp MO_Nat_Add
-                      [StReg tso, StInt (toInteger (TSO_SP*BYTES_PER_WORD))])
-            (StReg stgSp)
-        : StAssignMem PtrRep
-            (StMachOp MO_Nat_Add
-                      [StReg stgCurrentNursery, 
-                       StInt (toInteger (BDESCR_FREE * BYTES_PER_WORD))])
-             (StMachOp MO_Nat_Add 
-                       [StReg stgHp, StInt (toInteger (1 * BYTES_PER_WORD))]) 
-        : xs
-     )
-
-load_thread_state 
-   = getUniqueUs   `thenUs` \ tso_uq -> 
-     let tso = StixTemp (StixVReg tso_uq PtrRep) in
-     returnUs (\xs ->
-       StAssignReg PtrRep tso (StReg stgCurrentTSO)
-       : StAssignReg PtrRep 
-             stgSp
-            (StInd PtrRep 
-                  (StMachOp MO_Nat_Add
-                            [StReg tso, StInt (toInteger (TSO_SP*BYTES_PER_WORD))]))
-       : StAssignReg PtrRep 
-             stgSpLim
-            (StMachOp MO_Nat_Add 
-                       [StReg tso, 
-                       StInt (toInteger ((TSO_STACK + rESERVED_STACK_WORDS)
-                                         *BYTES_PER_WORD))])
-       : StAssignReg PtrRep 
-             stgHp
-            (StMachOp MO_Nat_Sub 
-                       [StInd PtrRep 
-                              (StMachOp MO_Nat_Add
-                                       [StReg stgCurrentNursery, 
-                                        StInt (toInteger (BDESCR_FREE * BYTES_PER_WORD))]),
-                       StInt (toInteger (1 * BYTES_PER_WORD))
-                      ]) 
-        : StAssignReg PtrRep 
-             stgHpLim
-             (StIndex Word8Rep 
-                (StInd PtrRep 
-                       (StIndex PtrRep (StReg stgCurrentNursery)
-                                       (StInt (toInteger BDESCR_START))
-                       )
-                )
-                (StMachOp MO_Nat_Sub
-                   [StMachOp MO_NatU_Mul
-                      [StInd WordRep 
-                             (StIndex PtrRep (StReg stgCurrentNursery)
-                                             (StInt (toInteger BDESCR_BLOCKS))),
-                       StInt (toInteger bLOCK_SIZE{-in bytes-})
-                      ],
-                      StInt (1 * BYTES_PER_WORD)
-                   ]
-                )
-
-             ) 
-
-        : xs
-     )
-\end{code}
index 414aa4f..d97d5e0 100644 (file)
@@ -9,12 +9,16 @@ module Ctype
        , is_lower      -- Char# -> Bool
        , is_upper      -- Char# -> Bool
        , is_digit      -- Char# -> Bool
+
+       , is_hexdigit, is_octdigit
+       , hexDigit, octDecDigit
        ) where
 
 #include "HsVersions.h"
 
 import DATA_INT                ( Int32 )
 import DATA_BITS       ( Bits((.&.)) )
+import Char            ( ord, chr )
 \end{code}
 
 Bit masks
@@ -48,6 +52,28 @@ is_upper  = is_ctype cUpper
 is_digit  = is_ctype cDigit
 \end{code}
 
+Utils
+
+\begin{code}
+hexDigit :: Char -> Int
+hexDigit c | is_digit c = ord c - ord '0'
+           | otherwise  = ord (to_lower c) - ord 'a' + 10
+
+octDecDigit :: Char -> Int
+octDecDigit c = ord c - ord '0'
+
+is_hexdigit c
+       =  is_digit c 
+       || (c >= 'a' && c <= 'f')
+       || (c >= 'A' && c <= 'F')
+
+is_octdigit c = c >= '0' && c <= '7'
+
+to_lower c 
+  | c >=  'A' && c <= 'Z' = chr (ord c - (ord 'A' - ord 'a'))
+  | otherwise = c
+\end{code}
+
 We really mean .|. instead of + below, but GHC currently doesn't do
 any constant folding with bitops. *sigh*
 
index c90e934..8304918 100644 (file)
 
 {
 module Lexer (
-   Token(..), lexer, mkPState,
+   Token(..), lexer, mkPState, PState(..),
    P(..), ParseResult(..), getSrcLoc, 
-   failMsgP, failLocMsgP, failSpanMsgP, srcParseFail,
-   popContext, pushCurrentContext,
+   failLocMsgP, failSpanMsgP, srcParseFail,
+   popContext, pushCurrentContext, setLastToken, setSrcLoc,
+   getLexState, popLexState, pushLexState
   ) where
 
 #include "HsVersions.h"
@@ -39,7 +40,7 @@ import SrcLoc
 import UniqFM
 import CmdLineOpts
 import Ctype
-import Util            ( maybePrefixMatch )
+import Util            ( maybePrefixMatch, readRational )
 
 import DATA_BITS
 import Char
@@ -153,14 +154,14 @@ $white_no_nl+                             ;
 
 -- single-line line pragmas, of the form
 --    # <line> "<file>" <extra-stuff> \n
-<line_prag1> $digit+                   { set_line line_prag1a }
-<line_prag1a> \" [$graphic \ ]* \"     { set_file line_prag1b }
+<line_prag1> $digit+                   { setLine line_prag1a }
+<line_prag1a> \" [$graphic \ ]* \"     { setFile line_prag1b }
 <line_prag1b> .*                       { pop }
 
 -- Haskell-style line pragmas, of the form
 --    {-# LINE <line> "<file>" #-}
-<line_prag2> $digit+                   { set_line line_prag2a }
-<line_prag2a> \" [$graphic \ ]* \"     { set_file line_prag2b }
+<line_prag2> $digit+                   { setLine line_prag2a }
+<line_prag2a> \" [$graphic \ ]* \"     { setFile line_prag2b }
 <line_prag2b> "#-}"|"-}"               { pop }
    -- NOTE: accept -} at the end of a LINE pragma, for compatibility
    -- with older versions of GHC which generated these.
@@ -709,32 +710,26 @@ sym con span buf len =
        fs = lexemeToFastString buf len
 
 tok_decimal span buf len 
-  = return (L span (ITinteger  $! parseInteger buf len 10 oct_or_dec))
+  = return (L span (ITinteger  $! parseInteger buf len 10 octDecDigit))
 
 tok_octal span buf len 
-  = return (L span (ITinteger  $! parseInteger (stepOnBy 2 buf) (len-2) 8 oct_or_dec))
+  = return (L span (ITinteger  $! parseInteger (stepOnBy 2 buf) (len-2) 8 octDecDigit))
 
 tok_hexadecimal span buf len 
-  = return (L span (ITinteger  $! parseInteger (stepOnBy 2 buf) (len-2) 16 hex))
+  = return (L span (ITinteger  $! parseInteger (stepOnBy 2 buf) (len-2) 16 hexDigit))
 
 prim_decimal span buf len 
-  = return (L span (ITprimint  $! parseInteger buf (len-1) 10 oct_or_dec))
+  = return (L span (ITprimint  $! parseInteger buf (len-1) 10 octDecDigit))
 
 prim_octal span buf len 
-  = return (L span (ITprimint  $! parseInteger (stepOnBy 2 buf) (len-3) 8 oct_or_dec))
+  = return (L span (ITprimint  $! parseInteger (stepOnBy 2 buf) (len-3) 8 octDecDigit))
 
 prim_hexadecimal span buf len 
-  = return (L span (ITprimint  $! parseInteger (stepOnBy 2 buf) (len-3) 16 hex))
+  = return (L span (ITprimint  $! parseInteger (stepOnBy 2 buf) (len-3) 16 hexDigit))
 
-tok_float        str = ITrational $! readRational__ str
-prim_float       str = ITprimfloat  $! readRational__ str
-prim_double      str = ITprimdouble $! readRational__ str
-
-parseInteger :: StringBuffer -> Int -> Integer -> (Char->Int) -> Integer
-parseInteger buf len radix to_int 
-  = go 0 0
-  where go i x | i == len  = x
-              | otherwise = go (i+1) (x * radix + toInteger (to_int (lookAhead buf i)))
+tok_float        str = ITrational   $! readRational str
+prim_float       str = ITprimfloat  $! readRational str
+prim_double      str = ITprimdouble $! readRational str
 
 -- -----------------------------------------------------------------------------
 -- Layout processing
@@ -800,17 +795,17 @@ do_layout_left span _buf _len = do
 -- -----------------------------------------------------------------------------
 -- LINE pragmas
 
-set_line :: Int -> Action
-set_line code span buf len = do
-  let line = parseInteger buf len 10 oct_or_dec
+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
   popLexState
   pushLexState code
   lexToken
 
-set_file :: Int -> Action
-set_file code span buf len = do
+setFile :: Int -> Action
+setFile code span buf len = do
   let file = lexemeToFastString (stepOn buf) (len-2)
   setSrcLoc (mkSrcLoc file (srcSpanEndLine span) (srcSpanEndCol span))
   popLexState
@@ -957,9 +952,9 @@ lex_escape = do
                        then return (chr (ord c - ord '@'))
                        else lit_error
 
-       'x'   -> readNum is_hexdigit 16 hex
-       'o'   -> readNum is_octdigit  8 oct_or_dec
-       x | is_digit x -> readNum2 is_digit 10 oct_or_dec (oct_or_dec x)
+       'x'   -> readNum is_hexdigit 16 hexDigit
+       'o'   -> readNum is_octdigit  8 octDecDigit
+       x | is_digit x -> readNum2 is_digit 10 octDecDigit (octDecDigit x)
 
        c1 ->  do
           i <- getInput
@@ -1000,22 +995,6 @@ readNum2 is_digit base conv i = do
                   then return (chr i)
                   else lit_error
 
-is_hexdigit c
-       =  is_digit c 
-       || (c >= 'a' && c <= 'f')
-       || (c >= 'A' && c <= 'F')
-
-hex c | is_digit c = ord c - ord '0'
-      | otherwise  = ord (to_lower c) - ord 'a' + 10
-
-oct_or_dec c = ord c - ord '0'
-
-is_octdigit c = c >= '0' && c <= '7'
-
-to_lower c 
-  | c >=  'A' && c <= 'Z' = chr (ord c - (ord 'A' - ord 'a'))
-  | otherwise = c
-
 silly_escape_chars = [
        ("NUL", '\NUL'),
        ("SOH", '\SOH'),
@@ -1063,54 +1042,6 @@ getCharOrFail =  do
        Just (c,i)  -> do setInput i; return c
 
 -- -----------------------------------------------------------------------------
--- Floats
-
-readRational :: ReadS Rational -- NB: doesn't handle leading "-"
-readRational r = do 
-     (n,d,s) <- readFix r
-     (k,t)   <- readExp s
-     return ((n%1)*10^^(k-d), t)
- where
-     readFix r = do
-       (ds,s)  <- lexDecDigits r
-       (ds',t) <- lexDotDigits s
-       return (read (ds++ds'), length ds', t)
-
-     readExp (e:s) | e `elem` "eE" = readExp' s
-     readExp s                    = return (0,s)
-
-     readExp' ('+':s) = readDec s
-     readExp' ('-':s) = do
-                       (k,t) <- readDec s
-                       return (-k,t)
-     readExp' s              = readDec s
-
-     readDec s = do
-        (ds,r) <- nonnull isDigit s
-        return (foldl1 (\n d -> n * 10 + d) [ ord d - ord '0' | d <- ds ],
-                r)
-
-     lexDecDigits = nonnull isDigit
-
-     lexDotDigits ('.':s) = return (span isDigit s)
-     lexDotDigits s       = return ("",s)
-
-     nonnull p s = do (cs@(_:_),t) <- return (span p s)
-                      return (cs,t)
-
-readRational__ :: String -> Rational -- NB: *does* handle a leading "-"
-readRational__ top_s
-  = case top_s of
-      '-' : xs -> - (read_me xs)
-      xs       -> read_me xs
-  where
-    read_me s
-      = case (do { (x,"") <- readRational s ; return x }) of
-         [x] -> x
-         []  -> error ("readRational__: no parse:"        ++ top_s)
-         _   -> error ("readRational__: ambiguous parse:" ++ top_s)
-
--- -----------------------------------------------------------------------------
 -- The Parse Monad
 
 data LayoutContext
@@ -1135,7 +1066,10 @@ data PState = PState {
        lex_state  :: [Int]
      }
        -- last_loc and last_len are used when generating error messages,
-       -- and in pushCurrentContext only.
+       -- and in pushCurrentContext only.  Sigh, if only Happy passed the
+       -- current token to happyError, we could at least get rid of last_len.
+       -- Getting rid of last_loc would require finding another way to 
+       -- implement pushCurrentContext (which is only called from one place).
 
 newtype P a = P { unP :: PState -> ParseResult a }
 
@@ -1301,7 +1235,7 @@ srcParseErr buf len
 -- detected during parsing.
 srcParseFail :: P a
 srcParseFail = P $ \PState{ buffer = buf, last_len = len,      
-                               last_loc = last_loc, loc = loc } ->
+                           last_loc = last_loc } ->
     PFailed last_loc (srcParseErr buf len)
 
 -- A lexical error is reported at a particular position in the source file,
index a5e5da4..2ba5ae0 100644 (file)
@@ -21,7 +21,7 @@ import RdrName
 import TysWiredIn      ( unitTyCon, unitDataCon, tupleTyCon, tupleCon, nilDataCon,
                          listTyCon_RDR, parrTyCon_RDR, consDataCon_RDR )
 import Type            ( funTyCon )
-import ForeignCall     ( Safety(..), CExportSpec(..), 
+import ForeignCall     ( Safety(..), CExportSpec(..), CLabelString,
                          CCallConv(..), CCallTarget(..), defaultCCallConv
                        )
 import OccName         ( UserFS, varName, dataName, tcClsName, tvName )
@@ -38,7 +38,6 @@ import OrdList
 import Bag             ( emptyBag )
 import Panic
 
-import CStrings                ( CLabelString )
 import FastString
 import Maybes          ( orElse )
 import Outputable
index 729c33d..781b085 100644 (file)
@@ -61,13 +61,12 @@ import Kind         ( liftedTypeKind )
 import HscTypes                ( GenAvailInfo(..) )
 import TysWiredIn      ( unitTyCon ) 
 import ForeignCall     ( CCallConv, Safety, CCallTarget(..), CExportSpec(..),
-                         DNCallSpec(..), DNKind(..))
+                         DNCallSpec(..), DNKind(..), CLabelString )
 import OccName         ( OccName, srcDataName, varName, isDataOcc, isTcOcc, 
                          occNameUserString, isValOcc )
 import BasicTypes      ( initialVersion, StrictnessMark(..) )
 import Module          ( ModuleName )
 import SrcLoc
-import CStrings                ( CLabelString )
 import CmdLineOpts     ( opt_InPackage )
 import OrdList         ( OrdList, fromOL )
 import Bag             ( Bag, emptyBag, snocBag, consBag, foldrBag )
index ab04abf..12b85b1 100644 (file)
@@ -1,5 +1,3 @@
-{-% DrIFT (Automatic class derivations for Haskell) v1.1 %-}
-{-% DrIFT (Automatic class derivations for Haskell) v1.1 %-}
 %
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
@@ -10,7 +8,7 @@ module ForeignCall (
        ForeignCall(..),
        Safety(..), playSafe, playThreadSafe,
 
-       CExportSpec(..),
+       CExportSpec(..), CLabelString, isCLabelString, pprCLabelString,
        CCallSpec(..), 
        CCallTarget(..), isDynamicTarget,
        CCallConv(..), defaultCCallConv, ccallConvToInt, ccallConvAttribute,
@@ -21,8 +19,8 @@ module ForeignCall (
 
 #include "HsVersions.h"
 
-import CStrings                        ( CLabelString, pprCLabelString )
-import FastString              ( FastString )
+import FastString      ( FastString, unpackFS )
+import Char            ( isAlphaNum )
 import Binary
 import Outputable
 \end{code}
@@ -155,6 +153,22 @@ ccallConvAttribute StdCallConv = "__stdcall"
 ccallConvAttribute CCallConv   = ""
 \end{code}
 
+\begin{code}
+type CLabelString = FastString         -- A C label, completely unencoded
+
+pprCLabelString :: CLabelString -> SDoc
+pprCLabelString lbl = ftext lbl
+
+isCLabelString :: CLabelString -> Bool -- Checks to see if this is a valid C label
+isCLabelString lbl 
+  = all ok (unpackFS lbl)
+  where
+    ok c = isAlphaNum c || c == '_' || c == '.'
+       -- The '.' appears in e.g. "foo.so" in the 
+       -- module part of a ExtName.  Maybe it should be separate
+\end{code}
+
+
 Printing into C files:
 
 \begin{code}
index 6dc4ec1..18024f7 100644 (file)
@@ -17,15 +17,15 @@ module PrimOp (
 
 #include "HsVersions.h"
 
-import PrimRep         -- most of it
 import TysPrim
 import TysWiredIn
 
 import NewDemand
 import Var             ( TyVar )
 import OccName         ( OccName, pprOccName, mkVarOcc )
-import TyCon           ( TyCon, isPrimTyCon, tyConPrimRep )
-import Type            ( Type, mkForAllTys, mkFunTy, mkFunTys, typePrimRep, tyConAppTyCon )
+import TyCon           ( TyCon, isPrimTyCon, tyConPrimRep, PrimRep(..) )
+import Type            ( Type, mkForAllTys, mkFunTy, mkFunTys, tyConAppTyCon,
+                         typePrimRep )
 import BasicTypes      ( Arity, Boxity(..) )
 import Outputable
 import FastTypes
diff --git a/ghc/compiler/prelude/PrimRep.lhs b/ghc/compiler/prelude/PrimRep.lhs
deleted file mode 100644 (file)
index a58240b..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-%
-% (c) The GRASP Project, Glasgow University, 1992-1998
-%
-\section[PrimRep]{Primitive machine-level kinds of things.}
-
-At various places in the back end, we want to be to tag things with a
-``primitive kind''---i.e., the machine-manipulable implementation
-types.
-
-\begin{code}
-module PrimRep (
-       PrimRep(..),
-       separateByPtrFollowness,
-       isFollowableRep,
-       isFloatingRep,
-       isNonPtrRep,     
-       is64BitRep,
-       getPrimRepSize,
-       getPrimRepSizeInBytes,
-       retPrimRepSize,
-
-       ArgRep(..), primRepToArgRep,
- ) where
-
-#include "HsVersions.h"
-
-import Constants ( dOUBLE_SIZE, iNT64_SIZE, wORD64_SIZE, wORD_SIZE )
-import Outputable
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[PrimRep-datatype]{The @PrimRep@ datatype}
-%*                                                                     *
-%************************************************************************
-
-These pretty much correspond to the C types declared in StgTypes.h.
-
-\begin{code}
-data PrimRep
-  = -- These pointer-kinds are all really the same, but we keep
-    -- them separate for documentation purposes.
-    PtrRep             -- Pointer to a closure; a ``word''.
-  | CodePtrRep         -- Pointer to code
-  | DataPtrRep         -- Pointer to data
-  | RetRep             -- Pointer to code or data (return vector or code pointer)
-  | CostCentreRep      -- Pointer to a cost centre
-
-  | CharRep            -- Machine characters
-  | IntRep             --         signed   integers (same size as ptr on this arch)
-  | WordRep            --         unsigned integers (same size as ptr on this arch)
-  | AddrRep            --         addresses (C pointers)
-  | FloatRep           --         floats
-  | DoubleRep          --         doubles
-
-  | Int8Rep             --          8 bit signed   integers
-  | Int16Rep            --         16 bit signed   integers
-  | Int32Rep            --         32 bit signed   integers
-  | Int64Rep           --         64 bit signed   integers
-  | Word8Rep            --          8 bit unsigned integers
-  | Word16Rep           --         16 bit unsigned integers
-  | Word32Rep           --         32 bit unsigned integers
-  | Word64Rep          --         64 bit unsigned integers
-
-  | StablePtrRep       -- guaranteed to be represented by a pointer
-
-  | VoidRep            -- Occupies no space at all!
-                       -- (Primitive states are mapped onto this)
-  deriving (Eq, Ord)
-\end{code}
-
-
-%************************************************************************
-%*                                                                     *
-\subsection[PrimRep-predicates]{Follow-ness, sizes, and such---on @PrimitiveKinds@}
-%*                                                                     *
-%************************************************************************
-
-Whether or not the thing is a pointer that the garbage-collector
-should follow. Or, to put it another (less confusing) way, whether
-the object in question is a heap object. 
-
-Depending on the outcome, this predicate determines what stack
-the pointer/object possibly will have to be saved onto, and the
-computation of GC liveness info.
-
-\begin{code}
-isFollowableRep :: PrimRep -> Bool  -- True <=> points to a heap object
-isFollowableRep PtrRep               = True
-isFollowableRep other        = False
-
-separateByPtrFollowness :: (a -> PrimRep) -> [a] -> ([a], [a])
-separateByPtrFollowness kind_fun things
-  = sep_things kind_fun things [] []
-    -- accumulating params for follow-able and don't-follow things...
-  where
-    sep_things kfun []     bs us = (reverse bs, reverse us)
-    sep_things kfun (t:ts) bs us
-      = if (isFollowableRep . kfun) t then
-           sep_things kfun ts (t:bs) us
-       else
-           sep_things kfun ts bs (t:us)
-\end{code}
-
-@isFloatingRep@ is used to distinguish @Double@ and @Float@ which
-cause inadvertent numeric conversions if you aren't jolly careful.
-See codeGen/CgCon:cgTopRhsCon.
-
-\begin{code}
-isFloatingRep :: PrimRep -> Bool
-isFloatingRep DoubleRep = True
-isFloatingRep FloatRep  = True
-isFloatingRep _         = False
-\end{code}
-
-Identify anything which is one word large and not a pointer.
-
-\begin{code}
-isNonPtrRep :: PrimRep -> Bool
-isNonPtrRep PtrRep  = False
-isNonPtrRep VoidRep = False
-isNonPtrRep r       = not (isFloatingRep r) && not (is64BitRep r)
-\end{code}
-
-\begin{code}
-is64BitRep :: PrimRep -> Bool
-is64BitRep Int64Rep  = True
-is64BitRep Word64Rep = True
-is64BitRep _         = False
-
--- Size in words.
-
-getPrimRepSize :: PrimRep -> Int
-getPrimRepSize DoubleRep = dOUBLE_SIZE
-getPrimRepSize Word64Rep = wORD64_SIZE
-getPrimRepSize Int64Rep  = iNT64_SIZE
-getPrimRepSize VoidRep   = 0
-getPrimRepSize _         = 1
-
-retPrimRepSize :: Int
-retPrimRepSize = getPrimRepSize RetRep
-
--- Sizes in bytes.  (used in some settings to figure out how many
--- bytes we have to push onto the stack when calling external entry
--- points (e.g., stdcalling on win32)
-
--- Note: the "size in bytes" is also the scaling factor used when we
--- have an array of these things.  For example, a ByteArray# of
--- Int16Rep will use a scaling factor of 2 when accessing the
--- elements.
-
-getPrimRepSizeInBytes :: PrimRep -> Int
-getPrimRepSizeInBytes PtrRep        = wORD_SIZE
-getPrimRepSizeInBytes CodePtrRep    = wORD_SIZE
-getPrimRepSizeInBytes DataPtrRep    = wORD_SIZE
-getPrimRepSizeInBytes RetRep        = wORD_SIZE
-getPrimRepSizeInBytes CostCentreRep = wORD_SIZE
-getPrimRepSizeInBytes CharRep       = 4
-getPrimRepSizeInBytes IntRep        = wORD_SIZE
-getPrimRepSizeInBytes WordRep       = wORD_SIZE
-getPrimRepSizeInBytes AddrRep       = wORD_SIZE
-getPrimRepSizeInBytes FloatRep      = wORD_SIZE
-getPrimRepSizeInBytes DoubleRep     = dOUBLE_SIZE * wORD_SIZE
-getPrimRepSizeInBytes Int8Rep       = 1
-getPrimRepSizeInBytes Int16Rep      = 2
-getPrimRepSizeInBytes Int32Rep      = 4
-getPrimRepSizeInBytes Int64Rep      = 8
-getPrimRepSizeInBytes Word8Rep      = 1
-getPrimRepSizeInBytes Word16Rep     = 2
-getPrimRepSizeInBytes Word32Rep     = 4
-getPrimRepSizeInBytes Word64Rep     = 8
-getPrimRepSizeInBytes StablePtrRep  = wORD_SIZE
-getPrimRepSizeInBytes other         = pprPanic "getPrimRepSizeInBytes" (ppr other)
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{ArgReps}
-%*                                                                     *
-%************************************************************************
-
-An ArgRep is similar to a PrimRep, except that it is slightly
-narrower.  It corresponds to the distinctions we make between
-different type of function arguments for the purposes of a function's
-calling convention.  These reps are used to decide which of the RTS's
-generic apply functions to call when applying an unknown function.
-
-All 64-bit PrimReps map to the same ArgRep, because they're passed in
-the same register, but a PtrRep is still different from an IntRep
-(RepP vs. RepN respectively) because the function's entry convention
-has to take into account the pointer-hood of arguments for the
-purposes of describing the stack on entry to the garbage collector.
-
-\begin{code}
-data ArgRep = RepV | RepP | RepN | RepF | RepD | RepL
-
-primRepToArgRep VoidRep   = RepV
-primRepToArgRep FloatRep  = RepF
-primRepToArgRep DoubleRep = RepD
-primRepToArgRep r
-   | isFollowableRep r     = RepP
-   | is64BitRep r          = RepL
-   | otherwise             = ASSERT(getPrimRepSize r == 1) RepN
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[PrimRep-instances]{Boring instance decls for @PrimRep@}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-instance Outputable PrimRep where
-    ppr kind = text (showPrimRep kind)
-
-showPrimRep  :: PrimRep -> String
-showPrimRep PtrRep        = "P_"       -- short for StgPtr
-showPrimRep CodePtrRep     = "P_"      -- DEATH to StgFunPtr! (94/02/22 WDP)
-showPrimRep DataPtrRep     = "D_"
-showPrimRep RetRep         = "P_"
-showPrimRep CostCentreRep  = "CostCentre"
-showPrimRep CharRep       = "C_"
-showPrimRep Int8Rep       = "StgInt8"
-showPrimRep Int16Rep      = "StgInt16"
-showPrimRep Int32Rep      = "StgInt32"
-showPrimRep Word8Rep      = "StgWord8"
-showPrimRep Word16Rep     = "StgWord16"
-showPrimRep Word32Rep     = "StgWord32"
-showPrimRep IntRep        = "I_"       -- short for StgInt
-showPrimRep WordRep       = "W_"       -- short for StgWord
-showPrimRep Int64Rep       = "LI_"       -- short for StgLongInt
-showPrimRep Word64Rep      = "LW_"       -- short for StgLongWord
-showPrimRep AddrRep       = "StgAddr"
-showPrimRep FloatRep      = "StgFloat"
-showPrimRep DoubleRep     = "StgDouble"
-showPrimRep StablePtrRep   = "StgStablePtr"
-showPrimRep VoidRep       = "!!VOID_KIND!!"
-\end{code}
-
-
index fab63e5..f971348 100644 (file)
@@ -47,8 +47,8 @@ module TysPrim(
 import Var             ( TyVar, mkTyVar )
 import Name            ( Name, mkInternalName, mkWiredInName )
 import OccName         ( mkVarOcc, mkOccFS, tcName )
-import PrimRep         ( PrimRep(..) )
-import TyCon           ( TyCon, ArgVrcs, mkPrimTyCon, mkLiftedPrimTyCon )
+import TyCon           ( TyCon, ArgVrcs, mkPrimTyCon, mkLiftedPrimTyCon,
+                         PrimRep(..) )
 import Type            ( mkTyConApp, mkTyConTy, mkTyVarTys, mkTyVarTy,
                          unliftedTypeKind, liftedTypeKind, openTypeKind, 
                          Kind, mkArrowKinds,
@@ -204,13 +204,13 @@ pcPrimTyCon0 name rep
     result_kind = unliftedTypeKind -- all primitive types are unlifted
 
 charPrimTy     = mkTyConTy charPrimTyCon
-charPrimTyCon  = pcPrimTyCon0 charPrimTyConName CharRep
+charPrimTyCon  = pcPrimTyCon0 charPrimTyConName WordRep
 
 intPrimTy      = mkTyConTy intPrimTyCon
 intPrimTyCon   = pcPrimTyCon0 intPrimTyConName IntRep
 
 int32PrimTy    = mkTyConTy int32PrimTyCon
-int32PrimTyCon = pcPrimTyCon0 int32PrimTyConName Int32Rep
+int32PrimTyCon = pcPrimTyCon0 int32PrimTyConName IntRep
 
 int64PrimTy    = mkTyConTy int64PrimTyCon
 int64PrimTyCon = pcPrimTyCon0 int64PrimTyConName Int64Rep
@@ -219,7 +219,7 @@ wordPrimTy  = mkTyConTy wordPrimTyCon
 wordPrimTyCon  = pcPrimTyCon0 wordPrimTyConName WordRep
 
 word32PrimTy   = mkTyConTy word32PrimTyCon
-word32PrimTyCon        = pcPrimTyCon0 word32PrimTyConName Word32Rep
+word32PrimTyCon        = pcPrimTyCon0 word32PrimTyConName WordRep
 
 word64PrimTy   = mkTyConTy word64PrimTyCon
 word64PrimTyCon        = pcPrimTyCon0 word64PrimTyConName Word64Rep
@@ -256,7 +256,7 @@ statePrimTyCon       = pcPrimTyCon statePrimTyConName vrcsZ VoidRep
 \end{code}
 
 RealWorld is deeply magical.  It is *primitive*, but it is not
-*unlifted* (hence PtrRep).  We never manipulate values of type
+*unlifted* (hence ptrArg).  We never manipulate values of type
 RealWorld; it's only used in the type system, to parameterise State#.
 
 \begin{code}
@@ -318,7 +318,7 @@ mkMVarPrimTy s elt      = mkTyConApp mVarPrimTyCon [s, elt]
 %************************************************************************
 
 \begin{code}
-stablePtrPrimTyCon = pcPrimTyCon stablePtrPrimTyConName vrcsP StablePtrRep
+stablePtrPrimTyCon = pcPrimTyCon stablePtrPrimTyConName vrcsP AddrRep
 
 mkStablePtrPrimTy ty = mkTyConApp stablePtrPrimTyCon [ty]
 \end{code}
index 5efe37a..46fd3c3 100644 (file)
@@ -13,16 +13,18 @@ module CostCentre (
        noCCS, subsumedCCS, currentCCS, overheadCCS, dontCareCCS,
        noCostCentre, noCCAttached,
        noCCSAttached, isCurrentCCS,  isSubsumedCCS, currentOrSubsumedCCS,
-       isDerivedFromCurrentCCS,
+       isDerivedFromCurrentCCS, maybeSingletonCCS,
+       decomposeCCS,
 
        mkUserCC, mkAutoCC, mkAllCafsCC, 
        mkSingletonCCS, dupifyCC, pushCCOnCCS,
-       isCafCCS,
+       isCafCCS, isCafCC,
        isSccCountCostCentre,
        sccAbleCostCentre,
        ccFromThisModule,
 
-       pprCostCentreDecl, pprCostCentreStackDecl, pprCostCentreCore,
+       pprCostCentreCore,
+       costCentreUserName,
 
        cmpCostCentre   -- used for removing dups in a list
     ) where
@@ -33,11 +35,8 @@ import Var           ( Id )
 import Name            ( UserFS, EncodedFS, encodeFS, decode,
                          getOccName, occNameFS
                        )
-import Module          ( Module, ModuleName, moduleName,
-                         moduleNameUserString
-                       )
+import Module          ( Module, ModuleName, moduleName )
 import Outputable      
-import CStrings                ( pprStringInCStyle )
 import FastTypes
 import FastString
 import Util            ( thenCmp )
@@ -193,6 +192,9 @@ isDerivedFromCurrentCCS _           = False
 currentOrSubsumedCCS SubsumedCCS       = True
 currentOrSubsumedCCS CurrentCCS                = True
 currentOrSubsumedCCS _                 = False
+
+maybeSingletonCCS (PushCC cc NoCCS)    = Just cc
+maybeSingletonCCS _                    = Nothing
 \end{code}
 
 Building cost centres
@@ -222,10 +224,7 @@ pushCCOnCCS = PushCC
 
 dupifyCC cc = cc {cc_is_dupd = DupdCC}
 
-isEmptyCC, isCafCC, isDupdCC :: CostCentre -> Bool
-
-isEmptyCC (NoCostCentre)               = True
-isEmptyCC _                            = False
+isCafCC, isDupdCC :: CostCentre -> Bool
 
 isCafCC (AllCafsCC {})                  = True
 isCafCC (NormalCC {cc_is_caf = CafCC}) = True
@@ -288,6 +287,11 @@ cmp_caf NotCafCC CafCC     = LT
 cmp_caf NotCafCC NotCafCC  = EQ
 cmp_caf CafCC    CafCC     = EQ
 cmp_caf CafCC    NotCafCC  = GT
+
+decomposeCCS :: CostCentreStack -> ([CostCentre],CostCentreStack)
+decomposeCCS (PushCC cc ccs) = (cc:more, ccs') 
+  where (more,ccs') = decomposeCCS ccs
+decomposeCCS ccs = ([],ccs)
 \end{code}
 
 -----------------------------------------------------------------------------
@@ -310,20 +314,8 @@ instance Outputable CostCentreStack where
   ppr SubsumedCCS      = ptext SLIT("CCS_SUBSUMED")
   ppr (PushCC cc NoCCS) = ppr cc <> ptext SLIT("_ccs")
   ppr (PushCC cc ccs)   = ptext SLIT("PushCostCentre") <> 
-                          parens (ppr ccs <> comma <> ppr cc)
-
--- print the static declaration for a singleton CCS.
-pprCostCentreStackDecl :: CostCentreStack -> SDoc
-pprCostCentreStackDecl ccs@(PushCC cc NoCCS)
-  = hcat [ ptext SLIT("CCS_DECLARE"), char '(',
-          ppr ccs,             comma,  -- better be codeStyle
-          ppCostCentreLbl cc,  comma,
-          empty,       -- Now always externally visible
-          text ");"
-        ]
-
-pprCostCentreStackDecl ccs 
-  = pprPanic "pprCostCentreStackDecl: " (ppr ccs)
+                          parens (ppr ccs <> comma <> 
+                          parens(ptext SLIT("void *")) <> ppr cc)
 \end{code}
 
 -----------------------------------------------------------------------------
@@ -380,32 +372,3 @@ costCentreUserName (AllCafsCC {})  = "CAF"
 costCentreUserName cc@(NormalCC {cc_name = name, cc_is_caf = is_caf})
   =  case is_caf of { CafCC -> "CAF:";   _ -> "" } ++ decode (unpackFS name)
 \end{code}
-
-Cost Centre Declarations
-
-\begin{code}
-#ifdef DEBUG
-pprCostCentreDecl is_local (NoCostCentre)
-  = panic "pprCostCentreDecl: no cost centre!"
-#endif
-pprCostCentreDecl is_local cc
-  = if is_local then
-       hcat [
-           ptext SLIT("CC_DECLARE"),char '(',
-           cc_ident,                                                   comma,
-           pprStringInCStyle (costCentreUserName cc),                  comma,
-           pprStringInCStyle (moduleNameUserString mod_name),          comma,
-           is_subsumed,                                                comma,
-           empty,      -- Now always externally visible
-           text ");"]
-    else
-       hcat [ ptext SLIT("CC_EXTERN"),char '(', cc_ident, text ");" ]
-  where
-    cc_ident    = ppCostCentreLbl cc
-    mod_name   = cc_mod cc
-    is_subsumed = ccSubsumed cc
-
-ccSubsumed :: CostCentre -> SDoc               -- subsumed value
-ccSubsumed cc | isCafCC  cc = ptext SLIT("CC_IS_CAF")
-             | otherwise   = ptext SLIT("CC_IS_BORING")
-\end{code}
index d13b4bb..d18fe5f 100644 (file)
@@ -17,7 +17,7 @@ module TcForeign
         , tcForeignExports
        ) where
 
-#include "config.h"
+#include "../includes/ghcconfig.h"
 #include "HsVersions.h"
 
 import HsSyn
@@ -43,8 +43,9 @@ import TcType         ( Type, tcSplitFunTys, tcSplitTyConApp_maybe,
                          toDNType
                        )
 import ForeignCall     ( CExportSpec(..), CCallTarget(..), 
+                         CLabelString, isCLabelString,
                          isDynamicTarget, withDNTypes, DNKind(..), DNCallSpec(..) ) 
-import CStrings                ( CLabelString, isCLabelString )
+import MachOp          ( machRepByteWidth )
 import PrelNames       ( hasKey, ioTyConKey )
 import CmdLineOpts     ( dopt_HscLang, HscLang(..) )
 import Outputable
@@ -177,11 +178,11 @@ The check is needed for both via-C and native-code routes
 #include "nativeGen/NCG.h"
 #if alpha_TARGET_ARCH
 checkFEDArgs arg_tys
-  = check (integral_args <= 4) err
+  = check (integral_args <= 32) err
   where
-    integral_args = sum (map getPrimRepSize $
-                         filter (not . isFloatingRep) $
-                         map typePrimRep arg_tys)
+    integral_args = sum [ machRepByteWidth rep
+                       | (rep,hint) <- map typeMachRepRep arg_tys,
+                         hint /= FloatHint ]
     err = ptext SLIT("On Alpha, I can only handle 4 non-floating-point arguments to foreign export dynamic")
 #else
 checkFEDArgs arg_tys = returnM ()
index a7a130d..0670a0c 100644 (file)
@@ -48,9 +48,8 @@ import TysPrim          ( charPrimTy, intPrimTy, floatPrimTy,
 import TysWiredIn ( charTy, stringTy, intTy, 
                    mkListTy, mkPArrTy, mkTupleTy, unitTy,
                    voidTy, listTyCon, tupleTyCon )
-import TyCon     ( mkPrimTyCon, tyConKind )
+import TyCon     ( mkPrimTyCon, tyConKind, PrimRep(..) )
 import Kind      ( splitKindFunTys )
-import PrimRep   ( PrimRep(VoidRep) )
 import Name      ( getOccName, mkInternalName, mkDerivedTyConOcc )
 import Var       ( Var, isId, isLocalVar, tyVarKind )
 import VarSet
index a915651..3f34791 100644 (file)
@@ -167,10 +167,10 @@ data TcGblEnv
                -- accumulated, but never consulted until the end.  
                -- Nevertheless, it's convenient to accumulate them along 
                -- with the rest of the info from this module.
-       tcg_exports :: NameSet,                 -- What is exported
-       tcg_imports :: ImportAvails,            -- Information about what was imported 
-                                               --    from where, including things bound
-                                               --    in this module
+       tcg_exports :: NameSet,         -- What is exported
+       tcg_imports :: ImportAvails,    -- Information about what was imported 
+                                       --    from where, including things bound
+                                       --    in this module
 
        tcg_dus :: DefUses,     -- What is defined in this module and what is used.
                                -- The latter is used to generate 
index 5115beb..51b81d6 100644 (file)
@@ -7,6 +7,9 @@
 module TyCon(
        TyCon, ArgVrcs, 
 
+       PrimRep(..),
+       tyConPrimRep,
+
        AlgTyConRhs(..), visibleDataCons,
 
        isFunTyCon, isUnLiftedTyCon, isProductTyCon, isAbstractTyCon,
@@ -33,7 +36,6 @@ module TyCon(
        algTyConRhs, tyConDataCons, tyConDataCons_maybe, tyConFamilySize,
        tyConSelIds,
        tyConTheta,
-       tyConPrimRep,
        tyConArity,
        isClassTyCon, tyConClass_maybe,
        getSynTyConDefn,
@@ -60,7 +62,6 @@ import Kind           ( Kind )
 import BasicTypes      ( Arity, RecFlag(..), Boxity(..), isBoxed )
 import Name            ( Name, nameUnique, NamedThing(getName) )
 import PrelNames       ( Unique, Uniquable(..) )
-import PrimRep         ( PrimRep(..) )
 import Maybes          ( orElse )
 import Outputable
 import FastString
@@ -109,13 +110,15 @@ data TyCon
 
   | PrimTyCon {                        -- Primitive types; cannot be defined in Haskell
                                -- Now includes foreign-imported types
-       tyConUnique  :: Unique,
-       tyConName    :: Name,
-       tyConKind    :: Kind,
-       tyConArity   :: Arity,
-       argVrcs      :: ArgVrcs,
-       primTyConRep :: PrimRep,        -- Many primitive tycons are unboxed, but some are
-                                       -- boxed (represented by pointers). The PrimRep tells.
+       tyConUnique   :: Unique,
+       tyConName     :: Name,
+       tyConKind     :: Kind,
+       tyConArity    :: Arity,
+       argVrcs       :: ArgVrcs,
+
+       primTyConRep  :: PrimRep,
+                       -- Many primitive tycons are unboxed, but some are
+                       -- boxed (represented by pointers). The CgRep tells.
 
        isUnLifted   :: Bool,           -- Most primitive tycons are unlifted, 
                                        -- but foreign-imported ones may not be
@@ -186,6 +189,42 @@ visibleDataCons (DataTyCon cs _) = cs
 visibleDataCons (NewTyCon c _ _) = [c]
 \end{code}
 
+%************************************************************************
+%*                                                                     *
+\subsection{PrimRep}
+%*                                                                     *
+%************************************************************************
+
+A PrimRep is an abstraction of a type.  It contains information that
+the code generator needs in order to pass arguments, return results,
+and store values of this type.
+
+A PrimRep is somewhat similar to a CgRep (see codeGen/SMRep) and a
+MachRep (see cmm/MachOp), although each of these types has a distinct
+and clearly defined purpose:
+
+  - A PrimRep is a CgRep + information about signedness + information
+    about primitive pointers (AddrRep).  Signedness and primitive
+    pointers are required when passing a primitive type to a foreign
+    function, but aren't needed for call/return conventions of Haskell
+    functions.
+
+  - A MachRep is a basic machine type (non-void, doesn't contain
+    information on pointerhood or signedness, but contains some
+    reps that don't have corresponding Haskell types).
+
+\begin{code}
+data PrimRep
+  = VoidRep
+  | PtrRep
+  | IntRep             -- signed, word-sized
+  | WordRep            -- unsinged, word-sized
+  | Int64Rep           -- signed, 64 bit (32-bit words only)
+  | Word64Rep          -- unsigned, 64 bit (32-bit words only)
+  | AddrRep            -- a pointer, but not to a Haskell value
+  | FloatRep
+  | DoubleRep
+\end{code}
 
 %************************************************************************
 %*                                                                     *
@@ -261,7 +300,6 @@ mkTupleTyCon name kind arity tyvars con boxed gen_info
 -- as primitive, but *lifted*, TyCons for now. They are lifted
 -- because the Haskell type T representing the (foreign) .NET
 -- type T is actually implemented (in ILX) as a thunk<T>
--- They have PtrRep
 mkForeignTyCon name ext_name kind arity arg_vrcs
   = PrimTyCon {
        tyConName    = name,
@@ -269,7 +307,7 @@ mkForeignTyCon name ext_name kind arity arg_vrcs
        tyConKind    = kind,
        tyConArity   = arity,
         argVrcs      = arg_vrcs,
-       primTyConRep = PtrRep,
+       primTyConRep = PtrRep, -- they all do
        isUnLifted   = False,
        tyConExtName = ext_name
     }
@@ -447,13 +485,12 @@ newTyConRep (AlgTyCon {tyConTyVars = tvs, algRhs = NewTyCon _ _ rep}) = (tvs, re
 
 newTyConRhs :: TyCon -> ([TyVar], Type)
 newTyConRhs (AlgTyCon {tyConTyVars = tvs, algRhs = NewTyCon _ rhs _}) = (tvs, rhs)
+\end{code}
 
+\begin{code}
 tyConPrimRep :: TyCon -> PrimRep
 tyConPrimRep (PrimTyCon {primTyConRep = rep}) = rep
-tyConPrimRep tc                                      = ASSERT( not (isUnboxedTupleTyCon tc) )
-                                               PtrRep
-       -- We should not be asking what the representation of an
-       -- unboxed tuple is, because it isn't a first class value.
+tyConPrimRep tc = ASSERT(not (isUnboxedTupleTyCon tc)) PtrRep
 \end{code}
 
 \begin{code}
index bb3c670..c7e5fa2 100644 (file)
@@ -12,6 +12,8 @@ module Type (
        -- Re-exports from Kind
        module Kind,
 
+       -- Re-exports from TyCon
+       PrimRep(..),
 
        mkTyVarTy, mkTyVarTys, getTyVar, getTyVar_maybe, isTyVarTy,
 
@@ -86,14 +88,12 @@ import TyCon        ( TyCon, isRecursiveTyCon, isPrimTyCon,
                  isUnboxedTupleTyCon, isUnLiftedTyCon,
                  isFunTyCon, isNewTyCon, newTyConRep, newTyConRhs,
                  isAlgTyCon, isSynTyCon, tyConArity, 
-                 tyConKind, getSynTyConDefn, 
-                 tyConPrimRep, 
+                 tyConKind, getSynTyConDefn, PrimRep(..), tyConPrimRep,
                )
 
 -- others
 import CmdLineOpts     ( opt_DictsStrict )
 import SrcLoc          ( noSrcLoc )
-import PrimRep         ( PrimRep(..) )
 import Unique          ( Uniquable(..) )
 import Util            ( mapAccumL, seqList, lengthIs, snocView )
 import Outputable
@@ -391,13 +391,20 @@ repType (NewTcApp tc tys) = ASSERT( tys `lengthIs` tyConArity tc )
 repType ty               = ty
 
 
+-- ToDo: this could be moved to the code generator, using splitTyConApp instead
+-- of inspecting the type directly.
 typePrimRep :: Type -> PrimRep
 typePrimRep ty = case repType ty of
                   TyConApp tc _ -> tyConPrimRep tc
                   FunTy _ _     -> PtrRep
-                  AppTy _ _     -> PtrRep      -- ??
+                  AppTy _ _     -> PtrRep      -- See note below
                   TyVarTy _     -> PtrRep
                   other         -> pprPanic "typePrimRep" (ppr ty)
+       -- Types of the form 'f a' must be of kind *, not *#, so
+       -- we are guaranteed that they are represented by pointers.
+       -- The reason is that f must have kind *->*, not *->*#, because
+       -- (we claim) there is no way to constrain f's kind any other
+       -- way.
 
 -- new_type_rep doesn't ask any questions: 
 -- it just expands newtype, whether recursive or not
@@ -407,7 +414,6 @@ new_type_rep new_tycon tys = ASSERT( tys `lengthIs` tyConArity new_tycon )
 \end{code}
 
 
-
 ---------------------------------------------------------------------
                                ForAllTy
                                ~~~~~~~~
index d46b775..8dbfefa 100644 (file)
@@ -3,8 +3,18 @@
 %
 \section{Fast strings}
 
-Compact representations of character strings with
-unique identifiers (hash-cons'ish).
+FastString:    A compact, hash-consed, representation of character strings.
+               Comparison is O(1), and you can get a Unique from them.
+               Generated by the FSLIT macro
+               Turn into SDoc with Outputable.ftext
+
+LitString:     Just a wrapper for the Addr# of a C string (Ptr CChar).
+               Practically no operations
+               Outputing them is fast
+               Generated by the SLIT macro
+               Turn into SDoc with Outputable.ptext
+
+Use LitString unless you want the facilities of FastString
 
 \begin{code}
 module FastString
@@ -498,7 +508,6 @@ hPutFS handle (UnicodeStr _ is)
 -- LitStrings, here for convenience only.
 
 type LitString = Ptr ()
--- ToDo: make it a Ptr when we don't have to support 4.08 any more
 
 mkLitString# :: Addr# -> LitString
 mkLitString# a# = Ptr a#
index d093e43..7f22b38 100644 (file)
@@ -48,6 +48,15 @@ appOL None bs   = bs
 appOL as   None = as
 appOL as   bs   = Two as bs
 
+mapOL :: (a -> b) -> OrdList a -> OrdList b
+mapOL f None = None
+mapOL f (One x) = One (f x)
+mapOL f (Two x y) = Two (mapOL f x) (mapOL f y)
+mapOL f (Many xs) = Many (map f xs)
+
+instance Functor OrdList where
+  fmap = mapOL
+
 foldrOL :: (a->b->b) -> b -> OrdList a -> b
 foldrOL k z None        = z
 foldrOL k z (One x)     = k x z
index 00c9e2f..2a5d3a4 100644 (file)
@@ -20,7 +20,7 @@ module Panic
    ) where
 
 #include "HsVersions.h"
-#include "config.h"
+#include "../includes/ghcconfig.h"
 
 import Config
 import FastTypes
index 6c5d653..61a0321 100644 (file)
@@ -27,6 +27,9 @@ module StringBuffer
          -- * Conversion
         lexemeToString,     -- :: StringBuffer -> Int -> String
         lexemeToFastString, -- :: StringBuffer -> Int -> FastString
+
+        -- * Parsing integers
+        parseInteger,
        ) where
 
 #include "HsVersions.h"
@@ -174,4 +177,13 @@ lexemeToFastString :: StringBuffer -> Int -> FastString
 lexemeToFastString _ 0 = mkFastString ""
 lexemeToFastString (StringBuffer fo _ current#) (I# len) =
     mkFastSubStringBA# fo current# len
+
+-- -----------------------------------------------------------------------------
+-- Parsing integer strings in various bases
+
+parseInteger :: StringBuffer -> Int -> Integer -> (Char->Int) -> Integer
+parseInteger buf len radix to_int 
+  = go 0 0
+  where go i x | i == len  = x
+              | otherwise = go (i+1) (x * radix + toInteger (to_int (lookAhead buf i)))
 \end{code}
index bb22d4e..ed7ee9a 100644 (file)
@@ -10,7 +10,7 @@ module Util (
        zipEqual, zipWithEqual, zipWith3Equal, zipWith4Equal,
         zipLazy, stretchZipWith,
        mapAndUnzip, mapAndUnzip3,
-       nOfThem, 
+       nOfThem, filterOut,
        lengthExceeds, lengthIs, lengthAtLeast, listLengthCmp, atLength,
        isSingleton, only,
        notNull, snocView,
@@ -47,10 +47,13 @@ module Util (
        -- module names
        looksLikeModuleName,
        
-       toArgs
+       toArgs,
+
+       -- Floating point stuff
+       readRational,
     ) where
 
-#include "../includes/config.h"
+#include "../includes/ghcconfig.h"
 #include "HsVersions.h"
 
 import Panic           ( panic, trace )
@@ -68,7 +71,8 @@ import qualified List ( elem, notElem )
 import List            ( zipWith4 )
 #endif
 
-import Char            ( isUpper, isAlphaNum, isSpace )
+import Char            ( isUpper, isAlphaNum, isSpace, ord, isDigit )
+import Ratio           ( (%) )
 
 infixr 9 `thenCmp`
 \end{code}
@@ -128,6 +132,14 @@ nTimes n f = f . nTimes (n-1) f
 %*                                                                     *
 %************************************************************************
 
+\begin{code}
+filterOut :: (a->Bool) -> [a] -> [a]
+-- Like filter, only reverses the sense of the test
+filterOut p [] = []
+filterOut p (x:xs) | p x       = filterOut p xs
+                  | otherwise = x : filterOut p xs
+\end{code}
+
 A paranoid @zip@ (and some @zipWith@ friends) that checks the lists
 are of equal length.  Alastair Reid thinks this should only happen if
 DEBUGging on; hey, why not?
@@ -826,3 +838,53 @@ toArgs s  =
    stripQuotes ('"':xs)  = init xs
    stripQuotes xs        = xs
 \end{code}
+
+-- -----------------------------------------------------------------------------
+-- Floats
+
+\begin{code}
+readRational__ :: ReadS Rational -- NB: doesn't handle leading "-"
+readRational__ r = do 
+     (n,d,s) <- readFix r
+     (k,t)   <- readExp s
+     return ((n%1)*10^^(k-d), t)
+ where
+     readFix r = do
+       (ds,s)  <- lexDecDigits r
+       (ds',t) <- lexDotDigits s
+       return (read (ds++ds'), length ds', t)
+
+     readExp (e:s) | e `elem` "eE" = readExp' s
+     readExp s                    = return (0,s)
+
+     readExp' ('+':s) = readDec s
+     readExp' ('-':s) = do
+                       (k,t) <- readDec s
+                       return (-k,t)
+     readExp' s              = readDec s
+
+     readDec s = do
+        (ds,r) <- nonnull isDigit s
+        return (foldl1 (\n d -> n * 10 + d) [ ord d - ord '0' | d <- ds ],
+                r)
+
+     lexDecDigits = nonnull isDigit
+
+     lexDotDigits ('.':s) = return (span isDigit s)
+     lexDotDigits s       = return ("",s)
+
+     nonnull p s = do (cs@(_:_),t) <- return (span p s)
+                      return (cs,t)
+
+readRational :: String -> Rational -- NB: *does* handle a leading "-"
+readRational top_s
+  = case top_s of
+      '-' : xs -> - (read_me xs)
+      xs       -> read_me xs
+  where
+    read_me s
+      = case (do { (x,"") <- readRational__ s ; return x }) of
+         [x] -> x
+         []  -> error ("readRational: no parse:"        ++ top_s)
+         _   -> error ("readRational: ambiguous parse:" ++ top_s)
+\end{code}
index 8d63c53..889d720 100644 (file)
@@ -63,7 +63,9 @@ identifiers, expressions, rules, and their operations.</strong>
 <p><li>
        TyCon (loop Type.Type, loop Type.Kind, loop DataCon.DataCon, loop Generics.GenInfo)
 <p><li>
-       Type (loop DataCon.DataCon, loop Subst.substTy)
+       TypeRep (loop DataCon.DataCon, loop Subst.substTyWith)
+<p><li>
+       Type (loop PprType.pprType, loop Subst.substTyWith)
 <p><li>
        FieldLabel(Type) <br> 
        TysPrim(Type) <br> 
index 99c81d0..3916591 100644 (file)
@@ -108,7 +108,7 @@ POSIX-compliant to explicitly say so by having <code>#include
 
 <p><li> Some architectures have memory alignment constraints.  Others
 don't have any constraints but go faster if you align things.  These
-macros (from <tt>config.h</tt>) tell you which alignment to use
+macros (from <tt>ghcconfig.h</tt>) tell you which alignment to use
 
 <pre>
   /* minimum alignment of unsigned int */
index b19550d..fbcd934 100644 (file)
@@ -99,19 +99,16 @@ sub init_TARGET_STUFF {
     $T_MOVE_DIRVS   = '^(\s*(\$.*\.\.ng:|\.align\s+\d+|\.(globl|ent)\s+\S+|\#.*|\.(file|loc)\s+\S+\s+\S+|\.text|\.r?data)\n)';
     $T_COPY_DIRVS   = '^\s*(\$.*\.\.ng:|\#|\.(file|globl|ent|loc))';
 
-    $T_hsc_cc_PAT   = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"';
     $T_DOT_WORD            = '\.(long|quad|byte|word)';
     $T_DOT_GLOBAL   = '^\t\.globl';
     $T_HDR_literal  = "\.rdata\n\t\.align 3\n";
     $T_HDR_misc            = "\.text\n\t\.align 3\n";
     $T_HDR_data            = "\.data\n\t\.align 3\n";
-    $T_HDR_consist  = "\.text\n";
+    $T_HDR_rodata   = "\.rdata\n\t\.align 3\n";
     $T_HDR_closure  = "\.data\n\t\.align 3\n";
-    $T_HDR_srt      = "\.text\n\t\.align 3\n";
     $T_HDR_info            = "\.text\n\t\.align 3\n";
     $T_HDR_entry    = "\.text\n\t\.align 3\n";
     $T_HDR_vector   = "\.text\n\t\.align 3\n";
-    $T_HDR_direct   = "\.text\n\t\.align 3\n";
 
     #--------------------------------------------------------#
     } elsif ( $TargetPlatform =~ /^hppa/ ) {
@@ -125,19 +122,16 @@ sub init_TARGET_STUFF {
     $T_MOVE_DIRVS   = '^((\s+\.(IMPORT|EXPORT|PARAM).*|\s+\.align\s+\d+|\s+\.(SPACE|SUBSPA)\s+\S+|\s*)\n)';
     $T_COPY_DIRVS   = '^\s+\.(IMPORT|EXPORT)';
 
-    $T_hsc_cc_PAT   = '\.STRING.*\)(hsc|cc) (.*)\\\\x09(.*)\\\\x00"';
     $T_DOT_WORD            = '\.(blockz|word|half|byte)';
     $T_DOT_GLOBAL   = '^\s+\.EXPORT';
     $T_HDR_literal  = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n";
     $T_HDR_misc            = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
     $T_HDR_data            = "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n";
-    $T_HDR_consist  = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n";
+    $T_HDR_rodata   = "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n";
     $T_HDR_closure  = "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n";
-    $T_HDR_srt      = "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n";
     $T_HDR_info            = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
     $T_HDR_entry    = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
     $T_HDR_vector   = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
-    $T_HDR_direct   = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
 
     #--------------------------------------------------------#
     } elsif ( $TargetPlatform =~ /^i386-.*-(linuxaout|freebsd2|nextstep3|cygwin32|mingw32)$/ ) {
@@ -154,19 +148,16 @@ sub init_TARGET_STUFF {
 
     $T_MOVE_DIRVS   = '^(\s*(\.(p2)?align\s+\d+(,0x90)?|\.globl\s+\S+|\.text|\.data|\.stab[^n].*|\.type\s+.*|\.size\s+.*|\.lcomm.*)\n)';
     $T_COPY_DIRVS   = '\.(globl|stab|lcomm)';
-    $T_hsc_cc_PAT   = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"';
     $T_DOT_WORD            = '\.(long|word|value|byte|space)';
     $T_DOT_GLOBAL   = '\.globl';
     $T_HDR_literal  = "\.text\n\t\.align 2\n";
     $T_HDR_misc            = "\.text\n\t\.align 2,0x90\n";
     $T_HDR_data            = "\.data\n\t\.align 2\n";
-    $T_HDR_consist  = "\.text\n";
+    $T_HDR_rodata   = "\.text\n\t\.align 2\n";
     $T_HDR_closure  = "\.data\n\t\.align 2\n";
-    $T_HDR_srt      = "\.text\n\t\.align 2\n";
     $T_HDR_info            = "\.text\n\t\.align 2\n"; # NB: requires padding
     $T_HDR_entry    = "\.text\n"; # no .align so we're right next to _info (arguably wrong...?)
     $T_HDR_vector   = "\.text\n\t\.align 2\n"; # NB: requires padding
-    $T_HDR_direct   = "\.text\n\t\.align 2,0x90\n";
 
     #--------------------------------------------------------#
     } elsif ( $TargetPlatform =~ /^i386-.*-(solaris2|linux|freebsd|netbsd|openbsd)$/ ) {
@@ -184,24 +175,16 @@ sub init_TARGET_STUFF {
     $T_MOVE_DIRVS   = '^(\s*(\.(p2)?align\s+\d+(,\s*0x90)?|\.globl\s+\S+|\.text|\.data|\.section\s+.*|\.type\s+.*|\.size\s+\S+\s*,\s*\d+|\.ident.*|\.local.*)\n)';
     $T_COPY_DIRVS   = '^\s*\.(globl|type|size|local)';
 
-    if ( $TargetPlatform =~ /freebsd|netbsd/ ) {
-        $T_hsc_cc_PAT   = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"';
-    } else {
-        $T_hsc_cc_PAT   = '\.string.*\)(hsc|cc) (.*)\\\\t(.*)"';
-    }
-
     $T_DOT_WORD            = '\.(long|value|word|byte|zero)';
     $T_DOT_GLOBAL   = '\.globl';
     $T_HDR_literal  = "\.section\t\.rodata\n"; # or just use .text??? (WDP 95/11)
     $T_HDR_misc            = "\.text\n\t\.align 4\n";
-    $T_HDR_data            = "\.data\n\t\.align 4\n"; # ToDo: change align??
-    $T_HDR_consist  = "\.text\n";
-    $T_HDR_closure  = "\.data\n\t\.align 4\n"; # ToDo: change align?
-    $T_HDR_srt      = "\.text\n\t\.align 4\n"; # ToDo: change align?
-    $T_HDR_info            = "\.text\n\t\.align 4\n"; # NB: requires padding
+    $T_HDR_data            = "\.data\n\t\.align 4\n";
+    $T_HDR_rodata   = "\.section\t\.rodata\n\t\.align 4\n";
+    $T_HDR_closure  = "\.data\n\t\.align 4\n";
+    $T_HDR_info            = "\.text\n\t\.align 4\n";
     $T_HDR_entry    = "\.text\n"; # no .align so we're right next to _info (arguably wrong...?)
     $T_HDR_vector   = "\.text\n\t\.align 4\n"; # NB: requires padding
-    $T_HDR_direct   = "\.text\n\t\.align 4\n";
 
     #--------------------------------------------------------#
     } elsif ( $TargetPlatform =~ /^ia64-.*-linux$/ ) {
@@ -215,19 +198,16 @@ sub init_TARGET_STUFF {
     $T_MOVE_DIRVS   = '^(\s*\.(global|proc|pred\.safe_across_calls|text|data|section|subsection|align|size|type|ident)\s+.*\n)';
     $T_COPY_DIRVS   = '\.(global|proc)';
 
-    $T_hsc_cc_PAT   = '\.string.*\)(hsc|cc) (.*)\\\\t(.*)"';
     $T_DOT_WORD     = '\.(long|value|byte|zero)';
     $T_DOT_GLOBAL   = '\.global';
     $T_HDR_literal  = "\.section\t\.rodata\n";
     $T_HDR_misc     = "\.text\n\t\.align 8\n";
     $T_HDR_data     = "\.data\n\t\.align 8\n";
-    $T_HDR_consist  = "\.text\n";
+    $T_HDR_rodata   = "\.section\t\.rodata\n\t\.align 8\n";
     $T_HDR_closure  = "\.data\n\t\.align 8\n";
-    $T_HDR_srt      = "\.text\n\t\.align 8\n";
     $T_HDR_info     = "\.text\n\t\.align 8\n";
     $T_HDR_entry    = "\.text\n\t\.align 16\n";
     $T_HDR_vector   = "\.text\n\t\.align 8\n";
-    $T_HDR_direct   = "\.text\n\t\.align 8\n";
 
     #--------------------------------------------------------#
     } elsif ( $TargetPlatform =~ /^x86_64-.*-(linux|openbsd)$/ ) {
@@ -241,19 +221,16 @@ sub init_TARGET_STUFF {
     $T_MOVE_DIRVS   = '^(\s*\.(globl|text|data|section|align|size|type|ident|local)\s+.*\n)';
     $T_COPY_DIRVS   = '\.(globl|local)';
 
-    $T_hsc_cc_PAT   = '\.string.*\)(hsc|cc) (.*)\\\\t(.*)"';
     $T_DOT_WORD     = '\.(quad|long|value|byte|zero)';
     $T_DOT_GLOBAL   = '\.global';
     $T_HDR_literal  = "\.section\t\.rodata\n";
     $T_HDR_misc     = "\.text\n\t\.align 8\n";
     $T_HDR_data     = "\.data\n\t\.align 8\n";
-    $T_HDR_consist  = "\.text\n";
+    $T_HDR_rodata   = "\.section\t\.rodata\n\t\.align 8\n";
     $T_HDR_closure  = "\.data\n\t\.align 8\n";
-    $T_HDR_srt      = "\.text\n\t\.align 8\n";
     $T_HDR_info     = "\.text\n\t\.align 8\n";
     $T_HDR_entry    = "\.text\n\t\.align 8\n";
     $T_HDR_vector   = "\.text\n\t\.align 8\n";
-    $T_HDR_direct   = "\.text\n\t\.align 8\n";
 
     #--------------------------------------------------------#
     } elsif ( $TargetPlatform =~ /^m68k-.*-sunos4/ ) {
@@ -266,20 +243,17 @@ sub init_TARGET_STUFF {
 
     $T_MOVE_DIRVS   = '^(\s*(\.align\s+\d+|\.proc\s+\d+|\.const|\.cstring|\.globl\s+\S+|\.text|\.data|\.even|\.stab[^n].*)\n)';
     $T_COPY_DIRVS   = '\.(globl|proc|stab)';
-    $T_hsc_cc_PAT   = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"';
 
     $T_DOT_WORD            = '\.long';
     $T_DOT_GLOBAL   = '\.globl';
     $T_HDR_literal  = "\.text\n\t\.even\n";
     $T_HDR_misc            = "\.text\n\t\.even\n";
     $T_HDR_data            = "\.data\n\t\.even\n";
-    $T_HDR_consist  = "\.text\n";
+    $T_HDR_rodata   = "\.text\n\t\.even\n";
     $T_HDR_closure  = "\.data\n\t\.even\n";
-    $T_HDR_srt      = "\.text\n\t\.even\n";
     $T_HDR_info            = "\.text\n\t\.even\n";
     $T_HDR_entry    = "\.text\n\t\.even\n";
     $T_HDR_vector   = "\.text\n\t\.even\n";
-    $T_HDR_direct   = "\.text\n\t\.even\n";
 
     #--------------------------------------------------------#
     } elsif ( $TargetPlatform =~ /^mips-.*/ ) {
@@ -293,19 +267,16 @@ sub init_TARGET_STUFF {
     $T_MOVE_DIRVS   = '^(\s*(\.align\s+\d+|\.(globl|ent)\s+\S+|\.text|\.r?data)\n)';
     $T_COPY_DIRVS   = '\.(globl|ent)';
 
-    $T_hsc_cc_PAT   = 'I WAS TOO LAZY TO DO THIS BIT (WDP 95/05)';
     $T_DOT_WORD            = '\.word';
     $T_DOT_GLOBAL   = '^\t\.globl';
     $T_HDR_literal  = "\t\.rdata\n\t\.align 2\n";
     $T_HDR_misc            = "\t\.text\n\t\.align 2\n";
     $T_HDR_data            = "\t\.data\n\t\.align 2\n";
-    $T_HDR_consist  = 'TOO LAZY TO DO THIS TOO';
+    $T_HDR_rodata   = "\t\.rdata\n\t\.align 2\n";
     $T_HDR_closure  = "\t\.data\n\t\.align 2\n";
-    $T_HDR_srt      = "\t\.text\n\t\.align 2\n";
     $T_HDR_info            = "\t\.text\n\t\.align 2\n";
     $T_HDR_entry    = "\t\.text\n\t\.align 2\n";
     $T_HDR_vector   = "\t\.text\n\t\.align 2\n";
-    $T_HDR_direct   = "\t\.text\n\t\.align 2\n";
 
     #--------------------------------------------------------#
     } elsif ( $TargetPlatform =~ /^powerpc-apple-.*/ ) {
@@ -319,20 +290,17 @@ sub init_TARGET_STUFF {
     $T_MOVE_DIRVS   = '^(\s*(\.align \d+|\.text|\.data|\.const_data|\.cstring|\.non_lazy_symbol_pointer|\.const|\.static_const|\.literal4|\.literal8|\.static_data|\.globl \S+|\.section .*|\.lcomm.*)\n)';
     $T_COPY_DIRVS   = '\.(globl|lcomm)';
 
-    $T_hsc_cc_PAT   = '\.byte.*\)(hsc|cc) (.*)"\n\t\.byte \d+\n\t\.byte "(.*)"\n\t\.byte \d+';
     $T_DOT_WORD            = '\.(long|short|byte|fill|space)';
     $T_DOT_GLOBAL   = '\.globl';
     $T_HDR_toc      = "\.toc\n";
     $T_HDR_literal  = "\t\.const_data\n\t\.align 2\n";
     $T_HDR_misc            = "\t\.text\n\t\.align 2\n";
     $T_HDR_data            = "\t\.data\n\t\.align 2\n";
-    $T_HDR_consist  = "\t\.text\n\t\.align 2\n";
+    $T_HDR_rodata   = "\t\.const_data\n\t\.align 2\n";
     $T_HDR_closure  = "\t\.const_data\n\t\.align 2\n";
-    $T_HDR_srt      = "\t\.text\n\t\.align 2\n";
     $T_HDR_info            = "\t\.text\n\t\.align 2\n";
     $T_HDR_entry    = "\t\.text\n\t\.align 2\n";
     $T_HDR_vector   = "\t\.text\n\t\.align 2\n";
-    $T_HDR_direct   = "\t\.text\n\t\.align 2\n";
 
     #--------------------------------------------------------#
     } elsif ( $TargetPlatform =~ /^powerpc-.*-linux/ ) {
@@ -346,20 +314,17 @@ sub init_TARGET_STUFF {
     $T_MOVE_DIRVS   = '^(\s*(\.(p2)?align\s+\d+(,\s*0x90)?|\.globl\s+\S+|\.text|\.data|\.section\s+.*|\.type\s+.*|\.size\s+\S+\s*,\s*\d+|\.ident.*|\.local.*)\n)';
     $T_COPY_DIRVS   = '^\s*\.(globl|type|size|local)';
 
-    $T_hsc_cc_PAT   = '\.string.*\)(hsc|cc) (.*)\\\\t(.*)"';
     $T_DOT_WORD            = '\.(long|short|byte|fill|space)';
     $T_DOT_GLOBAL   = '\.globl';
     $T_HDR_toc      = "\.toc\n";
     $T_HDR_literal  = "\t\.section\t.rodata\n\t\.align 2\n";
     $T_HDR_misc            = "\t\.text\n\t\.align 2\n";
     $T_HDR_data            = "\t\.data\n\t\.align 2\n";
-    $T_HDR_consist  = "\t\.text\n\t\.align 2\n";
+    $T_HDR_rodata   = "\t\.section\t.rodata\n\t\.align 2\n";
     $T_HDR_closure  = "\t\.data\n\t\.align 2\n";
-    $T_HDR_srt      = "\t\.text\n\t\.align 2\n";
     $T_HDR_info            = "\t\.text\n\t\.align 2\n";
     $T_HDR_entry    = "\t\.text\n\t\.align 2\n";
     $T_HDR_vector   = "\t\.text\n\t\.align 2\n";
-    $T_HDR_direct   = "\t\.text\n\t\.align 2\n";
 
     #--------------------------------------------------------#
     } elsif ( $TargetPlatform =~ /^sparc-.*-(solaris2|openbsd)/ ) {
@@ -373,19 +338,15 @@ sub init_TARGET_STUFF {
     $T_MOVE_DIRVS   = '^((\s+\.align\s+\d+|\s+\.proc\s+\d+|\s+\.global\s+\S+|\.text|\.data|\.stab.*|\.section.*|\s+\.type.*|\s+\.size.*)\n)';
     $T_COPY_DIRVS   = '\.(global|proc|stab)';
 
-    $T_hsc_cc_PAT   = '\.asciz.*\)(hsc|cc) (.*)\\\\t(.*)"';
     $T_DOT_WORD            = '\.(long|word|byte|half|skip|uahalf|uaword)';
     $T_DOT_GLOBAL   = '^\t\.global';
     $T_HDR_literal  = "\.text\n\t\.align 8\n";
     $T_HDR_misc            = "\.text\n\t\.align 4\n";
     $T_HDR_data            = "\.data\n\t\.align 8\n";
-    $T_HDR_consist  = "\.text\n";
+    $T_HDR_rodata   = "\.text\n\t\.align 4\n";
     $T_HDR_closure  = "\.data\n\t\.align 4\n";
-    $T_HDR_srt      = "\.data\n\t\.align 4\n";
-    $T_HDR_info            = "\.text\n\t\.align 4\n";
     $T_HDR_entry    = "\.text\n\t\.align 4\n";
     $T_HDR_vector   = "\.text\n\t\.align 4\n";
-    $T_HDR_direct   = "\.text\n\t\.align 4\n";
 
     #--------------------------------------------------------#
     } elsif ( $TargetPlatform =~ /^sparc-.*-sunos4/ ) {
@@ -398,20 +359,17 @@ sub init_TARGET_STUFF {
 
     $T_MOVE_DIRVS   = '^((\s+\.align\s+\d+|\s+\.proc\s+\d+|\s+\.global\s+\S+|\.text|\.data|\.stab.*)\n)';
     $T_COPY_DIRVS   = '\.(global|proc|stab)';
-    $T_hsc_cc_PAT   = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"';
 
     $T_DOT_WORD            = '\.word';
     $T_DOT_GLOBAL   = '^\t\.global';
     $T_HDR_literal  = "\.text\n\t\.align 8\n";
     $T_HDR_misc            = "\.text\n\t\.align 4\n";
     $T_HDR_data            = "\.data\n\t\.align 8\n";
-    $T_HDR_consist  = "\.text\n";
+    $T_HDR_rodata   = "\.text\n\t\.align 4\n";
     $T_HDR_closure  = "\.data\n\t\.align 4\n";
-    $T_HDR_srt      = "\.data\n\t\.align 4\n";
     $T_HDR_info            = "\.text\n\t\.align 4\n";
     $T_HDR_entry    = "\.text\n\t\.align 4\n";
     $T_HDR_vector   = "\.text\n\t\.align 4\n";
-    $T_HDR_direct   = "\.text\n\t\.align 4\n";
 
     #--------------------------------------------------------#
     } elsif ( $TargetPlatform =~ /^sparc-.*-linux/ ) {
@@ -425,19 +383,16 @@ sub init_TARGET_STUFF {
     $T_MOVE_DIRVS   = '^((\s+\.align\s+\d+|\s+\.proc\s+\d+|\s+\.global\s+\S+|\.text|\.data|\.seg|\.stab.*|\t?\.section.*|\s+\.type.*|\s+\.size.*)\n)';
     $T_COPY_DIRVS   = '\.(global|globl|proc|stab)';
 
-    $T_hsc_cc_PAT   = '\.asciz.*\)(hsc|cc) (.*)\\\\t(.*)"';
     $T_DOT_WORD     = '\.(long|word|nword|xword|byte|half|short|skip|uahalf|uaword)';
     $T_DOT_GLOBAL   = '^\t\.global';
     $T_HDR_literal  = "\.text\n\t\.align 8\n";
     $T_HDR_misc     = "\.text\n\t\.align 4\n";
     $T_HDR_data     = "\.data\n\t\.align 8\n";
-    $T_HDR_consist  = "\.text\n";
+    $T_HDR_rodata   = "\.text\n\t\.align 4\n";
     $T_HDR_closure  = "\.data\n\t\.align 4\n";
-    $T_HDR_srt      = "\.data\n\t\.align 4\n";
     $T_HDR_info     = "\.text\n\t\.align 4\n";
     $T_HDR_entry    = "\.text\n\t\.align 4\n";
     $T_HDR_vector   = "\.text\n\t\.align 4\n";
-    $T_HDR_direct   = "\.text\n\t\.align 4\n";
 
     #--------------------------------------------------------#
     } else {
@@ -458,17 +413,15 @@ if ( $TargetPlatform =~ /^i386-/ ) {
 }
 print STDERR "T_MOVE_DIRVS: $T_MOVE_DIRVS\n";
 print STDERR "T_COPY_DIRVS: $T_COPY_DIRVS\n";
-print STDERR "T_hsc_cc_PAT: $T_hsc_cc_PAT\n";
 print STDERR "T_DOT_WORD: $T_DOT_WORD\n";
 print STDERR "T_HDR_literal: $T_HDR_literal\n";
 print STDERR "T_HDR_misc: $T_HDR_misc\n";
 print STDERR "T_HDR_data: $T_HDR_data\n";
-print STDERR "T_HDR_consist: $T_HDR_consist\n";
+print STDERR "T_HDR_rodata: $T_HDR_rodata\n";
 print STDERR "T_HDR_closure: $T_HDR_closure\n";
 print STDERR "T_HDR_info: $T_HDR_info\n";
 print STDERR "T_HDR_entry: $T_HDR_entry\n";
 print STDERR "T_HDR_vector: $T_HDR_vector\n";
-print STDERR "T_HDR_direct: $T_HDR_direct\n";
 }
 
 }
@@ -541,6 +494,12 @@ sub mangle_asm {
            $chkcat[$i]  = 'data';
            $chksymb[$i] = '';
 
+       # Labels beginning "_c": these are literal strings.
+       } elsif ( /^${T_US}_c.*$/ ) {
+           $chk[++$i]   = $_;
+           $chkcat[$i]  = 'rodata';
+           $chksymb[$i] = '';
+
        } elsif ( /^\s+/ ) { # most common case first -- a simple line!
            # duplicated from the bottom
 
@@ -891,6 +850,7 @@ sub mangle_asm {
                    $e =~ s/^\tlw?z? r\d+,\d+\(r1\)\n//; 
                    $e =~ s/^\tmtlr r0\n//;
                    $e =~ s/^\tblr\n//;
+                   $e =~ s/^\tb restFP ;.*\n//;
                } else {
                    print STDERR "$Pgm: unknown epilogue mangling? $TargetPlatform\n";
                }
@@ -1085,42 +1045,6 @@ sub mangle_asm {
                print OUTASM $chk[$i];
            }
 
-       } elsif ( $chkcat[$i] eq 'consist' ) {
-           if ( $chk[$i] =~ /$T_hsc_cc_PAT/o ) {
-               local($consist) = "$1.$2.$3";
-               $consist =~ s/,/./g;
-               $consist =~ s/\//./g;
-               $consist =~ s/-/_/g;
-               $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly?
-               #
-               # Using a cygnus-2.7-96q4 gcc build on hppas, the 
-               # consistency chunk for ghc_cc_ID often (but not always!)
-               # gets lumped with a bunch of .IMPORT directives containing info on
-               # the code or data space nature of external symbols. We can't
-               # toss these, so once the consistency ID has been turned into
-               # a representable symbol, we substitute it for the symbol
-               # that the string was attached to in the first place (ghc_cc_ID.)
-               # (The original string is also substituted away.)
-               #
-               # This change may affect the code output on other platforms in
-               # adverse ways, hence we restrict this hack hppa targets only.
-               #
-               #    -- 2/98 SOF
-               if ( $TargetPlatform =~ /^hppa/ )  {
-                       $chk[$i] =~ s/^${T_US}ghc.*c_ID$TPOSTLBL/$consist/o;
-                       $chk[$i] =~ s/\t$T_hsc_cc_PAT/$T_HDR_misc/o;
-                       $consist = $chk[$i]; #clumsily
-                }
-               print OUTASM $T_HDR_consist, "${consist}${T_POST_LBL}\n";
-
-           } elsif ( $TargetPlatform !~ /^(mips)-/ ) { # we just don't try in those case (ToDo)
-               # on mips: consistency string is just a v
-               # horrible bunch of .bytes,
-               # which I am too lazy to sort out (WDP 95/05)
-
-               print STDERR "Couldn't grok consistency: ", $chk[$i];
-           }
-
        } elsif ( $chkcat[$i] eq 'splitmarker' ) {
            # we can just re-constitute this one...
            # NB: we emit _three_ underscores no matter what,
@@ -1142,7 +1066,7 @@ sub mangle_asm {
 
            # SRT
            if ( defined($srtchk{$symb}) ) {
-               print OUTASM $T_HDR_srt;
+               print OUTASM $T_HDR_rodata;
                print OUTASM $chk[$srtchk{$symb}];
                $chkcat[$srtchk{$symb}] = 'DONE ALREADY';
            }
@@ -1158,11 +1082,18 @@ sub mangle_asm {
                $chkcat[$infochk{$symb}] = 'DONE ALREADY';
            }
 
-           # STD ENTRY POINT
+           # ENTRY POINT
            if ( defined($entrychk{$symb}) ) {
 
                $c = $chk[$entrychk{$symb}];
 
+               # If this is an entry point with an info table,
+                # eliminate the entry symbol and all directives involving it.
+               if (defined($infochk{$symb}) && $TargetPlatform !~ /^ia64-/) {
+                       $c =~ s/^.*$symb_(entry|ret)${T_POST_LBL}\n//;
+                       $c =~ s/^\s*\..*$symb.*\n//g;
+               }
+
                print OUTASM $T_HDR_entry;
 
                &print_doctored($c, 1); # NB: the 1!!!
@@ -1170,8 +1101,7 @@ sub mangle_asm {
                $chkcat[$entrychk{$symb}] = 'DONE ALREADY';
            }
            
-       } elsif ( $chkcat[$i] eq 'vector'
-              || $chkcat[$i] eq 'direct' ) { # do them in that order
+       } elsif ( $chkcat[$i] eq 'vector' ) {
            $symb = $chksymb[$i];
 
            # VECTOR TABLE
@@ -1192,6 +1122,11 @@ sub mangle_asm {
                print OUTASM "\t# nop\n";
            }
            
+       } elsif ( $chkcat[$i] eq 'rodata' ) {
+               print OUTASM $T_HDR_rodata;
+               print OUTASM $chk[$i];
+               $chkcat[$i] = 'DONE ALREADY';
+
        } elsif ( $chkcat[$i] eq 'toc' ) {
             # silly optimisation to print tocs, since they come in groups...
            print OUTASM $T_HDR_toc;
index ac30e8c..d7599c5 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Block.h,v 1.16 2003/11/26 12:14:26 simonmar Exp $
+ * $Id: Block.h,v 1.17 2004/08/13 13:09:09 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
  * on a 32-bit machine.
  */
 
-typedef struct _bdescr {
+#ifndef CMINUSMINUS
+typedef struct bdescr_ {
   StgPtr start;                        /* start addr of memory */
   StgPtr free;                 /* first free byte of memory */
-  struct _bdescr *link;                /* used for chaining blocks together */
+  struct bdescr_ *link;                /* used for chaining blocks together */
   union { 
-      struct _bdescr *back;    /* used (occasionally) for doubly-linked lists*/
+      struct bdescr_ *back;    /* used (occasionally) for doubly-linked lists*/
       StgWord *bitmap;
   } u;
   unsigned int gen_no;         /* generation */
@@ -65,6 +66,7 @@ typedef struct _bdescr {
   StgWord32 _padding[0];
 #endif
 } bdescr;
+#endif
 
 #if SIZEOF_VOID_P == 8
 #define BDESCR_SIZE  0x40
@@ -76,17 +78,25 @@ typedef struct _bdescr {
 #define BDESCR_SHIFT 5
 #endif
 
-// Block contains objects evacuated during this GC
+/* Block contains objects evacuated during this GC */
 #define BF_EVACUATED 1
-// Block is a large object
+/* Block is a large object */
 #define BF_LARGE     2
-// Block is pinned
+/* Block is pinned */
 #define BF_PINNED    4
-// Block is part of a compacted generation
+/* Block is part of a compacted generation */
 #define BF_COMPACTED 8
 
 /* Finding the block descriptor for a given block -------------------------- */
 
+#ifdef CMINUSMINUS
+
+#define Bdescr(p) \
+    ((((p) &  MBLOCK_MASK & ~BLOCK_MASK) >> (BLOCK_SHIFT-BDESCR_SHIFT)) \
+     | ((p) & ~MBLOCK_MASK))
+
+#else
+
 INLINE_HEADER bdescr *Bdescr(StgPtr p)
 {
   return (bdescr *)
@@ -95,6 +105,8 @@ INLINE_HEADER bdescr *Bdescr(StgPtr p)
      );
 }
 
+#endif
+
 /* Useful Macros ------------------------------------------------------------ */
 
 /* Offset of first real data block in a megablock */
@@ -129,4 +141,20 @@ INLINE_HEADER bdescr *Bdescr(StgPtr p)
 #define BLOCKS_TO_MBLOCKS(n) \
    (1 + (W_)MBLOCK_ROUND_UP((n-BLOCKS_PER_MBLOCK) * BLOCK_SIZE) / MBLOCK_SIZE)
 
+
+/* Double-linked block lists: --------------------------------------------- */
+
+#ifndef CMINUSMINUS
+INLINE_HEADER void
+dbl_link_onto(bdescr *bd, bdescr **list)
+{
+  bd->link = *list;
+  bd->u.back = NULL;
+  if (*list) {
+    (*list)->u.back = bd; /* double-link the list */
+  }
+  *list = bd;
+}
+#endif
+
 #endif /* BLOCK_H */
diff --git a/ghc/includes/CCall.h b/ghc/includes/CCall.h
deleted file mode 100644 (file)
index 3040c17..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: CCall.h,v 1.4 2000/01/13 14:34:00 hwloidl Exp $
- *
- * (c) The GHC Team, 1998-1999
- *
- * Macros for performing C calls from the STG world.
- *
- * -------------------------------------------------------------------------- */
-
-#ifndef CCALL_H
-#define CCALL_H
-
-/* 
- * Most C-Calls made from STG land are of the 'unsafe' variety.
- * An unsafe C-Call is one where we trust the C function not to do
- * anything nefarious while it has control.
- *
- * Nefarious actions include doing allocation on the Haskell heap,
- * garbage collecting, creating/deleting threads, re-entering the
- * scheduler, and messing with runtime system data structures.
- * 
- * For these calls, the code generator will kindly provide CALLER_SAVE
- * and CALLER_RESTORE macros for any registers that are live across the
- * call.  These macros may expand into saves of the relevant registers
- * if those registers are designated caller-saves by the C calling
- * convention, otherwise they will expand to nothing.
- */
-
-/* Unsafe C-Calls have no macros: we just use a straightforward call.
- */
-
-/*
- * An STGCALL<n> is used when we want the relevant registers to be
- * saved automatically.  An STGCALL doesn't return a result, there's
- * an alternative set of RET_STGCALL<n> macros for that (and we hope
- * that the restoring of the caller-saves registers doesn't clobber
- * the result!)
- */
-
-#define STGCALL0(f) \
-  CALLER_SAVE_ALL (void) f(); CALLER_RESTORE_ALL
-
-#define STGCALL1(f,a) \
-  CALLER_SAVE_ALL (void) f(a); CALLER_RESTORE_ALL
-
-#define STGCALL2(f,a,b) \
-  CALLER_SAVE_ALL (void) f(a,b); CALLER_RESTORE_ALL
-
-#define STGCALL3(f,a,b,c) \
-  CALLER_SAVE_ALL (void) f(a,b,c); CALLER_RESTORE_ALL
-
-#define STGCALL4(f,a,b,c,d) \
-  CALLER_SAVE_ALL (void) f(a,b,c,d); CALLER_RESTORE_ALL
-
-#define STGCALL5(f,a,b,c,d,e) \
-  CALLER_SAVE_ALL (void) f(a,b,c,d,e); CALLER_RESTORE_ALL
-
-#define STGCALL6(f,a,b,c,d,e,z) \
-  CALLER_SAVE_ALL (void) f(a,b,c,d,e,z); CALLER_RESTORE_ALL
-
-
-#define RET_STGCALL0(t,f) \
-  ({ t _r; CALLER_SAVE_ALL _r = f(); CALLER_RESTORE_ALL; _r; })
-
-#define RET_STGCALL1(t,f,a) \
-  ({ t _r; CALLER_SAVE_ALL _r = f(a); CALLER_RESTORE_ALL; _r; })
-
-#define RET_STGCALL2(t,f,a,b) \
-  ({ t _r; CALLER_SAVE_ALL _r = f(a,b); CALLER_RESTORE_ALL; _r; })
-
-#define RET_STGCALL3(t,f,a,b,c) \
-  ({ t _r; CALLER_SAVE_ALL _r = f(a,b,c); CALLER_RESTORE_ALL; _r; })
-
-#define RET_STGCALL4(t,f,a,b,c,d) \
-  ({ t _r; CALLER_SAVE_ALL _r = f(a,b,c,d); CALLER_RESTORE_ALL; _r; })
-
-#define RET_STGCALL5(t,f,a,b,c,d,e) \
-  ({ t _r; CALLER_SAVE_ALL _r = f(a,b,c,d,e); CALLER_RESTORE_ALL; _r; })
-
-#define RET_STGCALL6(t,f,a,b,c,d,e,z) \
-  ({ t _r; CALLER_SAVE_ALL _r = f(a,b,c,d,e,z); CALLER_RESTORE_ALL; _r; })
-
-
-/*
- * A PRIM_STGCALL is used when we have arranged to save the R<n>,
- * F<n>, and D<n> registers already, we only need the "system"
- * registers saved for us.  These are used in PrimOps, where the
- * compiler has a good idea of what registers are live, and so doesn't
- * need to save all of them.
- */
-
-#define PRIM_STGCALL0(f) \
-  CALLER_SAVE_SYSTEM (void) f(); CALLER_RESTORE_SYSTEM
-
-#define PRIM_STGCALL1(f,a) \
-  CALLER_SAVE_SYSTEM (void) f(a); CALLER_RESTORE_SYSTEM
-
-#define PRIM_STGCALL2(f,a,b) \
-  CALLER_SAVE_SYSTEM (void) f(a,b); CALLER_RESTORE_SYSTEM
-
-#define PRIM_STGCALL3(f,a,b,c) \
-  CALLER_SAVE_SYSTEM (void) f(a,b,c); CALLER_RESTORE_SYSTEM
-
-#define PRIM_STGCALL4(f,a,b,c,d) \
-  CALLER_SAVE_SYSTEM (void) f(a,b,c,d); CALLER_RESTORE_SYSTEM
-
-#define PRIM_STGCALL5(f,a,b,c,d,e) \
-  CALLER_SAVE_SYSTEM (void) f(a,b,c,d,e); CALLER_RESTORE_SYSTEM
-
-#define PRIM_STGCALL6(f,a,b,c,d,e,z) \
-  CALLER_SAVE_SYSTEM (void) f(a,b,c,d,e,z); CALLER_RESTORE_SYSTEM
-
-
-#define RET_PRIM_STGCALL0(t,f) \
-  ({ t _r; CALLER_SAVE_SYSTEM _r = f(); CALLER_RESTORE_SYSTEM; _r; })
-
-#define RET_PRIM_STGCALL1(t,f,a) \
-  ({ t _r; CALLER_SAVE_SYSTEM _r = f(a); CALLER_RESTORE_SYSTEM; _r; })
-
-#define RET_PRIM_STGCALL2(t,f,a,b) \
-  ({ t _r; CALLER_SAVE_SYSTEM _r = f(a,b); CALLER_RESTORE_SYSTEM; _r; })
-
-#define RET_PRIM_STGCALL3(t,f,a,b,c) \
-  ({ t _r; CALLER_SAVE_SYSTEM _r = f(a,b,c); CALLER_RESTORE_SYSTEM; _r; })
-
-#define RET_PRIM_STGCALL4(t,f,a,b,c,d) \
-  ({ t _r; CALLER_SAVE_SYSTEM _r = f(a,b,c,d); CALLER_RESTORE_SYSTEM; _r; })
-
-#define RET_PRIM_STGCALL5(t,f,a,b,c,d,e) \
-  ({ t _r; CALLER_SAVE_SYSTEM _r = f(a,b,c,d,e); CALLER_RESTORE_SYSTEM; _r; })
-
-#define RET_PRIM_STGCALL6(t,f,a,b,c,d,e,z) \
-  ({ t _r; CALLER_SAVE_SYSTEM _r = f(a,b,c,d,e,z); CALLER_RESTORE_SYSTEM; _r; })
-
-/* ToDo: ccalls that might garbage collect - do we need to return to
- * the scheduler to perform these?  Similarly, ccalls that might want
- * to call Haskell right back, or start a new thread or something.
- */
-
-#endif /* CCALL_H */
-
index b977851..e2519bb 100644 (file)
@@ -1,7 +1,6 @@
 /* ----------------------------------------------------------------------------
- * $Id: ClosureMacros.h,v 1.38 2003/11/12 17:27:00 sof Exp $
  *
- * (c) The GHC Team, 1998-1999
+ * (c) The GHC Team, 1998-2004
  *
  * Macros for building and manipulating closures
  *
@@ -52,7 +51,6 @@
  
    -------------------------------------------------------------------------- */
 
-#define INIT_INFO(i)  info : (StgInfoTable *)&(i)
 #define SET_INFO(c,i) ((c)->header.info = (i))
 #define GET_INFO(c)   ((c)->header.info)
 #define GET_ENTRY(c)  (ENTRY_CODE(GET_INFO(c)))
 #define get_fun_itbl(c) (FUN_INFO_PTR_TO_STRUCT((c)->header.info))
 #define get_thunk_itbl(c) (THUNK_INFO_PTR_TO_STRUCT((c)->header.info))
 
+#define GET_TAG(con) (get_itbl(con)->srt_bitmap)
 
 #ifdef TABLES_NEXT_TO_CODE
-#define INIT_ENTRY(e)
-#define ENTRY_CODE(info) (info)
 #define INFO_PTR_TO_STRUCT(info) ((StgInfoTable *)(info) - 1)
 #define RET_INFO_PTR_TO_STRUCT(info) ((StgRetInfoTable *)(info) - 1)
 #define FUN_INFO_PTR_TO_STRUCT(info) ((StgFunInfoTable *)(info) - 1)
 #define THUNK_INFO_PTR_TO_STRUCT(info) ((StgThunkInfoTable *)(info) - 1)
-INLINE_HEADER StgFunPtr get_entry(const StgInfoTable *itbl) {
-    return (StgFunPtr)(itbl+1);
-}
 #define itbl_to_fun_itbl(i) ((StgFunInfoTable *)(((StgInfoTable *)(i) + 1)) - 1)
 #define itbl_to_ret_itbl(i) ((StgRetInfoTable *)(((StgInfoTable *)(i) + 1)) - 1)
 #define itbl_to_thunk_itbl(i) ((StgThunkInfoTable *)(((StgInfoTable *)(i) + 1)) - 1)
 #else
-#define INIT_ENTRY(e)    entry : (F_)(e)
-#define ENTRY_CODE(info) (((StgInfoTable *)info)->entry)
 #define INFO_PTR_TO_STRUCT(info) ((StgInfoTable *)info)
 #define RET_INFO_PTR_TO_STRUCT(info) ((StgRetInfoTable *)info)
 #define FUN_INFO_PTR_TO_STRUCT(info) ((StgFunInfoTable *)info)
 #define THUNK_INFO_PTR_TO_STRUCT(info) ((StgThunkInfoTable *)info)
-INLINE_HEADER StgFunPtr get_entry(const StgInfoTable *itbl) {
-    return itbl->entry;
-}
 #define itbl_to_fun_itbl(i) ((StgFunInfoTable *)(i))
 #define itbl_to_ret_itbl(i) ((StgRetInfoTable *)(i))
 #define itbl_to_thunk_itbl(i) ((StgThunkInfoTable *)(i))
@@ -104,7 +93,6 @@ INLINE_HEADER StgFunPtr get_entry(const StgInfoTable *itbl) {
   Note: change those functions building Haskell objects from C datatypes, i.e.,
   all rts_mk???() functions in RtsAPI.c, as well.
  */
-extern StgWord flip;
 #define SET_PROF_HDR(c,ccs_)            \
         ((c)->header.prof.ccs = ccs_, (c)->header.prof.hp.rs = (retainerSet *)((StgWord)NULL | flip))
 #else
@@ -125,10 +113,10 @@ extern StgWord flip;
  */
 #define SET_PROF_HDR(c,ccs_)            \
         ((c)->header.prof.ccs = ccs_,   \
-        LDV_recordCreate((c)))
+        LDV_RECORD_CREATE((c)))
 #endif  // DEBUG_RETAINER
 #define SET_STATIC_PROF_HDR(ccs_)       \
-        prof : { ccs : ccs_, hp : { rs : NULL } },
+        prof : { ccs : (CostCentreStack *)ccs_, hp : { rs : NULL } },
 #else
 #define SET_PROF_HDR(c,ccs)
 #define SET_STATIC_PROF_HDR(ccs)
@@ -158,9 +146,9 @@ extern StgWord flip;
 #define SET_STATIC_TICKY_HDR(stuff)
 #endif
 
-#define SET_HDR(c,info,ccs)                            \
+#define SET_HDR(c,_info,ccs)                           \
    {                                                   \
-       SET_INFO(c,info);                               \
+       (c)->header.info = _info;                       \
        SET_GRAN_HDR((StgClosure *)(c),ThisPE);         \
        SET_PAR_HDR((StgClosure *)(c),LOCAL_GA);        \
        SET_PROF_HDR((StgClosure *)(c),ccs);            \
@@ -172,34 +160,13 @@ extern StgWord flip;
    (c)->words = n_words;
 
 /* -----------------------------------------------------------------------------
-   Static closures are defined as follows:
-
-
-   SET_STATIC_HDR(PrelBase_CZh_closure,PrelBase_CZh_info,costCentreStack,closure_class,info_class);
-
-   The info argument must have type 'StgInfoTable' or
-   'StgSRTInfoTable', since we use '&' to get its address in the macro.
+   How to get hold of the static link field for a static closure.
+   
+   Note that we have to use (*cast(T*,&e)) instead of cast(T,e)
+   because C won't let us take the address of a casted
+   expression. Huh?
    -------------------------------------------------------------------------- */
 
-#define SET_STATIC_HDR(label,info,costCentreStack,closure_class,info_class)    \
-   info_class info;                                                            \
-   closure_class StgClosure label = {                                          \
-   STATIC_HDR(info,costCentreStack)
-
-#define STATIC_HDR(info,ccs)                   \
-       header : {                              \
-               INIT_INFO(info),                \
-               SET_STATIC_GRAN_HDR             \
-               SET_STATIC_PAR_HDR(LOCAL_GA)    \
-               SET_STATIC_PROF_HDR(ccs)        \
-               SET_STATIC_TICKY_HDR(0)         \
-       }
-
-/* how to get hold of the static link field for a static closure.
- *
- * Note that we have to use (*cast(T*,&e)) instead of cast(T,e)
- * because C won't let us take the address of a casted expression. Huh?
- */
 #define STATIC_LINK(info,p)                                            \
    (*(StgClosure**)(&((p)->payload[info->layout.payload.ptrs +         \
                                        info->layout.payload.nptrs])))
@@ -230,17 +197,4 @@ extern StgWord flip;
 #define CHARLIKE_CLOSURE(n) ((P_)&stg_CHARLIKE_closure[(n)-MIN_CHARLIKE])
 #define INTLIKE_CLOSURE(n)  ((P_)&stg_INTLIKE_closure[(n)-MIN_INTLIKE])
 
-/* -----------------------------------------------------------------------------
-   Closure Tables (for enumerated data types)
-   -------------------------------------------------------------------------- */
-
-#define CLOSURE_TBL(lbl) const StgClosure *lbl[] = {
-
-/* -----------------------------------------------------------------------------
-   CONSTRs.
-   -------------------------------------------------------------------------- */
-
-/* constructors don't have SRTs */
-#define GET_TAG(info) (INFO_PTR_TO_STRUCT(info)->srt_bitmap)
-
 #endif /* CLOSUREMACROS_H */
index 1b4fb0a..d546792 100644 (file)
@@ -1,7 +1,6 @@
 /* ----------------------------------------------------------------------------
- * $Id: Closures.h,v 1.35 2003/11/14 14:28:07 stolz Exp $
  *
- * (c) The GHC Team, 1998-1999
+ * (c) The GHC Team, 1998-2004
  *
  * Closures
  *
@@ -52,8 +51,6 @@ typedef struct {
 #endif
 } StgHeader;
 
-#define FIXED_HS (sizeof(StgHeader))
-
 /* -----------------------------------------------------------------------------
    Closure Types
 
@@ -233,11 +230,53 @@ typedef struct {
 #define BCO_BITMAP_SIZEW(bco) ((BCO_BITMAP_SIZE(bco) + BITS_IN(StgWord) - 1) \
                                / BITS_IN(StgWord))
 
-/* Dynamic stack frames - these have a liveness mask in the object
- * itself, rather than in the info table.  Useful for generic heap
- * check code.  See StgMacros.h, HEAP_CHK_GEN().
- */
+/* -----------------------------------------------------------------------------
+   Dynamic stack frames for generic heap checks.
+
+   These generic heap checks are slow, but have the advantage of being
+   usable in a variety of situations.
+
+   The one restriction is that any relevant SRTs must already be pointed
+   to from the stack.  The return address doesn't need to have an info
+   table attached: hence it can be any old code pointer.
+
+   The liveness mask contains a 1 at bit n, if register Rn contains a
+   non-pointer.  The contents of all 8 vanilla registers are always saved
+   on the stack; the liveness mask tells the GC which ones contain
+   pointers.
+
+   Good places to use a generic heap check: 
+
+        - case alternatives (the return address with an SRT is already
+         on the stack).
+
+       - primitives (no SRT required).
+
+   The stack frame layout for a RET_DYN is like this:
+
+          some pointers         |-- RET_DYN_PTRS(liveness) words
+          some nonpointers      |-- RET_DYN_NONPTRS(liveness) words
+                              
+         L1                    \
+          D1-2                  |-- RET_DYN_NONPTR_REGS_SIZE words
+         F1-4                  /
+                              
+         R1-8                  |-- RET_DYN_BITMAP_SIZE words
+                              
+         return address        \
+         liveness mask         |-- StgRetDyn structure
+         stg_gen_chk_info      /
+
+   we assume that the size of a double is always 2 pointers (wasting a
+   word when it is only one pointer, but avoiding lots of #ifdefs).
+
+   See Liveness.h for the macros (RET_DYN_PTRS() etc.).
+
+   NOTE: if you change the layout of RET_DYN stack frames, then you
+   might also need to adjust the value of RESERVED_STACK_WORDS in
+   Constants.h.
+   -------------------------------------------------------------------------- */
+
 typedef struct {
     const struct _StgInfoTable* info;
     StgWord        liveness;
diff --git a/ghc/includes/Cmm.h b/ghc/includes/Cmm.h
new file mode 100644 (file)
index 0000000..608e97d
--- /dev/null
@@ -0,0 +1,465 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The University of Glasgow 2004
+ *
+ * This file is included at the top of all .cmm source files (and
+ * *only* .cmm files).  It defines a collection of useful macros for
+ * making .cmm code a bit less error-prone to write, and a bit easier
+ * on the eye for the reader.
+ *
+ * For the syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
+ *
+ * If you're used to the old HC file syntax, here's a quick cheat sheet
+ * for converting HC code:
+ *
+ *       - Remove FB_/FE_
+ *       - Remove all type casts
+ *       - Remove '&'
+ *       - STGFUN(foo) { ... }  ==>  foo { ... }
+ *       - FN_(foo) { ... }  ==>  foo { ... }
+ *       - JMP_(e)  ==> jump e;
+ *       - Remove EXTFUN(foo)
+ *       - Sp[n]  ==>  Sp(n)
+ *       - Hp[n]  ==>  Hp(n)
+ *       - Sp += n  ==> Sp_adj(n)
+ *       - Hp += n  ==> Hp_adj(n)
+ *       - R1.i   ==>  R1   (similarly for R1.w, R1.cl etc.)
+ *       - You need to explicitly dereference variables; eg. 
+ *             context_switch   ==>  CInt[context_switch]
+ *       - convert all word offsets into byte offsets:
+ *             - e ==> WDS(e)
+ *       - sizeofW(StgFoo)  ==>  SIZEOF_StgFoo
+ *       - ENTRY_CODE(e)  ==>  %ENTRY_CODE(e)
+ *       - get_itbl(c)  ==>  %GET_STD_INFO(c)
+ *       - Change liveness masks in STK_CHK_GEN, HP_CHK_GEN:
+ *             R1_PTR | R2_PTR  ==>  R1_PTR & R2_PTR
+ *             (NOTE: | becomes &)
+ *       - Declarations like 'StgPtr p;' become just 'W_ p;'
+ *       - e->payload[n] ==> PAYLOAD(e,n)
+ *       - Be very careful with comparisons: the infix versions (>, >=, etc.)
+ *         are unsigned, so use %lt(a,b) to get signed less-than for example.
+ *
+ * Accessing fields of structures defined in the RTS header files is
+ * done via automatically-generated macros in DerivedConstants.h.  For
+ * example, where previously we used
+ *
+ *          CurrentTSO->what_next = x
+ *
+ * in C-- we now use
+ *
+ *          StgTSO_what_next(CurrentTSO) = x
+ *
+ * where the StgTSO_what_next() macro is automatically generated by
+ * mkDerivedConstnants.c.  If you need to access a field that doesn't
+ * already have a macro, edit that file (it's pretty self-explanatory).
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef CMM_H
+#define CMM_H
+
+// In files that are included into both C and C-- (and perhaps
+// Haskell) sources, we sometimes need to conditionally compile bits
+// depending on the language.  CMINUSMINUS==1 in .cmm sources:
+#define CMINUSMINUS 1
+
+#include "ghcconfig.h"
+#include "RtsConfig.h"
+
+/* -----------------------------------------------------------------------------
+   Types 
+
+   The following synonyms for C-- types are declared here:
+
+     I8, I16, I32, I64    MachRep-style names for convenience
+
+     W_                   is shorthand for the word type (== StgWord)
+     F_                          shorthand for float  (F_ == StgFloat == C's float)
+     D_                          shorthand for double (D_ == StgDouble == C's double)
+
+     CInt                has the same size as an int in C on this platform
+     CLong               has the same size as a long in C on this platform
+   
+  --------------------------------------------------------------------------- */
+
+#define I8  bits8
+#define I16 bits16
+#define I32 bits32
+#define I64 bits64
+
+#if SIZEOF_VOID_P == 4
+#define W_ bits32
+#elif SIZEOF_VOID_P == 8
+#define W_ bits64
+#else
+#error Unknown word size
+#endif
+
+#if SIZEOF_INT == 4
+#define CInt bits32
+#elif SIZEOF_INT = 8
+#define CInt bits64
+#else
+#error Unknown int size
+#endif
+
+#if SIZEOF_LONG == 4
+#define CLong bits32
+#elif SIZEOF_LONG = 8
+#define CLong bits64
+#else
+#error Unknown long size
+#endif
+
+#define F_ float32
+#define D_ float64
+#define L_ bits64
+
+#define SIZEOF_StgDouble 8
+#define SIZEOF_StgWord64 8
+
+/* -----------------------------------------------------------------------------
+   Misc useful stuff
+   -------------------------------------------------------------------------- */
+
+#define NULL (0::W_)
+
+#define STRING(name,str)                       \
+  section "rodata" {                           \
+       name : bits8[] str;                     \
+  }                                            \
+
+/* -----------------------------------------------------------------------------
+   Byte/word macros
+
+   Everything in C-- is in byte offsets (well, most things).  We use
+   some macros to allow us to express offsets in words and to try to
+   avoid byte/word confusion.
+   -------------------------------------------------------------------------- */
+
+#define SIZEOF_W  SIZEOF_VOID_P
+#define W_MASK    (SIZEOF_W-1)
+
+#if SIZEOF_W == 4
+#define W_SHIFT 2
+#elif SIZEOF_W == 8
+#define W_SHIFT 4
+#endif
+
+// Converting quantities of words to bytes
+#define WDS(n) ((n)*SIZEOF_W)
+
+// Converting quantities of bytes to words
+// NB. these work on *unsigned* values only
+#define BYTES_TO_WDS(n) ((n) / SIZEOF_W)
+#define ROUNDUP_BYTES_TO_WDS(n) (((n) + SIZEOF_W - 1) / SIZEOF_W)
+
+// TO_W_(n) converts n to W_ type from a smaller type
+#if SIZEOF_W == 4
+#define TO_W_(x) %sx32(x)
+#define HALF_W_(x) %lobits16(x)
+#elif SIZEOF_W == 8
+#define TO_W_(x) %sx64(x)
+#define HALF_W_(x) %lobits32(x)
+#endif
+
+/* -----------------------------------------------------------------------------
+   Heap/stack access, and adjusting the heap/stack pointers.
+   -------------------------------------------------------------------------- */
+
+#define Sp(n)  W_[Sp + WDS(n)]
+#define Hp(n)  W_[Hp + WDS(n)]
+
+#define Sp_adj(n) Sp = Sp + WDS(n)
+#define Hp_adj(n) Hp = Hp + WDS(n)
+
+/* -----------------------------------------------------------------------------
+   Assertions and Debuggery
+   -------------------------------------------------------------------------- */
+
+#ifdef DEBUG
+#define ASSERT(predicate)                      \
+       if (predicate) {                        \
+           /*null*/;                           \
+       } else {                                \
+           foreign "C" _stgAssert(NULL, __LINE__); \
+        }
+#else
+#define ASSERT(p) /* nothing */
+#endif
+
+#ifdef DEBUG
+#define DEBUG_ONLY(s) s
+#else
+#define DEBUG_ONLY(s) /* nothing */
+#endif
+
+//
+// The IF_DEBUG macro is useful for debug messages that depend on one
+// of the RTS debug options.  For example:
+// 
+//   IF_DEBUG(RtsFlags_DebugFlags_apply,
+//      foreign "C" fprintf(stderr, stg_ap_0_ret_str));
+//
+// Note the syntax is slightly different to the C version of this macro.
+//
+#ifdef DEBUG
+#define IF_DEBUG(c,s)  if (RtsFlags_DebugFlags_##c(RtsFlags)) { s; }
+#else
+#define IF_DEBUG(c,s)  /* nothing */
+#endif
+
+/* -----------------------------------------------------------------------------
+   Entering 
+
+   It isn't safe to "enter" every closure.  Functions in particular
+   have no entry code as such; their entry point contains the code to
+   apply the function.
+
+   ToDo: range should end in N_CLOSURE_TYPES-1, not N_CLOSURE_TYPES,
+   but switch doesn't allow us to use exprs there yet.
+   -------------------------------------------------------------------------- */
+
+#define ENTER()                                                \
+ again:                                                        \
+  switch [INVALID_OBJECT .. N_CLOSURE_TYPES]           \
+         (TO_W_( %INFO_TYPE(%GET_STD_INFO(R1)) )) {    \
+  case                                                         \
+    IND,                                               \
+    IND_OLDGEN,                                                \
+    IND_PERM,                                          \
+    IND_OLDGEN_PERM,                                   \
+    IND_STATIC:                                                \
+   {                                                   \
+      R1 = StgInd_indirectee(R1);                      \
+      goto again;                                      \
+   }                                                   \
+  case                                                         \
+    BCO,                                               \
+    FUN,                                               \
+    FUN_1_0,                                           \
+    FUN_0_1,                                           \
+    FUN_2_0,                                           \
+    FUN_1_1,                                           \
+    FUN_0_2,                                           \
+    FUN_STATIC,                                                \
+    PAP:                                               \
+   {                                                   \
+      jump %ENTRY_CODE(Sp(0));                         \
+   }                                                   \
+  default:                                             \
+   {                                                   \
+      jump %GET_ENTRY(R1);                             \
+   }                                                   \
+  }
+
+/* -----------------------------------------------------------------------------
+   Constants.
+   -------------------------------------------------------------------------- */
+
+#include "Constants.h"
+#include "DerivedConstants.h"
+#include "ClosureTypes.h"
+#include "StgFun.h"
+
+//
+// Need MachRegs, because some of the RTS code is conditionally
+// compiled based on REG_R1, REG_R2, etc.
+//
+#define STOLEN_X86_REGS 4
+#include "MachRegs.h"
+
+#include "Liveness.h"
+#include "StgLdvProf.h"
+
+#undef BLOCK_SIZE
+#undef MBLOCK_SIZE
+#include "Block.h"  // For Bdescr()
+
+
+// Can't think of a better place to put this.
+#if SIZEOF_mp_limb_t != SIZEOF_VOID_P
+#error mp_limb_t != StgWord: assumptions in PrimOps.cmm are now false
+#endif
+
+/* -------------------------------------------------------------------------
+   Allocation and garbage collection
+   ------------------------------------------------------------------------- */
+
+// ALLOC_PRIM is for allocating memory on the heap for a primitive
+// object.  It is used all over PrimOps.cmm.
+//
+// We make the simplifying assumption that the "admin" part of a
+// primitive closure is just the header when calculating sizes for
+// ticky-ticky.  It's not clear whether eg. the size field of an array
+// should be counted as "admin", or the various fields of a BCO.
+//
+#define ALLOC_PRIM(bytes,liveness,reentry)                     \
+   HP_CHK_GEN_TICKY(bytes,liveness,reentry);                   \
+   TICK_ALLOC_PRIM(SIZEOF_StgHeader,bytes-SIZEOF_StgHeader,0); \
+   CCCS_ALLOC(bytes);
+
+// CCS_ALLOC wants the size in words, because ccs->mem_alloc is in words
+#define CCCS_ALLOC(__alloc) CCS_ALLOC(BYTES_TO_WDS(__alloc), W_[CCCS])
+
+#define HP_CHK_GEN_TICKY(alloc,liveness,reentry)       \
+   HP_CHK_GEN(alloc,liveness,reentry);                 \
+   TICK_ALLOC_HEAP_NOCTR(alloc);
+
+#define MAYBE_GC(liveness,reentry)                     \
+   if (CInt[alloc_blocks] >= CInt[alloc_blocks_lim]) { \
+       R9  = liveness;                                 \
+        R10 = reentry;                                 \
+        jump stg_gc_gen_hp;                            \
+   }
+
+/* -----------------------------------------------------------------------------
+   Closures
+   -------------------------------------------------------------------------- */
+
+// The offset of the payload of an array
+#define BYTE_ARR_CTS(arr)  ((arr) + SIZEOF_StgArrWords)
+
+// Getting/setting the info pointer of a closure
+#define SET_INFO(p,info) StgHeader_info(p) = info
+#define GET_INFO(p) StgHeader_info(p)
+
+// Determine the size of an ordinary closure from its info table
+#define sizeW_fromITBL(itbl) \
+  SIZEOF_StgHeader + WDS(%INFO_PTRS(itbl)) + WDS(%INFO_NPTRS(itbl))
+
+// NB. duplicated from InfoTables.h!
+#define BITMAP_SIZE(bitmap) ((bitmap) & BITMAP_SIZE_MASK)
+#define BITMAP_BITS(bitmap) ((bitmap) >> BITMAP_BITS_SHIFT)
+
+// Debugging macros
+#define LOOKS_LIKE_INFO_PTR(p)                         \
+   ((p) != NULL &&                                     \
+     (TO_W_(%INFO_TYPE(%STD_INFO(p))) != INVALID_OBJECT) &&    \
+     (TO_W_(%INFO_TYPE(%STD_INFO(p))) <  N_CLOSURE_TYPES))
+
+#define LOOKS_LIKE_CLOSURE_PTR(p) (LOOKS_LIKE_INFO_PTR(GET_INFO(p)))
+
+//
+// The layout of the StgFunInfoExtra part of an info table changes
+// depending on TABLES_NEXT_TO_CODE.  So we define field access
+// macros which use the appropriate version here:
+//
+#ifdef TABLES_NEXT_TO_CODE
+#define StgFunInfoExtra_slow_apply(i) StgFunInfoExtraRev_slow_apply(i)
+#define StgFunInfoExtra_fun_type(i)   StgFunInfoExtraRev_fun_type(i)
+#define StgFunInfoExtra_arity(i)      StgFunInfoExtraRev_arity(i)
+#define StgFunInfoExtra_bitmap(i)     StgFunInfoExtraRev_bitmap(i)
+#else
+#define StgFunInfoExtra_slow_apply(i) StgFunInfoExtraFwd_slow_apply(i)
+#define StgFunInfoExtra_fun_type(i)   StgFunInfoExtraFwd_fun_type(i)
+#define StgFunInfoExtra_arity(i)      StgFunInfoExtraFwd_arity(i)
+#define StgFunInfoExtra_bitmap(i)     StgFunInfoExtraFwd_bitmap(i)
+#endif
+
+/* -----------------------------------------------------------------------------
+   Voluntary Yields/Blocks
+
+   We only have a generic version of this at the moment - if it turns
+   out to be slowing us down we can make specialised ones.
+   -------------------------------------------------------------------------- */
+
+#define YIELD(liveness,reentry)                        \
+   R9  = liveness;                             \
+   R10 = reentry;                              \
+   jump stg_gen_yield;
+
+#define BLOCK(liveness,reentry)                        \
+   R9  = liveness;                             \
+   R10 = reentry;                              \
+   jump stg_gen_block;
+
+/* -----------------------------------------------------------------------------
+   Ticky macros 
+   -------------------------------------------------------------------------- */
+
+#ifdef TICKY_TICKY
+#define TICK_BUMP_BY(ctr,n) CLong[ctr] = CLong[ctr] + n
+#else
+#define TICK_BUMP_BY(ctr,n) /* nothing */
+#endif
+
+#define TICK_BUMP(ctr)      TICK_BUMP_BY(ctr,1)
+
+#define TICK_ENT_DYN_IND()             TICK_BUMP(ENT_DYN_IND_ctr)
+#define TICK_ENT_DYN_THK()             TICK_BUMP(ENT_DYN_THK_ctr)
+#define TICK_ENT_VIA_NODE()            TICK_BUMP(ENT_VIA_NODE_ctr)
+#define TICK_ENT_STATIC_IND()                  TICK_BUMP(ENT_STATIC_IND_ctr)
+#define TICK_ENT_PERM_IND()            TICK_BUMP(ENT_PERM_IND_ctr)
+#define TICK_ENT_PAP()                 TICK_BUMP(ENT_PAP_ctr)
+#define TICK_ENT_AP()                          TICK_BUMP(ENT_AP_ctr)
+#define TICK_ENT_AP_STACK()            TICK_BUMP(ENT_AP_STACK_ctr)
+#define TICK_ENT_BH()                          TICK_BUMP(ENT_BH_ctr)
+#define TICK_UNKNOWN_CALL()            TICK_BUMP(UNKNOWN_CALL_ctr)
+#define TICK_UPDF_PUSHED()             TICK_BUMP(UPDF_PUSHED_ctr)
+#define TICK_CATCHF_PUSHED()           TICK_BUMP(CATCHF_PUSHED_ctr)
+#define TICK_UPDF_OMITTED()            TICK_BUMP(UPDF_OMITTED_ctr)
+#define TICK_UPD_NEW_IND()             TICK_BUMP(UPD_NEW_IND_ctr)
+#define TICK_UPD_NEW_PERM_IND()        TICK_BUMP(UPD_NEW_PERM_IND_ctr)
+#define TICK_UPD_OLD_IND()             TICK_BUMP(UPD_OLD_IND_ctr)
+#define TICK_UPD_OLD_PERM_IND()        TICK_BUMP(UPD_OLD_PERM_IND_ctr)
+  
+#define TICK_SLOW_CALL_FUN_TOO_FEW()   TICK_BUMP(SLOW_CALL_FUN_TOO_FEW_ctr)
+#define TICK_SLOW_CALL_FUN_CORRECT()   TICK_BUMP(SLOW_CALL_FUN_CORRECT_ctr)
+#define TICK_SLOW_CALL_FUN_TOO_MANY()  TICK_BUMP(SLOW_CALL_FUN_TOO_MANY_ctr)
+#define TICK_SLOW_CALL_PAP_TOO_FEW()   TICK_BUMP(SLOW_CALL_PAP_TOO_FEW_ctr)
+#define TICK_SLOW_CALL_PAP_CORRECT()   TICK_BUMP(SLOW_CALL_PAP_CORRECT_ctr)
+#define TICK_SLOW_CALL_PAP_TOO_MANY()  TICK_BUMP(SLOW_CALL_PAP_TOO_MANY_ctr)
+
+#define TICK_SLOW_CALL_v()             TICK_BUMP(SLOW_CALL_v_ctr)
+#define TICK_SLOW_CALL_p()             TICK_BUMP(SLOW_CALL_p_ctr)
+#define TICK_SLOW_CALL_pv()            TICK_BUMP(SLOW_CALL_pv_ctr)
+#define TICK_SLOW_CALL_pp()            TICK_BUMP(SLOW_CALL_pp_ctr)
+#define TICK_SLOW_CALL_ppp()           TICK_BUMP(SLOW_CALL_ppp_ctr)
+#define TICK_SLOW_CALL_pppp()                  TICK_BUMP(SLOW_CALL_pppp_ctr)
+#define TICK_SLOW_CALL_ppppp()         TICK_BUMP(SLOW_CALL_ppppp_ctr)
+#define TICK_SLOW_CALL_pppppp()        TICK_BUMP(SLOW_CALL_pppppp_ctr)
+
+#ifdef TICKY_TICKY
+#define TICK_HISTO_BY(histo,n,i)                       \
+        W_ __idx;                                      \
+        __idx = (n);                                   \
+        if (__idx > 8) {                               \
+           __idx = 8;                                  \
+         }                                             \
+        CLong[histo##_hst + _idx*SIZEOF_LONG]          \
+          = histo##_hst + __idx*SIZEOF_LONG] + i;
+#else
+#define TICK_HISTO_BY(histo,n,i) /* nothing */
+#endif
+
+#define TICK_HISTO(histo,n) TICK_HISTO_BY(histo,n,1)
+
+// An unboxed tuple with n components.
+#define TICK_RET_UNBOXED_TUP(n)                        \
+  TICK_BUMP(RET_UNBOXED_TUP_ctr++);            \
+  TICK_HISTO(RET_UNBOXED_TUP,n)
+
+// A slow call with n arguments.  In the unevald case, this call has
+// already been counted once, so don't count it again.
+#define TICK_SLOW_CALL(n)                      \
+  TICK_BUMP(SLOW_CALL_ctr);                    \
+  TICK_HISTO(SLOW_CALL,n)
+
+// This slow call was found to be to an unevaluated function; undo the
+// ticks we did in TICK_SLOW_CALL.
+#define TICK_SLOW_CALL_UNEVALD(n)              \
+  TICK_BUMP(SLOW_CALL_UNEVALD_ctr);            \
+  TICK_BUMP_BY(SLOW_CALL_ctr,-1);              \
+  TICK_HISTO_BY(SLOW_CALL,n,-1);
+
+// Updating a closure with a new CON
+#define TICK_UPD_CON_IN_NEW(n)                 \
+  TICK_BUMP(UPD_CON_IN_NEW_ctr);               \
+  TICK_HISTO(UPD_CON_IN_NEW,n)
+
+#define TICK_ALLOC_HEAP_NOCTR(n)               \
+    TICK_BUMP(ALLOC_HEAP_ctr);                 \
+    TICK_BUMP_BY(ALLOC_HEAP_tot,n)
+
+#endif // CMM_H
index 8974052..2d99ae9 100644 (file)
@@ -1,5 +1,5 @@
 /* ----------------------------------------------------------------------------
- * $Id: Constants.h,v 1.25 2003/04/28 09:55:20 simonmar Exp $
+ * $Id: Constants.h,v 1.26 2004/08/13 13:09:13 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2002
  *
@@ -62,8 +62,7 @@
  * space. 
  */
 
-#define MAX_SPEC_AP_SIZE       8
-/* ToDo: make it 8 again */
+#define MAX_SPEC_AP_SIZE       7
 
 /* Specialised FUN/THUNK/CONSTR closure types */
 
 #define MAX_SPEC_FUN_SIZE      2
 #define MAX_SPEC_CONSTR_SIZE   2
 
+/* Range of built-in table of static small int-like and char-like closures. 
+ * 
+ *   NB. This corresponds with the number of actual INTLIKE/CHARLIKE
+ *   closures defined in rts/StgMiscClosures.cmm.
+ */
+#define MAX_INTLIKE            16
+#define MIN_INTLIKE            (-16)
+
+#define MAX_CHARLIKE           255
+#define MIN_CHARLIKE           0
+
 /* -----------------------------------------------------------------------------
    STG Registers.
 
 #define MAX_VANILLA_REG 8
 #define MAX_FLOAT_REG   4
 #define MAX_DOUBLE_REG  2
-/* register is only used for returning (unboxed) 64-bit vals */
 #define MAX_LONG_REG    1
 
-/*---- Maximum number of constructors in a data type for direct-returns.  */
+/* -----------------------------------------------------------------------------
+ *  Maximum number of constructors in a data type for direct-returns. 
+ *
+ *   NB. There are various places that assume the value of this
+ *   constant, such as the polymorphic return frames for updates
+ *   (stg_upd_frame_info) and catch frames (stg_catch_frame_info).
+ * -------------------------------------------------------------------------- */
 
 #define MAX_VECTORED_RTN 8
 
-/*---- Range of built-in table of static small int-like and char-like closures. */
-
-#define MAX_INTLIKE            16
-#define MIN_INTLIKE            (-16)
-
-#define MAX_CHARLIKE           255
-#define MIN_CHARLIKE           0
-
-/* You can change these constants (I hope) but be sure to modify
-   rts/StgMiscClosures.hs accordingly. */
-
 /* -----------------------------------------------------------------------------
    Semi-Tagging constants
 
 #error unknown SIZEOF_VOID_P
 #endif
 
+/* -----------------------------------------------------------------------------
+   Lag/Drag/Void constants
+   -------------------------------------------------------------------------- */
+
+/*
+  An LDV word is divided into 3 parts: state bits (LDV_STATE_MASK), creation 
+  time bits (LDV_CREATE_MASK), and last use time bits (LDV_LAST_MASK). 
+ */
+#if SIZEOF_VOID_P == 8
+#define LDV_SHIFT               30
+#define LDV_STATE_MASK          0x1000000000000000
+#define LDV_CREATE_MASK         0x0FFFFFFFC0000000
+#define LDV_LAST_MASK           0x000000003FFFFFFF
+#define LDV_STATE_CREATE        0x0000000000000000
+#define LDV_STATE_USE           0x1000000000000000
+#else
+#define LDV_SHIFT               15
+#define LDV_STATE_MASK          0x40000000 
+#define LDV_CREATE_MASK         0x3FFF8000
+#define LDV_LAST_MASK           0x00007FFF
+#define LDV_STATE_CREATE        0x00000000
+#define LDV_STATE_USE           0x40000000
+#endif  // SIZEOF_VOID_P
+
+/* -----------------------------------------------------------------------------
+   TSO related constants
+   -------------------------------------------------------------------------- */
+
+/*
+ * Constants for the what_next field of a TSO, which indicates how it
+ * is to be run.
+ */
+#define ThreadRunGHC    1      /* return to address on top of stack */
+#define ThreadInterpret 2      /* interpret this thread */
+#define ThreadKilled   3       /* thread has died, don't run it */
+#define ThreadRelocated        4       /* thread has moved, link points to new locn */
+#define ThreadComplete 5       /* thread has finished */
+
+/*
+ * Constants for the why_blocked field of a TSO
+ */
+#define NotBlocked          0
+#define BlockedOnMVar       1
+#define BlockedOnBlackHole  2
+#define BlockedOnException  3
+#define BlockedOnRead       4
+#define BlockedOnWrite      5
+#define BlockedOnDelay      6
+
+/* Win32 only: */
+#define BlockedOnDoProc     7
+
+/* Only relevant for PAR: */
+  /* blocked on a remote closure represented by a Global Address: */
+#define BlockedOnGA         8
+  /* same as above but without sending a Fetch message */
+#define BlockedOnGA_NoSend  9
+/* Only relevant for RTS_SUPPORTS_THREADS: */
+#define BlockedOnCCall      10
+#define BlockedOnCCall_NoUnblockExc 11
+   /* same as above but don't unblock async exceptions in resumeThread() */
+
+/*
+ * These constants are returned to the scheduler by a thread that has
+ * stopped for one reason or another.  See typedef StgThreadReturnCode
+ * in TSO.h.
+ */
+#define HeapOverflow   1               /* might also be StackOverflow */
+#define StackOverflow  2
+#define ThreadYielding 3
+#define ThreadBlocked  4
+#define ThreadFinished 5
+
+/* -----------------------------------------------------------------------------
+   RET_DYN stack frames
+   -------------------------------------------------------------------------- */
+
+/* VERY MAGIC CONSTANTS! 
+ * must agree with code in HeapStackCheck.c, stg_gen_chk, and
+ * RESERVED_STACK_WORDS in Constants.h.
+ */
+#define RET_DYN_BITMAP_SIZE 8
+#define RET_DYN_NONPTR_REGS_SIZE 10
+
+/* Sanity check that RESERVED_STACK_WORDS is reasonable.  We can't
+ * just derive RESERVED_STACK_WORDS because it's used in Haskell code
+ * too.
+ */
+#if RESERVED_STACK_WORDS != (3 + RET_DYN_BITMAP_SIZE + RET_DYN_NONPTR_REGS_SIZE)
+#error RESERVED_STACK_WORDS may be wrong!
+#endif
+
 #endif /* CONSTANTS_H */
diff --git a/ghc/includes/Derived.h b/ghc/includes/Derived.h
deleted file mode 100644 (file)
index f65cfc8..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: Derived.h,v 1.2 2001/08/04 06:09:24 ken Exp $
- *
- * (c) The GHC Team, 1998-2001
- *
- * Configuration information derived from config.h.
- *
- * NOTE: assumes #include "config.h"
- * 
- * NB: THIS FILE IS INCLUDED IN NON-C CODE AND DATA!  #defines only please.
- * ---------------------------------------------------------------------------*/
-
-#ifndef DERIVED_H
-#define DERIVED_H
-
-/*
- * SUPPORT_LONG_LONGS controls whether we need to support long longs on a
- * particular platform.   On 64-bit platforms, we don't need to support
- * long longs since regular machine words will do just fine.
- */
-#if HAVE_LONG_LONG && SIZEOF_VOID_P < 8
-#define SUPPORT_LONG_LONGS 1
-#endif
-
-/*
- * Whether the runtime system will use libbfd for debugging purposes.
- */
-#if defined(DEBUG) && defined(HAVE_BFD_H) && !defined(_WIN32) && !defined(PAR) && !defined(GRAN)
-#define USING_LIBBFD 1
-#endif
-
-#endif /* DERIVED_H */
diff --git a/ghc/includes/DietHEP.h b/ghc/includes/DietHEP.h
deleted file mode 100644 (file)
index 28b3c05..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-
-typedef enum { dh_stdcall, dh_ccall } DH_CALLCONV;
-typedef int                           DH_MODULE;
-typedef char*                         DH_LPCSTR;
-
-extern __attribute__((__stdcall__))
-       DH_MODULE DH_LoadLibrary    ( DH_LPCSTR modname );
-extern __attribute__((__stdcall__))
-       void*     DH_GetProcAddress ( DH_CALLCONV  cconv, 
-                                     DH_MODULE    hModule, 
-                                     DH_LPCSTR    lpProcName );
-
-
index fc029bb..a96cb95 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: HsFFI.h,v 1.19 2004/04/12 16:26:40 panne Exp $
+ * $Id: HsFFI.h,v 1.20 2004/08/13 13:09:13 simonmar Exp $
  *
  * (c) The GHC Team, 2000
  *
@@ -18,7 +18,8 @@ extern "C" {
 #endif
 
 /* get types from GHC's runtime system */
-#include "config.h"
+#include "ghcconfig.h"
+#include "RtsConfig.h"
 #include "StgTypes.h"
 
 /* get limits for integral types */
diff --git a/ghc/includes/InfoMacros.h b/ghc/includes/InfoMacros.h
deleted file mode 100644 (file)
index 5aa4835..0000000
+++ /dev/null
@@ -1,692 +0,0 @@
-/* ----------------------------------------------------------------------------
- * $Id: InfoMacros.h,v 1.22 2003/05/14 09:14:01 simonmar Exp $
- * 
- * (c) The GHC Team, 1998-2002
- *
- * Macros for building and deconstructing info tables.
- *
- * -------------------------------------------------------------------------- */
-
-#ifndef INFOMACROS_H
-#define INFOMACROS_H
-
-#define STD_INFO(srt_bitmap_, type_)           \
-               srt_bitmap : srt_bitmap_,               \
-               type : type_
-
-#define THUNK_INFO(srt_, srt_off_)                     \
-               srt : (StgSRT *)((StgClosure **)srt_+srt_off_)
-
-#define FUN_GEN_INFO(srt_, srt_off_, fun_type_, arity_, bitmap_, slow_apply_) \
-
-#define RET_INFO(srt_, srt_off_)                               \
-               srt : (StgSRT *)((StgClosure **)srt_+srt_off_)
-
-#ifdef PROFILING
-#define PROF_INFO(type_str, desc_str)          \
-               prof: {                         \
-                  closure_type: type_str,      \
-                  closure_desc: desc_str,      \
-               },
-#else
-#define PROF_INFO(type_str, desc_str)
-#endif
-
-/*
-  On the GranSim/GUM specific parts of the InfoTables (GRAN/PAR):
-
-  In both GranSim and GUM we use revertible black holes (RBH) when putting
-  an updatable closure into a packet for communication. The entry code for
-  an RBH performs standard blocking (as with any kind of BH). The info
-  table for the RBH resides just before the one for the std info
-  table. (NB: there is one RBH ITBL for every ITBL of an updatable
-  closure.) The @rbh_infoptr@ field in the ITBL points from the std ITBL to
-  the RBH ITBL and vice versa. This is used by the RBH_INFOPTR and
-  REVERT_INFOPTR macros to turn an updatable node into an RBH and vice
-  versa. Note, that the only case where we have to revert the RBH in its
-  original form is when a packet is sent back because of garbage collection
-  on another PE. In the RTS for GdH we will use this reversion mechanism in 
-  order to deal with faults in the system. 
-  ToDo: Check that RBHs are needed for all the info tables below. From a quick
-  check of the macros generated in the libs it seems that all of them are used
-  for generating THUNKs.
-  Possible optimisation: Note that any RBH ITBL is a fixed distance away from 
-  the actual ITBL. We could inline this offset as a constant into the RTS and
-  avoid the rbh_infoptr fields altogether (Jim did that in the old RTS).
-  -- HWL
-*/
-
-
-/* function/thunk info tables --------------------------------------------- */
-
-#if defined(GRAN) || defined(PAR)
-
-#define \
-INFO_TABLE_THUNK(info,                         /* info-table label */  \
-              entry,                           /* entry code label */  \
-              ptrs, nptrs,                     /* closure layout info */\
-              srt_, srt_off_, srt_bitmap_,     /* SRT info */          \
-              type,                            /* closure type */      \
-              info_class, entry_class,         /* C storage classes */ \
-              prof_descr, prof_type)           /* profiling info */    \
-        entry_class(stg_RBH_##entry);                                          \
-        entry_class(entry);                                             \
-       ED_RO_ StgInfoTable info;                                       \
-       info_class const StgInfoTable stg_RBH_##info = {                \
-               layout : { payload : {ptrs,nptrs} },                    \
-                PROF_INFO(prof_type, prof_descr)                       \
-               SRT_INFO(RBH,srt_,srt_off_,srt_bitmap_),                        \
-                INCLUDE_RBH_INFO(info),                                        \
-                INIT_ENTRY(stg_RBH_##entry)                            \
-       } ;                                                             \
-        StgFunPtr stg_RBH_##entry (void) {                                  \
-          FB_                                                           \
-            JMP_(stg_RBH_entry);                                            \
-          FE_                                                           \
-        } ;                                                             \
-       info_class const StgInfoTable info = {                  \
-               layout : { payload : {ptrs,nptrs} },                    \
-                PROF_INFO(prof_type, prof_descr)                       \
-               SRT_INFO(type,srt_,srt_off_,srt_bitmap_),                       \
-                INCLUDE_RBH_INFO(stg_RBH_##info),                      \
-                INIT_ENTRY(entry)                                       \
-       }
-
-#else
-
-#define \
-INFO_TABLE_THUNK(info,                         /* info-table label */  \
-              entry,                           /* entry code label */  \
-              ptrs, nptrs,                     /* closure layout info */\
-              srt_, srt_off_, srt_bitmap_,     /* SRT info */          \
-              type_,                           /* closure type */      \
-              info_class, entry_class,         /* C storage classes */ \
-              prof_descr, prof_type)           /* profiling info */    \
-        entry_class(entry);                                             \
-       info_class const StgThunkInfoTable info = {             \
-               i : {                                                   \
-                 layout : { payload : {ptrs,nptrs} },                  \
-                  PROF_INFO(prof_type, prof_descr)                     \
-                 STD_INFO(srt_bitmap_, type_),                         \
-                  INIT_ENTRY(entry)                                     \
-               },                                                      \
-               THUNK_INFO(srt_,srt_off_),                              \
-       }
-
-#endif
-
-/* direct-return address info tables  --------------------------------------*/
-
-#if defined(GRAN) || defined(PAR)
-
-#define                                                                        \
-INFO_TABLE_RET(info, entry, bitmap_, srt_, srt_off_, srt_bitmap_,              \
-                     type, info_class, entry_class,                    \
-                     prof_descr, prof_type)                            \
-        entry_class(stg_RBH_##entry);                                  \
-        entry_class(entry);                                            \
-       ED_RO_ StgInfoTable info;                                       \
-       info_class const StgInfoTable stg_RBH_##info = {        \
-               layout : { bitmap : (StgWord)bitmap_ },                 \
-                PROF_INFO(prof_type, prof_descr)                       \
-               SRT_INFO(RBH,srt_,srt_off_,srt_bitmap_),                        \
-                INCLUDE_RBH_INFO(info),                                        \
-                INIT_ENTRY(stg_RBH_##entry)                            \
-       };                                                              \
-        StgFunPtr stg_RBH_##entry (void) {                              \
-          FB_                                                           \
-            JMP_(stg_RBH_entry);                                        \
-          FE_                                                           \
-        } ;                                                             \
-       info_class const StgInfoTable info = {                  \
-               layout : { bitmap : (StgWord)bitmap_ },                 \
-                PROF_INFO(prof_type, prof_descr)                       \
-               SRT_INFO(type,srt_,srt_off_,srt_bitmap_),                       \
-                INCLUDE_RBH_INFO(stg_RBH_##info),                      \
-                INIT_ENTRY(entry)                                      \
-       }
-
-#else
-
-#define                                                                        \
-INFO_TABLE_RET(info, entry, bitmap_, srt_, srt_off_, srt_bitmap_,              \
-                     type_, info_class, entry_class,                   \
-                     prof_descr, prof_type)                            \
-        entry_class(entry);                                            \
-       info_class const StgRetInfoTable info = {               \
-               i : {                                                   \
-                   layout : { bitmap : (StgWord)bitmap_ },             \
-                   PROF_INFO(prof_type, prof_descr)                    \
-                   STD_INFO(srt_bitmap_,type_),                                \
-                    INIT_ENTRY(entry)                                  \
-               },                                                      \
-               RET_INFO(srt_,srt_off_)                                 \
-       }
-#endif
-
-/* info-table without an SRT -----------------------------------------------*/
-
-#if defined(GRAN) || defined(PAR)
-
-#define                                                                \
-INFO_TABLE(info, entry, ptrs, nptrs, type, info_class,         \
-          entry_class, prof_descr, prof_type)                  \
-        entry_class(stg_RBH_##entry);                          \
-        entry_class(entry);                                    \
-       ED_ StgInfoTable info;                          \
-       info_class const StgInfoTable stg_RBH_##info = {        \
-               layout : { payload : {ptrs,nptrs} },            \
-                PROF_INFO(prof_type, prof_descr)               \
-               STD_INFO(RBH),                                  \
-                INCLUDE_RBH_INFO(info),                                \
-                INIT_ENTRY(stg_RBH_##entry)                    \
-       } ;                                                     \
-        StgFunPtr stg_RBH_##entry (void) {                      \
-          FB_                                                   \
-            JMP_(stg_RBH_entry);                                \
-          FE_                                                   \
-        } ;                                                     \
-       info_class const StgInfoTable info = {  \
-               layout : { payload : {ptrs,nptrs} },            \
-                PROF_INFO(prof_type, prof_descr)               \
-               STD_INFO(type),                                 \
-                INCLUDE_RBH_INFO(stg_RBH_##info),              \
-                INIT_ENTRY(entry)                              \
-       }
-
-#else
-
-#define                                                        \
-INFO_TABLE(info, entry, ptrs, nptrs, type, info_class, \
-          entry_class, prof_descr, prof_type)          \
-        entry_class(entry);                            \
-       info_class const StgInfoTable info = {  \
-               layout : { payload : {ptrs,nptrs} },    \
-                PROF_INFO(prof_type, prof_descr)       \
-               STD_INFO(0, type),                      \
-                INIT_ENTRY(entry)                      \
-       }
-
-#endif
-
-/* special selector-thunk info table ---------------------------------------*/
-
-#if defined(GRAN) || defined(PAR)
-
-#define                                                                \
-INFO_TABLE_SELECTOR(info, entry, offset, info_class,           \
-                   entry_class, prof_descr, prof_type)         \
-        entry_class(stg_RBH_##entry);                          \
-        entry_class(entry);                                    \
-       ED_RO_ StgInfoTable info;                               \
-       info_class const StgInfoTable stg_RBH_##info = {        \
-               layout : { selector_offset : offset },          \
-                PROF_INFO(prof_type, prof_descr)               \
-               STD_INFO(RBH),                                  \
-                INCLUDE_RBH_INFO(info),                                \
-                INIT_ENTRY(stg_RBH_##entry)                    \
-       };                                                      \
-        StgFunPtr stg_RBH_##entry (void) {                          \
-          FB_                                                   \
-            JMP_(stg_RBH_entry);                                    \
-          FE_                                                   \
-        } ;                                                     \
-       info_class const StgInfoTable info = {          \
-               layout : { selector_offset : offset },          \
-                PROF_INFO(prof_type, prof_descr)               \
-               STD_INFO(THUNK_SELECTOR),                       \
-                INCLUDE_RBH_INFO(stg_RBH_##info),                      \
-                INIT_ENTRY(entry)                              \
-       }
-
-#else
-
-#define                                                        \
-INFO_TABLE_SELECTOR(info, entry, offset, info_class,   \
-                   entry_class, prof_descr, prof_type) \
-        entry_class(entry);                            \
-       info_class const StgInfoTable info = {  \
-               layout : { selector_offset : offset },  \
-                PROF_INFO(prof_type, prof_descr)       \
-               STD_INFO(0,THUNK_SELECTOR),             \
-                INIT_ENTRY(entry)                      \
-       }
-
-#endif
-
-/* constructor info table --------------------------------------------------*/
-
-#define                                                                        \
-INFO_TABLE_CONSTR(info, entry, ptrs, nptrs, tag_,type_,info_class,     \
-                 entry_class, prof_descr, prof_type)                   \
-        entry_class(entry);                                            \
-       info_class const StgInfoTable info = {                  \
-               layout : { payload : {ptrs,nptrs} },                    \
-                PROF_INFO(prof_type, prof_descr)                       \
-                STD_INFO(tag_, type_),                                 \
-                INIT_ENTRY(entry)                                      \
-       }
-
-#define constrTag(con) (get_itbl(con)->srt_bitmap)
-
-/* function info table -----------------------------------------------------*/
-
-#define                                                                        \
-INFO_TABLE_FUN_GEN(info,                       /* info-table label */  \
-              entry,                           /* entry code label */  \
-              ptrs, nptrs,                     /* closure layout info */\
-              srt_, srt_off_, srt_bitmap_,     /* SRT info */          \
-              fun_type_, arity_, bitmap_, slow_apply_,                 \
-                                               /* Function info */     \
-              type_,                           /* closure type */      \
-              info_class, entry_class,         /* C storage classes */ \
-              prof_descr, prof_type)           /* profiling info */    \
-        entry_class(entry);                                             \
-       info_class const StgFunInfoTable info = {               \
-                i : {                                                  \
-                  layout : { payload : {ptrs,nptrs} },                 \
-                   PROF_INFO(prof_type, prof_descr)                    \
-                  STD_INFO(srt_bitmap_,type_),                         \
-                  INIT_ENTRY(entry)                                    \
-               },                                                      \
-               srt : (StgSRT *)((StgClosure **)srt_+srt_off_),         \
-                arity : arity_,                                                \
-                fun_type : fun_type_,                                  \
-               bitmap : (W_)bitmap_,                                   \
-               slow_apply : slow_apply_                                \
-       }
-
-/* return-vectors ----------------------------------------------------------*/
-
-/* vectored-return info tables have the vector slammed up against the
- * start of the info table.
- *
- * A vectored-return address always has an SRT and a bitmap-style
- * layout field, so we only need one macro for these.
- */
-
-#ifdef TABLES_NEXT_TO_CODE
-
-typedef struct {
-  StgFunPtr vec[2];
-  StgRetInfoTable i;
-} vec_info_2;
-
-typedef struct {
-  StgFunPtr vec[3];
-  StgRetInfoTable i;
-} vec_info_3;
-
-typedef struct {
-  StgFunPtr vec[4];
-  StgRetInfoTable i;
-} vec_info_4;
-
-typedef struct {
-  StgFunPtr vec[5];
-  StgRetInfoTable i;
-} vec_info_5;
-
-typedef struct {
-  StgFunPtr vec[6];
-  StgRetInfoTable i;
-} vec_info_6;
-
-typedef struct {
-  StgFunPtr vec[7];
-  StgRetInfoTable i;
-} vec_info_7;
-
-typedef struct {
-  StgFunPtr vec[8];
-  StgRetInfoTable i;
-} vec_info_8;
-
-#define VEC_INFO_2(info,bitmap_,srt_,srt_off_,srt_bitmap_,             \
-                  type_, info_class,                           \
-                  alt_1, alt_2)                                \
-       info_class const vec_info_2 info = {            \
-               { alt_2, alt_1 },                               \
-               i : {                                           \
-                  i : {                                        \
-                     layout : { bitmap : (StgWord)bitmap_ },   \
-                     STD_INFO(srt_bitmap_,type_)                       \
-                  },                                           \
-                  RET_INFO(srt_,srt_off_)                      \
-               }                                               \
-       }
-
-#define VEC_INFO_3(info,bitmap_,srt_,srt_off_,srt_bitmap_,             \
-                  type_, info_class,                           \
-                  alt_1, alt_2, alt_3                          \
-                 )                                             \
-       info_class const vec_info_3 info = {            \
-               { alt_3, alt_2, alt_1 },                        \
-               i : {                                           \
-                  i : {                                        \
-                     layout : { bitmap : (StgWord)bitmap_ },   \
-                     STD_INFO(srt_bitmap_,type_)                       \
-                  },                                           \
-                  RET_INFO(srt_,srt_off_)                      \
-               }                                               \
-       }
-
-#define VEC_INFO_4(info,bitmap_,srt_,srt_off_,srt_bitmap_,             \
-                  type_, info_class,                           \
-                  alt_1, alt_2, alt_3, alt_4                   \
-                 )                                             \
-       info_class const vec_info_4 info = {            \
-               { alt_4, alt_3, alt_2, alt_1 },                 \
-               i : {                                           \
-                  i : {                                        \
-                     layout : { bitmap : (StgWord)bitmap_ },   \
-                     STD_INFO(srt_bitmap_,type_)                       \
-                  },                                           \
-                  RET_INFO(srt_,srt_off_)                      \
-               }                                               \
-       }
-
-#define VEC_INFO_5(info,bitmap_,srt_,srt_off_,srt_bitmap_,             \
-                  type_, info_class,                           \
-                  alt_1, alt_2, alt_3, alt_4,                  \
-                  alt_5                                        \
-                 )                                             \
-       info_class const vec_info_5 info = {            \
-               { alt_5, alt_4, alt_3, alt_2,                   \
-                 alt_1 },                                      \
-               i : {                                           \
-                  i : {                                        \
-                     layout : { bitmap : (StgWord)bitmap_ },   \
-                     STD_INFO(srt_bitmap_,type_)                       \
-                  },                                           \
-                  RET_INFO(srt_,srt_off_)                      \
-               }                                               \
-       }
-
-#define VEC_INFO_6(info,bitmap_,srt_,srt_off_,srt_bitmap_,             \
-                  type_, info_class,                           \
-                  alt_1, alt_2, alt_3, alt_4,                  \
-                  alt_5, alt_6                                 \
-                 )                                             \
-       info_class const vec_info_6 info = {            \
-               { alt_6, alt_5, alt_4, alt_3,                   \
-                 alt_2, alt_1 },                               \
-               i : {                                           \
-                  i : {                                        \
-                     layout : { bitmap : (StgWord)bitmap_ },   \
-                     STD_INFO(srt_bitmap_,type_)                       \
-                  },                                           \
-                  RET_INFO(srt_,srt_off_)                      \
-               }                                               \
-       }
-
-#define VEC_INFO_7(info,bitmap_,srt_,srt_off_,srt_bitmap_,             \
-                  type_, info_class,                           \
-                  alt_1, alt_2, alt_3, alt_4,                  \
-                  alt_5, alt_6, alt_7                          \
-                 )                                             \
-       info_class const vec_info_7 info = {            \
-               { alt_7, alt_6, alt_5, alt_4,                   \
-                 alt_3, alt_2, alt_1 },                        \
-               i : {                                           \
-                  i : {                                        \
-                     layout : { bitmap : (StgWord)bitmap_ },   \
-                     STD_INFO(srt_bitmap_,type_)                       \
-                  },                                           \
-                  RET_INFO(srt_,srt_off_)                      \
-               }                                               \
-       }
-
-#define VEC_INFO_8(info,bitmap_,srt_,srt_off_,srt_bitmap_,             \
-                  type_, info_class,                           \
-                  alt_1, alt_2, alt_3, alt_4,                  \
-                  alt_5, alt_6, alt_7, alt_8                   \
-                 )                                             \
-       info_class const vec_info_8 info = {            \
-               { alt_8, alt_7, alt_6, alt_5,                   \
-                 alt_4, alt_3, alt_2, alt_1 },                 \
-               i : {                                           \
-                  i : {                                        \
-                     layout : { bitmap : (StgWord)bitmap_ },   \
-                     STD_INFO(srt_bitmap_,type_)                       \
-                  },                                           \
-                  RET_INFO(srt_,srt_off_)                      \
-               }                                               \
-       }
-
-
-#else
-
-/* We have to define these structure to work around a bug in gcc: if we
- * try to initialise the vector directly (it's defined as a zero-length
- * array tacked on the end of the info table structor), then gcc silently
- * throws away our vector table sometimes.
- */
-
-typedef struct {
-  StgRetInfoTable i;
-  StgFunPtr vec[2];
-} vec_info_2;
-
-typedef struct {
-  StgRetInfoTable i;
-  StgFunPtr vec[3];
-} vec_info_3;
-
-typedef struct {
-  StgRetInfoTable i;
-  StgFunPtr vec[4];
-} vec_info_4;
-
-typedef struct {
-  StgRetInfoTable i;
-  StgFunPtr vec[5];
-} vec_info_5;
-
-typedef struct {
-  StgRetInfoTable i;
-  StgFunPtr vec[6];
-} vec_info_6;
-
-typedef struct {
-  StgRetInfoTable i;
-  StgFunPtr vec[7];
-} vec_info_7;
-
-typedef struct {
-  StgRetInfoTable i;
-  StgFunPtr vec[8];
-} vec_info_8;
-
-#define VEC_INFO_2(info,bitmap_,srt_,srt_off_,srt_bitmap_,             \
-                  type_, info_class,                           \
-                  alt_1, alt_2)                                \
-       info_class const vec_info_2 info = {            \
-               i : {                                           \
-                  i : {                                        \
-                     layout : { bitmap : (StgWord)bitmap_ },   \
-                     STD_INFO(srt_bitmap_,type_)                       \
-                  },                                           \
-                  RET_INFO(srt_,srt_off_)                      \
-               }                                               \
-       }
-
-#define VEC_INFO_3(info,bitmap_,srt_,srt_off_,srt_bitmap_,             \
-                  type_, info_class,                           \
-                  alt_1, alt_2, alt_3                          \
-                 )                                             \
-       info_class const vec_info_3 info = {            \
-               i : {                                           \
-                  i : {                                        \
-                     layout : { bitmap : (StgWord)bitmap_ },   \
-                     STD_INFO(srt_bitmap_,type_)                       \
-                  },                                           \
-                  RET_INFO(srt_,srt_off_)                      \
-               },                                              \
-                vec : { alt_1, alt_2, alt_3 }                  \
-       }
-
-#define VEC_INFO_4(info,bitmap_,srt_,srt_off_,srt_bitmap_,             \
-                  type_, info_class,                           \
-                  alt_1, alt_2, alt_3, alt_4                   \
-                 )                                             \
-       info_class const vec_info_4 info = {            \
-               i : {                                           \
-                  i : {                                        \
-                     layout : { bitmap : (StgWord)bitmap_ },   \
-                     STD_INFO(srt_bitmap_,type_)                       \
-                  },                                           \
-                  RET_INFO(srt_,srt_off_)                      \
-               },                                              \
-                vec : { alt_1, alt_2, alt_3, alt_4 }           \
-       }
-
-#define VEC_INFO_5(info,bitmap_,srt_,srt_off_,srt_bitmap_,             \
-                  type_, info_class,                           \
-                  alt_1, alt_2, alt_3, alt_4,                  \
-                  alt_5                                        \
-                 )                                             \
-       info_class const vec_info_5 info = {            \
-               i : {                                           \
-                  i : {                                        \
-                     layout : { bitmap : (StgWord)bitmap_ },   \
-                     STD_INFO(srt_bitmap_,type_)                       \
-                  },                                           \
-                  RET_INFO(srt_,srt_off_)                      \
-               },                                              \
-                vec : { alt_1, alt_2, alt_3, alt_4,            \
-                       alt_5 }                                 \
-       }
-
-#define VEC_INFO_6(info,bitmap_,srt_,srt_off_,srt_bitmap_,             \
-                  type_, info_class,                           \
-                  alt_1, alt_2, alt_3, alt_4,                  \
-                  alt_5, alt_6                                 \
-                 )                                             \
-       info_class const vec_info_6 info = {            \
-               i : {                                           \
-                  i : {                                        \
-                     layout : { bitmap : (StgWord)bitmap_ },   \
-                     STD_INFO(srt_bitmap_,type_)                       \
-                  },                                           \
-                  RET_INFO(srt_,srt_off_)                      \
-               },                                              \
-                vec : { alt_1, alt_2, alt_3, alt_4,            \
-                       alt_5, alt_6 }                          \
-       }
-
-#define VEC_INFO_7(info,bitmap_,srt_,srt_off_,srt_bitmap_,             \
-                  type_, info_class,                           \
-                  alt_1, alt_2, alt_3, alt_4,                  \
-                  alt_5, alt_6, alt_7                          \
-                 )                                             \
-       info_class const vec_info_7 info = {            \
-               i : {                                           \
-                  i : {                                        \
-                     layout : { bitmap : (StgWord)bitmap_ },   \
-                     STD_INFO(srt_bitmap_,type_)                       \
-                  },                                           \
-                  RET_INFO(srt_,srt_off_)                      \
-               },                                              \
-                vec : { alt_1, alt_2, alt_3, alt_4,            \
-                       alt_5, alt_6, alt_7 }                   \
-       }
-
-#define VEC_INFO_8(info,bitmap_,srt_,srt_off_,srt_bitmap_,             \
-                  type_, info_class,                           \
-                  alt_1, alt_2, alt_3, alt_4,                  \
-                  alt_5, alt_6, alt_7, alt_8                   \
-                 )                                             \
-       info_class const vec_info_8 info = {            \
-               i : {                                           \
-                  i : {                                        \
-                     layout : { bitmap : (StgWord)bitmap_ },   \
-                     STD_INFO(srt_bitmap_,type_)                       \
-                  },                                           \
-                  RET_INFO(srt_,srt_off_)                      \
-               },                                              \
-                vec : { alt_1, alt_2, alt_3, alt_4,            \
-                       alt_5, alt_6, alt_7, alt_8 }            \
-       }
-
-#endif /* TABLES_NEXT_TO_CODE */
-
-/* For polymorphic activation records, we need both a direct return
- * address and a return vector:
- */
-
-typedef vec_info_8 StgPolyInfoTable;
-
-#ifndef TABLES_NEXT_TO_CODE
-
-#define VEC_POLY_INFO_TABLE(nm, bitmap_,                       \
-                          srt_, srt_off_, srt_bitmap_,         \
-                          type_, info_class, entry_class       \
-                          )                                    \
-  info_class const vec_info_8 nm##_info = {                    \
-               i : {                                           \
-                   i : {                                       \
-                       layout : {                              \
-                       bitmap : (StgWord)bitmap_ },            \
-                       STD_INFO(srt_bitmap_, type_),           \
-                       INIT_ENTRY(nm##_ret)                    \
-                   },                                          \
-                   RET_INFO(srt_,srt_off_)                     \
-               },                                              \
-               vec : {                                         \
-                       (F_) nm##_0_ret,                        \
-                       (F_) nm##_1_ret,                        \
-                       (F_) nm##_2_ret,                        \
-                       (F_) nm##_3_ret,                        \
-                       (F_) nm##_4_ret,                        \
-                       (F_) nm##_5_ret,                        \
-                       (F_) nm##_6_ret,                        \
-                       (F_) nm##_7_ret                         \
-               }                                               \
-           }
-#else
-
-#define VEC_POLY_INFO_TABLE(nm, bitmap_,                       \
-                          srt_, srt_off_, srt_bitmap_,         \
-                          type_, info_class, entry_class       \
-                          )                                    \
-       info_class const vec_info_8 nm##_info = {       \
-               {                                               \
-                       (F_) nm##_7_ret,                        \
-                       (F_) nm##_6_ret,                        \
-                       (F_) nm##_5_ret,                        \
-                       (F_) nm##_4_ret,                        \
-                       (F_) nm##_3_ret,                        \
-                       (F_) nm##_2_ret,                        \
-                       (F_) nm##_1_ret,                        \
-                       (F_) nm##_0_ret                 \
-               },                                              \
-               i : {                                           \
-                   i : {                                       \
-                       layout : {                              \
-                       bitmap : (StgWord)bitmap_ },            \
-                       STD_INFO(srt_bitmap_, type_),           \
-                       INIT_ENTRY(nm##_ret)                    \
-                   },                                          \
-                   RET_INFO(srt_,srt_off_)                     \
-               }                                               \
-       }
-
-#endif
-
-#define SRT(lbl) \
-  static const StgSRT lbl = {
-
-/* DLL_SRT_ENTRY is used on the Win32 side when filling initialising
-   an entry in an SRT table with a reference to a closure that's
-   living in a DLL. See elsewhere for reasons as to why we need
-   to distinguish these kinds of references.
-   (ToDo: fill in a more precise href.)
-*/
-#ifdef ENABLE_WIN32_DLL_SUPPORT /* mingw DietHEP doesn't seem to care either way */
-#define DLL_SRT_ENTRY(x) ((StgClosure*)(((char*)&DLL_IMPORT_DATA_VAR(x)) + 1))
-#else
-#define DLL_SRT_ENTRY(x) no-can-do
-#endif
-
-#endif /* INFOMACROS_H */
index 5284932..a605ba2 100644 (file)
@@ -1,5 +1,5 @@
 /* ----------------------------------------------------------------------------
- * $Id: InfoTables.h,v 1.32 2003/11/14 14:28:08 stolz Exp $
+ * $Id: InfoTables.h,v 1.33 2004/08/13 13:09:17 simonmar Exp $
  * 
  * (c) The GHC Team, 1998-2002
  *
@@ -169,6 +169,8 @@ extern StgWord16 closure_flags[];
    (usually on the stack) to the garbage collector.  The two primary
    uses are for stack frames, and functions (where we need to describe
    the layout of a PAP to the GC).
+
+   In these bitmaps: 0 == ptr, 1 == non-ptr.
    -------------------------------------------------------------------------- */
 
 //
@@ -285,21 +287,29 @@ typedef struct _StgInfoTable {
       bitmap fields have also been omitted.
    -------------------------------------------------------------------------- */
 
-typedef struct _StgFunInfoTable {
-#if defined(TABLES_NEXT_TO_CODE)
+typedef struct _StgFunInfoExtraRev {
     StgFun         *slow_apply; // apply to args on the stack
     StgWord        bitmap;     // arg ptr/nonptr bitmap
     StgSRT         *srt;       // pointer to the SRT table
     StgHalfWord    fun_type;    // function type
     StgHalfWord    arity;       // function arity
-    StgInfoTable i;
-#else
-    StgInfoTable i;
+} StgFunInfoExtraRev;
+
+typedef struct _StgFunInfoExtraFwd {
     StgHalfWord    fun_type;    // function type
     StgHalfWord    arity;       // function arity
     StgSRT         *srt;       // pointer to the SRT table
     StgWord        bitmap;     // arg ptr/nonptr bitmap
     StgFun         *slow_apply; // apply to args on the stack
+} StgFunInfoExtraFwd;
+
+typedef struct {
+#if defined(TABLES_NEXT_TO_CODE)
+    StgFunInfoExtraRev f;
+    StgInfoTable i;
+#else
+    StgInfoTable i;
+    StgFunInfoExtraFwd f;
 #endif
 } StgFunInfoTable;
 
@@ -310,15 +320,13 @@ typedef struct _StgFunInfoTable {
 // When info tables are laid out backwards, we can omit the SRT
 // pointer iff srt_bitmap is zero.
 
-typedef struct _StgRetInfoTable {
-#if !defined(TABLES_NEXT_TO_CODE)
-    StgInfoTable i;
-#endif
-    StgSRT         *srt;       // pointer to the SRT table
+typedef struct {
 #if defined(TABLES_NEXT_TO_CODE)
+    StgSRT      *srt;  // pointer to the SRT table
     StgInfoTable i;
-#endif
-#if !defined(TABLES_NEXT_TO_CODE)
+#else
+    StgInfoTable i;
+    StgSRT      *srt;  // pointer to the SRT table
     StgFunPtr vector[FLEXIBLE_ARRAY];
 #endif
 } StgRetInfoTable;
diff --git a/ghc/includes/Liveness.h b/ghc/includes/Liveness.h
new file mode 100644 (file)
index 0000000..cc93cae
--- /dev/null
@@ -0,0 +1,34 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The University of Glasgow 2004
+ *
+ * Building liveness masks for RET_DYN stack frames.
+ * A few macros that are used in both .cmm and .c sources.
+ *
+ * A liveness mask is constructed like so:
+ *
+ *    R1_PTR & R2_PTR & R3_PTR
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef LIVENESS_H
+#define LIVENESS_H
+
+#define NO_PTRS   0xff
+#define R1_PTR   (NO_PTRS ^ (1<<0))
+#define R2_PTR   (NO_PTRS ^ (1<<1))
+#define R3_PTR   (NO_PTRS ^ (1<<2))
+#define R4_PTR   (NO_PTRS ^ (1<<3))
+#define R5_PTR   (NO_PTRS ^ (1<<4))
+#define R6_PTR   (NO_PTRS ^ (1<<5))
+#define R7_PTR   (NO_PTRS ^ (1<<6))
+#define R8_PTR   (NO_PTRS ^ (1<<7))
+
+#define N_NONPTRS(n)  ((n)<<16)
+#define N_PTRS(n)     ((n)<<24)
+
+#define RET_DYN_NONPTRS(l) ((l)>>16 & 0xff)
+#define RET_DYN_PTRS(l)    ((l)>>24 & 0xff)
+#define RET_DYN_LIVENESS(l) ((l) & 0xffff)
+
+#endif /* LIVENESS_H */
index 77fa21b..39ce757 100644 (file)
@@ -1,5 +1,4 @@
 /* -----------------------------------------------------------------------------
- * $Id: MachDeps.h,v 1.8 2002/12/11 15:36:37 simonmar Exp $
  *
  * (c) The University of Glasgow 2002
  * 
@@ -14,7 +13,7 @@
 #define MACHDEPS_H
 
 /* Sizes of C types come from here... */
-#include "config.h"
+#include "ghcconfig.h"
 
 /* Sizes of Haskell types follow.  These sizes correspond to:
  *   - the number of bytes in the primitive type (eg. Int#)
index c54de67..8297023 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: MachRegs.h,v 1.15 2003/12/10 11:35:25 wolfgang Exp $
+ * $Id: MachRegs.h,v 1.16 2004/08/13 13:09:18 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
 #define REG_Hp         r25
 #define REG_HpLim      r26
 
-#define NCG_SpillTmp_I1        r27
-#define NCG_SpillTmp_I2        r28
-
-#define NCG_SpillTmp_D1        f20
-#define NCG_SpillTmp_D2        f21
+#define REG_Base        r27
 
 #endif /* powerpc */
 
index 11e4e1b..2d6a27a 100644 (file)
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# $Id: Makefile,v 1.22 2003/09/04 09:56:16 simonmar Exp $
+# $Id: Makefile,v 1.23 2004/08/13 13:09:18 simonmar Exp $
 #
 
 TOP = ..
@@ -20,11 +20,11 @@ endif
 #
 # Header file built from the configure script's findings
 #
-H_CONFIG = config.h
+H_CONFIG = ghcconfig.h
 
 boot :: gmp.h
 
-all :: $(H_CONFIG) NativeDefs.h
+all :: $(H_CONFIG)
 
 # gmp.h is copied from the GMP directory
 gmp.h : $(FPTOOLS_TOP)/ghc/rts/gmp/gmp.h
@@ -39,8 +39,8 @@ $(H_CONFIG) : $(FPTOOLS_TOP)/mk/config.h $(FPTOOLS_TOP)/mk/config.mk
 $(H_CONFIG) :
        @echo "Creating $@..."
        @$(RM) $@
-       @echo "#ifndef __FPTOOLS_CONFIG_H__"  >$@
-       @echo "#define __FPTOOLS_CONFIG_H__" >>$@
+       @echo "#ifndef __GHCCONFIG_H__"  >$@
+       @echo "#define __GHCCONFIG_H__" >>$@
        @echo >> $@
        @echo "#define HostPlatform_TYPE   $(HostPlatform_CPP)" >> $@
        @echo "#define TargetPlatform_TYPE $(TargetPlatform_CPP)" >> $@
@@ -72,8 +72,8 @@ endif
        @echo "#define $(HostVendor_CPP)_HOST_VENDOR    1" >> $@
        @echo "#define $(TargetVendor_CPP)_TARGET_VENDOR  1" >> $@
        @echo "#define $(BuildVendor_CPP)_BUILD_VENDOR  1" >> $@
-       @cat $(FPTOOLS_TOP)/mk/$@ >> $@
-       @echo "#endif /* __FPTOOLS_CONFIG_H__ */"          >> $@
+       @cat $(FPTOOLS_TOP)/mk/config.h >> $@
+       @echo "#endif /* __GHCCONFIG_H__ */"          >> $@
        @echo "Done."
 
 # ---------------------------------------------------------------------------
@@ -87,24 +87,27 @@ mkDerivedConstantsHdr : mkDerivedConstants.o
        $(CC) -o $@ $(CC_OPTS) $(LD_OPTS) mkDerivedConstants.o
 
 DerivedConstants.h : mkDerivedConstantsHdr
-       ./mkDerivedConstantsHdr >DerivedConstants.h
+       ./mkDerivedConstantsHdr >$@
 
 CLEAN_FILES += mkDerivedConstantsHdr$(exeext) DerivedConstants.h
 
-# ---------------------------------------------------------------------------
-# Make NativeDefs.h for the NCG
+# -----------------------------------------------------------------------------
+#
 
-all :: NativeDefs.h
+all :: GHCConstants.h
 
-mkNativeHdr.o : DerivedConstants.h
+mkGHCConstants.c : $(H_CONFIG)
 
-mkNativeHdr : mkNativeHdr.o
-       $(CC) -o $@ $(CC_OPTS) $(LD_OPTS) mkNativeHdr.o
+mkGHCConstants : mkGHCConstants.o
+       $(CC) -o $@ $(CC_OPTS) $(LD_OPTS) mkGHCConstants.o
 
-NativeDefs.h : mkNativeHdr
-       ./mkNativeHdr >NativeDefs.h
+mkGHCConstants.o : mkDerivedConstants.c
+       $(CC) -o $@ -c $<  -DGEN_HASKELL
 
-CLEAN_FILES += mkNativeHdr$(exeext) NativeDefs.h
+GHCConstants.h : mkGHCConstants
+       ./mkGHCConstants >$@
+
+CLEAN_FILES += mkDerivedConstantsHdr$(exeext) DerivedConstants.h
 
 # ---------------------------------------------------------------------------
 # boot setup:
diff --git a/ghc/includes/PosixSource.h b/ghc/includes/PosixSource.h
deleted file mode 100644 (file)
index 37966b4..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: PosixSource.h,v 1.2 2002/04/23 17:16:01 ken Exp $
- *
- * (c) The GHC Team, 1998-2001
- *
- * Include this file into sources which should not need any non-Posix services.
- * That includes most RTS C sources.
- * ---------------------------------------------------------------------------*/
-
-#ifndef POSIXSOURCE_H
-#define POSIXSOURCE_H
-
-#define _POSIX_SOURCE   1
-#define _POSIX_C_SOURCE 199506L
-#define _ISOC9X_SOURCE
-
-/* Let's be ISO C9X too... */
-
-#endif
diff --git a/ghc/includes/PrimOps.h b/ghc/includes/PrimOps.h
deleted file mode 100644 (file)
index e7d5ff5..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: PrimOps.h,v 1.107 2003/11/12 17:27:01 sof Exp $
- *
- * (c) The GHC Team, 1998-2000
- *
- * Macros for primitive operations in STG-ish C code.
- *
- * ---------------------------------------------------------------------------*/
-
-/* As of 5 Dec 01, this file no longer implements the primops, since they are
-   translated into standard C in compiler/absCSyn/AbsCUtils during the absC
-   flattening pass.  Only {add,sub,mul}IntCzh remain untranslated.  Most of
-   what is here is now EXTFUN_RTS declarations for the out-of-line primop
-   implementations which live in compiler/rts/PrimOps.hc.
-*/
-
-#ifndef PRIMOPS_H
-#define PRIMOPS_H
-
-#include "MachDeps.h"
-
-#if WORD_SIZE_IN_BITS < 32
-#error GHC C backend requires 32+-bit words
-#endif
-
-
-/* -----------------------------------------------------------------------------
- * Int operations with carry.
- * -------------------------------------------------------------------------- */
-
-/* Multiply with overflow checking.
- *
- * This is tricky - the usual sign rules for add/subtract don't apply.  
- *
- * On 32-bit machines we use gcc's 'long long' types, finding
- * overflow with some careful bit-twiddling.
- *
- * On 64-bit machines where gcc's 'long long' type is also 64-bits,
- * we use a crude approximation, testing whether either operand is
- * larger than 32-bits; if neither is, then we go ahead with the
- * multiplication.
- *
- * Return non-zero if there is any possibility that the signed multiply
- * of a and b might overflow.  Return zero only if you are absolutely sure
- * that it won't overflow.  If in doubt, return non-zero.
- */
-
-#if SIZEOF_VOID_P == 4
-
-#ifdef WORDS_BIGENDIAN
-#define RTS_CARRY_IDX__ 0
-#define RTS_REM_IDX__  1
-#else
-#define RTS_CARRY_IDX__ 1
-#define RTS_REM_IDX__ 0
-#endif
-
-typedef union {
-    StgInt64 l;
-    StgInt32 i[2];
-} long_long_u ;
-
-#define mulIntMayOflo(a,b)                     \
-({                                              \
-  StgInt32 r, c;                               \
-  long_long_u z;                               \
-  z.l = (StgInt64)a * (StgInt64)b;             \
-  r = z.i[RTS_REM_IDX__];                      \
-  c = z.i[RTS_CARRY_IDX__];                    \
-  if (c == 0 || c == -1) {                     \
-    c = ((StgWord)((a^b) ^ r))                 \
-      >> (BITS_IN (I_) - 1);                   \
-  }                                            \
-  c;                                            \
-})
-
-/* Careful: the carry calculation above is extremely delicate.  Make sure
- * you test it thoroughly after changing it.
- */
-
-#else
-
-#define HALF_INT  (((I_)1) << (BITS_IN (I_) / 2))
-
-#define stg_abs(a) (((I_)(a)) < 0 ? -((I_)(a)) : ((I_)(a)))
-
-#define mulIntMayOflo(a,b)                     \
-({                                              \
-  I_ c;                                        \
-  if (stg_abs(a) >= HALF_INT ||                        \
-      stg_abs(b) >= HALF_INT) {                        \
-    c = 1;                                     \
-  } else {                                     \
-    c = 0;                                     \
-  }                                            \
-  c;                                            \
-})
-#endif
-
-
-/* -----------------------------------------------------------------------------
-   Integer PrimOps.
-   -------------------------------------------------------------------------- */
-
-/* NOTE: gcdIntzh and gcdIntegerIntzh work only for positive inputs! */
-
-/* Some of these are out-of-line: -------- */
-
-/* Integer arithmetic */
-EXTFUN_RTS(plusIntegerzh_fast);
-EXTFUN_RTS(minusIntegerzh_fast);
-EXTFUN_RTS(timesIntegerzh_fast);
-EXTFUN_RTS(gcdIntegerzh_fast);
-EXTFUN_RTS(quotRemIntegerzh_fast);
-EXTFUN_RTS(quotIntegerzh_fast);
-EXTFUN_RTS(remIntegerzh_fast);
-EXTFUN_RTS(divExactIntegerzh_fast);
-EXTFUN_RTS(divModIntegerzh_fast);
-
-EXTFUN_RTS(cmpIntegerIntzh_fast);
-EXTFUN_RTS(cmpIntegerzh_fast);
-EXTFUN_RTS(integer2Intzh_fast);
-EXTFUN_RTS(integer2Wordzh_fast);
-EXTFUN_RTS(gcdIntegerIntzh_fast);
-EXTFUN_RTS(gcdIntzh_fast);
-
-/* Conversions */
-EXTFUN_RTS(int2Integerzh_fast);
-EXTFUN_RTS(word2Integerzh_fast);
-
-/* Floating-point decodings */
-EXTFUN_RTS(decodeFloatzh_fast);
-EXTFUN_RTS(decodeDoublezh_fast);
-
-/* Bit operations */
-EXTFUN_RTS(andIntegerzh_fast);
-EXTFUN_RTS(orIntegerzh_fast);
-EXTFUN_RTS(xorIntegerzh_fast);
-EXTFUN_RTS(complementIntegerzh_fast);
-
-
-/* -----------------------------------------------------------------------------
-   Word64 PrimOps.
-   -------------------------------------------------------------------------- */
-
-#ifdef SUPPORT_LONG_LONGS
-
-/* Conversions */
-EXTFUN_RTS(int64ToIntegerzh_fast);
-EXTFUN_RTS(word64ToIntegerzh_fast);
-
-#endif
-
-/* -----------------------------------------------------------------------------
-   Array PrimOps.
-   -------------------------------------------------------------------------- */
-
-/* We cast to void* instead of StgChar* because this avoids a warning
- * about increasing the alignment requirements.
- */
-#define REAL_BYTE_ARR_CTS(a)   ((void *) (((StgArrWords *)(a))->payload))
-#define REAL_PTRS_ARR_CTS(a)   ((P_)   (((StgMutArrPtrs  *)(a))->payload))
-
-#ifdef DEBUG
-#define BYTE_ARR_CTS(a)                                  \
- ({ ASSERT(GET_INFO((StgArrWords *)(a)) == &stg_ARR_WORDS_info);         \
-    REAL_BYTE_ARR_CTS(a); })
-#define PTRS_ARR_CTS(a)                                  \
- ({ ASSERT((GET_INFO((StgMutArrPtrs  *)(a)) == &stg_MUT_ARR_PTRS_FROZEN_info)    \
-       || (GET_INFO((StgMutArrPtrs  *)(a)) == &stg_MUT_ARR_PTRS_info));  \
-    REAL_PTRS_ARR_CTS(a); })
-#else
-#define BYTE_ARR_CTS(a)                REAL_BYTE_ARR_CTS(a)
-#define PTRS_ARR_CTS(a)                REAL_PTRS_ARR_CTS(a)
-#endif
-
-
-extern I_ genSymZh(void);
-extern I_ resetGenSymZh(void);
-
-/*--- Almost everything in line. */
-
-EXTFUN_RTS(unsafeThawArrayzh_fast);
-EXTFUN_RTS(newByteArrayzh_fast);
-EXTFUN_RTS(newPinnedByteArrayzh_fast);
-EXTFUN_RTS(newArrayzh_fast);
-
-/* The decode operations are out-of-line because they need to allocate
- * a byte array.
- */
-
-/* We only support IEEE floating point formats. */
-#include "ieee-flpt.h"
-EXTFUN_RTS(decodeFloatzh_fast);
-EXTFUN_RTS(decodeDoublezh_fast);
-
-/* grimy low-level support functions defined in StgPrimFloat.c */
-extern StgDouble __encodeDouble (I_ size, StgByteArray arr, I_ e);
-extern StgDouble __int_encodeDouble (I_ j, I_ e);
-extern StgFloat  __encodeFloat (I_ size, StgByteArray arr, I_ e);
-extern StgFloat  __int_encodeFloat (I_ j, I_ e);
-extern void      __decodeDouble (MP_INT *man, I_ *_exp, StgDouble dbl);
-extern void      __decodeFloat  (MP_INT *man, I_ *_exp, StgFloat flt);
-extern StgInt    isDoubleNaN(StgDouble d);
-extern StgInt    isDoubleInfinite(StgDouble d);
-extern StgInt    isDoubleDenormalized(StgDouble d);
-extern StgInt    isDoubleNegativeZero(StgDouble d);
-extern StgInt    isFloatNaN(StgFloat f);
-extern StgInt    isFloatInfinite(StgFloat f);
-extern StgInt    isFloatDenormalized(StgFloat f);
-extern StgInt    isFloatNegativeZero(StgFloat f);
-
-
-/* -----------------------------------------------------------------------------
-   Mutable variables
-
-   newMutVar is out of line.
-   -------------------------------------------------------------------------- */
-
-EXTFUN_RTS(newMutVarzh_fast);
-EXTFUN_RTS(atomicModifyMutVarzh_fast);
-
-/* -----------------------------------------------------------------------------
-   MVar PrimOps.
-
-   All out of line, because they either allocate or may block.
-   -------------------------------------------------------------------------- */
-
-EXTFUN_RTS(isEmptyMVarzh_fast);
-EXTFUN_RTS(newMVarzh_fast);
-EXTFUN_RTS(takeMVarzh_fast);
-EXTFUN_RTS(putMVarzh_fast);
-EXTFUN_RTS(tryTakeMVarzh_fast);
-EXTFUN_RTS(tryPutMVarzh_fast);
-
-
-/* -----------------------------------------------------------------------------
-   Delay/Wait PrimOps
-   -------------------------------------------------------------------------- */
-
-EXTFUN_RTS(waitReadzh_fast);
-EXTFUN_RTS(waitWritezh_fast);
-EXTFUN_RTS(delayzh_fast);
-#ifdef mingw32_TARGET_OS
-EXTFUN_RTS(asyncReadzh_fast);
-EXTFUN_RTS(asyncWritezh_fast);
-EXTFUN_RTS(asyncDoProczh_fast);
-#endif
-
-
-/* -----------------------------------------------------------------------------
-   Primitive I/O, error-handling PrimOps
-   -------------------------------------------------------------------------- */
-
-EXTFUN_RTS(catchzh_fast);
-EXTFUN_RTS(raisezh_fast);
-EXTFUN_RTS(raiseIOzh_fast);
-
-extern void stg_exit(int n) GNU_ATTRIBUTE(__noreturn__);
-
-/* -----------------------------------------------------------------------------
-   Stable Name / Stable Pointer  PrimOps
-   -------------------------------------------------------------------------- */
-
-EXTFUN_RTS(makeStableNamezh_fast);
-EXTFUN_RTS(makeStablePtrzh_fast);
-EXTFUN_RTS(deRefStablePtrzh_fast);
-
-
-/* -----------------------------------------------------------------------------
-   Concurrency/Exception PrimOps.
-   -------------------------------------------------------------------------- */
-
-EXTFUN_RTS(forkzh_fast);
-EXTFUN_RTS(yieldzh_fast);
-EXTFUN_RTS(killThreadzh_fast);
-EXTFUN_RTS(seqzh_fast);
-EXTFUN_RTS(blockAsyncExceptionszh_fast);
-EXTFUN_RTS(unblockAsyncExceptionszh_fast);
-EXTFUN_RTS(myThreadIdzh_fast);
-EXTFUN_RTS(labelThreadzh_fast);
-EXTFUN_RTS(isCurrentThreadBoundzh_fast);
-
-extern int cmp_thread(StgPtr tso1, StgPtr tso2);
-extern int rts_getThreadId(StgPtr tso);
-extern int forkOS_createThread ( HsStablePtr entry );
-
-/* -----------------------------------------------------------------------------
-   Weak Pointer PrimOps.
-   -------------------------------------------------------------------------- */
-
-EXTFUN_RTS(mkWeakzh_fast);
-EXTFUN_RTS(finalizzeWeakzh_fast);
-EXTFUN_RTS(deRefWeakzh_fast);
-
-
-/* -----------------------------------------------------------------------------
-   Foreign Object PrimOps.
-   -------------------------------------------------------------------------- */
-
-EXTFUN_RTS(mkForeignObjzh_fast);
-
-
-/* -----------------------------------------------------------------------------
-   Constructor tags
-   -------------------------------------------------------------------------- */
-
-/*
- * This macro is only used when compiling unregisterised code (see 
- * AbsCUtils.dsCOpStmt for motivation & the Story).
- */
-#ifndef TABLES_NEXT_TO_CODE
-# define dataToTagzh(r,a)  r=(GET_TAG(((StgClosure *)a)->header.info))
-#endif
-
-/* -----------------------------------------------------------------------------
-   BCOs and BCO linkery
-   -------------------------------------------------------------------------- */
-
-EXTFUN_RTS(newBCOzh_fast);
-EXTFUN_RTS(mkApUpd0zh_fast);
-
-/* ------------------------------------------------------------------------
-   Parallel PrimOps
-
-   A par in the Haskell code is ultimately translated to a parzh macro
-   (with a case wrapped around it to guarantee that the macro is actually 
-    executed; see compiler/prelude/PrimOps.lhs)
-   In GUM and SMP we only add a pointer to the spark pool.
-   In GranSim we call an RTS fct, forwarding additional parameters which
-   supply info on granularity of the computation, size of the result value
-   and the degree of parallelism in the sparked expression.
-   ---------------------------------------------------------------------- */
-
-#if defined(GRAN)
-//@cindex _par_
-#define parzh(r,node)             parAny(r,node,1,0,0,0,0,0)
-
-//@cindex _parAt_
-#define parAtzh(r,node,where,identifier,gran_info,size_info,par_info,rest) \
-       parAT(r,node,where,identifier,gran_info,size_info,par_info,rest,1)
-
-//@cindex _parAtAbs_
-#define parAtAbszh(r,node,proc,identifier,gran_info,size_info,par_info,rest) \
-       parAT(r,node,proc,identifier,gran_info,size_info,par_info,rest,2)
-
-//@cindex _parAtRel_
-#define parAtRelzh(r,node,proc,identifier,gran_info,size_info,par_info,rest) \
-       parAT(r,node,proc,identifier,gran_info,size_info,par_info,rest,3)
-
-//@cindex _parAtForNow_
-#define parAtForNowzh(r,node,where,identifier,gran_info,size_info,par_info,rest)       \
-       parAT(r,node,where,identifier,gran_info,size_info,par_info,rest,0)
-
-#define parAT(r,node,where,identifier,gran_info,size_info,par_info,rest,local) \
-{                                                              \
-  if (closure_SHOULD_SPARK((StgClosure*)node)) {               \
-    rtsSparkQ result;                                          \
-    PEs p;                                                      \
-                                                                \
-    STGCALL6(newSpark, node,identifier,gran_info,size_info,par_info,local); \
-    switch (local) {                                                        \
-      case 2: p = where;  /* parAtAbs means absolute PE no. expected */     \
-              break;                                                        \
-      case 3: p = CurrentProc+where; /* parAtRel means rel PE no. expected */\
-              break;                                                        \
-      default: p = where_is(where); /* parAt means closure expected */      \
-              break;                                                        \
-    }                                                                       \
-    /* update GranSim state according to this spark */                      \
-    STGCALL3(GranSimSparkAtAbs, result, (I_)p, identifier);                 \
-  }                                                                         \
-}
-
-//@cindex _parLocal_
-#define parLocalzh(r,node,identifier,gran_info,size_info,par_info,rest)        \
-       parAny(r,node,rest,identifier,gran_info,size_info,par_info,1)
-
-//@cindex _parGlobal_
-#define parGlobalzh(r,node,identifier,gran_info,size_info,par_info,rest) \
-       parAny(r,node,rest,identifier,gran_info,size_info,par_info,0)
-
-#define parAny(r,node,rest,identifier,gran_info,size_info,par_info,local) \
-{                                                                        \
-  if (closure_SHOULD_SPARK((StgClosure*)node)) {                         \
-    rtsSpark *result;                                                   \
-    result = RET_STGCALL6(rtsSpark*, newSpark,                           \
-                          node,identifier,gran_info,size_info,par_info,local);\
-    STGCALL1(add_to_spark_queue,result);                               \
-    STGCALL2(GranSimSpark, local,(P_)node);                            \
-  }                                                                    \
-}
-
-#define copyablezh(r,node)                             \
-  /* copyable not yet implemented!! */
-
-#define noFollowzh(r,node)                             \
-  /* noFollow not yet implemented!! */
-
-#elif defined(SMP) || defined(PAR)
-
-#define parzh(r,node)                                  \
-{                                                      \
-  extern unsigned int context_switch;                  \
-  if (closure_SHOULD_SPARK((StgClosure *)node) &&      \
-      SparkTl < SparkLim) {                            \
-    *SparkTl++ = (StgClosure *)(node);                 \
-  }                                                    \
-  r = context_switch = 1;                              \
-}
-#else /* !GRAN && !SMP && !PAR */
-#define parzh(r,node) r = 1
-#endif
-
-/* -----------------------------------------------------------------------------
-   ForeignObj - the C backend still needs this. 
-   -------------------------------------------------------------------------- */
-#define ForeignObj_CLOSURE_DATA(c)  (((StgForeignObj *)c)->data)
-
-
-#endif /* PRIMOPS_H */
diff --git a/ghc/includes/README b/ghc/includes/README
new file mode 100644 (file)
index 0000000..ec10ca1
--- /dev/null
@@ -0,0 +1,114 @@
+-----------------------------------------------------------------------------
+The External API to the GHC Runtime System.
+-----------------------------------------------------------------------------
+
+The header files in this directory form the external API for the
+runtime.  The header files are used in the following scenarios:
+
+  1. Included into the RTS source code itself.
+       In this case we include "Rts.h", which includes everything
+       else in the appropriate order.
+
+       Pretty much everything falls into this category.
+
+  2. Included into a .hc file generated by the compiler.
+       In this case we include Stg.h, which includes a
+       subset of the headers, in the appropriate order and
+       with the appropriate settings (e.g. global register variables
+       turned on).
+
+       Includes everything below Stg.h in the hierarchy (see below).
+
+  3. Included into external C source code.
+       The following headers are designed to be included into
+        external C  code (i.e. C code compiled using a GHC installation,
+        not part of GHC itself or the RTS):
+
+               HsFFI.h
+               RtsAPI.h
+               SchedAPI.h
+               RtsFlags.h
+               Linker.h
+
+       These interfaces are intended to be relatively stable.
+
+       Also Rts.h can be included to get hold of everything else, including
+       definitions of heap objects, info tables, the storage manager interface
+       and so on.  But be warned: none of this is guaranteed to remain stable
+       from one GHC release to the next.
+
+  4. Included into non-C source code, including Haskell (GHC itself)
+     and C-- code in the RTS.
+
+       The following headers are #included into non-C source, so
+       cannot contain any C code or declarations:
+               config.h
+               RtsConfig.h
+               Constants.h
+               DerivedConstants.h
+               ClosureTypes.h
+               StgFun.h
+               MachRegs.h
+               Liveness.h
+               StgLdvProf.h
+
+Here is a rough hierarchy of the header files by dependency.
+
+Rts.h
+  Stg.h
+    config.h           // configuration info derived by the configure script.
+    RtsConfig.h                // settings for Rts things (eg. eager vs. lazy BH)
+    MachDeps.h         // sizes of various basic types
+    StgTypes.h         // basic types specific to the virtual machine
+    TailCalls.h                // tail calls in .hc code
+    StgDLL.h           // stuff related to Windows DLLs
+    MachRegs.h         // global register assignments for this arch
+    Regs.h             // "registers" in the virtual machine
+    StgProf.h          // profiling gubbins
+    StgMiscClosures.h  // decls for closures & info tables in the RTS
+    RtsExternal.h      // decls for RTS things required by .hc code
+      (RtsAPI.h)
+      (HsFFI.h)
+
+  RtsTypes.h           // types used in the RTS
+
+  Constants.h          // build-time constants
+  StgLdvProf.h
+  StgFun.h
+  Closures.h
+  Liveness.h           // macros for constructing RET_DYN liveness masks
+  ClosureMacros.h
+  ClosureTypes.h
+  InfoTables.h
+  TSO.h
+  Updates.h            // macros for performing updates
+  GranSim.h
+  Parallel.h
+  SMP.h
+  Block.h
+  StgTicky.h
+  Stable.h
+  Hooks.h
+  Signals.h
+  DNInvoke.h
+    Dotnet.h
+
+Cmm.h                  // included into .cmm source only
+  DerivedConstants.h   // generated by mkDerivedConstants.c from other
+                       // .h files.
+  (Constants.h)
+  (ClosureTypes.h)
+  (StgFun.h)
+  (MachRegs.h)
+  (Liveness.h)  
+  (Block.h)
+
+Bytecodes.h    // Bytecode definitions for the interpreter
+Linker.h       // External API to the linker
+RtsFlags.h     // External API to the RTS runtime flags
+SchedAPI.h     // External API to the RTS scheduler
+ieee-flpt.h    // ToDo: needed?
+
+RtsAPI.h       // The top-level interface to the RTS (rts_evalIO(), etc.)
+HsFFI.h                // The external FFI api
+  
index 8afc6c9..cd5ff95 100644 (file)
@@ -1,20 +1,27 @@
 /* -----------------------------------------------------------------------------
- * $Id: Regs.h,v 1.14 2003/11/14 14:28:08 stolz Exp $
  *
- * (c) The GHC Team, 1998-1999
+ * (c) The GHC Team, 1998-2004
  *
- * Registers used in STG code.  Might or might not correspond to
- * actual machine registers.
+ * Registers in the STG machine.
+ *
+ * The STG machine has a collection of "registers", each one of which
+ * may or may not correspond to an actual machine register when
+ * running code.  
+ *
+ * The register set is backed by a table in memory (struct
+ * StgRegTable).  If a particular STG register is not mapped to a
+ * machine register, then the apprpriate slot in this table is used
+ * instead.  
+ *
+ * This table is itself pointed to by another register, BaseReg.  If
+ * BaseReg is not in a machine register, then the register table is
+ * used from an absolute location (MainCapability).
  *
  * ---------------------------------------------------------------------------*/
 
 #ifndef REGS_H
 #define REGS_H
 
-/*
- * This file should do the right thing if we have no machine-registers
- * defined, i.e. everything lives in the RegTable.
- */
 
 /* 
  * This is the table that holds shadow-locations for all the STG
@@ -37,6 +44,25 @@ typedef struct {
   StgFunPtr      stgGCFun;
 } StgFunTable;
 
+/*
+ * Vanilla registers are given this union type, which is purely so
+ * that we can cast the vanilla reg to a variety of types with the
+ * minimum of syntax.  eg.  R1.w instead of (StgWord)R1.
+ */
+typedef union {
+    StgWord        w;
+    StgAddr        a;
+    StgChar        c;
+    StgInt8        i8;
+    StgFloat       f;
+    StgInt         i;
+    StgPtr         p;
+    StgClosurePtr  cl;
+    StgStackOffset offset;     /* unused? */
+    StgByteArray   b;
+    StgTSOPtr      t;
+} StgUnion;
+
 typedef struct StgRegTable_ {
   StgUnion       rR1;
   StgUnion       rR2;
@@ -59,10 +85,10 @@ typedef struct StgRegTable_ {
   StgPtr         rSpLim;
   StgPtr         rHp;
   StgPtr         rHpLim;
-  StgTSO         *rCurrentTSO;
-  struct _bdescr *rNursery;
-  struct _bdescr *rCurrentNursery;
-  StgWord         rHpAlloc;    // number of words being allocated in heap 
+  struct StgTSO_ *rCurrentTSO;
+  struct bdescr_ *rNursery;
+  struct bdescr_ *rCurrentNursery;
+  StgWord         rHpAlloc;    // number of *bytes* being allocated in heap 
 #if defined(SMP) || defined(PAR)
   StgSparkPool   rSparks;      // per-task spark pool
 #endif
@@ -82,12 +108,16 @@ typedef struct Capability_ {
 #endif
 } Capability;
 
-/* No such thing as a MainRegTable under SMP - each thread must
- * have its own MainRegTable.
+/* No such thing as a MainCapability under SMP - each thread must have
+ * its own Capability.
  */
 #ifndef SMP
+#if IN_STG_CODE
+extern W_ MainCapability[];
+#else
 extern DLL_IMPORT_RTS Capability  MainCapability;
 #endif
+#endif
 
 #if IN_STG_CODE
 
@@ -291,7 +321,7 @@ GLOBAL_REG_DECL(StgRegTable *,BaseReg,REG_Base)
 #ifdef SMP
 #error BaseReg must be in a register for SMP
 #endif
-#define BaseReg (&MainCapability.r)
+#define BaseReg (&((Capability *)MainCapability)[0].r)
 #endif
 
 #ifdef REG_Sp
@@ -319,7 +349,7 @@ GLOBAL_REG_DECL(P_,HpLim,REG_HpLim)
 #endif
 
 #ifdef REG_CurrentTSO
-GLOBAL_REG_DECL(StgTSO *,CurrentTSO,REG_CurrentTSO)
+GLOBAL_REG_DECL(struct _StgTSO *,CurrentTSO,REG_CurrentTSO)
 #else
 #define CurrentTSO (BaseReg->rCurrentTSO)
 #endif
@@ -712,7 +742,6 @@ GLOBAL_REG_DECL(bdescr *,SparkLim,REG_SparkLim)
 #define CALLER_RESTORE_SYSTEM  /* nothing */
 
 #endif /* IN_STG_CODE */
-
 #define CALLER_SAVE_ALL                                \
   CALLER_SAVE_SYSTEM                           \
   CALLER_SAVE_USER
@@ -722,4 +751,3 @@ GLOBAL_REG_DECL(bdescr *,SparkLim,REG_SparkLim)
   CALLER_RESTORE_USER
 
 #endif /* REGS_H */
-
index b0ad6ea..8d42730 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Rts.h,v 1.23 2003/11/12 17:27:03 sof Exp $
+ * $Id: Rts.h,v 1.24 2004/08/13 13:09:27 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -19,6 +19,171 @@ extern "C" {
 #endif
 #include "Stg.h"
 
+#include "RtsTypes.h"
+
+#if __GNUC__ >= 3
+/* Assume that a flexible array member at the end of a struct
+ * can be defined thus: T arr[]; */
+#define FLEXIBLE_ARRAY
+#else
+/* Assume that it must be defined thus: T arr[0]; */
+#define FLEXIBLE_ARRAY 0
+#endif
+
+#if defined(SMP) || defined(THREADED_RTS)
+#define RTS_SUPPORTS_THREADS 1
+#endif
+
+/* Fix for mingw stat problem (done here so it's early enough) */
+#ifdef mingw32_TARGET_OS
+#define __MSVCRT__ 1
+#endif
+
+#if defined(__GNUC__)
+#define GNU_ATTRIBUTE(at) __attribute__((at))
+#else
+#define GNU_ATTRIBUTE(at)
+#endif
+
+#if __GNUC__ >= 3 
+#define GNUC3_ATTRIBUTE(at) __attribute__((at))
+#else
+#define GNUC3_ATTRIBUTE(at)
+#endif
+
+/* 
+ * Empty structures isn't supported by all, so to define
+ * empty structures, please protect the defn with an
+ * #if SUPPORTS_EMPTY_STRUCTS. Similarly for use,
+ * employ the macro MAYBE_EMPTY_STRUCT():
+ *
+ *     MAYBE_EMPTY_STRUCT(structFoo, fieldName);
+ */
+#if SUPPORTS_EMPTY_STRUCTS
+# define MAYBE_EMPTY_STRUCT(a,b) a b;
+#else
+# define MAYBE_EMPTY_STRUCT(a,b) /* empty */
+#endif
+
+/*
+ * We often want to know the size of something in units of an
+ * StgWord... (rounded up, of course!)
+ */
+#define sizeofW(t) ((sizeof(t)+sizeof(W_)-1)/sizeof(W_))
+
+/* 
+ * It's nice to be able to grep for casts
+ */
+#define stgCast(ty,e) ((ty)(e))
+
+/* -----------------------------------------------------------------------------
+   Assertions and Debuggery
+   -------------------------------------------------------------------------- */
+
+#ifndef DEBUG
+#define ASSERT(predicate) /* nothing */
+#else
+
+void _stgAssert (char *, unsigned int);
+
+#define ASSERT(predicate)                      \
+       if (predicate)                          \
+           /*null*/;                           \
+       else                                    \
+           _stgAssert(__FILE__, __LINE__)
+#endif /* DEBUG */
+
+/* 
+ * Use this on the RHS of macros which expand to nothing
+ * to make sure that the macro can be used in a context which
+ * demands a non-empty statement.
+ */
+
+#define doNothing() do { } while (0)
+
+/* -----------------------------------------------------------------------------
+   Include everything STG-ish
+   -------------------------------------------------------------------------- */
+
+/* System headers: stdlib.h is eeded so that we can use NULL.  It must
+ * come after MachRegs.h, because stdlib.h might define some inline
+ * functions which may only be defined after register variables have
+ * been declared.
+ */
+#include <stdlib.h>
+
+/* Global constaints */
+#include "Constants.h"
+
+/* Profiling information */
+#include "StgProf.h"
+#include "StgLdvProf.h"
+
+/* Storage format definitions */
+#include "StgFun.h"
+#include "Closures.h"
+#include "Liveness.h"
+#include "ClosureTypes.h"
+#include "InfoTables.h"
+#include "TSO.h"
+
+/* Info tables, closures & code fragments defined in the RTS */
+#include "StgMiscClosures.h"
+
+/* Simulated-parallel information */
+#include "GranSim.h"
+
+/* Parallel information */
+#include "Parallel.h"
+
+/* STG/Optimised-C related stuff */
+#include "SMP.h"
+#include "Block.h"
+
+#ifdef SMP
+#include <pthread.h>
+#endif
+
+/* GNU mp library */
+#include "gmp.h"
+
+/* Macros for STG/C code */
+#include "ClosureMacros.h"
+#include "StgTicky.h"
+#include "Stable.h"
+
+/* Runtime-system hooks */
+#include "Hooks.h"
+
+#include "ieee-flpt.h"
+
+#include "Signals.h"
+
+/* Misc stuff without a home */
+DLL_IMPORT_RTS extern char **prog_argv;        /* so we can get at these from Haskell */
+DLL_IMPORT_RTS extern int    prog_argc;
+DLL_IMPORT_RTS extern char  *prog_name;
+
+extern void stackOverflow(void);
+
+extern void      __decodeDouble (MP_INT *man, I_ *_exp, StgDouble dbl);
+extern void      __decodeFloat  (MP_INT *man, I_ *_exp, StgFloat flt);
+
+#if defined(WANT_DOTNET_SUPPORT)
+#include "DNInvoke.h"
+#endif
+
+/* Creating and destroying an adjustor thunk and initialising the whole
+   adjustor thunk machinery. I cannot make myself create a separate .h file
+   for these three (sof.) 
+   
+*/
+extern void*   createAdjustor(int cconv, StgStablePtr hptr, StgFunPtr wptr);
+extern void    freeHaskellFunctionPtr(void* ptr);
+extern rtsBool initAdjustor(void);
+
+extern void stg_exit(int n) GNU_ATTRIBUTE(__noreturn__);
+
 /* -----------------------------------------------------------------------------
    RTS Exit codes
    -------------------------------------------------------------------------- */
index d8e772f..f554b96 100644 (file)
@@ -1,7 +1,6 @@
 /* ----------------------------------------------------------------------------
- * $Id: RtsAPI.h,v 1.36 2003/09/21 22:20:52 wolfgang Exp $
  *
- * (c) The GHC Team, 1998-1999
+ * (c) The GHC Team, 1998-2004
  *
  * API for invoking Haskell functions via the RTS
  *
@@ -131,10 +130,10 @@ rts_checkSchedStatus ( char* site, SchedulerStatus rc);
    These are used by foreign export and foreign import "wrapper" stubs.
    ----------------------------------------------------------------------- */
 
-extern StgClosure GHCziTopHandler_runIO_closure;
-extern StgClosure GHCziTopHandler_runNonIO_closure;
-#define runIO_closure            (&GHCziTopHandler_runIO_closure)
-#define runNonIO_closure         (&GHCziTopHandler_runNonIO_closure)
+extern StgWord GHCziTopHandler_runIO_closure[];
+extern StgWord GHCziTopHandler_runNonIO_closure[];
+#define runIO_closure            GHCziTopHandler_runIO_closure
+#define runNonIO_closure         GHCziTopHandler_runNonIO_closure
 
 /* ------------------------------------------------------------------------ */
 
diff --git a/ghc/includes/RtsConfig.h b/ghc/includes/RtsConfig.h
new file mode 100644 (file)
index 0000000..1af4517
--- /dev/null
@@ -0,0 +1,84 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2004
+ *
+ * Rts settings.
+ *
+ * NOTE: assumes #include "ghcconfig.h"
+ * 
+ * NB: THIS FILE IS INCLUDED IN NON-C CODE AND DATA!  #defines only please.
+ * ---------------------------------------------------------------------------*/
+
+#ifndef RTSCONFIG_H
+#define RTSCONFIG_H
+
+/*
+ * SUPPORT_LONG_LONGS controls whether we need to support long longs on a
+ * particular platform.   On 64-bit platforms, we don't need to support
+ * long longs since regular machine words will do just fine.
+ */
+#if HAVE_LONG_LONG && SIZEOF_VOID_P < 8
+#define SUPPORT_LONG_LONGS 1
+#endif
+
+/*
+ * Whether the runtime system will use libbfd for debugging purposes.
+ */
+#if defined(DEBUG) && defined(HAVE_BFD_H) && !defined(_WIN32) && !defined(PAR) && !defined(GRAN)
+#define USING_LIBBFD 1
+#endif
+
+/* Turn lazy blackholing and eager blackholing on/off.
+ *
+ * Using eager blackholing makes things easier to debug because
+ * the blackholes are more predictable - but it's slower and less sexy.
+ *
+ * For now, do lazy and not eager.
+ */
+
+/* TICKY_TICKY needs EAGER_BLACKHOLING to verify no double-entries of
+ * single-entry thunks.
+ *
+ * SMP needs EAGER_BLACKHOLING because it has to lock thunks
+ * synchronously, in case another thread is trying to evaluate the
+ * same thunk simultaneously.
+ */
+#if defined(SMP) || defined(TICKY_TICKY)
+#  define EAGER_BLACKHOLING
+#else
+#  define LAZY_BLACKHOLING
+#endif
+
+/* TABLES_NEXT_TO_CODE says whether to assume that info tables are
+ * assumed to reside just before the code for a function.
+ *
+ * UNDEFINING THIS WON'T WORK ON ITS OWN.  You have been warned.
+ */
+#if !defined(USE_MINIINTERPRETER) && !defined(ia64_TARGET_ARCH)
+#define TABLES_NEXT_TO_CODE
+#endif
+
+/* -----------------------------------------------------------------------------
+   Labels - entry labels & info labels point to the same place in
+   TABLES_NEXT_TO_CODE, so we only generate the _info label.  Jumps
+   must therefore be directed to foo_info rather than foo_entry when
+   TABLES_NEXT_TO_CODE is on.
+
+   This isn't a good place for these macros, but they need to be
+   available to .cmm sources as well as C and we don't have a better
+   place.
+   -------------------------------------------------------------------------- */
+
+#ifdef TABLES_NEXT_TO_CODE
+#define ENTRY_LBL(f) f##_info
+#else
+#define ENTRY_LBL(f) f##_entry
+#endif
+
+#ifdef TABLES_NEXT_TO_CODE
+#define RET_LBL(f) f##_info
+#else
+#define RET_LBL(f) f##_ret
+#endif
+
+#endif /* RTSCONFIG_H */
diff --git a/ghc/includes/RtsExternal.h b/ghc/includes/RtsExternal.h
new file mode 100644 (file)
index 0000000..da4f02e
--- /dev/null
@@ -0,0 +1,67 @@
+/* -----------------------------------------------------------------------------
+ * $Id: RtsExternal.h,v 1.2 2004/08/13 13:09:29 simonmar Exp $
+ *
+ * (c) The GHC Team, 1998-2004
+ *
+ * Things visible externally to the RTS
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef RTSEXTERNAL_H
+#define RTSEXTERNAL_H
+
+/* The RTS public interface. */
+#include "RtsAPI.h"
+
+/* The standard FFI interface */
+#include "HsFFI.h"
+
+/* -----------------------------------------------------------------------------
+   Functions exported by the RTS for use in Stg code
+   -------------------------------------------------------------------------- */
+
+#if IN_STG_CODE
+extern void newCAF(void*);
+#else
+extern void newCAF(StgClosure*);
+#endif
+
+/* ToDo: remove? */
+extern I_ genSymZh(void);
+extern I_ resetGenSymZh(void);
+
+/* Concurrency/Exception PrimOps. */
+extern int cmp_thread(StgPtr tso1, StgPtr tso2);
+extern int rts_getThreadId(StgPtr tso);
+extern int forkOS_createThread ( HsStablePtr entry );
+
+/* grimy low-level support functions defined in StgPrimFloat.c */
+extern StgDouble __encodeDouble (I_ size, StgByteArray arr, I_ e);
+extern StgDouble __int_encodeDouble (I_ j, I_ e);
+extern StgFloat  __encodeFloat (I_ size, StgByteArray arr, I_ e);
+extern StgFloat  __int_encodeFloat (I_ j, I_ e);
+extern StgInt    isDoubleNaN(StgDouble d);
+extern StgInt    isDoubleInfinite(StgDouble d);
+extern StgInt    isDoubleDenormalized(StgDouble d);
+extern StgInt    isDoubleNegativeZero(StgDouble d);
+extern StgInt    isFloatNaN(StgFloat f);
+extern StgInt    isFloatInfinite(StgFloat f);
+extern StgInt    isFloatDenormalized(StgFloat f);
+extern StgInt    isFloatNegativeZero(StgFloat f);
+
+/* Suspending/resuming threads around foreign calls */
+extern StgInt        suspendThread ( StgRegTable * );
+extern StgRegTable * resumeThread  ( StgInt );
+
+/* -----------------------------------------------------------------------------
+   Storage manager stuff exported
+   -------------------------------------------------------------------------- */
+
+/* Prototype for an evacuate-like function */
+typedef void (*evac_fn)(StgClosure **);
+
+extern void performGC(void);
+extern void performMajorGC(void);
+extern void performGCWithRoots(void (*get_roots)(evac_fn));
+
+#endif /*  RTSEXTERNAL_H */
index 01f631d..1d45748 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: RtsFlags.h,v 1.45 2003/01/23 12:13:10 simonmar Exp $
+ * $Id: RtsFlags.h,v 1.46 2004/08/13 13:09:29 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -73,15 +73,8 @@ struct COST_CENTRE_FLAGS {
     int            msecsPerTick;    /* derived */
 };
 
-#ifdef PROFILING
 struct PROFILING_FLAGS {
     unsigned int       doHeapProfile;
-
-    nat                 profileInterval;      /* delta between samples (in ms) */
-    nat                 profileIntervalTicks; /* delta between samples (in 'ticks') */
-    rtsBool             includeTSOs;
-
-
 # define NO_HEAP_PROFILING     0       /* N.B. Used as indexes into arrays */
 # define HEAP_BY_CCS           1
 # define HEAP_BY_MOD           2
@@ -90,6 +83,14 @@ struct PROFILING_FLAGS {
 # define HEAP_BY_RETAINER       6
 # define HEAP_BY_LDV            7
 
+# define HEAP_BY_INFOPTR        1      /* DEBUG only */
+# define HEAP_BY_CLOSURE_TYPE   2      /* DEBUG only */
+
+    nat                 profileInterval;      /* delta between samples (in ms) */
+    nat                 profileIntervalTicks; /* delta between samples (in 'ticks') */
+    rtsBool             includeTSOs;
+
+
     rtsBool            showCCSOnException;
 
     nat                 maxRetainerSetSize;
@@ -103,15 +104,6 @@ struct PROFILING_FLAGS {
     char*               bioSelector;
 
 };
-#elif defined(DEBUG)
-# define NO_HEAP_PROFILING     0
-# define HEAP_BY_INFOPTR        1
-# define HEAP_BY_CLOSURE_TYPE   2
-struct PROFILING_FLAGS {
-    unsigned int  doHeapProfile;     /* heap profile using symbol table */
-
-};
-#endif /* DEBUG || PROFILING */
 
 struct CONCURRENT_FLAGS {
     int ctxtSwitchTime;                /* in milliseconds */
@@ -288,44 +280,38 @@ struct GRAN_FLAGS {
 };
 #endif /* GRAN */
 
-#ifdef TICKY_TICKY
 struct TICKY_FLAGS {
     rtsBool showTickyStats;
     FILE   *tickyFile;
 };
-#endif /* TICKY_TICKY */
 
 
 /* Put them together: */
 
-struct RTS_FLAGS {
-    struct GC_FLAGS    GcFlags;
-    struct CONCURRENT_FLAGS ConcFlags;
-
-#ifdef DEBUG
-    struct DEBUG_FLAGS DebugFlags;
-#endif
-#if defined(PROFILING) || defined(PAR)
+typedef struct _RTS_FLAGS {
+       // The first portion of RTS_FLAGS is invariant.
+    struct GC_FLAGS         GcFlags;
+    struct CONCURRENT_FLAGS  ConcFlags;
+    struct DEBUG_FLAGS      DebugFlags;
     struct COST_CENTRE_FLAGS CcFlags;
-#endif
-#if defined(PROFILING) || defined(DEBUG)
-    struct PROFILING_FLAGS ProfFlags;
-#endif
+    struct PROFILING_FLAGS   ProfFlags;
+    struct TICKY_FLAGS      TickyFlags;
+
 #if defined(SMP) || defined(PAR)
     struct PAR_FLAGS   ParFlags;
 #endif
 #ifdef GRAN
     struct GRAN_FLAGS  GranFlags;
 #endif
-#ifdef TICKY_TICKY
-    struct TICKY_FLAGS TickyFlags;
-#endif
-};
+} RTS_FLAGS;
 
 #ifdef COMPILING_RTS_MAIN
-extern DLLIMPORT struct RTS_FLAGS RtsFlags;
+extern DLLIMPORT RTS_FLAGS RtsFlags;
+#elif IN_STG_CODE
+// Hack because the C code generator can't generate '&label'.
+extern RTS_FLAGS RtsFlags[];
 #else
-extern struct RTS_FLAGS RtsFlags;
+extern RTS_FLAGS RtsFlags;
 #endif
 
 /* Routines that operate-on/to-do-with RTS flags: */
index fefdba9..ca2e721 100644 (file)
@@ -1,7 +1,6 @@
 /* -----------------------------------------------------------------------------
- * $Id: Stable.h,v 1.15 2003/11/12 17:27:03 sof Exp $
  *
- * (c) The GHC Team, 1998-2000
+ * (c) The GHC Team, 1998-2004
  *
  * Stable Pointers: A stable pointer is represented as an index into
  * the stable pointer table in the low BITS_PER_WORD-8 bits with a
@@ -55,4 +54,13 @@ StgPtr deRefStablePtr(StgStablePtr sp)
 extern StgPtr deRefStablePtr(StgStablePtr sp);
 #endif
 
+extern void    initStablePtrTable    ( void );
+extern void    enlargeStablePtrTable ( void );
+extern StgWord lookupStableName      ( StgPtr p );
+
+extern void    markStablePtrTable    ( evac_fn evac );
+extern void    threadStablePtrTable  ( evac_fn evac );
+extern void    gcStablePtrTable      ( void );
+extern void    updateStablePtrTable  ( rtsBool full );
+
 #endif
index dd41d37..12051e0 100644 (file)
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
- * $Id: Stg.h,v 1.62 2004/03/23 10:03:18 simonmar Exp $
+ * $Id: Stg.h,v 1.63 2004/08/13 13:09:30 simonmar Exp $
  *
- * (c) The GHC Team, 1998-1999
+ * (c) The GHC Team, 1998-2004
  *
  * Top-level include file for everything STG-ish.  
  *
  * functions are defined (some system headers have been known to
  * define the odd inline function).
  *
+ * We generally try to keep as little visible as possible when
+ * compiling .hc files.  So for example the definitions of the
+ * InfoTable structs, closure structs and other RTS types are not
+ * visible here.  The compiler knows enough about the representations
+ * of these types to generate code which manipulates them directly
+ * with pointer arithmetic.
+ *
  * ---------------------------------------------------------------------------*/
 
 #ifndef STG_H
 #endif
 
 /* Configuration */
-#include "config.h"
-
-/* This needs to be up near the top as the register line on alpha needs
- * to be before all procedures */
-#include "TailCalls.h"
-
-#if __GNUC__ >= 3
-/* Assume that a flexible array member at the end of a struct
- * can be defined thus: T arr[]; */
-#define FLEXIBLE_ARRAY
-#else
-/* Assume that it must be defined thus: T arr[0]; */
-#define FLEXIBLE_ARRAY 0
-#endif
-
-#if defined(SMP) || defined(THREADED_RTS)
-#define RTS_SUPPORTS_THREADS 1
-#endif
-
-/* Some macros to handle DLLing (Win32 only at the moment). */
-#include "StgDLL.h"
+#include "ghcconfig.h"
+#include "RtsConfig.h"
 
-/* Fix for mingw stat problem (done here so it's early enough) */
-#ifdef mingw32_TARGET_OS
-#define __MSVCRT__ 1
-#endif
-
-/* Turn lazy blackholing and eager blackholing on/off.
- *
- * Using eager blackholing makes things easier to debug because
- * the blackholes are more predictable - but it's slower and less sexy.
- *
- * For now, do lazy and not eager.
- */
+/* -----------------------------------------------------------------------------
+   Useful definitions
+   -------------------------------------------------------------------------- */
 
-/* TICKY_TICKY needs EAGER_BLACKHOLING to verify no double-entries of
- * single-entry thunks.
- *
- * SMP needs EAGER_BLACKHOLING because it has to lock thunks
- * synchronously, in case another thread is trying to evaluate the
- * same thunk simultaneously.
+/*
+ * The C backend like to refer to labels by just mentioning their
+ * names.  Howevver, when a symbol is declared as a variable in C, the
+ * C compiler will implicitly dereference it when it occurs in source.
+ * So we must subvert this behaviour for .hc files by declaring
+ * variables as arrays, which eliminates the implicit dereference.
  */
-#if defined(SMP) || defined(TICKY_TICKY)
-#  define EAGER_BLACKHOLING
+#if IN_STG_CODE
+#define RTS_VAR(x) (x)[]
+#define RTS_DEREF(x) (*(x))
 #else
-#  define LAZY_BLACKHOLING
+#define RTS_VAR(x) x
+#define RTS_DEREF(x) x
 #endif
 
-#if defined(__GNUC__)
-#define GNU_ATTRIBUTE(at) __attribute__((at))
-#else
-#define GNU_ATTRIBUTE(at)
-#endif
-
-#if __GNUC__ >= 3 
-#define GNUC3_ATTRIBUTE(at) __attribute__((at))
-#else
-#define GNUC3_ATTRIBUTE(at)
-#endif
-
-/* 
- * Empty structures isn't supported by all, so to define
- * empty structures, please protect the defn with an
- * #if SUPPORTS_EMPTY_STRUCTS. Similarly for use,
- * employ the macro MAYBE_EMPTY_STRUCT():
- *
- *     MAYBE_EMPTY_STRUCT(structFoo, fieldName);
+/* bit macros
  */
-#if SUPPORTS_EMPTY_STRUCTS
-# define MAYBE_EMPTY_STRUCT(a,b) a b;
-#else
-# define MAYBE_EMPTY_STRUCT(a,b) /* empty */
-#endif
+#define BITS_PER_BYTE 8
+#define BITS_IN(x) (BITS_PER_BYTE * sizeof(x))
 
 /*
- * 'Portable' 
+ * 'Portable' inlining
  */
 #if defined(__GNUC__) || defined( __INTEL_COMPILER)
 # define INLINE_HEADER static inline
 # error "Don't know how to inline functions with your C compiler."
 #endif
 
-/* TABLES_NEXT_TO_CODE says whether to assume that info tables are
- * assumed to reside just before the code for a function.
- *
- * UNDEFINING THIS WON'T WORK ON ITS OWN.  You have been warned.
- */
-#if !defined(USE_MINIINTERPRETER) && !defined(ia64_TARGET_ARCH)
-#define TABLES_NEXT_TO_CODE
-#endif
-
-/* bit macros
- */
-#define BITS_PER_BYTE 8
-#define BITS_IN(x) (BITS_PER_BYTE * sizeof(x))
-
-/* -----------------------------------------------------------------------------
-   Assertions and Debuggery
-   -------------------------------------------------------------------------- */
-
-#ifndef DEBUG
-#define ASSERT(predicate) /* nothing */
-#else
-
-void _stgAssert (char *, unsigned int);
-
-#define ASSERT(predicate)                      \
-       if (predicate)                          \
-           /*null*/;                           \
-       else                                    \
-           _stgAssert(__FILE__, __LINE__)
-#endif /* DEBUG */
-
-/* 
- * Use this on the RHS of macros which expand to nothing
- * to make sure that the macro can be used in a context which
- * demands a non-empty statement.
- */
-
-#define doNothing() do { } while (0)
-
 /* -----------------------------------------------------------------------------
    Global type definitions
    -------------------------------------------------------------------------- */
 
+#include "MachDeps.h"
 #include "StgTypes.h"
-#include "RtsTypes.h"
 
 /* -----------------------------------------------------------------------------
    Shorthand forms
@@ -187,107 +108,321 @@ typedef StgClosurePtr   L_;
 typedef StgInt64        LI_;
 typedef StgWord64       LW_;
 
-/*
- * We often want to know the size of something in units of an
- * StgWord... (rounded up, of course!)
- */
+#define IF_(f)         static F_ f(void)
+#define FN_(f)         F_ f(void)
+#define EF_(f)         extern F_ f(void)
 
-#define sizeofW(t) ((sizeof(t)+sizeof(W_)-1)/sizeof(W_))
+typedef StgWord StgWordArray[];
+#define EI_             extern StgWordArray
+#define II_             static StgWordArray
 
-/* 
- * It's nice to be able to grep for casts
- */
+/* -----------------------------------------------------------------------------
+   Tail calls
+
+   This needs to be up near the top as the register line on alpha needs
+   to be before all procedures (inline & out-of-line).
+   -------------------------------------------------------------------------- */
 
-#define stgCast(ty,e) ((ty)(e))
+#include "TailCalls.h"
 
 /* -----------------------------------------------------------------------------
-   Include everything STG-ish
+   Moving Floats and Doubles
+
+   ASSIGN_FLT is for assigning a float to memory (usually the
+              stack/heap).  The memory address is guaranteed to be
+             StgWord aligned (currently == sizeof(void *)).
+
+   PK_FLT     is for pulling a float out of memory.  The memory is
+              guaranteed to be StgWord aligned.
    -------------------------------------------------------------------------- */
 
-/* Global constaints */
-#include "Constants.h"
+INLINE_HEADER void       ASSIGN_FLT (W_ [], StgFloat);
+INLINE_HEADER StgFloat    PK_FLT     (W_ []);
 
-/* Profiling information */
-#include "StgProf.h"
-#include "StgLdvProf.h"
+#if ALIGNMENT_FLOAT <= ALIGNMENT_LONG
 
-/* Storage format definitions */
-#include "StgFun.h"
-#include "Closures.h"
-#include "ClosureTypes.h"
-#include "InfoTables.h"
-#include "TSO.h"
+INLINE_HEADER void     ASSIGN_FLT(W_ p_dest[], StgFloat src) { *(StgFloat *)p_dest = src; }
+INLINE_HEADER StgFloat PK_FLT    (W_ p_src[])                { return *(StgFloat *)p_src; }
 
-/* Simulated-parallel information */
-#include "GranSim.h"
+#else  /* ALIGNMENT_FLOAT > ALIGNMENT_UNSIGNED_INT */
 
-/* Parallel information */
-#include "Parallel.h"
+INLINE_HEADER void ASSIGN_FLT(W_ p_dest[], StgFloat src)
+{
+    float_thing y;
+    y.f = src;
+    *p_dest = y.fu;
+}
 
-/* STG/Optimised-C related stuff */
-#include "SMP.h"
-#include "MachRegs.h"
-#include "Regs.h"
-#include "Block.h"
+INLINE_HEADER StgFloat PK_FLT(W_ p_src[])
+{
+    float_thing y;
+    y.fu = *p_src;
+    return(y.f);
+}
+
+#endif /* ALIGNMENT_FLOAT > ALIGNMENT_LONG */
+
+#if ALIGNMENT_DOUBLE <= ALIGNMENT_LONG
+
+INLINE_HEADER void       ASSIGN_DBL (W_ [], StgDouble);
+INLINE_HEADER StgDouble   PK_DBL     (W_ []);
 
-/* RTS public interface */
-#include "RtsAPI.h"
+INLINE_HEADER void      ASSIGN_DBL(W_ p_dest[], StgDouble src) { *(StgDouble *)p_dest = src; }
+INLINE_HEADER StgDouble PK_DBL    (W_ p_src[])                 { return *(StgDouble *)p_src; }
 
-/* System headers: stdlib.h is eeded so that we can use NULL.  It must
- * come after MachRegs.h, because stdlib.h might define some inline
- * functions which may only be defined after register variables have
- * been declared.
+#else  /* ALIGNMENT_DOUBLE > ALIGNMENT_LONG */
+
+/* Sparc uses two floating point registers to hold a double.  We can
+ * write ASSIGN_DBL and PK_DBL by directly accessing the registers
+ * independently - unfortunately this code isn't writable in C, we
+ * have to use inline assembler.
  */
-#include <stdlib.h>
+#if sparc_TARGET_ARCH
+
+#define ASSIGN_DBL(dst0,src) \
+    { StgPtr dst = (StgPtr)(dst0); \
+      __asm__("st %2,%0\n\tst %R2,%1" : "=m" (((P_)(dst))[0]), \
+       "=m" (((P_)(dst))[1]) : "f" (src)); \
+    }
+
+#define PK_DBL(src0) \
+    ( { StgPtr src = (StgPtr)(src0); \
+        register double d; \
+      __asm__("ld %1,%0\n\tld %2,%R0" : "=f" (d) : \
+       "m" (((P_)(src))[0]), "m" (((P_)(src))[1])); d; \
+    } )
+
+#else /* ! sparc_TARGET_ARCH */
+
+INLINE_HEADER void       ASSIGN_DBL (W_ [], StgDouble);
+INLINE_HEADER StgDouble   PK_DBL     (W_ []);
+
+typedef struct
+  { StgWord dhi;
+    StgWord dlo;
+  } unpacked_double;
+
+typedef union
+  { StgDouble d;
+    unpacked_double du;
+  } double_thing;
+
+INLINE_HEADER void ASSIGN_DBL(W_ p_dest[], StgDouble src)
+{
+    double_thing y;
+    y.d = src;
+    p_dest[0] = y.du.dhi;
+    p_dest[1] = y.du.dlo;
+}
+
+/* GCC also works with this version, but it generates
+   the same code as the previous one, and is not ANSI
+
+#define ASSIGN_DBL( p_dest, src ) \
+       *p_dest = ((double_thing) src).du.dhi; \
+       *(p_dest+1) = ((double_thing) src).du.dlo \
+*/
 
-#ifdef SMP
-#include <pthread.h>
-#endif
+INLINE_HEADER StgDouble PK_DBL(W_ p_src[])
+{
+    double_thing y;
+    y.du.dhi = p_src[0];
+    y.du.dlo = p_src[1];
+    return(y.d);
+}
 
-/* GNU mp library */
-#include "gmp.h"
+#endif /* ! sparc_TARGET_ARCH */
 
-/* Storage Manager */
-#include "StgStorage.h"
+#endif /* ALIGNMENT_DOUBLE > ALIGNMENT_UNSIGNED_INT */
 
-/* Macros for STG/C code */
-#include "ClosureMacros.h"
-#include "InfoMacros.h"
-#include "StgMacros.h"
-#include "PrimOps.h"
-#include "Updates.h"
-#include "StgTicky.h"
-#include "CCall.h"
-#include "Stable.h"
 
-/* Built-in entry points */
+/* -----------------------------------------------------------------------------
+   Moving 64-bit quantities around
+
+   ASSIGN_Word64      assign an StgWord64/StgInt64 to a memory location
+   PK_Word64          load an StgWord64/StgInt64 from a amemory location
+
+   In both cases the memory location might not be 64-bit aligned.
+   -------------------------------------------------------------------------- */
+
+#ifdef SUPPORT_LONG_LONGS
+
+typedef struct
+  { StgWord dhi;
+    StgWord dlo;
+  } unpacked_double_word;
+
+typedef union
+  { StgInt64 i;
+    unpacked_double_word iu;
+  } int64_thing;
+
+typedef union
+  { StgWord64 w;
+    unpacked_double_word wu;
+  } word64_thing;
+
+INLINE_HEADER void ASSIGN_Word64(W_ p_dest[], StgWord64 src)
+{
+    word64_thing y;
+    y.w = src;
+    p_dest[0] = y.wu.dhi;
+    p_dest[1] = y.wu.dlo;
+}
+
+INLINE_HEADER StgWord64 PK_Word64(W_ p_src[])
+{
+    word64_thing y;
+    y.wu.dhi = p_src[0];
+    y.wu.dlo = p_src[1];
+    return(y.w);
+}
+
+INLINE_HEADER void ASSIGN_Int64(W_ p_dest[], StgInt64 src)
+{
+    int64_thing y;
+    y.i = src;
+    p_dest[0] = y.iu.dhi;
+    p_dest[1] = y.iu.dlo;
+}
+
+INLINE_HEADER StgInt64 PK_Int64(W_ p_src[])
+{
+    int64_thing y;
+    y.iu.dhi = p_src[0];
+    y.iu.dlo = p_src[1];
+    return(y.i);
+}
+
+#elif SIZEOF_VOID_P == 8
+
+INLINE_HEADER void ASSIGN_Word64(W_ p_dest[], StgWord64 src)
+{
+       p_dest[0] = src;
+}
+
+INLINE_HEADER StgWord64 PK_Word64(W_ p_src[])
+{
+    return p_src[0];
+}
+
+INLINE_HEADER void ASSIGN_Int64(W_ p_dest[], StgInt64 src)
+{
+    p_dest[0] = src;
+}
+
+INLINE_HEADER StgInt64 PK_Int64(W_ p_src[])
+{
+    return p_src[0];
+}
+
+#endif
+
+/* -----------------------------------------------------------------------------
+   Other Stg stuff...
+   -------------------------------------------------------------------------- */
+
+#include "StgDLL.h"
+#include "MachRegs.h"
+#include "Regs.h"
+#include "StgProf.h"  /* ToDo: separate out RTS-only stuff from here */
+
+#if IN_STG_CODE
+/*
+ * This is included later for RTS sources, after definitions of
+ * StgInfoTable, StgClosure and so on. 
+ */
 #include "StgMiscClosures.h"
+#endif
 
-/* Runtime-system hooks */
-#include "Hooks.h"
+/* RTS external interface */
+#include "RtsExternal.h"
 
-#include "Signals.h"
+/* -----------------------------------------------------------------------------
+   Split markers
+   -------------------------------------------------------------------------- */
 
-#include "HsFFI.h"
+#if defined(USE_SPLIT_MARKERS)
+#if defined(LEADING_UNDERSCORE)
+#define __STG_SPLIT_MARKER __asm__("\n___stg_split_marker:");
+#else
+#define __STG_SPLIT_MARKER __asm__("\n__stg_split_marker:");
+#endif
+#else
+#define __STG_SPLIT_MARKER /* nothing */
+#endif
+
+/* -----------------------------------------------------------------------------
+   Integer multiply with overflow
+   -------------------------------------------------------------------------- */
 
-/* Misc stuff without a home */
-DLL_IMPORT_RTS extern char **prog_argv;        /* so we can get at these from Haskell */
-DLL_IMPORT_RTS extern int    prog_argc;
-DLL_IMPORT_RTS extern char  *prog_name;
+/* Multiply with overflow checking.
+ *
+ * This is tricky - the usual sign rules for add/subtract don't apply.  
+ *
+ * On 32-bit machines we use gcc's 'long long' types, finding
+ * overflow with some careful bit-twiddling.
+ *
+ * On 64-bit machines where gcc's 'long long' type is also 64-bits,
+ * we use a crude approximation, testing whether either operand is
+ * larger than 32-bits; if neither is, then we go ahead with the
+ * multiplication.
+ *
+ * Return non-zero if there is any possibility that the signed multiply
+ * of a and b might overflow.  Return zero only if you are absolutely sure
+ * that it won't overflow.  If in doubt, return non-zero.
+ */
 
-extern void stackOverflow(void);
+#if SIZEOF_VOID_P == 4
 
-#if defined(WANT_DOTNET_SUPPORT)
-#include "DNInvoke.h"
+#ifdef WORDS_BIGENDIAN
+#define RTS_CARRY_IDX__ 0
+#define RTS_REM_IDX__  1
+#else
+#define RTS_CARRY_IDX__ 1
+#define RTS_REM_IDX__ 0
 #endif
 
-/* Creating and destroying an adjustor thunk and initialising the whole
-   adjustor thunk machinery. I cannot make myself create a separate .h file
-   for these three (sof.) 
-   
-*/
-extern void*   createAdjustor(int cconv, StgStablePtr hptr, StgFunPtr wptr);
-extern void    freeHaskellFunctionPtr(void* ptr);
-extern rtsBool initAdjustor(void);
+typedef union {
+    StgInt64 l;
+    StgInt32 i[2];
+} long_long_u ;
+
+#define mulIntMayOflo(a,b)                     \
+({                                              \
+  StgInt32 r, c;                               \
+  long_long_u z;                               \
+  z.l = (StgInt64)a * (StgInt64)b;             \
+  r = z.i[RTS_REM_IDX__];                      \
+  c = z.i[RTS_CARRY_IDX__];                    \
+  if (c == 0 || c == -1) {                     \
+    c = ((StgWord)((a^b) ^ r))                 \
+      >> (BITS_IN (I_) - 1);                   \
+  }                                            \
+  c;                                            \
+})
+
+/* Careful: the carry calculation above is extremely delicate.  Make sure
+ * you test it thoroughly after changing it.
+ */
+
+#else
+
+#define HALF_INT  (((I_)1) << (BITS_IN (I_) / 2))
+
+#define stg_abs(a) (((I_)(a)) < 0 ? -((I_)(a)) : ((I_)(a)))
+
+#define mulIntMayOflo(a,b)                     \
+({                                              \
+  I_ c;                                        \
+  if (stg_abs(a) >= HALF_INT ||                        \
+      stg_abs(b) >= HALF_INT) {                        \
+    c = 1;                                     \
+  } else {                                     \
+    c = 0;                                     \
+  }                                            \
+  c;                                            \
+})
+#endif
 
 #endif /* STG_H */
index b89cd98..a1a4712 100644 (file)
@@ -19,6 +19,9 @@
 /* specialised function types: bitmaps and calling sequences
  * for these functions are pre-generated (see ghc/utils/genapply), and
  * the generated code in ghc/rts/AutoApply.hc.
+ *
+ *  NOTE: this ordering/numbering is hard-coded into the tables
+ *  generated by GenApply.hs which end up in AutoApply.cmm.
  */
 #define ARG_N        3 
 #define ARG_P        4 
 #define ARG_NP       9 
 #define ARG_PN       10
 #define ARG_PP       11
-#define ARG_FF       12
-#define ARG_DD       13
-#define ARG_LL       14
-#define ARG_NNN      15
-#define ARG_NNP      16
-#define ARG_NPN      17
-#define ARG_NPP      18
-#define ARG_PNN      19
-#define ARG_PNP      20
-#define ARG_PPN      21
-#define ARG_PPP      22
-#define ARG_PPPP     23
-#define ARG_PPPPP    24
-#define ARG_PPPPPP   25
-#define ARG_PPPPPPP  26
-#define ARG_PPPPPPPP 27
+#define ARG_NNN      12
+#define ARG_NNP      13
+#define ARG_NPN      14
+#define ARG_NPP      15
+#define ARG_PNN      16
+#define ARG_PNP      17
+#define ARG_PPN      18
+#define ARG_PPP      19
+#define ARG_PPPP     20
+#define ARG_PPPPP    21
+#define ARG_PPPPPP   22
+#define ARG_PPPPPPP  23
+#define ARG_PPPPPPPP 24
 
 #endif // STGFUN_H
index dceefd7..f5f7ae2 100644 (file)
@@ -1,8 +1,6 @@
 /* -----------------------------------------------------------------------------
- * $Id: StgLdvProf.h,v 1.2 2001/11/26 16:54:22 simonmar Exp $
  *
- * (c) The GHC Team, 2001
- * Author: Sungwoo Park
+ * (c) The University of Glasgow, 2004
  *
  * Lag/Drag/Void profiling.
  *
 #ifndef STGLDVPROF_H
 #define STGLDVPROF_H
 
-/*
-  An LDV word is divided into 3 parts: state bits (LDV_STATE_MASK), creation 
-  time bits (LDV_CREATE_MASK), and last use time bits (LDV_LAST_MASK). 
- */
-#if SIZEOF_VOID_P == 8
-#define LDV_SHIFT               30
-#define LDV_STATE_MASK          0x1000000000000000
-#define LDV_CREATE_MASK         0x0FFFFFFFC0000000
-#define LDV_LAST_MASK           0x000000003FFFFFFF
-#define LDV_STATE_CREATE        0x0000000000000000
-#define LDV_STATE_USE           0x1000000000000000
-#else
-#define LDV_SHIFT               15
-#define LDV_STATE_MASK          0x40000000 
-#define LDV_CREATE_MASK         0x3FFF8000
-#define LDV_LAST_MASK           0x00007FFF
-#define LDV_STATE_CREATE        0x00000000
-#define LDV_STATE_USE           0x40000000
-#endif  // SIZEOF_VOID_P
-
 #ifdef PROFILING
 
-extern nat era;
-
-// retrieves the LDV word from closure c
+/* retrieves the LDV word from closure c */
 #define LDVW(c)                 (((StgClosure *)(c))->header.prof.hp.ldvw)
 
-// Stores the creation time for closure c. 
-// This macro is called at the very moment of closure creation.
-//
-// NOTE: this initializes LDVW(c) to zero, which ensures that there
-// is no conflict between retainer profiling and LDV profiling,
-// because retainer profiling also expects LDVW(c) to be initialised
-// to zero.
-#define LDV_recordCreate(c)   \
-  LDVW((c)) = (era << LDV_SHIFT) | LDV_STATE_CREATE
-
-// Stores the last use time for closure c.
-// This macro *must* be called whenever a closure is used, that is, it is 
-// entered.
-#define LDV_recordUse(c)                               \
-  {                                                    \
-    if (era > 0)                                       \
-      LDVW((c)) = (LDVW((c)) & LDV_CREATE_MASK) |      \
-                  era |                                        \
-                  LDV_STATE_USE;                       \
-  }
-
-// Macros called when a closure is entered. 
-// The closure is not an 'inherently used' one.
-// The closure is not IND or IND_OLDGEN because neither is considered for LDV
-// profiling.
-#define LDV_ENTER(c)            LDV_recordUse((c))
+/*
+ * Stores the creation time for closure c. 
+ * This macro is called at the very moment of closure creation.
+ *
+ * NOTE: this initializes LDVW(c) to zero, which ensures that there
+ * is no conflict between retainer profiling and LDV profiling,
+ * because retainer profiling also expects LDVW(c) to be initialised
+ * to zero.
+ */
+#ifndef CMINUSMINUS
+#define LDV_RECORD_CREATE(c)   \
+  LDVW((c)) = (RTS_DEREF(era) << LDV_SHIFT) | LDV_STATE_CREATE
+#endif
+
+#ifdef CMINUSMINUS
+#define LDV_RECORD_DEAD_FILL_SLOP_DYNAMIC(c) \
+  foreign "C" LDV_recordDead_FILL_SLOP_DYNAMIC(c "ptr")
+#else
+#define LDV_RECORD_DEAD_FILL_SLOP_DYNAMIC(c) \
+  LDV_recordDead_FILL_SLOP_DYNAMIC(c)
+#endif
 
-#else  // !PROFILING
+#else  /* !PROFILING */
 
-#define LDV_ENTER(c)            
+#define LDV_RECORD_CREATE(c)   /* nothing */
+#define LDV_RECORD_DEAD_FILL_SLOP_DYNAMIC(c)  /* nothing */
 
-#endif // PROFILING
-#endif // STGLDVPROF_H
+#endif /* PROFILING */
+#endif /* STGLDVPROF_H */
diff --git a/ghc/includes/StgMacros.h b/ghc/includes/StgMacros.h
deleted file mode 100644 (file)
index bb1fcf6..0000000
+++ /dev/null
@@ -1,851 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: StgMacros.h,v 1.57 2003/11/12 17:27:04 sof Exp $
- *
- * (c) The GHC Team, 1998-1999
- *
- * Macros used for writing STG-ish C code.
- *
- * ---------------------------------------------------------------------------*/
-
-#ifndef STGMACROS_H
-#define STGMACROS_H
-
-/* -----------------------------------------------------------------------------
-  The following macros create function headers.
-
-  Each basic block is represented by a C function with no arguments.
-  We therefore always begin with either
-
-  extern F_ f(void)
-
-  or
-  
-  static F_ f(void)
-
-  The macros can be used either to define the function itself, or to provide
-  prototypes (by following with a ';').
-
-  Note: the various I*_ shorthands in the second block below are used to
-  declare forward references to local symbols. These shorthands *have* to
-  use the 'extern' type specifier and not 'static'. The reason for this is
-  that 'static' declares a reference as being a static/local variable,
-  and *not* as a forward reference to a static variable.
-
-  This might seem obvious, but it had me stumped as to why my info tables
-  were suddenly all filled with 0s.
-
-    -- sof 1/99 
-
-  --------------------------------------------------------------------------- */
-
-#define STGFUN(f)       StgFunPtr f(void)
-#define EXTFUN(f)      extern StgFunPtr f(void)
-#define EXTFUN_RTS(f)  extern DLL_IMPORT_RTS StgFunPtr f(void)
-#define FN_(f)         F_ f(void)
-#define IF_(f)         static F_ f(void)
-#define EF_(f)         extern F_ f(void)
-#define EDF_(f)                extern DLLIMPORT F_ f(void)
-
-#define EXTINFO_RTS    extern DLL_IMPORT_RTS const StgInfoTable
-#define ETI_RTS                extern DLL_IMPORT_RTS const StgThunkInfoTable
-
-// Info tables as generated by the compiler are simply arrays of words.
-typedef StgWord StgWordArray[];
-
-#define ED_            extern
-#define EDD_           extern DLLIMPORT
-#define ED_RO_         extern const
-#define ID_            static
-#define ID_RO_         static const
-#define EI_             extern StgWordArray
-#define ERI_            extern const StgRetInfoTable
-#define II_             static StgWordArray
-#define IRI_            static const StgRetInfoTable
-#define EC_            extern StgClosure
-#define EDC_           extern DLLIMPORT StgClosure
-#define IC_            static StgClosure
-#define ECP_(x)                extern const StgClosure *(x)[]
-#define EDCP_(x)       extern DLLIMPORT StgClosure *(x)[]
-#define ICP_(x)                static const StgClosure *(x)[]
-
-/* -----------------------------------------------------------------------------
-   Entering 
-
-   It isn't safe to "enter" every closure.  Functions in particular
-   have no entry code as such; their entry point contains the code to
-   apply the function.
-   -------------------------------------------------------------------------- */
-
-#define ENTER()                                        \
- {                                             \
- again:                                                \
-  switch (get_itbl(R1.cl)->type) {             \
-  case IND:                                    \
-  case IND_OLDGEN:                             \
-  case IND_PERM:                               \
-  case IND_OLDGEN_PERM:                                \
-  case IND_STATIC:                             \
-      R1.cl = ((StgInd *)R1.cl)->indirectee;    \
-      goto again;                              \
-  case BCO:                                    \
-  case FUN:                                    \
-  case FUN_1_0:                                        \
-  case FUN_0_1:                                        \
-  case FUN_2_0:                                        \
-  case FUN_1_1:                                        \
-  case FUN_0_2:                                        \
-  case FUN_STATIC:                             \
-  case PAP:                                    \
-      JMP_(ENTRY_CODE(Sp[0]));                 \
-  default:                                     \
-      JMP_(GET_ENTRY(R1.cl));                  \
-  }                                            \
- }
-
-/* -----------------------------------------------------------------------------
-   Heap/Stack Checks.
-
-   When failing a check, we save a return address on the stack and
-   jump to a pre-compiled code fragment that saves the live registers
-   and returns to the scheduler.
-
-   The return address in most cases will be the beginning of the basic
-   block in which the check resides, since we need to perform the check
-   again on re-entry because someone else might have stolen the resource
-   in the meantime.
-   ------------------------------------------------------------------------- */
-
-#define STK_CHK_FUN(headroom,assts)            \
-       if (Sp - headroom < SpLim) {            \
-           assts                               \
-           JMP_(stg_gc_fun);                   \
-       }
-
-#define HP_CHK_FUN(headroom,assts)                                     \
-        DO_GRAN_ALLOCATE(headroom)                                     \
-       if ((Hp += headroom) > HpLim) {                                 \
-            HpAlloc = (headroom);                                      \
-           assts                                                       \
-           JMP_(stg_gc_fun);                                           \
-       }
-
-// When doing both a heap and a stack check, don't move the heap
-// pointer unless the stack check succeeds.  Otherwise we might end up
-// with slop at the end of the current block, which can confuse the
-// LDV profiler.
-#define HP_STK_CHK_FUN(stk_headroom,hp_headroom,assts)                 \
-        DO_GRAN_ALLOCATE(hp_headroom)                                  \
-       if (Sp - stk_headroom < SpLim || (Hp += hp_headroom) > HpLim) { \
-            HpAlloc = (hp_headroom);                                   \
-           assts                                                       \
-           JMP_(stg_gc_fun);                                           \
-       }
-
-/* -----------------------------------------------------------------------------
-   A Heap Check in a case alternative are much simpler: everything is
-   on the stack and covered by a liveness mask already, and there is
-   even a return address with an SRT info table there as well.  
-
-   Just push R1 and return to the scheduler saying 'EnterGHC'
-
-   {STK,HP,HP_STK}_CHK_NP are the various checking macros for
-   bog-standard case alternatives, thunks, and non-top-level
-   functions.  In all these cases, node points to a closure that we
-   can just enter to restart the heap check (the NP stands for 'node points').
-
-   In the NP case GranSim absolutely has to check whether the current node 
-   resides on the current processor. Otherwise a FETCH event has to be
-   scheduled. All that is done in GranSimFetch. -- HWL
-
-   HpLim points to the LAST WORD of valid allocation space.
-   -------------------------------------------------------------------------- */
-
-#define STK_CHK_NP(headroom,tag_assts)         \
-       if ((Sp - (headroom)) < SpLim) {        \
-            tag_assts                          \
-           JMP_(stg_gc_enter_1);               \
-       }
-
-#define HP_CHK_NP(headroom,tag_assts)                                  \
-        DO_GRAN_ALLOCATE(headroom)                                     \
-       if ((Hp += (headroom)) > HpLim) {                               \
-            HpAlloc = (headroom);                                      \
-            tag_assts                                                  \
-           JMP_(stg_gc_enter_1);                                       \
-       }                                                       
-
-// See comment on HP_STK_CHK_FUN above.
-#define HP_STK_CHK_NP(stk_headroom, hp_headroom, tag_assts) \
-        DO_GRAN_ALLOCATE(hp_headroom)                              \
-       if ((Sp - (stk_headroom)) < SpLim || (Hp += (hp_headroom)) > HpLim) { \
-            HpAlloc = (hp_headroom);                           \
-            tag_assts                                          \
-           JMP_(stg_gc_enter_1);                               \
-       }                                                       
-
-
-/* Heap checks for branches of a primitive case / unboxed tuple return */
-
-#define GEN_HP_CHK_ALT(headroom,lbl,tag_assts)                 \
-        DO_GRAN_ALLOCATE(headroom)                              \
-       if ((Hp += (headroom)) > HpLim) {                       \
-            HpAlloc = (headroom);                              \
-            tag_assts                                          \
-           JMP_(lbl);                                          \
-       }                                                       
-
-#define HP_CHK_NOREGS(headroom,tag_assts) \
-    GEN_HP_CHK_ALT(headroom,stg_gc_noregs,tag_assts);
-#define HP_CHK_UNPT_R1(headroom,tag_assts)  \
-    GEN_HP_CHK_ALT(headroom,stg_gc_unpt_r1,tag_assts);
-#define HP_CHK_UNBX_R1(headroom,tag_assts)  \
-    GEN_HP_CHK_ALT(headroom,stg_gc_unbx_r1,tag_assts);
-#define HP_CHK_F1(headroom,tag_assts)       \
-    GEN_HP_CHK_ALT(headroom,stg_gc_f1,tag_assts);
-#define HP_CHK_D1(headroom,tag_assts)       \
-    GEN_HP_CHK_ALT(headroom,stg_gc_d1,tag_assts);
-#define HP_CHK_L1(headroom,tag_assts)       \
-    GEN_HP_CHK_ALT(headroom,stg_gc_l1,tag_assts);
-
-/* -----------------------------------------------------------------------------
-   Generic Heap checks.
-
-   These are slow, but have the advantage of being usable in a variety
-   of situations.  
-
-   The one restriction is that any relevant SRTs must already be pointed
-   to from the stack.  The return address doesn't need to have an info
-   table attached: hence it can be any old code pointer.
-
-   The liveness mask is a logical 'XOR' of NO_PTRS and zero or more
-   Rn_PTR constants defined below.  All registers will be saved, but
-   the garbage collector needs to know which ones contain pointers.
-
-   Good places to use a generic heap check: 
-
-        - case alternatives (the return address with an SRT is already
-         on the stack).
-
-       - primitives (no SRT required).
-
-   The stack frame layout for a RET_DYN is like this:
-
-          some pointers         |-- GET_PTRS(liveness) words
-          some nonpointers      |-- GET_NONPTRS(liveness) words
-                              
-         L1                    \
-          D1-2                  |-- RET_DYN_NONPTR_REGS_SIZE words
-         F1-4                  /
-                              
-         R1-8                  |-- RET_DYN_BITMAP_SIZE words
-                              
-         return address        \
-         liveness mask         |-- StgRetDyn structure
-         stg_gen_chk_info      /
-
-   we assume that the size of a double is always 2 pointers (wasting a
-   word when it is only one pointer, but avoiding lots of #ifdefs).
-
-   NOTE: if you change the layout of RET_DYN stack frames, then you
-   might also need to adjust the value of RESERVED_STACK_WORDS in
-   Constants.h.
-   -------------------------------------------------------------------------- */
-
-// VERY MAGIC CONSTANTS! 
-// must agree with code in HeapStackCheck.c, stg_gen_chk, and
-// RESERVED_STACK_WORDS in Constants.h.
-//
-#define RET_DYN_BITMAP_SIZE 8
-#define RET_DYN_NONPTR_REGS_SIZE 10
-#define ALL_NON_PTRS 0xff
-
-// Sanity check that RESERVED_STACK_WORDS is reasonable.  We can't
-// just derive RESERVED_STACK_WORDS because it's used in Haskell code
-// too.
-#if RESERVED_STACK_WORDS != (3 + RET_DYN_BITMAP_SIZE + RET_DYN_NONPTR_REGS_SIZE)
-#error RESERVED_STACK_WORDS may be wrong!
-#endif
-
-#define LIVENESS_MASK(ptr_regs)  (ALL_NON_PTRS ^ (ptr_regs))
-
-// We can have up to 255 pointers and 255 nonpointers in the stack
-// frame.
-#define N_NONPTRS(n)  ((n)<<16)
-#define N_PTRS(n)     ((n)<<24)
-
-#define GET_NONPTRS(l) ((l)>>16 & 0xff)
-#define GET_PTRS(l)    ((l)>>24 & 0xff)
-#define GET_LIVENESS(l) ((l) & 0xffff)
-
-#define NO_PTRS   0
-#define R1_PTR   1<<0
-#define R2_PTR   1<<1
-#define R3_PTR   1<<2
-#define R4_PTR   1<<3
-#define R5_PTR   1<<4
-#define R6_PTR   1<<5
-#define R7_PTR   1<<6
-#define R8_PTR   1<<7
-
-#define HP_CHK_UNBX_TUPLE(headroom,liveness,code)      \
-   if ((Hp += (headroom)) > HpLim ) {                  \
-        HpAlloc = (headroom);                          \
-        code                                           \
-       R9.w = (W_)LIVENESS_MASK(liveness);             \
-        JMP_(stg_gc_ut);                               \
-    }                                                       
-
-#define HP_CHK_GEN(headroom,liveness,reentry)                  \
-   if ((Hp += (headroom)) > HpLim ) {                          \
-        HpAlloc = (headroom);                                  \
-       R9.w = (W_)LIVENESS_MASK(liveness);                     \
-        R10.w = (W_)reentry;                                   \
-        JMP_(stg_gc_gen);                                      \
-    }                                                       
-
-#define HP_CHK_GEN_TICKY(headroom,liveness,reentry)    \
-   HP_CHK_GEN(headroom,liveness,reentry);              \
-   TICK_ALLOC_HEAP_NOCTR(headroom)
-
-#define STK_CHK_GEN(headroom,liveness,reentry) \
-   if ((Sp - (headroom)) < SpLim) {                            \
-       R9.w = (W_)LIVENESS_MASK(liveness);                     \
-        R10.w = (W_)reentry;                                   \
-        JMP_(stg_gc_gen);                                      \
-   }
-
-#define MAYBE_GC(liveness,reentry)             \
-   if (doYouWantToGC()) {                      \
-       R9.w = (W_)LIVENESS_MASK(liveness);     \
-        R10.w = (W_)reentry;                   \
-        JMP_(stg_gc_gen_hp);                   \
-   }
-
-/* -----------------------------------------------------------------------------
-   Voluntary Yields/Blocks
-
-   We only have a generic version of this at the moment - if it turns
-   out to be slowing us down we can make specialised ones.
-   -------------------------------------------------------------------------- */
-
-EXTFUN_RTS(stg_gen_yield);
-EXTFUN_RTS(stg_gen_block);
-
-#define YIELD(liveness,reentry)                        \
-  {                                            \
-   R9.w  = (W_)LIVENESS_MASK(liveness);                \
-   R10.w = (W_)reentry;                                \
-   JMP_(stg_gen_yield);                                \
-  }
-
-#define BLOCK(liveness,reentry)                        \
-  {                                            \
-   R9.w  = (W_)LIVENESS_MASK(liveness);                \
-   R10.w = (W_)reentry;                                \
-   JMP_(stg_gen_block);                                \
-  }
-
-#define BLOCK_NP(ptrs)                         \
-  {                                            \
-    EXTFUN_RTS(stg_block_##ptrs);                      \
-    JMP_(stg_block_##ptrs);                    \
-  }
-
-#if defined(PAR)
-/*
-  Similar to BLOCK_NP but separates the saving of the thread state from the
-  actual jump via an StgReturn
-*/
-
-#define SAVE_THREAD_STATE(ptrs)                  \
-  ASSERT(ptrs==1);                               \
-  Sp -= 1;                                       \
-  Sp[0] = R1.w;                                  \
-  SaveThreadState();                             
-
-#define THREAD_RETURN(ptrs)                      \
-  ASSERT(ptrs==1);                               \
-  CurrentTSO->what_next = ThreadEnterGHC;        \
-  R1.i = ThreadBlocked;                          \
-  JMP_(StgReturn);                               
-#endif
-
-/* -----------------------------------------------------------------------------
-   CCall_GC needs to push a dummy stack frame containing the contents
-   of volatile registers and variables.  
-
-   We use a RET_DYN frame the same as for a dynamic heap check.
-   ------------------------------------------------------------------------- */
-
-/* -----------------------------------------------------------------------------
-   Vectored Returns
-
-   RETVEC(p,t) where 'p' is a pointer to the info table for a
-   vectored return address, returns the address of the return code for
-   tag 't'.
-
-   Return vectors are placed in *reverse order* immediately before the info
-   table for the return address.  Hence the formula for computing the
-   actual return address is (addr - sizeof(RetInfoTable) - tag - 1).
-   The extra subtraction of one word is because tags start at zero.
-   -------------------------------------------------------------------------- */
-
-#ifdef TABLES_NEXT_TO_CODE
-#define RET_VEC(p,t) (*((P_)(p) - sizeofW(StgRetInfoTable) - t - 1))
-#else
-#define RET_VEC(p,t) (((StgRetInfoTable *)p)->vector[t])
-#endif
-
-/* -----------------------------------------------------------------------------
-   Misc
-   -------------------------------------------------------------------------- */
-
-
-/* set the tag register (if we have one) */
-#define SET_TAG(t)  /* nothing */
-
-#ifdef EAGER_BLACKHOLING
-#  ifdef SMP
-#    define UPD_BH_UPDATABLE(info)                             \
-        TICK_UPD_BH_UPDATABLE();                               \
-        {                                                      \
-         bdescr *bd = Bdescr(R1.p);                            \
-          if (bd->u.back != (bdescr *)BaseReg) {               \
-             if (bd->gen_no >= 1 || bd->step->no >= 1) {       \
-                LOCK_THUNK(info);                              \
-             } else {                                          \
-                EXTFUN_RTS(stg_gc_enter_1_hponly);             \
-                JMP_(stg_gc_enter_1_hponly);                   \
-             }                                                 \
-          }                                                    \
-       }                                                       \
-        SET_INFO(R1.cl,&stg_BLACKHOLE_info)
-#    define UPD_BH_SINGLE_ENTRY(info)                          \
-        TICK_UPD_BH_SINGLE_ENTRY();                            \
-        {                                                      \
-         bdescr *bd = Bdescr(R1.p);                            \
-          if (bd->u.back != (bdescr *)BaseReg) {               \
-             if (bd->gen_no >= 1 || bd->step->no >= 1) {       \
-                LOCK_THUNK(info);                              \
-             } else {                                          \
-                EXTFUN_RTS(stg_gc_enter_1_hponly);             \
-                JMP_(stg_gc_enter_1_hponly);                   \
-             }                                                 \
-          }                                                    \
-       }                                                       \
-        SET_INFO(R1.cl,&stg_BLACKHOLE_info)
-#  else
-#   ifndef PROFILING
-#    define UPD_BH_UPDATABLE(info)             \
-        TICK_UPD_BH_UPDATABLE();               \
-        SET_INFO(R1.cl,&stg_BLACKHOLE_info)
-#    define UPD_BH_SINGLE_ENTRY(info)          \
-        TICK_UPD_BH_SINGLE_ENTRY();            \
-        SET_INFO(R1.cl,&stg_SE_BLACKHOLE_info)
-#   else
-// An object is replaced by a blackhole, so we fill the slop with zeros.
-// 
-// This looks like it can't work - we're overwriting the contents of
-// the THUNK with slop!  Perhaps this never worked??? --SDM
-// The problem is that with eager-black-holing we currently perform
-// the black-holing operation at the *beginning* of the basic block,
-// when we still need the contents of the thunk.
-// Perhaps the thing to do is to overwrite it at the *end* of the
-// basic block, when we've already sucked out the thunk's contents? -- SLPJ
-//
-// Todo: maybe use SET_HDR() and remove LDV_recordCreate()?
-// 
-#    define UPD_BH_UPDATABLE(info)             \
-        TICK_UPD_BH_UPDATABLE();               \
-        LDV_recordDead_FILL_SLOP_DYNAMIC(R1.cl);               \
-        SET_INFO(R1.cl,&stg_BLACKHOLE_info);    \
-        LDV_recordCreate(R1.cl)
-#    define UPD_BH_SINGLE_ENTRY(info)          \
-        TICK_UPD_BH_SINGLE_ENTRY();            \
-        LDV_recordDead_FILL_SLOP_DYNAMIC(R1.cl);               \
-        SET_INFO(R1.cl,&stg_SE_BLACKHOLE_info)  \
-        LDV_recordCreate(R1.cl)
-#   endif /* PROFILING */
-#  endif
-#else /* !EAGER_BLACKHOLING */
-#  define UPD_BH_UPDATABLE(thunk)    /* nothing */
-#  define UPD_BH_SINGLE_ENTRY(thunk) /* nothing */
-#endif /* EAGER_BLACKHOLING */
-
-/* -----------------------------------------------------------------------------
-   Moving Floats and Doubles
-
-   ASSIGN_FLT is for assigning a float to memory (usually the
-              stack/heap).  The memory address is guaranteed to be
-             StgWord aligned (currently == sizeof(void *)).
-
-   PK_FLT     is for pulling a float out of memory.  The memory is
-              guaranteed to be StgWord aligned.
-   -------------------------------------------------------------------------- */
-
-INLINE_HEADER void       ASSIGN_FLT (W_ [], StgFloat);
-INLINE_HEADER StgFloat    PK_FLT     (W_ []);
-
-#if ALIGNMENT_FLOAT <= ALIGNMENT_LONG
-
-INLINE_HEADER void     ASSIGN_FLT(W_ p_dest[], StgFloat src) { *(StgFloat *)p_dest = src; }
-INLINE_HEADER StgFloat PK_FLT    (W_ p_src[])                { return *(StgFloat *)p_src; }
-
-#else  /* ALIGNMENT_FLOAT > ALIGNMENT_UNSIGNED_INT */
-
-INLINE_HEADER void ASSIGN_FLT(W_ p_dest[], StgFloat src)
-{
-    float_thing y;
-    y.f = src;
-    *p_dest = y.fu;
-}
-
-INLINE_HEADER StgFloat PK_FLT(W_ p_src[])
-{
-    float_thing y;
-    y.fu = *p_src;
-    return(y.f);
-}
-
-#endif /* ALIGNMENT_FLOAT > ALIGNMENT_LONG */
-
-#if ALIGNMENT_DOUBLE <= ALIGNMENT_LONG
-
-INLINE_HEADER void       ASSIGN_DBL (W_ [], StgDouble);
-INLINE_HEADER StgDouble   PK_DBL     (W_ []);
-
-INLINE_HEADER void      ASSIGN_DBL(W_ p_dest[], StgDouble src) { *(StgDouble *)p_dest = src; }
-INLINE_HEADER StgDouble PK_DBL    (W_ p_src[])                 { return *(StgDouble *)p_src; }
-
-#else  /* ALIGNMENT_DOUBLE > ALIGNMENT_LONG */
-
-/* Sparc uses two floating point registers to hold a double.  We can
- * write ASSIGN_DBL and PK_DBL by directly accessing the registers
- * independently - unfortunately this code isn't writable in C, we
- * have to use inline assembler.
- */
-#if sparc_TARGET_ARCH
-
-#define ASSIGN_DBL(dst0,src) \
-    { StgPtr dst = (StgPtr)(dst0); \
-      __asm__("st %2,%0\n\tst %R2,%1" : "=m" (((P_)(dst))[0]), \
-       "=m" (((P_)(dst))[1]) : "f" (src)); \
-    }
-
-#define PK_DBL(src0) \
-    ( { StgPtr src = (StgPtr)(src0); \
-        register double d; \
-      __asm__("ld %1,%0\n\tld %2,%R0" : "=f" (d) : \
-       "m" (((P_)(src))[0]), "m" (((P_)(src))[1])); d; \
-    } )
-
-#else /* ! sparc_TARGET_ARCH */
-
-INLINE_HEADER void       ASSIGN_DBL (W_ [], StgDouble);
-INLINE_HEADER StgDouble   PK_DBL     (W_ []);
-
-typedef struct
-  { StgWord dhi;
-    StgWord dlo;
-  } unpacked_double;
-
-typedef union
-  { StgDouble d;
-    unpacked_double du;
-  } double_thing;
-
-INLINE_HEADER void ASSIGN_DBL(W_ p_dest[], StgDouble src)
-{
-    double_thing y;
-    y.d = src;
-    p_dest[0] = y.du.dhi;
-    p_dest[1] = y.du.dlo;
-}
-
-/* GCC also works with this version, but it generates
-   the same code as the previous one, and is not ANSI
-
-#define ASSIGN_DBL( p_dest, src ) \
-       *p_dest = ((double_thing) src).du.dhi; \
-       *(p_dest+1) = ((double_thing) src).du.dlo \
-*/
-
-INLINE_HEADER StgDouble PK_DBL(W_ p_src[])
-{
-    double_thing y;
-    y.du.dhi = p_src[0];
-    y.du.dlo = p_src[1];
-    return(y.d);
-}
-
-#endif /* ! sparc_TARGET_ARCH */
-
-#endif /* ALIGNMENT_DOUBLE > ALIGNMENT_UNSIGNED_INT */
-
-#ifdef SUPPORT_LONG_LONGS
-
-typedef struct
-  { StgWord dhi;
-    StgWord dlo;
-  } unpacked_double_word;
-
-typedef union
-  { StgInt64 i;
-    unpacked_double_word iu;
-  } int64_thing;
-
-typedef union
-  { StgWord64 w;
-    unpacked_double_word wu;
-  } word64_thing;
-
-INLINE_HEADER void ASSIGN_Word64(W_ p_dest[], StgWord64 src)
-{
-    word64_thing y;
-    y.w = src;
-    p_dest[0] = y.wu.dhi;
-    p_dest[1] = y.wu.dlo;
-}
-
-INLINE_HEADER StgWord64 PK_Word64(W_ p_src[])
-{
-    word64_thing y;
-    y.wu.dhi = p_src[0];
-    y.wu.dlo = p_src[1];
-    return(y.w);
-}
-
-INLINE_HEADER void ASSIGN_Int64(W_ p_dest[], StgInt64 src)
-{
-    int64_thing y;
-    y.i = src;
-    p_dest[0] = y.iu.dhi;
-    p_dest[1] = y.iu.dlo;
-}
-
-INLINE_HEADER StgInt64 PK_Int64(W_ p_src[])
-{
-    int64_thing y;
-    y.iu.dhi = p_src[0];
-    y.iu.dlo = p_src[1];
-    return(y.i);
-}
-
-#elif SIZEOF_VOID_P == 8
-
-INLINE_HEADER void ASSIGN_Word64(W_ p_dest[], StgWord64 src)
-{
-       p_dest[0] = src;
-}
-
-INLINE_HEADER StgWord64 PK_Word64(W_ p_src[])
-{
-    return p_src[0];
-}
-
-INLINE_HEADER void ASSIGN_Int64(W_ p_dest[], StgInt64 src)
-{
-    p_dest[0] = src;
-}
-
-INLINE_HEADER StgInt64 PK_Int64(W_ p_src[])
-{
-    return p_src[0];
-}
-
-#endif
-
-/* -----------------------------------------------------------------------------
-   Catch frames
-   -------------------------------------------------------------------------- */
-
-extern DLL_IMPORT_RTS const StgPolyInfoTable stg_catch_frame_info;
-
-/* -----------------------------------------------------------------------------
-   Split markers
-   -------------------------------------------------------------------------- */
-
-#if defined(USE_SPLIT_MARKERS)
-#if defined(LEADING_UNDERSCORE)
-#define __STG_SPLIT_MARKER __asm__("\n___stg_split_marker:");
-#else
-#define __STG_SPLIT_MARKER __asm__("\n__stg_split_marker:");
-#endif
-#else
-#define __STG_SPLIT_MARKER /* nothing */
-#endif
-
-/* -----------------------------------------------------------------------------
-   Closure and Info Macros with casting.
-
-   We don't want to mess around with casts in the generated C code, so
-   we use this casting versions of the closure macro.
-
-   This version of SET_HDR also includes CCS_ALLOC for profiling - the
-   reason we don't use two separate macros is that the cost centre
-   field is sometimes a non-simple expression and we want to share its
-   value between SET_HDR and CCS_ALLOC.
-   -------------------------------------------------------------------------- */
-
-#define SET_HDR_(c,info,ccs,size)                              \
-  {                                                            \
-      CostCentreStack *tmp = (ccs);                            \
-      SET_HDR((StgClosure *)(c),(StgInfoTable *)(info),tmp);   \
-      CCS_ALLOC(tmp,size);                                     \
-  }
-
-/* -----------------------------------------------------------------------------
-   Saving context for exit from the STG world, and loading up context
-   on entry to STG code.
-
-   We save all the STG registers (that is, the ones that are mapped to
-   machine registers) in their places in the TSO.  
-
-   The stack registers go into the current stack object, and the
-   current nursery is updated from the heap pointer.
-
-   These functions assume that BaseReg is loaded appropriately (if
-   we have one).
-   -------------------------------------------------------------------------- */
-
-#if IN_STG_CODE
-
-INLINE_HEADER void
-SaveThreadState(void)
-{
-  StgTSO *tso;
-
-  /* Don't need to save REG_Base, it won't have changed. */
-
-  tso = CurrentTSO;
-  tso->sp       = Sp;
-  CloseNursery(Hp);
-
-#ifdef REG_CurrentTSO
-  SAVE_CurrentTSO = tso;
-#endif
-#ifdef REG_CurrentNursery
-  SAVE_CurrentNursery = CurrentNursery;
-#endif
-#if defined(PROFILING)
-  CurrentTSO->prof.CCCS = CCCS;
-#endif
-}
-
-INLINE_HEADER void 
-LoadThreadState (void)
-{
-  StgTSO *tso;
-
-#ifdef REG_CurrentTSO
-  CurrentTSO = SAVE_CurrentTSO;
-#endif
-
-  tso = CurrentTSO;
-  Sp    = tso->sp;
-  SpLim = (P_)&(tso->stack) + RESERVED_STACK_WORDS;
-  OpenNursery(Hp,HpLim);
-
-#ifdef REG_CurrentNursery
-  CurrentNursery = SAVE_CurrentNursery;
-#endif
-# if defined(PROFILING)
-  CCCS = CurrentTSO->prof.CCCS;
-# endif
-}
-
-#endif
-
-/* -----------------------------------------------------------------------------
-   Module initialisation
-
-   The module initialisation code looks like this, roughly:
-
-       FN(__stginit_Foo) {
-         JMP_(__stginit_Foo_1_p)
-       }
-
-       FN(__stginit_Foo_1_p) {
-       ...
-       }
-
-   We have one version of the init code with a module version and the
-   'way' attached to it.  The version number helps to catch cases
-   where modules are not compiled in dependency order before being
-   linked: if a module has been compiled since any modules which depend on
-   it, then the latter modules will refer to a different version in their
-   init blocks and a link error will ensue.
-
-   The 'way' suffix helps to catch cases where modules compiled in different
-   ways are linked together (eg. profiled and non-profiled).
-
-   We provide a plain, unadorned, version of the module init code
-   which just jumps to the version with the label and way attached.  The
-   reason for this is that when using foreign exports, the caller of
-   startupHaskell() must supply the name of the init function for the "top"
-   module in the program, and we don't want to require that this name
-   has the version and way info appended to it.
-   -------------------------------------------------------------------------- */
-
-#define PUSH_INIT_STACK(reg_function)          \
-       *(Sp++) = (W_)reg_function
-
-#define POP_INIT_STACK()                       \
-       *(--Sp)
-
-#define MOD_INIT_WRAPPER(label,real_init)      \
-
-
-#define START_MOD_INIT(plain_lbl, real_lbl)    \
-       static int _module_registered = 0;      \
-       EF_(real_lbl);                          \
-       FN_(plain_lbl) {                        \
-            FB_                                        \
-            JMP_(real_lbl);                    \
-           FE_                                 \
-        }                                      \
-       FN_(real_lbl) {                 \
-           FB_;                                \
-           if (! _module_registered) {         \
-               _module_registered = 1;         \
-               { 
-           /* extern decls go here, followed by init code */
-
-#define REGISTER_FOREIGN_EXPORT(reg_fe_binder) \
-        STGCALL1(getStablePtr,reg_fe_binder)
-       
-#define REGISTER_IMPORT(reg_mod_name)          \
-        PUSH_INIT_STACK(reg_mod_name)
-
-#define END_MOD_INIT()                         \
-        }};                                    \
-       JMP_(POP_INIT_STACK());                 \
-       FE_ }
-
-/* -----------------------------------------------------------------------------
-   Support for _ccall_GC_ and _casm_GC.
-   -------------------------------------------------------------------------- */
-
-/* 
- * Suspending/resuming threads for doing external C-calls (_ccall_GC).
- * These functions are defined in rts/Schedule.c.
- */
-StgInt        suspendThread ( StgRegTable *, rtsBool);
-StgRegTable * resumeThread  ( StgInt, rtsBool );
-
-#define SUSPEND_THREAD(token,threaded)         \
-   SaveThreadState();                          \
-   token = suspendThread(BaseReg,threaded);
-
-#ifdef SMP
-#define RESUME_THREAD(token,threaded)          \
-    BaseReg = resumeThread(token,threaded);    \
-    LoadThreadState();
-#else
-#define RESUME_THREAD(token,threaded)          \
-   (void)resumeThread(token,threaded);         \
-   LoadThreadState();
-#endif
-
-#endif /* STGMACROS_H */
-
index 6cc9173..ef39a8e 100644 (file)
-/* -----------------------------------------------------------------------------
- * $Id: StgMiscClosures.h,v 1.47 2003/03/27 13:54:31 simonmar Exp $
+/* ----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2004
  *
- * (c) The GHC Team, 1998-2002
+ * Declarations for various symbols exported by the RTS.
  *
- * Entry code for various built-in closure types.
+ * ToDo: many of the symbols in here don't need to be exported, but
+ * our Cmm code generator doesn't know how to generate local symbols
+ * for the RTS bits (it assumes all RTS symbols are external).
  *
- * ---------------------------------------------------------------------------*/
+ * --------------------------------------------------------------------------*/
+
+#ifndef STGMISCCLOSURES_H
+#define STGMISCCLOSURES_H
+
+#if IN_STG_CODE
+#  define RTS_RET_INFO(i)   extern W_(i)[]
+#  define RTS_FUN_INFO(i)   extern W_(i)[]
+#  define RTS_THUNK_INFO(i) extern W_(i)[]
+#  define RTS_INFO(i)       extern W_(i)[]
+#  define RTS_CLOSURE(i)    extern W_(i)[]
+#  define RTS_FUN(f)       extern DLL_IMPORT_RTS StgFunPtr f(void)
+#else
+#  define RTS_RET_INFO(i)   extern DLL_IMPORT_RTS const StgRetInfoTable i
+#  define RTS_FUN_INFO(i)   extern DLL_IMPORT_RTS const StgFunInfoTable i
+#  define RTS_THUNK_INFO(i) extern DLL_IMPORT_RTS const StgThunkInfoTable i
+#  define RTS_INFO(i)       extern DLL_IMPORT_RTS const StgInfoTable i
+#  define RTS_CLOSURE(i)    extern DLL_IMPORT_RTS StgClosure i
+#  define RTS_FUN(f)       extern DLL_IMPORT_RTS StgFunPtr f(void)
+#endif
 
-/* The naming scheme here follows the naming scheme for closure types
- * defined in InfoTables.h.  The actual info tables and entry code for
- * these objects can be found in StgMiscClosures.hc.
- */
+#ifdef TABLES_NEXT_TO_CODE
+#  define RTS_ENTRY(f)    /* nothing */
+#else
+#  define RTS_ENTRY(f)    RTS_FUN(f)
+#endif
 
-/* Various entry points */
-STGFUN(stg_PAP_entry);
-STGFUN(stg_BCO_entry);
+/* Stack frames */
+RTS_RET_INFO(stg_upd_frame_info);
+RTS_RET_INFO(stg_noupd_frame_info);
+RTS_RET_INFO(stg_seq_frame_info);
+RTS_RET_INFO(stg_catch_frame_info);
+
+RTS_ENTRY(stg_upd_frame_ret);
+RTS_ENTRY(stg_seq_frame_ret);
 
 /* Entry code for constructors created by the bytecode interpreter */
-STGFUN(stg_interp_constr_entry);
-STGFUN(stg_interp_constr1_entry);
-STGFUN(stg_interp_constr2_entry);
-STGFUN(stg_interp_constr3_entry);
-STGFUN(stg_interp_constr4_entry);
-STGFUN(stg_interp_constr5_entry);
-STGFUN(stg_interp_constr6_entry);
-STGFUN(stg_interp_constr7_entry);
-STGFUN(stg_interp_constr8_entry);
+RTS_ENTRY(stg_interp_constr_entry);
+RTS_ENTRY(stg_interp_constr1_entry);
+RTS_ENTRY(stg_interp_constr2_entry);
+RTS_ENTRY(stg_interp_constr3_entry);
+RTS_ENTRY(stg_interp_constr4_entry);
+RTS_ENTRY(stg_interp_constr5_entry);
+RTS_ENTRY(stg_interp_constr6_entry);
+RTS_ENTRY(stg_interp_constr7_entry);
+RTS_ENTRY(stg_interp_constr8_entry);
 
 /* Magic glue code for when compiled code returns a value in R1/F1/D1
    or a VoidRep to the interpreter. */
-extern DLL_IMPORT_RTS const StgPolyInfoTable stg_ctoi_ret_R1p_info;
-extern DLL_IMPORT_RTS const StgRetInfoTable stg_ctoi_ret_R1unpt_info;
-extern DLL_IMPORT_RTS const StgRetInfoTable stg_ctoi_ret_R1n_info;
-extern DLL_IMPORT_RTS const StgRetInfoTable stg_ctoi_ret_F1_info;
-extern DLL_IMPORT_RTS const StgRetInfoTable stg_ctoi_ret_D1_info;
-extern DLL_IMPORT_RTS const StgRetInfoTable stg_ctoi_ret_L1_info;
-extern DLL_IMPORT_RTS const StgRetInfoTable stg_ctoi_ret_V_info;
-
-extern DLL_IMPORT_RTS const StgRetInfoTable stg_apply_interp_info;
-
-/* this is the NIL ptr for a TSO queue (e.g. runnable queue) */
-#define END_TSO_QUEUE  ((StgTSO *)(void*)&stg_END_TSO_QUEUE_closure)
-/* this is the NIL ptr for a list CAFs */
-#define END_ECAF_LIST   ((StgCAF *)(void*)&stg_END_TSO_QUEUE_closure)
+RTS_RET_INFO(stg_ctoi_R1p_info);
+RTS_RET_INFO(stg_ctoi_R1unpt_info);
+RTS_RET_INFO(stg_ctoi_R1n_info);
+RTS_RET_INFO(stg_ctoi_F1_info);
+RTS_RET_INFO(stg_ctoi_D1_info);
+RTS_RET_INFO(stg_ctoi_L1_info);
+RTS_RET_INFO(stg_ctoi_V_info);
+
+RTS_ENTRY(stg_ctoi_R1p_ret);
+RTS_ENTRY(stg_ctoi_R1unpt_ret);
+RTS_ENTRY(stg_ctoi_R1n_ret);
+RTS_ENTRY(stg_ctoi_F1_ret);
+RTS_ENTRY(stg_ctoi_D1_ret);
+RTS_ENTRY(stg_ctoi_L1_ret);
+RTS_ENTRY(stg_ctoi_V_ret);
+
+RTS_RET_INFO(stg_apply_interp_info);
+RTS_ENTRY(stg_apply_interp_ret);
+
+RTS_INFO(stg_IND_info);
+RTS_INFO(stg_IND_direct_info);
+RTS_INFO(stg_IND_0_info);
+RTS_INFO(stg_IND_1_info);
+RTS_INFO(stg_IND_2_info);
+RTS_INFO(stg_IND_3_info);
+RTS_INFO(stg_IND_4_info);
+RTS_INFO(stg_IND_5_info);
+RTS_INFO(stg_IND_6_info);
+RTS_INFO(stg_IND_7_info);
+RTS_INFO(stg_IND_STATIC_info);
+RTS_INFO(stg_IND_PERM_info);
+RTS_INFO(stg_IND_OLDGEN_info);
+RTS_INFO(stg_IND_OLDGEN_PERM_info);
+RTS_INFO(stg_CAF_UNENTERED_info);
+RTS_INFO(stg_CAF_ENTERED_info);
+RTS_INFO(stg_BLACKHOLE_info);
+RTS_INFO(stg_CAF_BLACKHOLE_info);
+RTS_INFO(stg_BLACKHOLE_BQ_info);
+#ifdef TICKY_TICKY
+RTS_INFO(stg_SE_BLACKHOLE_info);
+RTS_INFO(stg_SE_CAF_BLACKHOLE_info);
+#endif
+
 #if defined(PAR) || defined(GRAN)
-/* this is the NIL ptr for a blocking queue */
-# define END_BQ_QUEUE  ((StgBlockingQueueElement *)(void*)&stg_END_TSO_QUEUE_closure)
-/* this is the NIL ptr for a blocked fetch queue (as in PendingFetches in GUM) */
-# define END_BF_QUEUE  ((StgBlockedFetch *)(void*)&stg_END_TSO_QUEUE_closure)
+RTS_INFO(stg_RBH_info);
 #endif
-/* ToDo?: different name for end of sleeping queue ? -- HWL */
-
-/* info tables */
-
-extern DLL_IMPORT_RTS const StgInfoTable stg_IND_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_IND_direct_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_IND_0_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_IND_1_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_IND_2_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_IND_3_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_IND_4_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_IND_5_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_IND_6_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_IND_7_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_IND_STATIC_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_IND_PERM_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_IND_OLDGEN_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_IND_OLDGEN_PERM_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_CAF_UNENTERED_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_CAF_ENTERED_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_BLACKHOLE_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_CAF_BLACKHOLE_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_BLACKHOLE_BQ_info;
-#ifdef SMP
-extern DLL_IMPORT_RTS const StgInfoTable stg_WHITEHOLE_info;
+#if defined(PAR)
+RTS_INFO(stg_FETCH_ME_BQ_info);
 #endif
+RTS_FUN_INFO(stg_BCO_info);
+RTS_INFO(stg_EVACUATED_info);
+RTS_INFO(stg_FOREIGN_info);
+RTS_INFO(stg_WEAK_info);
+RTS_INFO(stg_DEAD_WEAK_info);
+RTS_INFO(stg_STABLE_NAME_info);
+RTS_INFO(stg_FULL_MVAR_info);
+RTS_INFO(stg_EMPTY_MVAR_info);
+RTS_INFO(stg_TSO_info);
+RTS_INFO(stg_ARR_WORDS_info);
+RTS_INFO(stg_MUT_ARR_WORDS_info);
+RTS_INFO(stg_MUT_ARR_PTRS_info);
+RTS_INFO(stg_MUT_ARR_PTRS_FROZEN_info);
+RTS_INFO(stg_MUT_VAR_info);
+RTS_INFO(stg_END_TSO_QUEUE_info);
+RTS_INFO(stg_MUT_CONS_info);
+RTS_INFO(stg_END_MUT_LIST_info);
+RTS_INFO(stg_catch_info);
+RTS_INFO(stg_PAP_info);
+RTS_INFO(stg_AP_info);
+RTS_INFO(stg_AP_STACK_info);
+RTS_INFO(stg_dummy_ret_info);
+RTS_INFO(stg_raise_info);
+
+RTS_ENTRY(stg_IND_entry);
+RTS_ENTRY(stg_IND_direct_entry);
+RTS_ENTRY(stg_IND_0_entry);
+RTS_ENTRY(stg_IND_1_entry);
+RTS_ENTRY(stg_IND_2_entry);
+RTS_ENTRY(stg_IND_3_entry);
+RTS_ENTRY(stg_IND_4_entry);
+RTS_ENTRY(stg_IND_5_entry);
+RTS_ENTRY(stg_IND_6_entry);
+RTS_ENTRY(stg_IND_7_entry);
+RTS_ENTRY(stg_IND_STATIC_entry);
+RTS_ENTRY(stg_IND_PERM_entry);
+RTS_ENTRY(stg_IND_OLDGEN_entry);
+RTS_ENTRY(stg_IND_OLDGEN_PERM_entry);
+RTS_ENTRY(stg_CAF_UNENTERED_entry);
+RTS_ENTRY(stg_CAF_ENTERED_entry);
+RTS_ENTRY(stg_BLACKHOLE_entry);
+RTS_ENTRY(stg_CAF_BLACKHOLE_entry);
+RTS_ENTRY(stg_BLACKHOLE_BQ_entry);
 #ifdef TICKY_TICKY
-extern DLL_IMPORT_RTS const StgInfoTable stg_SE_BLACKHOLE_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_SE_CAF_BLACKHOLE_info;
+RTS_ENTRY(stg_SE_BLACKHOLE_entry);
+RTS_ENTRY(stg_SE_CAF_BLACKHOLE_entry);
 #endif
 #if defined(PAR) || defined(GRAN)
-extern DLL_IMPORT_RTS const StgInfoTable stg_RBH_info;
+RTS_ENTRY(stg_RBH_entry);
 #endif
 #if defined(PAR)
-extern DLL_IMPORT_RTS const StgInfoTable stg_FETCH_ME_BQ_info;
+RTS_ENTRY(stg_FETCH_ME_BQ_entry);
 #endif
-extern DLL_IMPORT_RTS const StgFunInfoTable stg_BCO_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_EVACUATED_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_FOREIGN_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_WEAK_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_DEAD_WEAK_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_STABLE_NAME_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_FULL_MVAR_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_EMPTY_MVAR_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_TSO_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_ARR_WORDS_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_MUT_ARR_WORDS_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_MUT_ARR_PTRS_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_MUT_ARR_PTRS_FROZEN_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_MUT_VAR_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_END_TSO_QUEUE_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_MUT_CONS_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_END_MUT_LIST_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_catch_info;
-extern DLL_IMPORT_RTS const StgPolyInfoTable stg_seq_frame_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_PAP_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_AP_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_AP_STACK_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_dummy_ret_info;
-extern DLL_IMPORT_RTS const StgInfoTable stg_raise_info;
-extern DLL_IMPORT_RTS const StgRetInfoTable stg_forceIO_info;
-extern DLL_IMPORT_RTS const StgRetInfoTable stg_noforceIO_info;
+RTS_ENTRY(stg_BCO_entry);
+RTS_ENTRY(stg_EVACUATED_entry);
+RTS_ENTRY(stg_FOREIGN_entry);
+RTS_ENTRY(stg_WEAK_entry);
+RTS_ENTRY(stg_DEAD_WEAK_entry);
+RTS_ENTRY(stg_STABLE_NAME_entry);
+RTS_ENTRY(stg_FULL_MVAR_entry);
+RTS_ENTRY(stg_EMPTY_MVAR_entry);
+RTS_ENTRY(stg_TSO_entry);
+RTS_ENTRY(stg_ARR_WORDS_entry);
+RTS_ENTRY(stg_MUT_ARR_WORDS_entry);
+RTS_ENTRY(stg_MUT_ARR_PTRS_entry);
+RTS_ENTRY(stg_MUT_ARR_PTRS_FROZEN_entry);
+RTS_ENTRY(stg_MUT_VAR_entry);
+RTS_ENTRY(stg_END_TSO_QUEUE_entry);
+RTS_ENTRY(stg_MUT_CONS_entry);
+RTS_ENTRY(stg_END_MUT_LIST_entry);
+RTS_ENTRY(stg_catch_entry);
+RTS_ENTRY(stg_PAP_entry);
+RTS_ENTRY(stg_AP_entry);
+RTS_ENTRY(stg_AP_STACK_entry);
+RTS_ENTRY(stg_dummy_ret_entry);
+RTS_ENTRY(stg_raise_entry);
+
+
+RTS_ENTRY(stg_unblockAsyncExceptionszh_ret_ret);
+RTS_ENTRY(stg_blockAsyncExceptionszh_ret_ret);
+RTS_ENTRY(stg_catch_frame_ret);
+RTS_ENTRY(stg_catch_entry);
+RTS_ENTRY(stg_raise_entry);
+
 /* closures */
 
-extern DLL_IMPORT_RTS StgClosure stg_END_TSO_QUEUE_closure;
-extern DLL_IMPORT_RTS StgClosure stg_END_MUT_LIST_closure;
-extern DLL_IMPORT_RTS StgClosure stg_NO_FINALIZER_closure;
-extern DLL_IMPORT_RTS StgClosure stg_dummy_ret_closure;
-extern DLL_IMPORT_RTS StgClosure stg_forceIO_closure;
+RTS_CLOSURE(stg_END_TSO_QUEUE_closure);
+RTS_CLOSURE(stg_END_MUT_LIST_closure);
+RTS_CLOSURE(stg_NO_FINALIZER_closure);
+RTS_CLOSURE(stg_dummy_ret_closure);
+RTS_CLOSURE(stg_forceIO_closure);
+
+RTS_ENTRY(stg_NO_FINALIZER_entry);
+RTS_ENTRY(stg_END_EXCEPTION_LIST_entry);
+RTS_ENTRY(stg_EXCEPTION_CONS_entry);
 
+#if IN_STG_CODE
+extern DLL_IMPORT_RTS StgWordArray stg_CHARLIKE_closure;
+extern DLL_IMPORT_RTS StgWordArray stg_INTLIKE_closure;
+#else
 extern DLL_IMPORT_RTS StgIntCharlikeClosure stg_CHARLIKE_closure[];
 extern DLL_IMPORT_RTS StgIntCharlikeClosure stg_INTLIKE_closure[];
+#endif
+
+/* StgStartup */
+
+RTS_RET_INFO(stg_forceIO_info);
+RTS_ENTRY(stg_forceIO_ret);
 
+RTS_RET_INFO(stg_noforceIO_info);
+RTS_ENTRY(stg_noforceIO_ret);
 
 /* standard entry points */
 
 /* standard selector thunks */
 
-EXTINFO_RTS stg_sel_0_upd_info;
-EXTINFO_RTS stg_sel_1_upd_info;
-EXTINFO_RTS stg_sel_2_upd_info;
-EXTINFO_RTS stg_sel_3_upd_info;
-EXTINFO_RTS stg_sel_4_upd_info;
-EXTINFO_RTS stg_sel_5_upd_info;
-EXTINFO_RTS stg_sel_6_upd_info;
-EXTINFO_RTS stg_sel_7_upd_info;
-EXTINFO_RTS stg_sel_8_upd_info;
-EXTINFO_RTS stg_sel_8_upd_info;
-EXTINFO_RTS stg_sel_9_upd_info;
-EXTINFO_RTS stg_sel_10_upd_info;
-EXTINFO_RTS stg_sel_11_upd_info;
-EXTINFO_RTS stg_sel_12_upd_info;
-EXTINFO_RTS stg_sel_13_upd_info;
-EXTINFO_RTS stg_sel_14_upd_info;
-EXTINFO_RTS stg_sel_15_upd_info;
-
-EXTINFO_RTS stg_sel_0_noupd_info;
-EXTINFO_RTS stg_sel_1_noupd_info;
-EXTINFO_RTS stg_sel_2_noupd_info;
-EXTINFO_RTS stg_sel_3_noupd_info;
-EXTINFO_RTS stg_sel_4_noupd_info;
-EXTINFO_RTS stg_sel_5_noupd_info;
-EXTINFO_RTS stg_sel_6_noupd_info;
-EXTINFO_RTS stg_sel_7_noupd_info;
-EXTINFO_RTS stg_sel_8_noupd_info;
-EXTINFO_RTS stg_sel_9_noupd_info;
-EXTINFO_RTS stg_sel_10_noupd_info;
-EXTINFO_RTS stg_sel_11_noupd_info;
-EXTINFO_RTS stg_sel_12_noupd_info;
-EXTINFO_RTS stg_sel_13_noupd_info;
-EXTINFO_RTS stg_sel_14_noupd_info;
-EXTINFO_RTS stg_sel_15_noupd_info;
-
-  /* and their standard entry points  -- KSW 1998-12 */
-
-EXTFUN_RTS(stg_sel_0_upd_entry);
-EXTFUN_RTS(stg_sel_1_upd_entry);
-EXTFUN_RTS(stg_sel_2_upd_entry);
-EXTFUN_RTS(stg_sel_3_upd_entry);
-EXTFUN_RTS(stg_sel_4_upd_entry);
-EXTFUN_RTS(stg_sel_5_upd_entry);
-EXTFUN_RTS(stg_sel_6_upd_entry);
-EXTFUN_RTS(stg_sel_7_upd_entry);
-EXTFUN_RTS(stg_sel_8_upd_entry);
-EXTFUN_RTS(stg_sel_8_upd_entry);
-EXTFUN_RTS(stg_sel_9_upd_entry);
-EXTFUN_RTS(stg_sel_10_upd_entry);
-EXTFUN_RTS(stg_sel_11_upd_entry);
-EXTFUN_RTS(stg_sel_12_upd_entry);
-EXTFUN_RTS(stg_sel_13_upd_entry);
-EXTFUN_RTS(stg_sel_14_upd_entry);
-EXTFUN_RTS(stg_sel_15_upd_entry);
-
-EXTFUN_RTS(stg_sel_0_noupd_entry);
-EXTFUN_RTS(stg_sel_1_noupd_entry);
-EXTFUN_RTS(stg_sel_2_noupd_entry);
-EXTFUN_RTS(stg_sel_3_noupd_entry);
-EXTFUN_RTS(stg_sel_4_noupd_entry);
-EXTFUN_RTS(stg_sel_5_noupd_entry);
-EXTFUN_RTS(stg_sel_6_noupd_entry);
-EXTFUN_RTS(stg_sel_7_noupd_entry);
-EXTFUN_RTS(stg_sel_8_noupd_entry);
-EXTFUN_RTS(stg_sel_9_noupd_entry);
-EXTFUN_RTS(stg_sel_10_noupd_entry);
-EXTFUN_RTS(stg_sel_11_noupd_entry);
-EXTFUN_RTS(stg_sel_12_noupd_entry);
-EXTFUN_RTS(stg_sel_13_noupd_entry);
-EXTFUN_RTS(stg_sel_14_noupd_entry);
-EXTFUN_RTS(stg_sel_15_noupd_entry);
-
-// standard ap thunks
-
-ETI_RTS stg_ap_1_upd_info;
-ETI_RTS stg_ap_2_upd_info;
-ETI_RTS stg_ap_3_upd_info;
-ETI_RTS stg_ap_4_upd_info;
-ETI_RTS stg_ap_5_upd_info;
-ETI_RTS stg_ap_6_upd_info;
-ETI_RTS stg_ap_7_upd_info;
-ETI_RTS stg_ap_8_upd_info;
-
-// standard application routines (see also rts/gen_apply.py, 
-// and compiler/codeGen/CgStackery.lhs).
-
-extern DLL_IMPORT_RTS const StgPolyInfoTable stg_ap_0_info;
-ERI_(stg_ap_v_info);
-ERI_(stg_ap_f_info);
-ERI_(stg_ap_d_info);
-ERI_(stg_ap_l_info);
-ERI_(stg_ap_n_info);
-ERI_(stg_ap_p_info);
-ERI_(stg_ap_pv_info);
-ERI_(stg_ap_pp_info);
-ERI_(stg_ap_ppv_info);
-ERI_(stg_ap_ppp_info);
-ERI_(stg_ap_pppp_info);
-ERI_(stg_ap_ppppp_info);
-ERI_(stg_ap_pppppp_info);
-ERI_(stg_ap_ppppppp_info);
-
-EXTFUN(stg_ap_0_ret);
-EXTFUN(stg_ap_v_ret);
-EXTFUN(stg_ap_f_ret);
-EXTFUN(stg_ap_d_ret);
-EXTFUN(stg_ap_l_ret);
-EXTFUN(stg_ap_n_ret);
-EXTFUN(stg_ap_p_ret);
-EXTFUN(stg_ap_pv_ret);
-EXTFUN(stg_ap_pp_ret);
-EXTFUN(stg_ap_ppv_ret);
-EXTFUN(stg_ap_ppp_ret);
-EXTFUN(stg_ap_pppp_ret);
-EXTFUN(stg_ap_ppppp_ret);
-EXTFUN(stg_ap_pppppp_ret);
-EXTFUN(stg_ap_ppppppp_ret);
+RTS_ENTRY(stg_sel_ret_0_upd_ret);
+RTS_ENTRY(stg_sel_ret_1_upd_ret);
+RTS_ENTRY(stg_sel_ret_2_upd_ret);
+RTS_ENTRY(stg_sel_ret_3_upd_ret);
+RTS_ENTRY(stg_sel_ret_4_upd_ret);
+RTS_ENTRY(stg_sel_ret_5_upd_ret);
+RTS_ENTRY(stg_sel_ret_6_upd_ret);
+RTS_ENTRY(stg_sel_ret_7_upd_ret);
+RTS_ENTRY(stg_sel_ret_8_upd_ret);
+RTS_ENTRY(stg_sel_ret_8_upd_ret);
+RTS_ENTRY(stg_sel_ret_9_upd_ret);
+RTS_ENTRY(stg_sel_ret_10_upd_ret);
+RTS_ENTRY(stg_sel_ret_11_upd_ret);
+RTS_ENTRY(stg_sel_ret_12_upd_ret);
+RTS_ENTRY(stg_sel_ret_13_upd_ret);
+RTS_ENTRY(stg_sel_ret_14_upd_ret);
+RTS_ENTRY(stg_sel_ret_15_upd_ret);
+
+RTS_INFO(stg_sel_0_upd_info);
+RTS_INFO(stg_sel_1_upd_info);
+RTS_INFO(stg_sel_2_upd_info);
+RTS_INFO(stg_sel_3_upd_info);
+RTS_INFO(stg_sel_4_upd_info);
+RTS_INFO(stg_sel_5_upd_info);
+RTS_INFO(stg_sel_6_upd_info);
+RTS_INFO(stg_sel_7_upd_info);
+RTS_INFO(stg_sel_8_upd_info);
+RTS_INFO(stg_sel_8_upd_info);
+RTS_INFO(stg_sel_9_upd_info);
+RTS_INFO(stg_sel_10_upd_info);
+RTS_INFO(stg_sel_11_upd_info);
+RTS_INFO(stg_sel_12_upd_info);
+RTS_INFO(stg_sel_13_upd_info);
+RTS_INFO(stg_sel_14_upd_info);
+RTS_INFO(stg_sel_15_upd_info);
+
+RTS_ENTRY(stg_sel_0_upd_entry);
+RTS_ENTRY(stg_sel_1_upd_entry);
+RTS_ENTRY(stg_sel_2_upd_entry);
+RTS_ENTRY(stg_sel_3_upd_entry);
+RTS_ENTRY(stg_sel_4_upd_entry);
+RTS_ENTRY(stg_sel_5_upd_entry);
+RTS_ENTRY(stg_sel_6_upd_entry);
+RTS_ENTRY(stg_sel_7_upd_entry);
+RTS_ENTRY(stg_sel_8_upd_entry);
+RTS_ENTRY(stg_sel_8_upd_entry);
+RTS_ENTRY(stg_sel_9_upd_entry);
+RTS_ENTRY(stg_sel_10_upd_entry);
+RTS_ENTRY(stg_sel_11_upd_entry);
+RTS_ENTRY(stg_sel_12_upd_entry);
+RTS_ENTRY(stg_sel_13_upd_entry);
+RTS_ENTRY(stg_sel_14_upd_entry);
+RTS_ENTRY(stg_sel_15_upd_entry);
+
+RTS_ENTRY(stg_sel_ret_0_noupd_ret);
+RTS_ENTRY(stg_sel_ret_1_noupd_ret);
+RTS_ENTRY(stg_sel_ret_2_noupd_ret);
+RTS_ENTRY(stg_sel_ret_3_noupd_ret);
+RTS_ENTRY(stg_sel_ret_4_noupd_ret);
+RTS_ENTRY(stg_sel_ret_5_noupd_ret);
+RTS_ENTRY(stg_sel_ret_6_noupd_ret);
+RTS_ENTRY(stg_sel_ret_7_noupd_ret);
+RTS_ENTRY(stg_sel_ret_8_noupd_ret);
+RTS_ENTRY(stg_sel_ret_8_noupd_ret);
+RTS_ENTRY(stg_sel_ret_9_noupd_ret);
+RTS_ENTRY(stg_sel_ret_10_noupd_ret);
+RTS_ENTRY(stg_sel_ret_11_noupd_ret);
+RTS_ENTRY(stg_sel_ret_12_noupd_ret);
+RTS_ENTRY(stg_sel_ret_13_noupd_ret);
+RTS_ENTRY(stg_sel_ret_14_noupd_ret);
+RTS_ENTRY(stg_sel_ret_15_noupd_ret);
+
+RTS_INFO(stg_sel_0_noupd_info);
+RTS_INFO(stg_sel_1_noupd_info);
+RTS_INFO(stg_sel_2_noupd_info);
+RTS_INFO(stg_sel_3_noupd_info);
+RTS_INFO(stg_sel_4_noupd_info);
+RTS_INFO(stg_sel_5_noupd_info);
+RTS_INFO(stg_sel_6_noupd_info);
+RTS_INFO(stg_sel_7_noupd_info);
+RTS_INFO(stg_sel_8_noupd_info);
+RTS_INFO(stg_sel_9_noupd_info);
+RTS_INFO(stg_sel_10_noupd_info);
+RTS_INFO(stg_sel_11_noupd_info);
+RTS_INFO(stg_sel_12_noupd_info);
+RTS_INFO(stg_sel_13_noupd_info);
+RTS_INFO(stg_sel_14_noupd_info);
+RTS_INFO(stg_sel_15_noupd_info);
+
+RTS_ENTRY(stg_sel_0_noupd_entry);
+RTS_ENTRY(stg_sel_1_noupd_entry);
+RTS_ENTRY(stg_sel_2_noupd_entry);
+RTS_ENTRY(stg_sel_3_noupd_entry);
+RTS_ENTRY(stg_sel_4_noupd_entry);
+RTS_ENTRY(stg_sel_5_noupd_entry);
+RTS_ENTRY(stg_sel_6_noupd_entry);
+RTS_ENTRY(stg_sel_7_noupd_entry);
+RTS_ENTRY(stg_sel_8_noupd_entry);
+RTS_ENTRY(stg_sel_9_noupd_entry);
+RTS_ENTRY(stg_sel_10_noupd_entry);
+RTS_ENTRY(stg_sel_11_noupd_entry);
+RTS_ENTRY(stg_sel_12_noupd_entry);
+RTS_ENTRY(stg_sel_13_noupd_entry);
+RTS_ENTRY(stg_sel_14_noupd_entry);
+RTS_ENTRY(stg_sel_15_noupd_entry);
+
+/* standard ap thunks */
+
+RTS_THUNK_INFO(stg_ap_1_upd_info);
+RTS_THUNK_INFO(stg_ap_2_upd_info);
+RTS_THUNK_INFO(stg_ap_3_upd_info);
+RTS_THUNK_INFO(stg_ap_4_upd_info);
+RTS_THUNK_INFO(stg_ap_5_upd_info);
+RTS_THUNK_INFO(stg_ap_6_upd_info);
+RTS_THUNK_INFO(stg_ap_7_upd_info);
+
+RTS_ENTRY(stg_ap_1_upd_entry);
+RTS_ENTRY(stg_ap_2_upd_entry);
+RTS_ENTRY(stg_ap_3_upd_entry);
+RTS_ENTRY(stg_ap_4_upd_entry);
+RTS_ENTRY(stg_ap_5_upd_entry);
+RTS_ENTRY(stg_ap_6_upd_entry);
+RTS_ENTRY(stg_ap_7_upd_entry);
+
+/* standard application routines (see also rts/gen_apply.py, 
+ * and compiler/codeGen/CgStackery.lhs).
+ */
+RTS_RET_INFO(stg_ap_0_info);
+RTS_RET_INFO(stg_ap_v_info);
+RTS_RET_INFO(stg_ap_f_info);
+RTS_RET_INFO(stg_ap_d_info);
+RTS_RET_INFO(stg_ap_l_info);
+RTS_RET_INFO(stg_ap_n_info);
+RTS_RET_INFO(stg_ap_p_info);
+RTS_RET_INFO(stg_ap_pv_info);
+RTS_RET_INFO(stg_ap_pp_info);
+RTS_RET_INFO(stg_ap_ppv_info);
+RTS_RET_INFO(stg_ap_ppp_info);
+RTS_RET_INFO(stg_ap_pppv_info);
+RTS_RET_INFO(stg_ap_pppp_info);
+RTS_RET_INFO(stg_ap_ppppp_info);
+RTS_RET_INFO(stg_ap_pppppp_info);
+
+RTS_ENTRY(stg_ap_0_ret);
+RTS_ENTRY(stg_ap_v_ret);
+RTS_ENTRY(stg_ap_f_ret);
+RTS_ENTRY(stg_ap_d_ret);
+RTS_ENTRY(stg_ap_l_ret);
+RTS_ENTRY(stg_ap_n_ret);
+RTS_ENTRY(stg_ap_p_ret);
+RTS_ENTRY(stg_ap_pv_ret);
+RTS_ENTRY(stg_ap_pp_ret);
+RTS_ENTRY(stg_ap_ppv_ret);
+RTS_ENTRY(stg_ap_ppp_ret);
+RTS_ENTRY(stg_ap_pppv_ret);
+RTS_ENTRY(stg_ap_pppp_ret);
+RTS_ENTRY(stg_ap_ppppp_ret);
+RTS_ENTRY(stg_ap_pppppp_ret);
 
 /* standard GC & stack check entry points, all defined in HeapStackCheck.hc */
 
-ERI_(stg_enter_info);
-EF_(stg_enter_ret);
+RTS_RET_INFO(stg_enter_info);
+RTS_ENTRY(stg_enter_ret);
+
+RTS_RET_INFO(stg_gc_void_info);
+RTS_ENTRY(stg_gc_void_ret);
+
+RTS_FUN(__stg_gc_enter_1);
+
+RTS_FUN(stg_gc_noregs);
 
-ERI_(stg_gc_void_info);
+RTS_RET_INFO(stg_gc_unpt_r1_info);
+RTS_ENTRY(stg_gc_unpt_r1_ret);
+RTS_FUN(stg_gc_unpt_r1);
 
-EF_(__stg_gc_enter_1);
+RTS_RET_INFO(stg_gc_unbx_r1_info);
+RTS_ENTRY(stg_gc_unbx_r1_ret);
+RTS_FUN(stg_gc_unbx_r1);
 
-EF_(stg_gc_noregs);
+RTS_RET_INFO(stg_gc_f1_info);
+RTS_ENTRY(stg_gc_f1_ret);
+RTS_FUN(stg_gc_f1);
 
-ERI_(stg_gc_unpt_r1_info);
-EF_(stg_gc_unpt_r1);
+RTS_RET_INFO(stg_gc_d1_info);
+RTS_ENTRY(stg_gc_d1_ret);
+RTS_FUN(stg_gc_d1);
 
-ERI_(stg_gc_unbx_r1_info);
-EF_(stg_gc_unbx_r1);
+RTS_RET_INFO(stg_gc_l1_info);
+RTS_ENTRY(stg_gc_l1_ret);
+RTS_FUN(stg_gc_l1);
 
-ERI_(stg_gc_f1_info);
-EF_(stg_gc_f1);
+RTS_FUN(__stg_gc_fun);
+RTS_RET_INFO(stg_gc_fun_info);
+RTS_ENTRY(stg_gc_fun_ret);
 
-ERI_(stg_gc_d1_info);
-EF_(stg_gc_d1);
+RTS_RET_INFO(stg_gc_gen_info);
+RTS_ENTRY(stg_gc_gen_ret);
+RTS_FUN(stg_gc_gen);
 
-ERI_(stg_gc_l1_info);
-EF_(stg_gc_l1);
+RTS_ENTRY(stg_ut_1_0_unreg_ret);
+RTS_RET_INFO(stg_ut_1_0_unreg_info);
 
-EF_(__stg_gc_fun);
-ERI_(stg_gc_fun_info);
-EF_(stg_gc_fun_ret);
+RTS_FUN(stg_gc_gen_hp);
+RTS_FUN(stg_gc_ut);
+RTS_FUN(stg_gen_yield);
+RTS_FUN(stg_yield_noregs);
+RTS_FUN(stg_yield_to_interpreter);
+RTS_FUN(stg_gen_block);
+RTS_FUN(stg_block_noregs);
+RTS_FUN(stg_block_1);
+RTS_FUN(stg_block_takemvar);
+RTS_ENTRY(stg_block_takemvar_ret);
+RTS_FUN(stg_block_putmvar);
+RTS_ENTRY(stg_block_putmvar_ret);
+#ifdef mingw32_TARGET_OS
+RTS_FUN(stg_block_async);
+#endif
+
+/* Entry/exit points from StgStartup.cmm */
+
+RTS_RET_INFO(stg_stop_thread_info);
+RTS_ENTRY(stg_stop_thread_ret);
+
+RTS_FUN(stg_returnToStackTop);
+RTS_FUN(stg_enterStackTop);
+
+RTS_FUN(stg_init_finish);
+RTS_FUN(stg_init);
+
+/* -----------------------------------------------------------------------------
+   PrimOps
+   -------------------------------------------------------------------------- */
+
+RTS_FUN(plusIntegerzh_fast);
+RTS_FUN(minusIntegerzh_fast);
+RTS_FUN(timesIntegerzh_fast);
+RTS_FUN(gcdIntegerzh_fast);
+RTS_FUN(quotRemIntegerzh_fast);
+RTS_FUN(quotIntegerzh_fast);
+RTS_FUN(remIntegerzh_fast);
+RTS_FUN(divExactIntegerzh_fast);
+RTS_FUN(divModIntegerzh_fast);
+
+RTS_FUN(cmpIntegerIntzh_fast);
+RTS_FUN(cmpIntegerzh_fast);
+RTS_FUN(integer2Intzh_fast);
+RTS_FUN(integer2Wordzh_fast);
+RTS_FUN(gcdIntegerIntzh_fast);
+RTS_FUN(gcdIntzh_fast);
+
+RTS_FUN(int2Integerzh_fast);
+RTS_FUN(word2Integerzh_fast);
+
+RTS_FUN(decodeFloatzh_fast);
+RTS_FUN(decodeDoublezh_fast);
+
+RTS_FUN(andIntegerzh_fast);
+RTS_FUN(orIntegerzh_fast);
+RTS_FUN(xorIntegerzh_fast);
+RTS_FUN(complementIntegerzh_fast);
+
+#ifdef SUPPORT_LONG_LONGS
+
+RTS_FUN(int64ToIntegerzh_fast);
+RTS_FUN(word64ToIntegerzh_fast);
+
+#endif
 
-EF_(stg_gc_gen);
-ERI_(stg_gc_gen_info);
+RTS_FUN(unsafeThawArrayzh_fast);
+RTS_FUN(newByteArrayzh_fast);
+RTS_FUN(newPinnedByteArrayzh_fast);
+RTS_FUN(newArrayzh_fast);
 
-EF_(stg_ut_1_0_unreg_ret);
-ERI_(stg_ut_1_0_unreg_info);
+RTS_FUN(decodeFloatzh_fast);
+RTS_FUN(decodeDoublezh_fast);
 
-EF_(stg_gc_gen_hp);
-EF_(stg_gc_ut);
-EF_(stg_gen_yield);
-EF_(stg_yield_noregs);
-EF_(stg_yield_to_interpreter);
-EF_(stg_gen_block);
-EF_(stg_block_noregs);
-EF_(stg_block_1);
-EF_(stg_block_takemvar);
-EF_(stg_block_putmvar);
+RTS_FUN(newMutVarzh_fast);
+RTS_FUN(atomicModifyMutVarzh_fast);
+
+RTS_FUN(isEmptyMVarzh_fast);
+RTS_FUN(newMVarzh_fast);
+RTS_FUN(takeMVarzh_fast);
+RTS_FUN(putMVarzh_fast);
+RTS_FUN(tryTakeMVarzh_fast);
+RTS_FUN(tryPutMVarzh_fast);
+
+RTS_FUN(waitReadzh_fast);
+RTS_FUN(waitWritezh_fast);
+RTS_FUN(delayzh_fast);
 #ifdef mingw32_TARGET_OS
-EF_(stg_block_async);
+RTS_FUN(asyncReadzh_fast);
+RTS_FUN(asyncWritezh_fast);
+RTS_FUN(asyncDoProczh_fast);
 #endif
+
+RTS_FUN(catchzh_fast);
+RTS_FUN(raisezh_fast);
+RTS_FUN(raiseIOzh_fast);
+
+RTS_FUN(makeStableNamezh_fast);
+RTS_FUN(makeStablePtrzh_fast);
+RTS_FUN(deRefStablePtrzh_fast);
+
+RTS_FUN(forkzh_fast);
+RTS_FUN(yieldzh_fast);
+RTS_FUN(killThreadzh_fast);
+RTS_FUN(blockAsyncExceptionszh_fast);
+RTS_FUN(unblockAsyncExceptionszh_fast);
+RTS_FUN(myThreadIdzh_fast);
+RTS_FUN(labelThreadzh_fast);
+RTS_FUN(isCurrentThreadBoundzh_fast);
+
+RTS_FUN(mkWeakzh_fast);
+RTS_FUN(finalizzeWeakzh_fast);
+RTS_FUN(deRefWeakzh_fast);
+
+RTS_FUN(mkForeignObjzh_fast);
+
+RTS_FUN(newBCOzh_fast);
+RTS_FUN(mkApUpd0zh_fast);
+
+#endif /* STGMISCCLOSURES_H */
index 165475d..26ee622 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: StgProf.h,v 1.17 2003/11/12 17:27:04 sof Exp $
+ * $Id: StgProf.h,v 1.18 2004/08/13 13:09:37 simonmar Exp $
  *
  * (c) The GHC Team, 1998
  *
  * Data Structures 
  * ---------------------------------------------------------------------------*/  
 typedef struct _CostCentre {
-  int ccID;
+  StgInt ccID;
 
-  char *label;
-  char *module;
+  char * label;
+  char * module;
  
   /* used for accumulating costs at the end of the run... */
-  unsigned long time_ticks;
-  ullong        mem_alloc;
+  StgWord   time_ticks;
+  StgWord64 mem_alloc;
 
-  char is_caf;
+  StgInt    is_caf;
 
   struct _CostCentre *link;
 } CostCentre;
 
 
 typedef struct _CostCentreStack {
-  int ccsID;
+  StgInt ccsID;
 
   CostCentre *cc;
   struct _CostCentreStack *prevStack;
   struct _IndexTable *indexTable;
 
-  unsigned int selected;
-
-  ullong scc_count;
-
-  unsigned long time_ticks;
-
-  ullong mem_alloc;
-
-  unsigned long inherited_ticks;
-  ullong inherited_alloc;
+  StgWord    selected;
+  StgWord64  scc_count;
+  StgWord    time_ticks;
+  StgWord64  mem_alloc;
+  StgWord    inherited_ticks;
+  StgWord64  inherited_alloc;
 
   CostCentre *root;
 } CostCentreStack;
@@ -85,8 +81,30 @@ typedef struct _IndexTable {
    Pre-defined cost centres and cost centre stacks
    -------------------------------------------------------------------------- */
 
-extern CostCentreStack *CCCS;          /* current CCS */
+extern CostCentreStack * RTS_VAR(CCCS);                /* current CCS */
  
+#if IN_STG_CODE
+
+extern StgWord CC_MAIN[];      
+extern StgWord CCS_MAIN[];      /* Top CCS */
+
+extern StgWord CC_SYSTEM[];    
+extern StgWord CCS_SYSTEM[];    /* RTS costs */
+
+extern StgWord CC_GC[];
+extern StgWord CCS_GC[];        /* Garbage collector costs */
+
+extern StgWord CC_SUBSUMED[];  
+extern StgWord CCS_SUBSUMED[];   /* Costs are subsumed by caller */
+
+extern StgWord CC_OVERHEAD[];
+extern StgWord CCS_OVERHEAD[];   /* Profiling overhead */
+
+extern StgWord CC_DONT_CARE[];
+extern StgWord CCS_DONT_CARE[];  /* shouldn't ever get set */
+
+#else
+
 extern CostCentre      CC_MAIN[];      
 extern CostCentreStack CCS_MAIN[];      /* Top CCS */
 
@@ -105,19 +123,23 @@ extern CostCentreStack CCS_OVERHEAD[];   /* Profiling overhead */
 extern CostCentre      CC_DONT_CARE[];
 extern CostCentreStack CCS_DONT_CARE[];  /* shouldn't ever get set */
 
-extern unsigned int CC_ID;     /* global ids */
-extern unsigned int CCS_ID;
-extern unsigned int HP_ID;
+#endif // IN_STG_CODE
+
+extern unsigned int RTS_VAR(CC_ID);    /* global ids */
+extern unsigned int RTS_VAR(CCS_ID);
+extern unsigned int RTS_VAR(HP_ID);
+
+extern unsigned int RTS_VAR(era);
 
 /* -----------------------------------------------------------------------------
  * Functions 
  * ---------------------------------------------------------------------------*/
 
-CostCentreStack *EnterFunCCS ( CostCentreStack *cccs, CostCentreStack *ccsfn );
+void EnterFunCCS ( CostCentreStack *ccsfn );
 CostCentreStack *PushCostCentre ( CostCentreStack *, CostCentre * );
 CostCentreStack *AppendCCS ( CostCentreStack *ccs1, CostCentreStack *ccs2 );
 
-extern unsigned int entering_PAP;
+extern unsigned int RTS_VAR(entering_PAP);
 
 /* -----------------------------------------------------------------------------
  * Registering CCs
@@ -142,8 +164,8 @@ extern unsigned int entering_PAP;
 
  -------------------------------------------------------------------------- */
 
-extern CostCentre *CC_LIST;               /* registered CC list */
-extern CostCentreStack *CCS_LIST;         /* registered CCS list */
+extern CostCentre * RTS_VAR(CC_LIST);               /* registered CC list */
+extern CostCentreStack * RTS_VAR(CCS_LIST);         /* registered CCS list */
 
 #define REGISTER_CC(cc)                                        \
        do {                                            \
@@ -208,7 +230,7 @@ extern CostCentreStack *CCS_LIST;         /* registered CCS list */
 /* Restore the CCCS from a stack frame.
  * (addr should always be Sp->header.prof.ccs) 
  */
-#define RESTORE_CCCS(addr)   (CCCS = (CostCentreStack *)(addr))
+#define RESTORE_CCCS(addr)   (*CCCS = (CostCentreStack *)(addr))
 
 /* -----------------------------------------------------------------------------
  * Pushing a new cost centre (i.e. for scc annotations)
@@ -291,7 +313,7 @@ extern CostCentreStack *CCS_LIST;         /* registered CCS list */
 
 #define ENTER_CCS_T(ccs)                               \
         do {                                           \
-        CCCS = (CostCentreStack *)(ccs);               \
+        *CCCS = (CostCentreStack *)(ccs);              \
         CCCS_DETAIL_COUNT(CCCS->thunk_count);          \
         } while(0)      
  
@@ -305,12 +327,7 @@ extern CostCentreStack *CCS_LIST;         /* registered CCS list */
  *  (b) The CCS is CAF-ish.
  * -------------------------------------------------------------------------- */
 
-#define ENTER_CCS_F(stack)                                             \
-        do {                                                           \
-        CostCentreStack *ccs = (CostCentreStack *) (stack);            \
-        CCCS_DETAIL_COUNT(CCCS->function_count);                       \
-        CCCS = EnterFunCCS(CCCS,ccs);                                  \
-        } while(0)
+#define ENTER_CCS_F(stack) EnterFunCCS(stack)
  
 #define ENTER_CCS_FCL(closure)  ENTER_CCS_F(CCS_HDR(closure))
 
@@ -343,7 +360,7 @@ extern CostCentreStack *CCS_LIST;         /* registered CCS list */
 #define ENTER_CCS_PAP(stack)                   \
         do {                                   \
        ENTER_CCS_F(stack);                     \
-       entering_PAP = rtsTrue;                 \
+       *entering_PAP = rtsTrue;                \
        } while(0)
 
 #define ENTER_CCS_PAP_CL(closure)  \
diff --git a/ghc/includes/StgStorage.h b/ghc/includes/StgStorage.h
deleted file mode 100644 (file)
index 5c0ca12..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: StgStorage.h,v 1.12 2003/03/26 17:40:58 sof Exp $
- *
- * (c) The GHC Team, 1998-1999
- *
- * STG Storage Manager Interface
- *
- * ---------------------------------------------------------------------------*/
-
-#ifndef STGSTORAGE_H
-#define STGSTORAGE_H
-
-/* GENERATION GC NOTES
- *
- * We support an arbitrary number of generations, with an arbitrary number
- * of steps per generation.  Notes (in no particular order):
- *
- *       - all generations except the oldest should have two steps.  This gives
- *         objects a decent chance to age before being promoted, and in
- *         particular will ensure that we don't end up with too many
- *         thunks being updated in older generations.
- *
- *       - the oldest generation has one step.  There's no point in aging
- *         objects in the oldest generation.
- *
- *       - generation 0, step 0 (G0S0) is the allocation area.  It is given
- *         a fixed set of blocks during initialisation, and these blocks
- *         are never freed.
- *
- *       - during garbage collection, each step which is an evacuation
- *         destination (i.e. all steps except G0S0) is allocated a to-space.
- *         evacuated objects are allocated into the step's to-space until
- *         GC is finished, when the original step's contents may be freed
- *         and replaced by the to-space.
- *
- *       - the mutable-list is per-generation (not per-step).  G0 doesn't 
- *         have one (since every garbage collection collects at least G0).
- * 
- *       - block descriptors contain pointers to both the step and the
- *         generation that the block belongs to, for convenience.
- *
- *       - static objects are stored in per-generation lists.  See GC.c for
- *         details of how we collect CAFs in the generational scheme.
- *
- *       - large objects are per-step, and are promoted in the same way
- *         as small objects, except that we may allocate large objects into
- *         generation 1 initially.
- */
-
-typedef struct _step {
-  unsigned int         no;             /* step number */
-  bdescr *             blocks;         /* blocks in this step */
-  unsigned int         n_blocks;       /* number of blocks */
-  struct _step *       to;             /* destination step for live objects */
-  struct _generation * gen;            /* generation this step belongs to */
-  unsigned int         gen_no;          /* generation number (cached) */
-  bdescr *             large_objects;  /* large objects (doubly linked) */
-  unsigned int         n_large_blocks;  /* no. of blocks used by large objs */
-  int                  is_compacted;   /* compact this step? (old gen only) */
-
-  /* temporary use during GC: */
-  StgPtr       hp;                     /* next free locn in to-space */
-  StgPtr       hpLim;                  /* end of current to-space block */
-  bdescr *     hp_bd;                  /* bdescr of current to-space block */
-  bdescr *     to_blocks;              /* bdescr of first to-space block */
-  unsigned int n_to_blocks;            /* number of blocks in to-space */
-  bdescr *     scan_bd;                        /* block currently being scanned */
-  StgPtr       scan;                   /* scan pointer in current block */
-  bdescr *     new_large_objects;      /* large objects collected so far */
-  bdescr *     scavenged_large_objects; /* live large objs after GC (d-link) */
-  unsigned int n_scavenged_large_blocks;/* size of above */
-  bdescr *     bitmap;                 /* bitmap for compacting collection */
-} step;
-
-typedef struct _generation {
-  unsigned int   no;                   /* generation number */
-  step *         steps;                        /* steps */
-  unsigned int   n_steps;              /* number of steps */
-  unsigned int   max_blocks;           /* max blocks in step 0 */
-  StgMutClosure *mut_list;             /* mut objects in this gen (not G0)*/
-  StgMutClosure *mut_once_list;        /* objects that point to younger gens */
-
-  /* temporary use during GC: */
-  StgMutClosure * saved_mut_list;
-
-  /* stats information */
-  unsigned int collections;
-  unsigned int failed_promotions;
-} generation;
-
-/* -----------------------------------------------------------------------------
-   Allocation area for compiled code
-
-   OpenNursery(hp,hplim)        Opens the allocation area, and sets hp
-                               and hplim appropriately.
-
-   CloseNursery(hp)            Closes the allocation area.
-
-   -------------------------------------------------------------------------- */
-
-#define OpenNursery(hp,hplim)                          \
-  (hp    = CurrentNursery->free-1,                     \
-   hplim = CurrentNursery->start + CurrentNursery->blocks*BLOCK_SIZE_W - 1)
-  
-#define CloseNursery(hp)  (CurrentNursery->free = (P_)(hp)+1)
-
-/* -----------------------------------------------------------------------------
-   Prototype for an evacuate-like function
-   -------------------------------------------------------------------------- */
-
-typedef void (*evac_fn)(StgClosure **);
-
-/* -----------------------------------------------------------------------------
-   Trigger a GC from Haskell land.
-   -------------------------------------------------------------------------- */
-
-extern void performGC(void);
-extern void performMajorGC(void);
-extern void performGCWithRoots(void (*get_roots)(evac_fn));
-
-#endif /* STGSTORAGE_H */
index 22e2606..c39c0ce 100644 (file)
@@ -1,5 +1,5 @@
 /* ----------------------------------------------------------------------------
- * $Id: StgTicky.h,v 1.15 2003/07/28 15:59:09 simonmar Exp $
+ * $Id: StgTicky.h,v 1.16 2004/08/13 13:09:38 simonmar Exp $
  *
  * (c) The AQUA project, Glasgow University, 1994-1997
  * (c) The GHC Team, 1998-1999
 #ifndef TICKY_H
 #define TICKY_H
 
+/* -----------------------------------------------------------------------------
+   The StgEntCounter type - needed regardless of TICKY_TICKY
+   -------------------------------------------------------------------------- */
+
+typedef struct _StgEntCounter {
+    StgWord16  registeredp;    /* 0 == no, 1 == yes */
+    StgWord16  arity;          /* arity (static info) */
+    StgWord16  stk_args;       /* # of args off stack */
+                               /* (rest of args are in registers) */
+    char       *str;           /* name of the thing */
+    char       *arg_kinds;     /* info about the args types */
+    StgInt     entry_count;    /* Trips to fast entry code */
+    StgInt      allocs;         /* number of allocations by this fun */
+    struct _StgEntCounter *link;/* link to chain them all together */
+} StgEntCounter;
+
+
 #ifdef TICKY_TICKY
 
 /* -----------------------------------------------------------------------------
@@ -77,6 +94,8 @@
        ALLOC_BH_gds += (g);    ALLOC_BH_slp += (s);    \
        TICK_ALLOC_HISTO(BH,_HS,g,s)
 
+// admin size doesn't take into account the FUN, that is accounted for
+// in the "goods".
 #define TICK_ALLOC_PAP(g,s)                                    \
        ALLOC_PAP_ctr++;      ALLOC_PAP_adm += sizeofW(StgPAP)-1; \
        ALLOC_PAP_gds += (g); ALLOC_PAP_slp += (s);     \
 #define TICK_ENT_STATIC_THK()  ENT_STATIC_THK_ctr++ 
 #define TICK_ENT_DYN_THK()     ENT_DYN_THK_ctr++
 
-typedef struct _StgEntCounter {
-    unsigned   registeredp:16, /* 0 == no, 1 == yes */
-               arity:16,       /* arity (static info) */
-               stk_args:16;    /* # of args off stack */
-                               /* (rest of args are in registers) */
-    char       *str;           /* name of the thing */
-    char       *arg_kinds;     /* info about the args types */
-    I_         entry_count;      /* Trips to fast entry code */
-    I_          allocs;         /* number of allocations by this fun */
-    struct _StgEntCounter *link;/* link to chain them all together */
-} StgEntCounter;
-
 #define TICK_CTR(f_ct, str, arity, args, arg_kinds)    \
    static StgEntCounter f_ct                   \
        = { 0, arity, args,                     \
@@ -196,16 +203,65 @@ extern StgEntCounter *ticky_entry_ctrs;
    SLOW_CALL_hst[((__idx > 8) ? 8 : __idx)] += 1;      \
  }
 
-// A slow call with n arguments
-#define TICK_SLOW_CALL(n)       SLOW_CALL_ctr++; \
-                                TICK_SLOW_HISTO(n)
-
-// A slow call to a FUN found insufficient arguments, and built a PAP
-#define TICK_SLOW_CALL_BUILT_PAP() SLOW_CALL_BUILT_PAP_ctr++
+#define UNDO_TICK_SLOW_HISTO(n)                                \
+ { unsigned __idx;                                     \
+   __idx = (n);                                                \
+   SLOW_CALL_hst[((__idx > 8) ? 8 : __idx)] -= 1;      \
+ }
 
-// A slow call to a PAP found insufficient arguments, and build a new PAP
-#define TICK_SLOW_CALL_NEW_PAP()   SLOW_CALL_NEW_PAP_ctr++
+// A slow call with n arguments.  In the unevald case, this call has
+// already been counted once, so don't count it again.
+#define TICK_SLOW_CALL(n) \
+  SLOW_CALL_ctr++; \
+  TICK_SLOW_HISTO(n)
+
+// This slow call was found to be to an unevaluated function; undo the
+// ticks we did in TICK_SLOW_CALL.
+#define TICK_SLOW_CALL_UNEVALD(n) \
+  SLOW_CALL_UNEVALD_ctr++; \
+  SLOW_CALL_ctr--; \
+  UNDO_TICK_SLOW_HISTO(n)
+
+#define TICK_MULTI_CHUNK_SLOW_CALL(pattern, chunks) \
+  fprintf(stderr, "Multi-chunk slow call: %s\n", pattern); \
+  MULTI_CHUNK_SLOW_CALL_ctr++; \
+  MULTI_CHUNK_SLOW_CALL_CHUNKS_ctr += chunks;
+
+// A completely unknown tail-call
+#define TICK_UNKNOWN_CALL()               UNKNOWN_CALL_ctr++
+
+// slow call patterns (includes "extra" args to known calls,
+// so the total of these will be greater than UNKNOWN_CALL_ctr).
+#define TICK_SLOW_CALL_v()             SLOW_CALL_v_ctr++
+#define TICK_SLOW_CALL_f()             SLOW_CALL_f_ctr++
+#define TICK_SLOW_CALL_d()             SLOW_CALL_d_ctr++
+#define TICK_SLOW_CALL_l()             SLOW_CALL_l_ctr++
+#define TICK_SLOW_CALL_n()             SLOW_CALL_n_ctr++
+#define TICK_SLOW_CALL_p()             SLOW_CALL_p_ctr++
+#define TICK_SLOW_CALL_pv()            SLOW_CALL_pv_ctr++
+#define TICK_SLOW_CALL_pp()            SLOW_CALL_pp_ctr++
+#define TICK_SLOW_CALL_ppv()           SLOW_CALL_ppv_ctr++
+#define TICK_SLOW_CALL_ppp()           SLOW_CALL_ppp_ctr++
+#define TICK_SLOW_CALL_pppv()          SLOW_CALL_pppv_ctr++
+#define TICK_SLOW_CALL_pppp()          SLOW_CALL_pppp_ctr++
+#define TICK_SLOW_CALL_ppppp()         SLOW_CALL_ppppp_ctr++
+#define TICK_SLOW_CALL_pppppp()        SLOW_CALL_pppppp_ctr++
+#define TICK_SLOW_CALL_OTHER(pattern) \
+     fprintf(stderr,"slow call: %s\n", pattern); \
+     SLOW_CALL_OTHER_ctr++
+
+#define TICK_KNOWN_CALL()               KNOWN_CALL_ctr++
+#define TICK_KNOWN_CALL_TOO_FEW_ARGS()  KNOWN_CALL_TOO_FEW_ARGS_ctr++
+#define TICK_KNOWN_CALL_EXTRA_ARGS()    KNOWN_CALL_EXTRA_ARGS_ctr++
 
+// A slow call to a FUN found insufficient arguments, and built a PAP
+#define TICK_SLOW_CALL_FUN_TOO_FEW()       SLOW_CALL_FUN_TOO_FEW_ctr++
+#define TICK_SLOW_CALL_FUN_CORRECT()       SLOW_CALL_FUN_CORRECT_ctr++
+#define TICK_SLOW_CALL_FUN_TOO_MANY()      SLOW_CALL_FUN_TOO_MANY_ctr++
+#define TICK_SLOW_CALL_PAP_TOO_FEW()       SLOW_CALL_PAP_TOO_FEW_ctr++
+#define TICK_SLOW_CALL_PAP_CORRECT()       SLOW_CALL_PAP_CORRECT_ctr++
+#define TICK_SLOW_CALL_PAP_TOO_MANY()      SLOW_CALL_PAP_TOO_MANY_ctr++
+  
 /* -----------------------------------------------------------------------------
    Returns
    -------------------------------------------------------------------------- */
@@ -475,9 +531,38 @@ EXTERN unsigned long ENT_AP_ctr INIT(0);
 EXTERN unsigned long ENT_AP_STACK_ctr INIT(0);
 EXTERN unsigned long ENT_BH_ctr INIT(0);
 
+EXTERN unsigned long UNKNOWN_CALL_ctr INIT(0);
+
+EXTERN unsigned long SLOW_CALL_v_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_f_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_d_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_l_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_n_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_p_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_pv_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_pp_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_ppv_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_ppp_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_pppv_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_pppp_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_ppppp_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_pppppp_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_OTHER_ctr INIT(0);
+
+EXTERN unsigned long ticky_slow_call_unevald INIT(0);
 EXTERN unsigned long SLOW_CALL_ctr INIT(0);
-EXTERN unsigned long SLOW_CALL_BUILT_PAP_ctr INIT(0);
-EXTERN unsigned long SLOW_CALL_NEW_PAP_ctr INIT(0);
+EXTERN unsigned long MULTI_CHUNK_SLOW_CALL_ctr INIT(0);
+EXTERN unsigned long MULTI_CHUNK_SLOW_CALL_CHUNKS_ctr INIT(0);
+EXTERN unsigned long KNOWN_CALL_ctr INIT(0);
+EXTERN unsigned long KNOWN_CALL_TOO_FEW_ARGS_ctr INIT(0);
+EXTERN unsigned long KNOWN_CALL_EXTRA_ARGS_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_FUN_TOO_FEW_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_FUN_CORRECT_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_FUN_TOO_MANY_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_PAP_TOO_FEW_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_PAP_CORRECT_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_PAP_TOO_MANY_ctr INIT(0);
+EXTERN unsigned long SLOW_CALL_UNEVALD_ctr INIT(0);
 
 EXTERN unsigned long SLOW_CALL_hst[8]
 #ifdef TICKY_C
@@ -608,8 +693,34 @@ EXTERN unsigned long GC_WORDS_COPIED_ctr INIT(0);
 #define TICK_ENT_BH()
 
 #define TICK_SLOW_CALL(n)
-#define TICK_SLOW_CALL_BUILT_PAP()
-#define TICK_SLOW_CALL_NEW_PAP()
+#define TICK_SLOW_CALL_UNEVALD(n)
+#define TICK_SLOW_CALL_FUN_TOO_FEW()
+#define TICK_SLOW_CALL_FUN_CORRECT()
+#define TICK_SLOW_CALL_FUN_TOO_MANY()
+#define TICK_SLOW_CALL_PAP_TOO_FEW()
+#define TICK_SLOW_CALL_PAP_CORRECT()
+#define TICK_SLOW_CALL_PAP_TOO_MANY()
+
+#define TICK_SLOW_CALL_v()
+#define TICK_SLOW_CALL_f()
+#define TICK_SLOW_CALL_d()
+#define TICK_SLOW_CALL_l()
+#define TICK_SLOW_CALL_n()
+#define TICK_SLOW_CALL_p()
+#define TICK_SLOW_CALL_pv()
+#define TICK_SLOW_CALL_pp()
+#define TICK_SLOW_CALL_ppv()
+#define TICK_SLOW_CALL_ppp()
+#define TICK_SLOW_CALL_pppv()
+#define TICK_SLOW_CALL_pppp()
+#define TICK_SLOW_CALL_ppppp()
+#define TICK_SLOW_CALL_pppppp()
+#define TICK_SLOW_CALL_OTHER(pattern)
+
+#define TICK_KNOWN_CALL()
+#define TICK_KNOWN_CALL_TOO_FEW_ARGS()
+#define TICK_KNOWN_CALL_EXTRA_ARGS()
+#define TICK_UNKNOWN_CALL()
 
 #define TICK_RET_NEW(n)
 #define TICK_RET_OLD(n)
index 2492046..ae9eec5 100644 (file)
@@ -1,10 +1,9 @@
 /* -----------------------------------------------------------------------------
- * $Id: StgTypes.h,v 1.20 2003/11/12 17:27:05 sof Exp $
  *
- * (c) The GHC Team, 1998-2000
+ * (c) The GHC Team, 1998-2004
  *
  * Various C datatypes used in the run-time system.  This is the
- * lowest-level include file, after config.h and Derived.h.
+ * lowest-level include file, after ghcconfig.h and RtsConfig.h.
  *
  * This module should define types *only*, all beginning with "Stg".
  *
@@ -27,7 +26,7 @@
 
  * WARNING: Keep this file, MachDeps.h, and HsFFI.h in synch!
  *
- * NOTE: assumes #include "config.h"
+ * NOTE: assumes #include "ghcconfig.h"
  * 
  * Works with or without _POSIX_SOURCE.
  *
@@ -36,8 +35,6 @@
 #ifndef STGTYPES_H
 #define STGTYPES_H
 
-#include "Derived.h"
-
 /*
  * First, platform-dependent definitions of size-specific integers.
  * Assume for now that the int type is 32 bits.
@@ -150,18 +147,4 @@ typedef void*                 StgStablePtr;
 typedef void  *(*(*StgFunPtr)(void))(void);
 typedef StgFunPtr StgFun(void);
 
-typedef union {
-    StgWord        w;
-    StgAddr        a;
-    StgChar        c;
-    StgInt8        i8;
-    StgFloat       f;
-    StgInt         i;
-    StgPtr         p;
-    StgClosurePtr  cl;
-    StgStackOffset offset;     /* unused? */
-    StgByteArray   b;
-    StgTSOPtr      t;
-} StgUnion;
-
 #endif /* STGTYPES_H */
similarity index 54%
rename from ghc/rts/Storage.h
rename to ghc/includes/Storage.h
index fb84740..861cbeb 100644 (file)
@@ -1,7 +1,6 @@
 /* -----------------------------------------------------------------------------
- * $Id: Storage.h,v 1.53 2003/11/12 17:49:11 sof Exp $
  *
- * (c) The GHC Team, 1998-2002
+ * (c) The GHC Team, 1998-2004
  *
  * External Storage Manger Interface
  *
 #ifndef STORAGE_H
 #define STORAGE_H
 
-#include "Block.h"
-#include "MBlock.h"
-#include "BlockAlloc.h"
-#include "StoragePriv.h"
-#ifdef PROFILING
-#include "LdvProfile.h"
-#endif
+#include <stddef.h>
+
+/* -----------------------------------------------------------------------------
+ * Generational GC
+ *
+ * We support an arbitrary number of generations, with an arbitrary number
+ * of steps per generation.  Notes (in no particular order):
+ *
+ *       - all generations except the oldest should have two steps.  This gives
+ *         objects a decent chance to age before being promoted, and in
+ *         particular will ensure that we don't end up with too many
+ *         thunks being updated in older generations.
+ *
+ *       - the oldest generation has one step.  There's no point in aging
+ *         objects in the oldest generation.
+ *
+ *       - generation 0, step 0 (G0S0) is the allocation area.  It is given
+ *         a fixed set of blocks during initialisation, and these blocks
+ *         are never freed.
+ *
+ *       - during garbage collection, each step which is an evacuation
+ *         destination (i.e. all steps except G0S0) is allocated a to-space.
+ *         evacuated objects are allocated into the step's to-space until
+ *         GC is finished, when the original step's contents may be freed
+ *         and replaced by the to-space.
+ *
+ *       - the mutable-list is per-generation (not per-step).  G0 doesn't 
+ *         have one (since every garbage collection collects at least G0).
+ * 
+ *       - block descriptors contain pointers to both the step and the
+ *         generation that the block belongs to, for convenience.
+ *
+ *       - static objects are stored in per-generation lists.  See GC.c for
+ *         details of how we collect CAFs in the generational scheme.
+ *
+ *       - large objects are per-step, and are promoted in the same way
+ *         as small objects, except that we may allocate large objects into
+ *         generation 1 initially.
+ *
+ * ------------------------------------------------------------------------- */
+
+typedef struct _step {
+  unsigned int         no;             /* step number */
+  bdescr *             blocks;         /* blocks in this step */
+  unsigned int         n_blocks;       /* number of blocks */
+  struct _step *       to;             /* destination step for live objects */
+  struct _generation * gen;            /* generation this step belongs to */
+  unsigned int         gen_no;          /* generation number (cached) */
+  bdescr *             large_objects;  /* large objects (doubly linked) */
+  unsigned int         n_large_blocks;  /* no. of blocks used by large objs */
+  int                  is_compacted;   /* compact this step? (old gen only) */
+
+  /* temporary use during GC: */
+  StgPtr       hp;                     /* next free locn in to-space */
+  StgPtr       hpLim;                  /* end of current to-space block */
+  bdescr *     hp_bd;                  /* bdescr of current to-space block */
+  bdescr *     to_blocks;              /* bdescr of first to-space block */
+  unsigned int n_to_blocks;            /* number of blocks in to-space */
+  bdescr *     scan_bd;                        /* block currently being scanned */
+  StgPtr       scan;                   /* scan pointer in current block */
+  bdescr *     new_large_objects;      /* large objects collected so far */
+  bdescr *     scavenged_large_objects; /* live large objs after GC (d-link) */
+  unsigned int n_scavenged_large_blocks;/* size of above */
+  bdescr *     bitmap;                 /* bitmap for compacting collection */
+} step;
+
+typedef struct _generation {
+  unsigned int   no;                   /* generation number */
+  step *         steps;                        /* steps */
+  unsigned int   n_steps;              /* number of steps */
+  unsigned int   max_blocks;           /* max blocks in step 0 */
+  StgMutClosure *mut_list;             /* mut objects in this gen (not G0)*/
+  StgMutClosure *mut_once_list;        /* objects that point to younger gens */
+
+  /* temporary use during GC: */
+  StgMutClosure * saved_mut_list;
+
+  /* stats information */
+  unsigned int collections;
+  unsigned int failed_promotions;
+} generation;
+
+extern generation * RTS_VAR(generations);
+
+extern generation * RTS_VAR(g0);
+extern step * RTS_VAR(g0s0);
+extern generation * RTS_VAR(oldest_gen);
 
 /* -----------------------------------------------------------------------------
    Initialisation / De-initialisation
@@ -63,6 +142,16 @@ extern StgPtr  allocate        ( nat n );
 extern StgPtr  allocatePinned  ( nat n );
 extern lnat    allocated_bytes ( void );
 
+extern bdescr * RTS_VAR(small_alloc_list);
+extern bdescr * RTS_VAR(large_alloc_list);
+extern bdescr * RTS_VAR(pinned_object_block);
+
+extern StgPtr RTS_VAR(alloc_Hp);
+extern StgPtr RTS_VAR(alloc_HpLim);
+
+extern nat RTS_VAR(alloc_blocks);
+extern nat RTS_VAR(alloc_blocks_lim);
+
 INLINE_HEADER rtsBool
 doYouWantToGC( void )
 {
@@ -70,21 +159,6 @@ doYouWantToGC( void )
 }
 
 /* -----------------------------------------------------------------------------
-   ExtendNursery(hp,hplim)      When hplim is reached, try to grab
-                               some more allocation space.  Returns
-                               False if the allocation space is
-                               exhausted, and the application should
-                               call GarbageCollect().
-  -------------------------------------------------------------------------- */
-
-#define ExtendNursery(hp,hplim)                        \
-  (CloseNursery(hp),                            \
-   CurrentNursery->link == NULL ? rtsFalse :   \
-   (CurrentNursery = CurrentNursery->link,     \
-    OpenNursery(hp,hplim),                     \
-    rtsTrue))
-
-/* -----------------------------------------------------------------------------
    Performing Garbage Collection
 
    GarbageCollect(get_roots)    Performs a garbage collection.  
@@ -142,8 +216,8 @@ recordMutable(StgMutClosure *p)
 
   bd = Bdescr((P_)p);
   if (bd->gen_no > 0) {
-    p->mut_link = generations[bd->gen_no].mut_list;
-    generations[bd->gen_no].mut_list = p;
+    p->mut_link = RTS_DEREF(generations)[bd->gen_no].mut_list;
+    RTS_DEREF(generations)[bd->gen_no].mut_list = p;
   }
 }
 
@@ -154,180 +228,10 @@ recordOldToNewPtrs(StgMutClosure *p)
   
   bd = Bdescr((P_)p);
   if (bd->gen_no > 0) {
-    p->mut_link = generations[bd->gen_no].mut_once_list;
-    generations[bd->gen_no].mut_once_list = p;
-  }
-}
-
-// @LDV profiling
-// We zero out the slop when PROFILING is on.
-// #ifndef DEBUG
-#if !defined(DEBUG) && !defined(PROFILING)
-#define updateWithIndirection(info, ind_info, p1, p2, and_then)                \
-  {                                                                    \
-    bdescr *bd;                                                                \
-                                                                       \
-    bd = Bdescr((P_)p1);                                               \
-    if (bd->gen_no == 0) {                                             \
-      ((StgInd *)p1)->indirectee = p2;                                 \
-      SET_INFO(p1,ind_info);                                           \
-      TICK_UPD_NEW_IND();                                              \
-      and_then;                                                                \
-    } else {                                                           \
-      ((StgIndOldGen *)p1)->indirectee = p2;                           \
-      if (info != &stg_BLACKHOLE_BQ_info) {                            \
-        ACQUIRE_SM_LOCK;                                               \
-        ((StgIndOldGen *)p1)->mut_link = generations[bd->gen_no].mut_once_list;        \
-        generations[bd->gen_no].mut_once_list = (StgMutClosure *)p1;                   \
-        RELEASE_SM_LOCK;                                               \
-      }                                                                        \
-      SET_INFO(p1,&stg_IND_OLDGEN_info);                               \
-      TICK_UPD_OLD_IND();                                              \
-      and_then;                                                                \
-    }                                                                  \
-  }
-#elif defined(PROFILING)
-// @LDV profiling
-// We call LDV_recordDead_FILL_SLOP_DYNAMIC(p1) regardless of the generation in 
-// which p1 resides.
-//
-// Note: 
-//   After all, we do *NOT* need to call LDV_recordCreate() for both IND and 
-//   IND_OLDGEN closures because they are inherently used. But, it corrupts
-//   the invariants that every closure keeps its creation time in the profiling
-//   field. So, we call LDV_recordCreate().
-
-#define updateWithIndirection(info, ind_info, p1, p2, and_then)                \
-  {                                                                    \
-    bdescr *bd;                                                                \
-                                                                       \
-    LDV_recordDead_FILL_SLOP_DYNAMIC((p1));                             \
-    bd = Bdescr((P_)p1);                                               \
-    if (bd->gen_no == 0) {                                             \
-      ((StgInd *)p1)->indirectee = p2;                                 \
-      SET_INFO(p1,ind_info);                                           \
-      LDV_recordCreate((p1));                                           \
-      TICK_UPD_NEW_IND();                                              \
-      and_then;                                                                \
-    } else {                                                           \
-      ((StgIndOldGen *)p1)->indirectee = p2;                           \
-      if (info != &stg_BLACKHOLE_BQ_info) {                            \
-        ACQUIRE_SM_LOCK;                                               \
-        ((StgIndOldGen *)p1)->mut_link = generations[bd->gen_no].mut_once_list;        \
-        generations[bd->gen_no].mut_once_list = (StgMutClosure *)p1;    \
-        RELEASE_SM_LOCK;                                               \
-      }                                                                        \
-      SET_INFO(p1,&stg_IND_OLDGEN_info);                               \
-      LDV_recordCreate((p1));                                           \
-      and_then;                                                                \
-    }                                                                  \
-  }
-
-#else
-
-/* In the DEBUG case, we also zero out the slop of the old closure,
- * so that the sanity checker can tell where the next closure is.
- *
- * Two important invariants: we should never try to update a closure
- * to point to itself, and the closure being updated should not
- * already have been updated (the mutable list will get messed up
- * otherwise).
- */
-#define updateWithIndirection(info, ind_info, p1, p2, and_then)                \
-  {                                                                    \
-    bdescr *bd;                                                                \
-                                                                       \
-    ASSERT( p1 != p2 && !closure_IND(p1) );                            \
-    bd = Bdescr((P_)p1);                                               \
-    if (bd->gen_no == 0) {                                             \
-      ((StgInd *)p1)->indirectee = p2;                                 \
-      SET_INFO(p1,ind_info);                                           \
-      TICK_UPD_NEW_IND();                                              \
-      and_then;                                                                \
-    } else {                                                           \
-      if (info != &stg_BLACKHOLE_BQ_info) {                            \
-       {                                                               \
-          StgInfoTable *inf = get_itbl(p1);                            \
-         nat np = inf->layout.payload.ptrs,                            \
-             nw = inf->layout.payload.nptrs, i;                        \
-          if (inf->type != THUNK_SELECTOR) {                           \
-             for (i = 0; i < np + nw; i++) {                           \
-               ((StgClosure *)p1)->payload[i] = 0;                     \
-             }                                                         \
-          }                                                            \
-        }                                                              \
-        ACQUIRE_SM_LOCK;                                               \
-        ((StgIndOldGen *)p1)->mut_link = generations[bd->gen_no].mut_once_list;        \
-        generations[bd->gen_no].mut_once_list = (StgMutClosure *)p1;                   \
-        RELEASE_SM_LOCK;                                               \
-      }                                                                        \
-      ((StgIndOldGen *)p1)->indirectee = p2;                           \
-      SET_INFO(p1,&stg_IND_OLDGEN_info);                               \
-      TICK_UPD_OLD_IND();                                              \
-      and_then;                                                                \
-    }                                                                  \
-  }
-#endif
-
-/* Static objects all live in the oldest generation
- */
-#define updateWithStaticIndirection(info, p1, p2)                      \
-  {                                                                    \
-    ASSERT( p1 != p2 && !closure_IND(p1) );                            \
-    ASSERT( ((StgMutClosure*)p1)->mut_link == NULL );                  \
-                                                                       \
-    ACQUIRE_SM_LOCK;                                                   \
-    ((StgMutClosure *)p1)->mut_link = oldest_gen->mut_once_list;       \
-    oldest_gen->mut_once_list = (StgMutClosure *)p1;                   \
-    RELEASE_SM_LOCK;                                                   \
-                                                                       \
-    ((StgInd *)p1)->indirectee = p2;                                   \
-    SET_INFO((StgInd *)p1, &stg_IND_STATIC_info);                      \
-    TICK_UPD_STATIC_IND();                                             \
-  }
-
-#if defined(TICKY_TICKY) || defined(PROFILING)
-INLINE_HEADER void
-updateWithPermIndirection(const StgInfoTable *info, StgClosure *p1, StgClosure *p2) 
-{
-  bdescr *bd;
-
-  ASSERT( p1 != p2 && !closure_IND(p1) );
-
-#ifdef PROFILING
-  // @LDV profiling
-  // Destroy the old closure.
-  // Nb: LDV_* stuff cannot mix with ticky-ticky
-  LDV_recordDead_FILL_SLOP_DYNAMIC(p1);
-#endif
-  bd = Bdescr((P_)p1);
-  if (bd->gen_no == 0) {
-    ((StgInd *)p1)->indirectee = p2;
-    SET_INFO(p1,&stg_IND_PERM_info);
-#ifdef PROFILING
-    // @LDV profiling
-    // We have just created a new closure.
-    LDV_recordCreate(p1);
-#endif
-    TICK_UPD_NEW_PERM_IND(p1);
-  } else {
-    ((StgIndOldGen *)p1)->indirectee = p2;
-    if (info != &stg_BLACKHOLE_BQ_info) {
-      ACQUIRE_SM_LOCK;
-      ((StgIndOldGen *)p1)->mut_link = generations[bd->gen_no].mut_once_list;
-      generations[bd->gen_no].mut_once_list = (StgMutClosure *)p1;
-      RELEASE_SM_LOCK;
-    }
-    SET_INFO(p1,&stg_IND_OLDGEN_PERM_info);
-#ifdef PROFILING
-    // @LDV profiling
-    // We have just created a new closure.
-    LDV_recordCreate(p1);
-#endif
-    TICK_UPD_OLD_PERM_IND();
+    p->mut_link = RTS_DEREF(generations)[bd->gen_no].mut_once_list;
+    RTS_DEREF(generations)[bd->gen_no].mut_once_list = p;
   }
 }
-#endif
 
 /* -----------------------------------------------------------------------------
    The CAF table - used to let us revert CAFs in GHCi
@@ -421,7 +325,7 @@ INLINE_HEADER StgWord stack_frame_sizeW( StgClosure *frame )
        StgRetDyn *dyn = (StgRetDyn *)frame;
        return  sizeofW(StgRetDyn) + RET_DYN_BITMAP_SIZE + 
            RET_DYN_NONPTR_REGS_SIZE +
-           GET_PTRS(dyn->liveness) + GET_NONPTRS(dyn->liveness);
+           RET_DYN_PTRS(dyn->liveness) + RET_DYN_NONPTRS(dyn->liveness);
     }
            
     case RET_FUN:
@@ -440,12 +344,68 @@ INLINE_HEADER StgWord stack_frame_sizeW( StgClosure *frame )
 }
 
 /* -----------------------------------------------------------------------------
-   Debugging bits
+   Nursery manipulation
+   -------------------------------------------------------------------------- */
+
+extern void     allocNurseries ( void );
+extern void     resetNurseries ( void );
+extern bdescr * allocNursery   ( bdescr *last_bd, nat blocks );
+extern void     resizeNursery  ( nat blocks );
+extern void     tidyAllocateLists ( void );
+
+/* -----------------------------------------------------------------------------
+   MUTABLE LISTS
+   A mutable list is ended with END_MUT_LIST, so that we can use NULL
+   as an indication that an object is not on a mutable list.
+   ------------------------------------------------------------------------- */
+
+#define END_MUT_LIST ((StgMutClosure *)(void *)&stg_END_MUT_LIST_closure)
+
+/* -----------------------------------------------------------------------------
+   Functions from GC.c 
+   -------------------------------------------------------------------------- */
+
+extern void         threadPaused ( StgTSO * );
+extern StgClosure * isAlive      ( StgClosure *p );
+extern void         markCAFs     ( evac_fn evac );
+
+/* -----------------------------------------------------------------------------
+   Stats 'n' DEBUG stuff
    -------------------------------------------------------------------------- */
 
+extern lnat RTS_VAR(total_allocated);
+
+extern lnat calcAllocated  ( void );
+extern lnat calcLive       ( void );
+extern lnat calcNeeded     ( void );
+
+#if defined(DEBUG)
+extern void memInventory(void);
+extern void checkSanity(void);
+extern nat  countBlocks(bdescr *);
+#endif
+
 #if defined(DEBUG)
 void printMutOnceList(generation *gen);
 void printMutableList(generation *gen);
 #endif
 
+/* ----------------------------------------------------------------------------
+   Storage manager internal APIs and globals
+   ------------------------------------------------------------------------- */
+
+#define END_OF_STATIC_LIST stgCast(StgClosure*,1)
+
+extern void newDynCAF(StgClosure *);
+
+extern void move_TSO(StgTSO *src, StgTSO *dest);
+extern StgTSO *relocate_stack(StgTSO *dest, ptrdiff_t diff);
+
+extern StgClosure * RTS_VAR(static_objects);
+extern StgClosure * RTS_VAR(scavenged_static_objects);
+extern StgWeak    * RTS_VAR(old_weak_ptr_list);
+extern StgWeak    * RTS_VAR(weak_ptr_list);
+extern StgClosure * RTS_VAR(caf_list);
+extern StgTSO     * RTS_VAR(resurrected_threads);
+
 #endif // STORAGE_H
index 22f3e53..87ea876 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: TSO.h,v 1.34 2004/03/01 14:18:35 simonmar Exp $
+ * $Id: TSO.h,v 1.35 2004/08/13 13:09:40 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -36,79 +36,64 @@ typedef struct {
 } StgTSOStatBuf;
 #endif
 
-#if defined(PROFILING)
+/*
+ * PROFILING info in a TSO
+ */
 typedef struct {
   CostCentreStack *CCCS;       /* thread's current CCS */
 } StgTSOProfInfo;
-#else /* !PROFILING */
-# if defined(SUPPORTS_EMPTY_STRUCTS)
-typedef struct {
-    /* empty */
-} StgTSOProfInfo;
-# endif
-#endif /* PROFILING */
 
-#if defined(PAR)
+/*
+ * PAR info in a TSO
+ */
+#ifdef PAR
 typedef StgTSOStatBuf StgTSOParInfo;
-#else /* !PAR */
-# if defined(SUPPORTS_EMPTY_STRUCTS)
+#else
+#ifdef SUPPORTS_EMPTY_STRUCTS
 typedef struct {
-    /* empty */
+       /* empty */
 } StgTSOParInfo;
-# endif
-#endif /* PAR */
+#endif
+#endif
 
-#if defined(DIST)
+/*
+ * DIST info in a TSO
+ */
+#ifdef DIST
 typedef struct {
   StgThreadPriority  priority;   
   StgInt             revalTid;   /* ToDo: merge both into 1 word */
   StgInt             revalSlot;
 } StgTSODistInfo;
-#else /* !DIST */
-# if defined(SUPPORTS_EMPTY_STRUCTS)
+#else
+#ifdef SUPPORTS_EMPTY_STRUCTS
 typedef struct {
-    /* empty */
+       /* empty */
 } StgTSODistInfo;
-# endif
-#endif /* DIST */
+#endif
+#endif
 
-#if defined(GRAN)
+/*
+ * GRAN info in a TSO
+ */
+#ifdef GRAN
 typedef StgTSOStatBuf StgTSOGranInfo;
-#else /* !GRAN */
-# if defined(SUPPORTS_EMPTY_STRUCTS)
+#else
+#ifdef SUPPORTS_EMPTY_STRUCTS
 typedef struct {
-    /* empty */
+       /* empty */
 } StgTSOGranInfo;
-# endif
-#endif /* GRAN */
-
+#endif
+#endif
 
-#if defined(TICKY)
-typedef struct {
-} StgTSOTickyInfo;
-#else /* !TICKY_TICKY */
-# if defined(SUPPORTS_EMPTY_STRUCTS)
+/*
+ * TICKY_TICKY info in a TSO
+ */
+#ifdef SUPPORTS_EMPTY_STRUCTS
 typedef struct {
     /* empty */
 } StgTSOTickyInfo;
-# endif
-#endif /* TICKY_TICKY */
-
-typedef enum {
-    tso_state_runnable,
-    tso_state_stopped
-} StgTSOState;
-
-/*
- * The what_next field of a TSO indicates how the thread is to be run. 
- */
-typedef enum {
-  ThreadRunGHC,                        /* return to address on top of stack */
-  ThreadInterpret,             /* interpret this thread */
-  ThreadKilled,                        /* thread has died, don't run it */
-  ThreadRelocated,             /* thread has moved, link points to new locn */
-  ThreadComplete               /* thread has finished */
-} StgTSOWhatNext;
+#endif
 
 /*
  * Thread IDs are 32 bits.
@@ -116,17 +101,11 @@ typedef enum {
 typedef StgWord32 StgThreadID;
 
 /*
- * This type is returned to the scheduler by a thread that has
- * stopped for one reason or another.
+ * Type returned after running a thread.  Values of this type
+ * include HeapOverflow, StackOverflow etc.  See Constants.h for the
+ * full list.
  */
-
-typedef enum {
-  HeapOverflow,                        /* might also be StackOverflow */
-  StackOverflow,
-  ThreadYielding,
-  ThreadBlocked,
-  ThreadFinished
-} StgThreadReturnCode;
+typedef unsigned int StgThreadReturnCode;
 
 /*
  * We distinguish between the various classes of threads in the system.
@@ -138,34 +117,6 @@ typedef enum {
   RevalPriority
 } StgThreadPriority;
 
-/* 
- * Threads may be blocked for several reasons.  A blocked thread will
- * have the reason in the why_blocked field of the TSO, and some
- * further info (such as the closure the thread is blocked on, or the
- * file descriptor if the thread is waiting on I/O) in the block_info
- * field.
- */
-
-typedef enum {
-  NotBlocked,
-  BlockedOnMVar,
-  BlockedOnBlackHole,
-  BlockedOnException,
-  BlockedOnRead,
-  BlockedOnWrite,
-  BlockedOnDelay
-#if defined(mingw32_TARGET_OS)
-  , BlockedOnDoProc
-#endif
-#if defined(PAR)
-  , BlockedOnGA  // blocked on a remote closure represented by a Global Address
-  , BlockedOnGA_NoSend // same as above but without sending a Fetch message
-#endif
-  , BlockedOnCCall
-  , BlockedOnCCall_NoUnblockExc // same as above but don't unblock
-                               // async exceptions in resumeThread()
-} StgTSOBlockReason;
-
 #if defined(mingw32_TARGET_OS)
 /* results from an async I/O request + it's ID. */
 typedef struct {
@@ -192,30 +143,42 @@ typedef union {
  */
 
 /* 
+ * Threads may be blocked for several reasons.  A blocked thread will
+ * have the reason in the why_blocked field of the TSO, and some
+ * further info (such as the closure the thread is blocked on, or the
+ * file descriptor if the thread is waiting on I/O) in the block_info
+ * field.
+ */
+
+/* 
  * ToDo: make this structure sensible on a non-32-bit arch.
  */
 
 typedef struct StgTSO_ {
   StgHeader          header;
 
-  struct StgTSO_*    link;          /* Links threads onto blocking queues */
-  StgMutClosure *    mut_link;      /* TSO's are mutable of course! */
-  struct StgTSO_*    global_link;    /* Links all threads together */
+  struct StgTSO_*    link;          // Links threads onto blocking queues */
+  StgMutClosure *    mut_link;      // TSO's are mutable of course! */
+  struct StgTSO_*    global_link;    // Links all threads together */
   
-  StgTSOWhatNext         what_next   : 16;
-  StgTSOBlockReason      why_blocked : 16;
-  StgTSOBlockInfo        block_info;
-  struct StgTSO_*        blocked_exceptions;
-  StgThreadID            id;
-  int                    saved_errno;
-  struct StgMainThread_* main;
+  StgWord16           what_next;  // Values defined in Constants.h
+  StgWord16           why_blocked;  // Values defined in Constants.h
+  StgTSOBlockInfo    block_info;
+  struct StgTSO_*    blocked_exceptions;
+  StgThreadID        id;
+  int                saved_errno;
   
+#ifdef TICKY_TICKY
   MAYBE_EMPTY_STRUCT(StgTSOTickyInfo,ticky)
-  MAYBE_EMPTY_STRUCT(StgTSOProfInfo,prof)
-  MAYBE_EMPTY_STRUCT(StgTSOParInfo,par)
-  MAYBE_EMPTY_STRUCT(StgTSOGranInfo,gran)
-  MAYBE_EMPTY_STRUCT(StgTSODistInfo,dist)
-    
+#endif
+#ifdef PROFILING
+   StgTSOProfInfo prof;
+#endif
+
+   MAYBE_EMPTY_STRUCT(StgTSOParInfo,par);
+   MAYBE_EMPTY_STRUCT(StgTSOGranInfo,gran);
+   MAYBE_EMPTY_STRUCT(StgTSODistInfo,dist);
+
   /* The thread stack... */
   StgWord           stack_size;     /* stack size in *words* */
   StgWord            max_stack_size; /* maximum stack size in *words* */
@@ -300,4 +263,16 @@ extern StgTSO dummy_tso;
 
 #define TSO_STRUCT_SIZEW (TSO_STRUCT_SIZE / sizeof(W_))
 
+
+/* this is the NIL ptr for a TSO queue (e.g. runnable queue) */
+#define END_TSO_QUEUE  ((StgTSO *)(void*)&stg_END_TSO_QUEUE_closure)
+
+#if defined(PAR) || defined(GRAN)
+/* this is the NIL ptr for a blocking queue */
+# define END_BQ_QUEUE  ((StgBlockingQueueElement *)(void*)&stg_END_TSO_QUEUE_closure)
+/* this is the NIL ptr for a blocked fetch queue (as in PendingFetches in GUM) */
+# define END_BF_QUEUE  ((StgBlockedFetch *)(void*)&stg_END_TSO_QUEUE_closure)
+#endif
+/* ToDo?: different name for end of sleeping queue ? -- HWL */
+
 #endif /* TSO_H */
index bdcc400..a61695e 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: TailCalls.h,v 1.15 2003/10/12 13:24:52 igloo Exp $
+ * $Id: TailCalls.h,v 1.16 2004/08/13 13:09:41 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -16,7 +16,7 @@
 
 #ifdef USE_MINIINTERPRETER
 
-#define JMP_(cont) return(stgCast(StgFunPtr,cont))
+#define JMP_(cont) return((StgFunPtr)(cont))
 #define FB_
 #define FE_
 
index ebc2e73..208c9f0 100644 (file)
@@ -1,9 +1,8 @@
 /* -----------------------------------------------------------------------------
- * $Id: Updates.h,v 1.34 2003/11/12 17:27:06 sof Exp $
  *
- * (c) The GHC Team, 1998-1999
+ * (c) The GHC Team, 1998-2004
  *
- * Definitions related to updates.
+ * Performing updates.
  *
  * ---------------------------------------------------------------------------*/
 
 #define UPDATES_H
 
 /* -----------------------------------------------------------------------------
-   Update a closure with an indirection.  This may also involve waking
-   up a queue of blocked threads waiting on the result of this
-   computation.
-   -------------------------------------------------------------------------- */
+   Updates
 
-/* ToDo: overwrite slop words with something safe in case sanity checking 
- *       is turned on.  
- *       (I think the fancy version of the GC is supposed to do this too.)
- */
+   We have two layers of update macros.  The top layer, UPD_IND() and
+   friends perform all the work of an update.  In detail:
 
-/* This expands to a fair chunk of code, what with waking up threads 
- * and checking whether we're updating something in a old generation.
- * preferably don't use this macro inline in compiled code.
- */
+      - if the closure being updated is a blocking queue, then all the
+        threads waiting on the blocking queue are updated.
+
+      - then the lower level updateWithIndirection() macro is invoked 
+        to actually replace the closure with an indirection (see below).
+
+   -------------------------------------------------------------------------- */
 
 #ifdef TICKY_TICKY
 # define UPD_IND(updclosure, heapptr) \
 #else
 #  define SEMI ;
 # define UPD_IND(updclosure, heapptr) \
-   UPD_REAL_IND(updclosure,&stg_IND_info,heapptr,SEMI)
+   UPD_REAL_IND(updclosure,INFO_PTR(stg_IND_info),heapptr,SEMI)
 # define UPD_SPEC_IND(updclosure, ind_info, heapptr, and_then) \
    UPD_REAL_IND(updclosure,ind_info,heapptr,and_then)
 #endif
 
+/* These macros have to work in both C and C--, so here's the
+ * impedence matching:
+ */
+#ifdef CMINUSMINUS
+#define DECLARE_IPTR(info)  W_ info
+#define FCALL               foreign "C"
+#define INFO_PTR(info)      info
+#define ARG_PTR             "ptr"
+#else
+#define DECLARE_IPTR(info)  const StgInfoTable *(info)
+#define FCALL               /* nothing */
+#define INFO_PTR(info)      &info
+#define StgBlockingQueue_blocking_queue(closure) \
+    (((StgBlockingQueue *)closure)->blocking_queue)
+#define ARG_PTR             /* nothing */
+#endif
+
 /* UPD_IND actually does a PERM_IND if TICKY_TICKY is on;
    if you *really* need an IND use UPD_REAL_IND
  */
-#ifdef SMP
 #define UPD_REAL_IND(updclosure, ind_info, heapptr, and_then)          \
-   {                                                                   \
-       const StgInfoTable *info;                                       \
-       if (Bdescr((P_)updclosure)->u.back != (bdescr *)BaseReg) {      \
-               info = LOCK_CLOSURE(updclosure);                        \
-       } else {                                                        \
-               info = updclosure->header.info;                         \
-       }                                                               \
+       DECLARE_IPTR(info);                                             \
+       info = GET_INFO(updclosure);                                    \
         AWAKEN_BQ(info,updclosure);                                    \
-       updateWithIndirection(info, ind_info,                           \
-                             (StgClosure *)updclosure,                 \
-                             (StgClosure *)heapptr,                    \
-                             and_then);                                \
-   }
-#else
-#define UPD_REAL_IND(updclosure, ind_info, heapptr, and_then)  \
-   {                                                   \
-       const StgInfoTable *info;                       \
-       info = ((StgClosure *)updclosure)->header.info; \
-        AWAKEN_BQ(info,updclosure);                    \
-       updateWithIndirection(((StgClosure *)updclosure)->header.info, ind_info,                \
-                             (StgClosure *)updclosure, \
-                             (StgClosure *)heapptr,    \
-                             and_then);                \
-   }
-#endif
-
-#define UPD_STATIC_IND(updclosure, heapptr)                    \
-   {                                                           \
-       const StgInfoTable *info;                               \
-       info = ((StgClosure *)updclosure)->header.info;         \
-        AWAKEN_STATIC_BQ(info,updclosure);                     \
-       updateWithStaticIndirection(info,                       \
-                                   (StgClosure *)updclosure,   \
-                                   (StgClosure *)heapptr);     \
-   }
+       updateWithIndirection(GET_INFO(updclosure), ind_info,           \
+                             updclosure,                               \
+                             heapptr,                                  \
+                             and_then);
 
 #if defined(PROFILING) || defined(TICKY_TICKY)
-#define UPD_PERM_IND(updclosure, heapptr)                      \
-   {                                                           \
-       const StgInfoTable *info;                               \
-       info = ((StgClosure *)updclosure)->header.info;         \
-        AWAKEN_BQ(info,updclosure);                            \
-       updateWithPermIndirection(info,                         \
-                                 (StgClosure *)updclosure,     \
-                                 (StgClosure *)heapptr);       \
-   }
+#define UPD_PERM_IND(updclosure, heapptr)      \
+       DECLARE_IPTR(info);                     \
+       info = GET_INFO(updclosure);            \
+        AWAKEN_BQ(info,updclosure);            \
+       updateWithPermIndirection(info,         \
+                                 updclosure,   \
+                                 heapptr);
 #endif
 
-#ifdef SMP
-#define UPD_IND_NOLOCK(updclosure, heapptr)                            \
-   {                                                                   \
-       const StgInfoTable *info;                                       \
-       info = updclosure->header.info;                                 \
-        AWAKEN_BQ(info,updclosure);                                    \
-       updateWithIndirection(info,&stg_IND_info,                       \
-                             (StgClosure *)updclosure,                 \
-                             (StgClosure *)heapptr,);                  \
-   }
-#elif defined(RTS_SUPPORTS_THREADS)
+#if defined(RTS_SUPPORTS_THREADS)
 
 # ifdef TICKY_TICKY
-#  define UPD_IND_NOLOCK(updclosure, heapptr)                  \
-   {                                                           \
-       const StgInfoTable *info;                               \
-       info = ((StgClosure *)updclosure)->header.info;         \
-        AWAKEN_BQ_NOLOCK(info,updclosure);                     \
-       updateWithPermIndirection(info,                         \
-                                 (StgClosure *)updclosure,     \
-                                 (StgClosure *)heapptr);       \
-   }
+#  define UPD_IND_NOLOCK(updclosure, heapptr)  \
+       DECLARE_IPTR(info);                     \
+       info = GET_INFO(updclosure);            \
+        AWAKEN_BQ_NOLOCK(info,updclosure);     \
+       updateWithPermIndirection(info,         \
+                                 updclosure,   \
+                                 heapptr)
 # else
 #  define UPD_IND_NOLOCK(updclosure, heapptr)          \
-   {                                                   \
-       const StgInfoTable *info;                       \
-       info = ((StgClosure *)updclosure)->header.info; \
+       DECLARE_IPTR(info);                             \
+       info = GET_INFO(updclosure);                    \
         AWAKEN_BQ_NOLOCK(info,updclosure);             \
-       updateWithIndirection(info,&stg_IND_info,       \
-                             (StgClosure *)updclosure, \
-                             (StgClosure *)heapptr,);  \
-   }
+       updateWithIndirection(info,stg_IND_info,        \
+                             updclosure,               \
+                             heapptr,); 
 # endif
 
 #else
 #endif
 
 /* -----------------------------------------------------------------------------
-   Awaken any threads waiting on this computation
+   Awaken any threads waiting on a blocking queue (BLACKHOLE_BQ).
    -------------------------------------------------------------------------- */
 
 #if defined(PAR) 
@@ -189,99 +158,209 @@ extern void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node);
 
 #else /* !GRAN && !PAR */
 
-extern void awakenBlockedQueue(StgTSO *q);
 #define DO_AWAKEN_BQ(closure)          \
-        STGCALL1(awakenBlockedQueue,           \
-                ((StgBlockingQueue *)closure)->blocking_queue);
+        FCALL awakenBlockedQueue(StgBlockingQueue_blocking_queue(closure) ARG_PTR);
 
 #define AWAKEN_BQ(info,closure)                                                \
-       if (info == &stg_BLACKHOLE_BQ_info) {                           \
+       if (info == INFO_PTR(stg_BLACKHOLE_BQ_info)) {                  \
           DO_AWAKEN_BQ(closure);                                        \
        }
 
 #define AWAKEN_STATIC_BQ(info,closure)                                 \
-       if (info == &stg_BLACKHOLE_BQ_STATIC_info) {                    \
+       if (info == INFO_PTR(stg_BLACKHOLE_BQ_STATIC_info)) {           \
           DO_AWAKEN_BQ(closure);                                        \
        }
 
 #ifdef RTS_SUPPORTS_THREADS
-extern void awakenBlockedQueueNoLock(StgTSO *q);
-#define DO_AWAKEN_BQ_NOLOCK(closure)                                   \
-        STGCALL1(awakenBlockedQueueNoLock,                             \
-                ((StgBlockingQueue *)closure)->blocking_queue);
+#define DO_AWAKEN_BQ_NOLOCK(closure) \
+        FCALL awakenBlockedQueueNoLock(StgBlockingQueue_blocking_queue(closure) ARG_PTR);
 
 #define AWAKEN_BQ_NOLOCK(info,closure)                                 \
-       if (info == &stg_BLACKHOLE_BQ_info) {                           \
+       if (info == INFO_PTR(stg_BLACKHOLE_BQ_info)) {                  \
           DO_AWAKEN_BQ_NOLOCK(closure);                                 \
        }
 #endif
 #endif /* GRAN || PAR */
 
-/* -------------------------------------------------------------------------
-   Push an update frame on the stack.
-   ------------------------------------------------------------------------- */
-
-#if defined(PROFILING)
-// frame->header.prof.hp.rs = NULL (or frame-header.prof.hp.ldvw = 0) is unnecessary 
-// because it is not used anyhow.
-#define PUSH_STD_CCCS(frame) (frame->header.prof.ccs = CCCS)
-#else
-#define PUSH_STD_CCCS(frame)
-#endif
+/* -----------------------------------------------------------------------------
+   Updates: lower-level macros which update a closure with an
+   indirection to another closure.
 
-extern DLL_IMPORT_RTS const StgPolyInfoTable stg_upd_frame_info; 
-extern DLL_IMPORT_RTS const StgPolyInfoTable stg_noupd_frame_info; 
-
-#define PUSH_UPD_FRAME(target, Sp_offset)                      \
-       {                                                       \
-               StgUpdateFrame *__frame;                        \
-               TICK_UPDF_PUSHED(target, GET_INFO((StgClosure*)target)); \
-               __frame = (StgUpdateFrame *)(Sp + (Sp_offset)) - 1; \
-               SET_INFO(__frame, (StgInfoTable *)&stg_upd_frame_info);   \
-               __frame->updatee = (StgClosure *)(target);      \
-               PUSH_STD_CCCS(__frame);                         \
-       }
+   There are several variants of this code.
 
-/* -----------------------------------------------------------------------------
-   Entering CAFs
+       PROFILING:
+   -------------------------------------------------------------------------- */
 
-   When a CAF is first entered, it creates a black hole in the heap,
-   and updates itself with an indirection to this new black hole.
+/* LDV profiling:
+ * We call LDV_recordDead_FILL_SLOP_DYNAMIC(p1) regardless of the generation in 
+ * which p1 resides.
+ *
+ * Note: 
+ *   After all, we do *NOT* need to call LDV_RECORD_CREATE() for both IND and 
+ *   IND_OLDGEN closures because they are inherently used. But, it corrupts
+ *   the invariants that every closure keeps its creation time in the profiling
+ *  field. So, we call LDV_RECORD_CREATE().
+ */
 
-   We update the CAF with an indirection to a newly-allocated black
-   hole in the heap.  We also set the blocking queue on the newly
-   allocated black hole to be empty.
+/* In the DEBUG case, we also zero out the slop of the old closure,
+ * so that the sanity checker can tell where the next closure is.
+ *
+ * Two important invariants: we should never try to update a closure
+ * to point to itself, and the closure being updated should not
+ * already have been updated (the mutable list will get messed up
+ * otherwise).
+ */
+#if !defined(DEBUG)
+
+#define DEBUG_FILL_SLOP(p) /* nothing */
+
+#else  /* DEBUG */
+
+#ifdef CMINUSMINUS
+
+#define DEBUG_FILL_SLOP(p)                     \
+  W_ inf;                                      \
+  W_ np;                                       \
+  W_ nw;                                       \
+  W_ i;                                                \
+  inf = %GET_STD_INFO(p);                      \
+  np = TO_W_(%INFO_PTRS(inf));                 \
+  nw = TO_W_(%INFO_NPTRS(inf));                        \
+  if (%INFO_TYPE(inf) != THUNK_SELECTOR::I16) {        \
+    i = 0;                                     \
+    for:                                       \
+      if (i < np + nw) {                       \
+        StgClosure_payload(p,i) = 0;           \
+        i = i + 1;                             \
+        goto for;                              \
+      }                                                \
+  }
 
-   Why do we make a black hole in the heap when we enter a CAF?
-      
-       - for a  generational garbage collector, which needs a fast
-         test for whether an updatee is in an old generation or not
 
-       - for the parallel system, which can implement updates more
-         easily if the updatee is always in the heap. (allegedly).
+#else /* !CMINUSMINUS */
 
-   When debugging, we maintain a separate CAF list so we can tell when
-   a CAF has been garbage collected.
-   -------------------------------------------------------------------------- */
-   
-/* ToDo: only call newCAF when debugging. */
+INLINE_HEADER void
+DEBUG_FILL_SLOP(StgClosure *p)
+{                                              
+    StgInfoTable *inf = get_itbl(p);           
+    nat np = inf->layout.payload.ptrs,         
+       nw = inf->layout.payload.nptrs, i;
+    if (inf->type != THUNK_SELECTOR) {
+       for (i = 0; i < np + nw; i++) {
+           ((StgClosure *)p)->payload[i] = 0;
+       }
+    }
+}
 
-extern void newCAF(StgClosure*);
+#endif /* CMINUSMINUS */
+#endif /* DEBUG */
 
-/* newCAF must be called before the itbl ptr is overwritten, since
-   newCAF records the old itbl ptr in order to do CAF reverting
-   (which Hugs needs to do in order that combined mode works right.)
-*/
-#define UPD_CAF(cafptr, bhptr)                                         \
+/* We have two versions of this macro (sadly), one for use in C-- code,
+ * and the other for C.
+ *
+ * The and_then argument is a performance hack so that we can paste in
+ * the continuation code directly.  It helps shave a couple of
+ * instructions off the common case in the update code, which is
+ * worthwhile (the update code is often part of the inner loop).
+ * (except that gcc now appears to common up this code again and
+ * invert the optimisation.  Grrrr --SDM).
+ */
+#ifdef CMINUSMINUS
+#define generation(n) (W_[generations] + n*SIZEOF_generation)
+#define updateWithIndirection(info, ind_info, p1, p2, and_then)        \
+    W_ bd;                                                     \
+                                                               \
+/*    ASSERT( p1 != p2 && !closure_IND(p1) );                  \
+ */ LDV_RECORD_DEAD_FILL_SLOP_DYNAMIC(p1);                     \
+    bd = Bdescr(p1);                                           \
+    if (bdescr_gen_no(bd) == 0) {                              \
+      StgInd_indirectee(p1) = p2;                              \
+      SET_INFO(p1, ind_info);                                  \
+      LDV_RECORD_CREATE(p1);                                   \
+      TICK_UPD_NEW_IND();                                      \
+      and_then;                                                        \
+    } else {                                                   \
+      if (info != stg_BLACKHOLE_BQ_info) {                     \
+        DEBUG_FILL_SLOP(p1);                                   \
+        W_ __mut_once_list;                                    \
+        __mut_once_list = generation(bdescr_gen_no(bd)) +      \
+                             OFFSET_generation_mut_once_list;  \
+        StgMutClosure_mut_link(p1) = W_[__mut_once_list];      \
+        W_[__mut_once_list] = p1;                              \
+      }                                                                \
+      StgInd_indirectee(p1) = p2;                              \
+      SET_INFO(p1, stg_IND_OLDGEN_info);                       \
+      LDV_RECORD_CREATE(p1);                                   \
+      TICK_UPD_OLD_IND();                                      \
+      and_then;                                                        \
+  }
+#else
+#define updateWithIndirection(_info, ind_info, p1, p2, and_then)       \
   {                                                                    \
-    LOCK_CLOSURE(cafptr);                                              \
-    STGCALL1(newCAF,(StgClosure *)cafptr);                             \
-    ((StgInd *)cafptr)->indirectee   = (StgClosure *)(bhptr);          \
-    SET_INFO((StgInd *)cafptr,(const StgInfoTable*)&stg_IND_STATIC_info);\
+    bdescr *bd;                                                                \
+                                                                       \
+    ASSERT( (P_)p1 != (P_)p2 && !closure_IND(p1) );                    \
+    LDV_RECORD_DEAD_FILL_SLOP_DYNAMIC(p1);                             \
+    bd = Bdescr((P_)p1);                                               \
+    if (bd->gen_no == 0) {                                             \
+      ((StgInd *)p1)->indirectee = p2;                                 \
+      SET_INFO(p1, ind_info);                                          \
+      LDV_RECORD_CREATE(p1);                                           \
+      TICK_UPD_NEW_IND();                                              \
+      and_then;                                                                \
+    } else {                                                           \
+      if (_info != &stg_BLACKHOLE_BQ_info) {                           \
+        DEBUG_FILL_SLOP(p1);                                           \
+        ((StgIndOldGen *)p1)->mut_link = generations[bd->gen_no].mut_once_list;        \
+        generations[bd->gen_no].mut_once_list = (StgMutClosure *)p1;    \
+      }                                                                        \
+      ((StgIndOldGen *)p1)->indirectee = p2;                           \
+      SET_INFO(p1, &stg_IND_OLDGEN_info);                              \
+      TICK_UPD_OLD_IND();                                              \
+      and_then;                                                                \
+    }                                                                  \
   }
+#endif
 
-/* -----------------------------------------------------------------------------
-   Update-related prototypes
-   -------------------------------------------------------------------------- */
+/* The permanent indirection version isn't performance critical.  We
+ * therefore use an inline C function instead of the C-- macro.
+ */
+#ifndef CMINUSMINUS
+INLINE_HEADER void
+updateWithPermIndirection(const StgInfoTable *info, 
+                         StgClosure *p1,
+                         StgClosure *p2) 
+{
+  bdescr *bd;
+
+  ASSERT( p1 != p2 && !closure_IND(p1) );
+
+  // @LDV profiling
+  // Destroy the old closure.
+  // Nb: LDV_* stuff cannot mix with ticky-ticky
+  LDV_RECORD_DEAD_FILL_SLOP_DYNAMIC(p1);
+
+  bd = Bdescr((P_)p1);
+  if (bd->gen_no == 0) {
+    ((StgInd *)p1)->indirectee = p2;
+    SET_INFO(p1, &stg_IND_PERM_info);
+    // @LDV profiling
+    // We have just created a new closure.
+    LDV_RECORD_CREATE(p1);
+    TICK_UPD_NEW_PERM_IND(p1);
+  } else {
+    if (info != &stg_BLACKHOLE_BQ_info) {
+      ((StgIndOldGen *)p1)->mut_link = generations[bd->gen_no].mut_once_list;
+      generations[bd->gen_no].mut_once_list = (StgMutClosure *)p1;
+    }
+    ((StgIndOldGen *)p1)->indirectee = p2;
+    SET_INFO(p1, &stg_IND_OLDGEN_PERM_info);
+    // @LDV profiling
+    // We have just created a new closure.
+    LDV_RECORD_CREATE(p1);
+    TICK_UPD_OLD_PERM_IND();
+  }
+}
+#endif
 
 #endif /* UPDATES_H */
index 8c7591a..1baacdb 100644 (file)
 /* --------------------------------------------------------------------------
- * $Id: mkDerivedConstants.c,v 1.5 2004/03/08 10:31:00 stolz Exp $
  *
- * (c) The GHC Team, 1992-1998
+ * (c) The GHC Team, 1992-2004
  *
- * Generate a header for the native code generator
+ * mkDerivedConstants.c
+ *
+ * Basically this is a C program that extracts information from the C
+ * declarations in the header files (primarily struct field offsets)
+ * and generates a header file that can be #included into non-C source
+ * containing this information.
  *
  * ------------------------------------------------------------------------*/
 
 #include <stdio.h>
 
 #define IN_STG_CODE 0
-#include "Stg.h"
+
+// We need offsets of profiled things... better be careful that this
+// doesn't affect the offsets of anything else.
+#define PROFILING
+
+#include "Rts.h"
+#include "RtsFlags.h"
+#include "Storage.h"
+
+#define str(a,b) #a "_" #b
 
 #define OFFSET(s_type, field) ((unsigned int)&(((s_type*)0)->field))
 
+#if defined(GEN_HASKELL)
+#define def_offset(str, offset) \
+    printf("oFFSET_" str " = %d::Int\n", offset);
+#else
+#define def_offset(str, offset) \
+    printf("#define OFFSET_" str " %d\n", offset);
+#endif
+
+#if defined(GEN_HASKELL)
+#define ctype(type) /* nothing */
+#else
+#define ctype(type) \
+    printf("#define SIZEOF_" #type " %d\n", sizeof(type)); 
+#endif
+
+#if defined(GEN_HASKELL)
+#define field_type_(str, s_type, field) /* nothing */
+#else
+#define field_type_(str, s_type, field) \
+    printf("#define REP_" str " I"); \
+    printf("%d\n", sizeof (__typeof__(((((s_type*)0)->field)))) * 8);
+#endif
+
+#define field_type(s_type, field) \
+    field_type_(str(s_type,field),s_type,field);
+
+#define field_offset_(str, s_type, field) \
+    def_offset(str, OFFSET(s_type,field));
+
+#define field_offset(s_type, field) \
+    field_offset_(str(s_type,field),s_type,field);
+
+// An access macro for use in C-- sources.  
+#define struct_field_macro(str) \
+    printf("#define " str "(__ptr__)  REP_" str "[__ptr__+OFFSET_" str "]\n");
+
+// Outputs the byte offset and MachRep for a field
+#define struct_field(s_type, field)            \
+    field_offset(s_type, field);               \
+    field_type(s_type, field);                 \
+    struct_field_macro(str(s_type,field))
+
+#define struct_field_(str, s_type, field)      \
+    field_offset_(str, s_type, field);         \
+    field_type_(str, s_type, field);           \
+    struct_field_macro(str)
+
+#if defined(GEN_HASKELL)
+#define def_size(str, size) \
+    printf("sIZEOF_" str " = %d::Int\n", size);
+#else
+#define def_size(str, size) \
+    printf("#define SIZEOF_" str " %d\n", size);
+#endif
+
+#if defined(GEN_HASKELL)
+#define def_closure_size(str, size) /* nothing */
+#else
+#define def_closure_size(str, size) \
+    printf("#define SIZEOF_" str " (SIZEOF_StgHeader+%d)\n", size);
+#endif
+
+#define struct_size(s_type) \
+    def_size(#s_type, sizeof(s_type));
+
+// Size of a closure type, minus the header, named SIZEOF_<type>_NoHdr
+// Also, we #define SIZEOF_<type> to be the size of the whole closure for .cmm.
+#define closure_size(s_type) \
+    def_size(#s_type "_NoHdr", sizeof(s_type) - sizeof(StgHeader)); \
+    def_closure_size(#s_type, sizeof(s_type) - sizeof(StgHeader));
+
+// An access macro for use in C-- sources.  
+#define closure_field_macro(str) \
+    printf("#define " str "(__ptr__)  REP_" str "[__ptr__+SIZEOF_StgHeader+OFFSET_" str "]\n");
+
+#define closure_field_offset_(str, s_type,field) \
+    def_offset(str, OFFSET(s_type,field) - sizeof(StgHeader));
+
+#define closure_field_offset(s_type,field) \
+    closure_field_offset_(str(s_type,field),s_type,field);
+
+#define closure_payload_macro(str) \
+    printf("#define " str "(__ptr__,__ix__)  W_[__ptr__+SIZEOF_StgHeader+OFFSET_" str " + WDS(__ix__)]\n");
+
+#define closure_payload(s_type,field) \
+    closure_field_offset_(str(s_type,field),s_type,field); \
+    closure_payload_macro(str(s_type,field));
+
+// Byte offset and MachRep for a closure field, minus the header
+#define closure_field(s_type, field) \
+    closure_field_offset(s_type,field) \
+    field_type(s_type, field); \
+    closure_field_macro(str(s_type,field))
+
+// Byte offset and MachRep for a closure field, minus the header
+#define closure_field_(str, s_type, field) \
+    closure_field_offset_(str,s_type,field) \
+    field_type_(str, s_type, field); \
+    closure_field_macro(str)
+
+// Byte offset and MachRep for a TSO field, minus the header and
+// variable prof bit.
+#define tso_offset(s_type, field) \
+    def_offset(str(s_type,field), OFFSET(s_type,field) - sizeof(StgHeader) - sizeof(StgTSOProfInfo));
+
+#define tso_field_macro(str) \
+    printf("#define " str "(__ptr__)  REP_" str "[__ptr__+SIZEOF_StgHeader+SIZEOF_OPT_StgTSOProfInfo+SIZEOF_OPT_StgTSOTickyInfo+SIZEOF_OPT_StgTSOParInfo+SIZEOF_OPT_StgTSOGranInfo+SIZEOF_OPT_StgTSODistInfo+OFFSET_" str "]\n");
+
+#define tso_field(s_type, field)               \
+    tso_offset(s_type, field);                 \
+    field_type(s_type, field);                 \
+    tso_field_macro(str(s_type,field))
+
+#define opt_struct_size(s_type, option)                                        \
+    printf("#ifdef " #option "\n");                                    \
+    printf("#define SIZEOF_OPT_" #s_type " SIZEOF_" #s_type "\n");     \
+    printf("#else\n");                                                 \
+    printf("#define SIZEOF_OPT_" #s_type " 0\n");                      \
+    printf("#endif\n\n");
+
+#define FUN_OFFSET(sym) (OFFSET(Capability,f.sym) - OFFSET(Capability,r))
+
+
 int
 main(int argc, char *argv[])
 {
-    printf("-- This file is created automatically.  Do not edit by hand.\n\n");
+#ifndef GEN_HASKELL
+    printf("/* This file is created automatically.  Do not edit by hand.*/\n\n");
 
-    printf("#define STD_HDR_SIZE   %d\n", sizeofW(StgHeader));
+    printf("#define STD_HDR_SIZE   %d\n", sizeofW(StgHeader) - sizeofW(StgProfHeader));
+    // grrr.. PROFILING is on so we need to subtract sizeofW(StgProfHeader)
     printf("#define PROF_HDR_SIZE  %d\n", sizeofW(StgProfHeader));
     printf("#define GRAN_HDR_SIZE  %d\n", sizeofW(StgGranHeader));
 
-    printf("#define ARR_WORDS_HDR_SIZE  %d\n", 
-          sizeofW(StgArrWords) - sizeofW(StgHeader));
-
-    printf("#define ARR_PTRS_HDR_SIZE   %d\n", 
-          sizeofW(StgMutArrPtrs) - sizeofW(StgHeader));
-
     printf("#define STD_ITBL_SIZE   %d\n", sizeofW(StgInfoTable));
     printf("#define RET_ITBL_SIZE   %d\n", sizeofW(StgRetInfoTable) - sizeofW(StgInfoTable));
     printf("#define PROF_ITBL_SIZE  %d\n", sizeofW(StgProfInfo));
     printf("#define GRAN_ITBL_SIZE  %d\n", 0);
     printf("#define TICKY_ITBL_SIZE %d\n", sizeofW(StgTickyInfo));
 
-    printf("#define STD_UF_SIZE   %d\n", sizeofW(StgUpdateFrame));
-    printf("#define GRAN_UF_SIZE   %d\n",  
-          sizeofW(StgUpdateFrame) + sizeofW(StgGranHeader));
-    printf("#define PROF_UF_SIZE   %d\n",  
-          sizeofW(StgUpdateFrame) + sizeofW(StgProfHeader));
+    printf("#define BLOCK_SIZE   %d\n", BLOCK_SIZE);
+    printf("#define MBLOCK_SIZE   %d\n", MBLOCK_SIZE);  
 
-    printf("#define UF_RET     %d\n",
-          OFFSET(StgUpdateFrame,header.info));
+    printf("\n\n");
+#endif
 
-    printf("#define UF_UPDATEE %d\n",
-          OFFSET(StgUpdateFrame,updatee) / sizeof(W_));
+    field_offset(StgRegTable, rR1);
+    field_offset(StgRegTable, rR2);
+    field_offset(StgRegTable, rR3);
+    field_offset(StgRegTable, rR4);
+    field_offset(StgRegTable, rR5);
+    field_offset(StgRegTable, rR6);
+    field_offset(StgRegTable, rR7);
+    field_offset(StgRegTable, rR8);
+    field_offset(StgRegTable, rR9);
+    field_offset(StgRegTable, rR10);
+    field_offset(StgRegTable, rF1);
+    field_offset(StgRegTable, rF2);
+    field_offset(StgRegTable, rF3);
+    field_offset(StgRegTable, rF4);
+    field_offset(StgRegTable, rD1);
+    field_offset(StgRegTable, rD2);
+#ifdef SUPPORT_LONG_LONGS
+    field_offset(StgRegTable, rL1);
+#endif
+    field_offset(StgRegTable, rSp);
+    field_offset(StgRegTable, rSpLim);
+    field_offset(StgRegTable, rHp);
+    field_offset(StgRegTable, rHpLim);
+    field_offset(StgRegTable, rCurrentTSO);
+    field_offset(StgRegTable, rCurrentNursery);
+    field_offset(StgRegTable, rHpAlloc);
 
-    printf("#define BLOCK_SIZE   %d\n", BLOCK_SIZE);
-    printf("#define MBLOCK_SIZE   %d\n", MBLOCK_SIZE);  
+    def_offset("stgGCEnter1", FUN_OFFSET(stgGCEnter1));
+    def_offset("stgGCFun", FUN_OFFSET(stgGCFun));
+
+    field_offset(Capability, r);
+
+    struct_field(bdescr, start);
+    struct_field(bdescr, free);
+    struct_field(bdescr, blocks);
+    struct_field(bdescr, gen_no);
+    struct_field(bdescr, link);
+
+    struct_size(generation);
+    struct_field(generation, mut_once_list);
+
+    struct_field(CostCentreStack, ccsID);
+    struct_field(CostCentreStack, mem_alloc);
+    struct_field(CostCentreStack, scc_count);
+    struct_field(CostCentreStack, prevStack);
+
+    struct_field(CostCentre, ccID);
+    struct_field(CostCentre, link);
+
+    struct_field(StgHeader, info);
+    struct_field_("StgHeader_ccs",  StgHeader, prof.ccs);
+    struct_field_("StgHeader_ldvw", StgHeader, prof.hp.ldvw);
+
+    closure_payload(StgClosure,payload);
+
+    struct_field(StgEntCounter, allocs);
+    struct_field(StgEntCounter, registeredp);
+    struct_field(StgEntCounter, link);
+    
+    closure_size(StgUpdateFrame);
+    closure_size(StgCatchFrame);
+    closure_size(StgStopFrame);
+
+    closure_size(StgMutArrPtrs);
+    closure_field(StgMutArrPtrs, ptrs);
+
+    closure_size(StgArrWords);
+    closure_field(StgArrWords, words);
+    closure_payload(StgArrWords, payload);
+
+    closure_field(StgTSO, link);
+    closure_field(StgTSO, mut_link);
+    closure_field(StgTSO, global_link);
+    closure_field(StgTSO, what_next);
+    closure_field(StgTSO, why_blocked);
+    closure_field(StgTSO, block_info);
+    closure_field(StgTSO, blocked_exceptions);
+    closure_field(StgTSO, id);
+    closure_field(StgTSO, saved_errno);
+    closure_field_("StgTSO_CCCS", StgTSO, prof.CCCS);
+    tso_field(StgTSO, sp);
+    tso_offset(StgTSO, stack);
+    tso_field(StgTSO, stack_size);
+
+    struct_size(StgTSOProfInfo);
+    struct_size(StgTSOTickyInfo);
+    struct_size(StgTSOParInfo);
+    struct_size(StgTSOGranInfo);
+    struct_size(StgTSODistInfo);
+
+    opt_struct_size(StgTSOProfInfo,PROFILING);
+    opt_struct_size(StgTSOTickyInfo,TICKY_TICKY);
+    opt_struct_size(StgTSOParInfo,PAR);
+    opt_struct_size(StgTSOGranInfo,GRAN);
+    opt_struct_size(StgTSODistInfo,DIST);
+
+    closure_size(StgBlockingQueue);
+    closure_field(StgBlockingQueue, blocking_queue);
+
+    closure_field(StgUpdateFrame, updatee);
+
+    closure_field(StgCatchFrame, handler);
+    closure_field(StgCatchFrame, exceptions_blocked);
+
+    closure_size(StgPAP);
+    closure_field(StgPAP, n_args);
+    closure_field(StgPAP, fun);
+    closure_field(StgPAP, arity);
+    closure_payload(StgPAP, payload);
+
+    closure_size(StgAP);
+    closure_field(StgAP, n_args);
+    closure_field(StgAP, fun);
+    closure_payload(StgAP, payload);
+
+    closure_size(StgAP_STACK);
+    closure_field(StgAP_STACK, size);
+    closure_field(StgAP_STACK, fun);
+    closure_payload(StgAP_STACK, payload);
+
+    closure_field(StgInd, indirectee);
+    closure_field(StgMutClosure, mut_link);
+
+    closure_size(StgMutVar);
+    closure_field(StgMutVar, var);
+
+    closure_size(StgForeignObj);
+    closure_field(StgForeignObj,data);
+
+    closure_size(StgWeak);
+    closure_field(StgWeak,link);
+    closure_field(StgWeak,key);
+    closure_field(StgWeak,value);
+    closure_field(StgWeak,finalizer);
+
+    closure_size(StgMVar);
+    closure_field(StgMVar,head);
+    closure_field(StgMVar,tail);
+    closure_field(StgMVar,value);
+
+    closure_size(StgBCO);
+    closure_field(StgBCO, instrs);
+    closure_field(StgBCO, literals);
+    closure_field(StgBCO, ptrs);
+    closure_field(StgBCO, itbls);
+    closure_field(StgBCO, arity);
+    closure_field(StgBCO, size);
+    closure_payload(StgBCO, bitmap);
+
+    closure_size(StgStableName);
+    closure_field(StgStableName,sn);
+
+    struct_field_("RtsFlags_ProfFlags_showCCSOnException",
+                 RTS_FLAGS, ProfFlags.showCCSOnException);
+    struct_field_("RtsFlags_DebugFlags_apply",
+                 RTS_FLAGS, DebugFlags.apply);
+    struct_field_("RtsFlags_DebugFlags_sanity",
+                 RTS_FLAGS, DebugFlags.sanity);
+    struct_field_("RtsFlags_DebugFlags_weak",
+                 RTS_FLAGS, DebugFlags.weak);
+    struct_field_("RtsFlags_GcFlags_initialStkSize",
+                 RTS_FLAGS, GcFlags.initialStkSize);
+
+    struct_size(StgFunInfoExtraFwd);
+    struct_field(StgFunInfoExtraFwd, slow_apply);
+    struct_field(StgFunInfoExtraFwd, fun_type);
+    struct_field(StgFunInfoExtraFwd, arity);
+    struct_field(StgFunInfoExtraFwd, bitmap);
+
+    struct_size(StgFunInfoExtraRev);
+    struct_field(StgFunInfoExtraRev, slow_apply);
+    struct_field(StgFunInfoExtraRev, fun_type);
+    struct_field(StgFunInfoExtraRev, arity);
+    struct_field(StgFunInfoExtraRev, bitmap);
+
+    struct_field(StgLargeBitmap, size);
+    field_offset(StgLargeBitmap, bitmap);
+
+    struct_size(snEntry);
+    struct_field(snEntry,sn_obj);
+    struct_field(snEntry,addr);
+
+#ifdef mingw32_TARGET_OS
+    struct_size(StgAsyncIOResult);
+    struct_field(StgAsyncIOResult, reqID);
+    struct_field(StgAsyncIOResult, len);
+    struct_field(StgAsyncIOResult, errCode);
+#endif
+
+    struct_size(MP_INT);
+    struct_field(MP_INT,_mp_alloc);
+    struct_field(MP_INT,_mp_size);
+    struct_field(MP_INT,_mp_d);
+
+    ctype(mp_limb_t);
     return 0;
 }
diff --git a/ghc/includes/mkNativeHdr.c b/ghc/includes/mkNativeHdr.c
deleted file mode 100644 (file)
index d078055..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/* --------------------------------------------------------------------------
- * $Id: mkNativeHdr.c,v 1.12 2003/03/21 15:48:06 sof Exp $
- *
- * (c) The GHC Team, 1992-1998
- *
- * Generate a header for the native code generator
- *
- * ------------------------------------------------------------------------*/
-
-#include "Stg.h"
-
-#include <stdio.h>
-
-#define OFFSET(table, x) ((StgUnion *) &(x) - (StgUnion *) (&table))
-
-#define OFFSET_R1    OFFSET(RegTable, RegTable.rR1)
-#define OFFSET_R2    OFFSET(RegTable, RegTable.rR2)
-#define OFFSET_R3    OFFSET(RegTable, RegTable.rR3)
-#define OFFSET_R4    OFFSET(RegTable, RegTable.rR4)
-#define OFFSET_R5    OFFSET(RegTable, RegTable.rR5)
-#define OFFSET_R6    OFFSET(RegTable, RegTable.rR6)
-#define OFFSET_R7    OFFSET(RegTable, RegTable.rR7)
-#define OFFSET_R8    OFFSET(RegTable, RegTable.rR8)
-#define OFFSET_R9    OFFSET(RegTable, RegTable.rR9)
-#define OFFSET_R10   OFFSET(RegTable, RegTable.rR10)
-#define OFFSET_F1    OFFSET(RegTable, RegTable.rF1)
-#define OFFSET_F2    OFFSET(RegTable, RegTable.rF2)
-#define OFFSET_F3    OFFSET(RegTable, RegTable.rF3)
-#define OFFSET_F4    OFFSET(RegTable, RegTable.rF4)
-#define OFFSET_D1    OFFSET(RegTable, RegTable.rD1)
-#define OFFSET_D2    OFFSET(RegTable, RegTable.rD2)
-#define OFFSET_L1    OFFSET(RegTable, RegTable.rL1)
-#define OFFSET_Sp    OFFSET(RegTable, RegTable.rSp)
-#define OFFSET_SpLim OFFSET(RegTable, RegTable.rSpLim)
-#define OFFSET_Hp    OFFSET(RegTable, RegTable.rHp)
-#define OFFSET_HpLim OFFSET(RegTable, RegTable.rHpLim)
-#define OFFSET_CurrentTSO OFFSET(RegTable, RegTable.rCurrentTSO)
-#define OFFSET_CurrentNursery OFFSET(RegTable, RegTable.rCurrentNursery)
-#define OFFSET_HpAlloc OFFSET(RegTable, RegTable.rHpAlloc)
-
-#define FUN_OFFSET(sym) ((StgPtr)&cap.f.sym - (StgPtr)&cap.r)
-
-#define OFFSET_stgGCEnter1   FUN_OFFSET(stgGCEnter1)
-#define OFFSET_stgGCFun      FUN_OFFSET(stgGCFun)
-
-#define OFFW_Capability_r  OFFSET(cap, cap.r)
-
-#define TSO_SP       OFFSET(tso, tso.sp)
-#define TSO_STACK    OFFSET(tso, tso.stack)
-
-#define BDESCR_START OFFSET(bd, bd.start)
-#define BDESCR_FREE  OFFSET(bd, bd.free)
-#define BDESCR_BLOCKS OFFSET(bd, bd.blocks)
-
-StgRegTable RegTable;
-
-Capability cap;
-
-StgTSO tso;
-bdescr bd;
-
-int
-main()
-{
-    printf("-- This file is created automatically.  Do not edit by hand.\n\n");
-
-    printf("\n-- Base table offsets for the Native Code Generator\n");
-
-    printf("#define OFFSET_R1 %d\n", OFFSET_R1);
-    printf("#define OFFSET_R2 %d\n", OFFSET_R2);
-    printf("#define OFFSET_R3 %d\n", OFFSET_R3);
-    printf("#define OFFSET_R4 %d\n", OFFSET_R4);
-    printf("#define OFFSET_R5 %d\n", OFFSET_R5);
-    printf("#define OFFSET_R6 %d\n", OFFSET_R6);
-    printf("#define OFFSET_R7 %d\n", OFFSET_R7);
-    printf("#define OFFSET_R8 %d\n", OFFSET_R8);
-    printf("#define OFFSET_R9 %d\n", OFFSET_R9);
-    printf("#define OFFSET_R10 %d\n", OFFSET_R10);
-    printf("#define OFFSET_F1 %d\n", OFFSET_F1);
-    printf("#define OFFSET_F2 %d\n", OFFSET_F2);
-    printf("#define OFFSET_F3 %d\n", OFFSET_F3);
-    printf("#define OFFSET_F4 %d\n", OFFSET_F4);
-    printf("#define OFFSET_D1 %d\n", OFFSET_D1);
-    printf("#define OFFSET_D2 %d\n", OFFSET_D2);
-#ifdef SUPPORT_LONG_LONGS
-    printf("#define OFFSET_L1 %d\n", OFFSET_L1);
-#endif
-    printf("#define OFFSET_Sp %d\n", OFFSET_Sp);
-    printf("#define OFFSET_SpLim %d\n", OFFSET_SpLim);
-    printf("#define OFFSET_Hp %d\n", OFFSET_Hp);
-    printf("#define OFFSET_HpLim %d\n", OFFSET_HpLim);
-    printf("#define OFFSET_CurrentTSO %d\n", OFFSET_CurrentTSO);
-    printf("#define OFFSET_CurrentNursery %d\n", OFFSET_CurrentNursery);
-    printf("#define OFFSET_HpAlloc %d\n", OFFSET_HpAlloc);
-
-    printf("#define OFFSET_stgGCEnter1 (%d)\n", OFFSET_stgGCEnter1);
-    printf("#define OFFSET_stgGCFun (%d)\n", OFFSET_stgGCFun);
-
-    printf("\n-- Offset of the .r (StgRegTable) field in a Capability\n");
-
-    printf("#define OFFW_Capability_r (%d)\n", OFFW_Capability_r);
-
-    printf("\n-- Storage Manager offsets for the Native Code Generator\n");
-
-    printf("\n-- TSO offsets for the Native Code Generator\n");
-
-    printf("#define TSO_SP %d\n", TSO_SP);
-    printf("#define TSO_STACK %d\n", TSO_STACK);
-
-    printf("\n-- Block descriptor offsets for the Native Code Generator\n");
-
-    printf("#define BDESCR_START %d\n", BDESCR_START);
-    printf("#define BDESCR_FREE %d\n", BDESCR_FREE);
-    printf("#define BDESCR_BLOCKS %d\n", BDESCR_BLOCKS);
-
-    exit(0);
-}
diff --git a/ghc/rts/Apply.cmm b/ghc/rts/Apply.cmm
new file mode 100644 (file)
index 0000000..2c7a0e9
--- /dev/null
@@ -0,0 +1,281 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The University of Glasgow 2004
+ *
+ * Application-related bits.
+ *
+ * This file is written in a subset of C--, extended with various
+ * features specific to GHC.  It is compiled by GHC directly.  For the
+ * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "Cmm.h"
+
+/* ----------------------------------------------------------------------------
+ * Evaluate a closure and return it.
+ *
+ *      stg_ap_0_info   <--- Sp
+ *
+ * NOTE: this needs to be a polymorphic return point, because we can't
+ * be sure that the thing being evaluated is not a function.
+ */
+
+#if MAX_VECTORED_RTN > 8
+#error MAX_VECTORED_RTN has changed: please modify stg_ap_0 too.
+#endif
+
+STRING(stg_ap_0_ret_str,"stg_ap_0_ret... ")
+
+INFO_TABLE_RET( stg_ap_0,
+               0/*framsize*/, 0/*bitmap*/, RET_SMALL,
+               RET_LBL(stg_ap_0),      
+               RET_LBL(stg_ap_0),      
+               RET_LBL(stg_ap_0),      
+               RET_LBL(stg_ap_0),      
+               RET_LBL(stg_ap_0),      
+               RET_LBL(stg_ap_0),      
+               RET_LBL(stg_ap_0),      
+               RET_LBL(stg_ap_0) )
+{ 
+    // fn is in R1, no args on the stack
+
+    IF_DEBUG(apply,
+       foreign "C" fprintf(stderr, stg_ap_0_ret_str);
+       foreign "C" printClosure(R1 "ptr"));
+
+    IF_DEBUG(sanity,
+       foreign "C" checkStackChunk(Sp+WDS(1) "ptr",
+                                   CurrentTSO + OFFSET_StgTSO_stack +
+                                   WDS(StgTSO_stack_size(CurrentTSO)) "ptr"));
+
+    Sp_adj(1);
+    ENTER();
+}
+
+/* -----------------------------------------------------------------------------
+   Entry Code for a PAP.
+
+   This entry code is *only* called by one of the stg_ap functions.
+   On entry: Sp points to the remaining arguments on the stack.  If
+   the stack check fails, we can just push the PAP on the stack and
+   return to the scheduler.
+
+   On entry: R1 points to the PAP.  The rest of the function's
+   arguments (apart from those that are already in the PAP) are on the
+   stack, starting at Sp(0).  R2 contains an info table which
+   describes these arguments, which is used in the event that the
+   stack check in the entry code below fails.  The info table is
+   currently one of the stg_ap_*_ret family, as this code is always
+   entered from those functions.
+
+   The idea is to copy the chunk of stack from the PAP object onto the
+   stack / into registers, and enter the function.
+   -------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_PAP,/*special layout*/0,0,PAP,"PAP","PAP")
+{
+  W_ Words;
+  W_ pap;
+    
+  pap = R1;
+
+  Words = TO_W_(StgPAP_n_args(pap));
+
+  //
+  // Check for stack overflow and bump the stack pointer.
+  // We have a hand-rolled stack check fragment here, because none of
+  // the canned ones suit this situation.
+  //
+  if ((Sp - WDS(Words)) < SpLim) {
+      // there is a return address in R2 in the event of a
+      // stack check failure.  The various stg_apply functions arrange
+      // this before calling stg_PAP_entry.
+      Sp_adj(-1); 
+      Sp(0) = R2;
+      jump stg_gc_unpt_r1;
+  }
+  Sp_adj(-Words);
+
+  // profiling
+  TICK_ENT_PAP();
+  LDV_ENTER(pap);
+  // Enter PAP cost centre 
+  ENTER_CCS_PAP_CL(pap);
+
+  R1 = StgPAP_fun(pap);
+
+  // Reload the stack 
+  W_ i;
+  W_ p;
+  p = pap + SIZEOF_StgHeader + OFFSET_StgPAP_payload;
+  i = 0;
+for:
+  if (i < Words) {
+    Sp(i) = W_[p];
+    p = p + WDS(1);
+    i = i + 1;
+    goto for;
+  }
+
+  // Off we go! 
+  TICK_ENT_VIA_NODE();
+
+#ifdef NO_ARG_REGS
+  jump %GET_ENTRY(R1);
+#else
+      W_ info;
+      info = %GET_FUN_INFO(R1);
+      W_ type;
+      type = TO_W_(StgFunInfoExtra_fun_type(info));
+      if (type == ARG_GEN) {
+         jump StgFunInfoExtra_slow_apply(info);
+      }
+      if (type == ARG_GEN_BIG) {
+         jump StgFunInfoExtra_slow_apply(info);
+      }
+      if (type == ARG_BCO) {
+         Sp_adj(-2);
+         Sp(1) = R1;
+         Sp(0) = stg_apply_interp_info;
+         jump stg_yield_to_interpreter;
+      }
+      jump W_[stg_ap_stack_entries + 
+               WDS(TO_W_(StgFunInfoExtra_fun_type(info)))];
+#endif
+}
+
+/* -----------------------------------------------------------------------------
+   Entry Code for an AP (a PAP with arity zero).
+
+   The entry code is very similar to a PAP, except there are no
+   further arguments on the stack to worry about, so the stack check
+   is simpler.  We must also push an update frame on the stack before
+   applying the function.
+   -------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_AP,/*special layout*/0,0,AP,"AP","AP")
+{
+  W_ Words;
+  W_ ap;
+    
+  ap = R1;
+  
+  Words = TO_W_(StgAP_n_args(ap));
+
+  /* 
+   * Check for stack overflow.  IMPORTANT: use a _NP check here,
+   * because if the check fails, we might end up blackholing this very
+   * closure, in which case we must enter the blackhole on return rather
+   * than continuing to evaluate the now-defunct closure.
+   */
+  STK_CHK_NP(WDS(Words) + SIZEOF_StgUpdateFrame);
+
+  PUSH_UPD_FRAME(Sp - SIZEOF_StgUpdateFrame, R1);
+  Sp = Sp - SIZEOF_StgUpdateFrame - WDS(Words);
+
+  TICK_ENT_AP();
+  LDV_ENTER(ap);
+
+  // Enter PAP cost centre
+  ENTER_CCS_PAP_CL(ap);   // ToDo: ENTER_CC_AP_CL 
+
+  R1 = StgAP_fun(ap);
+
+  // Reload the stack 
+  W_ i;
+  W_ p;
+  p = ap + SIZEOF_StgHeader + OFFSET_StgAP_payload;
+  i = 0;
+for:
+  if (i < Words) {
+    Sp(i) = W_[p];
+    p = p + WDS(1);
+    i = i + 1;
+    goto for;
+  }
+
+  // Off we go! 
+  TICK_ENT_VIA_NODE();
+
+#ifdef NO_ARG_REGS
+  jump %GET_ENTRY(R1);
+#else
+      W_ info;
+      info = %GET_FUN_INFO(R1);
+      W_ type;
+      type = TO_W_(StgFunInfoExtra_fun_type(info));
+      if (type == ARG_GEN) {
+         jump StgFunInfoExtra_slow_apply(info);
+      }
+      if (type == ARG_GEN_BIG) {
+         jump StgFunInfoExtra_slow_apply(info);
+      }
+      if (type == ARG_BCO) {
+         Sp_adj(-2);
+         Sp(1) = R1;
+         Sp(0) = stg_apply_interp_info;
+         jump stg_yield_to_interpreter;
+      }
+      jump W_[stg_ap_stack_entries + 
+               WDS(TO_W_(StgFunInfoExtra_fun_type(info)))];
+#endif
+}
+
+/* -----------------------------------------------------------------------------
+   Entry Code for an AP_STACK.
+
+   Very similar to a PAP and AP.  The layout is the same as PAP
+   and AP, except that the payload is a chunk of stack instead of
+   being described by the function's info table.  Like an AP,
+   there are no further arguments on the stack to worry about.
+   However, the function closure (ap->fun) does not necessarily point
+   directly to a function, so we have to enter it using stg_ap_0.
+   -------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_AP_STACK,/*special layout*/0,0,AP_STACK,"AP_STACK","AP_STACK")
+{
+  W_ Words;
+  W_ ap;
+
+  ap = R1;
+  
+  Words = StgAP_STACK_size(ap);
+
+  /* 
+   * Check for stack overflow.  IMPORTANT: use a _NP check here,
+   * because if the check fails, we might end up blackholing this very
+   * closure, in which case we must enter the blackhole on return rather
+   * than continuing to evaluate the now-defunct closure.
+   */
+  STK_CHK_NP(WDS(Words) + SIZEOF_StgUpdateFrame);
+
+  PUSH_UPD_FRAME(Sp - SIZEOF_StgUpdateFrame, R1);
+  Sp = Sp - SIZEOF_StgUpdateFrame - WDS(Words);
+
+  TICK_ENT_AP();
+  LDV_ENTER(ap);
+
+  // Enter PAP cost centre
+  ENTER_CCS_PAP_CL(ap);   // ToDo: ENTER_CC_AP_CL 
+
+  R1 = StgAP_STACK_fun(ap);
+
+  // Reload the stack
+  W_ i;
+  W_ p;
+  p = ap + SIZEOF_StgHeader + OFFSET_StgAP_STACK_payload;
+  i = 0;
+for:
+  if (i < Words) {
+    Sp(i) = W_[p];
+    p = p + WDS(1);
+    i = i + 1;
+    goto for;
+  }
+
+  // Off we go!
+  TICK_ENT_VIA_NODE();
+
+  ENTER();
+}
index fe41341..14031c2 100644 (file)
@@ -1,72 +1,29 @@
-// -----------------------------------------------------------------------------
-// Apply.h
-//
-// (c) The University of Glasgow 2002
-//
-// Helper bits for the generic apply code (AutoApply.hc)
-// -----------------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The University of Glasgow 2002-2004
+ *
+ * Declarations for things defined in AutoApply.cmm
+ *
+ * -------------------------------------------------------------------------- */
 
 #ifndef APPLY_H
 #define APPLY_H
 
-// Build a new PAP: function is in R1,p
-// ret addr and m arguments taking up n words are on the stack.
-#define BUILD_PAP(m,n,f)                       \
- {                                             \
-    StgPAP *pap;                               \
-    nat size, i;                               \
-    TICK_SLOW_CALL_BUILT_PAP();                        \
-    size = PAP_sizeW(n);                       \
-    HP_CHK_NP(size, Sp[0] = f;);               \
-    TICK_ALLOC_PAP(n, 0);                      \
-    pap = (StgPAP *) (Hp + 1 - size);          \
-    SET_HDR(pap, &stg_PAP_info, CCCS);         \
-    pap->arity = arity - m;                    \
-    pap->fun = R1.cl;                          \
-    pap->n_args = n;                           \
-    for (i = 0; i < n; i++) {                  \
-      pap->payload[i] = (StgClosure *)Sp[1+i]; \
-    }                                          \
-    R1.p = (P_)pap;                            \
-    Sp += 1 + n;                               \
-    JMP_(ENTRY_CODE(Sp[0]));                   \
- }
-
-// Copy the old PAP, build a new one with the extra arg(s)
-// ret addr and m arguments taking up n words are on the stack.
-#define NEW_PAP(m,n,f)                                 \
- {                                                     \
-     StgPAP *pap, *new_pap;                            \
-     nat size, i;                                      \
-     TICK_SLOW_CALL_NEW_PAP();                         \
-     pap = (StgPAP *)R1.p;                             \
-     size = PAP_sizeW(pap->n_args + n);                        \
-     HP_CHK_NP(size, Sp[0] = f;);                      \
-     TICK_ALLOC_PAP(n, 0);                             \
-     new_pap = (StgPAP *) (Hp + 1 - size);             \
-     SET_HDR(new_pap, &stg_PAP_info, CCCS);            \
-     new_pap->arity = arity - m;                       \
-     new_pap->n_args = pap->n_args + n;                        \
-     new_pap->fun = pap->fun;                          \
-     for (i = 0; i < pap->n_args; i++) {               \
-        new_pap->payload[i] = pap->payload[i];         \
-     }                                                 \
-     for (i = 0; i < n; i++) {                         \
-        new_pap->payload[pap->n_args+i] = (StgClosure *)Sp[1+i];       \
-     }                                                 \
-     R1.p = (P_)new_pap;                               \
-     Sp += n+1;                                                \
-     JMP_(ENTRY_CODE(Sp[0]));                          \
- }
-
 // canned slow entry points, indexed by arg type (ARG_P, ARG_PP, etc.)
-extern StgFun * stg_ap_stack_entries[];
+#ifdef IN_STG_CODE
+extern StgWord stg_ap_stack_entries[];
+#else
+extern StgFun *stg_ap_stack_entries[];
+#endif
 
 // canned register save code for heap check failure in a function
-extern StgFun * stg_stack_save_entries[];
+#ifdef IN_STG_CODE
+extern StgWord stg_stack_save_entries[];
+#else
+extern StgFun *stg_stack_save_entries[];
+#endif
 
 // canned bitmap for each arg type
 extern StgWord stg_arg_bitmaps[];
 
 #endif // APPLY_H
-
diff --git a/ghc/rts/Apply.hc b/ghc/rts/Apply.hc
deleted file mode 100644 (file)
index 30fbb50..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-// -----------------------------------------------------------------------------
-// Apply.hc
-//
-// (c) The University of Glasgow 2002
-//
-// Application-related bits.
-//
-// -----------------------------------------------------------------------------
-
-#include "Stg.h"
-#include "Rts.h"
-#include "RtsFlags.h"
-#include "Storage.h"
-#include "RtsUtils.h"
-#include "Printer.h"
-#include "Sanity.h"
-#include "Apply.h"
-
-#include <stdio.h>
-
-// ----------------------------------------------------------------------------
-// Evaluate a closure and return it.
-//
-//      stg_ap_0_info   <--- Sp
-//
-// NOTE: this needs to be a polymorphic return point, because we can't
-// be sure that the thing being evaluated is not a function.
-
-// These names are just to keep VEC_POLY_INFO_TABLE() happy - all the
-// entry points in the polymorphic info table point to the same code.
-#define stg_ap_0_0_ret stg_ap_0_ret
-#define stg_ap_0_1_ret stg_ap_0_ret
-#define stg_ap_0_2_ret stg_ap_0_ret
-#define stg_ap_0_3_ret stg_ap_0_ret
-#define stg_ap_0_4_ret stg_ap_0_ret
-#define stg_ap_0_5_ret stg_ap_0_ret
-#define stg_ap_0_6_ret stg_ap_0_ret
-#define stg_ap_0_7_ret stg_ap_0_ret
-
-VEC_POLY_INFO_TABLE(stg_ap_0,
-              MK_SMALL_BITMAP(0/*framsize*/, 0/*bitmap*/),
-              0,0,0,RET_SMALL,,EF_);
-F_
-stg_ap_0_ret(void)
-{ 
-    // fn is in R1, no args on the stack
-    StgInfoTable *info;
-    nat arity;
-    FB_;
-
-    IF_DEBUG(apply,fprintf(stderr, "stg_ap_0_ret... "); printClosure(R1.cl));
-    IF_DEBUG(sanity,checkStackChunk(Sp+1,CurrentTSO->stack + CurrentTSO->stack_size));
-
-    Sp++;
-    ENTER();
-    FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Entry Code for a PAP.
-
-   This entry code is *only* called by one of the stg_ap functions.
-   On entry: Sp points to the remaining arguments on the stack.  If
-   the stack check fails, we can just push the PAP on the stack and
-   return to the scheduler.
-
-   On entry: R1 points to the PAP.  The rest of the function's
-   arguments (apart from those that are already in the PAP) are on the
-   stack, starting at Sp[0].  R2 contains an info table which
-   describes these arguments, which is used in the event that the
-   stack check in the entry code below fails.  The info table is
-   currently one of the stg_ap_*_ret family, as this code is always
-   entered from those functions.
-
-   The idea is to copy the chunk of stack from the PAP object onto the
-   stack / into registers, and enter the function.
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE(stg_PAP_info,stg_PAP_entry,/*special layout*/0,0,PAP,,EF_,"PAP","PAP");
-STGFUN(stg_PAP_entry)
-{
-  nat Words;
-  StgPtr p;
-  nat i;
-  StgPAP *pap;
-  FB_
-    
-  pap = (StgPAP *) R1.p;
-
-  Words = pap->n_args;
-
-  // Check for stack overflow and bump the stack pointer.
-  // We have a hand-rolled stack check fragment here, because none of
-  // the canned ones suit this situation.
-  if ((Sp - Words) < SpLim) {
-      // there is a return address in R2 in the event of a
-      // stack check failure.  The various stg_apply functions arrange
-      // this before calling stg_PAP_entry.
-      Sp--; 
-      Sp[0] = R2.w;
-      JMP_(stg_gc_unpt_r1);
-  }
-  Sp -= Words;
-
-  // profiling
-  TICK_ENT_PAP(pap);
-  LDV_ENTER(pap);
-  // Enter PAP cost centre -- lexical scoping only
-  ENTER_CCS_PAP_CL(pap);
-
-  R1.cl = pap->fun;
-  p = (P_)(pap->payload);
-
-  // Reload the stack
-  for (i=0; i<Words; i++) {
-      Sp[i] = (W_) *p++;
-  }
-
-  // Off we go!
-  TICK_ENT_VIA_NODE();
-
-#ifdef NO_ARG_REGS
-  JMP_(GET_ENTRY(R1.cl));
-#else
-  {
-      StgFunInfoTable *info;
-      info = get_fun_itbl(R1.cl);
-      if (info->fun_type == ARG_GEN || info->fun_type == ARG_GEN_BIG) {
-         JMP_(info->slow_apply);
-      } else if (info->fun_type == ARG_BCO) {
-         Sp -= 2;
-         Sp[1] = R1.w;
-         Sp[0] = (W_)&stg_apply_interp_info;
-         JMP_(stg_yield_to_interpreter);
-      } else {
-         JMP_(stg_ap_stack_entries[info->fun_type]);
-      }
-  }
-#endif
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Entry Code for an AP (a PAP with arity zero).
-
-   The entry code is very similar to a PAP, except there are no
-   further arguments on the stack to worry about, so the stack check
-   is simpler.  We must also push an update frame on the stack before
-   applying the function.
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE(stg_AP_info,stg_AP_entry,/*special layout*/0,0,AP,,EF_,"AP","AP");
-STGFUN(stg_AP_entry)
-{
-  nat Words;
-  P_ p;
-  nat i;
-  StgAP *ap;
-
-  FB_
-    
-  ap = (StgAP *) R1.p;
-  
-  Words = ap->n_args;
-
-  // Check for stack overflow.  IMPORTANT: use a _NP check here,
-  // because if the check fails, we might end up blackholing this very
-  // closure, in which case we must enter the blackhole on return rather
-  // than continuing to evaluate the now-defunct closure.
-  STK_CHK_NP(Words+sizeofW(StgUpdateFrame),);
-
-  PUSH_UPD_FRAME(R1.p, 0);
-  Sp -= sizeofW(StgUpdateFrame) + Words;
-
-  TICK_ENT_AP(ap);
-  LDV_ENTER(ap);
-
-  // Enter PAP cost centre -- lexical scoping only
-  ENTER_CCS_PAP_CL(ap);   /* ToDo: ENTER_CC_AP_CL */
-
-  R1.cl = ap->fun;
-  p = (P_)(ap->payload);
-
-  // Reload the stack
-  for (i=0; i<Words; i++) Sp[i] = (W_) *p++;
-
-  // Off we go!
-  TICK_ENT_VIA_NODE();
-
-#ifdef NO_ARG_REGS
-  JMP_(GET_ENTRY(R1.cl));
-#else
-  {
-      StgFunInfoTable *info;
-      info = get_fun_itbl(R1.cl);
-      if (info->fun_type == ARG_GEN || info->fun_type == ARG_GEN_BIG) {
-         JMP_(info->slow_apply);
-      } else if (info->fun_type == ARG_BCO) {
-         Sp -= 2;
-         Sp[1] = R1.w;
-         Sp[0] = (W_)&stg_apply_interp_info;
-         JMP_(stg_yield_to_interpreter);
-      } else {
-         JMP_(stg_ap_stack_entries[info->fun_type]);
-      }
-  }
-#endif
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Entry Code for an AP_STACK.
-
-   Very similar to a PAP and AP.  The layout is the same as PAP
-   and AP, except that the payload is a chunk of stack instead of
-   being described by the function's info table.  Like an AP,
-   there are no further arguments on the stack to worry about.
-   However, the function closure (ap->fun) does not necessarily point
-   directly to a function, so we have to enter it using stg_ap_0.
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE(stg_AP_STACK_info,stg_AP_STACK_entry,/*special layout*/0,0,AP_STACK,,EF_,"AP_STACK","AP_STACK");
-STGFUN(stg_AP_STACK_entry)
-{
-  nat Words;
-  P_ p;
-  nat i;
-  StgAP_STACK *ap;
-
-  FB_
-    
-  ap = (StgAP_STACK *) R1.p;
-  
-  Words = ap->size;
-
-  // Check for stack overflow.  IMPORTANT: use a _NP check here,
-  // because if the check fails, we might end up blackholing this very
-  // closure, in which case we must enter the blackhole on return rather
-  // than continuing to evaluate the now-defunct closure.
-  STK_CHK_NP(Words+sizeofW(StgUpdateFrame),);
-
-  PUSH_UPD_FRAME(R1.p, 0);
-  Sp -= sizeofW(StgUpdateFrame) + Words;
-
-  TICK_ENT_AP(ap);
-  LDV_ENTER(ap);
-
-  // Enter PAP cost centre -- lexical scoping only */
-  ENTER_CCS_PAP_CL(ap);   /* ToDo: ENTER_CC_AP_STACK_CL */
-
-  R1.cl = ap->fun;
-  p = (P_)(ap->payload);
-
-  // Reload the stack
-  for (i=0; i<Words; i++) Sp[i] = (W_) *p++;
-
-  // Off we go!
-  TICK_ENT_VIA_NODE();
-  ENTER();
-  FE_
-}
diff --git a/ghc/rts/AutoApply.h b/ghc/rts/AutoApply.h
new file mode 100644 (file)
index 0000000..d0090b2
--- /dev/null
@@ -0,0 +1,80 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The University of Glasgow 2002-2004
+ *
+ * Helper bits for the generic apply code (AutoApply.hc)
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef AUTOAPPLY_H
+#define AUTOAPPLY_H
+
+// Build a new PAP: function is in R1
+// ret addr and m arguments taking up n words are on the stack.
+// NB. x is a dummy argument attached to the 'for' label so that
+// BUILD_PAP can be used multiple times in the same function.
+#define BUILD_PAP(m,n,f,x)                             \
+    W_ pap;                                            \
+    W_ size;                                           \
+    W_ i;                                              \
+    size = SIZEOF_StgPAP + WDS(n);                     \
+    HP_CHK_NP_ASSIGN_SP0(size,f);                      \
+    TICK_ALLOC_HEAP_NOCTR(BYTES_TO_WDS(size));         \
+    TICK_ALLOC_PAP(n+1 /* +1 for the FUN */, 0);       \
+    pap = Hp + WDS(1) - size;                          \
+    SET_HDR(pap, stg_PAP_info, W_[CCCS]);              \
+    StgPAP_arity(pap) = HALF_W_(arity - m);            \
+    StgPAP_fun(pap)   = R1;                            \
+    StgPAP_n_args(pap) = HALF_W_(n);                   \
+    i = 0;                                             \
+  for##x:                                              \
+    if (i < n) {                                       \
+       StgPAP_payload(pap,i) = Sp(1+i);                \
+       i = i + 1;                                      \
+       goto for##x;                                    \
+    }                                                  \
+    R1 = pap;                                          \
+    Sp_adj(1 + n);                                     \
+    jump %ENTRY_CODE(Sp(0));
+
+// Copy the old PAP, build a new one with the extra arg(s)
+// ret addr and m arguments taking up n words are on the stack.
+// NB. x is a dummy argument attached to the 'for' label so that
+// BUILD_PAP can be used multiple times in the same function.
+#define NEW_PAP(m,n,f,x)                                       \
+     W_ pap;                                                   \
+     W_ new_pap;                                               \
+     W_ size;                                                  \
+     W_ i;                                                     \
+     pap = R1;                                                 \
+     size = SIZEOF_StgPAP + WDS(TO_W_(StgPAP_n_args(pap))) + WDS(n);   \
+     HP_CHK_NP_ASSIGN_SP0(size,f);                             \
+     TICK_ALLOC_HEAP_NOCTR(BYTES_TO_WDS(size));                        \
+     TICK_ALLOC_PAP(n+1 /* +1 for the FUN */, 0);              \
+     new_pap = Hp + WDS(1) - size;                             \
+     SET_HDR(new_pap, stg_PAP_info, W_[CCCS]);                 \
+     StgPAP_arity(new_pap) = HALF_W_(arity - m);               \
+     W_ n_args;                                                        \
+     n_args = TO_W_(StgPAP_n_args(pap));                       \
+     StgPAP_n_args(new_pap) = HALF_W_(n_args + n);             \
+     StgPAP_fun(new_pap) = StgPAP_fun(pap);                    \
+     i = 0;                                                    \
+   for1##x:                                                    \
+     if (i < n_args) {                                         \
+         StgPAP_payload(new_pap,i) = StgPAP_payload(pap,i);    \
+        i = i + 1;                                             \
+        goto for1##x;                                          \
+     }                                                         \
+     i = 0;                                                    \
+   for2##x:                                                    \
+     if (i < n) {                                              \
+        StgPAP_payload(new_pap,n_args+i) = Sp(1+i);            \
+         i = i + 1;                                            \
+         goto for2##x;                                         \
+     }                                                         \
+     R1 = new_pap;                                             \
+     Sp_adj(n+1);                                              \
+     jump %ENTRY_CODE(Sp(0));
+
+#endif // APPLY_H
+
index eea28ef..450bf74 100644 (file)
 #ifndef __CAPABILITY_H__
 #define __CAPABILITY_H__
 
-#if !defined(SMP)
-extern Capability MainCapability;
-#endif
-
 // Initialised the available capabilities.
 //
 extern void initCapabilities( void );
index f8660e6..41b66f1 100644 (file)
@@ -4,8 +4,8 @@
  * Copyright (c) 1994-2002.
  *
  * $RCSfile: Disassembler.c,v $
- * $Revision: 1.27 $
- * $Date: 2003/03/25 17:04:09 $
+ * $Revision: 1.28 $
+ * $Date: 2004/08/13 13:09:46 $
  * ---------------------------------------------------------------------------*/
 
 #ifdef DEBUG
@@ -140,9 +140,6 @@ disInstr ( StgBCO *bco, int pc )
       case bci_PUSH_APPLY_PPPPPP:
          fprintf(stderr, "PUSH_APPLY_PPPPPP\n");
          break;
-      case bci_PUSH_APPLY_PPPPPPP:
-         fprintf(stderr, "PUSH_APPLY_PPPPPPP\n");
-         break;
       case bci_SLIDE: 
          fprintf(stderr, "SLIDE     %d down by %d\n", instrs[pc], instrs[pc+1] );
          pc += 2; break;
diff --git a/ghc/rts/Exception.cmm b/ghc/rts/Exception.cmm
new file mode 100644 (file)
index 0000000..04f328b
--- /dev/null
@@ -0,0 +1,396 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2004
+ *
+ * Exception support
+ *
+ * This file is written in a subset of C--, extended with various
+ * features specific to GHC.  It is compiled by GHC directly.  For the
+ * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "Cmm.h"
+
+/* -----------------------------------------------------------------------------
+   Exception Primitives
+
+   A thread can request that asynchronous exceptions not be delivered
+   ("blocked") for the duration of an I/O computation.  The primitive
+   
+       blockAsyncExceptions# :: IO a -> IO a
+
+   is used for this purpose.  During a blocked section, asynchronous
+   exceptions may be unblocked again temporarily:
+
+       unblockAsyncExceptions# :: IO a -> IO a
+
+   Furthermore, asynchronous exceptions are blocked automatically during
+   the execution of an exception handler.  Both of these primitives
+   leave a continuation on the stack which reverts to the previous
+   state (blocked or unblocked) on exit.
+
+   A thread which wants to raise an exception in another thread (using
+   killThread#) must block until the target thread is ready to receive
+   it.  The action of unblocking exceptions in a thread will release all
+   the threads waiting to deliver exceptions to that thread.
+
+   -------------------------------------------------------------------------- */
+
+INFO_TABLE_RET( stg_unblockAsyncExceptionszh_ret,
+               0/*framesize*/, 0/*bitmap*/, RET_SMALL )
+{
+    ASSERT(StgTSO_blocked_exceptions(CurrentTSO) != NULL);
+#if defined(GRAN) || defined(PAR)
+    foreign "C" awakenBlockedQueue(StgTSO_blocked_exceptions(CurrentTSO) "ptr", 
+                                  NULL "ptr"); 
+#else
+    foreign "C" awakenBlockedQueue(StgTSO_blocked_exceptions(CurrentTSO) "ptr");
+#endif
+    StgTSO_blocked_exceptions(CurrentTSO) = NULL;
+#ifdef REG_R1
+    Sp_adj(1);
+    jump %ENTRY_CODE(Sp(0));
+#else
+    Sp(1) = Sp(0);
+    Sp_adj(1);
+    jump %ENTRY_CODE(Sp(1));
+#endif
+}
+
+INFO_TABLE_RET( stg_blockAsyncExceptionszh_ret,
+               0/*framesize*/, 0/*bitmap*/, RET_SMALL )
+{
+    ASSERT(StgTSO_blocked_exceptions(CurrentTSO) == NULL);
+    StgTSO_blocked_exceptions(CurrentTSO) = END_TSO_QUEUE;
+#ifdef REG_R1
+    Sp_adj(1);
+    jump %ENTRY_CODE(Sp(0));
+#else
+    Sp(1) = Sp(0);
+    Sp_adj(1);
+    jump %ENTRY_CODE(Sp(1));
+#endif
+}
+
+blockAsyncExceptionszh_fast
+{
+    /* Args: R1 :: IO a */
+    STK_CHK_GEN( WDS(2)/* worst case */, R1_PTR, blockAsyncExceptionszh_fast);
+
+    if (StgTSO_blocked_exceptions(CurrentTSO) == NULL) {
+      StgTSO_blocked_exceptions(CurrentTSO) = END_TSO_QUEUE;
+      /* avoid growing the stack unnecessarily */
+      if (Sp(0) == stg_blockAsyncExceptionszh_ret_info) {
+       Sp_adj(1);
+      } else {
+       Sp_adj(-1);
+       Sp(0) = stg_unblockAsyncExceptionszh_ret_info;
+      }
+    }
+    Sp_adj(-1);
+    TICK_UNKNOWN_CALL();
+    TICK_SLOW_CALL_v();
+    jump RET_LBL(stg_ap_v);
+}
+
+unblockAsyncExceptionszh_fast
+{
+    /* Args: R1 :: IO a */
+    STK_CHK_GEN( WDS(2), R1_PTR, unblockAsyncExceptionszh_fast);
+
+    if (StgTSO_blocked_exceptions(CurrentTSO) != NULL) {
+#if defined(GRAN) || defined(PAR)
+      foreign "C" awakenBlockedQueue(StgTSO_blocked_exceptions(CurrentTSO) "ptr", 
+                                    StgTSO_block_info(CurrentTSO) "ptr");
+#else
+      foreign "C" awakenBlockedQueue(StgTSO_blocked_exceptions(CurrentTSO) "ptr");
+#endif
+      StgTSO_blocked_exceptions(CurrentTSO) = NULL;
+
+      /* avoid growing the stack unnecessarily */
+      if (Sp(0) == stg_unblockAsyncExceptionszh_ret_info) {
+       Sp_adj(1);
+      } else {
+       Sp_adj(-1);
+       Sp(0) = stg_blockAsyncExceptionszh_ret_info;
+      }
+    }
+    Sp_adj(-1);
+    TICK_UNKNOWN_CALL();
+    TICK_SLOW_CALL_v();
+    jump RET_LBL(stg_ap_v);
+}
+
+
+#define interruptible(what_next)               \
+        (   what_next == BlockedOnMVar         \
+         || what_next == BlockedOnException    \
+         || what_next == BlockedOnRead         \
+         || what_next == BlockedOnWrite                \
+         || what_next == BlockedOnDelay                \
+         || what_next == BlockedOnDoProc)
+
+killThreadzh_fast
+{
+  /* args: R1 = TSO to kill, R2 = Exception */
+
+  W_ why_blocked;
+
+  /* This thread may have been relocated.
+   * (see Schedule.c:threadStackOverflow)
+   */
+ while:
+  if (StgTSO_what_next(R1) == ThreadRelocated::I16) {
+    R1 = StgTSO_link(R1);
+    goto while;
+  }
+
+  /* Determine whether this thread is interruptible or not */
+
+  /* If the target thread is currently blocking async exceptions,
+   * we'll have to block until it's ready to accept them.  The
+   * exception is interruptible threads - ie. those that are blocked
+   * on some resource.
+   */
+  why_blocked = TO_W_(StgTSO_why_blocked(R1));
+  if (StgTSO_blocked_exceptions(R1) != NULL && !interruptible(why_blocked))
+  {
+      StgTSO_link(CurrentTSO) = StgTSO_blocked_exceptions(R1);
+      StgTSO_blocked_exceptions(R1) = CurrentTSO;
+      
+      StgTSO_why_blocked(CurrentTSO) = BlockedOnException::I16;
+      StgTSO_block_info(CurrentTSO) = R1;
+      
+      BLOCK( R1_PTR & R2_PTR, killThreadzh_fast );
+  }
+
+  /* Killed threads turn into zombies, which might be garbage
+   * collected at a later date.  That's why we don't have to
+   * explicitly remove them from any queues they might be on.
+   */
+
+  /* We might have killed ourselves.  In which case, better be *very*
+   * careful.  If the exception killed us, then return to the scheduler.
+   * If the exception went to a catch frame, we'll just continue from
+   * the handler.
+   */
+  if (R1 == CurrentTSO) {
+       SAVE_THREAD_STATE();
+       foreign "C" raiseAsyncWithLock(R1 "ptr", R2 "ptr");
+       if (StgTSO_what_next(CurrentTSO) == ThreadKilled::I16) {
+               R1 = ThreadFinished;
+               jump StgReturn;
+       } else {
+               LOAD_THREAD_STATE();
+               ASSERT(StgTSO_what_next(CurrentTSO) == ThreadRunGHC::I16);
+               jump %ENTRY_CODE(Sp(0));
+       }
+  } else {
+       foreign "C" raiseAsyncWithLock(R1 "ptr", R2 "ptr");
+  }
+
+  jump %ENTRY_CODE(Sp(0));
+}
+
+/* -----------------------------------------------------------------------------
+   Catch frames
+   -------------------------------------------------------------------------- */
+
+#ifdef REG_R1
+#define CATCH_FRAME_ENTRY_TEMPLATE(label,ret)  \
+   label                                       \
+   {                                           \
+      Sp = Sp + SIZEOF_StgCatchFrame;          \
+      jump ret;                                        \
+   }
+#else
+#define CATCH_FRAME_ENTRY_TEMPLATE(label,ret)  \
+   label                                       \
+   {                                           \
+      W_ rval;                                 \
+      rval = Sp(0);                            \
+      Sp_adj(1);                               \
+      Sp = Sp + SIZEOF_StgCatchFrame - WDS(1);  \
+      Sp(0) = rval;                            \
+      jump ret;                                        \
+   }
+#endif
+
+#ifdef REG_R1
+#define SP_OFF 0
+#else
+#define SP_OFF 1
+#endif
+
+CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_0_ret,%RET_VEC(Sp(SP_OFF),0))
+CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_1_ret,%RET_VEC(Sp(SP_OFF),1))
+CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_2_ret,%RET_VEC(Sp(SP_OFF),2))
+CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_3_ret,%RET_VEC(Sp(SP_OFF),3))
+CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_4_ret,%RET_VEC(Sp(SP_OFF),4))
+CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_5_ret,%RET_VEC(Sp(SP_OFF),5))
+CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_6_ret,%RET_VEC(Sp(SP_OFF),6))
+CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_7_ret,%RET_VEC(Sp(SP_OFF),7))
+
+#if MAX_VECTORED_RTN > 8
+#error MAX_VECTORED_RTN has changed: please modify stg_catch_frame too.
+#endif
+
+#if defined(PROFILING)
+#define CATCH_FRAME_BITMAP 7
+#define CATCH_FRAME_WORDS  4
+#else
+#define CATCH_FRAME_BITMAP 1
+#define CATCH_FRAME_WORDS  2
+#endif
+
+/* Catch frames are very similar to update frames, but when entering
+ * one we just pop the frame off the stack and perform the correct
+ * kind of return to the activation record underneath us on the stack.
+ */
+
+INFO_TABLE_RET(stg_catch_frame,
+              CATCH_FRAME_WORDS, CATCH_FRAME_BITMAP,
+              CATCH_FRAME,
+              stg_catch_frame_0_ret,
+              stg_catch_frame_1_ret,
+              stg_catch_frame_2_ret,
+              stg_catch_frame_3_ret,
+              stg_catch_frame_4_ret,
+              stg_catch_frame_5_ret,
+              stg_catch_frame_6_ret,
+              stg_catch_frame_7_ret)
+CATCH_FRAME_ENTRY_TEMPLATE(,%ENTRY_CODE(Sp(SP_OFF)))
+
+/* -----------------------------------------------------------------------------
+ * The catch infotable
+ *
+ * This should be exactly the same as would be generated by this STG code
+ *
+ * catch = {x,h} \n {} -> catch#{x,h}
+ *
+ * It is used in deleteThread when reverting blackholes.
+ * -------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_catch,2,0,FUN,"catch","catch")
+{
+  R2 = StgClosure_payload(R1,1); /* h */
+  R1 = StgClosure_payload(R1,0); /* x */
+  jump catchzh_fast;
+}
+
+catchzh_fast
+{
+    /* args: R1 = m :: IO a, R2 = handler :: Exception -> IO a */
+    STK_CHK_GEN(SIZEOF_StgCatchFrame + WDS(1), R1_PTR & R2_PTR, catchzh_fast);
+  
+    /* Set up the catch frame */
+    Sp = Sp - SIZEOF_StgCatchFrame;
+    SET_HDR(Sp,stg_catch_frame_info,CCCS);
+    
+    StgCatchFrame_handler(Sp) = R2;
+    StgCatchFrame_exceptions_blocked(Sp) = 
+       (StgTSO_blocked_exceptions(CurrentTSO) != NULL);
+    TICK_CATCHF_PUSHED();
+
+    /* Apply R1 to the realworld token */
+    Sp_adj(-1);
+    TICK_UNKNOWN_CALL();
+    TICK_SLOW_CALL_v();
+    jump RET_LBL(stg_ap_v);
+}      
+
+/* -----------------------------------------------------------------------------
+ * The raise infotable
+ * 
+ * This should be exactly the same as would be generated by this STG code
+ *
+ *   raise = {err} \n {} -> raise#{err}
+ *
+ * It is used in raisezh_fast to update thunks on the update list
+ * -------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_raise,1,0,THUNK,"raise","raise")
+{
+  R1 = StgClosure_payload(R1,0);
+  jump raisezh_fast;
+}
+
+raisezh_fast
+{
+    W_ handler;
+    W_ raise_closure;
+    W_ frame_type;
+    /* args : R1 :: Exception */
+
+
+#if defined(PROFILING)
+    /* Debugging tool: on raising an  exception, show where we are. */
+
+    /* ToDo: currently this is a hack.  Would be much better if
+     * the info was only displayed for an *uncaught* exception.
+     */
+    if (RtsFlags_ProfFlags_showCCSOnException(RtsFlags)) {
+      foreign "C" fprintCCS(stderr,CCCS);
+    }
+#endif
+
+    StgTSO_sp(CurrentTSO) = Sp;
+    frame_type = foreign "C" raiseExceptionHelper(CurrentTSO "ptr", R1 "ptr");
+    Sp = StgTSO_sp(CurrentTSO);
+
+    if (frame_type == STOP_FRAME) {
+       /* We've stripped the entire stack, the thread is now dead. */
+       Sp = CurrentTSO + OFFSET_StgTSO_stack 
+               + WDS(StgTSO_stack_size(CurrentTSO)) - WDS(1);
+       Sp(0) = R1;             /* save the exception */
+       StgTSO_what_next(CurrentTSO) = ThreadKilled::I16;
+       SAVE_THREAD_STATE();    /* inline! */
+       R1 = ThreadFinished;
+       jump StgReturn;
+    }
+
+    /* Ok, Sp points to the enclosing CATCH_FRAME.  Pop everything down to
+     * and including this frame, update Su, push R1, and enter the handler.
+     */
+    handler = StgCatchFrame_handler(Sp);
+
+    /* Restore the blocked/unblocked state for asynchronous exceptions
+     * at the CATCH_FRAME.  
+     *
+     * If exceptions were unblocked, arrange that they are unblocked
+     * again after executing the handler by pushing an
+     * unblockAsyncExceptions_ret stack frame.
+     */
+    W_ frame;
+    frame = Sp;
+    Sp = Sp + SIZEOF_StgCatchFrame;
+
+    if (StgCatchFrame_exceptions_blocked(frame) == 0) {
+      Sp_adj(-1);
+      Sp(0) = stg_unblockAsyncExceptionszh_ret_info;
+    }
+
+    /* Ensure that async excpetions are blocked when running the handler.
+    */
+    if (StgTSO_blocked_exceptions(CurrentTSO) == NULL) {
+      StgTSO_blocked_exceptions(CurrentTSO) = END_TSO_QUEUE;
+    }
+
+    /* Call the handler, passing the exception value and a realworld
+     * token as arguments.
+     */
+    Sp_adj(-1);
+    Sp(0) = R1;
+    R1 = handler;
+    Sp_adj(-1);
+    TICK_UNKNOWN_CALL();
+    TICK_SLOW_CALL_pv();
+    jump RET_LBL(stg_ap_pv);
+}
+
+raiseIOzh_fast
+{
+  /* Args :: R1 :: Exception */
+  jump raisezh_fast;
+}
index ea22223..c20be8f 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Exception.h,v 1.8 2004/03/01 14:18:35 simonmar Exp $
+ * $Id: Exception.h,v 1.9 2004/08/13 13:09:46 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2000
  *
@@ -33,3 +33,4 @@ interruptible(StgTSO *t)
     return 0;
   }
 }
+
diff --git a/ghc/rts/Exception.hc b/ghc/rts/Exception.hc
deleted file mode 100644 (file)
index 2350aa3..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: Exception.hc,v 1.29 2003/06/26 20:47:08 panne Exp $
- *
- * (c) The GHC Team, 1998-2000
- *
- * Exception support
- *
- * ---------------------------------------------------------------------------*/
-
-#include "Stg.h"
-#include "Rts.h"
-#include "Exception.h"
-#include "Schedule.h"
-#include "StgRun.h"
-#include "Storage.h"
-#include "RtsUtils.h"
-#include "RtsFlags.h"
-#if defined(PAR)
-# include "FetchMe.h"
-#endif
-#if defined(PROFILING)
-# include "Profiling.h"
-#endif
-
-/* -----------------------------------------------------------------------------
-   Exception Primitives
-
-   A thread can request that asynchronous exceptions not be delivered
-   ("blocked") for the duration of an I/O computation.  The primitive
-   
-       blockAsyncExceptions# :: IO a -> IO a
-
-   is used for this purpose.  During a blocked section, asynchronous
-   exceptions may be unblocked again temporarily:
-
-       unblockAsyncExceptions# :: IO a -> IO a
-
-   Furthermore, asynchronous exceptions are blocked automatically during
-   the execution of an exception handler.  Both of these primitives
-   leave a continuation on the stack which reverts to the previous
-   state (blocked or unblocked) on exit.
-
-   A thread which wants to raise an exception in another thread (using
-   killThread#) must block until the target thread is ready to receive
-   it.  The action of unblocking exceptions in a thread will release all
-   the threads waiting to deliver exceptions to that thread.
-
-   -------------------------------------------------------------------------- */
-
-FN_(blockAsyncExceptionszh_fast)
-{
-  FB_
-    /* Args: R1 :: IO a */
-    STK_CHK_GEN( 2/* worst case */, R1_PTR, blockAsyncExceptionszh_fast);
-
-    if (CurrentTSO->blocked_exceptions == NULL) {
-      CurrentTSO->blocked_exceptions = END_TSO_QUEUE;
-      /* avoid growing the stack unnecessarily */
-      if (Sp[0] == (W_)&stg_blockAsyncExceptionszh_ret_info) {
-       Sp++;
-      } else {
-       Sp--;
-       Sp[0] = (W_)&stg_unblockAsyncExceptionszh_ret_info;
-      }
-    }
-    Sp--;
-    JMP_(stg_ap_v_ret);
-  FE_
-}
-
-INFO_TABLE_RET( \
-  stg_unblockAsyncExceptionszh_ret_info, \
-  stg_unblockAsyncExceptionszh_ret_entry, \
-  MK_SMALL_BITMAP(0/*framesize*/, 0/*bitmap*/), \
-  0, 0, 0, RET_SMALL, , EF_, 0, 0 \
-);
-
-FN_(stg_unblockAsyncExceptionszh_ret_entry)
-{
-  FB_
-    ASSERT(CurrentTSO->blocked_exceptions != NULL);
-#if defined(GRAN)
-      awakenBlockedQueue(CurrentTSO->blocked_exceptions, 
-                        (StgClosure*)NULL); 
-#elif defined(PAR)
-      /* we don't need node info (2nd arg) in this case
-        (note that CurrentTSO->block_info.closure isn't always set) */
-      awakenBlockedQueue(CurrentTSO->blocked_exceptions, 
-                        (StgClosure*)NULL); 
-#else
-    awakenBlockedQueue(CurrentTSO->blocked_exceptions);
-#endif
-    CurrentTSO->blocked_exceptions = NULL;
-#ifdef REG_R1
-    Sp++;
-    JMP_(ENTRY_CODE(Sp[0]));
-#else
-    Sp[1] = Sp[0];
-    Sp++;
-    JMP_(ENTRY_CODE(Sp[1]));
-#endif
-  FE_
-}
-
-FN_(unblockAsyncExceptionszh_fast)
-{
-  FB_
-    /* Args: R1 :: IO a */
-    STK_CHK_GEN(2, R1_PTR, unblockAsyncExceptionszh_fast);
-
-    if (CurrentTSO->blocked_exceptions != NULL) {
-#if defined(GRAN)
-      awakenBlockedQueue(CurrentTSO->blocked_exceptions, 
-                        CurrentTSO->block_info.closure);
-#elif defined(PAR)
-      // is CurrentTSO->block_info.closure always set to the node
-      // holding the blocking queue !? -- HWL
-      awakenBlockedQueue(CurrentTSO->blocked_exceptions, 
-                        CurrentTSO->block_info.closure);
-#else
-      awakenBlockedQueue(CurrentTSO->blocked_exceptions);
-#endif
-      CurrentTSO->blocked_exceptions = NULL;
-
-      /* avoid growing the stack unnecessarily */
-      if (Sp[0] == (W_)&stg_unblockAsyncExceptionszh_ret_info) {
-       Sp++;
-      } else {
-       Sp--;   
-       Sp[0] = (W_)&stg_blockAsyncExceptionszh_ret_info;
-      }
-    }
-    Sp--;
-    JMP_(stg_ap_v_ret);
-  FE_
-}
-
-INFO_TABLE_RET( \
-  stg_blockAsyncExceptionszh_ret_info, \
-  stg_blockAsyncExceptionszh_ret_entry, \
-  MK_SMALL_BITMAP(0/*framesize*/, 0/*bitmap*/), \
-  0, 0, 0, RET_SMALL, , EF_, 0, 0 \
-);
-
-FN_(stg_blockAsyncExceptionszh_ret_entry)
-{
-  FB_
-    ASSERT(CurrentTSO->blocked_exceptions == NULL);
-    CurrentTSO->blocked_exceptions = END_TSO_QUEUE;
-#ifdef REG_R1
-    Sp++;
-    JMP_(ENTRY_CODE(Sp[0]));
-#else
-    Sp[1] = Sp[0];
-    Sp++;
-    JMP_(ENTRY_CODE(Sp[1]));
-#endif
-  FE_
-}
-
-FN_(killThreadzh_fast)
-{
-  FB_
-  /* args: R1.p = TSO to kill, R2.p = Exception */
-
-  /* This thread may have been relocated.
-   * (see Schedule.c:threadStackOverflow)
-   */
-  while (R1.t->what_next == ThreadRelocated) {
-    R1.t = R1.t->link;
-  }
-
-  /* If the target thread is currently blocking async exceptions,
-   * we'll have to block until it's ready to accept them.  The
-   * exception is interruptible threads - ie. those that are blocked
-   * on some resource.
-   */
-  if (R1.t->blocked_exceptions != NULL && !interruptible(R1.t) ) {
-    
-    /* ToDo (SMP): locking if destination thread is currently
-     * running...
-     */
-    CurrentTSO->link = R1.t->blocked_exceptions;
-    R1.t->blocked_exceptions = CurrentTSO;
-
-    CurrentTSO->why_blocked = BlockedOnException;
-    CurrentTSO->block_info.tso = R1.t;
-    
-    BLOCK( R1_PTR | R2_PTR, killThreadzh_fast );
-  }
-
-  /* Killed threads turn into zombies, which might be garbage
-   * collected at a later date.  That's why we don't have to
-   * explicitly remove them from any queues they might be on.
-   */
-
-  /* We might have killed ourselves.  In which case, better be *very*
-   * careful.  If the exception killed us, then return to the scheduler.
-   * If the exception went to a catch frame, we'll just continue from
-   * the handler.
-   */
-  if (R1.t == CurrentTSO) {
-       SaveThreadState();      /* inline! */
-       STGCALL2(raiseAsyncWithLock, R1.t, R2.cl);
-       if (CurrentTSO->what_next == ThreadKilled) {
-               R1.w = ThreadFinished;
-               JMP_(StgReturn);
-       } else {
-               LoadThreadState();
-               ASSERT(CurrentTSO->what_next == ThreadRunGHC);
-               JMP_(ENTRY_CODE(Sp[0]));
-       }
-  } else {
-       STGCALL2(raiseAsyncWithLock, R1.t, R2.cl);
-  }
-
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-
-
-/* -----------------------------------------------------------------------------
-   Catch frames
-   -------------------------------------------------------------------------- */
-
-#ifdef REG_R1
-#define CATCH_FRAME_ENTRY_TEMPLATE(label,ret)  \
-   FN_(label);                                 \
-   FN_(label)                                  \
-   {                                           \
-      FB_                                      \
-      Sp += sizeofW(StgCatchFrame);            \
-      JMP_(ret);                               \
-      FE_                                      \
-   }
-#else
-#define CATCH_FRAME_ENTRY_TEMPLATE(label,ret)  \
-   FN_(label);                                 \
-   FN_(label)                                  \
-   {                                           \
-      StgWord rval;                            \
-      FB_                                      \
-      rval = Sp[0];                            \
-      Sp++;                                    \
-      Sp += sizeofW(StgCatchFrame) - 1;                \
-      Sp[0] = rval;                            \
-      JMP_(ret);                               \
-      FE_                                      \
-   }
-#endif
-
-#ifdef REG_R1
-#define SP_OFF 0
-#else
-#define SP_OFF 1
-#endif
-
-CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_ret,ENTRY_CODE(Sp[SP_OFF]));
-CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_0_ret,RET_VEC(Sp[SP_OFF],0));
-CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_1_ret,RET_VEC(Sp[SP_OFF],1));
-CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_2_ret,RET_VEC(Sp[SP_OFF],2));
-CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_3_ret,RET_VEC(Sp[SP_OFF],3));
-CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_4_ret,RET_VEC(Sp[SP_OFF],4));
-CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_5_ret,RET_VEC(Sp[SP_OFF],5));
-CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_6_ret,RET_VEC(Sp[SP_OFF],6));
-CATCH_FRAME_ENTRY_TEMPLATE(stg_catch_frame_7_ret,RET_VEC(Sp[SP_OFF],7));
-
-#if defined(PROFILING)
-#define CATCH_FRAME_BITMAP 7
-#define CATCH_FRAME_WORDS  4
-#else
-#define CATCH_FRAME_BITMAP 1
-#define CATCH_FRAME_WORDS  2
-#endif
-
-/* Catch frames are very similar to update frames, but when entering
- * one we just pop the frame off the stack and perform the correct
- * kind of return to the activation record underneath us on the stack.
- */
-
-VEC_POLY_INFO_TABLE(stg_catch_frame, \
-       MK_SMALL_BITMAP(CATCH_FRAME_WORDS, CATCH_FRAME_BITMAP), \
-       NULL/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, CATCH_FRAME,, EF_);
-
-/* -----------------------------------------------------------------------------
- * The catch infotable
- *
- * This should be exactly the same as would be generated by this STG code
- *
- * catch = {x,h} \n {} -> catch#{x,h}
- *
- * It is used in deleteThread when reverting blackholes.
- * -------------------------------------------------------------------------- */
-
-INFO_TABLE(stg_catch_info,stg_catch_entry,2,0,FUN,,EF_,0,0);
-STGFUN(stg_catch_entry)
-{
-  FB_
-  R2.cl = R1.cl->payload[1]; /* h */
-  R1.cl = R1.cl->payload[0]; /* x */
-  JMP_(catchzh_fast);
-  FE_
-}
-
-FN_(catchzh_fast)
-{
-  StgCatchFrame *fp;
-  FB_
-
-    /* args: R1 = m :: IO a, R2 = handler :: Exception -> IO a */
-    STK_CHK_GEN(sizeofW(StgCatchFrame) + 1, R1_PTR | R2_PTR, catchzh_fast);
-  
-    /* Set up the catch frame */
-    Sp -= sizeofW(StgCatchFrame);
-    fp = (StgCatchFrame *)Sp;
-    SET_HDR(fp,(StgInfoTable *)&stg_catch_frame_info,CCCS);
-    fp -> handler = R2.cl;
-    fp -> exceptions_blocked = (CurrentTSO->blocked_exceptions != NULL);
-    TICK_CATCHF_PUSHED();
-
-
-/* Apply R1 to the realworld token */
-    Sp--;
-    JMP_(stg_ap_v_ret);
-  FE_
-}      
-
-/* -----------------------------------------------------------------------------
- * The raise infotable
- * 
- * This should be exactly the same as would be generated by this STG code
- *
- *   raise = {err} \n {} -> raise#{err}
- *
- * It is used in raisezh_fast to update thunks on the update list
- * -------------------------------------------------------------------------- */
-
-INFO_TABLE(stg_raise_info,stg_raise_entry,1,0,THUNK,,EF_,0,0);
-STGFUN(stg_raise_entry)
-{
-  FB_
-  R1.cl = R1.cl->payload[0];
-  JMP_(raisezh_fast);
-  FE_
-}
-
-FN_(raisezh_fast)
-{
-  StgClosure *handler;
-  StgPtr p;
-  StgClosure *raise_closure;
-  FB_
-    /* args : R1.p :: Exception */
-
-
-#if defined(PROFILING)
-    /* Debugging tool: on raising an  exception, show where we are. */
-
-    /* ToDo: currently this is a hack.  Would be much better if
-     * the info was only displayed for an *uncaught* exception.
-     */
-    if (RtsFlags.ProfFlags.showCCSOnException) {
-      STGCALL2(fprintCCS,stderr,CCCS);
-    }
-#endif
-
-    /* This closure represents the expression 'raise# E' where E
-     * is the exception raise.  It is used to overwrite all the
-     * thunks which are currently under evaluataion.
-     */
-    /*    
-    // @LDV profiling
-    // stg_raise_info has THUNK as its closure type. Since a THUNK takes at least
-    // MIN_UPD_SIZE words in its payload, MIN_UPD_SIZE is more approprate than 1.
-    // It seems that 1 does not cause any problem unless profiling is performed.
-    // However, when LDV profiling goes on, we need to linearly scan small object pool,
-    // where raise_closure is stored, so we should use MIN_UPD_SIZE.
-    raise_closure = (StgClosure *)RET_STGCALL1(P_,allocate,
-                                              sizeofW(StgClosure)+1);
-     */
-    raise_closure = (StgClosure *)RET_STGCALL1(P_,allocate,
-                                              sizeofW(StgClosure)+MIN_UPD_SIZE);
-    SET_HDR(raise_closure, &stg_raise_info, CCCS);
-    raise_closure->payload[0] = R1.cl;
-
-    // Walk up the stack, looking for the catch frame.  On the way,
-    // we update any closures pointed to from update frames with the
-    // raise closure that we just built.
-    {          
-       StgPtr next;
-       StgRetInfoTable *info;
-
-       p = Sp;
-       while(1) {
-
-           info = get_ret_itbl((StgClosure *)p);
-           next = p + stack_frame_sizeW((StgClosure *)p);
-           switch (info->i.type) {
-
-           case UPDATE_FRAME:
-               UPD_IND(((StgUpdateFrame *)p)->updatee,raise_closure);
-               p = next;
-               continue;
-
-           case CATCH_FRAME:
-               /* found it! */
-               break;
-
-           case STOP_FRAME:
-               /* We've stripped the entire stack, the thread is now dead. */
-               Sp = CurrentTSO->stack + CurrentTSO->stack_size - 1;
-               Sp[0] = R1.w;           /* save the exception */
-               CurrentTSO->what_next = ThreadKilled;
-               SaveThreadState();      /* inline! */
-               R1.w = ThreadFinished;
-               JMP_(StgReturn);
-               
-           default:
-               p = next; 
-               continue;
-           }
-      
-           break;
-       }
-    }
-    
-    /* Ok, p points to the enclosing CATCH_FRAME.  Pop everything down to
-     * and including this frame, update Su, push R1, and enter the handler.
-     */
-    handler = ((StgCatchFrame *)p)->handler;
-    
-    Sp = (P_)p + sizeofW(StgCatchFrame);
-
-    /* Restore the blocked/unblocked state for asynchronous exceptions
-     * at the CATCH_FRAME.  
-     *
-     * If exceptions were unblocked, arrange that they are unblocked
-     * again after executing the handler by pushing an
-     * unblockAsyncExceptions_ret stack frame.
-     */
-    if (! ((StgCatchFrame *)p)->exceptions_blocked) {
-      *(--Sp) = (W_)&stg_unblockAsyncExceptionszh_ret_info;
-    }
-
-    /* Ensure that async excpetions are blocked when running the handler.
-    */
-    if (CurrentTSO->blocked_exceptions == NULL) {
-      CurrentTSO->blocked_exceptions = END_TSO_QUEUE;
-    }
-
-    /* Call the handler, passing the exception value and a realworld
-     * token as arguments.
-     */
-    Sp -= 2;
-    Sp[1] = (W_)&stg_ap_v_info;
-    Sp[0] = R1.w;
-    R1.cl = handler;
-    Sp--;
-    JMP_(stg_ap_p_ret);
-  FE_
-}
-
-FN_(raiseIOzh_fast)
-{
-  FB_
-  /* Args :: R1.p :: Exception */
-  JMP_(raisezh_fast);
-  FE_
-}
index 477fce0..85faeeb 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: FrontPanel.c,v 1.8 2003/06/24 08:49:55 stolz Exp $
+ * $Id: FrontPanel.c,v 1.9 2004/08/13 13:09:49 simonmar Exp $
  *
  * (c) The GHC Team 2000
  *
@@ -17,7 +17,6 @@
 #include "MBlock.h"
 #include "FrontPanel.h"
 #include "Storage.h"
-#include "StoragePriv.h"
 #include "Stats.h"
 #include "RtsFlags.h"
 #include "Schedule.h"
index 98624b6..adb36cc 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: GC.c,v 1.167 2004/05/21 13:28:59 simonmar Exp $
+ * $Id: GC.c,v 1.168 2004/08/13 13:09:49 simonmar Exp $
  *
  * (c) The GHC Team 1998-2003
  *
@@ -13,7 +13,8 @@
 #include "RtsUtils.h"
 #include "Apply.h"
 #include "Storage.h"
-#include "StoragePriv.h"
+#include "LdvProfile.h"
+#include "Updates.h"
 #include "Stats.h"
 #include "Schedule.h"
 #include "SchedAPI.h"          // for ReverCAFs prototype
@@ -23,7 +24,6 @@
 #include "ProfHeap.h"
 #include "SchedAPI.h"
 #include "Weak.h"
-#include "StablePriv.h"
 #include "Prelude.h"
 #include "ParTicky.h"          // ToDo: move into Rts.h
 #include "GCCompact.h"
@@ -44,7 +44,6 @@
 #endif
 
 #include "RetainerProfile.h"
-#include "LdvProfile.h"
 
 #include <string.h>
 
@@ -585,17 +584,6 @@ GarbageCollect ( void (*get_roots)(evac_fn), rtsBool force_major_gc )
    */
   markStablePtrTable(mark_root);
 
-#ifdef INTERPRETER
-  { 
-      /* ToDo: To fix the caf leak, we need to make the commented out
-       * parts of this code do something sensible - as described in 
-       * the CAF document.
-       */
-      extern void markHugsObjects(void);
-      markHugsObjects();
-  }
-#endif
-
   /* -------------------------------------------------------------------------
    * Repeatedly scavenge all the areas we know about until there's no
    * more scavenging to be done.
@@ -1435,7 +1423,7 @@ upd_evacuee(StgClosure *p, StgClosure *dest)
     ASSERT((Bdescr((P_)p)->flags & BF_EVACUATED) == 0);
     // not true: (ToDo: perhaps it should be)
     // ASSERT(Bdescr((P_)dest)->flags & BF_EVACUATED);
-    p->header.info = &stg_EVACUATED_info;
+    SET_INFO(p, &stg_EVACUATED_info);
     ((StgEvacuated *)p)->evacuee = dest;
 }
 
@@ -2172,15 +2160,15 @@ selector_loop:
              // For the purposes of LDV profiling, we have destroyed
              // the original selector thunk.
              SET_INFO(p, info_ptr);
-             LDV_recordDead_FILL_SLOP_DYNAMIC(selectee);
+             LDV_RECORD_DEAD_FILL_SLOP_DYNAMIC(selectee);
 #endif
              ((StgInd *)selectee)->indirectee = val;
              SET_INFO(selectee,&stg_IND_info);
-#ifdef PROFILING
+
              // For the purposes of LDV profiling, we have created an
              // indirection.
-             LDV_recordCreate(selectee);
-#endif
+             LDV_RECORD_CREATE(selectee);
+
              selectee = val;
              goto selector_loop;
          }
@@ -2326,7 +2314,7 @@ scavenge_fun_srt(const StgInfoTable *info)
     StgFunInfoTable *fun_info;
 
     fun_info = itbl_to_fun_itbl(info);
-    scavenge_srt((StgClosure **)fun_info->srt, fun_info->i.srt_bitmap);
+    scavenge_srt((StgClosure **)fun_info->f.srt, fun_info->i.srt_bitmap);
 }
 
 STATIC_INLINE void
@@ -2379,19 +2367,19 @@ scavenge_arg_block (StgFunInfoTable *fun_info, StgClosure **args)
     nat size;
 
     p = (StgPtr)args;
-    switch (fun_info->fun_type) {
+    switch (fun_info->f.fun_type) {
     case ARG_GEN:
-       bitmap = BITMAP_BITS(fun_info->bitmap);
-       size = BITMAP_SIZE(fun_info->bitmap);
+       bitmap = BITMAP_BITS(fun_info->f.bitmap);
+       size = BITMAP_SIZE(fun_info->f.bitmap);
        goto small_bitmap;
     case ARG_GEN_BIG:
-       size = ((StgLargeBitmap *)fun_info->bitmap)->size;
-       scavenge_large_bitmap(p, (StgLargeBitmap *)fun_info->bitmap, size);
+       size = ((StgLargeBitmap *)fun_info->f.bitmap)->size;
+       scavenge_large_bitmap(p, (StgLargeBitmap *)fun_info->f.bitmap, size);
        p += size;
        break;
     default:
-       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->fun_type]);
-       size = BITMAP_SIZE(stg_arg_bitmaps[fun_info->fun_type]);
+       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
+       size = BITMAP_SIZE(stg_arg_bitmaps[fun_info->f.fun_type]);
     small_bitmap:
        while (size > 0) {
            if ((bitmap & 1) == 0) {
@@ -2420,12 +2408,12 @@ scavenge_PAP (StgPAP *pap)
     p = (StgPtr)pap->payload;
     size = pap->n_args;
 
-    switch (fun_info->fun_type) {
+    switch (fun_info->f.fun_type) {
     case ARG_GEN:
-       bitmap = BITMAP_BITS(fun_info->bitmap);
+       bitmap = BITMAP_BITS(fun_info->f.bitmap);
        goto small_bitmap;
     case ARG_GEN_BIG:
-       scavenge_large_bitmap(p, (StgLargeBitmap *)fun_info->bitmap, size);
+       scavenge_large_bitmap(p, (StgLargeBitmap *)fun_info->f.bitmap, size);
        p += size;
        break;
     case ARG_BCO:
@@ -2433,7 +2421,7 @@ scavenge_PAP (StgPAP *pap)
        p += size;
        break;
     default:
-       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->fun_type]);
+       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
     small_bitmap:
        size = pap->n_args;
        while (size > 0) {
@@ -2619,14 +2607,12 @@ scavenge(step *stp)
         LDV_recordDead((StgClosure *)p, sizeofW(StgInd));
 #endif        
         // 
-        // Todo: maybe use SET_HDR() and remove LDV_recordCreate()?
+        // Todo: maybe use SET_HDR() and remove LDV_RECORD_CREATE()?
         //
        SET_INFO(((StgClosure *)p), &stg_IND_OLDGEN_PERM_info);
-#ifdef PROFILING
-        // @LDV profiling
+
         // We pretend that p has just been created.
-        LDV_recordCreate((StgClosure *)p);
-#endif
+        LDV_RECORD_CREATE((StgClosure *)p);
       }
        // fall through 
     case IND_OLDGEN_PERM:
@@ -3829,16 +3815,16 @@ scavenge_stack(StgPtr p, StgPtr stack_end)
        dyn = ((StgRetDyn *)p)->liveness;
 
        // traverse the bitmap first
-       bitmap = GET_LIVENESS(dyn);
+       bitmap = RET_DYN_LIVENESS(dyn);
        p      = (P_)&((StgRetDyn *)p)->payload[0];
        size   = RET_DYN_BITMAP_SIZE;
        p = scavenge_small_bitmap(p, size, bitmap);
 
        // skip over the non-ptr words
-       p += GET_NONPTRS(dyn) + RET_DYN_NONPTR_REGS_SIZE;
+       p += RET_DYN_NONPTRS(dyn) + RET_DYN_NONPTR_REGS_SIZE;
        
        // follow the ptr words
-       for (size = GET_PTRS(dyn); size > 0; size--) {
+       for (size = RET_DYN_PTRS(dyn); size > 0; size--) {
            (StgClosure *)*p = evacuate((StgClosure *)*p);
            p++;
        }
@@ -3949,7 +3935,7 @@ revertCAFs( void )
     for (c = (StgIndStatic *)caf_list; c != NULL; 
         c = (StgIndStatic *)c->static_link) 
     {
-       c->header.info = c->saved_info;
+       SET_INFO(c, c->saved_info);
        c->saved_info = NULL;
        // could, but not necessary: c->static_link = NULL; 
     }
@@ -4070,11 +4056,9 @@ threadLazyBlackHole(StgTSO *tso)
                LDV_recordDead_FILL_SLOP_DYNAMIC((StgClosure *)bh);
 #endif
                SET_INFO(bh,&stg_BLACKHOLE_info);
-#ifdef PROFILING
-               // @LDV profiling
+
                // We pretend that bh has just been created.
-               LDV_recordCreate(bh);
-#endif
+               LDV_RECORD_CREATE(bh);
            }
            
            frame = (StgClosure *) ((StgUpdateFrame *)frame + 1);
@@ -4217,12 +4201,11 @@ threadSqueezeStack(StgTSO *tso)
                    // We pretend that bh is now dead.
                    LDV_recordDead_FILL_SLOP_DYNAMIC((StgClosure *)bh);
 #endif
-                   // Todo: maybe use SET_HDR() and remove LDV_recordCreate()?
+                   // Todo: maybe use SET_HDR() and remove LDV_RECORD_CREATE()?
                    SET_INFO(bh,&stg_BLACKHOLE_info);
-#ifdef PROFILING
+
                    // We pretend that bh has just been created.
-                   LDV_recordCreate(bh);
-#endif
+                   LDV_RECORD_CREATE(bh);
                }
 
                prev_was_update_frame = rtsTrue;
index 860c531..8f61d73 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: GCCompact.c,v 1.18 2003/11/12 17:49:07 sof Exp $
+ * $Id: GCCompact.c,v 1.19 2004/08/13 13:09:56 simonmar Exp $
  *
  * (c) The GHC Team 2001
  *
@@ -16,7 +16,6 @@
 #include "MBlock.h"
 #include "GCCompact.h"
 #include "Schedule.h"
-#include "StablePriv.h"
 #include "Apply.h"
 
 // Turn off inlining when debugging - it obfuscates things
@@ -214,19 +213,19 @@ thread_arg_block (StgFunInfoTable *fun_info, StgClosure **args)
     nat size;
 
     p = (StgPtr)args;
-    switch (fun_info->fun_type) {
+    switch (fun_info->f.fun_type) {
     case ARG_GEN:
-       bitmap = BITMAP_BITS(fun_info->bitmap);
-       size = BITMAP_SIZE(fun_info->bitmap);
+       bitmap = BITMAP_BITS(fun_info->f.bitmap);
+       size = BITMAP_SIZE(fun_info->f.bitmap);
        goto small_bitmap;
     case ARG_GEN_BIG:
-       size = ((StgLargeBitmap *)fun_info->bitmap)->size;
-       thread_large_bitmap(p, (StgLargeBitmap *)fun_info->bitmap, size);
+       size = ((StgLargeBitmap *)fun_info->f.bitmap)->size;
+       thread_large_bitmap(p, (StgLargeBitmap *)fun_info->f.bitmap, size);
        p += size;
        break;
     default:
-       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->fun_type]);
-       size = BITMAP_SIZE(stg_arg_bitmaps[fun_info->fun_type]);
+       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
+       size = BITMAP_SIZE(stg_arg_bitmaps[fun_info->f.fun_type]);
     small_bitmap:
        while (size > 0) {
            if ((bitmap & 1) == 0) {
@@ -267,7 +266,7 @@ thread_stack(StgPtr p, StgPtr stack_end)
            dyn = ((StgRetDyn *)p)->liveness;
 
            // traverse the bitmap first
-           bitmap = GET_LIVENESS(dyn);
+           bitmap = RET_DYN_LIVENESS(dyn);
            p      = (P_)&((StgRetDyn *)p)->payload[0];
            size   = RET_DYN_BITMAP_SIZE;
            while (size > 0) {
@@ -280,10 +279,10 @@ thread_stack(StgPtr p, StgPtr stack_end)
            }
            
            // skip over the non-ptr words
-           p += GET_NONPTRS(dyn) + RET_DYN_NONPTR_REGS_SIZE;
+           p += RET_DYN_NONPTRS(dyn) + RET_DYN_NONPTR_REGS_SIZE;
            
            // follow the ptr words
-           for (size = GET_PTRS(dyn); size > 0; size--) {
+           for (size = RET_DYN_PTRS(dyn); size > 0; size--) {
                thread(p);
                p++;
            }
@@ -367,12 +366,12 @@ thread_PAP (StgPAP *pap)
     p = (StgPtr)pap->payload;
     size = pap->n_args;
 
-    switch (fun_info->fun_type) {
+    switch (fun_info->f.fun_type) {
     case ARG_GEN:
-       bitmap = BITMAP_BITS(fun_info->bitmap);
+       bitmap = BITMAP_BITS(fun_info->f.bitmap);
        goto small_bitmap;
     case ARG_GEN_BIG:
-       thread_large_bitmap(p, (StgLargeBitmap *)fun_info->bitmap, size);
+       thread_large_bitmap(p, (StgLargeBitmap *)fun_info->f.bitmap, size);
        p += size;
        break;
     case ARG_BCO:
@@ -380,7 +379,7 @@ thread_PAP (StgPAP *pap)
        p += size;
        break;
     default:
-       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->fun_type]);
+       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
     small_bitmap:
        size = pap->n_args;
        while (size > 0) {
diff --git a/ghc/rts/HeapStackCheck.cmm b/ghc/rts/HeapStackCheck.cmm
new file mode 100644 (file)
index 0000000..516d0ad
--- /dev/null
@@ -0,0 +1,880 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2004
+ *
+ * Canned Heap-Check and Stack-Check sequences.
+ *
+ * This file is written in a subset of C--, extended with various
+ * features specific to GHC.  It is compiled by GHC directly.  For the
+ * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "Cmm.h"
+
+/* Stack/Heap Check Failure
+ * ------------------------
+ *
+ * On discovering that a stack or heap check has failed, we do the following:
+ *
+ *    - If the context_switch flag is set, indicating that there are more
+ *      threads waiting to run, we yield to the scheduler 
+ *     (return ThreadYielding).
+ *
+ *    - If Hp > HpLim, we've had a heap check failure.  This means we've
+ *     come to the end of the current heap block, so we try to chain
+ *     another block on with ExtendNursery().  
+ *
+ *          - If this succeeds, we carry on without returning to the 
+ *            scheduler.  
+ *
+ *          - If it fails, we return to the scheduler claiming HeapOverflow
+ *            so that a garbage collection can be performed.
+ *
+ *    - If Hp <= HpLim, it must have been a stack check that failed.  In
+ *     which case, we return to the scheduler claiming StackOverflow, the
+ *     scheduler will either increase the size of our stack, or raise
+ *     an exception if the stack is already too big.
+ *
+ * The effect of checking for context switch only in the heap/stack check
+ * failure code is that we'll switch threads after the current thread has
+ * reached the end of its heap block.  If a thread isn't allocating
+ * at all, it won't yield.  Hopefully this won't be a problem in practice.
+ */
+/* Remember that the return address is *removed* when returning to a
+ * ThreadRunGHC thread.
+ */
+
+#define GC_GENERIC                                             \
+    DEBUG_ONLY(foreign "C" heapCheckFail());                   \
+    if (Hp > HpLim) {                                          \
+        Hp = Hp - HpAlloc/*in bytes*/;                         \
+        if (HpAlloc <= BLOCK_SIZE                              \
+            && bdescr_link(CurrentNursery) != NULL) {          \
+            CLOSE_NURSERY();                                   \
+            CurrentNursery = bdescr_link(CurrentNursery);      \
+            OPEN_NURSERY();                                    \
+            if (CInt[context_switch] != 0) {                   \
+                R1 = ThreadYielding;                           \
+                goto sched;                                    \
+            } else {                                           \
+                jump %ENTRY_CODE(Sp(0));                       \
+            }                                                  \
+       } else {                                                \
+            R1 = HeapOverflow;                                 \
+            goto sched;                                                \
+        }                                                      \
+    } else {                                                   \
+        R1 = StackOverflow;                                    \
+    }                                                          \
+  sched:                                                       \
+    SAVE_THREAD_STATE();                                       \
+    StgTSO_what_next(CurrentTSO) = ThreadRunGHC::I16;          \
+    jump StgReturn;
+
+#define RETURN_TO_SCHED(why,what_next)                 \
+  SAVE_THREAD_STATE();                                 \
+  StgTSO_what_next(CurrentTSO) = what_next::I16;       \
+  R1 = why;                                            \
+  jump StgReturn;
+
+#define HP_GENERIC           RETURN_TO_SCHED(HeapOverflow,   ThreadRunGHC)
+#define YIELD_GENERIC        RETURN_TO_SCHED(ThreadYielding, ThreadRunGHC)
+#define YIELD_TO_INTERPRETER RETURN_TO_SCHED(ThreadYielding, ThreadInterpret)
+#define BLOCK_GENERIC        RETURN_TO_SCHED(ThreadBlocked,  ThreadRunGHC)
+
+/* -----------------------------------------------------------------------------
+   Heap checks in thunks/functions.
+
+   In these cases, node always points to the function closure.  This gives
+   us an easy way to return to the function: just leave R1 on the top of
+   the stack, and have the scheduler enter it to return.
+
+   There are canned sequences for 'n' pointer values in registers.
+   -------------------------------------------------------------------------- */
+
+INFO_TABLE_RET( stg_enter, 1/*framesize*/, 0/*bitmap*/, RET_SMALL)
+{
+    R1 = Sp(1);
+    Sp_adj(2);
+    ENTER();
+}
+
+__stg_gc_enter_1
+{
+    Sp_adj(-2);
+    Sp(1) = R1;
+    Sp(0) = stg_enter_info;
+    GC_GENERIC
+}
+
+#ifdef SMP
+stg_gc_enter_1_hponly
+{
+    Sp_adj(-1);
+    Sp(0) = R1;
+    R1 = HeapOverflow;
+    SAVE_THREAD_STATE();
+    TSO_what_next(CurrentTSO) = ThreadRunGHC::I16;
+    jump StgReturn;
+}
+#endif
+
+#if defined(GRAN)
+/*
+  ToDo: merge the block and yield macros, calling something like BLOCK(N)
+        at the end;
+*/
+
+/* 
+   Should we actually ever do a yield in such a case?? -- HWL
+*/
+gran_yield_0
+{
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadYielding;
+    jump StgReturn;
+}
+
+gran_yield_1
+{
+    Sp_adj(-1);
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadYielding;
+    jump StgReturn;
+}
+
+/*- 2 Regs--------------------------------------------------------------------*/
+
+gran_yield_2
+{
+    Sp_adj(-2);
+    Sp(1) = R2;
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadYielding;
+    jump StgReturn;
+}
+
+/*- 3 Regs -------------------------------------------------------------------*/
+
+gran_yield_3
+{
+    Sp_adj(-3);
+    Sp(2) = R3;
+    Sp(1) = R2;
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadYielding;
+    jump StgReturn;
+}
+
+/*- 4 Regs -------------------------------------------------------------------*/
+
+gran_yield_4
+{
+    Sp_adj(-4);
+    Sp(3) = R4;
+    Sp(2) = R3;
+    Sp(1) = R2;
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadYielding;
+    jump StgReturn;
+}
+
+/*- 5 Regs -------------------------------------------------------------------*/
+
+gran_yield_5
+{
+    Sp_adj(-5);
+    Sp(4) = R5;
+    Sp(3) = R4;
+    Sp(2) = R3;
+    Sp(1) = R2;
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadYielding;
+    jump StgReturn;
+}
+
+/*- 6 Regs -------------------------------------------------------------------*/
+
+gran_yield_6
+{
+    Sp_adj(-6);
+    Sp(5) = R6;
+    Sp(4) = R5;
+    Sp(3) = R4;
+    Sp(2) = R3;
+    Sp(1) = R2;
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadYielding;
+    jump StgReturn;
+}
+
+/*- 7 Regs -------------------------------------------------------------------*/
+
+gran_yield_7
+{
+    Sp_adj(-7);
+    Sp(6) = R7;
+    Sp(5) = R6;
+    Sp(4) = R5;
+    Sp(3) = R4;
+    Sp(2) = R3;
+    Sp(1) = R2;
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadYielding;
+    jump StgReturn;
+}
+
+/*- 8 Regs -------------------------------------------------------------------*/
+
+gran_yield_8
+{
+    Sp_adj(-8);
+    Sp(7) = R8;
+    Sp(6) = R7;
+    Sp(5) = R6;
+    Sp(4) = R5;
+    Sp(3) = R4;
+    Sp(2) = R3;
+    Sp(1) = R2;
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadYielding;
+    jump StgReturn;
+}
+
+// the same routines but with a block rather than a yield
+
+gran_block_1
+{
+    Sp_adj(-1);
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadBlocked;
+    jump StgReturn;
+}
+
+/*- 2 Regs--------------------------------------------------------------------*/
+
+gran_block_2
+{
+    Sp_adj(-2);
+    Sp(1) = R2;
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadBlocked;
+    jump StgReturn;
+}
+
+/*- 3 Regs -------------------------------------------------------------------*/
+
+gran_block_3
+{
+    Sp_adj(-3);
+    Sp(2) = R3;
+    Sp(1) = R2;
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadBlocked;
+    jump StgReturn;
+}
+
+/*- 4 Regs -------------------------------------------------------------------*/
+
+gran_block_4
+{
+    Sp_adj(-4);
+    Sp(3) = R4;
+    Sp(2) = R3;
+    Sp(1) = R2;
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadBlocked;
+    jump StgReturn;
+}
+
+/*- 5 Regs -------------------------------------------------------------------*/
+
+gran_block_5
+{
+    Sp_adj(-5);
+    Sp(4) = R5;
+    Sp(3) = R4;
+    Sp(2) = R3;
+    Sp(1) = R2;
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadBlocked;
+    jump StgReturn;
+}
+
+/*- 6 Regs -------------------------------------------------------------------*/
+
+gran_block_6
+{
+    Sp_adj(-6);
+    Sp(5) = R6;
+    Sp(4) = R5;
+    Sp(3) = R4;
+    Sp(2) = R3;
+    Sp(1) = R2;
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadBlocked;
+    jump StgReturn;
+}
+
+/*- 7 Regs -------------------------------------------------------------------*/
+
+gran_block_7
+{
+    Sp_adj(-7);
+    Sp(6) = R7;
+    Sp(5) = R6;
+    Sp(4) = R5;
+    Sp(3) = R4;
+    Sp(2) = R3;
+    Sp(1) = R2;
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadBlocked;
+    jump StgReturn;
+}
+
+/*- 8 Regs -------------------------------------------------------------------*/
+
+gran_block_8
+{
+    Sp_adj(-8);
+    Sp(7) = R8;
+    Sp(6) = R7;
+    Sp(5) = R6;
+    Sp(4) = R5;
+    Sp(3) = R4;
+    Sp(2) = R3;
+    Sp(1) = R2;
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadBlocked;
+    jump StgReturn;
+}
+
+#endif
+
+#if 0 && defined(PAR)
+
+/*
+  Similar to stg_block_1 (called via StgMacro BLOCK_NP) but separates the
+  saving of the thread state from the actual jump via an StgReturn.
+  We need this separation because we call RTS routines in blocking entry codes
+  before jumping back into the RTS (see parallel/FetchMe.hc).
+*/
+
+par_block_1_no_jump
+{
+    Sp_adj(-1);
+    Sp(0) = R1;
+    SAVE_THREAD_STATE();                                       
+}
+
+par_jump
+{
+    TSO_what_next(CurrentTSO) = ThreadRunGHC;          
+    R1 = ThreadBlocked;
+    jump StgReturn;
+}
+
+#endif
+
+/* -----------------------------------------------------------------------------
+   Heap checks in Primitive case alternatives
+
+   A primitive case alternative is entered with a value either in 
+   R1, FloatReg1 or D1 depending on the return convention.  All the
+   cases are covered below.
+   -------------------------------------------------------------------------- */
+
+/*-- No Registers live ------------------------------------------------------ */
+
+stg_gc_noregs
+{
+    GC_GENERIC
+}
+
+/*-- void return ------------------------------------------------------------ */
+
+INFO_TABLE_RET( stg_gc_void, 0/*framesize*/, 0/*bitmap*/, RET_SMALL)
+{
+    Sp_adj(1);
+    jump %ENTRY_CODE(Sp(0));
+}
+
+/*-- R1 is boxed/unpointed -------------------------------------------------- */
+
+INFO_TABLE_RET( stg_gc_unpt_r1, 1/*framesize*/, 0/*bitmap*/, RET_SMALL)
+{
+    R1 = Sp(1);
+    Sp_adj(2);
+    jump %ENTRY_CODE(Sp(0));
+}
+
+stg_gc_unpt_r1
+{
+    Sp_adj(-2);
+    Sp(1) = R1;
+    Sp(0) = stg_gc_unpt_r1_info;
+    GC_GENERIC
+}
+
+/*-- R1 is unboxed -------------------------------------------------- */
+
+/* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */
+INFO_TABLE_RET(        stg_gc_unbx_r1, 1/*framesize*/, 1/*bitmap*/, RET_SMALL )
+{
+    R1 = Sp(1);
+    Sp_adj(2);
+    jump %ENTRY_CODE(Sp(0));
+}
+
+stg_gc_unbx_r1
+{
+    Sp_adj(-2);
+    Sp(1) = R1;
+    Sp(0) = stg_gc_unbx_r1_info;
+    GC_GENERIC
+}
+
+/*-- F1 contains a float ------------------------------------------------- */
+
+INFO_TABLE_RET(        stg_gc_f1, 1/*framesize*/, 1/*bitmap*/, RET_SMALL )
+{
+    F1 = F_[Sp+WDS(1)];
+    Sp_adj(2);
+    jump %ENTRY_CODE(Sp(0));
+}
+
+stg_gc_f1
+{
+    Sp_adj(-2);
+    F_[Sp + WDS(1)] = F1;
+    Sp(0) = stg_gc_f1_info;
+    GC_GENERIC
+}
+
+/*-- D1 contains a double ------------------------------------------------- */
+
+/* we support doubles of either 1 or 2 words in size */
+
+#if SIZEOF_DOUBLE == SIZEOF_VOID_P
+#  define DBL_BITMAP 1
+#  define DBL_WORDS  1
+#else
+#  define DBL_BITMAP 3
+#  define DBL_WORDS  2
+#endif 
+
+INFO_TABLE_RET(        stg_gc_d1, DBL_WORDS/*framesize*/, DBL_BITMAP/*bitmap*/, RET_SMALL )
+{
+    D1 = D_[Sp + WDS(1)];
+    Sp = Sp + WDS(1) + SIZEOF_StgDouble;
+    jump %ENTRY_CODE(Sp(0));
+}
+
+stg_gc_d1
+{
+    Sp = Sp - WDS(1) - SIZEOF_StgDouble;
+    D_[Sp + WDS(1)] = D1;
+    Sp(0) = stg_gc_d1_info;
+    GC_GENERIC
+}
+
+
+/*-- L1 contains an int64 ------------------------------------------------- */
+
+/* we support int64s of either 1 or 2 words in size */
+
+#if SIZEOF_VOID_P == 8
+#  define LLI_BITMAP 1
+#  define LLI_WORDS  1
+#else
+#  define LLI_BITMAP 3
+#  define LLI_WORDS  2
+#endif 
+
+INFO_TABLE_RET( stg_gc_l1, LLI_WORDS/*framesize*/, LLI_BITMAP/*bitmap*/, RET_SMALL )
+{
+    L1 = L_[Sp + WDS(1)];
+    Sp_adj(1) + SIZEOF_StgWord64;
+    jump %ENTRY_CODE(Sp(0));
+}
+
+stg_gc_l1
+{
+    Sp_adj(-1) - SIZEOF_StgWord64;
+    L_[Sp + WDS(1)] = L1;
+    Sp(0) = stg_gc_l1_info;
+    GC_GENERIC
+}
+
+/*-- Unboxed tuple return, one pointer (unregisterised build only) ---------- */
+
+INFO_TABLE_RET( stg_ut_1_0_unreg, 1/*size*/, 0/*BITMAP*/, RET_SMALL )
+{
+    Sp_adj(1);
+    // one ptr is on the stack (Sp(0))
+    jump %ENTRY_CODE(Sp(1));
+}
+
+/* -----------------------------------------------------------------------------
+   Generic function entry heap check code.
+
+   At a function entry point, the arguments are as per the calling convention,
+   i.e. some in regs and some on the stack.  There may or may not be 
+   a pointer to the function closure in R1 - if there isn't, then the heap
+   check failure code in the function will arrange to load it.
+
+   The function's argument types are described in its info table, so we
+   can just jump to this bit of generic code to save away all the
+   registers and return to the scheduler.
+
+   This code arranges the stack like this:
+        
+         |        ....         |
+         |        args         |
+        +---------------------+
+         |      f_closure      |
+        +---------------------+
+         |        size         |
+        +---------------------+
+         |   stg_gc_fun_info   |
+        +---------------------+
+
+   The size is the number of words of arguments on the stack, and is cached
+   in the frame in order to simplify stack walking: otherwise the size of
+   this stack frame would have to be calculated by looking at f's info table.
+
+   -------------------------------------------------------------------------- */
+
+__stg_gc_fun
+{
+    W_ size;
+    W_ info;
+    W_ type;
+
+    info = %GET_FUN_INFO(R1);
+
+    // cache the size
+    type = TO_W_(StgFunInfoExtra_fun_type(info));
+    if (type == ARG_GEN) {
+       size = BITMAP_SIZE(StgFunInfoExtra_bitmap(info));
+    } else { 
+       if (type == ARG_GEN_BIG) {
+           size = StgLargeBitmap_size( StgFunInfoExtra_bitmap(info) );
+       } else {
+           size = BITMAP_SIZE(W_[stg_arg_bitmaps + WDS(type)]);
+       }
+    }
+    
+#ifdef NO_ARG_REGS
+    // we don't have to save any registers away
+    Sp_adj(-3);
+    Sp(2) = R1;
+    Sp(1) = size;
+    Sp(0) = stg_gc_fun_info;
+    GC_GENERIC
+#else
+    W_ type;
+    type = TO_W_(StgFunInfoExtra_fun_type(info));
+    // cache the size
+    if (type == ARG_GEN || type == ARG_GEN_BIG) {
+        // regs already saved by the heap check code
+        Sp_adj(-3);
+        Sp(2) = R1;
+        Sp(1) = size;
+        Sp(0) = stg_gc_fun_info;
+        // DEBUG_ONLY(foreign "C" fprintf(stderr, "stg_fun_gc_gen(ARG_GEN)"););
+        GC_GENERIC
+    } else { 
+       jump W_[stg_stack_save_entries + WDS(type)];
+           // jumps to stg_gc_noregs after saving stuff
+    }
+#endif // !NO_ARG_REGS
+}
+
+/* -----------------------------------------------------------------------------
+   Generic Apply (return point)
+
+   The dual to stg_fun_gc_gen (above): this fragment returns to the
+   function, passing arguments in the stack and in registers
+   appropriately.  The stack layout is given above.
+   -------------------------------------------------------------------------- */
+
+INFO_TABLE_RET( stg_gc_fun, 0/*framesize*/, 0/*bitmap*/, RET_FUN )
+{
+    R1 = Sp(2);
+    Sp_adj(3);
+#ifdef NO_ARG_REGS
+    // Minor optimisation: there are no argument registers to load up,
+    // so we can just jump straight to the function's entry point.
+    jump %GET_ENTRY(R1);
+#else
+    W_ info;
+    W_ type;
+    
+    info = %GET_FUN_INFO(R1);
+    type = TO_W_(StgFunInfoExtra_fun_type(info));
+    if (type == ARG_GEN || type == ARG_GEN_BIG) {
+       jump StgFunInfoExtra_slow_apply(info);
+    } else { 
+       if (type == ARG_BCO) {
+           // cover this case just to be on the safe side
+           Sp_adj(-2);
+           Sp(1) = R1;
+           Sp(0) = stg_apply_interp_info;
+           jump stg_yield_to_interpreter;
+       } else {
+           jump W_[stg_ap_stack_entries + WDS(type)];
+       }
+    }
+#endif
+}
+
+/* -----------------------------------------------------------------------------
+   Generic Heap Check Code.
+
+   Called with Liveness mask in R9,  Return address in R10.
+   Stack must be consistent (containing all necessary info pointers
+   to relevant SRTs).
+
+   See StgMacros.h for a description of the RET_DYN stack frame.
+
+   We also define an stg_gen_yield here, because it's very similar.
+   -------------------------------------------------------------------------- */
+
+// For simplicity, we assume that SIZEOF_DOUBLE == 2*SIZEOF_VOID_P
+// on a 64-bit machine, we'll end up wasting a couple of words, but
+// it's not a big deal.
+
+#define RESTORE_EVERYTHING                     \
+    L1   = L_[Sp + WDS(19)];                   \
+    D2   = D_[Sp + WDS(17)];                   \
+    D1   = D_[Sp + WDS(15)];                   \
+    F4   = F_[Sp + WDS(14)];                   \
+    F3   = F_[Sp + WDS(13)];                   \
+    F2   = F_[Sp + WDS(12)];                   \
+    F1   = F_[Sp + WDS(11)];                   \
+    R8 = Sp(10);                               \
+    R7 = Sp(9);                                        \
+    R6 = Sp(8);                                        \
+    R5 = Sp(7);                                        \
+    R4 = Sp(6);                                        \
+    R3 = Sp(5);                                        \
+    R2 = Sp(4);                                        \
+    R1 = Sp(3);                                        \
+    Sp_adj(21);
+
+#define RET_OFFSET (-19)
+
+#define SAVE_EVERYTHING                                \
+    Sp_adj(-21);                               \
+    L_[Sp + WDS(19)] = L1;                     \
+    D_[Sp + WDS(17)] = D2;                     \
+    D_[Sp + WDS(15)] = D1;                     \
+    F_[Sp + WDS(14)] = F4;                     \
+    F_[Sp + WDS(13)] = F3;                     \
+    F_[Sp + WDS(12)] = F2;                     \
+    F_[Sp + WDS(11)] = F1;                     \
+    Sp(10) = R8;                               \
+    Sp(9) = R7;                                        \
+    Sp(8) = R6;                                        \
+    Sp(7) = R5;                                        \
+    Sp(6) = R4;                                        \
+    Sp(5) = R3;                                        \
+    Sp(4) = R2;                                        \
+    Sp(3) = R1;                                        \
+    Sp(2) = R10.w;    /* return address */     \
+    Sp(1) = R9;     /* liveness mask  */       \
+    Sp(0) = stg_gc_gen_info;
+
+INFO_TABLE_RET( stg_gc_gen, 0/*framesize*/, 0/*bitmap*/, RET_DYN )
+/* bitmap in the above info table is unused, the real one is on the stack. */
+{
+    RESTORE_EVERYTHING;
+    jump Sp(RET_OFFSET); /* No %ENTRY_CODE( - this is an actual code ptr */
+}
+
+stg_gc_gen
+{
+    SAVE_EVERYTHING;
+    GC_GENERIC
+}        
+
+// A heap check at an unboxed tuple return point.  The return address
+// is on the stack, and we can find it by using the offsets given
+// to us in the liveness mask.
+stg_gc_ut
+{
+    R10 = %ENTRY_CODE(Sp(RET_DYN_NONPTRS(R9) + RET_DYN_PTRS(R9)));
+    SAVE_EVERYTHING;
+    GC_GENERIC
+}
+
+/*
+ * stg_gen_hp is used by MAYBE_GC, where we can't use GC_GENERIC
+ * because we've just failed doYouWantToGC(), not a standard heap
+ * check.  GC_GENERIC would end up returning StackOverflow.
+ */
+stg_gc_gen_hp
+{
+    SAVE_EVERYTHING;
+    HP_GENERIC
+}        
+
+/* -----------------------------------------------------------------------------
+   Yields
+   -------------------------------------------------------------------------- */
+
+stg_gen_yield
+{
+    SAVE_EVERYTHING;
+    YIELD_GENERIC
+}
+
+stg_yield_noregs
+{
+    YIELD_GENERIC;
+}
+
+/* -----------------------------------------------------------------------------
+   Yielding to the interpreter... top of stack says what to do next.
+   -------------------------------------------------------------------------- */
+
+stg_yield_to_interpreter
+{
+    YIELD_TO_INTERPRETER;
+}
+
+/* -----------------------------------------------------------------------------
+   Blocks
+   -------------------------------------------------------------------------- */
+
+stg_gen_block
+{
+    SAVE_EVERYTHING;
+    BLOCK_GENERIC;
+}
+
+stg_block_noregs
+{
+    BLOCK_GENERIC;
+}
+
+stg_block_1
+{
+    Sp_adj(-2);
+    Sp(1) = R1;
+    Sp(0) = stg_enter_info;
+    BLOCK_GENERIC;
+}
+
+/* -----------------------------------------------------------------------------
+ * takeMVar/putMVar-specific blocks
+ *
+ * Stack layout for a thread blocked in takeMVar:
+ *      
+ *       ret. addr
+ *       ptr to MVar   (R1)
+ *       stg_block_takemvar_info
+ *
+ * Stack layout for a thread blocked in putMVar:
+ *      
+ *       ret. addr
+ *       ptr to Value  (R2)
+ *       ptr to MVar   (R1)
+ *       stg_block_putmvar_info
+ *
+ * See PrimOps.hc for a description of the workings of take/putMVar.
+ * 
+ * -------------------------------------------------------------------------- */
+
+INFO_TABLE_RET( stg_block_takemvar, 1/*framesize*/, 0/*bitmap*/, RET_SMALL )
+{
+    R1 = Sp(1);
+    Sp_adj(2);
+    jump takeMVarzh_fast;
+}
+
+stg_block_takemvar
+{
+    Sp_adj(-2);
+    Sp(1) = R1;
+    Sp(0) = stg_block_takemvar_info;
+    BLOCK_GENERIC;
+}
+
+INFO_TABLE_RET( stg_block_putmvar, 2/*framesize*/, 0/*bitmap*/, RET_SMALL )
+{
+    R2 = Sp(2);
+    R1 = Sp(1);
+    Sp_adj(3);
+    jump putMVarzh_fast;
+}
+
+stg_block_putmvar
+{
+    Sp_adj(-3);
+    Sp(2) = R2;
+    Sp(1) = R1;
+    Sp(0) = stg_block_putmvar_info;
+    BLOCK_GENERIC;
+}
+
+#ifdef mingw32_TARGET_OS
+INFO_TABLE_RET( stg_block_async, 0/*framesize*/, 0/*bitmap*/, RET_SMALL )
+{
+    W_ ares;
+    W_ len, errC;
+
+    ares = StgTSO_block_info(CurrentTSO);
+    len = StgAsyncIOResult_len(ares);
+    errC = StgAsyncIOResult_errC(ares);
+    StgTSO_block_info(CurrentTSO) = NULL;
+    foreign "C" free(ares);
+    R1 = len;
+    Sp(0) = errC;
+    jump %ENTRY_CODE(Sp(1));
+}
+
+stg_block_async
+{
+    Sp_adj(-1);
+    Sp(0) = stg_block_async_info;
+    BLOCK_GENERIC;
+}
+
+#endif
diff --git a/ghc/rts/HeapStackCheck.hc b/ghc/rts/HeapStackCheck.hc
deleted file mode 100644 (file)
index 2254b5c..0000000
+++ /dev/null
@@ -1,1062 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: HeapStackCheck.hc,v 1.31 2003/05/14 09:13:59 simonmar Exp $
- *
- * (c) The GHC Team, 1998-2002
- *
- * Canned Heap-Check and Stack-Check sequences.
- *
- * ---------------------------------------------------------------------------*/
-
-#include "Stg.h"
-#include "Rts.h"
-#include "Storage.h"           /* for CurrentTSO */
-#include "StgRun.h"    /* for StgReturn and register saving */
-#include "Schedule.h"   /* for context_switch */
-#include "RtsFlags.h"
-#include "RtsUtils.h"
-#include "Apply.h"
-
-#include <stdio.h>
-
-#ifdef mingw32_TARGET_OS
-#include <stdlib.h>
-#endif
-
-/* Stack/Heap Check Failure
- * ------------------------
- *
- * On discovering that a stack or heap check has failed, we do the following:
- *
- *    - If the context_switch flag is set, indicating that there are more
- *      threads waiting to run, we yield to the scheduler 
- *     (return ThreadYielding).
- *
- *    - If Hp > HpLim, we've had a heap check failure.  This means we've
- *     come to the end of the current heap block, so we try to chain
- *     another block on with ExtendNursery().  
- *
- *          - If this succeeds, we carry on without returning to the 
- *            scheduler.  
- *
- *          - If it fails, we return to the scheduler claiming HeapOverflow
- *            so that a garbage collection can be performed.
- *
- *    - If Hp <= HpLim, it must have been a stack check that failed.  In
- *     which case, we return to the scheduler claiming StackOverflow, the
- *     scheduler will either increase the size of our stack, or flag
- *     an error if the stack is already too big.
- *
- * The effect of checking for context switch only in the heap/stack check
- * failure code is that we'll switch threads after the current thread has
- * reached the end of its heap block.  If a thread isn't allocating
- * at all, it won't yield.  Hopefully this won't be a problem in practice.
- */
-/* Remember that the return address is *removed* when returning to a
- * ThreadRunGHC thread.
- */
-
-#define GC_GENERIC                                     \
-  DEBUG_ONLY(heapCheckFail());                         \
-  if (Hp > HpLim) {                                    \
-    Hp -= HpAlloc;                                     \
-    if (HpAlloc <= BLOCK_SIZE_W && ExtendNursery(Hp,HpLim)) {\
-       if (context_switch) {                           \
-           R1.i = ThreadYielding;                      \
-       } else {                                        \
-          JMP_(ENTRY_CODE(Sp[0]));                     \
-       }                                               \
-    } else {                                           \
-      R1.i = HeapOverflow;                             \
-    }                                                  \
-  } else {                                             \
-    R1.i = StackOverflow;                              \
-  }                                                    \
-  SaveThreadState();                                   \
-  CurrentTSO->what_next = ThreadRunGHC;                        \
-  JMP_(StgReturn);
-
-#define HP_GENERIC                             \
-  SaveThreadState();                           \
-  CurrentTSO->what_next = ThreadRunGHC;                \
-  R1.i = HeapOverflow;                         \
-  JMP_(StgReturn);
-
-#define YIELD_GENERIC                          \
-  SaveThreadState();                           \
-  CurrentTSO->what_next = ThreadRunGHC;                \
-  R1.i = ThreadYielding;                       \
-  JMP_(StgReturn);
-
-#define YIELD_TO_INTERPRETER                   \
-  SaveThreadState();                           \
-  CurrentTSO->what_next = ThreadInterpret;     \
-  R1.i = ThreadYielding;                       \
-  JMP_(StgReturn);
-
-#define BLOCK_GENERIC                          \
-  SaveThreadState();                           \
-  CurrentTSO->what_next = ThreadRunGHC;                \
-  R1.i = ThreadBlocked;                                \
-  JMP_(StgReturn);
-
-/* -----------------------------------------------------------------------------
-   Heap checks in thunks/functions.
-
-   In these cases, node always points to the function closure.  This gives
-   us an easy way to return to the function: just leave R1 on the top of
-   the stack, and have the scheduler enter it to return.
-
-   There are canned sequences for 'n' pointer values in registers.
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE_RET( stg_enter_info, stg_enter_ret, 
-               MK_SMALL_BITMAP(1/*framesize*/, 0/*bitmap*/),
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_SMALL,, EF_, 0, 0);
-EXTFUN(stg_enter_ret)
-{
-  FB_
-  R1.w = Sp[1];
-  Sp += 2;
-  ENTER();
-  FE_
-}
-
-EXTFUN(__stg_gc_enter_1)
-{
-  FB_
-  Sp -= 2;
-  Sp[1] = R1.w;
-  Sp[0] = (W_)&stg_enter_info;
-  GC_GENERIC
-  FE_
-}
-
-#ifdef SMP
-EXTFUN(stg_gc_enter_1_hponly)
-{
-  FB_
-  Sp -= 1;
-  Sp[0] = R1.w;
-  R1.i = HeapOverflow;
-  SaveThreadState();
-  CurrentTSO->what_next = ThreadRunGHC;
-  JMP_(StgReturn);
-  FE_
-}
-#endif
-
-#if defined(GRAN)
-/*
-  ToDo: merge the block and yield macros, calling something like BLOCK(N)
-        at the end;
-*/
-
-/* 
-   Should we actually ever do a yield in such a case?? -- HWL
-*/
-EXTFUN(gran_yield_0)
-{
-  FB_
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadYielding;
-  JMP_(StgReturn);
-  FE_
-}
-
-EXTFUN(gran_yield_1)
-{
-  FB_
-  Sp -= 1;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadYielding;
-  JMP_(StgReturn);
-  FE_
-}
-
-/*- 2 Regs--------------------------------------------------------------------*/
-
-EXTFUN(gran_yield_2)
-{
-  FB_
-  Sp -= 2;
-  Sp[1] = R2.w;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadYielding;
-  JMP_(StgReturn);
-  FE_
-}
-
-/*- 3 Regs -------------------------------------------------------------------*/
-
-EXTFUN(gran_yield_3)
-{
-  FB_
-  Sp -= 3;
-  Sp[2] = R3.w;
-  Sp[1] = R2.w;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadYielding;
-  JMP_(StgReturn);
-  FE_
-}
-
-/*- 4 Regs -------------------------------------------------------------------*/
-
-EXTFUN(gran_yield_4)
-{
-  FB_
-  Sp -= 4;
-  Sp[3] = R4.w;
-  Sp[2] = R3.w;
-  Sp[1] = R2.w;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadYielding;
-  JMP_(StgReturn);
-  FE_
-}
-
-/*- 5 Regs -------------------------------------------------------------------*/
-
-EXTFUN(gran_yield_5)
-{
-  FB_
-  Sp -= 5;
-  Sp[4] = R5.w;
-  Sp[3] = R4.w;
-  Sp[2] = R3.w;
-  Sp[1] = R2.w;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadYielding;
-  JMP_(StgReturn);
-  FE_
-}
-
-/*- 6 Regs -------------------------------------------------------------------*/
-
-EXTFUN(gran_yield_6)
-{
-  FB_
-  Sp -= 6;
-  Sp[5] = R6.w;
-  Sp[4] = R5.w;
-  Sp[3] = R4.w;
-  Sp[2] = R3.w;
-  Sp[1] = R2.w;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadYielding;
-  JMP_(StgReturn);
-  FE_
-}
-
-/*- 7 Regs -------------------------------------------------------------------*/
-
-EXTFUN(gran_yield_7)
-{
-  FB_
-  Sp -= 7;
-  Sp[6] = R7.w;
-  Sp[5] = R6.w;
-  Sp[4] = R5.w;
-  Sp[3] = R4.w;
-  Sp[2] = R3.w;
-  Sp[1] = R2.w;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadYielding;
-  JMP_(StgReturn);
-  FE_
-}
-
-/*- 8 Regs -------------------------------------------------------------------*/
-
-EXTFUN(gran_yield_8)
-{
-  FB_
-  Sp -= 8;
-  Sp[7] = R8.w;
-  Sp[6] = R7.w;
-  Sp[5] = R6.w;
-  Sp[4] = R5.w;
-  Sp[3] = R4.w;
-  Sp[2] = R3.w;
-  Sp[1] = R2.w;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadYielding;
-  JMP_(StgReturn);
-  FE_
-}
-
-// the same routines but with a block rather than a yield
-
-EXTFUN(gran_block_1)
-{
-  FB_
-  Sp -= 1;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadBlocked;
-  JMP_(StgReturn);
-  FE_
-}
-
-/*- 2 Regs--------------------------------------------------------------------*/
-
-EXTFUN(gran_block_2)
-{
-  FB_
-  Sp -= 2;
-  Sp[1] = R2.w;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadBlocked;
-  JMP_(StgReturn);
-  FE_
-}
-
-/*- 3 Regs -------------------------------------------------------------------*/
-
-EXTFUN(gran_block_3)
-{
-  FB_
-  Sp -= 3;
-  Sp[2] = R3.w;
-  Sp[1] = R2.w;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadBlocked;
-  JMP_(StgReturn);
-  FE_
-}
-
-/*- 4 Regs -------------------------------------------------------------------*/
-
-EXTFUN(gran_block_4)
-{
-  FB_
-  Sp -= 4;
-  Sp[3] = R4.w;
-  Sp[2] = R3.w;
-  Sp[1] = R2.w;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadBlocked;
-  JMP_(StgReturn);
-  FE_
-}
-
-/*- 5 Regs -------------------------------------------------------------------*/
-
-EXTFUN(gran_block_5)
-{
-  FB_
-  Sp -= 5;
-  Sp[4] = R5.w;
-  Sp[3] = R4.w;
-  Sp[2] = R3.w;
-  Sp[1] = R2.w;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadBlocked;
-  JMP_(StgReturn);
-  FE_
-}
-
-/*- 6 Regs -------------------------------------------------------------------*/
-
-EXTFUN(gran_block_6)
-{
-  FB_
-  Sp -= 6;
-  Sp[5] = R6.w;
-  Sp[4] = R5.w;
-  Sp[3] = R4.w;
-  Sp[2] = R3.w;
-  Sp[1] = R2.w;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadBlocked;
-  JMP_(StgReturn);
-  FE_
-}
-
-/*- 7 Regs -------------------------------------------------------------------*/
-
-EXTFUN(gran_block_7)
-{
-  FB_
-  Sp -= 7;
-  Sp[6] = R7.w;
-  Sp[5] = R6.w;
-  Sp[4] = R5.w;
-  Sp[3] = R4.w;
-  Sp[2] = R3.w;
-  Sp[1] = R2.w;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadBlocked;
-  JMP_(StgReturn);
-  FE_
-}
-
-/*- 8 Regs -------------------------------------------------------------------*/
-
-EXTFUN(gran_block_8)
-{
-  FB_
-  Sp -= 8;
-  Sp[7] = R8.w;
-  Sp[6] = R7.w;
-  Sp[5] = R6.w;
-  Sp[4] = R5.w;
-  Sp[3] = R4.w;
-  Sp[2] = R3.w;
-  Sp[1] = R2.w;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadBlocked;
-  JMP_(StgReturn);
-  FE_
-}
-
-#endif
-
-#if 0 && defined(PAR)
-
-/*
-  Similar to stg_block_1 (called via StgMacro BLOCK_NP) but separates the
-  saving of the thread state from the actual jump via an StgReturn.
-  We need this separation because we call RTS routines in blocking entry codes
-  before jumping back into the RTS (see parallel/FetchMe.hc).
-*/
-
-EXTFUN(par_block_1_no_jump)
-{
-  FB_
-  Sp -= 1;
-  Sp[0] = R1.w;
-  SaveThreadState();                                   
-  FE_
-}
-
-EXTFUN(par_jump)
-{
-  FB_
-  CurrentTSO->what_next = ThreadRunGHC;                
-  R1.i = ThreadBlocked;
-  JMP_(StgReturn);
-  FE_
-}
-
-#endif
-
-/* -----------------------------------------------------------------------------
-   Heap checks in Primitive case alternatives
-
-   A primitive case alternative is entered with a value either in 
-   R1, FloatReg1 or D1 depending on the return convention.  All the
-   cases are covered below.
-   -------------------------------------------------------------------------- */
-
-/*-- No Registers live ------------------------------------------------------ */
-
-EXTFUN(stg_gc_noregs)
-{
-  FB_
-  GC_GENERIC
-  FE_
-}
-
-/*-- void return ------------------------------------------------------------ */
-
-INFO_TABLE_RET( stg_gc_void_info, stg_gc_void_ret, 
-               MK_SMALL_BITMAP(0/*framesize*/, 0/*bitmap*/),
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_SMALL,, EF_, 0, 0);
-
-EXTFUN(stg_gc_void_ret)
-{
-  FB_
-  Sp += 1;
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-
-/*-- R1 is boxed/unpointed -------------------------------------------------- */
-
-INFO_TABLE_RET( stg_gc_unpt_r1_info, stg_gc_unpt_r1_ret, 
-               MK_SMALL_BITMAP(1/*framesize*/, 0/*bitmap*/),
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_SMALL,, EF_, 0, 0);
-
-EXTFUN(stg_gc_unpt_r1_ret)
-{
-  FB_
-  R1.w = Sp[1];
-  Sp += 2;
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-
-EXTFUN(stg_gc_unpt_r1)
-{
-  FB_
-  Sp -= 2;
-  Sp[1] = R1.w;
-  Sp[0] = (W_)&stg_gc_unpt_r1_info;
-  GC_GENERIC
-  FE_
-}
-
-/*-- R1 is unboxed -------------------------------------------------- */
-
-INFO_TABLE_RET(        stg_gc_unbx_r1_info, stg_gc_unbx_r1_ret, 
-               MK_SMALL_BITMAP(1/*framesize*/, 1/*bitmap*/),
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_SMALL,, EF_, 0, 0);
-
-/* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */
-
-EXTFUN(stg_gc_unbx_r1_ret)
-{
-  FB_
-  R1.w = Sp[1];
-  Sp += 2;
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-
-EXTFUN(stg_gc_unbx_r1)
-{
-  FB_
-  Sp -= 2;
-  Sp[1] = R1.w;
-  Sp[0] = (W_)&stg_gc_unbx_r1_info;
-  GC_GENERIC
-  FE_
-}
-
-/*-- F1 contains a float ------------------------------------------------- */
-
-INFO_TABLE_RET(        stg_gc_f1_info, stg_gc_f1_ret, 
-               MK_SMALL_BITMAP(1/*framesize*/, 1/*bitmap*/),
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_SMALL,, EF_, 0, 0);
-
-EXTFUN(stg_gc_f1_ret)
-{
-  FB_
-  F1 = PK_FLT(Sp+1);
-  Sp += 2;
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-
-EXTFUN(stg_gc_f1)
-{
-  FB_
-  Sp -= 2;
-  ASSIGN_FLT(Sp+1, F1);
-  Sp[0] = (W_)&stg_gc_f1_info;
-  GC_GENERIC
-  FE_
-}
-
-/*-- D1 contains a double ------------------------------------------------- */
-
-/* we support doubles of either 1 or 2 words in size */
-
-#if SIZEOF_DOUBLE == SIZEOF_VOID_P
-#  define DBL_BITMAP 1
-#  define DBL_WORDS  1
-#else
-#  define DBL_BITMAP 3
-#  define DBL_WORDS  2
-#endif 
-
-INFO_TABLE_RET(        stg_gc_d1_info, stg_gc_d1_ret, 
-               MK_SMALL_BITMAP(DBL_WORDS/*framesize*/, DBL_BITMAP/*bitmap*/),
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_SMALL,, EF_, 0, 0);
-
-EXTFUN(stg_gc_d1_ret)
-{
-  FB_
-  D1 = PK_DBL(Sp+1);
-  Sp += 1 + sizeofW(StgDouble);
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-
-EXTFUN(stg_gc_d1)
-{
-  FB_
-  Sp -= 1 + sizeofW(StgDouble);
-  ASSIGN_DBL(Sp+1,D1);
-  Sp[0] = (W_)&stg_gc_d1_info;
-  GC_GENERIC
-  FE_
-}
-
-
-/*-- L1 contains an int64 ------------------------------------------------- */
-
-/* we support int64s of either 1 or 2 words in size */
-
-#if SIZEOF_VOID_P == 8
-#  define LLI_BITMAP 1
-#  define LLI_WORDS  1
-#else
-#  define LLI_BITMAP 3
-#  define LLI_WORDS  2
-#endif 
-
-INFO_TABLE_RET( stg_gc_l1_info, stg_gc_l1_ret, 
-               MK_SMALL_BITMAP(LLI_WORDS/*framesize*/, LLI_BITMAP/*bitmap*/),
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_SMALL,, EF_, 0, 0);
-
-EXTFUN(stg_gc_l1_ret)
-{
-  FB_
-  L1 = PK_Int64(Sp+1);
-  Sp += 1 + sizeofW(StgWord64);
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-
-EXTFUN(stg_gc_l1)
-{
-  FB_
-  Sp -= 1 + sizeofW(StgWord64);
-  ASSIGN_Int64(Sp+1,L1);
-  Sp[0] = (W_)&stg_gc_l1_info;
-  GC_GENERIC
-  FE_
-}
-
-/*-- Unboxed tuple return, one pointer (unregisterised build only) ---------- */
-
-INFO_TABLE_RET( stg_ut_1_0_unreg_info, stg_ut_1_0_unreg_ret, 
-               MK_SMALL_BITMAP(1/*size*/, 0/*BITMAP*/),
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_SMALL,, EF_, 0, 0);
-
-EXTFUN(stg_ut_1_0_unreg_ret)
-{
-  FB_
-  Sp++;
-  /* one ptr is on the stack (Sp[0]) */
-  JMP_(ENTRY_CODE(Sp[1]));
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Generic function entry heap check code.
-
-   At a function entry point, the arguments are as per the calling convention,
-   i.e. some in regs and some on the stack.  There may or may not be 
-   a pointer to the function closure in R1 - if there isn't, then the heap
-   check failure code in the function will arrange to load it.
-
-   The function's argument types are described in its info table, so we
-   can just jump to this bit of generic code to save away all the
-   registers and return to the scheduler.
-
-   This code arranges the stack like this:
-        
-         |        ....         |
-         |        args         |
-        +---------------------+
-         |      f_closure      |
-        +---------------------+
-         |        size         |
-        +---------------------+
-         |   stg_gc_fun_info   |
-        +---------------------+
-
-   The size is the number of words of arguments on the stack, and is cached
-   in the frame in order to simplify stack walking: otherwise the size of
-   this stack frame would have to be calculated by looking at f's info table.
-
-   -------------------------------------------------------------------------- */
-
-EXTFUN(__stg_gc_fun)
-{
-    StgWord size;
-    StgFunInfoTable *info;
-    FB_
-
-    info = get_fun_itbl(R1.cl);
-
-    // cache the size
-    if (info->fun_type == ARG_GEN) {
-       size = BITMAP_SIZE(info->bitmap);
-    } else if (info->fun_type == ARG_GEN_BIG) {
-       size = ((StgLargeBitmap *)info->bitmap)->size;
-    } else {
-       size = BITMAP_SIZE(stg_arg_bitmaps[info->fun_type]);
-    }
-    
-#ifdef NO_ARG_REGS
-    // we don't have to save any registers away
-    Sp -= 3;
-    Sp[2] = R1.w;
-    Sp[1] = size;
-    Sp[0] = (W_)&stg_gc_fun_info;
-    GC_GENERIC
-#else
-    if (info->fun_type == ARG_GEN || info->fun_type == ARG_GEN_BIG) {
-        // regs already saved by the heap check code
-        Sp -= 3;
-        Sp[2] = R1.w;
-        Sp[1] = size;
-        Sp[0] = (W_)&stg_gc_fun_info;
-        DEBUG_ONLY(fprintf(stderr, "stg_fun_gc_gen(ARG_GEN)"););
-        GC_GENERIC
-    } else {
-        JMP_(stg_stack_save_entries[info->fun_type]);
-        // jumps to stg_gc_noregs after saving stuff
-    }
-#endif // !NO_ARG_REGS
-
-    FE_
-}   
-
-/* -----------------------------------------------------------------------------
-   Generic Apply (return point)
-
-   The dual to stg_fun_gc_gen (above): this fragment returns to the
-   function, passing arguments in the stack and in registers
-   appropriately.  The stack layout is given above.
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE_RET( stg_gc_fun_info,stg_gc_fun_ret,
-               MK_SMALL_BITMAP(0/*framesize*/, 0/*bitmap*/),
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_FUN,, EF_, 0, 0);
-
-EXTFUN(stg_gc_fun_ret)
-{
-  FB_
-  R1.w = Sp[2];
-  Sp += 3;
-#ifdef NO_ARG_REGS
-  // there are no argument registers to load up, so we can just jump
-  // straight to the function's entry point.
-  JMP_(GET_ENTRY(R1.cl));
-#else
-  {
-      StgFunInfoTable *info;
-
-      info = get_fun_itbl(R1.cl);
-      if (info->fun_type == ARG_GEN || info->fun_type == ARG_GEN_BIG) {
-         // regs already saved by the heap check code
-         DEBUG_ONLY(fprintf(stderr, "stg_gc_fun_ret(ARG_GEN)\n"););
-         JMP_(info->slow_apply);
-      } else if (info->fun_type == ARG_BCO) {
-         // cover this case just to be on the safe side
-         Sp -= 2;
-         Sp[1] = R1.cl;
-         Sp[0] = (W_)&stg_apply_interp_info;
-         JMP_(stg_yield_to_interpreter);
-      } else {
-         JMP_(stg_ap_stack_entries[info->fun_type]);
-      }
-  }
-#endif
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Generic Heap Check Code.
-
-   Called with Liveness mask in R9,  Return address in R10.
-   Stack must be consistent (containing all necessary info pointers
-   to relevant SRTs).
-
-   See StgMacros.h for a description of the RET_DYN stack frame.
-
-   We also define an stg_gen_yield here, because it's very similar.
-   -------------------------------------------------------------------------- */
-
-// For simplicity, we assume that SIZEOF_DOUBLE == 2*SIZEOF_VOID_P
-// on a 64-bit machine, we'll end up wasting a couple of words, but
-// it's not a big deal.
-
-#define RESTORE_EVERYTHING                     \
-    L1   = PK_Word64(Sp+19);                   \
-    D2   = PK_DBL(Sp+17);                      \
-    D1   = PK_DBL(Sp+15);                      \
-    F4   = PK_FLT(Sp+14);                      \
-    F3   = PK_FLT(Sp+13);                      \
-    F2   = PK_FLT(Sp+12);                      \
-    F1   = PK_FLT(Sp+11);                      \
-    R8.w = Sp[10];                             \
-    R7.w = Sp[9];                              \
-    R6.w = Sp[8];                              \
-    R5.w = Sp[7];                              \
-    R4.w = Sp[6];                              \
-    R3.w = Sp[5];                              \
-    R2.w = Sp[4];                              \
-    R1.w = Sp[3];                              \
-    Sp += 21;
-
-#define RET_OFFSET (-19)
-
-#define SAVE_EVERYTHING                                \
-    Sp -= 21;                                  \
-    ASSIGN_Word64(Sp+19,L1);                   \
-    ASSIGN_DBL(Sp+17,D2);                      \
-    ASSIGN_DBL(Sp+15,D1);                      \
-    ASSIGN_FLT(Sp+14,F4);                      \
-    ASSIGN_FLT(Sp+13,F3);                      \
-    ASSIGN_FLT(Sp+12,F2);                      \
-    ASSIGN_FLT(Sp+11,F1);                      \
-    Sp[10] = R8.w;                             \
-    Sp[9] = R7.w;                              \
-    Sp[8] = R6.w;                              \
-    Sp[7] = R5.w;                              \
-    Sp[6] = R4.w;                              \
-    Sp[5] = R3.w;                              \
-    Sp[4] = R2.w;                              \
-    Sp[3] = R1.w;                              \
-    Sp[2] = R10.w;    /* return address */     \
-    Sp[1] = R9.w;     /* liveness mask  */     \
-    Sp[0] = (W_)&stg_gc_gen_info;              \
-
-INFO_TABLE_RET( stg_gc_gen_info, stg_gc_gen_ret, 
-               0/*bitmap*/,
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_DYN,, EF_, 0, 0);
-
-/* bitmap in the above info table is unused, the real one is on the stack. 
- */
-
-FN_(stg_gc_gen_ret)
-{
-  FB_
-  RESTORE_EVERYTHING;
-  JMP_(Sp[RET_OFFSET]); /* No ENTRY_CODE() - this is an actual code ptr */
-  FE_
-}
-
-FN_(stg_gc_gen)
-{
-  FB_
-  SAVE_EVERYTHING;
-  GC_GENERIC
-  FE_
-}        
-
-// A heap check at an unboxed tuple return point.  The return address
-// is on the stack, and we can find it by using the offsets given
-// to us in the liveness mask.
-FN_(stg_gc_ut)
-{
-  FB_
-  R10.w = (W_)ENTRY_CODE(Sp[GET_NONPTRS(R9.w) + GET_PTRS(R9.w)]);
-  SAVE_EVERYTHING;
-  GC_GENERIC
-  FE_
-}
-
-/*
- * stg_gen_hp is used by MAYBE_GC, where we can't use GC_GENERIC
- * because we've just failed doYouWantToGC(), not a standard heap
- * check.  GC_GENERIC would end up returning StackOverflow.
- */
-FN_(stg_gc_gen_hp)
-{
-  FB_
-  SAVE_EVERYTHING;
-  HP_GENERIC
-  FE_
-}        
-
-/* -----------------------------------------------------------------------------
-   Yields
-   -------------------------------------------------------------------------- */
-
-FN_(stg_gen_yield)
-{
-  FB_
-  SAVE_EVERYTHING;
-  YIELD_GENERIC
-  FE_
-}
-
-FN_(stg_yield_noregs)
-{
-  FB_
-  YIELD_GENERIC;
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Yielding to the interpreter... top of stack says what to do next.
-   -------------------------------------------------------------------------- */
-
-FN_(stg_yield_to_interpreter)
-{
-  FB_
-  YIELD_TO_INTERPRETER;
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Blocks
-   -------------------------------------------------------------------------- */
-
-FN_(stg_gen_block)
-{
-  FB_
-  SAVE_EVERYTHING;
-  BLOCK_GENERIC
-  FE_
-}
-
-FN_(stg_block_noregs)
-{
-  FB_
-  BLOCK_GENERIC;
-  FE_
-}
-
-FN_(stg_block_1)
-{
-  FB_
-  Sp -= 2;
-  Sp[1] = R1.w;
-  Sp[0] = (W_)&stg_enter_info;
-  BLOCK_GENERIC;
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
- * takeMVar/putMVar-specific blocks
- *
- * Stack layout for a thread blocked in takeMVar:
- *      
- *       ret. addr
- *       ptr to MVar   (R1)
- *       stg_block_takemvar_info
- *
- * Stack layout for a thread blocked in putMVar:
- *      
- *       ret. addr
- *       ptr to Value  (R2)
- *       ptr to MVar   (R1)
- *       stg_block_putmvar_info
- *
- * See PrimOps.hc for a description of the workings of take/putMVar.
- * 
- * -------------------------------------------------------------------------- */
-
-INFO_TABLE_RET( stg_block_takemvar_info,  stg_block_takemvar_ret,
-               MK_SMALL_BITMAP(1/*framesize*/, 0/*bitmap*/),
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_SMALL,, IF_, 0, 0);
-
-IF_(stg_block_takemvar_ret)
-{
-  FB_
-  R1.w = Sp[1];
-  Sp += 2;
-  JMP_(takeMVarzh_fast);
-  FE_
-}
-
-FN_(stg_block_takemvar)
-{
-  FB_
-  Sp -= 2;
-  Sp[1] = R1.w;
-  Sp[0] = (W_)&stg_block_takemvar_info;
-  BLOCK_GENERIC;
-  FE_
-}
-
-INFO_TABLE_RET( stg_block_putmvar_info,  stg_block_putmvar_ret,
-               MK_SMALL_BITMAP(2/*framesize*/, 0/*bitmap*/),
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_SMALL,, IF_, 0, 0);
-
-IF_(stg_block_putmvar_ret)
-{
-  FB_
-  R2.w = Sp[2];
-  R1.w = Sp[1];
-  Sp += 3;
-  JMP_(putMVarzh_fast);
-  FE_
-}
-
-FN_(stg_block_putmvar)
-{
-  FB_
-  Sp -= 3;
-  Sp[2] = R2.w;
-  Sp[1] = R1.w;
-  Sp[0] = (W_)&stg_block_putmvar_info;
-  BLOCK_GENERIC;
-  FE_
-}
-
-#ifdef mingw32_TARGET_OS
-INFO_TABLE_RET( stg_block_async_info,  stg_block_async_ret,
-               MK_SMALL_BITMAP(0/*framesize*/, 0/*bitmap*/),
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_SMALL,, IF_, 0, 0);
-
-IF_(stg_block_async_ret)
-{
-  StgAsyncIOResult* ares;
-  int len,errC;
-  FB_
-  ares = CurrentTSO->block_info.async_result;
-  len  = ares->len;
-  errC = ares->errCode;
-  CurrentTSO->block_info.async_result = NULL;
-  STGCALL1(free,ares);
-  R1.w = len;
-  *Sp = (W_)errC;
-  JMP_(ENTRY_CODE(Sp[1]));
-  FE_
-}
-
-FN_(stg_block_async)
-{
-  FB_
-  Sp -= 1;
-  Sp[0] = (W_)&stg_block_async_info;
-  BLOCK_GENERIC;
-  FE_
-}
-
-#endif
index cc18059..cd7ab13 100644 (file)
@@ -4,12 +4,7 @@
  * Copyright (c) The GHC Team, 1994-2002.
  * ---------------------------------------------------------------------------*/
 
-#if !defined(SMP)
 #include "PosixSource.h"
-#else
-/* Hack and slash.. */
-#include "Stg.h"
-#endif
 #include "Rts.h"
 #include "RtsAPI.h"
 #include "RtsUtils.h"
@@ -20,6 +15,7 @@
 #include "Storage.h"
 #include "Updates.h"
 #include "Sanity.h"
+#include "Liveness.h"
 
 #include "Bytecodes.h"
 #include "Printer.h"
@@ -165,7 +161,6 @@ static StgWord app_ptrs_itbl[] = {
     (W_)&stg_ap_pppp_info,
     (W_)&stg_ap_ppppp_info,
     (W_)&stg_ap_pppppp_info,
-    (W_)&stg_ap_ppppppp_info
 };
 
 StgThreadReturnCode
@@ -400,9 +395,6 @@ do_return:
        if (info == (StgInfoTable *)&stg_ap_pppppp_info) {
            n = 6; m = 6; goto do_apply;
        }
-       if (info == (StgInfoTable *)&stg_ap_ppppppp_info) {
-           n = 7; m = 7; goto do_apply;
-       }
        goto do_return_unrecognised;
     }
 
@@ -815,7 +807,7 @@ run_BCO:
 
        case bci_PUSH_ALTS: {
            int o_bco  = BCO_NEXT;
-           Sp[-2] = (W_)&stg_ctoi_ret_R1p_info;
+           Sp[-2] = (W_)&stg_ctoi_R1p_info;
            Sp[-1] = BCO_PTR(o_bco);
            Sp -= 2;
            goto nextInsn;
@@ -823,7 +815,7 @@ run_BCO:
 
        case bci_PUSH_ALTS_P: {
            int o_bco  = BCO_NEXT;
-           Sp[-2] = (W_)&stg_ctoi_ret_R1unpt_info;
+           Sp[-2] = (W_)&stg_ctoi_R1unpt_info;
            Sp[-1] = BCO_PTR(o_bco);
            Sp -= 2;
            goto nextInsn;
@@ -831,7 +823,7 @@ run_BCO:
 
        case bci_PUSH_ALTS_N: {
            int o_bco  = BCO_NEXT;
-           Sp[-2] = (W_)&stg_ctoi_ret_R1n_info;
+           Sp[-2] = (W_)&stg_ctoi_R1n_info;
            Sp[-1] = BCO_PTR(o_bco);
            Sp -= 2;
            goto nextInsn;
@@ -839,7 +831,7 @@ run_BCO:
 
        case bci_PUSH_ALTS_F: {
            int o_bco  = BCO_NEXT;
-           Sp[-2] = (W_)&stg_ctoi_ret_F1_info;
+           Sp[-2] = (W_)&stg_ctoi_F1_info;
            Sp[-1] = BCO_PTR(o_bco);
            Sp -= 2;
            goto nextInsn;
@@ -847,7 +839,7 @@ run_BCO:
 
        case bci_PUSH_ALTS_D: {
            int o_bco  = BCO_NEXT;
-           Sp[-2] = (W_)&stg_ctoi_ret_D1_info;
+           Sp[-2] = (W_)&stg_ctoi_D1_info;
            Sp[-1] = BCO_PTR(o_bco);
            Sp -= 2;
            goto nextInsn;
@@ -855,7 +847,7 @@ run_BCO:
 
        case bci_PUSH_ALTS_L: {
            int o_bco  = BCO_NEXT;
-           Sp[-2] = (W_)&stg_ctoi_ret_L1_info;
+           Sp[-2] = (W_)&stg_ctoi_L1_info;
            Sp[-1] = BCO_PTR(o_bco);
            Sp -= 2;
            goto nextInsn;
@@ -863,7 +855,7 @@ run_BCO:
 
        case bci_PUSH_ALTS_V: {
            int o_bco  = BCO_NEXT;
-           Sp[-2] = (W_)&stg_ctoi_ret_V_info;
+           Sp[-2] = (W_)&stg_ctoi_V_info;
            Sp[-1] = BCO_PTR(o_bco);
            Sp -= 2;
            goto nextInsn;
@@ -902,9 +894,6 @@ run_BCO:
        case bci_PUSH_APPLY_PPPPPP:
            Sp--; Sp[0] = (W_)&stg_ap_pppppp_info;
            goto nextInsn;
-       case bci_PUSH_APPLY_PPPPPPP:
-           Sp--; Sp[0] = (W_)&stg_ap_ppppppp_info;
-           goto nextInsn;
            
        case bci_PUSH_UBX: {
            int i;
@@ -1018,7 +1007,7 @@ run_BCO:
            int discr  = BCO_NEXT;
            int failto = BCO_NEXT;
            StgClosure* con = (StgClosure*)Sp[0];
-           if (constrTag(con) >= discr) {
+           if (GET_TAG(con) >= discr) {
                bciPtr = failto;
            }
            goto nextInsn;
@@ -1028,7 +1017,7 @@ run_BCO:
            int discr  = BCO_NEXT;
            int failto = BCO_NEXT;
            StgClosure* con = (StgClosure*)Sp[0];
-           if (constrTag(con) != discr) {
+           if (GET_TAG(con) != discr) {
                bciPtr = failto;
            }
            goto nextInsn;
@@ -1191,11 +1180,11 @@ run_BCO:
            // on the stack frame to describe this chunk of stack.
            //
            Sp -= ret_dyn_size;
-           ((StgRetDyn *)Sp)->liveness = ALL_NON_PTRS | N_NONPTRS(stk_offset);
+           ((StgRetDyn *)Sp)->liveness = NO_PTRS | N_NONPTRS(stk_offset);
            ((StgRetDyn *)Sp)->info = (StgInfoTable *)&stg_gc_gen_info;
 
            SAVE_STACK_POINTERS;
-           tok = suspendThread(&cap->r,rtsFalse);
+           tok = suspendThread(&cap->r);
 
 #ifndef RTS_SUPPORTS_THREADS
            // Careful:
@@ -1212,7 +1201,7 @@ run_BCO:
 #endif
 
            // And restart the thread again, popping the RET_DYN frame.
-           cap = (Capability *)((void *)((unsigned char*)resumeThread(tok,rtsFalse) - sizeof(StgFunTable)));
+           cap = (Capability *)((void *)((unsigned char*)resumeThread(tok) - sizeof(StgFunTable)));
            LOAD_STACK_POINTERS;
            Sp += ret_dyn_size;
            
index 7db8903..d0ed1c8 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: LdvProfile.c,v 1.6 2003/11/12 17:49:08 sof Exp $
+ * $Id: LdvProfile.c,v 1.7 2004/08/13 13:10:05 simonmar Exp $
  *
  * (c) The GHC Team, 2001
  * Author: Sungwoo Park
@@ -10,7 +10,6 @@
 
 #ifdef PROFILING
 
-#include "Stg.h"
 #include "Rts.h"
 #include "LdvProfile.h"
 #include "RtsFlags.h"
index a9d3089..e6e82aa 100644 (file)
@@ -22,8 +22,8 @@
 #include "Linker.h"
 #include "LinkerInternals.h"
 #include "RtsUtils.h"
-#include "StoragePriv.h"
 #include "Schedule.h"
+#include "Storage.h"
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -312,12 +312,34 @@ typedef struct _RtsSymbolVal {
 # define MAIN_CAP_SYM
 #endif
 
+#ifdef TABLES_NEXT_TO_CODE
+#define RTS_RET_SYMBOLS /* nothing */
+#else
+#define RTS_RET_SYMBOLS                        \
+      SymX(stg_enter_ret)                      \
+      SymX(stg_gc_fun_ret)                     \
+      SymX(stg_ap_0_ret)                       \
+      SymX(stg_ap_v_ret)                       \
+      SymX(stg_ap_f_ret)                       \
+      SymX(stg_ap_d_ret)                       \
+      SymX(stg_ap_l_ret)                       \
+      SymX(stg_ap_n_ret)                       \
+      SymX(stg_ap_p_ret)                       \
+      SymX(stg_ap_pv_ret)                      \
+      SymX(stg_ap_pp_ret)                      \
+      SymX(stg_ap_ppv_ret)                     \
+      SymX(stg_ap_ppp_ret)                     \
+      SymX(stg_ap_pppv_ret)                    \
+      SymX(stg_ap_pppp_ret)                    \
+      SymX(stg_ap_ppppp_ret)                   \
+      SymX(stg_ap_pppppp_ret)
+#endif
+
 #define RTS_SYMBOLS                            \
       Maybe_ForeignObj                         \
       Maybe_Stable_Names                       \
       Sym(StgReturn)                           \
       SymX(stg_enter_info)                     \
-      SymX(stg_enter_ret)                      \
       SymX(stg_gc_void_info)                   \
       SymX(__stg_gc_enter_1)                   \
       SymX(stg_gc_noregs)                      \
@@ -333,7 +355,6 @@ typedef struct _RtsSymbolVal {
       SymX(stg_gc_l1)                          \
       SymX(__stg_gc_fun)                       \
       SymX(stg_gc_fun_info)                    \
-      SymX(stg_gc_fun_ret)                     \
       SymX(stg_gc_gen)                         \
       SymX(stg_gc_gen_info)                    \
       SymX(stg_gc_gen_hp)                      \
@@ -504,25 +525,10 @@ typedef struct _RtsSymbolVal {
       SymX(stg_ap_pp_info)                     \
       SymX(stg_ap_ppv_info)                    \
       SymX(stg_ap_ppp_info)                    \
+      SymX(stg_ap_pppv_info)                   \
       SymX(stg_ap_pppp_info)                   \
       SymX(stg_ap_ppppp_info)                  \
       SymX(stg_ap_pppppp_info)                 \
-      SymX(stg_ap_ppppppp_info)                        \
-      SymX(stg_ap_0_ret)                       \
-      SymX(stg_ap_v_ret)                       \
-      SymX(stg_ap_f_ret)                       \
-      SymX(stg_ap_d_ret)                       \
-      SymX(stg_ap_l_ret)                       \
-      SymX(stg_ap_n_ret)                       \
-      SymX(stg_ap_p_ret)                       \
-      SymX(stg_ap_pv_ret)                      \
-      SymX(stg_ap_pp_ret)                      \
-      SymX(stg_ap_ppv_ret)                     \
-      SymX(stg_ap_ppp_ret)                     \
-      SymX(stg_ap_pppp_ret)                    \
-      SymX(stg_ap_ppppp_ret)                   \
-      SymX(stg_ap_pppppp_ret)                  \
-      SymX(stg_ap_ppppppp_ret)                 \
       SymX(stg_ap_1_upd_info)                  \
       SymX(stg_ap_2_upd_info)                  \
       SymX(stg_ap_3_upd_info)                  \
@@ -530,7 +536,6 @@ typedef struct _RtsSymbolVal {
       SymX(stg_ap_5_upd_info)                  \
       SymX(stg_ap_6_upd_info)                  \
       SymX(stg_ap_7_upd_info)                  \
-      SymX(stg_ap_8_upd_info)                  \
       SymX(stg_exit)                           \
       SymX(stg_sel_0_upd_info)                 \
       SymX(stg_sel_10_upd_info)                        \
@@ -608,6 +613,7 @@ typedef struct _RtsSymbolVal {
 #define SymX(vvv) /**/
 #define SymX_redirect(vvv,xxx) /**/
 RTS_SYMBOLS
+RTS_RET_SYMBOLS
 RTS_LONG_LONG_SYMS
 RTS_POSIX_ONLY_SYMBOLS
 RTS_MINGW_ONLY_SYMBOLS
@@ -3247,7 +3253,45 @@ static int relocateSection(
                              - relocateAddress(oc, nSections, sections, pair->r_value));
                        i++;
                    }
-                   else
+                   else if(scat->r_type == PPC_RELOC_HI16
+                         || scat->r_type == PPC_RELOC_LO16
+                         || scat->r_type == PPC_RELOC_HA16
+                         || scat->r_type == PPC_RELOC_LO14)
+                    {   // these are generated by label+offset things
+                       struct relocation_info *pair = &relocs[i+1];
+                        if((pair->r_address & R_SCATTERED) || pair->r_type != PPC_RELOC_PAIR)
+                           barf("Invalid Mach-O file: "
+                                "PPC_RELOC_* not followed by PPC_RELOC_PAIR");
+                        
+                        if(scat->r_type == PPC_RELOC_LO16)
+                        {
+                            word = ((unsigned short*) wordPtr)[1];
+                            word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF) << 16;
+                        }
+                        else if(scat->r_type == PPC_RELOC_LO14)
+                        {
+                            barf("Unsupported Relocation: PPC_RELOC_LO14");
+                            word = ((unsigned short*) wordPtr)[1] & 0xFFFC;
+                            word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF) << 16;
+                        }
+                        else if(scat->r_type == PPC_RELOC_HI16)
+                        {
+                            word = ((unsigned short*) wordPtr)[1] << 16;
+                            word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF);
+                        }
+                        else if(scat->r_type == PPC_RELOC_HA16)
+                        {
+                            word = ((unsigned short*) wordPtr)[1] << 16;
+                            word += ((short)relocs[i+1].r_address & (short)0xFFFF);
+                        }
+                       
+                        
+                        word += (unsigned long) relocateAddress(oc, nSections, sections, scat->r_value)
+                                                - scat->r_value;
+                        
+                        i++;
+                    }
+                    else
                        continue;  // ignore the others
 
                     if(scat->r_type == GENERIC_RELOC_VANILLA
@@ -3255,15 +3299,15 @@ static int relocateSection(
                     {
                         *wordPtr = word;
                     }
-                    else if(scat->r_type == PPC_RELOC_LO16_SECTDIFF)
+                    else if(scat->r_type == PPC_RELOC_LO16_SECTDIFF || scat->r_type == PPC_RELOC_LO16)
                     {
                         ((unsigned short*) wordPtr)[1] = word & 0xFFFF;
                     }
-                    else if(scat->r_type == PPC_RELOC_HI16_SECTDIFF)
+                    else if(scat->r_type == PPC_RELOC_HI16_SECTDIFF || scat->r_type == PPC_RELOC_HI16)
                     {
                         ((unsigned short*) wordPtr)[1] = (word >> 16) & 0xFFFF;
                     }
-                    else if(scat->r_type == PPC_RELOC_HA16_SECTDIFF)
+                    else if(scat->r_type == PPC_RELOC_HA16_SECTDIFF || scat->r_type == PPC_RELOC_HA16)
                     {
                         ((unsigned short*) wordPtr)[1] = ((word >> 16) & 0xFFFF)
                             + ((word & (1<<15)) ? 1 : 0);
@@ -3327,15 +3371,17 @@ static int relocateSection(
                {
                    struct nlist *symbol = &nlist[reloc->r_symbolnum];
                    char *nm = image + symLC->stroff + symbol->n_un.n_strx;
-                   word = (unsigned long) (lookupSymbol(nm));
-                   if(!word)
+                   unsigned long symbolAddress = (unsigned long) (lookupSymbol(nm));
+                   if(!symbolAddress)
                    {
                        belch("\nunknown symbol `%s'", nm);
                        return 0;
                    }
 
                    if(reloc->r_pcrel)
-                    {
+                    {  
+                        ASSERT(word == 0);
+                        word = symbolAddress;
                         jumpIsland = (long) makeJumpIsland(oc,reloc->r_symbolnum,(void*)word);
                        word -= ((long)image) + sect->offset + reloc->r_address;
                         if(jumpIsland != 0)
@@ -3344,6 +3390,10 @@ static int relocateSection(
                                 - (((long)image) + sect->offset + reloc->r_address);
                         }
                     }
+                    else
+                    {
+                        word += symbolAddress;
+                    }
                }
 
                if(reloc->r_type == GENERIC_RELOC_VANILLA)
index f58c214..64fd459 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: MBlock.h,v 1.19 2003/09/21 13:26:05 igloo Exp $
+ * $Id: MBlock.h,v 1.20 2004/08/13 13:10:10 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -9,7 +9,8 @@
 
 #ifndef __MBLOCK_H__
 #define __MBLOCK_H__
-extern lnat mblocks_allocated;
+
+extern lnat RTS_VAR(mblocks_allocated);
 
 extern void * getMBlock(void);
 extern void * getMBlocks(nat n);
index 6029921..114b3fc 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Main.c,v 1.40 2003/09/21 22:20:55 wolfgang Exp $
+ * $Id: Main.c,v 1.41 2004/08/13 13:10:10 simonmar Exp $
  *
  * (c) The GHC Team 1998-2000
  *
 # include "Printer.h"   /* for printing        */
 #endif
 
-#ifdef INTERPRETER
-# include "Assembler.h"
-#endif
-
 #ifdef PAR
 # include "Parallel.h"
 # include "ParallelRts.h"
index 733399e..c31a486 100644 (file)
@@ -60,16 +60,18 @@ endif
 EXCLUDED_SRCS += parallel/SysMan.c
 
 # The build system doesn't give us these
-HC_SRCS = $(filter %.hc, $(SRCS))
-HC_OBJS = $(patsubst %.hc,%.$(way_)o, $(HC_SRCS))
+CMM_SRCS = $(filter-out AutoApply%.cmm, $(wildcard *.cmm)) $(EXTRA_CMM_SRCS)
+CMM_OBJS = $(patsubst %.cmm,%.$(way_)o, $(CMM_SRCS))
 
-CLEAN_FILES += $(HC_OBJS)
+CLEAN_FILES += $(CMM_OBJS)
 
 # Override the default $(LIBOBJS) (defaults to $(HS_OBJS))
-LIBOBJS = $(C_OBJS) $(HC_OBJS)
+LIBOBJS = $(C_OBJS) $(CMM_OBJS)
 
 SplitObjs=NO
 
+H_FILES = $(wildcard ../includes/*.h) $(wildcard *.h)
+
 #-----------------------------------------------------------------------------
 # Flags for compiling RTS .c and .hc files
 
@@ -101,7 +103,7 @@ ifeq "$(HOSTPLATFORM)" "i386-unknown-mingw32"
 STANDARD_OPTS += -Iwin32
 endif
 
-# HC_OPTS is included in both .c and .hc compilations, whereas CC_OPTS is
+# HC_OPTS is included in both .c and .cmm compilations, whereas CC_OPTS is
 # only included in .c compilations.  HC_OPTS included the WAY_* opts, which
 # must be included in both types of compilations.
 
@@ -163,7 +165,6 @@ endif
 #-----------------------------------------------------------------------------
 # make depend setup
 
-MKDEPENDC_SRCS     = $(C_SRCS) $(HC_SRCS)
 SRC_MKDEPENDC_OPTS += -I. -I../includes
 
 # Hack: we define every way-related option here, so that we get (hopefully)
@@ -175,17 +176,20 @@ SRC_MKDEPENDC_OPTS += -DPROFILING -DTHREADED_RTS -DDEBUG
 # -----------------------------------------------------------------------------
 # The auto-generated apply code
 
-AUTO_APPLY = AutoApply.hc
+# We want a slightly different version for the unregisterised way, so we make
+# AutoApply on a per-way basis (eg. AutoApply_p.cmm).
+
+AUTO_APPLY_CMM = AutoApply$(_way).cmm
 
 ifneq "$(BootingFromHc)" "YES"
-$(AUTO_APPLY): $(GHC_GENAPPLY)
+$(AUTO_APPLY_CMM): $(GHC_GENAPPLY)
        @$(RM) $@
-       $(GHC_GENAPPLY) >$@
+       $(GHC_GENAPPLY) $(if $(filter u,$(way)), -u) >$@
 endif
 
-EXTRA_SRCS += $(AUTO_APPLY)
+EXTRA_CMM_SRCS += $(AUTO_APPLY_CMM)
 
-CLEAN_FILES += $(AUTO_APPLY)
+CLEAN_FILES += $(AUTO_APPLY_CMM)
 
 # -----------------------------------------------------------------------------
 #
@@ -277,6 +281,50 @@ INSTALL_LIBEXECS += parallel/SysMan
 endif
 
 #-----------------------------------------------------------------------------
+# Compiling the cmm files
+
+# ToDo: should we really include Rts.h here?  Required for GNU_ATTRIBUTE().
+SRC_HC_OPTS += \
+  -\#include Prelude.h \
+  -\#include Rts.h \
+  -\#include RtsFlags.h \
+  -\#include RtsUtils.h \
+  -\#include StgRun.h \
+  -\#include Schedule.h \
+  -\#include Printer.h \
+  -\#include Sanity.h \
+  -\#include Storage.h \
+  -\#include SchedAPI.h \
+  -\#include Timer.h \
+  -\#include Itimer.h \
+  -\#include ProfHeap.h \
+  -\#include LdvProfile.h \
+  -\#include Profiling.h \
+  -\#include Apply.h
+
+# Cmm must be compiled via-C for now, because the NCG can't handle loops
+SRC_HC_OPTS += -fvia-C
+
+# We *want* type-checking of hand-written cmm.
+SRC_HC_OPTS += -dcmm-lint 
+
+# .cmm files depend on all the .h files, to a first approximation.
+%.$(way_)o : %.cmm $(H_FILES)
+       $(HC_PRE_OPTS)
+       $(HC) $(HC_OPTS) -c $< -o $@
+       $(HC_POST_OPTS)
+
+%.$(way_)hc : %.cmm $(H_FILES)
+       $(HC_PRE_OPTS)
+       $(HC) $(HC_OPTS) -C $< -o $@
+       $(HC_POST_OPTS)
+
+%.$(way_)s : %.cmm $(H_FILES)
+       $(HC_PRE_OPTS)
+       $(HC) $(HC_OPTS) -S $< -o $@
+       $(HC_POST_OPTS)
+
+#-----------------------------------------------------------------------------
 #
 # Files to install
 #
index 634ba5b..8e268f4 100644 (file)
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
- * $Id: Prelude.h,v 1.25 2004/03/01 14:11:01 simonmar Exp $
+ * $Id: Prelude.h,v 1.26 2004/08/13 13:10:12 simonmar Exp $
  *
- * (c) The GHC Team, 1998-2001
+ * (c) The GHC Team, 1998-2004
  *
  * Prelude identifiers that we sometimes need to refer to in the RTS.
  *
 #ifndef PRELUDE_H
 #define PRELUDE_H
 
+/* These definitions are required by the RTS .cmm files too, so we
+ * need declarations that we can #include into the generated .hc files.
+ */
+#if IN_STG_CODE
+#define PRELUDE_INFO(i)       extern W_(i)[]
+#define PRELUDE_CLOSURE(i)    extern W_(i)[]
+#else
+#define PRELUDE_INFO(i)       extern DLL_IMPORT const StgInfoTable i
+#define PRELUDE_CLOSURE(i)    extern DLL_IMPORT StgClosure i
+#endif
+
 /* Define canonical names so we can abstract away from the actual
  * modules these names are defined in.
  */
 
-extern DLL_IMPORT StgClosure GHCziBase_True_closure;
-extern DLL_IMPORT StgClosure GHCziBase_False_closure;
-extern DLL_IMPORT StgClosure GHCziPack_unpackCString_closure;
-extern DLL_IMPORT StgClosure GHCziWeak_runFinalizzerBatch_closure;
+PRELUDE_CLOSURE(GHCziBase_True_closure);
+PRELUDE_CLOSURE(GHCziBase_False_closure);
+PRELUDE_CLOSURE(GHCziPack_unpackCString_closure);
+PRELUDE_CLOSURE(GHCziWeak_runFinalizzerBatch_closure);
+
+#ifdef IN_STG_CODE
+extern W_ ZCMain_main_closure[];
+#else
 extern StgClosure ZCMain_main_closure;
-extern DLL_IMPORT StgClosure GHCziTopHandler_runIO_closure;
-extern DLL_IMPORT StgClosure GHCziTopHandler_runNonIO_closure;
+#endif
 
-extern DLL_IMPORT StgClosure GHCziIOBase_stackOverflow_closure;
-extern DLL_IMPORT StgClosure GHCziIOBase_heapOverflow_closure;
-extern DLL_IMPORT StgClosure GHCziIOBase_BlockedOnDeadMVar_closure;
-extern DLL_IMPORT StgClosure GHCziIOBase_NonTermination_closure;
+PRELUDE_CLOSURE(GHCziIOBase_stackOverflow_closure);
+PRELUDE_CLOSURE(GHCziIOBase_heapOverflow_closure);
+PRELUDE_CLOSURE(GHCziIOBase_BlockedOnDeadMVar_closure);
+PRELUDE_CLOSURE(GHCziIOBase_NonTermination_closure);
 
-extern DLL_IMPORT const StgInfoTable GHCziBase_Czh_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziBase_Izh_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziFloat_Fzh_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziFloat_Dzh_static_info;
-extern DLL_IMPORT const StgInfoTable Addr_Azh_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziPtr_Ptr_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziPtr_FunPtr_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziInt_I8zh_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziInt_I16zh_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziInt_I32zh_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziInt_I64zh_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziWord_Wzh_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziWord_W8zh_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziWord_W16zh_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziWord_W32zh_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziWord_W64zh_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziBase_Czh_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziBase_Izh_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziFloat_Fzh_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziFloat_Dzh_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziPtr_Ptr_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziPtr_FunPtr_con_info;
-extern DLL_IMPORT const StgInfoTable Addr_Azh_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziWord_Wzh_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziInt_I8zh_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziInt_I16zh_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziInt_I32zh_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziInt_I64zh_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziWord_W8zh_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziWord_W16zh_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziWord_W32zh_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziWord_W64zh_con_info;
-extern DLL_IMPORT const StgInfoTable GHCziStable_StablePtr_static_info;
-extern DLL_IMPORT const StgInfoTable GHCziStable_StablePtr_con_info;
+PRELUDE_INFO(GHCziBase_Czh_static_info);
+PRELUDE_INFO(GHCziBase_Izh_static_info);
+PRELUDE_INFO(GHCziFloat_Fzh_static_info);
+PRELUDE_INFO(GHCziFloat_Dzh_static_info);
+PRELUDE_INFO(Addr_Azh_static_info);
+PRELUDE_INFO(GHCziPtr_Ptr_static_info);
+PRELUDE_INFO(GHCziPtr_FunPtr_static_info);
+PRELUDE_INFO(GHCziInt_I8zh_static_info);
+PRELUDE_INFO(GHCziInt_I16zh_static_info);
+PRELUDE_INFO(GHCziInt_I32zh_static_info);
+PRELUDE_INFO(GHCziInt_I64zh_static_info);
+PRELUDE_INFO(GHCziWord_Wzh_static_info);
+PRELUDE_INFO(GHCziWord_W8zh_static_info);
+PRELUDE_INFO(GHCziWord_W16zh_static_info);
+PRELUDE_INFO(GHCziWord_W32zh_static_info);
+PRELUDE_INFO(GHCziWord_W64zh_static_info);
+PRELUDE_INFO(GHCziBase_Czh_con_info);
+PRELUDE_INFO(GHCziBase_Izh_con_info);
+PRELUDE_INFO(GHCziFloat_Fzh_con_info);
+PRELUDE_INFO(GHCziFloat_Dzh_con_info);
+PRELUDE_INFO(GHCziPtr_Ptr_con_info);
+PRELUDE_INFO(GHCziPtr_FunPtr_con_info);
+PRELUDE_INFO(Addr_Azh_con_info);
+PRELUDE_INFO(GHCziWord_Wzh_con_info);
+PRELUDE_INFO(GHCziInt_I8zh_con_info);
+PRELUDE_INFO(GHCziInt_I16zh_con_info);
+PRELUDE_INFO(GHCziInt_I32zh_con_info);
+PRELUDE_INFO(GHCziInt_I64zh_con_info);
+PRELUDE_INFO(GHCziWord_W8zh_con_info);
+PRELUDE_INFO(GHCziWord_W16zh_con_info);
+PRELUDE_INFO(GHCziWord_W32zh_con_info);
+PRELUDE_INFO(GHCziWord_W64zh_con_info);
+PRELUDE_INFO(GHCziStable_StablePtr_static_info);
+PRELUDE_INFO(GHCziStable_StablePtr_con_info);
 
 #define True_closure              (&GHCziBase_True_closure)
 #define False_closure             (&GHCziBase_False_closure)
 #define unpackCString_closure     (&GHCziPack_unpackCString_closure)
 #define runFinalizerBatch_closure (&GHCziWeak_runFinalizzerBatch_closure)
 #define mainIO_closure            (&ZCMain_main_closure)
-#define runIO_closure            (&GHCziTopHandler_runIO_closure)
-#define runNonIO_closure         (&GHCziTopHandler_runNonIO_closure)
 
 #define stackOverflow_closure     (&GHCziIOBase_stackOverflow_closure)
 #define heapOverflow_closure      (&GHCziIOBase_heapOverflow_closure)
diff --git a/ghc/rts/PrimOps.cmm b/ghc/rts/PrimOps.cmm
new file mode 100644 (file)
index 0000000..59a613d
--- /dev/null
@@ -0,0 +1,1511 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2004
+ *
+ * Out-of-line primitive operations
+ *
+ * This file contains the implementations of all the primitive
+ * operations ("primops") which are not expanded inline.  See
+ * ghc/compiler/prelude/primops.txt.pp for a list of all the primops;
+ * this file contains code for most of those with the attribute
+ * out_of_line=True.
+ *
+ * Entry convention: the entry convention for a primop is that all the
+ * args are in Stg registers (R1, R2, etc.).  This is to make writing
+ * the primops easier.  (see compiler/codeGen/CgCallConv.hs).
+ *
+ * Return convention: results from a primop are generally returned
+ * using the ordinary unboxed tuple return convention.  The C-- parser
+ * implements the RET_xxxx() macros to perform unboxed-tuple returns
+ * based on the prevailing return convention.
+ *
+ * This file is written in a subset of C--, extended with various
+ * features specific to GHC.  It is compiled by GHC directly.  For the
+ * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "Cmm.h"
+
+/*-----------------------------------------------------------------------------
+  Array Primitives
+
+  Basically just new*Array - the others are all inline macros.
+
+  The size arg is always passed in R1, and the result returned in R1.
+
+  The slow entry point is for returning from a heap check, the saved
+  size argument must be re-loaded from the stack.
+  -------------------------------------------------------------------------- */
+
+/* for objects that are *less* than the size of a word, make sure we
+ * round up to the nearest word for the size of the array.
+ */
+
+newByteArrayzh_fast
+{
+    W_ words, payload_words, n, p;
+    MAYBE_GC(NO_PTRS,newByteArrayzh_fast);
+    n = R1;
+    payload_words = ROUNDUP_BYTES_TO_WDS(n);
+    words = BYTES_TO_WDS(SIZEOF_StgArrWords) + payload_words;
+    "ptr" p = foreign "C" allocate(words);
+    TICK_ALLOC_PRIM(SIZEOF_StgArrWords,WDS(payload_words),0);
+    SET_HDR(p, stg_ARR_WORDS_info, W_[CCCS]);
+    StgArrWords_words(p) = payload_words;
+    RET_P(p);
+}
+
+newPinnedByteArrayzh_fast
+{
+    W_ words, payload_words, n, p;
+
+    MAYBE_GC(NO_PTRS,newPinnedByteArrayzh_fast);
+    n = R1;
+    payload_words = ROUNDUP_BYTES_TO_WDS(n);
+
+    // We want an 8-byte aligned array.  allocatePinned() gives us
+    // 8-byte aligned memory by default, but we want to align the
+    // *goods* inside the ArrWords object, so we have to check the
+    // size of the ArrWords header and adjust our size accordingly.
+    words = BYTES_TO_WDS(SIZEOF_StgArrWords) + payload_words;
+    if ((SIZEOF_StgArrWords & 7) != 0) {
+       words = words + 1;
+    }
+
+    "ptr" p = foreign "C" allocatePinned(words);
+    TICK_ALLOC_PRIM(SIZEOF_StgArrWords,WDS(payload_words),0);
+
+    // Again, if the ArrWords header isn't a multiple of 8 bytes, we
+    // have to push the object forward one word so that the goods
+    // fall on an 8-byte boundary.
+    if ((SIZEOF_StgArrWords & 7) != 0) {
+       p = p + WDS(1);
+    }
+
+    SET_HDR(p, stg_ARR_WORDS_info, W_[CCCS]);
+    StgArrWords_words(p) = payload_words;
+    RET_P(p);
+}
+
+newArrayzh_fast
+{
+    W_ words, n, init, arr, p;
+    /* Args: R1 = words, R2 = initialisation value */
+
+    n = R1;
+    MAYBE_GC(R2_PTR,newArrayzh_fast);
+
+    words = BYTES_TO_WDS(SIZEOF_StgMutArrPtrs) + n;
+    "ptr" arr = foreign "C" allocate(words);
+    TICK_ALLOC_PRIM(SIZEOF_StgMutArrPtrs, WDS(n), 0);
+
+    SET_HDR(arr, stg_MUT_ARR_PTRS_info, W_[CCCS]);
+    StgMutArrPtrs_ptrs(arr) = n;
+
+    // Initialise all elements of the the array with the value in R2
+    init = R2;
+    p = arr + SIZEOF_StgMutArrPtrs;
+  for:
+    if (p < arr + WDS(words)) {
+       W_[p] = init;
+       p = p + WDS(1);
+       goto for;
+    }
+
+    RET_P(arr);
+}
+
+unsafeThawArrayzh_fast
+{
+  SET_INFO(R1,stg_MUT_ARR_PTRS_info);
+
+  // SUBTLETY TO DO WITH THE OLD GEN MUTABLE LIST
+  //
+  // A MUT_ARR_PTRS lives on the mutable list, but a MUT_ARR_PTRS_FROZEN 
+  // normally doesn't.  However, when we freeze a MUT_ARR_PTRS, we leave
+  // it on the mutable list for the GC to remove (removing something from
+  // the mutable list is not easy, because the mut_list is only singly-linked).
+  // 
+  // So, when we thaw a MUT_ARR_PTRS_FROZEN, we must cope with two cases:
+  // either it is on a mut_list, or it isn't.  We adopt the convention that
+  // the mut_link field is NULL if it isn't on a mut_list, and the GC
+  // maintains this invariant.
+  //
+  if (StgMutClosure_mut_link(R1) == NULL) {
+       foreign "C" recordMutable(R1 "ptr");
+  }
+
+  RET_P(R1);
+}
+
+/* -----------------------------------------------------------------------------
+   MutVar primitives
+   -------------------------------------------------------------------------- */
+
+newMutVarzh_fast
+{
+    W_ mv;
+    /* Args: R1 = initialisation value */
+
+    ALLOC_PRIM( SIZEOF_StgMutVar, R1_PTR, newMutVarzh_fast);
+
+    mv = Hp - SIZEOF_StgMutVar + WDS(1);
+    SET_HDR(mv,stg_MUT_VAR_info,W_[CCCS]);
+    StgMutVar_var(mv) = R1;
+    
+    RET_P(mv);
+}
+
+atomicModifyMutVarzh_fast
+{
+    W_ mv, z, x, y, r;
+    /* Args: R1 :: MutVar#,  R2 :: a -> (a,b) */
+
+    /* If x is the current contents of the MutVar#, then 
+       We want to make the new contents point to
+
+         (sel_0 (f x))
+       and the return value is
+        
+        (sel_1 (f x))
+
+        obviously we can share (f x).
+
+         z = [stg_ap_2 f x]  (max (HS + 2) MIN_UPD_SIZE)
+        y = [stg_sel_0 z]   (max (HS + 1) MIN_UPD_SIZE)
+         r = [stg_sel_1 z]   (max (HS + 1) MIN_UPD_SIZE)
+    */
+
+#if MIN_UPD_SIZE > 1
+#define THUNK_1_SIZE (SIZEOF_StgHeader + WDS(MIN_UPD_SIZE))
+#define TICK_ALLOC_THUNK_1() TICK_ALLOC_UP_THK(WDS(1),WDS(MIN_UPD_SIZE-1))
+#else
+#define THUNK_1_SIZE (SIZEOF_StgHeader + WDS(1))
+#define TICK_ALLOC_THUNK_1() TICK_ALLOC_UP_THK(WDS(1),0)
+#endif
+
+#if MIN_UPD_SIZE > 2
+#define THUNK_2_SIZE (SIZEOF_StgHeader + WDS(MIN_UPD_SIZE))
+#define TICK_ALLOC_THUNK_2() TICK_ALLOC_UP_THK(WDS(2),WDS(MIN_UPD_SIZE-2))
+#else
+#define THUNK_2_SIZE (SIZEOF_StgHeader + WDS(2))
+#define TICK_ALLOC_THUNK_2() TICK_ALLOC_UP_THK(WDS(2),0)
+#endif
+
+#define SIZE (THUNK_2_SIZE + THUNK_1_SIZE + THUNK_1_SIZE)
+
+   HP_CHK_GEN_TICKY(SIZE, R1_PTR & R2_PTR, atomicModifyMutVarzh_fast);
+
+   x = StgMutVar_var(R1);
+
+   TICK_ALLOC_THUNK_2();
+   CCCS_ALLOC(THUNK_2_SIZE);
+   z = Hp - THUNK_2_SIZE + WDS(1);
+   SET_HDR(z, stg_ap_2_upd_info, W_[CCCS]);
+   LDV_RECORD_CREATE(z);
+   StgClosure_payload(z,0) = R2;
+   StgClosure_payload(z,1) = x;
+
+   TICK_ALLOC_THUNK_1();
+   CCCS_ALLOC(THUNK_1_SIZE);
+   y = z - THUNK_1_SIZE;
+   SET_HDR(y, stg_sel_0_upd_info, W_[CCCS]);
+   LDV_RECORD_CREATE(y);
+   StgClosure_payload(y,0) = z;
+
+   StgMutVar_var(R1) = y;
+
+   TICK_ALLOC_THUNK_1();
+   CCCS_ALLOC(THUNK_1_SIZE);
+   r = y - THUNK_1_SIZE;
+   SET_HDR(r, stg_sel_1_upd_info, W_[CCCS]);
+   LDV_RECORD_CREATE(r);
+   StgClosure_payload(r,0) = z;
+
+   RET_P(r);
+}
+
+/* -----------------------------------------------------------------------------
+   Foreign Object Primitives
+   -------------------------------------------------------------------------- */
+
+mkForeignObjzh_fast
+{
+  /* R1 = ptr to foreign object,
+  */
+  W_ result;
+
+  ALLOC_PRIM( SIZEOF_StgForeignObj, NO_PTRS, mkForeignObjzh_fast);
+
+  result = Hp - SIZEOF_StgForeignObj + WDS(1);
+  SET_HDR(result,stg_FOREIGN_info,W_[CCCS]);
+  StgForeignObj_data(result) = R1;
+
+  /* returns (# s#, ForeignObj# #) */
+  RET_P(result);
+}
+
+/* -----------------------------------------------------------------------------
+   Weak Pointer Primitives
+   -------------------------------------------------------------------------- */
+
+STRING(stg_weak_msg,"New weak pointer at %p\n")
+
+mkWeakzh_fast
+{
+  /* R1 = key
+     R2 = value
+     R3 = finalizer (or NULL)
+  */
+  W_ w;
+
+  if (R3 == NULL) {
+    R3 = stg_NO_FINALIZER_closure;
+  }
+
+  ALLOC_PRIM( SIZEOF_StgWeak, R1_PTR & R2_PTR & R3_PTR, mkWeakzh_fast );
+
+  w = Hp - SIZEOF_StgWeak + WDS(1);
+  SET_HDR(w, stg_WEAK_info, W_[CCCS]);
+
+  StgWeak_key(w)       = R1;
+  StgWeak_value(w)     = R2;
+  StgWeak_finalizer(w) = R3;
+
+  StgWeak_link(w)      = W_[weak_ptr_list];
+  W_[weak_ptr_list]    = w;
+
+  IF_DEBUG(weak, foreign "C" fprintf(stderr,stg_weak_msg,w));
+
+  RET_P(w);
+}
+
+
+finalizzeWeakzh_fast
+{
+  /* R1 = weak ptr
+   */
+  W_ w, f;
+
+  w = R1;
+
+  // already dead?
+  if (GET_INFO(w) == stg_DEAD_WEAK_info) {
+      RET_NP(0,stg_NO_FINALIZER_closure);
+  }
+
+  // kill it
+#ifdef PROFILING
+  // @LDV profiling
+  // A weak pointer is inherently used, so we do not need to call
+  // LDV_recordDead_FILL_SLOP_DYNAMIC():
+  //    LDV_recordDead_FILL_SLOP_DYNAMIC((StgClosure *)w);
+  // or, LDV_recordDead():
+  //    LDV_recordDead((StgClosure *)w, sizeofW(StgWeak) - sizeofW(StgProfHeader));
+  // Furthermore, when PROFILING is turned on, dead weak pointers are exactly as 
+  // large as weak pointers, so there is no need to fill the slop, either.
+  // See stg_DEAD_WEAK_info in StgMiscClosures.hc.
+#endif
+
+  //
+  // Todo: maybe use SET_HDR() and remove LDV_recordCreate()?
+  //
+  SET_INFO(w,stg_DEAD_WEAK_info);
+  LDV_RECORD_CREATE(w);
+
+  f = StgWeak_finalizer(w);
+
+  /* return the finalizer */
+  if (f == stg_NO_FINALIZER_closure) {
+      RET_NP(0,stg_NO_FINALIZER_closure);
+  } else {
+      RET_NP(1,f);
+  }
+}
+
+deRefWeakzh_fast
+{
+  /* R1 = weak ptr */
+  W_ w, code, val;
+
+  w = R1;
+  if (GET_INFO(w) == stg_WEAK_info) {
+    code = 1;
+    val = StgWeak_value(w);
+  } else {
+    code = 0;
+    val = w;
+  }
+  RET_NP(code,val);
+}
+
+/* -----------------------------------------------------------------------------
+   Arbitrary-precision Integer operations.
+
+   There are some assumptions in this code that mp_limb_t == W_.  This is
+   the case for all the platforms that GHC supports, currently.
+   -------------------------------------------------------------------------- */
+
+int2Integerzh_fast
+{
+   /* arguments: R1 = Int# */
+
+   W_ val, s, p;       /* to avoid aliasing */
+
+   val = R1;
+   ALLOC_PRIM( SIZEOF_StgArrWords + WDS(1), NO_PTRS, int2Integerzh_fast );
+
+   p = Hp - SIZEOF_StgArrWords;
+   SET_HDR(p, stg_ARR_WORDS_info, W_[CCCS]);
+   StgArrWords_words(p) = 1;
+
+   /* mpz_set_si is inlined here, makes things simpler */
+   if (%lt(val,0)) { 
+       s  = -1;
+       Hp(0) = -val;
+   } else { 
+     if (%gt(val,0)) {
+       s = 1;
+       Hp(0) = val;
+     } else {
+       s = 0;
+     }
+  }
+
+   /* returns (# size  :: Int#, 
+                data  :: ByteArray# 
+              #)
+   */
+   RET_NP(s,p);
+}
+
+word2Integerzh_fast
+{
+   /* arguments: R1 = Word# */
+
+   W_ val, s, p;       /* to avoid aliasing */
+
+   val = R1;
+
+   ALLOC_PRIM( SIZEOF_StgArrWords + WDS(1), NO_PTRS, word2Integerzh_fast);
+
+   p = Hp - SIZEOF_StgArrWords;
+   SET_HDR(p, stg_ARR_WORDS_info, W_[CCCS]);
+   StgArrWords_words(p) = 1;
+
+   if (val != 0) {
+       s = 1;
+       W_[Hp] = val;
+   } else {
+       s = 0;
+   }
+
+   /* returns (# size  :: Int#, 
+                data  :: ByteArray# #)
+   */
+   RET_NP(s,p);
+}
+
+
+/*
+ * 'long long' primops for converting to/from Integers.
+ */
+
+#ifdef SUPPORT_LONG_LONGS
+
+int64ToIntegerzh_fast
+{
+   /* arguments: L1 = Int64# */
+
+   L_ val;
+   W_ hi, s, neg, words_needed, p;
+
+   val = L1;
+   neg = 0;
+
+   if ( %ge(val,0x100000000::L_) || %le(val,-0x100000000::L_) )  { 
+       words_needed = 2;
+   } else { 
+       // minimum is one word
+       words_needed = 1;
+   }
+
+   ALLOC_PRIM( SIZEOF_StgArrWords + WDS(words_needed),
+              NO_PTRS, int64ToIntegerzh_fast );
+
+   p = Hp - SIZEOF_StgArrWords - WDS(words_needed) + WDS(1);
+   SET_HDR(p, stg_ARR_WORDS_info, W_[CCCS]);
+   StgArrWords_words(p) = words_needed;
+
+   if ( %lt(val,0::L_) ) {
+     neg = 1;
+     val = -val;
+   }
+
+   hi = TO_W_(val >> 32);
+
+   if ( words_needed == 2 )  { 
+      s = 2;
+      Hp(-1) = TO_W_(val);
+      Hp(0) = hi;
+   } else { 
+       if ( val != 0::L_ ) {
+          s = 1;
+          Hp(0) = TO_W_(val);
+       } else /* val==0 */  {
+          s = 0;
+       }
+   }
+   if ( neg != 0 ) {
+       s = -s;
+   }
+
+   /* returns (# size  :: Int#, 
+                data  :: ByteArray# #)
+   */
+   RET_NP(s,p);
+}
+
+word64ToIntegerzh_fast
+{
+   /* arguments: L1 = Word64# */
+
+   L_ val;
+   W_ hi, s, words_needed, p;
+
+   val = L1;
+   if ( val >= 0x100000000::L_ ) {
+      words_needed = 2;
+   } else {
+      words_needed = 1;
+   }
+
+   ALLOC_PRIM( SIZEOF_StgArrWords + WDS(words_needed),
+              NO_PTRS, word64ToIntegerzh_fast );
+
+   p = Hp - SIZEOF_StgArrWords - WDS(words_needed) + WDS(1);
+   SET_HDR(p, stg_ARR_WORDS_info, W_[CCCS]);
+   StgArrWords_words(p) = words_needed;
+
+   hi = TO_W_(val >> 32);
+   if ( val >= 0x100000000::L_ ) { 
+     s = 2;
+     Hp(-1) = TO_W_(val);
+     Hp(0)  = hi;
+   } else {
+      if ( val != 0::L_ ) {
+        s = 1;
+        Hp(0) = TO_W_(val);
+     } else /* val==0 */  {
+      s = 0;
+     }
+  }
+
+   /* returns (# size  :: Int#, 
+                data  :: ByteArray# #)
+   */
+   RET_NP(s,p);
+}
+
+
+#endif /* SUPPORT_LONG_LONGS */
+
+/* ToDo: this is shockingly inefficient */
+
+section "bss" {
+  mp_tmp1:
+    bits8 [SIZEOF_MP_INT];
+}
+
+section "bss" {
+  mp_tmp2:
+    bits8 [SIZEOF_MP_INT];
+}
+
+section "bss" {
+  result1:
+    bits8 [SIZEOF_MP_INT];
+}
+
+section "bss" {
+  result2:
+    bits8 [SIZEOF_MP_INT];
+}
+
+#define GMP_TAKE2_RET1(name,mp_fun)                    \
+name                                                   \
+{                                                      \
+  W_ s1, s2, d1, d2;                                   \
+                                                       \
+  /* call doYouWantToGC() */                           \
+  MAYBE_GC(R2_PTR & R4_PTR, name);                     \
+                                                       \
+  s1 = R1;                                             \
+  d1 = R2;                                             \
+  s2 = R3;                                             \
+  d2 = R4;                                             \
+                                                       \
+  MP_INT__mp_alloc(mp_tmp1) = StgArrWords_words(d1);   \
+  MP_INT__mp_size(mp_tmp1)  = (s1);                    \
+  MP_INT__mp_d(mp_tmp1)            = BYTE_ARR_CTS(d1);         \
+  MP_INT__mp_alloc(mp_tmp2) = StgArrWords_words(d2);   \
+  MP_INT__mp_size(mp_tmp2)  = (s2);                    \
+  MP_INT__mp_d(mp_tmp2)            = BYTE_ARR_CTS(d2);         \
+                                                       \
+  foreign "C" mpz_init(result1);                       \
+                                                       \
+  /* Perform the operation */                          \
+  foreign "C" mp_fun(result1,mp_tmp1,mp_tmp2);         \
+                                                       \
+  RET_NP(MP_INT__mp_size(result1),                     \
+         MP_INT__mp_d(result1) - SIZEOF_StgArrWords);  \
+}
+
+#define GMP_TAKE1_RET1(name,mp_fun)                            \
+name                                                           \
+{                                                              \
+  W_ s1, d1;                                                   \
+                                                               \
+  /* call doYouWantToGC() */                                   \
+  MAYBE_GC(R2_PTR, name);                                      \
+                                                               \
+  d1 = R2;                                                     \
+  s1 = R1;                                                     \
+                                                               \
+  MP_INT__mp_alloc(mp_tmp1)    = StgArrWords_words(d1);        \
+  MP_INT__mp_size(mp_tmp1)     = (s1);                         \
+  MP_INT__mp_d(mp_tmp1)                = BYTE_ARR_CTS(d1);             \
+                                                               \
+  foreign "C" mpz_init(result1);                               \
+                                                               \
+  /* Perform the operation */                                  \
+  foreign "C" mp_fun(result1,mp_tmp1);                         \
+                                                               \
+  RET_NP(MP_INT__mp_size(result1),                             \
+         MP_INT__mp_d(result1) - SIZEOF_StgArrWords);          \
+}
+
+#define GMP_TAKE2_RET2(name,mp_fun)                            \
+name                                                           \
+{                                                              \
+  W_ s1, s2, d1, d2;                                           \
+                                                               \
+  /* call doYouWantToGC() */                                   \
+  MAYBE_GC(R2_PTR & R4_PTR, name);                             \
+                                                               \
+  s1 = R1;                                                     \
+  d1 = R2;                                                     \
+  s2 = R3;                                                     \
+  d2 = R4;                                                     \
+                                                               \
+  MP_INT__mp_alloc(mp_tmp1)    = StgArrWords_words(d1);        \
+  MP_INT__mp_size(mp_tmp1)     = (s1);                         \
+  MP_INT__mp_d(mp_tmp1)                = BYTE_ARR_CTS(d1);             \
+  MP_INT__mp_alloc(mp_tmp2)    = StgArrWords_words(d2);        \
+  MP_INT__mp_size(mp_tmp2)     = (s2);                         \
+  MP_INT__mp_d(mp_tmp2)                = BYTE_ARR_CTS(d2);             \
+                                                               \
+  foreign "C" mpz_init(result1);                               \
+  foreign "C" mpz_init(result2);                               \
+                                                               \
+  /* Perform the operation */                                  \
+  foreign "C" mp_fun(result1,result2,mp_tmp1,mp_tmp2);         \
+                                                               \
+  RET_NPNP(MP_INT__mp_size(result1),                           \
+           MP_INT__mp_d(result1) - SIZEOF_StgArrWords,         \
+          MP_INT__mp_size(result2),                            \
+           MP_INT__mp_d(result2) - SIZEOF_StgArrWords);                \
+}
+
+GMP_TAKE2_RET1(plusIntegerzh_fast,     mpz_add)
+GMP_TAKE2_RET1(minusIntegerzh_fast,    mpz_sub)
+GMP_TAKE2_RET1(timesIntegerzh_fast,    mpz_mul)
+GMP_TAKE2_RET1(gcdIntegerzh_fast,      mpz_gcd)
+GMP_TAKE2_RET1(quotIntegerzh_fast,     mpz_tdiv_q)
+GMP_TAKE2_RET1(remIntegerzh_fast,      mpz_tdiv_r)
+GMP_TAKE2_RET1(divExactIntegerzh_fast, mpz_divexact)
+GMP_TAKE2_RET1(andIntegerzh_fast,      mpz_and)
+GMP_TAKE2_RET1(orIntegerzh_fast,       mpz_ior)
+GMP_TAKE2_RET1(xorIntegerzh_fast,      mpz_xor)
+GMP_TAKE1_RET1(complementIntegerzh_fast, mpz_com)
+
+GMP_TAKE2_RET2(quotRemIntegerzh_fast, mpz_tdiv_qr)
+GMP_TAKE2_RET2(divModIntegerzh_fast,  mpz_fdiv_qr)
+
+section "bss" {
+  aa:  W_; // NB. aa is really an mp_limb_t
+}
+
+gcdIntzh_fast
+{
+    /* R1 = the first Int#; R2 = the second Int# */
+    W_ r; 
+
+    W_[aa] = R1;
+    r = foreign "C" mpn_gcd_1(aa, 1, R2);
+
+    R1 = r;
+    /* Result parked in R1, return via info-pointer at TOS */
+    jump %ENTRY_CODE(Sp(0));
+}
+
+
+gcdIntegerIntzh_fast
+{
+    /* R1 = s1; R2 = d1; R3 = the int */
+    R1 = foreign "C" mpn_gcd_1( BYTE_ARR_CTS(R2) "ptr", R1, R3);
+    
+    /* Result parked in R1, return via info-pointer at TOS */
+    jump %ENTRY_CODE(Sp(0));
+}
+
+
+cmpIntegerIntzh_fast
+{
+    /* R1 = s1; R2 = d1; R3 = the int */
+    W_ usize, vsize, v_digit, u_digit;
+
+    usize = R1;
+    vsize = 0;
+    v_digit = R3;
+
+    // paraphrased from mpz_cmp_si() in the GMP sources
+    if (%gt(v_digit,0)) {
+       vsize = 1;
+    } else { 
+       if (%lt(v_digit,0)) {
+           vsize = -1;
+           v_digit = -v_digit;
+       }
+    }
+
+    if (usize != vsize) {
+       R1 = usize - vsize; 
+       jump %ENTRY_CODE(Sp(0));
+    }
+
+    if (usize == 0) {
+       R1 = 0; 
+       jump %ENTRY_CODE(Sp(0));
+    }
+
+    u_digit = W_[BYTE_ARR_CTS(R2)];
+
+    if (u_digit == v_digit) {
+       R1 = 0; 
+       jump %ENTRY_CODE(Sp(0));
+    }
+
+    if (%gtu(u_digit,v_digit)) { // NB. unsigned: these are mp_limb_t's
+       R1 = usize; 
+    } else {
+       R1 = -usize; 
+    }
+
+    jump %ENTRY_CODE(Sp(0));
+}
+
+cmpIntegerzh_fast
+{
+    /* R1 = s1; R2 = d1; R3 = s2; R4 = d2 */
+    W_ usize, vsize, size, up, vp;
+    CInt cmp;
+
+    // paraphrased from mpz_cmp() in the GMP sources
+    usize = R1;
+    vsize = R3;
+
+    if (usize != vsize) {
+       R1 = usize - vsize; 
+       jump %ENTRY_CODE(Sp(0));
+    }
+
+    if (usize == 0) {
+       R1 = 0; 
+       jump %ENTRY_CODE(Sp(0));
+    }
+
+    if (%lt(usize,0)) { // NB. not <, which is unsigned
+       size = -usize;
+    } else {
+       size = usize;
+    }
+
+    up = BYTE_ARR_CTS(R2);
+    vp = BYTE_ARR_CTS(R4);
+
+    cmp = foreign "C" mpn_cmp(up "ptr", vp "ptr", size);
+
+    if (cmp == 0) {
+       R1 = 0; 
+       jump %ENTRY_CODE(Sp(0));
+    }
+
+    if (%lt(cmp,0) == %lt(usize,0)) {
+       R1 = 1;
+    } else {
+       R1 = (-1); 
+    }
+    /* Result parked in R1, return via info-pointer at TOS */
+    jump %ENTRY_CODE(Sp(0));
+}
+
+integer2Intzh_fast
+{
+    /* R1 = s; R2 = d */
+    W_ r, s;
+
+    s = R1;
+    if (s == 0) {
+       r = 0;
+    } else {
+       r = W_[R2 + SIZEOF_StgArrWords];
+       if (%lt(s,0)) {
+           r = -r;
+       }
+    }
+    /* Result parked in R1, return via info-pointer at TOS */
+    R1 = r;
+    jump %ENTRY_CODE(Sp(0));
+}
+
+integer2Wordzh_fast
+{
+  /* R1 = s; R2 = d */
+  W_ r, s;
+
+  s = R1;
+  if (s == 0) {
+    r = 0;
+  } else {
+    r = W_[R2 + SIZEOF_StgArrWords];
+    if (%lt(s,0)) {
+       r = -r;
+    }
+  }
+  /* Result parked in R1, return via info-pointer at TOS */
+  R1 = r;
+  jump %ENTRY_CODE(Sp(0));
+}
+
+section "bss" {
+  exponent:  W_;
+}
+
+decodeFloatzh_fast
+{ 
+    W_ p;
+    F_ arg;
+    
+    /* arguments: F1 = Float# */
+    arg = F1;
+    
+    ALLOC_PRIM( SIZEOF_StgArrWords + WDS(1), NO_PTRS, decodeFloatzh_fast );
+    
+    /* Be prepared to tell Lennart-coded __decodeFloat
+       where mantissa._mp_d can be put (it does not care about the rest) */
+    p = Hp - SIZEOF_StgArrWords;
+    SET_HDR(p,stg_ARR_WORDS_info,W_[CCCS]);
+    StgArrWords_words(p) = 1;
+    MP_INT__mp_d(mp_tmp1) = BYTE_ARR_CTS(p);
+    
+    /* Perform the operation */
+    foreign "C" __decodeFloat(mp_tmp1,exponent,arg);
+    
+    /* returns: (Int# (expn), Int#, ByteArray#) */
+    RET_NNP(W_[exponent], MP_INT__mp_size(mp_tmp1), p);
+}
+
+#define DOUBLE_MANTISSA_SIZE SIZEOF_DOUBLE
+#define ARR_SIZE (SIZEOF_StgArrWords + DOUBLE_MANTISSA_SIZE)
+
+decodeDoublezh_fast
+{ 
+    D_ arg;
+    W_ p;
+
+    /* arguments: D1 = Double# */
+    arg = D1;
+
+    ALLOC_PRIM( ARR_SIZE, NO_PTRS, decodeDoublezh_fast );
+    
+    /* Be prepared to tell Lennart-coded __decodeDouble
+       where mantissa.d can be put (it does not care about the rest) */
+    p = Hp - ARR_SIZE + WDS(1);
+    SET_HDR(p, stg_ARR_WORDS_info, W_[CCCS]);
+    StgArrWords_words(p) = BYTES_TO_WDS(DOUBLE_MANTISSA_SIZE);
+    MP_INT__mp_d(mp_tmp1) = BYTE_ARR_CTS(p);
+
+    /* Perform the operation */
+    foreign "C" __decodeDouble(mp_tmp1,exponent,arg);
+    
+    /* returns: (Int# (expn), Int#, ByteArray#) */
+    RET_NNP(W_[exponent], MP_INT__mp_size(mp_tmp1), p);
+}
+
+/* -----------------------------------------------------------------------------
+ * Concurrency primitives
+ * -------------------------------------------------------------------------- */
+
+forkzh_fast
+{
+  /* args: R1 = closure to spark */
+  
+  MAYBE_GC(R1_PTR, forkzh_fast);
+
+  // create it right now, return ThreadID in R1
+  "ptr" R1 = foreign "C" createIOThread( RtsFlags_GcFlags_initialStkSize(RtsFlags), 
+                                  R1 "ptr");
+  foreign "C" scheduleThread(R1 "ptr");
+
+  // switch at the earliest opportunity
+  CInt[context_switch] = 1;
+  
+  RET_P(R1);
+}
+
+yieldzh_fast
+{
+  jump stg_yield_noregs;
+}
+
+myThreadIdzh_fast
+{
+  /* no args. */
+  RET_P(CurrentTSO);
+}
+
+labelThreadzh_fast
+{
+  /* args: 
+       R1 = ThreadId#
+       R2 = Addr# */
+#ifdef DEBUG
+  foreign "C" labelThread(R1 "ptr", R2 "ptr");
+#endif
+  jump %ENTRY_CODE(Sp(0));
+}
+
+isCurrentThreadBoundzh_fast
+{
+  /* no args */
+  W_ r;
+  r = foreign "C" isThreadBound(CurrentTSO);
+  RET_N(r);
+}
+
+/* -----------------------------------------------------------------------------
+ * MVar primitives
+ *
+ * take & putMVar work as follows.  Firstly, an important invariant:
+ *
+ *    If the MVar is full, then the blocking queue contains only
+ *    threads blocked on putMVar, and if the MVar is empty then the
+ *    blocking queue contains only threads blocked on takeMVar.
+ *
+ * takeMvar:
+ *    MVar empty : then add ourselves to the blocking queue
+ *    MVar full  : remove the value from the MVar, and
+ *                 blocking queue empty     : return
+ *                 blocking queue non-empty : perform the first blocked putMVar
+ *                                            from the queue, and wake up the
+ *                                            thread (MVar is now full again)
+ *
+ * putMVar is just the dual of the above algorithm.
+ *
+ * How do we "perform a putMVar"?  Well, we have to fiddle around with
+ * the stack of the thread waiting to do the putMVar.  See
+ * stg_block_putmvar and stg_block_takemvar in HeapStackCheck.c for
+ * the stack layout, and the PerformPut and PerformTake macros below.
+ *
+ * It is important that a blocked take or put is woken up with the
+ * take/put already performed, because otherwise there would be a
+ * small window of vulnerability where the thread could receive an
+ * exception and never perform its take or put, and we'd end up with a
+ * deadlock.
+ *
+ * -------------------------------------------------------------------------- */
+
+isEmptyMVarzh_fast
+{
+    /* args: R1 = MVar closure */
+
+    if (GET_INFO(R1) == stg_EMPTY_MVAR_info) {
+       RET_N(0);
+    } else {
+       RET_N(1);
+    }
+}
+
+newMVarzh_fast
+{
+    /* args: none */
+    W_ mvar;
+
+    ALLOC_PRIM ( SIZEOF_StgMVar, NO_PTRS, newMVarzh_fast );
+  
+    mvar = Hp - SIZEOF_StgMVar + WDS(1);
+    SET_HDR(mvar,stg_EMPTY_MVAR_info,W_[CCCS]);
+    StgMVar_head(mvar)  = stg_END_TSO_QUEUE_closure;
+    StgMVar_tail(mvar)  = stg_END_TSO_QUEUE_closure;
+    StgMVar_value(mvar) = stg_END_TSO_QUEUE_closure;
+    RET_P(mvar);
+}
+
+
+/* If R1 isn't available, pass it on the stack */
+#ifdef REG_R1
+#define PerformTake(tso, value)                                \
+    W_[StgTSO_sp(tso) + WDS(1)] = value;               \
+    W_[StgTSO_sp(tso) + WDS(0)] = stg_gc_unpt_r1_info;
+#else
+#define PerformTake(tso, value)                                        \
+    W_[StgTSO_sp(tso) + WDS(1)] = value;                       \
+    W_[StgTSO_sp(tso) + WDS(0)] = stg_ut_1_0_unreg_info;
+#endif
+
+#define PerformPut(tso,lval)                   \
+    StgTSO_sp(tso) = StgTSO_sp(tso) + WDS(3);  \
+    lval = W_[StgTSO_sp(tso) - WDS(1)];
+
+
+takeMVarzh_fast
+{
+    W_ mvar, val, info, tso;
+
+    /* args: R1 = MVar closure */
+    mvar = R1;
+
+    info = GET_INFO(mvar);
+
+    /* If the MVar is empty, put ourselves on its blocking queue,
+     * and wait until we're woken up.
+     */
+    if (info == stg_EMPTY_MVAR_info) {
+       if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
+           StgMVar_head(mvar) = CurrentTSO;
+       } else {
+           StgTSO_link(StgMVar_tail(mvar)) = CurrentTSO;
+       }
+       StgTSO_link(CurrentTSO)        = stg_END_TSO_QUEUE_closure;
+       StgTSO_why_blocked(CurrentTSO) = BlockedOnMVar::I16;
+       StgTSO_block_info(CurrentTSO)  = mvar;
+       StgMVar_tail(mvar) = CurrentTSO;
+       
+       jump stg_block_takemvar;
+  }
+
+  /* we got the value... */
+  val = StgMVar_value(mvar);
+
+  if (StgMVar_head(mvar) != stg_END_TSO_QUEUE_closure)
+  {
+      /* There are putMVar(s) waiting... 
+       * wake up the first thread on the queue
+       */
+      ASSERT(StgTSO_why_blocked(StgMVar_head(mvar)) == BlockedOnMVar::I16);
+
+      /* actually perform the putMVar for the thread that we just woke up */
+      tso = StgMVar_head(mvar);
+      PerformPut(tso,StgMVar_value(mvar));
+
+#if defined(GRAN) || defined(PAR)
+      /* ToDo: check 2nd arg (mvar) is right */
+      "ptr" tso = foreign "C" unblockOne(StgMVar_head(mvar),mvar);
+      StgMVar_head(mvar) = tso;
+#else
+      "ptr" tso = foreign "C" unblockOne(StgMVar_head(mvar) "ptr");
+      StgMVar_head(mvar) = tso;
+#endif
+      if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
+         StgMVar_tail(mvar) = stg_END_TSO_QUEUE_closure;
+      }
+      RET_P(val);
+  } 
+  else
+  {
+      /* No further putMVars, MVar is now empty */
+      
+      /* do this last... we might have locked the MVar in the SMP case,
+       * and writing the info pointer will unlock it.
+       */
+      SET_INFO(mvar,stg_EMPTY_MVAR_info);
+      StgMVar_value(mvar) = stg_END_TSO_QUEUE_closure;
+      RET_P(val);
+  }
+}
+
+
+tryTakeMVarzh_fast
+{
+    W_ mvar, val, info, tso;
+
+    /* args: R1 = MVar closure */
+
+    mvar = R1;
+
+    info = GET_INFO(mvar);
+
+    if (info == stg_EMPTY_MVAR_info) {
+       /* HACK: we need a pointer to pass back, 
+        * so we abuse NO_FINALIZER_closure
+        */
+       RET_NP(0, stg_NO_FINALIZER_closure);
+    }
+
+    /* we got the value... */
+    val = StgMVar_value(mvar);
+
+    if (StgMVar_head(mvar) != stg_END_TSO_QUEUE_closure) {
+       /* There are putMVar(s) waiting... 
+        * wake up the first thread on the queue
+        */
+       ASSERT(StgTSO_why_blocked(StgMVar_head(mvar)) == BlockedOnMVar::I16);
+
+       /* actually perform the putMVar for the thread that we just woke up */
+       tso = StgMVar_head(mvar);
+       PerformPut(tso,StgMVar_value(mvar));
+
+#if defined(GRAN) || defined(PAR)
+       /* ToDo: check 2nd arg (mvar) is right */
+       "ptr" tso = foreign "C" unblockOne(StgMVar_head(mvar) "ptr", mvar "ptr");
+       StgMVar_head(mvar) = tso;
+#else
+       "ptr" tso = foreign "C" unblockOne(StgMVar_head(mvar) "ptr");
+       StgMVar_head(mvar) = tso;
+#endif
+
+       if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
+           StgMVar_tail(mvar) = stg_END_TSO_QUEUE_closure;
+       }
+    }
+    else 
+    {
+       /* No further putMVars, MVar is now empty */
+       StgMVar_value(mvar) = stg_END_TSO_QUEUE_closure;
+       
+       /* do this last... we might have locked the MVar in the SMP case,
+        * and writing the info pointer will unlock it.
+        */
+       SET_INFO(mvar,stg_EMPTY_MVAR_info);
+    }
+    
+    RET_NP(1, val);
+}
+
+
+putMVarzh_fast
+{
+    W_ mvar, info, tso;
+
+    /* args: R1 = MVar, R2 = value */
+    mvar = R1;
+
+    info = GET_INFO(mvar);
+
+    if (info == stg_FULL_MVAR_info) {
+       if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
+           StgMVar_head(mvar) = CurrentTSO;
+       } else {
+           StgTSO_link(StgMVar_tail(mvar)) = CurrentTSO;
+       }
+       StgTSO_link(CurrentTSO)        = stg_END_TSO_QUEUE_closure;
+       StgTSO_why_blocked(CurrentTSO) = BlockedOnMVar::I16;
+       StgTSO_block_info(CurrentTSO)  = mvar;
+       StgMVar_tail(mvar) = CurrentTSO;
+       
+       jump stg_block_putmvar;
+    }
+  
+    if (StgMVar_head(mvar) != stg_END_TSO_QUEUE_closure) {
+       /* There are takeMVar(s) waiting: wake up the first one
+        */
+       ASSERT(StgTSO_why_blocked(StgMVar_head(mvar)) == BlockedOnMVar::I16);
+
+       /* actually perform the takeMVar */
+       tso = StgMVar_head(mvar);
+       PerformTake(tso, R2);
+      
+#if defined(GRAN) || defined(PAR)
+       /* ToDo: check 2nd arg (mvar) is right */
+       "ptr" tso = foreign "C" unblockOne(StgMVar_head(mvar) "ptr",mvar "ptr");
+       StgMVar_head(mvar) = tso;
+#else
+       "ptr" tso = foreign "C" unblockOne(StgMVar_head(mvar) "ptr");
+       StgMVar_head(mvar) = tso;
+#endif
+
+       if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
+           StgMVar_tail(mvar) = stg_END_TSO_QUEUE_closure;
+       }
+
+       jump %ENTRY_CODE(Sp(0));
+    }
+    else
+    {
+       /* No further takes, the MVar is now full. */
+       StgMVar_value(mvar) = R2;
+       /* unlocks the MVar in the SMP case */
+       SET_INFO(mvar,stg_FULL_MVAR_info);
+       jump %ENTRY_CODE(Sp(0));
+    }
+    
+    /* ToDo: yield afterward for better communication performance? */
+}
+
+
+tryPutMVarzh_fast
+{
+    W_ mvar, info, tso;
+
+    /* args: R1 = MVar, R2 = value */
+    mvar = R1;
+
+    info = GET_INFO(mvar);
+
+    if (info == stg_FULL_MVAR_info) {
+       RET_N(0);
+    }
+  
+    if (StgMVar_head(mvar) != stg_END_TSO_QUEUE_closure) {
+       /* There are takeMVar(s) waiting: wake up the first one
+        */
+       ASSERT(StgTSO_why_blocked(StgMVar_head(mvar)) == BlockedOnMVar::I16);
+       
+       /* actually perform the takeMVar */
+       tso = StgMVar_head(mvar);
+       PerformTake(tso, R2);
+      
+#if defined(GRAN) || defined(PAR)
+       /* ToDo: check 2nd arg (mvar) is right */
+       "ptr" tso = foreign "C" unblockOne(StgMVar_head(mvar) "ptr",mvar "ptr");
+       StgMVar_head(mvar) = tso;
+#else
+       "ptr" tso = foreign "C" unblockOne(StgMVar_head(mvar) "ptr");
+       StgMVar_head(mvar) = tso;
+#endif
+
+       if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
+           StgMVar_tail(mvar) = stg_END_TSO_QUEUE_closure;
+       }
+
+       jump %ENTRY_CODE(Sp(0));
+    }
+    else
+    {
+       /* No further takes, the MVar is now full. */
+       StgMVar_value(mvar) = R2;
+       /* unlocks the MVar in the SMP case */
+       SET_INFO(mvar,stg_FULL_MVAR_info);
+       jump %ENTRY_CODE(Sp(0));
+    }
+    
+    /* ToDo: yield afterward for better communication performance? */
+}
+
+
+/* -----------------------------------------------------------------------------
+   Stable pointer primitives
+   -------------------------------------------------------------------------  */
+
+makeStableNamezh_fast
+{
+    W_ index, sn_obj;
+
+    ALLOC_PRIM( SIZEOF_StgStableName, R1_PTR, makeStableNamezh_fast );
+  
+    index = foreign "C" lookupStableName(R1 "ptr");
+
+    /* Is there already a StableName for this heap object?
+     *  stable_ptr_table is an array of snEntry structs.
+     */
+    if ( snEntry_sn_obj(stable_ptr_table + index*SIZEOF_snEntry) == NULL ) {
+       sn_obj = Hp - SIZEOF_StgStableName + WDS(1);
+       SET_HDR(sn_obj, stg_STABLE_NAME_info, W_[CCCS]);
+       StgStableName_sn(sn_obj) = index;
+       snEntry_sn_obj(stable_ptr_table + index*SIZEOF_snEntry) = sn_obj;
+    } else {
+       sn_obj = snEntry_sn_obj(stable_ptr_table + index*SIZEOF_snEntry);
+    }
+    
+    RET_P(sn_obj);
+}
+
+
+makeStablePtrzh_fast
+{
+    /* Args: R1 = a */
+    W_ sp;
+    MAYBE_GC(R1_PTR, makeStablePtrzh_fast);
+    "ptr" sp = foreign "C" getStablePtr(R1 "ptr");
+    RET_N(sp);
+}
+
+deRefStablePtrzh_fast
+{
+    /* Args: R1 = the stable ptr */
+    W_ r, sp;
+    sp = R1;
+    r = snEntry_addr(stable_ptr_table + sp*SIZEOF_snEntry);
+    RET_P(r);
+}
+
+/* -----------------------------------------------------------------------------
+   Bytecode object primitives
+   -------------------------------------------------------------------------  */
+
+newBCOzh_fast
+{
+    /* R1 = instrs
+       R2 = literals
+       R3 = ptrs
+       R4 = itbls
+       R5 = arity
+       R6 = bitmap array
+    */
+    W_ bco, bitmap_arr, bytes, words;
+    
+    bitmap_arr = R6;
+    words = BYTES_TO_WDS(SIZEOF_StgBCO) + StgArrWords_words(bitmap_arr);
+    bytes = WDS(words);
+
+    ALLOC_PRIM( bytes, R1_PTR&R2_PTR&R3_PTR&R4_PTR&R6_PTR, newBCOzh_fast );
+
+    bco = Hp - bytes + WDS(1);
+    SET_HDR(bco, stg_BCO_info, W_[CCCS]);
+    
+    StgBCO_instrs(bco)     = R1;
+    StgBCO_literals(bco)   = R2;
+    StgBCO_ptrs(bco)       = R3;
+    StgBCO_itbls(bco)      = R4;
+    StgBCO_arity(bco)      = HALF_W_(R5);
+    StgBCO_size(bco)       = HALF_W_(words);
+    
+    // Copy the arity/bitmap info into the BCO
+    W_ i;
+    i = 0;
+for:
+    if (i < StgArrWords_words(bitmap_arr)) {
+       StgBCO_bitmap(bco,i) = StgArrWords_payload(bitmap_arr,i);
+       i = i + 1;
+       goto for;
+    }
+    
+    RET_P(bco);
+}
+
+
+mkApUpd0zh_fast
+{
+    // R1 = the BCO# for the AP
+    // 
+    W_ ap;
+
+    // This function is *only* used to wrap zero-arity BCOs in an
+    // updatable wrapper (see ByteCodeLink.lhs).  An AP thunk is always
+    // saturated and always points directly to a FUN or BCO.
+    ASSERT(%INFO_TYPE(%GET_STD_INFO(R1)) == BCO::I16 &&
+          StgBCO_arity(R1) == 0::I16);
+
+    HP_CHK_GEN_TICKY(SIZEOF_StgAP, R1_PTR, mkApUpd0zh_fast);
+    TICK_ALLOC_UP_THK(0, 0);
+    CCCS_ALLOC(SIZEOF_StgAP);
+
+    ap = Hp - SIZEOF_StgAP + WDS(1);
+    SET_HDR(ap, stg_AP_info, W_[CCCS]);
+    
+    StgAP_n_args(ap) = 0::I16;
+    StgAP_fun(ap) = R1;
+    
+    RET_P(ap);
+}
+
+/* -----------------------------------------------------------------------------
+   Thread I/O blocking primitives
+   -------------------------------------------------------------------------- */
+
+/* Add a thread to the end of the blocked queue. (C-- version of the C
+ * macro in Schedule.h).
+ */
+#define APPEND_TO_BLOCKED_QUEUE(tso)                   \
+    ASSERT(StgTSO_link(tso) == END_TSO_QUEUE);         \
+    if (W_[blocked_queue_hd] == END_TSO_QUEUE) {       \
+      W_[blocked_queue_hd] = tso;                      \
+    } else {                                           \
+      StgTSO_link(W_[blocked_queue_tl]) = tso;         \
+    }                                                  \
+    W_[blocked_queue_tl] = tso;
+
+waitReadzh_fast
+{
+    /* args: R1 */
+    ASSERT(StgTSO_why_blocked(CurrentTSO) == NotBlocked::I16);
+    StgTSO_why_blocked(CurrentTSO) = BlockedOnRead::I16;
+    StgTSO_block_info(CurrentTSO) = R1;
+    // No locking - we're not going to use this interface in the
+    // threaded RTS anyway.
+    APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
+    jump stg_block_noregs;
+}
+
+waitWritezh_fast
+{
+    /* args: R1 */
+    ASSERT(StgTSO_why_blocked(CurrentTSO) == NotBlocked::I16);
+    StgTSO_why_blocked(CurrentTSO) = BlockedOnWrite::I16;
+    StgTSO_block_info(CurrentTSO) = R1;
+    // No locking - we're not going to use this interface in the
+    // threaded RTS anyway.
+    APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
+    jump stg_block_noregs;
+}
+
+
+STRING(stg_delayzh_malloc_str, "delayzh_fast")
+delayzh_fast
+{
+#ifdef mingw32_TARGET_OS
+    W_ ares;
+    CInt reqID;
+#else
+    W_ t, prev, target;
+#endif
+
+    /* args: R1 (microsecond delay amount) */
+    ASSERT(StgTSO_why_blocked(CurrentTSO) == NotBlocked::I16);
+    StgTSO_why_blocked(CurrentTSO) = BlockedOnDelay::I16;
+
+#ifdef mingw32_TARGET_OS
+
+    /* could probably allocate this on the heap instead */
+    "ptr" ares = foreign "C" stgMallocBytes(SIZEOF_StgAsyncIOResult,
+                                           stg_delayzh_malloc_str);
+    reqID = foreign "C" addDelayRequest(R1);
+    StgAsyncIOResult_reqID(ares)   = reqID;
+    StgAsyncIOResult_len(ares)     = 0;
+    StgAsyncIOResult_errCode(ares) = 0;
+    StgTSO_block_info(CurrentTSO)  = ares;
+
+    /* Having all async-blocked threads reside on the blocked_queue
+     * simplifies matters, so change the status to OnDoProc put the
+     * delayed thread on the blocked_queue.
+     */
+    StgTSO_why_blocked(CurrentTSO) = BlockedOnDoProc::I16;
+    APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
+
+#else
+
+    CInt time;
+    time = foreign "C" getourtimeofday();
+    target = (R1 / (TICK_MILLISECS*1000)) + TO_W_(time);
+    StgTSO_block_info(CurrentTSO) = target;
+
+    /* Insert the new thread in the sleeping queue. */
+    prev = NULL;
+    t = W_[sleeping_queue];
+while:
+    if (t != END_TSO_QUEUE && StgTSO_block_info(t) < target) {
+       prev = t;
+       t = StgTSO_link(t);
+       goto while;
+    }
+
+    StgTSO_link(CurrentTSO) = t;
+    if (prev == NULL) {
+       W_[sleeping_queue] = CurrentTSO;
+    } else {
+       StgTSO_link(prev) = CurrentTSO;
+    }
+#endif
+
+    jump stg_block_noregs;
+}
+
+
+#ifdef mingw32_TARGET_OS
+STRING(stg_asyncReadzh_malloc_str, "asyncReadzh_fast")
+asyncReadzh_fast
+{
+    W_ ares;
+    CInt reqID;
+
+    /* args: R1 = fd, R2 = isSock, R3 = len, R4 = buf */
+    ASSERT(StgTSO_why_blocked(CurrentTSO) == NotBlocked::I16);
+    StgTSO_why_blocked(CurrentTSO) = BlockedOnRead::I16;
+
+    /* could probably allocate this on the heap instead */
+    "ptr" ares = foreign "C" stgMallocBytes(SIZEOF_StgAsyncIOResult,
+                                           stg_asyncReadzh_malloc_str);
+    reqID = foreign "C" addIORequest(R1,FALSE,R2,R3,R4);
+    StgAsyncIOResult_reqID(ares)   = reqID;
+    StgAsyncIOResult_len(ares)     = 0;
+    StgAsyncIOResult_errCode(ares) = 0;
+    StgTSO_block_info(CurrentTSO)  = ares;
+    APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
+    jump stg_block_async;
+}
+
+STRING(asyncWritezh_malloc_str, "asyncWritezh_fast")
+asyncWritezh_fast
+{
+    W_ ares;
+    CInt reqID;
+
+    /* args: R1 = fd, R2 = isSock, R3 = len, R4 = buf */
+    ASSERT(StgTSO_why_blocked(CurrentTSO) == NotBlocked::I16);
+    StgTSO_why_blocked(CurrentTSO) = BlockedOnWrite::I16;
+
+    "ptr" ares = foreign "C" stgMallocBytes(SIZEOF_StgAsyncIOResult,
+                                           asyncWritezh_malloc_str);
+    reqID = foreign "C" addIORequest(R1,TRUE,R2,R3,R4);
+
+    StgAsyncIOResult_reqID(ares)   = reqID;
+    StgAsyncIOResult_len(ares)     = 0;
+    StgAsyncIOResult_errCode(ares) = 0;
+    StgTSO_block_info(CurrentTSO)  = ares;
+    APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
+    jump stg_block_async;
+}
+
+STRING(asyncDoProczh_malloc_str, "asyncDoProczh_fast")
+asyncDoProczh_fast
+{
+    W_ ares;
+    CInt reqID;
+
+    /* args: R1 = proc, R2 = param */
+    ASSERT(StgTSO_why_blocked(CurrentTSO) == NotBlocked::I16);
+    StgTSO_why_blocked(CurrentTSO) = BlockedOnDoProc::I16;
+
+    /* could probably allocate this on the heap instead */
+    "ptr" ares = foreign "C" stgMallocBytes(SIZEOF_StgAsyncIOResult,
+                                           asyncDoProczh_malloc_str);
+    reqID = foreign "C" addDoProcRequest(R1,R2);
+    StgAsyncIOResult_reqID(ares)   = reqID;
+    StgAsyncIOResult_len(ares)     = 0;
+    StgAsyncIOResult_errCode(ares) = 0;
+    StgTSO_block_info(CurrentTSO) = ares;
+    APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
+    jump stg_block_async;
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+  ** temporary **
+
+   classes CCallable and CReturnable don't really exist, but the
+   compiler insists on generating dictionaries containing references
+   to GHC_ZcCCallable_static_info etc., so we provide dummy symbols
+   for these.  Some C compilers can't cope with zero-length static arrays,
+   so we have to make these one element long.
+  --------------------------------------------------------------------------- */
+
+section "rodata" {
+  GHC_ZCCCallable_static_info:   W_ 0;
+}
+
+section "rodata" {
+  GHC_ZCCReturnable_static_info: W_ 0;
+}
diff --git a/ghc/rts/PrimOps.hc b/ghc/rts/PrimOps.hc
deleted file mode 100644 (file)
index 134ed1b..0000000
+++ /dev/null
@@ -1,1749 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: PrimOps.hc,v 1.116 2004/01/08 15:26:44 simonmar Exp $
- *
- * (c) The GHC Team, 1998-2002
- *
- * Primitive functions / data
- *
- * ---------------------------------------------------------------------------*/
-
-#include "Stg.h"
-#include "Rts.h"
-
-#include "RtsFlags.h"
-#include "StgStartup.h"
-#include "SchedAPI.h"
-#include "Schedule.h"
-#include "RtsUtils.h"
-#include "Storage.h"
-#include "BlockAlloc.h" /* tmp */
-#include "StablePriv.h"
-#include "StgRun.h"
-#include "Timer.h"      /* TICK_MILLISECS */
-#include "Prelude.h"
-#ifndef mingw32_TARGET_OS
-#include "Itimer.h"    /* getourtimeofday() */
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#include <stdlib.h>
-
-#ifdef mingw32_TARGET_OS
-#include <windows.h>
-#include "win32/AsyncIO.h"
-#endif
-
-/* ** temporary **
-
-   classes CCallable and CReturnable don't really exist, but the
-   compiler insists on generating dictionaries containing references
-   to GHC_ZcCCallable_static_info etc., so we provide dummy symbols
-   for these.  Some C compilers can't cope with zero-length static arrays,
-   so we have to make these one element long.
-*/
-
-StgWord GHC_ZCCCallable_static_info[1];
-StgWord GHC_ZCCReturnable_static_info[1];
-  
-/* -----------------------------------------------------------------------------
-   Macros for Hand-written primitives.
-   -------------------------------------------------------------------------- */
-
-/*
- * Horrible macros for returning unboxed tuples.
- *
- * How an unboxed tuple is returned depends on two factors:
- *    - the number of real registers we have available
- *    - the boxedness of the returned fields.
- *
- * To return an unboxed tuple from a primitive operation, we have macros
- * RET_<layout> where <layout> describes the boxedness of each field of the
- * unboxed tuple:  N indicates a non-pointer field, and P indicates a pointer.
- *
- * We only define the cases actually used, to avoid having too much
- * garbage in this section.  Warning: any bugs in here will be hard to
- * track down.
- *
- * The return convention for an unboxed tuple is as follows:
- *   - fit as many fields as possible in registers (as per the
- *     function fast-entry point calling convention).
- *   - sort the rest of the fields into pointers and non-pointers.
- *     push the pointers on the stack, followed by the non-pointers.
- *     (so the pointers have higher addresses).
- */
-
-/*------ All Regs available */
-#if MAX_REAL_VANILLA_REG == 8
-# define RET_P(a)     R1.w = (W_)(a); JMP_(ENTRY_CODE(Sp[0]));
-# define RET_N(a)     RET_P(a)
-
-# define RET_PP(a,b)  R1.w = (W_)(a); R2.w = (W_)(b); JMP_(ENTRY_CODE(Sp[0]));
-# define RET_NN(a,b)  RET_PP(a,b)
-# define RET_NP(a,b)  RET_PP(a,b)
-
-# define RET_PPP(a,b,c) \
-       R1.w = (W_)(a); R2.w = (W_)(b); R3.w = (W_)(c); JMP_(ENTRY_CODE(Sp[0]));
-# define RET_NNP(a,b,c) RET_PPP(a,b,c)
-
-# define RET_NNNP(a,b,c,d) \
-        R1.w = (W_)(a); R2.w = (W_)(b); R3.w = (W_)(c); R4.w = (W_)d; \
-        JMP_(ENTRY_CODE(Sp[0]));
-
-# define RET_NPNP(a,b,c,d) \
-        R1.w = (W_)(a); R2.w = (W_)(b); R3.w = (W_)(c); R4.w = (W_)(d); \
-       JMP_(ENTRY_CODE(Sp[0]));
-
-#elif MAX_REAL_VANILLA_REG > 2 && MAX_REAL_VANILLA_REG < 8
-# error RET_n macros not defined for this setup.
-
-/*------ 2 Registers available */
-#elif MAX_REAL_VANILLA_REG == 2
-
-# define RET_P(a)     R1.w = (W_)(a); JMP_(ENTRY_CODE(Sp[0]));
-# define RET_N(a)     RET_P(a)
-
-# define RET_PP(a,b)   R1.w = (W_)(a); R2.w = (W_)(b); \
-                      JMP_(ENTRY_CODE(Sp[0]));
-# define RET_NN(a,b)   RET_PP(a,b)
-# define RET_NP(a,b)   RET_PP(a,b)
-
-# define RET_PPP(a,b,c)                                \
-       R1.w = (W_)(a);                         \
-       R2.w = (W_)(b);                         \
-       Sp[-1] = (W_)(c);                       \
-       Sp -= 1;                                \
-       JMP_(ENTRY_CODE(Sp[1]));
-
-# define RET_NNP(a,b,c)                                \
-       R1.w = (W_)(a);                         \
-       R2.w = (W_)(b);                         \
-       Sp[-1] = (W_)(c);                       \
-       Sp -= 1;                                \
-       JMP_(ENTRY_CODE(Sp[1]));
-
-# define RET_NNNP(a,b,c,d)                     \
-       R1.w = (W_)(a);                         \
-        R2.w = (W_)(b);                        \
-        Sp[-2] = (W_)(c);                      \
-        Sp[-1] = (W_)(d);                      \
-        Sp -= 2;                               \
-        JMP_(ENTRY_CODE(Sp[2]));
-
-# define RET_NPNP(a,b,c,d)                     \
-       R1.w = (W_)(a);                         \
-        R2.w = (W_)(b);                        \
-        Sp[-2] = (W_)(c);                      \
-        Sp[-1] = (W_)(d);                      \
-        Sp -= 2;                               \
-        JMP_(ENTRY_CODE(Sp[2]));
-
-/*------ 1 Register available */
-#elif MAX_REAL_VANILLA_REG == 1
-# define RET_P(a)     R1.w = (W_)(a); JMP_(ENTRY_CODE(Sp[0]));
-# define RET_N(a)     RET_P(a)
-
-# define RET_PP(a,b)   R1.w = (W_)(a); Sp[-1] = (W_)(b); Sp -= 1; \
-                      JMP_(ENTRY_CODE(Sp[1]));
-# define RET_NN(a,b)   R1.w = (W_)(a); Sp[-1] = (W_)(b); Sp -= 2; \
-                      JMP_(ENTRY_CODE(Sp[2]));
-# define RET_NP(a,b)   RET_PP(a,b)
-
-# define RET_PPP(a,b,c)                                \
-       R1.w = (W_)(a);                         \
-       Sp[-2] = (W_)(b);                       \
-       Sp[-1] = (W_)(c);                       \
-       Sp -= 2;                                \
-       JMP_(ENTRY_CODE(Sp[2]));
-
-# define RET_NNP(a,b,c)                                \
-       R1.w = (W_)(a);                         \
-       Sp[-2] = (W_)(b);                       \
-       Sp[-1] = (W_)(c);                       \
-       Sp -= 2;                                \
-       JMP_(ENTRY_CODE(Sp[2]));
-
-# define RET_NNNP(a,b,c,d)                     \
-       R1.w = (W_)(a);                         \
-        Sp[-3] = (W_)(b);                      \
-        Sp[-2] = (W_)(c);                      \
-        Sp[-1] = (W_)(d);                      \
-        Sp -= 3;                               \
-        JMP_(ENTRY_CODE(Sp[3]));
-
-# define RET_NPNP(a,b,c,d)                     \
-       R1.w = (W_)(a);                         \
-        Sp[-3] = (W_)(c);                      \
-        Sp[-2] = (W_)(b);                      \
-        Sp[-1] = (W_)(d);                      \
-        Sp -= 3;                               \
-        JMP_(ENTRY_CODE(Sp[3]));
-
-#else /* 0 Regs available */
-
-#define PUSH(o,x) Sp[-o] = (W_)(x)
-
-#define PUSHED(m)   Sp -= (m); JMP_(ENTRY_CODE(Sp[m]));
-
-# define RET_P(a)     PUSH(1,a); PUSHED(1)
-# define RET_N(a)     PUSH(1,a); PUSHED(1)
-
-# define RET_PP(a,b)   PUSH(2,a); PUSH(1,b); PUSHED(2)
-# define RET_NN(a,b)   PUSH(2,a); PUSH(1,b); PUSHED(2)
-# define RET_NP(a,b)   PUSH(2,a); PUSH(1,b); PUSHED(2)
-
-# define RET_PPP(a,b,c) PUSH(3,a); PUSH(2,b); PUSH(1,c); PUSHED(3)
-# define RET_NNP(a,b,c) PUSH(3,a); PUSH(2,b); PUSH(1,c); PUSHED(3)
-
-# define RET_NNNP(a,b,c,d) PUSH(4,a); PUSH(3,b); PUSH(2,c); PUSH(1,d); PUSHED(4)       
-# define RET_NPNP(a,b,c,d) PUSH(4,a); PUSH(3,c); PUSH(2,b); PUSH(1,d); PUSHED(4)       
-#endif
-
-/*-----------------------------------------------------------------------------
-  Array Primitives
-
-  Basically just new*Array - the others are all inline macros.
-
-  The size arg is always passed in R1, and the result returned in R1.
-
-  The slow entry point is for returning from a heap check, the saved
-  size argument must be re-loaded from the stack.
-  -------------------------------------------------------------------------- */
-
-/* for objects that are *less* than the size of a word, make sure we
- * round up to the nearest word for the size of the array.
- */
-
-#define BYTES_TO_STGWORDS(n) ((n) + sizeof(W_) - 1)/sizeof(W_)
-
-FN_(newByteArrayzh_fast)
- {
-   W_ size, stuff_size, n;
-   StgArrWords* p;
-   FB_
-     MAYBE_GC(NO_PTRS,newByteArrayzh_fast);
-     n = R1.w;
-     stuff_size = BYTES_TO_STGWORDS(n);
-     size = sizeofW(StgArrWords)+ stuff_size;
-     p = (StgArrWords *)RET_STGCALL1(P_,allocate,size);
-     TICK_ALLOC_PRIM(sizeofW(StgArrWords),stuff_size,0);
-     SET_HDR(p, &stg_ARR_WORDS_info, CCCS);
-     p->words = stuff_size;
-     TICK_RET_UNBOXED_TUP(1)
-     RET_P(p);
-   FE_
- }
-
-FN_(newPinnedByteArrayzh_fast)
- {
-   W_ size, stuff_size, n;
-   StgArrWords* p;
-   FB_
-     MAYBE_GC(NO_PTRS,newPinnedByteArrayzh_fast);
-     n = R1.w;
-     stuff_size = BYTES_TO_STGWORDS(n);
-
-     // We want an 8-byte aligned array.  allocatePinned() gives us
-     // 8-byte aligned memory by default, but we want to align the
-     // *goods* inside the ArrWords object, so we have to check the
-     // size of the ArrWords header and adjust our size accordingly.
-     size = sizeofW(StgArrWords)+ stuff_size;
-     if ((sizeof(StgArrWords) & 7) != 0) {
-        size++;
-     }
-
-     p = (StgArrWords *)RET_STGCALL1(P_,allocatePinned,size);
-     TICK_ALLOC_PRIM(sizeofW(StgArrWords),stuff_size,0);
-
-     // Again, if the ArrWords header isn't a multiple of 8 bytes, we
-     // have to push the object forward one word so that the goods
-     // fall on an 8-byte boundary.
-     if ((sizeof(StgArrWords) & 7) != 0) {
-        ((StgPtr)p)++;
-     }
-
-     SET_HDR(p, &stg_ARR_WORDS_info, CCCS);
-     p->words = stuff_size;
-     TICK_RET_UNBOXED_TUP(1)
-     RET_P(p);
-   FE_
- }
-
-FN_(newArrayzh_fast)
-{
-  W_ size, n, init;
-  StgMutArrPtrs* arr;
-  StgPtr p;
-  FB_
-    n = R1.w;
-
-    MAYBE_GC(R2_PTR,newArrayzh_fast);
-
-    size = sizeofW(StgMutArrPtrs) + n;
-    arr = (StgMutArrPtrs *)RET_STGCALL1(P_, allocate, size);
-    TICK_ALLOC_PRIM(sizeofW(StgMutArrPtrs), n, 0);
-
-    SET_HDR(arr,&stg_MUT_ARR_PTRS_info,CCCS);
-    arr->ptrs = n;
-
-    init = R2.w;
-    for (p = (P_)arr + sizeofW(StgMutArrPtrs); 
-        p < (P_)arr + size; p++) {
-       *p = (W_)init;
-    }
-
-    TICK_RET_UNBOXED_TUP(1);
-    RET_P(arr);
-  FE_
-}
-
-FN_(newMutVarzh_fast)
-{
-  StgMutVar* mv;
-  /* Args: R1.p = initialisation value */
-  FB_
-
-  HP_CHK_GEN_TICKY(sizeofW(StgMutVar), R1_PTR, newMutVarzh_fast);
-  TICK_ALLOC_PRIM(sizeofW(StgHeader)+1,1, 0); /* hack, dependent on rep. */
-  CCS_ALLOC(CCCS,sizeofW(StgMutVar));
-
-  mv = (StgMutVar *)(Hp-sizeofW(StgMutVar)+1);
-  SET_HDR(mv,&stg_MUT_VAR_info,CCCS);
-  mv->var = R1.cl;
-
-  TICK_RET_UNBOXED_TUP(1);
-  RET_P(mv);
-  FE_
-}
-
-FN_(atomicModifyMutVarzh_fast)
-{
-   StgMutVar* mv;
-   StgClosure *z, *x, *y, *r;
-   FB_
-   /* Args: R1.p :: MutVar#,  R2.p :: a -> (a,b) */
-
-   /* If x is the current contents of the MutVar#, then 
-      We want to make the new contents point to
-
-         (sel_0 (f x))
-      and the return value is
-
-        (sel_1 (f x))
-
-      obviously we can share (f x).
-
-         z = [stg_ap_2 f x]  (max (HS + 2) MIN_UPD_SIZE)
-        y = [stg_sel_0 z]   (max (HS + 1) MIN_UPD_SIZE)
-         r = [stg_sel_1 z]   (max (HS + 1) MIN_UPD_SIZE)
-   */
-
-#define THUNK_SIZE(n) (sizeofW(StgHeader) + stg_max((n), MIN_UPD_SIZE))
-#define SIZE (THUNK_SIZE(2) + THUNK_SIZE(1) + THUNK_SIZE(1))
-
-   HP_CHK_GEN_TICKY(SIZE, R1_PTR|R2_PTR, atomicModifyMutVarzh_fast);
-   CCS_ALLOC(CCCS,SIZE);
-
-   x = ((StgMutVar *)R1.cl)->var;
-
-   TICK_ALLOC_UP_THK(2,0); // XXX
-   z = (StgClosure *) Hp - THUNK_SIZE(2) + 1;
-   SET_HDR(z, (StgInfoTable *)&stg_ap_2_upd_info, CCCS);
-   z->payload[0] = R2.cl;
-   z->payload[1] = x;
-
-   TICK_ALLOC_UP_THK(1,1); // XXX
-   y = (StgClosure *) (StgPtr)z - THUNK_SIZE(1);
-   SET_HDR(y, &stg_sel_0_upd_info, CCCS);
-   y->payload[0] = z;
-
-   ((StgMutVar *)R1.cl)->var = y;
-
-   TICK_ALLOC_UP_THK(1,1); // XXX
-   r = (StgClosure *) (StgPtr)y - THUNK_SIZE(1);
-   SET_HDR(r, &stg_sel_1_upd_info, CCCS);
-   r->payload[0] = z;
-
-   RET_P(r);
-   FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Foreign Object Primitives
-   -------------------------------------------------------------------------- */
-
-FN_(mkForeignObjzh_fast)
-{
-  /* R1.p = ptr to foreign object,
-  */
-  StgForeignObj *result;
-  FB_
-
-  HP_CHK_GEN_TICKY(sizeofW(StgForeignObj), NO_PTRS, mkForeignObjzh_fast);
-  TICK_ALLOC_PRIM(sizeofW(StgHeader),
-                 sizeofW(StgForeignObj)-sizeofW(StgHeader), 0);
-  CCS_ALLOC(CCCS,sizeofW(StgForeignObj)); /* ccs prof */
-
-  result = (StgForeignObj *) (Hp + 1 - sizeofW(StgForeignObj));
-  SET_HDR(result,&stg_FOREIGN_info,CCCS);
-  result->data = R1.p;
-
-  /* returns (# s#, ForeignObj# #) */
-  TICK_RET_UNBOXED_TUP(1);
-  RET_P(result);
-  FE_
-}
-
-/* These two are out-of-line for the benefit of the NCG */
-FN_(unsafeThawArrayzh_fast)
-{
-  FB_
-  SET_INFO((StgClosure *)R1.cl,&stg_MUT_ARR_PTRS_info);
-
-  // SUBTLETY TO DO WITH THE OLD GEN MUTABLE LIST
-  //
-  // A MUT_ARR_PTRS lives on the mutable list, but a MUT_ARR_PTRS_FROZEN 
-  // normally doesn't.  However, when we freeze a MUT_ARR_PTRS, we leave
-  // it on the mutable list for the GC to remove (removing something from
-  // the mutable list is not easy, because the mut_list is only singly-linked).
-  // 
-  // So, when we thaw a MUT_ARR_PTRS_FROZEN, we must cope with two cases:
-  // either it is on a mut_list, or it isn't.  We adopt the convention that
-  // the mut_link field is NULL if it isn't on a mut_list, and the GC
-  // maintains this invariant.
-  //
-  if (((StgMutArrPtrs *)R1.cl)->mut_link == NULL) {
-       recordMutable((StgMutClosure*)R1.cl);
-  }
-
-  TICK_RET_UNBOXED_TUP(1);
-  RET_P(R1.p);
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Weak Pointer Primitives
-   -------------------------------------------------------------------------- */
-
-FN_(mkWeakzh_fast)
-{
-  /* R1.p = key
-     R2.p = value
-     R3.p = finalizer (or NULL)
-  */
-  StgWeak *w;
-  FB_
-
-  if (R3.cl == NULL) {
-    R3.cl = &stg_NO_FINALIZER_closure;
-  }
-
-  HP_CHK_GEN_TICKY(sizeofW(StgWeak),R1_PTR|R2_PTR|R3_PTR, mkWeakzh_fast);
-  TICK_ALLOC_PRIM(sizeofW(StgHeader)+1,  // +1 is for the link field
-                 sizeofW(StgWeak)-sizeofW(StgHeader)-1, 0);
-  CCS_ALLOC(CCCS,sizeofW(StgWeak)); /* ccs prof */
-
-  w = (StgWeak *) (Hp + 1 - sizeofW(StgWeak));
-  SET_HDR(w, &stg_WEAK_info, CCCS);
-
-  w->key        = R1.cl;
-  w->value      = R2.cl;
-  w->finalizer  = R3.cl;
-
-  w->link       = weak_ptr_list;
-  weak_ptr_list = w;
-  IF_DEBUG(weak, fprintf(stderr,"New weak pointer at %p\n",w));
-
-  TICK_RET_UNBOXED_TUP(1);
-  RET_P(w);
-  FE_
-}
-
-FN_(finalizzeWeakzh_fast)
-{
-  /* R1.p = weak ptr
-   */
-  StgDeadWeak *w;
-  StgClosure *f;
-  FB_
-  TICK_RET_UNBOXED_TUP(0);
-  w = (StgDeadWeak *)R1.p;
-
-  /* already dead? */
-  if (w->header.info == &stg_DEAD_WEAK_info) {
-      RET_NP(0,&stg_NO_FINALIZER_closure);
-  }
-
-  /* kill it */
-#ifdef PROFILING
-  // @LDV profiling
-  // A weak pointer is inherently used, so we do not need to call
-  // LDV_recordDead_FILL_SLOP_DYNAMIC():
-  //    LDV_recordDead_FILL_SLOP_DYNAMIC((StgClosure *)w);
-  // or, LDV_recordDead():
-  //    LDV_recordDead((StgClosure *)w, sizeofW(StgWeak) - sizeofW(StgProfHeader));
-  // Furthermore, when PROFILING is turned on, dead weak pointers are exactly as 
-  // large as weak pointers, so there is no need to fill the slop, either.
-  // See stg_DEAD_WEAK_info in StgMiscClosures.hc.
-#endif
-  //
-  // Todo: maybe use SET_HDR() and remove LDV_recordCreate()?
-  //
-  w->header.info = &stg_DEAD_WEAK_info;
-#ifdef PROFILING
-  // @LDV profiling
-  LDV_recordCreate((StgClosure *)w);
-#endif
-  f = ((StgWeak *)w)->finalizer;
-  w->link = ((StgWeak *)w)->link;
-
-  /* return the finalizer */
-  if (f == &stg_NO_FINALIZER_closure) {
-      RET_NP(0,&stg_NO_FINALIZER_closure);
-  } else {
-      RET_NP(1,f);
-  }
-  FE_
-}
-
-FN_(deRefWeakzh_fast)
-{
-  /* R1.p = weak ptr */
-  StgWeak* w;
-  I_       code;
-  P_       val;
-  FB_
-  w = (StgWeak*)R1.p;
-  if (w->header.info == &stg_WEAK_info) {
-    code = 1;
-    val = (P_)((StgWeak *)w)->value;
-  } else {
-    code = 0;
-    val = (P_)w;
-  }
-  RET_NP(code,val);
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Arbitrary-precision Integer operations.
-   -------------------------------------------------------------------------- */
-
-FN_(int2Integerzh_fast)
-{
-   /* arguments: R1 = Int# */
-
-   I_ val, s;                  /* to avoid aliasing */
-   StgArrWords* p;     /* address of array result */
-   FB_
-
-   val = R1.i;
-   HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+1, NO_PTRS, int2Integerzh_fast);
-   TICK_ALLOC_PRIM(sizeofW(StgArrWords),1,0);
-   CCS_ALLOC(CCCS,sizeofW(StgArrWords)+1); /* ccs prof */
-
-   p = (StgArrWords *)Hp - 1;
-   SET_ARR_HDR(p, &stg_ARR_WORDS_info, CCCS, 1);
-
-   /* mpz_set_si is inlined here, makes things simpler */
-   if (val < 0) { 
-       s  = -1;
-       *Hp = -val;
-   } else if (val > 0) {
-       s = 1;
-       *Hp = val;
-   } else {
-       s = 0;
-   }
-
-   /* returns (# size  :: Int#, 
-                data  :: ByteArray# 
-              #)
-   */
-   TICK_RET_UNBOXED_TUP(2);
-   RET_NP(s,p);
-   FE_
-}
-
-FN_(word2Integerzh_fast)
-{
-   /* arguments: R1 = Word# */
-
-   W_ val;             /* to avoid aliasing */
-   I_  s;
-   StgArrWords* p;     /* address of array result */
-   FB_
-
-   val = R1.w;
-   HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+1, NO_PTRS, word2Integerzh_fast)
-   TICK_ALLOC_PRIM(sizeofW(StgArrWords),1,0);
-   CCS_ALLOC(CCCS,sizeofW(StgArrWords)+1); /* ccs prof */
-
-   p = (StgArrWords *)Hp - 1;
-   SET_ARR_HDR(p, &stg_ARR_WORDS_info, CCCS, 1);
-
-   if (val != 0) {
-       s = 1;
-       *Hp = val;
-   } else {
-       s = 0;
-   }
-
-   /* returns (# size  :: Int#, 
-                data  :: ByteArray# 
-              #)
-   */
-   TICK_RET_UNBOXED_TUP(2);
-   RET_NP(s,p);
-   FE_
-}
-
-
-/*
- * 'long long' primops for converting to/from Integers.
- */
-
-#ifdef SUPPORT_LONG_LONGS
-
-FN_(int64ToIntegerzh_fast)
-{
-   /* arguments: L1 = Int64# */
-
-   StgInt64  val; /* to avoid aliasing */
-   W_ hi;
-   I_  s, neg, words_needed;
-   StgArrWords* p;     /* address of array result */
-   FB_
-
-   val = (LI_)L1;
-   neg = 0;
-
-   if ( val >= 0x100000000LL || val <= -0x100000000LL )  { 
-       words_needed = 2;
-   } else { 
-       /* minimum is one word */
-       words_needed = 1;
-   }
-   HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+words_needed, NO_PTRS, int64ToIntegerzh_fast)
-   TICK_ALLOC_PRIM(sizeofW(StgArrWords),words_needed,0);
-   CCS_ALLOC(CCCS,sizeofW(StgArrWords)+words_needed); /* ccs prof */
-
-   p = (StgArrWords *)(Hp-words_needed+1) - 1;
-   SET_ARR_HDR(p, &stg_ARR_WORDS_info, CCCS, words_needed);
-
-   if ( val < 0LL ) {
-     neg = 1;
-     val = -val;
-   }
-
-   hi = (W_)((LW_)val / 0x100000000ULL);
-
-   if ( words_needed == 2 )  { 
-      s = 2;
-      Hp[-1] = (W_)val;
-      Hp[0] = hi;
-   } else if ( val != 0 ) {
-      s = 1;
-      Hp[0] = (W_)val;
-   }  else /* val==0 */   {
-      s = 0;
-   }
-   s = ( neg ? -s : s );
-
-   /* returns (# size  :: Int#, 
-                data  :: ByteArray# 
-              #)
-   */
-   TICK_RET_UNBOXED_TUP(2);
-   RET_NP(s,p);
-   FE_
-}
-
-FN_(word64ToIntegerzh_fast)
-{
-   /* arguments: L1 = Word64# */
-
-   StgWord64 val; /* to avoid aliasing */
-   StgWord hi;
-   I_  s, words_needed;
-   StgArrWords* p;     /* address of array result */
-   FB_
-
-   val = (LW_)L1;
-   if ( val >= 0x100000000ULL ) {
-      words_needed = 2;
-   } else {
-      words_needed = 1;
-   }
-   HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+words_needed, NO_PTRS, word64ToIntegerzh_fast)
-   TICK_ALLOC_PRIM(sizeofW(StgArrWords),words_needed,0);
-   CCS_ALLOC(CCCS,sizeofW(StgArrWords)+words_needed); /* ccs prof */
-
-   p = (StgArrWords *)(Hp-words_needed+1) - 1;
-   SET_ARR_HDR(p, &stg_ARR_WORDS_info, CCCS, words_needed);
-
-   hi = (W_)((LW_)val / 0x100000000ULL);
-   if ( val >= 0x100000000ULL ) { 
-     s = 2;
-     Hp[-1] = ((W_)val);
-     Hp[0]  = (hi);
-   } else if ( val != 0 )      {
-      s = 1;
-      Hp[0] = ((W_)val);
-   } else /* val==0 */         {
-      s = 0;
-   }
-
-   /* returns (# size  :: Int#, 
-                data  :: ByteArray# 
-              #)
-   */
-   TICK_RET_UNBOXED_TUP(2);
-   RET_NP(s,p);
-   FE_
-}
-
-
-#endif /* SUPPORT_LONG_LONGS */
-
-/* ToDo: this is shockingly inefficient */
-
-#define GMP_TAKE2_RET1(name,mp_fun)                                    \
-FN_(name)                                                              \
-{                                                                      \
-  MP_INT arg1, arg2, result;                                           \
-  I_ s1, s2;                                                           \
-  StgArrWords* d1;                                                     \
-  StgArrWords* d2;                                                     \
-  FB_                                                                  \
-                                                                       \
-  /* call doYouWantToGC() */                                           \
-  MAYBE_GC(R2_PTR | R4_PTR, name);                                     \
-                                                                       \
-  d1 = (StgArrWords *)R2.p;                                            \
-  s1 = R1.i;                                                           \
-  d2 = (StgArrWords *)R4.p;                                            \
-  s2 = R3.i;                                                           \
-                                                                       \
-  arg1._mp_alloc       = d1->words;                                    \
-  arg1._mp_size                = (s1);                                         \
-  arg1._mp_d           = (unsigned long int *) (BYTE_ARR_CTS(d1));     \
-  arg2._mp_alloc       = d2->words;                                    \
-  arg2._mp_size                = (s2);                                         \
-  arg2._mp_d           = (unsigned long int *) (BYTE_ARR_CTS(d2));     \
-                                                                       \
-  STGCALL1(mpz_init,&result);                                          \
-                                                                       \
-  /* Perform the operation */                                          \
-  STGCALL3(mp_fun,&result,&arg1,&arg2);                                        \
-                                                                       \
-  TICK_RET_UNBOXED_TUP(2);                                             \
-  RET_NP(result._mp_size,                                              \
-         result._mp_d-sizeofW(StgArrWords));                           \
-  FE_                                                                  \
-}
-
-#define GMP_TAKE1_RET1(name,mp_fun)                                    \
-FN_(name)                                                              \
-{                                                                      \
-  MP_INT arg1, result;                                                 \
-  I_ s1;                                                               \
-  StgArrWords* d1;                                                     \
-  FB_                                                                  \
-                                                                       \
-  /* call doYouWantToGC() */                                           \
-  MAYBE_GC(R2_PTR, name);                                              \
-                                                                       \
-  d1 = (StgArrWords *)R2.p;                                            \
-  s1 = R1.i;                                                           \
-                                                                       \
-  arg1._mp_alloc       = d1->words;                                    \
-  arg1._mp_size                = (s1);                                         \
-  arg1._mp_d           = (unsigned long int *) (BYTE_ARR_CTS(d1));     \
-                                                                       \
-  STGCALL1(mpz_init,&result);                                          \
-                                                                       \
-  /* Perform the operation */                                          \
-  STGCALL2(mp_fun,&result,&arg1);                                      \
-                                                                       \
-  TICK_RET_UNBOXED_TUP(2);                                             \
-  RET_NP(result._mp_size,                                              \
-         result._mp_d-sizeofW(StgArrWords));                           \
-  FE_                                                                  \
-}
-
-#define GMP_TAKE2_RET2(name,mp_fun)                                    \
-FN_(name)                                                              \
-{                                                                      \
-  MP_INT arg1, arg2, result1, result2;                                 \
-  I_ s1, s2;                                                           \
-  StgArrWords* d1;                                                     \
-  StgArrWords* d2;                                                     \
-  FB_                                                                  \
-                                                                       \
-  /* call doYouWantToGC() */                                           \
-  MAYBE_GC(R2_PTR | R4_PTR, name);                                     \
-                                                                       \
-  d1 = (StgArrWords *)R2.p;                                            \
-  s1 = R1.i;                                                           \
-  d2 = (StgArrWords *)R4.p;                                            \
-  s2 = R3.i;                                                           \
-                                                                       \
-  arg1._mp_alloc       = d1->words;                                    \
-  arg1._mp_size                = (s1);                                         \
-  arg1._mp_d           = (unsigned long int *) (BYTE_ARR_CTS(d1));     \
-  arg2._mp_alloc       = d2->words;                                    \
-  arg2._mp_size                = (s2);                                         \
-  arg2._mp_d           = (unsigned long int *) (BYTE_ARR_CTS(d2));     \
-                                                                       \
-  STGCALL1(mpz_init,&result1);                                         \
-  STGCALL1(mpz_init,&result2);                                         \
-                                                                       \
-  /* Perform the operation */                                          \
-  STGCALL4(mp_fun,&result1,&result2,&arg1,&arg2);                      \
-                                                                       \
-  TICK_RET_UNBOXED_TUP(4);                                             \
-  RET_NPNP(result1._mp_size,                                           \
-           result1._mp_d-sizeofW(StgArrWords),                         \
-          result2._mp_size,                                            \
-           result2._mp_d-sizeofW(StgArrWords));                                \
-  FE_                                                                  \
-}
-
-GMP_TAKE2_RET1(plusIntegerzh_fast,     mpz_add);
-GMP_TAKE2_RET1(minusIntegerzh_fast,    mpz_sub);
-GMP_TAKE2_RET1(timesIntegerzh_fast,    mpz_mul);
-GMP_TAKE2_RET1(gcdIntegerzh_fast,      mpz_gcd);
-GMP_TAKE2_RET1(quotIntegerzh_fast,     mpz_tdiv_q);
-GMP_TAKE2_RET1(remIntegerzh_fast,      mpz_tdiv_r);
-GMP_TAKE2_RET1(divExactIntegerzh_fast, mpz_divexact);
-GMP_TAKE2_RET1(andIntegerzh_fast,      mpz_and);
-GMP_TAKE2_RET1(orIntegerzh_fast,       mpz_ior);
-GMP_TAKE2_RET1(xorIntegerzh_fast,      mpz_xor);
-GMP_TAKE1_RET1(complementIntegerzh_fast, mpz_com);
-
-GMP_TAKE2_RET2(quotRemIntegerzh_fast, mpz_tdiv_qr);
-GMP_TAKE2_RET2(divModIntegerzh_fast,  mpz_fdiv_qr);
-
-
-FN_(gcdIntzh_fast)
-{
-  /* R1 = the first Int#; R2 = the second Int# */
-  mp_limb_t aa;
-  I_ r;
-  FB_
-  aa = (mp_limb_t)(R1.i);
-  r = RET_STGCALL3(StgInt, mpn_gcd_1, (mp_limb_t *)(&aa), 1, (mp_limb_t)(R2.i));
-
-  R1.i = r;
-  /* Result parked in R1, return via info-pointer at TOS */
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-
-FN_(gcdIntegerIntzh_fast)
-{
-  /* R1 = s1; R2 = d1; R3 = the int */
-  I_ r;
-  FB_
-  r = RET_STGCALL3(StgInt,mpn_gcd_1,(mp_limb_t *)(BYTE_ARR_CTS(R2.p)), R1.i, R3.i);
-
-  R1.i = r;
-  /* Result parked in R1, return via info-pointer at TOS */
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-
-FN_(cmpIntegerIntzh_fast)
-{
-  /* R1 = s1; R2 = d1; R3 = the int */
-  I_ usize;
-  I_ vsize;
-  I_ v_digit;
-  mp_limb_t u_digit;
-  FB_
-
-  usize = R1.i;
-  vsize = 0;
-  v_digit = R3.i;
-
-  // paraphrased from mpz_cmp_si() in the GMP sources
-  if (v_digit > 0) {
-      vsize = 1;
-  } else if (v_digit < 0) {
-      vsize = -1;
-      v_digit = -v_digit;
-  }
-
-  if (usize != vsize) {
-    R1.i = usize - vsize; JMP_(ENTRY_CODE(Sp[0]));
-  }
-
-  if (usize == 0) {
-    R1.i = 0; JMP_(ENTRY_CODE(Sp[0]));
-  }
-
-  u_digit = *(mp_limb_t *)(BYTE_ARR_CTS(R2.p));
-
-  if (u_digit == (mp_limb_t) (unsigned long) v_digit) {
-    R1.i = 0; JMP_(ENTRY_CODE(Sp[0]));
-  }
-
-  if (u_digit > (mp_limb_t) (unsigned long) v_digit) {
-    R1.i = usize; 
-  } else {
-    R1.i = -usize; 
-  }
-
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-
-FN_(cmpIntegerzh_fast)
-{
-  /* R1 = s1; R2 = d1; R3 = s2; R4 = d2 */
-  I_ usize;
-  I_ vsize;
-  I_ size;
-  StgPtr up, vp;
-  int cmp;
-  FB_
-
-  // paraphrased from mpz_cmp() in the GMP sources
-  usize = R1.i;
-  vsize = R3.i;
-
-  if (usize != vsize) {
-    R1.i = usize - vsize; JMP_(ENTRY_CODE(Sp[0]));
-  }
-
-  if (usize == 0) {
-    R1.i = 0; JMP_(ENTRY_CODE(Sp[0]));
-  }
-
-  size = abs(usize);
-
-  up = BYTE_ARR_CTS(R2.p);
-  vp = BYTE_ARR_CTS(R4.p);
-
-  cmp = RET_STGCALL3(I_, mpn_cmp, (mp_limb_t *)up, (mp_limb_t *)vp, size);
-
-  if (cmp == 0) {
-    R1.i = 0; JMP_(ENTRY_CODE(Sp[0]));
-  }
-
-  if ((cmp < 0) == (usize < 0)) {
-    R1.i = 1;
-  } else {
-    R1.i = (-1); 
-  }
-  /* Result parked in R1, return via info-pointer at TOS */
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-
-FN_(integer2Intzh_fast)
-{
-  /* R1 = s; R2 = d */
-  I_ r, s;
-  FB_
-  s = R1.i;
-  if (s == 0)
-    r = 0;
-  else {
-    r = ((mp_limb_t *) (BYTE_ARR_CTS(R2.p)))[0];
-    if (s < 0) r = -r;
-  }
-  /* Result parked in R1, return via info-pointer at TOS */
-  R1.i = r;
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-
-FN_(integer2Wordzh_fast)
-{
-  /* R1 = s; R2 = d */
-  I_ s;
-  W_ r;
-  FB_
-  s = R1.i;
-  if (s == 0)
-    r = 0;
-  else {
-    r = ((mp_limb_t *) (BYTE_ARR_CTS(R2.p)))[0];
-    if (s < 0) r = -r;
-  }
-  /* Result parked in R1, return via info-pointer at TOS */
-  R1.w = r;
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-
-
-FN_(decodeFloatzh_fast)
-{ 
-  MP_INT mantissa;
-  I_ exponent;
-  StgArrWords* p;
-  StgFloat arg;
-  FB_
-
-  /* arguments: F1 = Float# */
-  arg = F1;
-
-  HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+1, NO_PTRS, decodeFloatzh_fast);
-  TICK_ALLOC_PRIM(sizeofW(StgArrWords),1,0);
-  CCS_ALLOC(CCCS,sizeofW(StgArrWords)+1); /* ccs prof */
-
-  /* Be prepared to tell Lennart-coded __decodeFloat   */
-  /* where mantissa._mp_d can be put (it does not care about the rest) */
-  p = (StgArrWords *)Hp - 1;
-  SET_ARR_HDR(p,&stg_ARR_WORDS_info,CCCS,1)
-  mantissa._mp_d = (void *)BYTE_ARR_CTS(p);
-
-  /* Perform the operation */
-  STGCALL3(__decodeFloat,&mantissa,&exponent,arg);
-
-  /* returns: (Int# (expn), Int#, ByteArray#) */
-  TICK_RET_UNBOXED_TUP(3);
-  RET_NNP(exponent,mantissa._mp_size,p);
-  FE_
-}
-
-#define DOUBLE_MANTISSA_SIZE (sizeofW(StgDouble))
-#define ARR_SIZE (sizeofW(StgArrWords) + DOUBLE_MANTISSA_SIZE)
-
-FN_(decodeDoublezh_fast)
-{ MP_INT mantissa;
-  I_ exponent;
-  StgDouble arg;
-  StgArrWords* p;
-  FB_
-
-  /* arguments: D1 = Double# */
-  arg = D1;
-
-  HP_CHK_GEN_TICKY(ARR_SIZE, NO_PTRS, decodeDoublezh_fast);
-  TICK_ALLOC_PRIM(sizeofW(StgArrWords),DOUBLE_MANTISSA_SIZE,0);
-  CCS_ALLOC(CCCS,ARR_SIZE); /* ccs prof */
-
-  /* Be prepared to tell Lennart-coded __decodeDouble  */
-  /* where mantissa.d can be put (it does not care about the rest) */
-  p = (StgArrWords *)(Hp-ARR_SIZE+1);
-  SET_ARR_HDR(p, &stg_ARR_WORDS_info, CCCS, DOUBLE_MANTISSA_SIZE);
-  mantissa._mp_d = (void *)BYTE_ARR_CTS(p);
-
-  /* Perform the operation */
-  STGCALL3(__decodeDouble,&mantissa,&exponent,arg);
-
-  /* returns: (Int# (expn), Int#, ByteArray#) */
-  TICK_RET_UNBOXED_TUP(3);
-  RET_NNP(exponent,mantissa._mp_size,p);
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
- * Concurrency primitives
- * -------------------------------------------------------------------------- */
-
-FN_(forkzh_fast)
-{
-  FB_
-  /* args: R1 = closure to spark */
-  
-  MAYBE_GC(R1_PTR, forkzh_fast);
-
-  /* create it right now, return ThreadID in R1 */
-  R1.t = RET_STGCALL2(StgTSO *, createIOThread, 
-                    RtsFlags.GcFlags.initialStkSize, R1.cl);
-  STGCALL1(scheduleThread, R1.t);
-      
-  /* switch at the earliest opportunity */ 
-  context_switch = 1;
-  
-  RET_P(R1.t);
-  FE_
-}
-
-FN_(yieldzh_fast)
-{
-  FB_
-  JMP_(stg_yield_noregs);
-  FE_
-}
-
-FN_(myThreadIdzh_fast)
-{
-  /* no args. */
-  FB_
-  RET_P((P_)CurrentTSO);
-  FE_
-}
-
-FN_(labelThreadzh_fast)
-{
-  FB_
-  /* args: 
-       R1.p = ThreadId#
-       R2.p = Addr# */
-#ifdef DEBUG
-  STGCALL2(labelThread,R1.p,(char *)R2.p);
-#endif
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-
-FN_(isCurrentThreadBoundzh_fast)
-{
-  /* no args */
-  I_ r;
-  FB_
-  r = (I_)(RET_STGCALL1(StgBool, isThreadBound, CurrentTSO));
-  RET_N(r);
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
- * MVar primitives
- *
- * take & putMVar work as follows.  Firstly, an important invariant:
- *
- *    If the MVar is full, then the blocking queue contains only
- *    threads blocked on putMVar, and if the MVar is empty then the
- *    blocking queue contains only threads blocked on takeMVar.
- *
- * takeMvar:
- *    MVar empty : then add ourselves to the blocking queue
- *    MVar full  : remove the value from the MVar, and
- *                 blocking queue empty     : return
- *                 blocking queue non-empty : perform the first blocked putMVar
- *                                            from the queue, and wake up the
- *                                            thread (MVar is now full again)
- *
- * putMVar is just the dual of the above algorithm.
- *
- * How do we "perform a putMVar"?  Well, we have to fiddle around with
- * the stack of the thread waiting to do the putMVar.  See
- * stg_block_putmvar and stg_block_takemvar in HeapStackCheck.c for
- * the stack layout, and the PerformPut and PerformTake macros below.
- *
- * It is important that a blocked take or put is woken up with the
- * take/put already performed, because otherwise there would be a
- * small window of vulnerability where the thread could receive an
- * exception and never perform its take or put, and we'd end up with a
- * deadlock.
- *
- * -------------------------------------------------------------------------- */
-
-FN_(isEmptyMVarzh_fast)
-{
-  /* args: R1 = MVar closure */
-  I_ r;
-  FB_
-  r = (I_)((GET_INFO((StgMVar*)(R1.p))) == &stg_EMPTY_MVAR_info);
-  RET_N(r);
-  FE_
-}
-
-
-FN_(newMVarzh_fast)
-{
-  StgMVar *mvar;
-
-  FB_
-  /* args: none */
-
-  HP_CHK_GEN_TICKY(sizeofW(StgMVar), NO_PTRS, newMVarzh_fast);
-  TICK_ALLOC_PRIM(sizeofW(StgMutVar)-1, // consider head,tail,link as admin wds
-                 1, 0);
-  CCS_ALLOC(CCCS,sizeofW(StgMVar)); /* ccs prof */
-  
-  mvar = (StgMVar *) (Hp - sizeofW(StgMVar) + 1);
-  SET_HDR(mvar,&stg_EMPTY_MVAR_info,CCCS);
-  mvar->head = mvar->tail = (StgTSO *)&stg_END_TSO_QUEUE_closure;
-  mvar->value = (StgClosure *)&stg_END_TSO_QUEUE_closure;
-
-  TICK_RET_UNBOXED_TUP(1);
-  RET_P(mvar);
-  FE_
-}
-
-/* If R1 isn't available, pass it on the stack */
-#ifdef REG_R1
-#define PerformTake(tso, value) ({             \
-    (tso)->sp[1] = (W_)value;                  \
-    (tso)->sp[0] = (W_)&stg_gc_unpt_r1_info;   \
-  })
-#else
-#define PerformTake(tso, value) ({             \
-    (tso)->sp[1] = (W_)value;                  \
-    (tso)->sp[0] = (W_)&stg_ut_1_0_unreg_info; \
-  })
-#endif
-
-
-#define PerformPut(tso) ({                             \
-    StgClosure *val = (StgClosure *)(tso)->sp[2];      \
-    (tso)->sp += 3;                                    \
-    val;                                               \
-  })
-
-FN_(takeMVarzh_fast)
-{
-  StgMVar *mvar;
-  StgClosure *val;
-  const StgInfoTable *info;
-
-  FB_
-  /* args: R1 = MVar closure */
-
-  mvar = (StgMVar *)R1.p;
-
-#ifdef SMP
-  info = LOCK_CLOSURE(mvar);
-#else
-  info = GET_INFO(mvar);
-#endif
-
-  /* If the MVar is empty, put ourselves on its blocking queue,
-   * and wait until we're woken up.
-   */
-  if (info == &stg_EMPTY_MVAR_info) {
-    if (mvar->head == (StgTSO *)&stg_END_TSO_QUEUE_closure) {
-      mvar->head = CurrentTSO;
-    } else {
-      mvar->tail->link = CurrentTSO;
-    }
-    CurrentTSO->link = (StgTSO *)&stg_END_TSO_QUEUE_closure;
-    CurrentTSO->why_blocked = BlockedOnMVar;
-    CurrentTSO->block_info.closure = (StgClosure *)mvar;
-    mvar->tail = CurrentTSO;
-
-#ifdef SMP
-    /* unlock the MVar */
-    mvar->header.info = &stg_EMPTY_MVAR_info;
-#endif
-    JMP_(stg_block_takemvar);
-  }
-
-  /* we got the value... */
-  val = mvar->value;
-
-  if (mvar->head != (StgTSO *)&stg_END_TSO_QUEUE_closure) {
-      /* There are putMVar(s) waiting... 
-       * wake up the first thread on the queue
-       */
-      ASSERT(mvar->head->why_blocked == BlockedOnMVar);
-
-      /* actually perform the putMVar for the thread that we just woke up */
-      mvar->value = PerformPut(mvar->head);
-
-#if defined(GRAN) || defined(PAR)
-      /* ToDo: check 2nd arg (mvar) is right */
-      mvar->head = RET_STGCALL2(StgTSO *,unblockOne,mvar->head,mvar);
-#else
-      mvar->head = RET_STGCALL1(StgTSO *,unblockOne,mvar->head);
-#endif
-      if (mvar->head == (StgTSO *)&stg_END_TSO_QUEUE_closure) {
-         mvar->tail = (StgTSO *)&stg_END_TSO_QUEUE_closure;
-      }
-#ifdef SMP
-      /* unlock in the SMP case */
-      SET_INFO(mvar,&stg_FULL_MVAR_info);
-#endif
-      TICK_RET_UNBOXED_TUP(1);
-      RET_P(val);
-  } else {
-      /* No further putMVars, MVar is now empty */
-
-      /* do this last... we might have locked the MVar in the SMP case,
-       * and writing the info pointer will unlock it.
-       */
-      SET_INFO(mvar,&stg_EMPTY_MVAR_info);
-      mvar->value = (StgClosure *)&stg_END_TSO_QUEUE_closure;
-      TICK_RET_UNBOXED_TUP(1);
-      RET_P(val);
-  }
-  FE_
-}
-
-FN_(tryTakeMVarzh_fast)
-{
-  StgMVar *mvar;
-  StgClosure *val;
-  const StgInfoTable *info;
-
-  FB_
-  /* args: R1 = MVar closure */
-
-  mvar = (StgMVar *)R1.p;
-
-#ifdef SMP
-  info = LOCK_CLOSURE(mvar);
-#else
-  info = GET_INFO(mvar);
-#endif
-
-  if (info == &stg_EMPTY_MVAR_info) {
-
-#ifdef SMP
-      /* unlock the MVar */
-      SET_INFO(mvar,&stg_EMPTY_MVAR_info);
-#endif
-
-      /* HACK: we need a pointer to pass back, 
-       * so we abuse NO_FINALIZER_closure
-       */
-      RET_NP(0, &stg_NO_FINALIZER_closure);
-  }
-
-  /* we got the value... */
-  val = mvar->value;
-
-  if (mvar->head != (StgTSO *)&stg_END_TSO_QUEUE_closure) {
-      /* There are putMVar(s) waiting... 
-       * wake up the first thread on the queue
-       */
-      ASSERT(mvar->head->why_blocked == BlockedOnMVar);
-
-      /* actually perform the putMVar for the thread that we just woke up */
-      mvar->value = PerformPut(mvar->head);
-
-#if defined(GRAN) || defined(PAR)
-      /* ToDo: check 2nd arg (mvar) is right */
-      mvar->head = RET_STGCALL2(StgTSO *,unblockOne,mvar->head,mvar);
-#else
-      mvar->head = RET_STGCALL1(StgTSO *,unblockOne,mvar->head);
-#endif
-      if (mvar->head == (StgTSO *)&stg_END_TSO_QUEUE_closure) {
-         mvar->tail = (StgTSO *)&stg_END_TSO_QUEUE_closure;
-      }
-#ifdef SMP
-      /* unlock in the SMP case */
-      SET_INFO(mvar,&stg_FULL_MVAR_info);
-#endif
-  } else {
-      /* No further putMVars, MVar is now empty */
-      mvar->value = (StgClosure *)&stg_END_TSO_QUEUE_closure;
-
-      /* do this last... we might have locked the MVar in the SMP case,
-       * and writing the info pointer will unlock it.
-       */
-      SET_INFO(mvar,&stg_EMPTY_MVAR_info);
-  }
-
-  TICK_RET_UNBOXED_TUP(1);
-  RET_NP((I_)1, val);
-  FE_
-}
-
-FN_(putMVarzh_fast)
-{
-  StgMVar *mvar;
-  const StgInfoTable *info;
-
-  FB_
-  /* args: R1 = MVar, R2 = value */
-
-  mvar = (StgMVar *)R1.p;
-
-#ifdef SMP
-  info = LOCK_CLOSURE(mvar);
-#else
-  info = GET_INFO(mvar);
-#endif
-
-  if (info == &stg_FULL_MVAR_info) {
-    if (mvar->head == (StgTSO *)&stg_END_TSO_QUEUE_closure) {
-      mvar->head = CurrentTSO;
-    } else {
-      mvar->tail->link = CurrentTSO;
-    }
-    CurrentTSO->link = (StgTSO *)&stg_END_TSO_QUEUE_closure;
-    CurrentTSO->why_blocked = BlockedOnMVar;
-    CurrentTSO->block_info.closure = (StgClosure *)mvar;
-    mvar->tail = CurrentTSO;
-
-#ifdef SMP
-    /* unlock the MVar */
-    SET_INFO(mvar,&stg_FULL_MVAR_info);
-#endif
-    JMP_(stg_block_putmvar);
-  }
-  
-  if (mvar->head != (StgTSO *)&stg_END_TSO_QUEUE_closure) {
-      /* There are takeMVar(s) waiting: wake up the first one
-       */
-      ASSERT(mvar->head->why_blocked == BlockedOnMVar);
-
-      /* actually perform the takeMVar */
-      PerformTake(mvar->head, R2.cl);
-      
-#if defined(GRAN) || defined(PAR)
-      /* ToDo: check 2nd arg (mvar) is right */
-      mvar->head = RET_STGCALL2(StgTSO *,unblockOne,mvar->head,mvar);
-#else
-      mvar->head = RET_STGCALL1(StgTSO *,unblockOne,mvar->head);
-#endif
-      if (mvar->head == (StgTSO *)&stg_END_TSO_QUEUE_closure) {
-         mvar->tail = (StgTSO *)&stg_END_TSO_QUEUE_closure;
-      }
-#ifdef SMP
-      /* unlocks the MVar in the SMP case */
-      SET_INFO(mvar,&stg_EMPTY_MVAR_info);
-#endif
-      JMP_(ENTRY_CODE(Sp[0]));
-  } else {
-      /* No further takes, the MVar is now full. */
-      mvar->value = R2.cl;
-      /* unlocks the MVar in the SMP case */
-      SET_INFO(mvar,&stg_FULL_MVAR_info);
-      JMP_(ENTRY_CODE(Sp[0]));
-  }
-
-  /* ToDo: yield afterward for better communication performance? */
-  FE_
-}
-
-FN_(tryPutMVarzh_fast)
-{
-  StgMVar *mvar;
-  const StgInfoTable *info;
-
-  FB_
-  /* args: R1 = MVar, R2 = value */
-
-  mvar = (StgMVar *)R1.p;
-
-#ifdef SMP
-  info = LOCK_CLOSURE(mvar);
-#else
-  info = GET_INFO(mvar);
-#endif
-
-  if (info == &stg_FULL_MVAR_info) {
-
-#ifdef SMP
-    /* unlock the MVar */
-    mvar->header.info = &stg_FULL_MVAR_info;
-#endif
-
-    RET_N(0);
-  }
-  
-  if (mvar->head != (StgTSO *)&stg_END_TSO_QUEUE_closure) {
-      /* There are takeMVar(s) waiting: wake up the first one
-       */
-      ASSERT(mvar->head->why_blocked == BlockedOnMVar);
-
-      /* actually perform the takeMVar */
-      PerformTake(mvar->head, R2.cl);
-      
-#if defined(GRAN) || defined(PAR)
-      /* ToDo: check 2nd arg (mvar) is right */
-      mvar->head = RET_STGCALL2(StgTSO *,unblockOne,mvar->head,mvar);
-#else
-      mvar->head = RET_STGCALL1(StgTSO *,unblockOne,mvar->head);
-#endif
-      if (mvar->head == (StgTSO *)&stg_END_TSO_QUEUE_closure) {
-         mvar->tail = (StgTSO *)&stg_END_TSO_QUEUE_closure;
-      }
-#ifdef SMP
-      /* unlocks the MVar in the SMP case */
-      SET_INFO(mvar,&stg_EMPTY_MVAR_info);
-#endif
-      JMP_(ENTRY_CODE(Sp[0]));
-  } else {
-      /* No further takes, the MVar is now full. */
-      mvar->value = R2.cl;
-      /* unlocks the MVar in the SMP case */
-      SET_INFO(mvar,&stg_FULL_MVAR_info);
-      JMP_(ENTRY_CODE(Sp[0]));
-  }
-
-  /* ToDo: yield afterward for better communication performance? */
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Stable pointer primitives
-   -------------------------------------------------------------------------  */
-
-FN_(makeStableNamezh_fast)
-{
-  StgWord index;
-  StgStableName *sn_obj;
-  FB_
-
-  HP_CHK_GEN_TICKY(sizeofW(StgStableName), R1_PTR, makeStableNamezh_fast);
-  TICK_ALLOC_PRIM(sizeofW(StgHeader), 
-                 sizeofW(StgStableName)-sizeofW(StgHeader), 0);
-  CCS_ALLOC(CCCS,sizeofW(StgStableName)); /* ccs prof */
-  
-  index = RET_STGCALL1(StgWord,lookupStableName,R1.p);
-
-  /* Is there already a StableName for this heap object? */
-  if (stable_ptr_table[index].sn_obj == NULL) {
-    sn_obj = (StgStableName *) (Hp - sizeofW(StgStableName) + 1);
-    SET_HDR(sn_obj,&stg_STABLE_NAME_info,CCCS);
-    sn_obj->sn = index;
-    stable_ptr_table[index].sn_obj = (StgClosure *)sn_obj;
-  } else {
-    (StgClosure *)sn_obj = stable_ptr_table[index].sn_obj;
-  }
-
-  TICK_RET_UNBOXED_TUP(1);
-  RET_P(sn_obj);
-}
-
-
-FN_(makeStablePtrzh_fast)
-{
-  /* Args: R1 = a */
-  StgStablePtr sp;
-  FB_
-  MAYBE_GC(R1_PTR, makeStablePtrzh_fast);
-  sp = RET_STGCALL1(StgStablePtr,getStablePtr,R1.p);
-  RET_N(sp);
-  FE_
-}
-
-FN_(deRefStablePtrzh_fast)
-{
-  /* Args: R1 = the stable ptr */
-  P_ r;
-  StgStablePtr sp;
-  FB_
-  sp = (StgStablePtr)R1.w;
-  r = stable_ptr_table[(StgWord)sp].addr;
-  RET_P(r);
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Bytecode object primitives
-   -------------------------------------------------------------------------  */
-
-FN_(newBCOzh_fast)
-{
-  /* R1.p = instrs
-     R2.p = literals
-     R3.p = ptrs
-     R4.p = itbls
-     R5.i = arity
-     R6.p = bitmap array
-  */
-  StgBCO *bco;
-  nat size;
-  StgArrWords *bitmap_arr;
-  FB_
-
-  bitmap_arr = (StgArrWords *)R6.cl;
-  size = sizeofW(StgBCO) + bitmap_arr->words;
-  HP_CHK_GEN_TICKY(size,R1_PTR|R2_PTR|R3_PTR|R4_PTR|R6_PTR, newBCOzh_fast);
-  TICK_ALLOC_PRIM(size, size-sizeofW(StgHeader), 0);
-  CCS_ALLOC(CCCS,size); /* ccs prof */
-  bco = (StgBCO *) (Hp + 1 - size);
-  SET_HDR(bco, (const StgInfoTable *)&stg_BCO_info, CCCS);
-
-  bco->instrs     = (StgArrWords*)R1.cl;
-  bco->literals   = (StgArrWords*)R2.cl;
-  bco->ptrs       = (StgMutArrPtrs*)R3.cl;
-  bco->itbls      = (StgArrWords*)R4.cl;
-  bco->arity      = R5.w;
-  bco->size       = size;
-
-  // Copy the arity/bitmap info into the BCO
-  { 
-    int i;
-    for (i = 0; i < bitmap_arr->words; i++) {
-       bco->bitmap[i] = bitmap_arr->payload[i];
-    }
-  }
-
-  TICK_RET_UNBOXED_TUP(1);
-  RET_P(bco);
-  FE_
-}
-
-FN_(mkApUpd0zh_fast)
-{
-  // R1.p = the BCO# for the AP
-  //
-  StgPAP* ap;
-  FB_
-
-  // This function is *only* used to wrap zero-arity BCOs in an
-  // updatable wrapper (see ByteCodeLink.lhs).  An AP thunk is always
-  // saturated and always points directly to a FUN or BCO.
-  ASSERT(get_itbl(R1.cl)->type == BCO && ((StgBCO *)R1.p)->arity == 0);
-
-  HP_CHK_GEN_TICKY(PAP_sizeW(0), R1_PTR, mkApUpd0zh_fast);
-  TICK_ALLOC_PRIM(sizeofW(StgHeader), PAP_sizeW(0)-sizeofW(StgHeader), 0);
-  CCS_ALLOC(CCCS,PAP_sizeW(0)); /* ccs prof */
-  ap = (StgPAP *) (Hp + 1 - PAP_sizeW(0));
-  SET_HDR(ap, &stg_AP_info, CCCS);
-
-  ap->n_args = 0;
-  ap->fun = R1.cl;
-
-  TICK_RET_UNBOXED_TUP(1);
-  RET_P(ap);
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Thread I/O blocking primitives
-   -------------------------------------------------------------------------- */
-
-FN_(waitReadzh_fast)
-{
-  FB_
-    /* args: R1.i */
-    ASSERT(CurrentTSO->why_blocked == NotBlocked);
-    CurrentTSO->why_blocked = BlockedOnRead;
-    CurrentTSO->block_info.fd = R1.i;
-    ACQUIRE_LOCK(&sched_mutex);
-    APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
-    RELEASE_LOCK(&sched_mutex);
-    JMP_(stg_block_noregs);
-  FE_
-}
-
-FN_(waitWritezh_fast)
-{
-  FB_
-    /* args: R1.i */
-    ASSERT(CurrentTSO->why_blocked == NotBlocked);
-    CurrentTSO->why_blocked = BlockedOnWrite;
-    CurrentTSO->block_info.fd = R1.i;
-    ACQUIRE_LOCK(&sched_mutex);
-    APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
-    RELEASE_LOCK(&sched_mutex);
-    JMP_(stg_block_noregs);
-  FE_
-}
-
-FN_(delayzh_fast)
-{
-#ifdef mingw32_TARGET_OS
-  StgAsyncIOResult* ares;
-  unsigned int reqID;
-#else
-  StgTSO *t, *prev;
-  nat target;
-#endif
-  FB_
-    /* args: R1.i (microsecond delay amount) */
-    ASSERT(CurrentTSO->why_blocked == NotBlocked);
-    CurrentTSO->why_blocked = BlockedOnDelay;
-
-    ACQUIRE_LOCK(&sched_mutex);
-#ifdef mingw32_TARGET_OS
-    /* could probably allocate this on the heap instead */
-    ares = (StgAsyncIOResult*)RET_STGCALL2(P_,stgMallocBytes,sizeof(StgAsyncIOResult), "delayzh_fast");
-    reqID = RET_STGCALL1(W_,addDelayRequest,R1.i);
-    ares->reqID   = reqID;
-    ares->len     = 0;
-    ares->errCode = 0;
-    CurrentTSO->block_info.async_result = ares;
-    /* Having all async-blocked threads reside on the blocked_queue simplifies matters, so
-     * change the status to OnDoProc & put the delayed thread on the blocked_queue.
-     */
-    CurrentTSO->why_blocked = BlockedOnDoProc;
-    APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
-#else
-    target = ((R1.i + TICK_MILLISECS*1000-1) / (TICK_MILLISECS*1000)) + getourtimeofday();
-    CurrentTSO->block_info.target = target;
-
-    /* Insert the new thread in the sleeping queue. */
-    prev = NULL;
-    t = sleeping_queue;
-    while (t != END_TSO_QUEUE && t->block_info.target < target) {
-       prev = t;
-       t = t->link;
-    }
-
-    CurrentTSO->link = t;
-    if (prev == NULL) {
-       sleeping_queue = CurrentTSO;
-    } else {
-       prev->link = CurrentTSO;
-    }
-#endif
-    RELEASE_LOCK(&sched_mutex);
-    JMP_(stg_block_noregs);
-  FE_
-}
-
-#ifdef mingw32_TARGET_OS
-FN_(asyncReadzh_fast)
-{
-  StgAsyncIOResult* ares;
-  unsigned int reqID;
-  FB_
-    /* args: R1.i = fd, R2.i = isSock, R3.i = len, R4.p = buf */
-    ASSERT(CurrentTSO->why_blocked == NotBlocked);
-    CurrentTSO->why_blocked = BlockedOnRead;
-    ACQUIRE_LOCK(&sched_mutex);
-    /* could probably allocate this on the heap instead */
-    ares = (StgAsyncIOResult*)RET_STGCALL2(P_,stgMallocBytes,sizeof(StgAsyncIOResult), "asyncReadzh_fast");
-    reqID = RET_STGCALL5(W_,addIORequest,R1.i,FALSE,R2.i,R3.i,(char*)R4.p);
-    ares->reqID   = reqID;
-    ares->len     = 0;
-    ares->errCode = 0;
-    CurrentTSO->block_info.async_result = ares;
-    APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
-    RELEASE_LOCK(&sched_mutex);
-    JMP_(stg_block_async);
-  FE_
-}
-
-FN_(asyncWritezh_fast)
-{
-  StgAsyncIOResult* ares;
-  unsigned int reqID;
-  FB_
-    /* args: R1.i */
-    /* args: R1.i = fd, R2.i = isSock, R3.i = len, R4.p = buf */
-    ASSERT(CurrentTSO->why_blocked == NotBlocked);
-    CurrentTSO->why_blocked = BlockedOnWrite;
-    ACQUIRE_LOCK(&sched_mutex);
-    ares = (StgAsyncIOResult*)RET_STGCALL2(P_,stgMallocBytes,sizeof(StgAsyncIOResult), "asyncWritezh_fast");
-    reqID = RET_STGCALL5(W_,addIORequest,R1.i,TRUE,R2.i,R3.i,(char*)R4.p);
-    ares->reqID   = reqID;
-    ares->len     = 0;
-    ares->errCode = 0;
-    CurrentTSO->block_info.async_result = ares;
-    APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
-    RELEASE_LOCK(&sched_mutex);
-    JMP_(stg_block_async);
-  FE_
-}
-
-FN_(asyncDoProczh_fast)
-{
-  StgAsyncIOResult* ares;
-  unsigned int reqID;
-  FB_
-    /* args: R1.i = proc, R2.i = param */
-    ASSERT(CurrentTSO->why_blocked == NotBlocked);
-    CurrentTSO->why_blocked = BlockedOnDoProc;
-    ACQUIRE_LOCK(&sched_mutex);
-    /* could probably allocate this on the heap instead */
-    ares = (StgAsyncIOResult*)RET_STGCALL2(P_,stgMallocBytes,sizeof(StgAsyncIOResult), "asyncDoProczh_fast");
-    reqID = RET_STGCALL2(W_,addDoProcRequest,R1.p,R2.p);
-    ares->reqID   = reqID;
-    ares->len     = 0;
-    ares->errCode = 0;
-    CurrentTSO->block_info.async_result = ares;
-    APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
-    RELEASE_LOCK(&sched_mutex);
-    JMP_(stg_block_async);
-  FE_
-}
-#endif
-
index 9f36146..e1c0b4d 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Printer.c,v 1.62 2003/11/12 17:49:08 sof Exp $
+ * $Id: Printer.c,v 1.63 2004/08/13 13:10:23 simonmar Exp $
  *
  * (c) The GHC Team, 1994-2000.
  *
@@ -28,7 +28,7 @@
 
 #if defined(GRAN) || defined(PAR)
 // HWL: explicit fixed header size to make debugging easier
-int fixed_hs = FIXED_HS, itbl_sz = sizeofW(StgInfoTable), 
+int fixed_hs = sizeof(StgHeader), itbl_sz = sizeofW(StgInfoTable), 
     uf_sz=sizeofW(StgUpdateFrame); 
 #endif
 
@@ -152,7 +152,7 @@ printClosure( StgClosure *obj )
     case FUN_1_0: case FUN_0_1: 
     case FUN_1_1: case FUN_0_2: case FUN_2_0:
     case FUN_STATIC:
-       fprintf(stderr,"FUN/%d(",itbl_to_fun_itbl(info)->arity);
+       fprintf(stderr,"FUN/%d(",itbl_to_fun_itbl(info)->f.arity);
        printPtr((StgPtr)obj->header.info);
 #ifdef PROFILING
        fprintf(stderr,", %s", obj->header.prof.ccs->cc->label);
@@ -458,19 +458,19 @@ printStackObj( StgPtr sp )
 
         StgClosure* c = (StgClosure*)(*sp);
         printPtr((StgPtr)*sp);
-        if (c == (StgClosure*)&stg_ctoi_ret_R1p_info) {
+        if (c == (StgClosure*)&stg_ctoi_R1p_info) {
            fprintf(stderr, "\t\t\tstg_ctoi_ret_R1p_info\n" );
        } else
-        if (c == (StgClosure*)&stg_ctoi_ret_R1n_info) {
+        if (c == (StgClosure*)&stg_ctoi_R1n_info) {
            fprintf(stderr, "\t\t\tstg_ctoi_ret_R1n_info\n" );
        } else
-        if (c == (StgClosure*)&stg_ctoi_ret_F1_info) {
+        if (c == (StgClosure*)&stg_ctoi_F1_info) {
            fprintf(stderr, "\t\t\tstg_ctoi_ret_F1_info\n" );
        } else
-        if (c == (StgClosure*)&stg_ctoi_ret_D1_info) {
+        if (c == (StgClosure*)&stg_ctoi_D1_info) {
            fprintf(stderr, "\t\t\tstg_ctoi_ret_D1_info\n" );
        } else
-        if (c == (StgClosure*)&stg_ctoi_ret_V_info) {
+        if (c == (StgClosure*)&stg_ctoi_V_info) {
            fprintf(stderr, "\t\t\tstg_ctoi_ret_V_info\n" );
        } else
         if (get_itbl(c)->type == BCO) {
@@ -559,16 +559,17 @@ printStackChunk( StgPtr sp, StgPtr spBottom )
 
            p = (P_)(r->payload);
            printSmallBitmap(spBottom, sp,
-                            GET_LIVENESS(r->liveness), RET_DYN_BITMAP_SIZE);
+                            RET_DYN_LIVENESS(r->liveness), 
+                            RET_DYN_BITMAP_SIZE);
            p += RET_DYN_BITMAP_SIZE + RET_DYN_NONPTR_REGS_SIZE;
 
-           for (size = GET_NONPTRS(dyn); size > 0; size--) {
+           for (size = RET_DYN_NONPTRS(dyn); size > 0; size--) {
                fprintf(stderr,"   stk[%ld] (%p) = ", (long)(spBottom-p), p);
                fprintf(stderr,"Word# %ld\n", (long)*p);
                p++;
            }
        
-           for (size = GET_PTRS(dyn); size > 0; size--) {
+           for (size = RET_DYN_PTRS(dyn); size > 0; size--) {
                fprintf(stderr,"   stk[%ld] (%p) = ", (long)(spBottom-p), p);
                printPtr(p);
                p++;
@@ -608,22 +609,22 @@ printStackChunk( StgPtr sp, StgPtr spBottom )
            ret_fun = (StgRetFun *)sp;
            fun_info = get_fun_itbl(ret_fun->fun);
            size = ret_fun->size;
-           fprintf(stderr,"RET_FUN (%p) (type=%d)\n", ret_fun, fun_info->fun_type);
-           switch (fun_info->fun_type) {
+           fprintf(stderr,"RET_FUN (%p) (type=%d)\n", ret_fun, fun_info->f.fun_type);
+           switch (fun_info->f.fun_type) {
            case ARG_GEN:
                printSmallBitmap(spBottom, sp+1,
-                                BITMAP_BITS(fun_info->bitmap),
-                                BITMAP_SIZE(fun_info->bitmap));
+                                BITMAP_BITS(fun_info->f.bitmap),
+                                BITMAP_SIZE(fun_info->f.bitmap));
                break;
            case ARG_GEN_BIG:
                printLargeBitmap(spBottom, sp+2,
-                                (StgLargeBitmap *)fun_info->bitmap,
-                                BITMAP_SIZE(fun_info->bitmap));
+                                (StgLargeBitmap *)fun_info->f.bitmap,
+                                BITMAP_SIZE(fun_info->f.bitmap));
                break;
            default:
                printSmallBitmap(spBottom, sp+1,
-                                BITMAP_BITS(stg_arg_bitmaps[fun_info->fun_type]),
-                                BITMAP_SIZE(stg_arg_bitmaps[fun_info->fun_type]));
+                                BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]),
+                                BITMAP_SIZE(stg_arg_bitmaps[fun_info->f.fun_type]));
                break;
            }
            continue;
@@ -1060,8 +1061,6 @@ extern void DEBUG_LoadSymbols( char *name STG_UNUSED )
 
 #endif /* HAVE_BFD_H */
 
-#include "StoragePriv.h"
-
 void findPtr(P_ p, int);               /* keep gcc -Wall happy */
 
 void
index e7d03be..49b3813 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: ProfHeap.c,v 1.52 2004/05/11 18:36:10 panne Exp $
+ * $Id: ProfHeap.c,v 1.53 2004/08/13 13:10:25 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2003
  *
@@ -250,6 +250,7 @@ LDV_recordDead( StgClosure *c, nat size )
 
     if (era > 0 && closureSatisfiesConstraints(c)) {
        size -= sizeofW(StgProfHeader);
+       ASSERT(LDVW(c) != 0);
        if ((LDVW((c)) & LDV_STATE_MASK) == LDV_STATE_CREATE) {
            t = (LDVW((c)) & LDV_CREATE_MASK) >> LDV_SHIFT;
            if (t < era) {
index a7466c7..abe319d 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Profiling.c,v 1.37 2003/08/22 22:24:13 sof Exp $
+ * $Id: Profiling.c,v 1.38 2004/08/13 13:10:26 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2000
  *
@@ -328,19 +328,19 @@ endProfiling ( void )
    -------------------------------------------------------------------------- */
 rtsBool entering_PAP;
 
-CostCentreStack *
-EnterFunCCS ( CostCentreStack *cccs, CostCentreStack *ccsfn )
+void
+EnterFunCCS ( CostCentreStack *ccsfn )
 {
   /* PAP_entry has already set CCCS for us */
   if (entering_PAP) {
     entering_PAP = rtsFalse;
-    return CCCS;
+    return;
   }
 
   if (ccsfn->root->is_caf == CC_IS_CAF) {
-    return AppendCCS(cccs,ccsfn);
+    CCCS = AppendCCS(CCCS,ccsfn);
   } else {
-    return ccsfn;
+    CCCS = ccsfn;
   }
 }
 
index 7cc38df..735fa66 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Profiling.h,v 1.5 2002/07/18 09:12:03 simonmar Exp $
+ * $Id: Profiling.h,v 1.6 2004/08/13 13:10:28 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2000
  *
@@ -23,7 +23,7 @@ void reportCCSProfiling ( void );
 
 void PrintNewStackDecls ( void );
 
-extern lnat total_prof_ticks;
+extern lnat RTS_VAR(total_prof_ticks);
 
 extern void fprintCCS( FILE *f, CostCentreStack *ccs );
 
index b28d898..1ff0027 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: RetainerProfile.c,v 1.10 2003/05/16 14:39:29 simonmar Exp $
+ * $Id: RetainerProfile.c,v 1.11 2004/08/13 13:10:28 simonmar Exp $
  *
  * (c) The GHC Team, 2001
  * Author: Sungwoo Park
 #include "Schedule.h"
 #include "Printer.h"
 #include "Storage.h"
-#include "StoragePriv.h"
 #include "RtsFlags.h"
 #include "Weak.h"
 #include "Sanity.h"
-#include "StablePriv.h"
 #include "Profiling.h"
 #include "Stats.h"
 #include "BlockAlloc.h"
@@ -334,11 +332,11 @@ init_srt_fun( stackPos *info, StgFunInfoTable *infoTable )
 {
     if (infoTable->i.srt_bitmap == (StgHalfWord)(-1)) {
        info->type = posTypeLargeSRT;
-       info->next.large_srt.srt = (StgLargeSRT *)infoTable->srt;
+       info->next.large_srt.srt = (StgLargeSRT *)infoTable->f.srt;
        info->next.large_srt.offset = 0;
     } else {
        info->type = posTypeSRT;
-       info->next.srt.srt = (StgClosure **)(infoTable->srt);
+       info->next.srt.srt = (StgClosure **)(infoTable->f.srt);
        info->next.srt.srt_bitmap = infoTable->i.srt_bitmap;
     }
 }
@@ -1357,16 +1355,16 @@ retainStack( StgClosure *c, retainer c_child_r,
            dyn = ((StgRetDyn *)p)->liveness;
 
            // traverse the bitmap first
-           bitmap = GET_LIVENESS(dyn);
+           bitmap = RET_DYN_LIVENESS(dyn);
            p      = (P_)&((StgRetDyn *)p)->payload[0];
            size   = RET_DYN_BITMAP_SIZE;
            p = retain_small_bitmap(p, size, bitmap, c, c_child_r);
            
            // skip over the non-ptr words
-           p += GET_NONPTRS(dyn) + RET_DYN_NONPTR_REGS_SIZE;
+           p += RET_DYN_NONPTRS(dyn) + RET_DYN_NONPTR_REGS_SIZE;
            
            // follow the ptr words
-           for (size = GET_PTRS(dyn); size > 0; size--) {
+           for (size = RET_DYN_PTRS(dyn); size > 0; size--) {
                retainClosure((StgClosure *)*p, c, c_child_r);
                p++;
            }
@@ -1381,21 +1379,21 @@ retainStack( StgClosure *c, retainer c_child_r,
            fun_info = get_fun_itbl(ret_fun->fun);
            
            p = (P_)&ret_fun->payload;
-           switch (fun_info->fun_type) {
+           switch (fun_info->f.fun_type) {
            case ARG_GEN:
-               bitmap = BITMAP_BITS(fun_info->bitmap);
-               size = BITMAP_SIZE(fun_info->bitmap);
+               bitmap = BITMAP_BITS(fun_info->f.bitmap);
+               size = BITMAP_SIZE(fun_info->f.bitmap);
                p = retain_small_bitmap(p, size, bitmap, c, c_child_r);
                break;
            case ARG_GEN_BIG:
-               size = ((StgLargeBitmap *)fun_info->bitmap)->size;
-               retain_large_bitmap(p, (StgLargeBitmap *)fun_info->bitmap, 
+               size = ((StgLargeBitmap *)fun_info->f.bitmap)->size;
+               retain_large_bitmap(p, (StgLargeBitmap *)fun_info->f.bitmap, 
                                    size, c, c_child_r);
                p += size;
                break;
            default:
-               bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->fun_type]);
-               size = BITMAP_SIZE(stg_arg_bitmaps[fun_info->fun_type]);
+               bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
+               size = BITMAP_SIZE(stg_arg_bitmaps[fun_info->f.fun_type]);
                p = retain_small_bitmap(p, size, bitmap, c, c_child_r);
                break;
            }
@@ -1437,14 +1435,14 @@ retain_PAP (StgPAP *pap, retainer c_child_r)
     p = (StgPtr)pap->payload;
     size = pap->n_args;
 
-    switch (fun_info->fun_type) {
+    switch (fun_info->f.fun_type) {
     case ARG_GEN:
-       bitmap = BITMAP_BITS(fun_info->bitmap);
+       bitmap = BITMAP_BITS(fun_info->f.bitmap);
        p = retain_small_bitmap(p, pap->n_args, bitmap, 
                                (StgClosure *)pap, c_child_r);
        break;
     case ARG_GEN_BIG:
-       retain_large_bitmap(p, (StgLargeBitmap *)fun_info->bitmap,
+       retain_large_bitmap(p, (StgLargeBitmap *)fun_info->f.bitmap,
                            size, (StgClosure *)pap, c_child_r);
        p += size;
        break;
@@ -1454,7 +1452,7 @@ retain_PAP (StgPAP *pap, retainer c_child_r)
        p += size;
        break;
     default:
-       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->fun_type]);
+       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
        p = retain_small_bitmap(p, pap->n_args, bitmap, 
                                (StgClosure *)pap, c_child_r);
        break;
index 09dcb1c..5eec192 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: RetainerProfile.h,v 1.3 2003/03/21 16:18:38 sof Exp $
+ * $Id: RetainerProfile.h,v 1.4 2004/08/13 13:10:29 simonmar Exp $
  *
  * (c) The GHC Team, 2001
  * Author: Sungwoo Park
@@ -21,7 +21,7 @@ extern void  printRetainer         ( FILE *, retainer );
 extern void  retainerProfile       ( void );
 extern void  resetStaticObjectForRetainerProfiling ( void );
 
-extern StgWord flip;
+extern StgWord RTS_VAR(flip);
 
 // extract the retainer set field from c
 #define RSET(c)   ((c)->header.prof.hp.rs)
index a965435..cf8d2c5 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: RtsFlags.c,v 1.74 2004/03/22 11:48:30 simonmar Exp $
+ * $Id: RtsFlags.c,v 1.75 2004/08/13 13:10:29 simonmar Exp $
  *
  * (c) The AQUA Project, Glasgow University, 1994-1997
  * (c) The GHC Team, 1998-1999
@@ -36,7 +36,8 @@
 #include <stdlib.h>
 #include <string.h>
 
-extern struct RTS_FLAGS RtsFlags;
+// Flag Structure
+RTS_FLAGS RtsFlags;
 
 /*
  * Split argument lists
index 824c22f..59300c4 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: RtsStartup.c,v 1.80 2004/03/19 23:17:06 panne Exp $
+ * $Id: RtsStartup.c,v 1.81 2004/08/13 13:10:32 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2002
  *
@@ -13,7 +13,6 @@
 #include "RtsUtils.h"
 #include "RtsFlags.h"  
 #include "Storage.h"    /* initStorage, exitStorage */
-#include "StablePriv.h" /* initStablePtrTable */
 #include "Schedule.h"   /* initScheduler */
 #include "Stats.h"      /* initStats */
 #include "Signals.h"
 #include "Weak.h"
 #include "Ticky.h"
 #include "StgRun.h"
-#include "StgStartup.h"
 #include "Prelude.h"           /* fixupRTStoPreludeRefs */
 #include "HsFFI.h"
 #include "Linker.h"
 #include "ThreadLabels.h"
+#include "BlockAlloc.h"
 
 #if defined(RTS_GTK_FRONTPANEL)
 #include "FrontPanel.h"
@@ -67,9 +66,6 @@
 #include <signal.h>
 #endif
 
-// Flag Structure
-struct RTS_FLAGS RtsFlags;
-
 // Count of how many outstanding hs_init()s there have been.
 static int hs_init_count = 0;
 
@@ -93,6 +89,10 @@ __hscore_set_saved_termios(int fd, void* ts)
   }
 }
 
+#if i386_TARGET_ARCH
+static void x86_init_fpu ( void );
+#endif
+
 /* -----------------------------------------------------------------------------
    Starting up the RTS
    -------------------------------------------------------------------------- */
@@ -202,6 +202,10 @@ hs_init(int *argc, char **argv[])
     setlocale(LC_CTYPE,"");
 #endif
 
+#if i386_TARGET_ARCH
+//    x86_init_fpu();
+#endif
+
     /* Record initialization times */
     stat_endInit();
 }
@@ -285,12 +289,14 @@ hs_add_root(void (*init_root)(void))
        barf("hs_add_root() must be called after hs_init()");
     }
 
-    init_sp = 0;
+    /* The initialisation stack grows downward, with sp pointing 
+       to the last occupied word */
+    init_sp = INIT_STACK_BLOCKS*BLOCK_SIZE_W;
     bd = allocGroup(INIT_STACK_BLOCKS);
     init_stack = (F_ *)bd->start;
-    init_stack[init_sp++] = (F_)stg_init_ret;
+    init_stack[--init_sp] = (F_)stg_init_finish;
     if (init_root != NULL) {
-       init_stack[init_sp++] = (F_)init_root;
+       init_stack[--init_sp] = (F_)init_root;
     }
     
     cap.r.rSp = (P_)(init_stack + init_sp);
@@ -458,3 +464,28 @@ stg_exit(int n)
   exit(n);
 }
 
+/* -----------------------------------------------------------------------------
+   Initialise floating point unit on x86
+   -------------------------------------------------------------------------- */
+
+#if i386_TARGET_ARCH
+static void
+x86_init_fpu ( void )
+{
+  __volatile unsigned short int fpu_cw;
+
+  // Grab the control word
+  __asm __volatile ("fnstcw %0" : "=m" (fpu_cw));
+
+#if 0
+  printf("fpu_cw: %x\n", fpu_cw);
+#endif
+
+  // Set bits 8-9 to 10 (64-bit precision).
+  fpu_cw = (fpu_cw & 0xfcff) | 0x0200;
+
+  // Store the new control word back
+  __asm __volatile ("fldcw %0" : : "m" (fpu_cw));
+}
+#endif
+
index dd036a9..efa178a 100644 (file)
@@ -1,7 +1,6 @@
 /* -----------------------------------------------------------------------------
- * $Id: RtsUtils.h,v 1.21 2004/03/23 10:04:18 simonmar Exp $
  *
- * (c) The GHC Team, 1998-1999
+ * (c) The GHC Team, 1998-2004
  *
  * General utility functions used in the RTS.
  *
index a71f862..82d6add 100644 (file)
@@ -1,5 +1,4 @@
 /* -----------------------------------------------------------------------------
- * $Id: Sanity.c,v 1.34 2003/07/03 15:14:58 sof Exp $
  *
  * (c) The GHC Team, 1998-2001
  *
@@ -26,7 +25,6 @@
 #include "MBlock.h"
 #include "Storage.h"
 #include "Schedule.h"
-#include "StoragePriv.h"   // for END_OF_STATIC_LIST
 #include "Apply.h"
 
 /* -----------------------------------------------------------------------------
@@ -113,21 +111,21 @@ checkStackFrame( StgPtr c )
        dyn = r->liveness;
        
        p = (P_)(r->payload);
-       checkSmallBitmap(p,GET_LIVENESS(r->liveness),RET_DYN_BITMAP_SIZE);
+       checkSmallBitmap(p,RET_DYN_LIVENESS(r->liveness),RET_DYN_BITMAP_SIZE);
        p += RET_DYN_BITMAP_SIZE + RET_DYN_NONPTR_REGS_SIZE;
 
        // skip over the non-pointers
-       p += GET_NONPTRS(dyn);
+       p += RET_DYN_NONPTRS(dyn);
        
        // follow the ptr words
-       for (size = GET_PTRS(dyn); size > 0; size--) {
+       for (size = RET_DYN_PTRS(dyn); size > 0; size--) {
            checkClosureShallow((StgClosure *)*p);
            p++;
        }
        
        return sizeofW(StgRetDyn) + RET_DYN_BITMAP_SIZE +
            RET_DYN_NONPTR_REGS_SIZE +
-           GET_NONPTRS(dyn) + GET_PTRS(dyn);
+           RET_DYN_NONPTRS(dyn) + RET_DYN_PTRS(dyn);
     }
 
     case UPDATE_FRAME:
@@ -165,18 +163,18 @@ checkStackFrame( StgPtr c )
        ret_fun = (StgRetFun *)c;
        fun_info = get_fun_itbl(ret_fun->fun);
        size = ret_fun->size;
-       switch (fun_info->fun_type) {
+       switch (fun_info->f.fun_type) {
        case ARG_GEN:
            checkSmallBitmap((StgPtr)ret_fun->payload, 
-                            BITMAP_BITS(fun_info->bitmap), size);
+                            BITMAP_BITS(fun_info->f.bitmap), size);
            break;
        case ARG_GEN_BIG:
            checkLargeBitmap((StgPtr)ret_fun->payload,
-                            (StgLargeBitmap *)fun_info->bitmap, size);
+                            (StgLargeBitmap *)fun_info->f.bitmap, size);
            break;
        default:
            checkSmallBitmap((StgPtr)ret_fun->payload,
-                            BITMAP_BITS(stg_arg_bitmaps[fun_info->fun_type]),
+                            BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]),
                             size);
            break;
        }
@@ -355,14 +353,14 @@ checkClosure( StgClosure* p )
            fun_info = get_fun_itbl(pap->fun);
 
            p = (StgClosure *)pap->payload;
-           switch (fun_info->fun_type) {
+           switch (fun_info->f.fun_type) {
            case ARG_GEN:
                checkSmallBitmap( (StgPtr)pap->payload, 
-                                 BITMAP_BITS(fun_info->bitmap), pap->n_args );
+                                 BITMAP_BITS(fun_info->f.bitmap), pap->n_args );
                break;
            case ARG_GEN_BIG:
                checkLargeBitmap( (StgPtr)pap->payload, 
-                                 (StgLargeBitmap *)fun_info->bitmap, 
+                                 (StgLargeBitmap *)fun_info->f.bitmap, 
                                  pap->n_args );
                break;
            case ARG_BCO:
@@ -372,7 +370,7 @@ checkClosure( StgClosure* p )
                break;
            default:
                checkSmallBitmap( (StgPtr)pap->payload, 
-                                 BITMAP_BITS(stg_arg_bitmaps[fun_info->fun_type]),
+                                 BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]),
                                  pap->n_args );
                break;
            }
index de3c123..b1b9fda 100644 (file)
@@ -1,7 +1,6 @@
 /* ---------------------------------------------------------------------------
- * $Id: Schedule.c,v 1.199 2004/08/09 14:27:53 simonmar Exp $
  *
- * (c) The GHC Team, 1998-2003
+ * (c) The GHC Team, 1998-2004
  *
  * Scheduler
  *
@@ -42,9 +41,9 @@
 #include "SchedAPI.h"
 #include "RtsUtils.h"
 #include "RtsFlags.h"
+#include "BlockAlloc.h"
 #include "Storage.h"
 #include "StgRun.h"
-#include "StgStartup.h"
 #include "Hooks.h"
 #define COMPILING_SCHEDULER
 #include "Schedule.h"
@@ -59,6 +58,8 @@
 #include "Timer.h"
 #include "Prelude.h"
 #include "ThreadLabels.h"
+#include "LdvProfile.h"
+#include "Updates.h"
 #ifdef PROFILING
 #include "Proftimer.h"
 #include "ProfHeap.h"
@@ -234,6 +235,7 @@ rtsBool emitSchedule = rtsTrue;
 
 #if DEBUG
 static char *whatNext_strs[] = {
+  "(unknown)",
   "ThreadRunGHC",
   "ThreadInterpret",
   "ThreadKilled",
@@ -340,7 +342,7 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
 # endif
 #endif
   rtsBool was_interrupted = rtsFalse;
-  StgTSOWhatNext prev_what_next;
+  nat prev_what_next;
   
   // Pre-condition: sched_mutex is held.
   // We might have a capability, passed in as initialCapability.
@@ -958,12 +960,12 @@ run_thread:
 #endif
 
       // did the task ask for a large block?
-      if (cap->r.rHpAlloc > BLOCK_SIZE_W) {
+      if (cap->r.rHpAlloc > BLOCK_SIZE) {
          // if so, get one and push it on the front of the nursery.
          bdescr *bd;
          nat blocks;
          
-         blocks = (nat)BLOCK_ROUND_UP(cap->r.rHpAlloc * sizeof(W_)) / BLOCK_SIZE;
+         blocks = (nat)BLOCK_ROUND_UP(cap->r.rHpAlloc) / BLOCK_SIZE;
 
          IF_DEBUG(scheduler,belch("--<< thread %ld (%s) stopped: requesting a large block (size %d)", 
                                   t->id, whatNext_strs[t->what_next], blocks));
@@ -1522,12 +1524,7 @@ deleteAllThreads ( void )
  * ------------------------------------------------------------------------- */
    
 StgInt
-suspendThread( StgRegTable *reg, 
-              rtsBool concCall
-#if !defined(DEBUG)
-              STG_UNUSED
-#endif
-              )
+suspendThread( StgRegTable *reg )
 {
   nat tok;
   Capability *cap;
@@ -1541,7 +1538,7 @@ suspendThread( StgRegTable *reg,
   ACQUIRE_LOCK(&sched_mutex);
 
   IF_DEBUG(scheduler,
-          sched_belch("thread %d did a _ccall_gc (is_concurrent: %d)", cap->r.rCurrentTSO->id,concCall));
+          sched_belch("thread %d did a _ccall_gc", cap->r.rCurrentTSO->id));
 
   // XXX this might not be necessary --SDM
   cap->r.rCurrentTSO->what_next = ThreadRunGHC;
@@ -1579,8 +1576,7 @@ suspendThread( StgRegTable *reg,
 }
 
 StgRegTable *
-resumeThread( StgInt tok,
-             rtsBool concCall STG_UNUSED )
+resumeThread( StgInt tok )
 {
   StgTSO *tso, **prev;
   Capability *cap;
@@ -3144,7 +3140,8 @@ raiseAsync(StgTSO *tso, StgClosure *exception)
            //
            if (!closure_IND(((StgUpdateFrame *)frame)->updatee)) {
                // revert the black hole
-               UPD_IND_NOLOCK(((StgUpdateFrame *)frame)->updatee,ap);
+               UPD_IND_NOLOCK(((StgUpdateFrame *)frame)->updatee,
+                              (StgClosure *)ap);
            }
            sp += sizeofW(StgUpdateFrame) - 1;
            sp[0] = (W_)ap; // push onto stack
@@ -3166,6 +3163,77 @@ raiseAsync(StgTSO *tso, StgClosure *exception)
 }
 
 /* -----------------------------------------------------------------------------
+   raiseExceptionHelper
+   
+   This function is called by the raise# primitve, just so that we can
+   move some of the tricky bits of raising an exception from C-- into
+   C.  Who knows, it might be a useful re-useable thing here too.
+   -------------------------------------------------------------------------- */
+
+StgWord
+raiseExceptionHelper (StgTSO *tso, StgClosure *exception)
+{
+    StgClosure *raise_closure = NULL;
+    StgPtr p, next;
+    StgRetInfoTable *info;
+    //
+    // This closure represents the expression 'raise# E' where E
+    // is the exception raise.  It is used to overwrite all the
+    // thunks which are currently under evaluataion.
+    //
+
+    //    
+    // LDV profiling: stg_raise_info has THUNK as its closure
+    // type. Since a THUNK takes at least MIN_UPD_SIZE words in its
+    // payload, MIN_UPD_SIZE is more approprate than 1.  It seems that
+    // 1 does not cause any problem unless profiling is performed.
+    // However, when LDV profiling goes on, we need to linearly scan
+    // small object pool, where raise_closure is stored, so we should
+    // use MIN_UPD_SIZE.
+    //
+    // raise_closure = (StgClosure *)RET_STGCALL1(P_,allocate,
+    //                                        sizeofW(StgClosure)+1);
+    //
+
+    //
+    // Walk up the stack, looking for the catch frame.  On the way,
+    // we update any closures pointed to from update frames with the
+    // raise closure that we just built.
+    //
+    p = tso->sp;
+    while(1) {
+       info = get_ret_itbl((StgClosure *)p);
+       next = p + stack_frame_sizeW((StgClosure *)p);
+       switch (info->i.type) {
+           
+       case UPDATE_FRAME:
+           // Only create raise_closure if we need to.
+           if (raise_closure == NULL) {
+               raise_closure = 
+                   (StgClosure *)allocate(sizeofW(StgClosure)+MIN_UPD_SIZE);
+               SET_HDR(raise_closure, &stg_raise_info, CCCS);
+               raise_closure->payload[0] = exception;
+           }
+           UPD_IND(((StgUpdateFrame *)p)->updatee,raise_closure);
+           p = next;
+           continue;
+           
+       case CATCH_FRAME:
+           tso->sp = p;
+           return CATCH_FRAME;
+           
+       case STOP_FRAME:
+           tso->sp = p;
+           return STOP_FRAME;
+
+       default:
+           p = next; 
+           continue;
+       }
+    }
+}
+
+/* -----------------------------------------------------------------------------
    resurrectThreads is called after garbage collection on the list of
    threads found to be garbage.  Each of these threads will be woken
    up and sent a signal: BlockedOnDeadMVar if the thread was blocked
index dc3763d..588ddc5 100644 (file)
@@ -1,5 +1,4 @@
 /* -----------------------------------------------------------------------------
- * $Id: Schedule.h,v 1.45 2004/03/01 14:18:36 simonmar Exp $
  *
  * (c) The GHC Team 1998-1999
  *
@@ -61,6 +60,9 @@ StgTSO *unblockOne(StgTSO *tso);
 void raiseAsync(StgTSO *tso, StgClosure *exception);
 void raiseAsyncWithLock(StgTSO *tso, StgClosure *exception);
 
+/* raiseExceptionHelper */
+StgWord raiseExceptionHelper (StgTSO *tso, StgClosure *exception);
+
 /* awaitEvent(rtsBool wait)
  *
  * Checks for blocked threads that need to be woken.
@@ -125,11 +127,11 @@ void    initThread(StgTSO *tso, nat stack_size);
 /* Context switch flag.
  * Locks required  : sched_mutex
  */
-extern nat context_switch;
-extern rtsBool interrupted;
+extern nat RTS_VAR(context_switch);
+extern rtsBool RTS_VAR(interrupted);
 
 /* In Select.c */
-extern nat timestamp;
+extern nat RTS_VAR(timestamp);
 
 /* Thread queues.
  * Locks required  : sched_mutex
@@ -139,19 +141,19 @@ extern nat timestamp;
 #if defined(GRAN)
 // run_queue_hds defined in GranSim.h
 #else
-extern  StgTSO *run_queue_hd, *run_queue_tl;
-extern  StgTSO *blocked_queue_hd, *blocked_queue_tl;
-extern  StgTSO *sleeping_queue;
+extern  StgTSO *RTS_VAR(run_queue_hd), *RTS_VAR(run_queue_tl);
+extern  StgTSO *RTS_VAR(blocked_queue_hd), *RTS_VAR(blocked_queue_tl);
+extern  StgTSO *RTS_VAR(sleeping_queue);
 #endif
 /* Linked list of all threads. */
-extern  StgTSO *all_threads;
+extern  StgTSO *RTS_VAR(all_threads);
 
 #if defined(RTS_SUPPORTS_THREADS)
 /* Schedule.c has detailed info on what these do */
-extern Mutex       sched_mutex;
-extern Condition   returning_worker_cond;
-extern nat         rts_n_waiting_workers;
-extern nat         rts_n_waiting_tasks;
+extern Mutex       RTS_VAR(sched_mutex);
+extern Condition   RTS_VAR(returning_worker_cond);
+extern nat         RTS_VAR(rts_n_waiting_workers);
+extern nat         RTS_VAR(rts_n_waiting_tasks);
 #endif
 
 StgBool rtsSupportsBoundThreads(void);
index ced711f..4d76b11 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Signals.c,v 1.40 2003/10/31 23:24:47 sof Exp $
+ * $Id: Signals.c,v 1.41 2004/08/13 13:10:44 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -16,7 +16,6 @@
 #include "Signals.h"
 #include "RtsUtils.h"
 #include "RtsFlags.h"
-#include "StablePriv.h"
 
 #ifdef alpha_TARGET_ARCH
 # if defined(linux_TARGET_OS)
index c047469..c0520da 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Stable.c,v 1.27 2003/11/12 17:49:11 sof Exp $
+ * $Id: Stable.c,v 1.28 2004/08/13 13:10:45 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2002
  *
@@ -13,7 +13,6 @@
 #include "PosixSource.h"
 #include "Rts.h"
 #include "Hash.h"
-#include "StablePriv.h"
 #include "RtsUtils.h"
 #include "Storage.h"
 #include "RtsAPI.h"
diff --git a/ghc/rts/StablePriv.h b/ghc/rts/StablePriv.h
deleted file mode 100644 (file)
index 05a50bc..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: StablePriv.h,v 1.3 2001/07/23 17:23:20 simonmar Exp $
- *
- * (c) The GHC Team, 1998-1999
- *
- * Internal RTS API for stable names and stable ptrs.
- *
- * ---------------------------------------------------------------------------*/
-
-extern void    initStablePtrTable    ( void );
-extern void    enlargeStablePtrTable ( void );
-extern StgWord lookupStableName      ( StgPtr p );
-
-extern void    markStablePtrTable    ( evac_fn evac );
-extern void    threadStablePtrTable  ( evac_fn evac );
-extern void    gcStablePtrTable      ( void );
-extern void    updateStablePtrTable  ( rtsBool full );
index 8e79801..4920b4b 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Stats.c,v 1.47 2004/05/27 09:29:28 simonmar Exp $
+ * $Id: Stats.c,v 1.48 2004/08/13 13:10:45 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
 #include "Rts.h"
 #include "RtsFlags.h"
 #include "RtsUtils.h"
-#include "StoragePriv.h"
 #include "MBlock.h"
 #include "Schedule.h"
 #include "Stats.h"
 #include "ParTicky.h"                       /* ToDo: move into Rts.h */
 #include "Profiling.h"
+#include "Storage.h"
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
index 8efa48f..b1d8b5a 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: StgCRun.c,v 1.41 2003/12/10 11:35:26 wolfgang Exp $
+ * $Id: StgCRun.c,v 1.42 2004/08/13 13:10:46 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2003
  *
@@ -50,7 +50,7 @@
  * that we don't use but which are callee-save registers.  The __divq() routine
  * in libc.a clobbers $s6.
  */
-#include "config.h"
+#include "ghcconfig.h"
 #ifdef alpha_TARGET_ARCH
 #define alpha_EXTRA_CAREFUL
 register long   fake_ra __asm__("$26");
@@ -68,9 +68,10 @@ register double fake_f9 __asm__("$f9");
 #include "Stg.h"
 #include "Rts.h"
 #include "StgRun.h"
+#include "RtsFlags.h"
+#include "Capability.h"
 
 #ifdef DEBUG
-#include "RtsFlags.h"
 #include "RtsUtils.h"
 #include "Printer.h"
 #endif
@@ -81,22 +82,22 @@ register double fake_f9 __asm__("$f9");
    any architecture (using miniinterpreter)
    -------------------------------------------------------------------------- */
 
-extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg STG_UNUSED)
+StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg STG_UNUSED)
 {
-   while (f) {
-      IF_DEBUG(interpreter,
-              fprintf(stderr,"Jumping to ");
-              printPtr((P_)f); fflush(stdout);
-              fprintf(stderr,"\n");
-             );
-      f = (StgFunPtr) (f)();
-   }
-   return (StgThreadReturnCode)R1.i;
+    while (f) {
+       if (RtsFlags[0].DebugFlags.interpreter) {
+           fprintf(stderr,"Jumping to ");
+           printPtr((P_)f); fflush(stdout);
+           fprintf(stderr,"\n");
+       }
+       f = (StgFunPtr) (f)();
+    }
+    return (StgThreadReturnCode)R1.i;
 }
 
-EXTFUN(StgReturn)
+StgFunPtr StgReturn(void)
 {
-   return 0;
+    return 0;
 }
 
 #else /* !USE_MINIINTERPRETER */
@@ -540,6 +541,7 @@ static void StgRunIsImplementedInAssembler(void)
                "\tbl saveFP # f14\n"
                "\tstmw r13,-220(r1)\n"
                "\tstwu r1,-%0(r1)\n"
+                "\tmr r27,r4\n" // BaseReg == r27
                "\tmtctr r3\n"
                "\tmr r12,r3\n"
                "\tbctr\n"
@@ -592,6 +594,7 @@ static void StgRunIsImplementedInAssembler(void)
                "\tstfd 29,-24(5)\n"
                "\tstfd 30,-16(5)\n"
                "\tstfd 31,-8(5)\n"
+               "\tmr 27,4\n"  // BaseReg == r27
                "\tmtctr 3\n"
                "\tmr 12,3\n"
                "\tbctr\n"
diff --git a/ghc/rts/StgMiscClosures.cmm b/ghc/rts/StgMiscClosures.cmm
new file mode 100644 (file)
index 0000000..78eef91
--- /dev/null
@@ -0,0 +1,984 @@
+/* ----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2004
+ *
+ * Entry code for various built-in closure types.
+ *
+ * This file is written in a subset of C--, extended with various
+ * features specific to GHC.  It is compiled by GHC directly.  For the
+ * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
+ *
+ * --------------------------------------------------------------------------*/
+
+#include "Cmm.h"
+
+/* ----------------------------------------------------------------------------
+   Support for the bytecode interpreter.
+   ------------------------------------------------------------------------- */
+
+/* 9 bits of return code for constructors created by the interpreter. */
+stg_interp_constr_entry
+{ 
+    /* R1 points at the constructor */
+    jump %ENTRY_CODE(Sp(0));
+}
+
+stg_interp_constr1_entry { jump %RET_VEC(Sp(0),0); }
+stg_interp_constr2_entry { jump %RET_VEC(Sp(0),1); }
+stg_interp_constr3_entry { jump %RET_VEC(Sp(0),2); }
+stg_interp_constr4_entry { jump %RET_VEC(Sp(0),3); }
+stg_interp_constr5_entry { jump %RET_VEC(Sp(0),4); }
+stg_interp_constr6_entry { jump %RET_VEC(Sp(0),5); }
+stg_interp_constr7_entry { jump %RET_VEC(Sp(0),6); }
+stg_interp_constr8_entry { jump %RET_VEC(Sp(0),7); }
+
+/* Some info tables to be used when compiled code returns a value to
+   the interpreter, i.e. the interpreter pushes one of these onto the
+   stack before entering a value.  What the code does is to
+   impedance-match the compiled return convention (in R1p/R1n/F1/D1 etc) to
+   the interpreter's convention (returned value is on top of stack),
+   and then cause the scheduler to enter the interpreter.
+
+   On entry, the stack (growing down) looks like this:
+
+      ptr to BCO holding return continuation
+      ptr to one of these info tables.
+   The info table code, both direct and vectored, must:
+      * push R1/F1/D1 on the stack, and its tag if necessary
+      * push the BCO (so it's now on the stack twice)
+      * Yield, ie, go to the scheduler.
+
+   Scheduler examines the t.o.s, discovers it is a BCO, and proceeds
+   directly to the bytecode interpreter.  That pops the top element
+   (the BCO, containing the return continuation), and interprets it.
+   Net result: return continuation gets interpreted, with the
+   following stack:
+
+      ptr to this BCO
+      ptr to the info table just jumped thru
+      return value
+
+   which is just what we want -- the "standard" return layout for the
+   interpreter.  Hurrah!
+
+   Don't ask me how unboxed tuple returns are supposed to work.  We
+   haven't got a good story about that yet.
+*/
+
+INFO_TABLE_RET( stg_ctoi_R1p, 
+               0/*size*/, 0/*bitmap*/,    /* special layout! */
+               RET_BCO,
+               RET_LBL(stg_ctoi_R1p),
+               RET_LBL(stg_ctoi_R1p),
+               RET_LBL(stg_ctoi_R1p),
+               RET_LBL(stg_ctoi_R1p),
+               RET_LBL(stg_ctoi_R1p),
+               RET_LBL(stg_ctoi_R1p),
+               RET_LBL(stg_ctoi_R1p),
+               RET_LBL(stg_ctoi_R1p))
+{
+    Sp_adj(-2);
+    Sp(1) = R1;
+    Sp(0) = stg_enter_info;
+    jump stg_yield_to_interpreter;
+}
+
+#if MAX_VECTORED_RTN != 8
+#error MAX_VECTORED_RTN has changed: please modify stg_ctoi_R1p too.
+#endif
+
+/*
+ * When the returned value is a pointer, but unlifted, in R1 ... 
+ */
+INFO_TABLE_RET( stg_ctoi_R1unpt,
+               0/*size*/, 0/*bitmap*/,    /* special layout! */
+               RET_BCO )
+{
+    Sp_adj(-2);
+    Sp(1) = R1;
+    Sp(0) = stg_gc_unpt_r1_info;
+    jump stg_yield_to_interpreter;
+}
+
+/*
+ * When the returned value is a non-pointer in R1 ...
+ */
+INFO_TABLE_RET( stg_ctoi_R1n,
+               0/*size*/, 0/*bitmap*/,    /* special layout! */
+               RET_BCO )
+{
+    Sp_adj(-2);
+    Sp(1) = R1;
+    Sp(0) = stg_gc_unbx_r1_info;
+    jump stg_yield_to_interpreter;
+}
+
+/*
+ * When the returned value is in F1
+ */
+INFO_TABLE_RET( stg_ctoi_F1,
+               0/*size*/, 0/*bitmap*/,    /* special layout! */
+               RET_BCO )
+{
+    Sp_adj(-2);
+    F_[Sp + WDS(1)] = F1;
+    Sp(0) = stg_gc_f1_info;
+    jump stg_yield_to_interpreter;
+}
+
+/*
+ * When the returned value is in D1
+ */
+INFO_TABLE_RET( stg_ctoi_D1,
+               0/*size*/, 0/*bitmap*/,    /* special layout! */
+               RET_BCO )
+{
+    Sp_adj(-1) - SIZEOF_DOUBLE;
+    D_[Sp + WDS(1)] = D1;
+    Sp(0) = stg_gc_d1_info;
+    jump stg_yield_to_interpreter;
+}
+
+/*
+ * When the returned value is in L1
+ */
+INFO_TABLE_RET( stg_ctoi_L1,
+               0/*size*/, 0/*bitmap*/,    /* special layout! */
+               RET_BCO )
+{
+    Sp_adj(-1) - 8;
+    L_[Sp + WDS(1)] = L1;
+    Sp(0) = stg_gc_l1_info;
+    jump stg_yield_to_interpreter;
+}
+
+/*
+ * When the returned value is a void
+ */
+INFO_TABLE_RET( stg_ctoi_V,
+               0/*size*/, 0/*bitmap*/,    /* special layout! */
+               RET_BCO )
+{
+    Sp_adj(-1);
+    Sp(0) = stg_gc_void_info;
+    jump stg_yield_to_interpreter;
+}
+
+/*
+ * Dummy info table pushed on the top of the stack when the interpreter
+ * should apply the BCO on the stack to its arguments, also on the
+ * stack.
+ */
+INFO_TABLE_RET( stg_apply_interp,
+               0/*size*/, 0/*bitmap*/,    /* special layout! */
+               RET_BCO )
+{
+    /* Just in case we end up in here... (we shouldn't) */
+    jump stg_yield_to_interpreter;
+}
+
+/* ----------------------------------------------------------------------------
+   Entry code for a BCO
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE_FUN( stg_BCO, 4, 0, BCO, "BCO", "BCO", ARG_BCO )
+{
+  /* entering a BCO means "apply it", same as a function */
+  Sp_adj(-2);
+  Sp(1) = R1;
+  Sp(0) = stg_apply_interp_info;
+  jump stg_yield_to_interpreter;
+}
+
+/* ----------------------------------------------------------------------------
+   Info tables for indirections.
+
+   SPECIALISED INDIRECTIONS: we have a specialised indirection for each
+   kind of return (direct, vectored 0-7), so that we can avoid entering
+   the object when we know what kind of return it will do.  The update
+   code (Updates.hc) updates objects with the appropriate kind of
+   indirection.  We only do this for young-gen indirections.
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_IND,1,0,IND,"IND","IND")
+{
+    TICK_ENT_DYN_IND();        /* tick */
+    R1 = StgInd_indirectee(R1);
+    TICK_ENT_VIA_NODE();
+    jump %GET_ENTRY(R1);
+}
+
+#define IND_SPEC(label,ret) \
+INFO_TABLE(label,1,0,IND,"IND","IND") \
+{                                              \
+    TICK_ENT_DYN_IND();        /* tick */              \
+    R1 = StgInd_indirectee(R1);                        \
+    TICK_ENT_VIA_NODE();                       \
+    jump ret;                                  \
+}
+
+IND_SPEC(stg_IND_direct, %ENTRY_CODE(Sp(0)))
+IND_SPEC(stg_IND_0, %RET_VEC(Sp(0),0))
+IND_SPEC(stg_IND_1, %RET_VEC(Sp(0),1))
+IND_SPEC(stg_IND_2, %RET_VEC(Sp(0),2))
+IND_SPEC(stg_IND_3, %RET_VEC(Sp(0),3))
+IND_SPEC(stg_IND_4, %RET_VEC(Sp(0),4))
+IND_SPEC(stg_IND_5, %RET_VEC(Sp(0),5))
+IND_SPEC(stg_IND_6, %RET_VEC(Sp(0),6))
+IND_SPEC(stg_IND_7, %RET_VEC(Sp(0),7))
+
+INFO_TABLE(stg_IND_STATIC,1,0,IND_STATIC,"IND_STATIC","IND_STATIC")
+{
+    TICK_ENT_STATIC_IND();     /* tick */
+    R1 = StgInd_indirectee(R1);
+    TICK_ENT_VIA_NODE();
+    jump %GET_ENTRY(R1);
+}
+
+INFO_TABLE(stg_IND_PERM,1,1,IND_PERM,"IND_PERM","IND_PERM")
+{
+    /* Don't add INDs to granularity cost */
+
+    /* Don't: TICK_ENT_STATIC_IND(Node); for ticky-ticky; this ind is
+       here only to help profiling */
+
+#if defined(TICKY_TICKY) && !defined(PROFILING)
+    /* TICKY_TICKY && !PROFILING means PERM_IND *replaces* an IND, rather than
+       being extra  */
+    TICK_ENT_PERM_IND();
+#endif
+
+    LDV_ENTER(R1);
+
+    /* Enter PAP cost centre */
+    ENTER_CCS_PAP_CL(R1);
+
+    /* For ticky-ticky, change the perm_ind to a normal ind on first
+     * entry, so the number of ent_perm_inds is the number of *thunks*
+     * entered again, not the number of subsequent entries.
+     *
+     * Since this screws up cost centres, we die if profiling and
+     * ticky_ticky are on at the same time.  KSW 1999-01.
+     */
+#ifdef TICKY_TICKY
+#  ifdef PROFILING
+#    error Profiling and ticky-ticky do not mix at present!
+#  endif  /* PROFILING */
+    StgHeader_info(R1) = stg_IND_info;
+#endif /* TICKY_TICKY */
+
+    R1 = StgInd_indirectee(R1);
+
+#if defined(TICKY_TICKY) && !defined(PROFILING)
+    TICK_ENT_VIA_NODE();
+#endif
+
+    jump %GET_ENTRY(R1);
+}  
+
+
+INFO_TABLE(stg_IND_OLDGEN,1,1,IND_OLDGEN,"IND_OLDGEN","IND_OLDGEN")
+{
+    TICK_ENT_STATIC_IND();     /* tick */
+    R1 = StgInd_indirectee(R1);
+    TICK_ENT_VIA_NODE();
+    jump %GET_ENTRY(R1);
+}
+
+INFO_TABLE(stg_IND_OLDGEN_PERM,1,1,IND_OLDGEN_PERM,"IND_OLDGEN_PERM","IND_OLDGEN_PERM")
+{
+    /* Don't: TICK_ENT_STATIC_IND(Node); for ticky-ticky; 
+       this ind is here only to help profiling */
+
+#if defined(TICKY_TICKY) && !defined(PROFILING)
+    /* TICKY_TICKY && !PROFILING means PERM_IND *replaces* an IND, 
+       rather than being extra  */
+    TICK_ENT_PERM_IND(R1); /* tick */
+#endif
+
+    LDV_ENTER(R1);
+
+    /* Enter PAP cost centre -- lexical scoping only */
+    ENTER_CCS_PAP_CL(R1);
+
+    /* see comment in IND_PERM */
+#ifdef TICKY_TICKY
+#  ifdef PROFILING
+#    error Profiling and ticky-ticky do not mix at present!
+#  endif  /* PROFILING */
+    StgHeader_info(R1) = stg_IND_OLDGEN_info;
+#endif /* TICKY_TICKY */
+
+    R1 = StgInd_indirectee(R1);
+
+    TICK_ENT_VIA_NODE();
+    jump %GET_ENTRY(R1);
+}
+
+/* ----------------------------------------------------------------------------
+   Black holes.
+
+   Entering a black hole normally causes a cyclic data dependency, but
+   in the concurrent world, black holes are synchronization points,
+   and they are turned into blocking queues when there are threads
+   waiting for the evaluation of the closure to finish.
+   ------------------------------------------------------------------------- */
+
+/* Note: a BLACKHOLE and BLACKHOLE_BQ must be big enough to be
+ * overwritten with an indirection/evacuee/catch.  Thus we claim it
+ * has 1 non-pointer word of payload (in addition to the pointer word
+ * for the blocking queue in a BQ), which should be big enough for an
+ * old-generation indirection. 
+ */
+INFO_TABLE(stg_BLACKHOLE,0,2,BLACKHOLE,"BLACKHOLE","BLACKHOLE")
+{
+#if defined(GRAN)
+    /* Before overwriting TSO_LINK */
+    STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1 /*Node*/);
+#endif
+
+    TICK_ENT_BH();
+
+    /* Actually this is not necessary because R1 is about to be destroyed. */
+    LDV_ENTER(R1);
+
+    /* Put ourselves on the blocking queue for this black hole */
+    StgTSO_link(CurrentTSO) = stg_END_TSO_QUEUE_closure;
+    StgBlockingQueue_blocking_queue(R1) = CurrentTSO;
+
+    /* jot down why and on what closure we are blocked */
+    StgTSO_why_blocked(CurrentTSO) = BlockedOnBlackHole::I16;
+    StgTSO_block_info(CurrentTSO) = R1;
+
+    /* Change the BLACKHOLE into a BLACKHOLE_BQ */
+#ifdef PROFILING
+    /* The size remains the same, so we call LDV_recordDead() - 
+       no need to fill slop. */
+    foreign "C" LDV_recordDead(R1 "ptr", BYTES_TO_WDS(SIZEOF_StgBlockingQueue));
+#endif
+    /*
+     * Todo: maybe use SET_HDR() and remove LDV_RECORD_CREATE()?
+     */ 
+    StgHeader_info(R1) = stg_BLACKHOLE_BQ_info;
+#ifdef PROFILING
+    foreign "C" LDV_RECORD_CREATE(R1);
+#endif
+
+    /* closure is mutable since something has just been added to its BQ */
+    foreign "C" recordMutable(R1 "ptr");
+
+    /* PAR: dumping of event now done in blockThread -- HWL */
+
+    /* stg_gen_block is too heavyweight, use a specialised one */
+    jump stg_block_1;
+}
+
+INFO_TABLE(stg_BLACKHOLE_BQ,1,1,BLACKHOLE_BQ,"BLACKHOLE_BQ","BLACKHOLE_BQ")
+{
+#if defined(GRAN)
+    /* Before overwriting TSO_LINK */
+    STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1 /*Node*/);
+#endif
+
+    TICK_ENT_BH();
+    LDV_ENTER(R1);
+
+    /* Put ourselves on the blocking queue for this black hole */
+    StgTSO_link(CurrentTSO) = StgBlockingQueue_blocking_queue(R1);
+    StgBlockingQueue_blocking_queue(R1) = CurrentTSO;
+
+    /* jot down why and on what closure we are blocked */
+    StgTSO_why_blocked(CurrentTSO) = BlockedOnBlackHole::I16;
+    StgTSO_block_info(CurrentTSO) = R1;
+
+    /* PAR: dumping of event now done in blockThread -- HWL */
+
+    /* stg_gen_block is too heavyweight, use a specialised one */
+    jump stg_block_1;
+}
+
+/*
+   Revertible black holes are needed in the parallel world, to handle
+   negative acknowledgements of messages containing updatable closures.
+   The idea is that when the original message is transmitted, the closure
+   is turned into a revertible black hole...an object which acts like a
+   black hole when local threads try to enter it, but which can be reverted
+   back to the original closure if necessary.
+
+   It's actually a lot like a blocking queue (BQ) entry, because revertible
+   black holes are initially set up with an empty blocking queue.
+*/
+
+#if defined(PAR) || defined(GRAN)
+
+INFO_TABLE(stg_RBH,1,1,RBH,"RBH","RBH")
+{
+# if defined(GRAN)
+    /* mainly statistics gathering for GranSim simulation */
+    STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1 /*Node*/);
+# endif
+
+    /* exactly the same as a BLACKHOLE_BQ_entry -- HWL */
+    /* Put ourselves on the blocking queue for this black hole */
+    TSO_link(CurrentTSO) = StgBlockingQueue_blocking_queue(R1);
+    StgBlockingQueue_blocking_queue(R1) = CurrentTSO;
+    /* jot down why and on what closure we are blocked */
+    TSO_why_blocked(CurrentTSO) = BlockedOnBlackHole::I16;
+    TSO_block_info(CurrentTSO) = R1;
+
+    /* PAR: dumping of event now done in blockThread -- HWL */
+
+    /* stg_gen_block is too heavyweight, use a specialised one */
+    jump stg_block_1;
+}
+
+INFO_TABLE(stg_RBH_Save_0,0,2,CONSTR,"RBH_Save_0","RBH_Save_0")
+{ foreign "C" barf("RBH_Save_0 object entered!"); }
+
+INFO_TABLE(stg_RBH_Save_1,1,1,CONSTR,"RBH_Save_1","RBH_Save_1");
+{ foreign "C" barf("RBH_Save_1 object entered!"); }
+
+INFO_TABLE(stg_RBH_Save_2,2,0,CONSTR,"RBH_Save_2","RBH_Save_2");
+{ foreign "C" barf("RBH_Save_2 object entered!"); }
+
+#endif /* defined(PAR) || defined(GRAN) */
+
+/* identical to BLACKHOLEs except for the infotag */
+INFO_TABLE(stg_CAF_BLACKHOLE,0,2,CAF_BLACKHOLE,"CAF_BLACKHOLE","CAF_BLACKHOLE")
+{
+#if defined(GRAN)
+    /* mainly statistics gathering for GranSim simulation */
+    STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1 /*Node*/);
+#endif
+
+    TICK_ENT_BH();
+    LDV_ENTER(R1);
+
+    /* Put ourselves on the blocking queue for this black hole */
+    StgTSO_link(CurrentTSO) = stg_END_TSO_QUEUE_closure;
+    StgBlockingQueue_blocking_queue(R1) = CurrentTSO;
+
+    /* jot down why and on what closure we are blocked */
+    StgTSO_why_blocked(CurrentTSO) = BlockedOnBlackHole::I16;
+    StgTSO_block_info(CurrentTSO) = R1;
+
+    /* Change the CAF_BLACKHOLE into a BLACKHOLE_BQ_STATIC */
+    StgHeader_info(R1) = stg_BLACKHOLE_BQ_info;
+
+    /* closure is mutable since something has just been added to its BQ */
+    foreign "C" recordMutable(R1 "ptr");
+
+    /* PAR: dumping of event now done in blockThread -- HWL */
+
+    /* stg_gen_block is too heavyweight, use a specialised one */
+    jump stg_block_1;
+}
+
+#ifdef EAGER_BLACKHOLING
+INFO_TABLE(stg_SE_BLACKHOLE_info, stg_SE_BLACKHOLE_entry,0,2,SE_BLACKHOLE,,IF_,"SE_BLACKHOLE","SE_BLACKHOLE");
+IF_(stg_SE_BLACKHOLE_entry)
+{
+    STGCALL3(fprintf,stderr,"SE_BLACKHOLE at %p entered!\n",R1);
+    STGCALL1(shutdownHaskellAndExit,EXIT_FAILURE);
+}
+
+INFO_TABLE(stg_SE_CAF_BLACKHOLE_info, SE_CAF_BLACKHOLE_entry,0,2,SE_CAF_BLACKHOLE,,IF_,"CAF_BLACKHOLE","CAF_BLACKHOLE");
+IF_(stg_SE_CAF_BLACKHOLE_entry)
+{
+    STGCALL3(fprintf,stderr,"SE_CAF_BLACKHOLE at %p entered!\n",R1);
+    STGCALL1(shutdownHaskellAndExit,EXIT_FAILURE);
+}
+#endif
+
+/* ----------------------------------------------------------------------------
+   Some static info tables for things that don't get entered, and
+   therefore don't need entry code (i.e. boxed but unpointed objects)
+   NON_ENTERABLE_ENTRY_CODE now defined at the beginning of the file
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_TSO, 0,0,TSO, "TSO", "TSO")
+{ foreign "C" barf("TSO object entered!"); }
+
+/* ----------------------------------------------------------------------------
+   Evacuees are left behind by the garbage collector.  Any attempt to enter
+   one is a real bug.
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_EVACUATED,1,0,EVACUATED,"EVACUATED","EVACUATED")
+{ foreign "C" barf("EVACUATED object entered!"); }
+
+/* ----------------------------------------------------------------------------
+   Weak pointers
+
+   Live weak pointers have a special closure type.  Dead ones are just
+   nullary constructors (although they live on the heap - we overwrite
+   live weak pointers with dead ones).
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_WEAK,0,4,WEAK,"WEAK","WEAK")
+{ foreign "C" barf("WEAK object entered!"); }
+
+/*
+ * It's important when turning an existing WEAK into a DEAD_WEAK
+ * (which is what finalizeWeak# does) that we don't lose the link
+ * field and break the linked list of weak pointers.  Hence, we give
+ * DEAD_WEAK 4 non-pointer fields, the same as WEAK.
+ */
+INFO_TABLE_CONSTR(stg_DEAD_WEAK,0,4,0,CONSTR,"DEAD_WEAK","DEAD_WEAK")
+{ foreign "C" barf("DEAD_WEAK object entered!"); }
+
+/* ----------------------------------------------------------------------------
+   NO_FINALIZER
+
+   This is a static nullary constructor (like []) that we use to mark an empty
+   finalizer in a weak pointer object.
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE_CONSTR(stg_NO_FINALIZER,0,0,0,CONSTR_NOCAF_STATIC,"NO_FINALIZER","NO_FINALIZER")
+{ foreign "C" barf("NO_FINALIZER object entered!"); }
+
+CLOSURE(stg_NO_FINALIZER_closure,stg_NO_FINALIZER);
+
+/* ----------------------------------------------------------------------------
+   Foreign Objects are unlifted and therefore never entered.
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_FOREIGN,0,1,FOREIGN,"FOREIGN","FOREIGN")
+{ foreign "C" barf("FOREIGN object entered!"); }
+
+/* ----------------------------------------------------------------------------
+   Stable Names are unlifted too.
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_STABLE_NAME,0,1,STABLE_NAME,"STABLE_NAME","STABLE_NAME")
+{ foreign "C" barf("STABLE_NAME object entered!"); }
+
+/* ----------------------------------------------------------------------------
+   MVars
+
+   There are two kinds of these: full and empty.  We need an info table
+   and entry code for each type.
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_FULL_MVAR,4,0,MVAR,"MVAR","MVAR")
+{ foreign "C" barf("FULL_MVAR object entered!"); }
+
+INFO_TABLE(stg_EMPTY_MVAR,4,0,MVAR,"MVAR","MVAR")
+{ foreign "C" barf("EMPTY_MVAR object entered!"); }
+
+/* ----------------------------------------------------------------------------
+   END_TSO_QUEUE
+
+   This is a static nullary constructor (like []) that we use to mark the
+   end of a linked TSO queue.
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE_CONSTR(stg_END_TSO_QUEUE,0,0,0,CONSTR_NOCAF_STATIC,"END_TSO_QUEUE","END_TSO_QUEUE")
+{ foreign "C" barf("END_TSO_QUEUE object entered!"); }
+
+CLOSURE(stg_END_TSO_QUEUE_closure,stg_END_TSO_QUEUE);
+
+/* ----------------------------------------------------------------------------
+   Mutable lists
+
+   Mutable lists (used by the garbage collector) consist of a chain of
+   StgMutClosures connected through their mut_link fields, ending in
+   an END_MUT_LIST closure.
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE_CONSTR(stg_END_MUT_LIST,0,0,0,CONSTR_NOCAF_STATIC,"END_MUT_LIST","END_MUT_LIST")
+{ foreign "C" barf("END_MUT_LIST object entered!"); }
+
+CLOSURE(stg_END_MUT_LIST_closure,stg_END_MUT_LIST);
+
+INFO_TABLE(stg_MUT_CONS, 1, 1, MUT_CONS, "MUT_CONS", "MUT_CONS")
+{ foreign "C" barf("MUT_CONS object entered!"); }
+
+/* ----------------------------------------------------------------------------
+   Exception lists
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE_CONSTR(stg_END_EXCEPTION_LIST,0,0,0,CONSTR_NOCAF_STATIC,"END_EXCEPTION_LIST","END_EXCEPTION_LIST")
+{ foreign "C" barf("END_EXCEPTION_LIST object entered!"); }
+
+CLOSURE(stg_END_EXCEPTION_LIST_closure,stg_END_EXCEPTION_LIST);
+
+INFO_TABLE(stg_EXCEPTION_CONS,1,1,CONSTR,"EXCEPTION_CONS","EXCEPTION_CONS")
+{ foreign "C" barf("EXCEPTION_CONS object entered!"); }
+
+/* ----------------------------------------------------------------------------
+   Arrays
+
+   These come in two basic flavours: arrays of data (StgArrWords) and arrays of
+   pointers (StgArrPtrs).  They all have a similar layout:
+
+       ___________________________
+       | Info | No. of | data....
+        |  Ptr | Words  |
+       ---------------------------
+
+   These are *unpointed* objects: i.e. they cannot be entered.
+
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_ARR_WORDS, 0, 0, ARR_WORDS, "ARR_WORDS", "ARR_WORDS")
+{ foreign "C" barf("ARR_WORDS object entered!"); }
+
+INFO_TABLE(stg_MUT_ARR_PTRS, 0, 0, MUT_ARR_PTRS, "MUT_ARR_PTRS", "MUT_ARR_PTRS")
+{ foreign "C" barf("MUT_ARR_PTRS object entered!"); }
+
+INFO_TABLE(stg_MUT_ARR_PTRS_FROZEN, 0, 0, MUT_ARR_PTRS_FROZEN, "MUT_ARR_PTRS_FROZEN", "MUT_ARR_PTRS_FROZEN")
+{ foreign "C" barf("MUT_ARR_PTRS_FROZEN object entered!"); }
+
+/* ----------------------------------------------------------------------------
+   Mutable Variables
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_MUT_VAR, 1, 1, MUT_VAR, "MUT_VAR", "MUT_VAR")
+{ foreign "C" barf("MUT_VAR object entered!"); }
+
+/* ----------------------------------------------------------------------------
+   Dummy return closure
+   Entering this closure will just return to the address on the top of the
+   stack.  Useful for getting a thread in a canonical form where we can
+   just enter the top stack word to start the thread.  (see deleteThread)
+ * ------------------------------------------------------------------------- */
+
+INFO_TABLE( stg_dummy_ret, 0, 0, CONSTR_NOCAF_STATIC, "DUMMY_RET", "DUMMY_RET")
+{
+  jump %ENTRY_CODE(Sp(0));
+}
+CLOSURE(stg_dummy_ret_closure,stg_dummy_ret);
+
+/* ----------------------------------------------------------------------------
+   CHARLIKE and INTLIKE closures.  
+
+   These are static representations of Chars and small Ints, so that
+   we can remove dynamic Chars and Ints during garbage collection and
+   replace them with references to the static objects.
+   ------------------------------------------------------------------------- */
+
+#if defined(ENABLE_WIN32_DLL_SUPPORT)
+/*
+ * When sticking the RTS in a DLL, we delay populating the
+ * Charlike and Intlike tables until load-time, which is only
+ * when we've got the real addresses to the C# and I# closures.
+ *
+ */
+static INFO_TBL_CONST StgInfoTable czh_static_info;
+static INFO_TBL_CONST StgInfoTable izh_static_info;
+#define Char_hash_static_info czh_static_info
+#define Int_hash_static_info izh_static_info
+#else
+#define Char_hash_static_info GHCziBase_Czh_static
+#define Int_hash_static_info GHCziBase_Izh_static
+#endif
+
+
+#define CHARLIKE_HDR(n)  CLOSURE(Char_hash_static_info, n)
+#define INTLIKE_HDR(n)   CLOSURE(Int_hash_static_info, n)
+
+/* put these in the *data* section, since the garbage collector relies
+ * on the fact that static closures live in the data section.
+ */
+
+/* end the name with _closure, to convince the mangler this is a closure */
+
+section "data" {
+ stg_CHARLIKE_closure:
+    CHARLIKE_HDR(0)
+    CHARLIKE_HDR(1)
+    CHARLIKE_HDR(2)
+    CHARLIKE_HDR(3)
+    CHARLIKE_HDR(4)
+    CHARLIKE_HDR(5)
+    CHARLIKE_HDR(6)
+    CHARLIKE_HDR(7)
+    CHARLIKE_HDR(8)
+    CHARLIKE_HDR(9)
+    CHARLIKE_HDR(10)
+    CHARLIKE_HDR(11)
+    CHARLIKE_HDR(12)
+    CHARLIKE_HDR(13)
+    CHARLIKE_HDR(14)
+    CHARLIKE_HDR(15)
+    CHARLIKE_HDR(16)
+    CHARLIKE_HDR(17)
+    CHARLIKE_HDR(18)
+    CHARLIKE_HDR(19)
+    CHARLIKE_HDR(20)
+    CHARLIKE_HDR(21)
+    CHARLIKE_HDR(22)
+    CHARLIKE_HDR(23)
+    CHARLIKE_HDR(24)
+    CHARLIKE_HDR(25)
+    CHARLIKE_HDR(26)
+    CHARLIKE_HDR(27)
+    CHARLIKE_HDR(28)
+    CHARLIKE_HDR(29)
+    CHARLIKE_HDR(30)
+    CHARLIKE_HDR(31)
+    CHARLIKE_HDR(32)
+    CHARLIKE_HDR(33)
+    CHARLIKE_HDR(34)
+    CHARLIKE_HDR(35)
+    CHARLIKE_HDR(36)
+    CHARLIKE_HDR(37)
+    CHARLIKE_HDR(38)
+    CHARLIKE_HDR(39)
+    CHARLIKE_HDR(40)
+    CHARLIKE_HDR(41)
+    CHARLIKE_HDR(42)
+    CHARLIKE_HDR(43)
+    CHARLIKE_HDR(44)
+    CHARLIKE_HDR(45)
+    CHARLIKE_HDR(46)
+    CHARLIKE_HDR(47)
+    CHARLIKE_HDR(48)
+    CHARLIKE_HDR(49)
+    CHARLIKE_HDR(50)
+    CHARLIKE_HDR(51)
+    CHARLIKE_HDR(52)
+    CHARLIKE_HDR(53)
+    CHARLIKE_HDR(54)
+    CHARLIKE_HDR(55)
+    CHARLIKE_HDR(56)
+    CHARLIKE_HDR(57)
+    CHARLIKE_HDR(58)
+    CHARLIKE_HDR(59)
+    CHARLIKE_HDR(60)
+    CHARLIKE_HDR(61)
+    CHARLIKE_HDR(62)
+    CHARLIKE_HDR(63)
+    CHARLIKE_HDR(64)
+    CHARLIKE_HDR(65)
+    CHARLIKE_HDR(66)
+    CHARLIKE_HDR(67)
+    CHARLIKE_HDR(68)
+    CHARLIKE_HDR(69)
+    CHARLIKE_HDR(70)
+    CHARLIKE_HDR(71)
+    CHARLIKE_HDR(72)
+    CHARLIKE_HDR(73)
+    CHARLIKE_HDR(74)
+    CHARLIKE_HDR(75)
+    CHARLIKE_HDR(76)
+    CHARLIKE_HDR(77)
+    CHARLIKE_HDR(78)
+    CHARLIKE_HDR(79)
+    CHARLIKE_HDR(80)
+    CHARLIKE_HDR(81)
+    CHARLIKE_HDR(82)
+    CHARLIKE_HDR(83)
+    CHARLIKE_HDR(84)
+    CHARLIKE_HDR(85)
+    CHARLIKE_HDR(86)
+    CHARLIKE_HDR(87)
+    CHARLIKE_HDR(88)
+    CHARLIKE_HDR(89)
+    CHARLIKE_HDR(90)
+    CHARLIKE_HDR(91)
+    CHARLIKE_HDR(92)
+    CHARLIKE_HDR(93)
+    CHARLIKE_HDR(94)
+    CHARLIKE_HDR(95)
+    CHARLIKE_HDR(96)
+    CHARLIKE_HDR(97)
+    CHARLIKE_HDR(98)
+    CHARLIKE_HDR(99)
+    CHARLIKE_HDR(100)
+    CHARLIKE_HDR(101)
+    CHARLIKE_HDR(102)
+    CHARLIKE_HDR(103)
+    CHARLIKE_HDR(104)
+    CHARLIKE_HDR(105)
+    CHARLIKE_HDR(106)
+    CHARLIKE_HDR(107)
+    CHARLIKE_HDR(108)
+    CHARLIKE_HDR(109)
+    CHARLIKE_HDR(110)
+    CHARLIKE_HDR(111)
+    CHARLIKE_HDR(112)
+    CHARLIKE_HDR(113)
+    CHARLIKE_HDR(114)
+    CHARLIKE_HDR(115)
+    CHARLIKE_HDR(116)
+    CHARLIKE_HDR(117)
+    CHARLIKE_HDR(118)
+    CHARLIKE_HDR(119)
+    CHARLIKE_HDR(120)
+    CHARLIKE_HDR(121)
+    CHARLIKE_HDR(122)
+    CHARLIKE_HDR(123)
+    CHARLIKE_HDR(124)
+    CHARLIKE_HDR(125)
+    CHARLIKE_HDR(126)
+    CHARLIKE_HDR(127)
+    CHARLIKE_HDR(128)
+    CHARLIKE_HDR(129)
+    CHARLIKE_HDR(130)
+    CHARLIKE_HDR(131)
+    CHARLIKE_HDR(132)
+    CHARLIKE_HDR(133)
+    CHARLIKE_HDR(134)
+    CHARLIKE_HDR(135)
+    CHARLIKE_HDR(136)
+    CHARLIKE_HDR(137)
+    CHARLIKE_HDR(138)
+    CHARLIKE_HDR(139)
+    CHARLIKE_HDR(140)
+    CHARLIKE_HDR(141)
+    CHARLIKE_HDR(142)
+    CHARLIKE_HDR(143)
+    CHARLIKE_HDR(144)
+    CHARLIKE_HDR(145)
+    CHARLIKE_HDR(146)
+    CHARLIKE_HDR(147)
+    CHARLIKE_HDR(148)
+    CHARLIKE_HDR(149)
+    CHARLIKE_HDR(150)
+    CHARLIKE_HDR(151)
+    CHARLIKE_HDR(152)
+    CHARLIKE_HDR(153)
+    CHARLIKE_HDR(154)
+    CHARLIKE_HDR(155)
+    CHARLIKE_HDR(156)
+    CHARLIKE_HDR(157)
+    CHARLIKE_HDR(158)
+    CHARLIKE_HDR(159)
+    CHARLIKE_HDR(160)
+    CHARLIKE_HDR(161)
+    CHARLIKE_HDR(162)
+    CHARLIKE_HDR(163)
+    CHARLIKE_HDR(164)
+    CHARLIKE_HDR(165)
+    CHARLIKE_HDR(166)
+    CHARLIKE_HDR(167)
+    CHARLIKE_HDR(168)
+    CHARLIKE_HDR(169)
+    CHARLIKE_HDR(170)
+    CHARLIKE_HDR(171)
+    CHARLIKE_HDR(172)
+    CHARLIKE_HDR(173)
+    CHARLIKE_HDR(174)
+    CHARLIKE_HDR(175)
+    CHARLIKE_HDR(176)
+    CHARLIKE_HDR(177)
+    CHARLIKE_HDR(178)
+    CHARLIKE_HDR(179)
+    CHARLIKE_HDR(180)
+    CHARLIKE_HDR(181)
+    CHARLIKE_HDR(182)
+    CHARLIKE_HDR(183)
+    CHARLIKE_HDR(184)
+    CHARLIKE_HDR(185)
+    CHARLIKE_HDR(186)
+    CHARLIKE_HDR(187)
+    CHARLIKE_HDR(188)
+    CHARLIKE_HDR(189)
+    CHARLIKE_HDR(190)
+    CHARLIKE_HDR(191)
+    CHARLIKE_HDR(192)
+    CHARLIKE_HDR(193)
+    CHARLIKE_HDR(194)
+    CHARLIKE_HDR(195)
+    CHARLIKE_HDR(196)
+    CHARLIKE_HDR(197)
+    CHARLIKE_HDR(198)
+    CHARLIKE_HDR(199)
+    CHARLIKE_HDR(200)
+    CHARLIKE_HDR(201)
+    CHARLIKE_HDR(202)
+    CHARLIKE_HDR(203)
+    CHARLIKE_HDR(204)
+    CHARLIKE_HDR(205)
+    CHARLIKE_HDR(206)
+    CHARLIKE_HDR(207)
+    CHARLIKE_HDR(208)
+    CHARLIKE_HDR(209)
+    CHARLIKE_HDR(210)
+    CHARLIKE_HDR(211)
+    CHARLIKE_HDR(212)
+    CHARLIKE_HDR(213)
+    CHARLIKE_HDR(214)
+    CHARLIKE_HDR(215)
+    CHARLIKE_HDR(216)
+    CHARLIKE_HDR(217)
+    CHARLIKE_HDR(218)
+    CHARLIKE_HDR(219)
+    CHARLIKE_HDR(220)
+    CHARLIKE_HDR(221)
+    CHARLIKE_HDR(222)
+    CHARLIKE_HDR(223)
+    CHARLIKE_HDR(224)
+    CHARLIKE_HDR(225)
+    CHARLIKE_HDR(226)
+    CHARLIKE_HDR(227)
+    CHARLIKE_HDR(228)
+    CHARLIKE_HDR(229)
+    CHARLIKE_HDR(230)
+    CHARLIKE_HDR(231)
+    CHARLIKE_HDR(232)
+    CHARLIKE_HDR(233)
+    CHARLIKE_HDR(234)
+    CHARLIKE_HDR(235)
+    CHARLIKE_HDR(236)
+    CHARLIKE_HDR(237)
+    CHARLIKE_HDR(238)
+    CHARLIKE_HDR(239)
+    CHARLIKE_HDR(240)
+    CHARLIKE_HDR(241)
+    CHARLIKE_HDR(242)
+    CHARLIKE_HDR(243)
+    CHARLIKE_HDR(244)
+    CHARLIKE_HDR(245)
+    CHARLIKE_HDR(246)
+    CHARLIKE_HDR(247)
+    CHARLIKE_HDR(248)
+    CHARLIKE_HDR(249)
+    CHARLIKE_HDR(250)
+    CHARLIKE_HDR(251)
+    CHARLIKE_HDR(252)
+    CHARLIKE_HDR(253)
+    CHARLIKE_HDR(254)
+    CHARLIKE_HDR(255)
+}
+
+section "data" {
+ stg_INTLIKE_closure:
+    INTLIKE_HDR(-16)   /* MIN_INTLIKE == -16 */
+    INTLIKE_HDR(-15)
+    INTLIKE_HDR(-14)
+    INTLIKE_HDR(-13)
+    INTLIKE_HDR(-12)
+    INTLIKE_HDR(-11)
+    INTLIKE_HDR(-10)
+    INTLIKE_HDR(-9)
+    INTLIKE_HDR(-8)
+    INTLIKE_HDR(-7)
+    INTLIKE_HDR(-6)
+    INTLIKE_HDR(-5)
+    INTLIKE_HDR(-4)
+    INTLIKE_HDR(-3)
+    INTLIKE_HDR(-2)
+    INTLIKE_HDR(-1)
+    INTLIKE_HDR(0)
+    INTLIKE_HDR(1)
+    INTLIKE_HDR(2)
+    INTLIKE_HDR(3)
+    INTLIKE_HDR(4)
+    INTLIKE_HDR(5)
+    INTLIKE_HDR(6)
+    INTLIKE_HDR(7)
+    INTLIKE_HDR(8)
+    INTLIKE_HDR(9)
+    INTLIKE_HDR(10)
+    INTLIKE_HDR(11)
+    INTLIKE_HDR(12)
+    INTLIKE_HDR(13)
+    INTLIKE_HDR(14)
+    INTLIKE_HDR(15)
+    INTLIKE_HDR(16)    /* MAX_INTLIKE == 16 */
+}
diff --git a/ghc/rts/StgMiscClosures.hc b/ghc/rts/StgMiscClosures.hc
deleted file mode 100644 (file)
index 8bf5dbb..0000000
+++ /dev/null
@@ -1,1151 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: StgMiscClosures.hc,v 1.85 2003/05/14 09:14:00 simonmar Exp $
- *
- * (c) The GHC Team, 1998-2002
- *
- * Entry code for various built-in closure types.
- *
- * ---------------------------------------------------------------------------*/
-
-#include "Stg.h"
-#include "Rts.h"
-#include "RtsUtils.h"
-#include "RtsFlags.h"
-#include "StgMiscClosures.h"
-#include "Storage.h"
-#include "StoragePriv.h"
-#include "Profiling.h"
-#include "Prelude.h"
-#include "Schedule.h"
-#include "SMP.h"
-#if defined(GRAN) || defined(PAR)
-# include "GranSimRts.h"      /* for DumpRawGranEvent */
-# include "StgRun.h"   /* for StgReturn and register saving */
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-/* ToDo: make the printing of panics more win32-friendly, i.e.,
- *       pop up some lovely message boxes (as well).
- */
-#define DUMP_ERRMSG(msg) STGCALL2(fprintf,stderr,msg)
-
-/*
-  Template for the entry code of non-enterable closures.
-*/
-
-#define NON_ENTERABLE_ENTRY_CODE(type)         \
-IF_(stg_##type##_entry)                        \
-{                                              \
-  FB_                                          \
-    STGCALL1(barf, #type " object entered!");  \
-  FE_                                          \
-}
-
-
-/* -----------------------------------------------------------------------------
-   Support for the bytecode interpreter.
-   -------------------------------------------------------------------------- */
-
-/* 9 bits of return code for constructors created by the interpreter. */
-FN_(stg_interp_constr_entry) 
-{ 
-  /* R1 points at the constructor */
-  FB_ 
-    /* STGCALL2(fprintf,stderr,"stg_interp_constr_entry (direct return)!\n"); */
-    /* Pointless, since SET_TAG doesn't do anything */
-    SET_TAG( GET_TAG(GET_INFO(R1.cl))); 
-    JMP_(ENTRY_CODE((P_)(*Sp))); 
-  FE_ 
-}
-
-FN_(stg_interp_constr1_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),0)); FE_ }
-FN_(stg_interp_constr2_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),1)); FE_ }
-FN_(stg_interp_constr3_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),2)); FE_ }
-FN_(stg_interp_constr4_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),3)); FE_ }
-FN_(stg_interp_constr5_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),4)); FE_ }
-FN_(stg_interp_constr6_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),5)); FE_ }
-FN_(stg_interp_constr7_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),6)); FE_ }
-FN_(stg_interp_constr8_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),7)); FE_ }
-/* Some info tables to be used when compiled code returns a value to
-   the interpreter, i.e. the interpreter pushes one of these onto the
-   stack before entering a value.  What the code does is to
-   impedance-match the compiled return convention (in R1p/R1n/F1/D1 etc) to
-   the interpreter's convention (returned value is on top of stack),
-   and then cause the scheduler to enter the interpreter.
-
-   On entry, the stack (growing down) looks like this:
-
-      ptr to BCO holding return continuation
-      ptr to one of these info tables.
-   The info table code, both direct and vectored, must:
-      * push R1/F1/D1 on the stack, and its tag if necessary
-      * push the BCO (so it's now on the stack twice)
-      * Yield, ie, go to the scheduler.
-
-   Scheduler examines the t.o.s, discovers it is a BCO, and proceeds
-   directly to the bytecode interpreter.  That pops the top element
-   (the BCO, containing the return continuation), and interprets it.
-   Net result: return continuation gets interpreted, with the
-   following stack:
-
-      ptr to this BCO
-      ptr to the info table just jumped thru
-      return value
-
-   which is just what we want -- the "standard" return layout for the
-   interpreter.  Hurrah!
-
-   Don't ask me how unboxed tuple returns are supposed to work.  We
-   haven't got a good story about that yet.
-*/
-
-// When the returned value is a pointer in R1...
-#define STG_CtoI_RET_R1p_Template(label)       \
-   IF_(label)                                  \
-   {                                           \
-      FB_                                      \
-      Sp -= 2;                                 \
-      Sp[1] = R1.w;                            \
-      Sp[0] = (W_)&stg_enter_info;             \
-      JMP_(stg_yield_to_interpreter);          \
-      FE_                                      \
-   }
-
-STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_ret);
-STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_0_ret);
-STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_1_ret);
-STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_2_ret);
-STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_3_ret);
-STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_4_ret);
-STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_5_ret);
-STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_6_ret);
-STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_7_ret);
-
-VEC_POLY_INFO_TABLE( stg_ctoi_ret_R1p, 0/* special layout */,
-                    0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, 
-                    RET_BCO,, EF_);
-
-// When the returned value is a pointer, but unlifted, in R1 ...
-INFO_TABLE_RET( stg_ctoi_ret_R1unpt_info, stg_ctoi_ret_R1unpt_entry,
-               0/* special layout */,
-               0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, RET_BCO,, IF_, 0, 0);
-IF_(stg_ctoi_ret_R1unpt_entry)
-{
-   FB_
-   Sp -= 2;
-   Sp[1] = R1.w;
-   Sp[0] = (W_)&stg_gc_unpt_r1_info;
-   JMP_(stg_yield_to_interpreter);
-   FE_
-}
-
-// When the returned value is a non-pointer in R1 ...
-INFO_TABLE_RET( stg_ctoi_ret_R1n_info, stg_ctoi_ret_R1n_entry,
-               0/* special layout */,
-               0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, RET_BCO,, IF_, 0, 0);
-IF_(stg_ctoi_ret_R1n_entry)
-{
-   FB_
-   Sp -= 2;
-   Sp[1] = R1.w;
-   Sp[0] = (W_)&stg_gc_unbx_r1_info;
-   JMP_(stg_yield_to_interpreter);
-   FE_
-}
-
-
-// When the returned value is in F1 ...
-INFO_TABLE_RET( stg_ctoi_ret_F1_info, stg_ctoi_ret_F1_entry, 
-               0/* special layout */,
-               0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, RET_BCO,, IF_, 0, 0);
-IF_(stg_ctoi_ret_F1_entry)
-{
-   FB_
-   Sp -= 2;
-   ASSIGN_FLT(Sp+1, F1);
-   Sp[0] = (W_)&stg_gc_f1_info;
-   JMP_(stg_yield_to_interpreter);
-   FE_
-}
-
-// When the returned value is in D1 ...
-INFO_TABLE_RET( stg_ctoi_ret_D1_info, stg_ctoi_ret_D1_entry,
-               0/* special layout */,
-               0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, RET_BCO,, IF_, 0, 0);
-IF_(stg_ctoi_ret_D1_entry)
-{
-   FB_
-   Sp -= 1 + sizeofW(StgDouble);
-   ASSIGN_DBL(Sp+1, D1);
-   Sp[0] = (W_)&stg_gc_d1_info;
-   JMP_(stg_yield_to_interpreter);
-   FE_
-}
-
-// When the returned value is in L1 ...
-INFO_TABLE_RET( stg_ctoi_ret_L1_info, stg_ctoi_ret_L1_entry,
-               0/* special layout */,
-               0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, RET_BCO,, IF_, 0, 0);
-IF_(stg_ctoi_ret_L1_entry)
-{
-   FB_
-   Sp -= 1 + sizeofW(StgInt64);
-   ASSIGN_Word64(Sp+1, L1);
-   Sp[0] = (W_)&stg_gc_l1_info;
-   JMP_(stg_yield_to_interpreter);
-   FE_
-}
-
-// When the returned value a VoidRep ...
-INFO_TABLE_RET( stg_ctoi_ret_V_info, stg_ctoi_ret_V_entry,
-               0/* special layout */,
-               0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, RET_BCO,, IF_, 0, 0);
-IF_(stg_ctoi_ret_V_entry)
-{
-   FB_
-   Sp--;
-   Sp[0] = (W_)&stg_gc_void_info;
-   JMP_(stg_yield_to_interpreter);
-   FE_
-}
-
-// Dummy info table pushed on the top of the stack when the interpreter
-// should apply the BCO on the stack to its arguments, also on the stack.
-INFO_TABLE_RET( stg_apply_interp_info, stg_apply_interp_entry,
-               0/* special layout */,
-               0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, RET_BCO,, IF_, 0, 0);
-IF_(stg_apply_interp_entry)
-{
-    FB_
-    // Just in case we end up in here... (we shouldn't)
-    JMP_(stg_yield_to_interpreter);
-    FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Entry code for a BCO
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE_FUN_GEN(stg_BCO_info,stg_BCO_entry,4,0,
-             0,0,0,  /* no SRT */
-             ARG_BCO, 0/*dummy arity*/, 0/*dummy bitmap*/, NULL/*slow_apply*/,
-             BCO,,EF_,"BCO","BCO");
-FN_(stg_BCO_entry) {
-  FB_
-  // entering a BCO means "apply it", same as a function
-  Sp -= 2;
-  Sp[1] = R1.w;
-  Sp[0] = (W_)&stg_apply_interp_info;
-  JMP_(stg_yield_to_interpreter);
-  FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Info tables for indirections.
-
-   SPECIALISED INDIRECTIONS: we have a specialised indirection for each
-   kind of return (direct, vectored 0-7), so that we can avoid entering
-   the object when we know what kind of return it will do.  The update
-   code (Updates.hc) updates objects with the appropriate kind of
-   indirection.  We only do this for young-gen indirections.
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE(stg_IND_info,stg_IND_entry,1,0,IND,,IF_,"IND","IND");
-IF_(stg_IND_entry)
-{
-    FB_
-    TICK_ENT_DYN_IND(Node);    /* tick */
-    R1.p = (P_) ((StgInd*)R1.p)->indirectee;
-    TICK_ENT_VIA_NODE();
-    JMP_(GET_ENTRY(R1.cl));
-    FE_
-}
-
-#define IND_SPEC(n,ret) \
-INFO_TABLE(stg_IND_##n##_info,stg_IND_##n##_entry,1,0,IND,,IF_,"IND","IND"); \
-IF_(stg_IND_##n##_entry)                       \
-{                                              \
-    FB_                                                \
-    TICK_ENT_DYN_IND(Node);    /* tick */      \
-    R1.p = (P_) ((StgInd*)R1.p)->indirectee;   \
-    TICK_ENT_VIA_NODE();                       \
-    JMP_(ret);                                 \
-    FE_                                                \
-}
-
-IND_SPEC(direct, ENTRY_CODE(Sp[0]))
-IND_SPEC(0, RET_VEC(Sp[0],0))
-IND_SPEC(1, RET_VEC(Sp[0],1))
-IND_SPEC(2, RET_VEC(Sp[0],2))
-IND_SPEC(3, RET_VEC(Sp[0],3))
-IND_SPEC(4, RET_VEC(Sp[0],4))
-IND_SPEC(5, RET_VEC(Sp[0],5))
-IND_SPEC(6, RET_VEC(Sp[0],6))
-IND_SPEC(7, RET_VEC(Sp[0],7))
-
-INFO_TABLE(stg_IND_STATIC_info,stg_IND_STATIC_entry,1,0,IND_STATIC,,IF_,"IND_STATIC","IND_STATIC");
-IF_(stg_IND_STATIC_entry)
-{
-    FB_
-    TICK_ENT_STATIC_IND(Node); /* tick */
-    R1.p = (P_) ((StgIndStatic*)R1.p)->indirectee;
-    TICK_ENT_VIA_NODE();
-    JMP_(GET_ENTRY(R1.cl));
-    FE_
-}
-
-INFO_TABLE(stg_IND_PERM_info,stg_IND_PERM_entry,1,1,IND_PERM,,IF_,"IND_PERM","IND_PERM");
-IF_(stg_IND_PERM_entry)
-{
-    FB_
-    /* Don't add INDs to granularity cost */
-    /* Dont: TICK_ENT_STATIC_IND(Node); for ticky-ticky; this ind is here only to help profiling */
-
-#if defined(TICKY_TICKY) && !defined(PROFILING)
-    /* TICKY_TICKY && !PROFILING means PERM_IND *replaces* an IND, rather than being extra  */
-    TICK_ENT_PERM_IND(R1.p); /* tick */
-#endif
-
-    LDV_ENTER((StgInd *)R1.p);
-
-    /* Enter PAP cost centre -- lexical scoping only */
-    ENTER_CCS_PAP_CL(R1.cl);
-
-    /* For ticky-ticky, change the perm_ind to a normal ind on first
-     * entry, so the number of ent_perm_inds is the number of *thunks*
-     * entered again, not the number of subsequent entries.
-     *
-     * Since this screws up cost centres, we die if profiling and
-     * ticky_ticky are on at the same time.  KSW 1999-01.
-     */
-
-#ifdef TICKY_TICKY
-#  ifdef PROFILING
-#    error Profiling and ticky-ticky do not mix at present!
-#  endif  /* PROFILING */
-    SET_INFO((StgInd*)R1.p,&stg_IND_info);
-#endif /* TICKY_TICKY */
-
-    R1.p = (P_) ((StgInd*)R1.p)->indirectee;
-
-    /* Dont: TICK_ENT_VIA_NODE(); for ticky-ticky; as above */
-
-#if defined(TICKY_TICKY) && !defined(PROFILING)
-    TICK_ENT_VIA_NODE();
-#endif
-
-    JMP_(GET_ENTRY(R1.cl));
-    FE_
-}  
-
-INFO_TABLE(stg_IND_OLDGEN_info,stg_IND_OLDGEN_entry,1,1,IND_OLDGEN,,IF_,"IND_OLDGEN","IND_OLDGEN");
-IF_(stg_IND_OLDGEN_entry)
-{
-    FB_
-    TICK_ENT_STATIC_IND(Node); /* tick */
-    R1.p = (P_) ((StgInd*)R1.p)->indirectee;
-    TICK_ENT_VIA_NODE();
-    JMP_(GET_ENTRY(R1.cl));
-    FE_
-}
-
-INFO_TABLE(stg_IND_OLDGEN_PERM_info,stg_IND_OLDGEN_PERM_entry,1,1,IND_OLDGEN_PERM,,IF_,"IND_OLDGEN_PERM","IND_OLDGEN_PERM");
-IF_(stg_IND_OLDGEN_PERM_entry)
-{
-    FB_
-    /* Dont: TICK_ENT_STATIC_IND(Node); for ticky-ticky; this ind is here only to help profiling */
-
-#if defined(TICKY_TICKY) && !defined(PROFILING)
-    /* TICKY_TICKY && !PROFILING means PERM_IND *replaces* an IND, rather than being extra  */
-    TICK_ENT_PERM_IND(R1.p); /* tick */
-#endif
-
-    LDV_ENTER((StgInd *)R1.p);
-
-    /* Enter PAP cost centre -- lexical scoping only */
-    ENTER_CCS_PAP_CL(R1.cl);
-
-    /* see comment in IND_PERM */
-#ifdef TICKY_TICKY
-#  ifdef PROFILING
-#    error Profiling and ticky-ticky do not mix at present!
-#  endif  /* PROFILING */
-    SET_INFO((StgInd*)R1.p,&stg_IND_OLDGEN_info);
-#endif /* TICKY_TICKY */
-
-    R1.p = (P_) ((StgInd*)R1.p)->indirectee;
-    TICK_ENT_VIA_NODE();
-    JMP_(GET_ENTRY(R1.cl));
-    FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Entry code for a black hole.
-
-   Entering a black hole normally causes a cyclic data dependency, but
-   in the concurrent world, black holes are synchronization points,
-   and they are turned into blocking queues when there are threads
-   waiting for the evaluation of the closure to finish.
-   -------------------------------------------------------------------------- */
-
-/* Note: a BLACKHOLE and BLACKHOLE_BQ must be big enough to be
- * overwritten with an indirection/evacuee/catch.  Thus we claim it
- * has 1 non-pointer word of payload (in addition to the pointer word
- * for the blocking queue in a BQ), which should be big enough for an
- * old-generation indirection. 
- */
-
-INFO_TABLE(stg_BLACKHOLE_info, stg_BLACKHOLE_entry,0,2,BLACKHOLE,,IF_,"BLACKHOLE","BLACKHOLE");
-IF_(stg_BLACKHOLE_entry)
-{
-  FB_
-#if defined(GRAN)
-    /* Before overwriting TSO_LINK */
-    STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1.p /*Node*/);
-#endif
-
-#ifdef SMP
-    {
-      bdescr *bd = Bdescr(R1.p);
-      if (bd->u.back != (bdescr *)BaseReg) {
-       if (bd->gen_no >= 1 || bd->step->no >= 1) {
-         CMPXCHG(R1.cl->header.info, &stg_BLACKHOLE_info, &stg_WHITEHOLE_info);
-       } else {
-         EXTFUN_RTS(stg_gc_enter_1_hponly);
-         JMP_(stg_gc_enter_1_hponly);
-       }
-      }
-    }
-#endif
-    TICK_ENT_BH();
-
-    // Actually this is not necessary because R1.p is about to be destroyed.
-    LDV_ENTER((StgClosure *)R1.p);
-
-    /* Put ourselves on the blocking queue for this black hole */
-#if defined(GRAN) || defined(PAR)
-    // in fact, only difference is the type of the end-of-queue marker!
-    CurrentTSO->link = END_BQ_QUEUE;
-    ((StgBlockingQueue *)R1.p)->blocking_queue = (StgBlockingQueueElement *)CurrentTSO;
-#else
-    CurrentTSO->link = END_TSO_QUEUE;
-    ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
-#endif
-    // jot down why and on what closure we are blocked
-    CurrentTSO->why_blocked = BlockedOnBlackHole;
-    CurrentTSO->block_info.closure = R1.cl;
-
-    /* Change the BLACKHOLE into a BLACKHOLE_BQ */
-#ifdef PROFILING
-
-    // The size remains the same, so we call LDV_recordDead() - no need to fill slop.
-    LDV_recordDead((StgClosure *)R1.p, BLACKHOLE_sizeW());
-#endif
-    // 
-    // Todo: maybe use SET_HDR() and remove LDV_recordCreate()?
-    // 
-    ((StgBlockingQueue *)R1.p)->header.info = &stg_BLACKHOLE_BQ_info;
-#ifdef PROFILING
-    LDV_recordCreate((StgClosure *)R1.p);
-#endif
-
-    // closure is mutable since something has just been added to its BQ
-    recordMutable((StgMutClosure *)R1.cl);
-
-    // PAR: dumping of event now done in blockThread -- HWL
-
-    // stg_gen_block is too heavyweight, use a specialised one
-    BLOCK_NP(1);
-  FE_
-}
-
-INFO_TABLE(stg_BLACKHOLE_BQ_info, stg_BLACKHOLE_BQ_entry,1,1,BLACKHOLE_BQ,,IF_,"BLACKHOLE","BLACKHOLE");
-IF_(stg_BLACKHOLE_BQ_entry)
-{
-  FB_
-#if defined(GRAN)
-    /* Before overwriting TSO_LINK */
-    STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1.p /*Node*/);
-#endif
-
-#ifdef SMP
-    {
-      bdescr *bd = Bdescr(R1.p);
-      if (bd->u.back != (bdescr *)BaseReg) {
-       if (bd->gen_no >= 1 || bd->step->no >= 1) {
-         CMPXCHG(R1.cl->header.info, &stg_BLACKHOLE_info, &stg_WHITEHOLE_info);
-       } else {
-         EXTFUN_RTS(stg_gc_enter_1_hponly);
-         JMP_(stg_gc_enter_1_hponly);
-       }
-      }
-    }
-#endif
-
-    TICK_ENT_BH();
-    LDV_ENTER((StgClosure *)R1.p);
-
-    /* Put ourselves on the blocking queue for this black hole */
-    CurrentTSO->link = ((StgBlockingQueue *)R1.p)->blocking_queue;
-    ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
-    /* jot down why and on what closure we are blocked */
-    CurrentTSO->why_blocked = BlockedOnBlackHole;
-    CurrentTSO->block_info.closure = R1.cl;
-#ifdef SMP
-    ((StgBlockingQueue *)R1.p)->header.info = &stg_BLACKHOLE_BQ_info;
-#endif
-
-    /* PAR: dumping of event now done in blockThread -- HWL */
-
-    /* stg_gen_block is too heavyweight, use a specialised one */
-    BLOCK_NP(1);
-  FE_
-}
-
-/*
-   Revertible black holes are needed in the parallel world, to handle
-   negative acknowledgements of messages containing updatable closures.
-   The idea is that when the original message is transmitted, the closure
-   is turned into a revertible black hole...an object which acts like a
-   black hole when local threads try to enter it, but which can be reverted
-   back to the original closure if necessary.
-
-   It's actually a lot like a blocking queue (BQ) entry, because revertible
-   black holes are initially set up with an empty blocking queue.
-*/
-
-#if defined(PAR) || defined(GRAN)
-
-INFO_TABLE(stg_RBH_info, stg_RBH_entry,1,1,RBH,,IF_,"RBH","RBH");
-IF_(stg_RBH_entry)
-{
-  FB_
-# if defined(GRAN)
-    /* mainly statistics gathering for GranSim simulation */
-    STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1.p /*Node*/);
-# endif
-
-    /* exactly the same as a BLACKHOLE_BQ_entry -- HWL */
-    /* Put ourselves on the blocking queue for this black hole */
-    CurrentTSO->link = ((StgBlockingQueue *)R1.p)->blocking_queue;
-    ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
-    /* jot down why and on what closure we are blocked */
-    CurrentTSO->why_blocked = BlockedOnBlackHole;
-    CurrentTSO->block_info.closure = R1.cl;
-
-    /* PAR: dumping of event now done in blockThread -- HWL */
-
-    /* stg_gen_block is too heavyweight, use a specialised one */
-    BLOCK_NP(1); 
-  FE_
-}
-
-INFO_TABLE(stg_RBH_Save_0_info, stg_RBH_Save_0_entry,0,2,CONSTR,,IF_,"RBH_Save_0","RBH_Save_0");
-NON_ENTERABLE_ENTRY_CODE(RBH_Save_0);
-
-INFO_TABLE(stg_RBH_Save_1_info, stg_RBH_Save_1_entry,1,1,CONSTR,,IF_,"RBH_Save_1","RBH_Save_1");
-NON_ENTERABLE_ENTRY_CODE(RBH_Save_1);
-
-INFO_TABLE(stg_RBH_Save_2_info, stg_RBH_Save_2_entry,2,0,CONSTR,,IF_,"RBH_Save_2","RBH_Save_2");
-NON_ENTERABLE_ENTRY_CODE(RBH_Save_2);
-#endif /* defined(PAR) || defined(GRAN) */
-
-/* identical to BLACKHOLEs except for the infotag */
-INFO_TABLE(stg_CAF_BLACKHOLE_info, stg_CAF_BLACKHOLE_entry,0,2,CAF_BLACKHOLE,,IF_,"CAF_BLACKHOLE","CAF_BLACKHOLE");
-IF_(stg_CAF_BLACKHOLE_entry)
-{
-  FB_
-#if defined(GRAN)
-    /* mainly statistics gathering for GranSim simulation */
-    STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1.p /*Node*/);
-#endif
-
-#ifdef SMP
-    {
-      bdescr *bd = Bdescr(R1.p);
-      if (bd->u.back != (bdescr *)BaseReg) {
-       if (bd->gen_no >= 1 || bd->step->no >= 1) {
-         CMPXCHG(R1.cl->header.info, &stg_CAF_BLACKHOLE_info, &stg_WHITEHOLE_info);
-       } else {
-         EXTFUN_RTS(stg_gc_enter_1_hponly);
-         JMP_(stg_gc_enter_1_hponly);
-       }
-      }
-    }
-#endif
-
-    TICK_ENT_BH();
-    LDV_ENTER((StgClosure *)R1.p);
-
-    // Put ourselves on the blocking queue for this black hole
-#if defined(GRAN) || defined(PAR)
-    // in fact, only difference is the type of the end-of-queue marker!
-    CurrentTSO->link = END_BQ_QUEUE;
-    ((StgBlockingQueue *)R1.p)->blocking_queue = (StgBlockingQueueElement *)CurrentTSO;
-#else
-    CurrentTSO->link = END_TSO_QUEUE;
-    ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
-#endif
-    // jot down why and on what closure we are blocked
-    CurrentTSO->why_blocked = BlockedOnBlackHole;
-    CurrentTSO->block_info.closure = R1.cl;
-
-    // Change the CAF_BLACKHOLE into a BLACKHOLE_BQ_STATIC
-    ((StgBlockingQueue *)R1.p)->header.info = &stg_BLACKHOLE_BQ_info;
-
-    // closure is mutable since something has just been added to its BQ
-    recordMutable((StgMutClosure *)R1.cl);
-
-    // PAR: dumping of event now done in blockThread -- HWL
-
-    // stg_gen_block is too heavyweight, use a specialised one
-    BLOCK_NP(1);
-  FE_
-}
-
-#ifdef EAGER_BLACKHOLING
-INFO_TABLE(stg_SE_BLACKHOLE_info, stg_SE_BLACKHOLE_entry,0,2,SE_BLACKHOLE,,IF_,"SE_BLACKHOLE","SE_BLACKHOLE");
-IF_(stg_SE_BLACKHOLE_entry)
-{
-  FB_
-    STGCALL3(fprintf,stderr,"SE_BLACKHOLE at %p entered!\n",R1.p);
-    STGCALL1(shutdownHaskellAndExit,EXIT_FAILURE);
-  FE_
-}
-
-INFO_TABLE(stg_SE_CAF_BLACKHOLE_info, SE_CAF_BLACKHOLE_entry,0,2,SE_CAF_BLACKHOLE,,IF_,"CAF_BLACKHOLE","CAF_BLACKHOLE");
-IF_(stg_SE_CAF_BLACKHOLE_entry)
-{
-  FB_
-    STGCALL3(fprintf,stderr,"SE_CAF_BLACKHOLE at %p entered!\n",R1.p);
-    STGCALL1(shutdownHaskellAndExit,EXIT_FAILURE);
-  FE_
-}
-#endif
-
-#ifdef SMP
-INFO_TABLE(stg_WHITEHOLE_info, stg_WHITEHOLE_entry,0,2,CONSTR_NOCAF_STATIC,,IF_,"WHITEHOLE","WHITEHOLE");
-IF_(stg_WHITEHOLE_entry)
-{
-  FB_
-    JMP_(GET_ENTRY(R1.cl));
-  FE_
-}
-#endif
-
-/* -----------------------------------------------------------------------------
-   Some static info tables for things that don't get entered, and
-   therefore don't need entry code (i.e. boxed but unpointed objects)
-   NON_ENTERABLE_ENTRY_CODE now defined at the beginning of the file
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE(stg_TSO_info, stg_TSO_entry, 0,0,TSO,,IF_,"TSO","TSO");
-NON_ENTERABLE_ENTRY_CODE(TSO);
-
-/* -----------------------------------------------------------------------------
-   Evacuees are left behind by the garbage collector.  Any attempt to enter
-   one is a real bug.
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE(stg_EVACUATED_info,stg_EVACUATED_entry,1,0,EVACUATED,,IF_,"EVACUATED","EVACUATED");
-NON_ENTERABLE_ENTRY_CODE(EVACUATED);
-
-/* -----------------------------------------------------------------------------
-   Weak pointers
-
-   Live weak pointers have a special closure type.  Dead ones are just
-   nullary constructors (although they live on the heap - we overwrite
-   live weak pointers with dead ones).
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE(stg_WEAK_info,stg_WEAK_entry,0,4,WEAK,,IF_,"WEAK","WEAK");
-NON_ENTERABLE_ENTRY_CODE(WEAK);
-
-// It's important when turning an existing WEAK into a DEAD_WEAK
-// (which is what finalizeWeak# does) that we don't lose the link
-// field and break the linked list of weak pointers.  Hence, we give
-// DEAD_WEAK 4 non-pointer fields, the same as WEAK.
-
-INFO_TABLE_CONSTR(stg_DEAD_WEAK_info,stg_DEAD_WEAK_entry,0,4,0,CONSTR,,IF_,"DEAD_WEAK","DEAD_WEAK");
-NON_ENTERABLE_ENTRY_CODE(DEAD_WEAK);
-
-/* -----------------------------------------------------------------------------
-   NO_FINALIZER
-
-   This is a static nullary constructor (like []) that we use to mark an empty
-   finalizer in a weak pointer object.
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE_CONSTR(stg_NO_FINALIZER_info,stg_NO_FINALIZER_entry,0,0,0,CONSTR_NOCAF_STATIC,,IF_,"NO_FINALIZER","NO_FINALIZER");
-NON_ENTERABLE_ENTRY_CODE(NO_FINALIZER);
-
-SET_STATIC_HDR(stg_NO_FINALIZER_closure,stg_NO_FINALIZER_info,0/*CC*/,,extern const StgInfoTable)
-, /*payload*/{} };
-
-/* -----------------------------------------------------------------------------
-   Foreign Objects are unlifted and therefore never entered.
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE(stg_FOREIGN_info,stg_FOREIGN_entry,0,1,FOREIGN,,IF_,"FOREIGN","FOREIGN");
-NON_ENTERABLE_ENTRY_CODE(FOREIGN);
-
-/* -----------------------------------------------------------------------------
-   Stable Names are unlifted too.
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE(stg_STABLE_NAME_info,stg_STABLE_NAME_entry,0,1,STABLE_NAME,,IF_,"STABLE_NAME","STABLE_NAME");
-NON_ENTERABLE_ENTRY_CODE(STABLE_NAME);
-
-/* -----------------------------------------------------------------------------
-   MVars
-
-   There are two kinds of these: full and empty.  We need an info table
-   and entry code for each type.
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE(stg_FULL_MVAR_info,stg_FULL_MVAR_entry,4,0,MVAR,,IF_,"MVAR","MVAR");
-NON_ENTERABLE_ENTRY_CODE(FULL_MVAR);
-
-INFO_TABLE(stg_EMPTY_MVAR_info,stg_EMPTY_MVAR_entry,4,0,MVAR,,IF_,"MVAR","MVAR");
-NON_ENTERABLE_ENTRY_CODE(EMPTY_MVAR);
-
-/* -----------------------------------------------------------------------------
-   END_TSO_QUEUE
-
-   This is a static nullary constructor (like []) that we use to mark the
-   end of a linked TSO queue.
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE_CONSTR(stg_END_TSO_QUEUE_info,stg_END_TSO_QUEUE_entry,0,0,0,CONSTR_NOCAF_STATIC,,IF_,"END_TSO_QUEUE","END_TSO_QUEUE");
-NON_ENTERABLE_ENTRY_CODE(END_TSO_QUEUE);
-
-SET_STATIC_HDR(stg_END_TSO_QUEUE_closure,stg_END_TSO_QUEUE_info,0/*CC*/,,extern const StgInfoTable)
-, /*payload*/{} };
-
-/* -----------------------------------------------------------------------------
-   Mutable lists
-
-   Mutable lists (used by the garbage collector) consist of a chain of
-   StgMutClosures connected through their mut_link fields, ending in
-   an END_MUT_LIST closure.
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE_CONSTR(stg_END_MUT_LIST_info,stg_END_MUT_LIST_entry,0,0,0,CONSTR_NOCAF_STATIC,,IF_,"END_MUT_LIST","END_MUT_LIST");
-NON_ENTERABLE_ENTRY_CODE(END_MUT_LIST);
-
-SET_STATIC_HDR(stg_END_MUT_LIST_closure,stg_END_MUT_LIST_info,0/*CC*/,,extern const StgInfoTable)
-, /*payload*/{} };
-
-INFO_TABLE(stg_MUT_CONS_info, stg_MUT_CONS_entry, 1, 1, MUT_CONS, , IF_, "MUT_CONS", "MUT_CONS");
-NON_ENTERABLE_ENTRY_CODE(MUT_CONS);
-
-/* -----------------------------------------------------------------------------
-   Exception lists
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE_CONSTR(stg_END_EXCEPTION_LIST_info,stg_END_EXCEPTION_LIST_entry,0,0,0,CONSTR_NOCAF_STATIC,,IF_,"END_EXCEPTION_LIST","END_EXCEPTION_LIST");
-NON_ENTERABLE_ENTRY_CODE(END_EXCEPTION_LIST);
-
-SET_STATIC_HDR(stg_END_EXCEPTION_LIST_closure,stg_END_EXCEPTION_LIST_info,0/*CC*/,,extern const StgInfoTable)
-, /*payload*/{} };
-
-INFO_TABLE(stg_EXCEPTION_CONS_info, stg_EXCEPTION_CONS_entry, 1, 1, CONSTR, , IF_, "EXCEPTION_CONS", "EXCEPTION_CONS");
-NON_ENTERABLE_ENTRY_CODE(EXCEPTION_CONS);
-
-/* -----------------------------------------------------------------------------
-   Arrays
-
-   These come in two basic flavours: arrays of data (StgArrWords) and arrays of
-   pointers (StgArrPtrs).  They all have a similar layout:
-
-       ___________________________
-       | Info | No. of | data....
-        |  Ptr | Words  |
-       ---------------------------
-
-   These are *unpointed* objects: i.e. they cannot be entered.
-
-   -------------------------------------------------------------------------- */
-
-#define ArrayInfo(type)                                        \
-INFO_TABLE(stg_##type##_info, stg_##type##_entry, 0, 0, type, , IF_,"" # type "","" # type "");
-
-ArrayInfo(ARR_WORDS);
-NON_ENTERABLE_ENTRY_CODE(ARR_WORDS);
-ArrayInfo(MUT_ARR_PTRS);
-NON_ENTERABLE_ENTRY_CODE(MUT_ARR_PTRS);
-ArrayInfo(MUT_ARR_PTRS_FROZEN);
-NON_ENTERABLE_ENTRY_CODE(MUT_ARR_PTRS_FROZEN);
-
-#undef ArrayInfo
-
-/* -----------------------------------------------------------------------------
-   Mutable Variables
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE(stg_MUT_VAR_info, stg_MUT_VAR_entry, 1, 1, MUT_VAR, , IF_, "MUT_VAR", "MUT_VAR");
-NON_ENTERABLE_ENTRY_CODE(MUT_VAR);
-
-/* -----------------------------------------------------------------------------
-   Dummy return closure
-   Entering this closure will just return to the address on the top of the
-   stack.  Useful for getting a thread in a canonical form where we can
-   just enter the top stack word to start the thread.  (see deleteThread)
- * -------------------------------------------------------------------------- */
-
-INFO_TABLE( stg_dummy_ret_info, stg_dummy_ret_entry, 
-           0, 0, CONSTR_NOCAF_STATIC, , EF_, "DUMMY_RET", "DUMMY_RET");
-
-STGFUN(stg_dummy_ret_entry)
-{
-  FB_
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
-}
-SET_STATIC_HDR(stg_dummy_ret_closure,stg_dummy_ret_info,CCS_DONT_CARE,,extern const StgInfoTable)
-, /*payload*/{} };
-
-/* -----------------------------------------------------------------------------
-   CHARLIKE and INTLIKE closures.  
-
-   These are static representations of Chars and small Ints, so that
-   we can remove dynamic Chars and Ints during garbage collection and
-   replace them with references to the static objects.
-   -------------------------------------------------------------------------- */
-
-#if defined(INTERPRETER) || defined(ENABLE_WIN32_DLL_SUPPORT)
-/*
- * When sticking the RTS in a DLL, we delay populating the
- * Charlike and Intlike tables until load-time, which is only
- * when we've got the real addresses to the C# and I# closures.
- *
- */
-static INFO_TBL_CONST StgInfoTable czh_static_info;
-static INFO_TBL_CONST StgInfoTable izh_static_info;
-#define Char_hash_static_info czh_static_info
-#define Int_hash_static_info izh_static_info
-#else
-#define Char_hash_static_info GHCziBase_Czh_static_info
-#define Int_hash_static_info GHCziBase_Izh_static_info
-#endif
-
-#define CHARLIKE_HDR(n)                                                \
-       {                                                       \
-         STATIC_HDR(Char_hash_static_info, /* C# */            \
-                        CCS_DONT_CARE),                        \
-          data : n                                             \
-       }
-                                            
-#define INTLIKE_HDR(n)                                         \
-       {                                                       \
-         STATIC_HDR(Int_hash_static_info,  /* I# */            \
-                        CCS_DONT_CARE),                        \
-          data : n                                             \
-       }
-
-/* put these in the *data* section, since the garbage collector relies
- * on the fact that static closures live in the data section.
- */
-
-/* end the name with _closure, to convince the mangler this is a closure */
-
-StgIntCharlikeClosure stg_CHARLIKE_closure[] = {
-    CHARLIKE_HDR(0),
-    CHARLIKE_HDR(1),
-    CHARLIKE_HDR(2),
-    CHARLIKE_HDR(3),
-    CHARLIKE_HDR(4),
-    CHARLIKE_HDR(5),
-    CHARLIKE_HDR(6),
-    CHARLIKE_HDR(7),
-    CHARLIKE_HDR(8),
-    CHARLIKE_HDR(9),
-    CHARLIKE_HDR(10),
-    CHARLIKE_HDR(11),
-    CHARLIKE_HDR(12),
-    CHARLIKE_HDR(13),
-    CHARLIKE_HDR(14),
-    CHARLIKE_HDR(15),
-    CHARLIKE_HDR(16),
-    CHARLIKE_HDR(17),
-    CHARLIKE_HDR(18),
-    CHARLIKE_HDR(19),
-    CHARLIKE_HDR(20),
-    CHARLIKE_HDR(21),
-    CHARLIKE_HDR(22),
-    CHARLIKE_HDR(23),
-    CHARLIKE_HDR(24),
-    CHARLIKE_HDR(25),
-    CHARLIKE_HDR(26),
-    CHARLIKE_HDR(27),
-    CHARLIKE_HDR(28),
-    CHARLIKE_HDR(29),
-    CHARLIKE_HDR(30),
-    CHARLIKE_HDR(31),
-    CHARLIKE_HDR(32),
-    CHARLIKE_HDR(33),
-    CHARLIKE_HDR(34),
-    CHARLIKE_HDR(35),
-    CHARLIKE_HDR(36),
-    CHARLIKE_HDR(37),
-    CHARLIKE_HDR(38),
-    CHARLIKE_HDR(39),
-    CHARLIKE_HDR(40),
-    CHARLIKE_HDR(41),
-    CHARLIKE_HDR(42),
-    CHARLIKE_HDR(43),
-    CHARLIKE_HDR(44),
-    CHARLIKE_HDR(45),
-    CHARLIKE_HDR(46),
-    CHARLIKE_HDR(47),
-    CHARLIKE_HDR(48),
-    CHARLIKE_HDR(49),
-    CHARLIKE_HDR(50),
-    CHARLIKE_HDR(51),
-    CHARLIKE_HDR(52),
-    CHARLIKE_HDR(53),
-    CHARLIKE_HDR(54),
-    CHARLIKE_HDR(55),
-    CHARLIKE_HDR(56),
-    CHARLIKE_HDR(57),
-    CHARLIKE_HDR(58),
-    CHARLIKE_HDR(59),
-    CHARLIKE_HDR(60),
-    CHARLIKE_HDR(61),
-    CHARLIKE_HDR(62),
-    CHARLIKE_HDR(63),
-    CHARLIKE_HDR(64),
-    CHARLIKE_HDR(65),
-    CHARLIKE_HDR(66),
-    CHARLIKE_HDR(67),
-    CHARLIKE_HDR(68),
-    CHARLIKE_HDR(69),
-    CHARLIKE_HDR(70),
-    CHARLIKE_HDR(71),
-    CHARLIKE_HDR(72),
-    CHARLIKE_HDR(73),
-    CHARLIKE_HDR(74),
-    CHARLIKE_HDR(75),
-    CHARLIKE_HDR(76),
-    CHARLIKE_HDR(77),
-    CHARLIKE_HDR(78),
-    CHARLIKE_HDR(79),
-    CHARLIKE_HDR(80),
-    CHARLIKE_HDR(81),
-    CHARLIKE_HDR(82),
-    CHARLIKE_HDR(83),
-    CHARLIKE_HDR(84),
-    CHARLIKE_HDR(85),
-    CHARLIKE_HDR(86),
-    CHARLIKE_HDR(87),
-    CHARLIKE_HDR(88),
-    CHARLIKE_HDR(89),
-    CHARLIKE_HDR(90),
-    CHARLIKE_HDR(91),
-    CHARLIKE_HDR(92),
-    CHARLIKE_HDR(93),
-    CHARLIKE_HDR(94),
-    CHARLIKE_HDR(95),
-    CHARLIKE_HDR(96),
-    CHARLIKE_HDR(97),
-    CHARLIKE_HDR(98),
-    CHARLIKE_HDR(99),
-    CHARLIKE_HDR(100),
-    CHARLIKE_HDR(101),
-    CHARLIKE_HDR(102),
-    CHARLIKE_HDR(103),
-    CHARLIKE_HDR(104),
-    CHARLIKE_HDR(105),
-    CHARLIKE_HDR(106),
-    CHARLIKE_HDR(107),
-    CHARLIKE_HDR(108),
-    CHARLIKE_HDR(109),
-    CHARLIKE_HDR(110),
-    CHARLIKE_HDR(111),
-    CHARLIKE_HDR(112),
-    CHARLIKE_HDR(113),
-    CHARLIKE_HDR(114),
-    CHARLIKE_HDR(115),
-    CHARLIKE_HDR(116),
-    CHARLIKE_HDR(117),
-    CHARLIKE_HDR(118),
-    CHARLIKE_HDR(119),
-    CHARLIKE_HDR(120),
-    CHARLIKE_HDR(121),
-    CHARLIKE_HDR(122),
-    CHARLIKE_HDR(123),
-    CHARLIKE_HDR(124),
-    CHARLIKE_HDR(125),
-    CHARLIKE_HDR(126),
-    CHARLIKE_HDR(127),
-    CHARLIKE_HDR(128),
-    CHARLIKE_HDR(129),
-    CHARLIKE_HDR(130),
-    CHARLIKE_HDR(131),
-    CHARLIKE_HDR(132),
-    CHARLIKE_HDR(133),
-    CHARLIKE_HDR(134),
-    CHARLIKE_HDR(135),
-    CHARLIKE_HDR(136),
-    CHARLIKE_HDR(137),
-    CHARLIKE_HDR(138),
-    CHARLIKE_HDR(139),
-    CHARLIKE_HDR(140),
-    CHARLIKE_HDR(141),
-    CHARLIKE_HDR(142),
-    CHARLIKE_HDR(143),
-    CHARLIKE_HDR(144),
-    CHARLIKE_HDR(145),
-    CHARLIKE_HDR(146),
-    CHARLIKE_HDR(147),
-    CHARLIKE_HDR(148),
-    CHARLIKE_HDR(149),
-    CHARLIKE_HDR(150),
-    CHARLIKE_HDR(151),
-    CHARLIKE_HDR(152),
-    CHARLIKE_HDR(153),
-    CHARLIKE_HDR(154),
-    CHARLIKE_HDR(155),
-    CHARLIKE_HDR(156),
-    CHARLIKE_HDR(157),
-    CHARLIKE_HDR(158),
-    CHARLIKE_HDR(159),
-    CHARLIKE_HDR(160),
-    CHARLIKE_HDR(161),
-    CHARLIKE_HDR(162),
-    CHARLIKE_HDR(163),
-    CHARLIKE_HDR(164),
-    CHARLIKE_HDR(165),
-    CHARLIKE_HDR(166),
-    CHARLIKE_HDR(167),
-    CHARLIKE_HDR(168),
-    CHARLIKE_HDR(169),
-    CHARLIKE_HDR(170),
-    CHARLIKE_HDR(171),
-    CHARLIKE_HDR(172),
-    CHARLIKE_HDR(173),
-    CHARLIKE_HDR(174),
-    CHARLIKE_HDR(175),
-    CHARLIKE_HDR(176),
-    CHARLIKE_HDR(177),
-    CHARLIKE_HDR(178),
-    CHARLIKE_HDR(179),
-    CHARLIKE_HDR(180),
-    CHARLIKE_HDR(181),
-    CHARLIKE_HDR(182),
-    CHARLIKE_HDR(183),
-    CHARLIKE_HDR(184),
-    CHARLIKE_HDR(185),
-    CHARLIKE_HDR(186),
-    CHARLIKE_HDR(187),
-    CHARLIKE_HDR(188),
-    CHARLIKE_HDR(189),
-    CHARLIKE_HDR(190),
-    CHARLIKE_HDR(191),
-    CHARLIKE_HDR(192),
-    CHARLIKE_HDR(193),
-    CHARLIKE_HDR(194),
-    CHARLIKE_HDR(195),
-    CHARLIKE_HDR(196),
-    CHARLIKE_HDR(197),
-    CHARLIKE_HDR(198),
-    CHARLIKE_HDR(199),
-    CHARLIKE_HDR(200),
-    CHARLIKE_HDR(201),
-    CHARLIKE_HDR(202),
-    CHARLIKE_HDR(203),
-    CHARLIKE_HDR(204),
-    CHARLIKE_HDR(205),
-    CHARLIKE_HDR(206),
-    CHARLIKE_HDR(207),
-    CHARLIKE_HDR(208),
-    CHARLIKE_HDR(209),
-    CHARLIKE_HDR(210),
-    CHARLIKE_HDR(211),
-    CHARLIKE_HDR(212),
-    CHARLIKE_HDR(213),
-    CHARLIKE_HDR(214),
-    CHARLIKE_HDR(215),
-    CHARLIKE_HDR(216),
-    CHARLIKE_HDR(217),
-    CHARLIKE_HDR(218),
-    CHARLIKE_HDR(219),
-    CHARLIKE_HDR(220),
-    CHARLIKE_HDR(221),
-    CHARLIKE_HDR(222),
-    CHARLIKE_HDR(223),
-    CHARLIKE_HDR(224),
-    CHARLIKE_HDR(225),
-    CHARLIKE_HDR(226),
-    CHARLIKE_HDR(227),
-    CHARLIKE_HDR(228),
-    CHARLIKE_HDR(229),
-    CHARLIKE_HDR(230),
-    CHARLIKE_HDR(231),
-    CHARLIKE_HDR(232),
-    CHARLIKE_HDR(233),
-    CHARLIKE_HDR(234),
-    CHARLIKE_HDR(235),
-    CHARLIKE_HDR(236),
-    CHARLIKE_HDR(237),
-    CHARLIKE_HDR(238),
-    CHARLIKE_HDR(239),
-    CHARLIKE_HDR(240),
-    CHARLIKE_HDR(241),
-    CHARLIKE_HDR(242),
-    CHARLIKE_HDR(243),
-    CHARLIKE_HDR(244),
-    CHARLIKE_HDR(245),
-    CHARLIKE_HDR(246),
-    CHARLIKE_HDR(247),
-    CHARLIKE_HDR(248),
-    CHARLIKE_HDR(249),
-    CHARLIKE_HDR(250),
-    CHARLIKE_HDR(251),
-    CHARLIKE_HDR(252),
-    CHARLIKE_HDR(253),
-    CHARLIKE_HDR(254),
-    CHARLIKE_HDR(255)
-};
-
-StgIntCharlikeClosure stg_INTLIKE_closure[] = {
-    INTLIKE_HDR(-16),  /* MIN_INTLIKE == -16 */
-    INTLIKE_HDR(-15),
-    INTLIKE_HDR(-14),
-    INTLIKE_HDR(-13),
-    INTLIKE_HDR(-12),
-    INTLIKE_HDR(-11),
-    INTLIKE_HDR(-10),
-    INTLIKE_HDR(-9),
-    INTLIKE_HDR(-8),
-    INTLIKE_HDR(-7),
-    INTLIKE_HDR(-6),
-    INTLIKE_HDR(-5),
-    INTLIKE_HDR(-4),
-    INTLIKE_HDR(-3),
-    INTLIKE_HDR(-2),
-    INTLIKE_HDR(-1),
-    INTLIKE_HDR(0),
-    INTLIKE_HDR(1),
-    INTLIKE_HDR(2),
-    INTLIKE_HDR(3),
-    INTLIKE_HDR(4),
-    INTLIKE_HDR(5),
-    INTLIKE_HDR(6),
-    INTLIKE_HDR(7),
-    INTLIKE_HDR(8),
-    INTLIKE_HDR(9),
-    INTLIKE_HDR(10),
-    INTLIKE_HDR(11),
-    INTLIKE_HDR(12),
-    INTLIKE_HDR(13),
-    INTLIKE_HDR(14),
-    INTLIKE_HDR(15),
-    INTLIKE_HDR(16)    /* MAX_INTLIKE == 16 */
-};
index e015169..2ea64cd 100644 (file)
@@ -1,7 +1,6 @@
 /* -----------------------------------------------------------------------------
- * $Id: StgRun.h,v 1.6 2001/05/25 18:33:46 sof Exp $
  *
- * (c) The GHC Team, 1998-1999
+ * (c) The GHC Team, 1998-2004
  *
  * Tiny assembler 'layer' between the C and STG worlds.
  * 
@@ -12,7 +11,6 @@
 
 extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg);
 
-EXTFUN(StgReturn);
+RTS_FUN(StgReturn);
 
 #endif /* STGRUN_H */
-
similarity index 53%
rename from ghc/rts/StgStartup.hc
rename to ghc/rts/StgStartup.cmm
index d3e4c2f..d9308d6 100644 (file)
@@ -1,16 +1,16 @@
 /* -----------------------------------------------------------------------------
- * $Id: StgStartup.hc,v 1.21 2003/05/14 09:14:00 simonmar Exp $
  *
- * (c) The GHC Team, 1998-2002
+ * (c) The GHC Team, 1998-2004
  *
  * Code for starting, stopping and restarting threads.
  *
+ * This file is written in a subset of C--, extended with various
+ * features specific to GHC.  It is compiled by GHC directly.  For the
+ * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
+ *
  * ---------------------------------------------------------------------------*/
 
-#include "Stg.h"
-#include "Rts.h"
-#include "StgRun.h" /* StgReturn */
-#include "StgStartup.h"
+#include "Cmm.h"
 
 /*
  * This module contains the two entry points and the final exit point
  */
 
 #define CHECK_SENSIBLE_REGS() \
-    ASSERT(Hp != (P_)0);                       \
-    ASSERT(Sp != (P_)0);                       \
-    ASSERT(SpLim != (P_)0);                    \
-    ASSERT(HpLim != (P_)0);                    \
+    ASSERT(Hp != 0);                   \
+    ASSERT(Sp != 0);                   \
+    ASSERT(SpLim != 0);                        \
+    ASSERT(HpLim != 0);                        \
     ASSERT(SpLim - RESERVED_STACK_WORDS <= Sp); \
     ASSERT(HpLim >= Hp);
 
@@ -41,8 +41,6 @@
    slot 0).
    -------------------------------------------------------------------------- */
 
-EXTFUN(stg_stop_thread_ret);
-
 #if defined(PROFILING)
 #define STOP_THREAD_BITMAP 3
 #define STOP_THREAD_WORDS  2
@@ -51,58 +49,53 @@ EXTFUN(stg_stop_thread_ret);
 #define STOP_THREAD_WORDS  0
 #endif
 
-/* VEC_POLY_INFO expects to see these names - but they should all be the same. */
-#define stg_stop_thread_0_ret stg_stop_thread_ret 
-#define stg_stop_thread_1_ret stg_stop_thread_ret 
-#define stg_stop_thread_2_ret stg_stop_thread_ret 
-#define stg_stop_thread_3_ret stg_stop_thread_ret 
-#define stg_stop_thread_4_ret stg_stop_thread_ret 
-#define stg_stop_thread_5_ret stg_stop_thread_ret 
-#define stg_stop_thread_6_ret stg_stop_thread_ret 
-#define stg_stop_thread_7_ret stg_stop_thread_ret 
-
-VEC_POLY_INFO_TABLE( stg_stop_thread,
-                    MK_SMALL_BITMAP(STOP_THREAD_WORDS, STOP_THREAD_BITMAP),
-                    0,0,0,STOP_FRAME,,EF_);
-
-STGFUN(stg_stop_thread_ret)
+/* A polymorhpic return address, where all the vector slots point to the
+   direct entry point. */
+INFO_TABLE_RET( stg_stop_thread, STOP_THREAD_WORDS, STOP_THREAD_BITMAP,
+               STOP_FRAME, 
+               RET_LBL(stg_stop_thread),
+               RET_LBL(stg_stop_thread),
+               RET_LBL(stg_stop_thread),
+               RET_LBL(stg_stop_thread),
+               RET_LBL(stg_stop_thread),
+               RET_LBL(stg_stop_thread),
+               RET_LBL(stg_stop_thread),
+               RET_LBL(stg_stop_thread) )
 {
-    FB_
-    // 
-    // The final exit.
-    //
-    // The top-top-level closures (e.g., "main") are of type "IO a".
-    // When entered, they perform an IO action and return an 'a' in R1.
-    //
-    // We save R1 on top of the stack where the scheduler can find it,
-    // tidy up the registers and return to the scheduler.
-    //
-    // We Leave the stack looking like this:
-    //
-    //         +----------------+
-    //          |      -------------------> return value
-    //         +----------------+
-    //         | stg_enter_info |
-    //         +----------------+
-    //
-    // The stg_enter_info is just a dummy info table so that the
-    // garbage collector can understand the stack (there must always
-    // be an info table on top of the stack).
-    //
-
-    Sp += sizeofW(StgStopFrame) - 2;
-    Sp[1] = R1.w;
-    Sp[0] = (W_)&stg_enter_info;
-
-    CurrentTSO->what_next = ThreadComplete;
-
-    SaveThreadState(); // inline!
-
-    // R1 contains the return value of the thread
-    R1.i = ThreadFinished;
-
-    JMP_(StgReturn);
-    FE_
+    /* 
+       The final exit.
+      
+       The top-top-level closures (e.g., "main") are of type "IO a".
+       When entered, they perform an IO action and return an 'a' in R1.
+      
+       We save R1 on top of the stack where the scheduler can find it,
+       tidy up the registers and return to the scheduler.
+      
+       We Leave the stack looking like this:
+      
+               +----------------+
+                |      -------------------> return value
+               +----------------+
+               | stg_enter_info |
+               +----------------+
+      
+       The stg_enter_info is just a dummy info table so that the
+       garbage collector can understand the stack (there must always
+       be an info table on top of the stack).
+    */
+
+    Sp = Sp + SIZEOF_StgStopFrame - WDS(2);
+    Sp(1) = R1;
+    Sp(0) = stg_enter_info;
+
+    StgTSO_what_next(CurrentTSO) = ThreadComplete::I16;
+
+    SAVE_THREAD_STATE();
+
+    /* R1 contains the return value of the thread */
+    R1 = ThreadFinished;
+
+    jump StgReturn;
 }
 
 /* -----------------------------------------------------------------------------
@@ -111,13 +104,11 @@ STGFUN(stg_stop_thread_ret)
    from C land.
    -------------------------------------------------------------------------- */
 
-STGFUN(stg_returnToStackTop)
+stg_returnToStackTop
 {
-  FB_
-  LoadThreadState();
+  LOAD_THREAD_STATE();
   CHECK_SENSIBLE_REGS();
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
+  jump %ENTRY_CODE(Sp(0));
 }
 
 /* -----------------------------------------------------------------------------
@@ -133,27 +124,18 @@ STGFUN(stg_returnToStackTop)
     results that comes back.
     ------------------------------------------------------------------------- */
 
-INFO_TABLE_RET( stg_forceIO_info,stg_forceIO_ret,
-               MK_SMALL_BITMAP(0/*size*/, 0/*BITMAP*/),
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_SMALL,, EF_, 0, 0);
+INFO_TABLE_RET( stg_forceIO, 0/*size*/, 0/*bitmap*/, RET_SMALL)
 
 #ifdef REG_R1
-STGFUN(stg_forceIO_ret)
 {
-  FB_
-  Sp++;
+  Sp_adj(1);
   ENTER();
-  FE_
 }
 #else
-STGFUN(stg_forceIO_ret)
 {
-  FB_
-  R1.w = Sp[0];
-  Sp += 2;
+  R1 = Sp(0);
+  Sp_adj(2);
   ENTER();
-  FE_
 }
 #endif
 
@@ -166,27 +148,18 @@ STGFUN(stg_forceIO_ret)
     is a register or not.
     ------------------------------------------------------------------------- */
 
-INFO_TABLE_RET( stg_noforceIO_info,stg_noforceIO_ret,
-               MK_SMALL_BITMAP(0/*size*/, 0/*BITMAP*/),
-               0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
-               RET_SMALL,, EF_, 0, 0);
+INFO_TABLE_RET( stg_noforceIO, 0/*size*/, 0/*bitmap*/, RET_SMALL )
 
 #ifdef REG_R1
-STGFUN(stg_noforceIO_ret)
 {
-  FB_
-  Sp++;
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
+  Sp_adj(1);
+  jump %ENTRY_CODE(Sp(0));
 }
 #else
-STGFUN(stg_noforceIO_ret)
 {
-  FB_
-  R1.w = Sp[0];
-  Sp += 2;
-  JMP_(ENTRY_CODE(Sp[0]));
-  FE_
+  R1 = Sp(0);
+  Sp_adj(2);
+  jump %ENTRY_CODE(Sp(0));
 }
 #endif
 
@@ -194,23 +167,20 @@ STGFUN(stg_noforceIO_ret)
    Special STG entry points for module registration.
    -------------------------------------------------------------------------- */
 
-extern F_ *init_stack;
-
-STGFUN(stg_init_ret)
+stg_init_finish
 {
-  FB_
-  JMP_(StgReturn);
-  FE_
+  jump StgReturn;
 }
 
 /* On entry to stg_init:
  *    init_stack[0] = &stg_init_ret;
  *    init_stack[1] = __stginit_Something;
  */
-STGFUN(stg_init)
+stg_init
 {
-  FB_
-  Sp = BaseReg->rSp;
-  JMP_(POP_INIT_STACK());
-  FE_
+  W_ next;
+  Sp = W_[MainCapability + OFFSET_Capability_r + OFFSET_StgRegTable_rSp];
+  next = W_[Sp];
+  Sp_adj(1);
+  jump next;
 }
diff --git a/ghc/rts/StgStartup.h b/ghc/rts/StgStartup.h
deleted file mode 100644 (file)
index 55f57e6..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: StgStartup.h,v 1.6 2002/02/12 15:17:23 simonmar Exp $
- *
- * (c) The GHC Team, 1998-1999
- *
- * Code for starting, stopping and restarting threads.
- *
- * ---------------------------------------------------------------------------*/
-
-extern const StgPolyInfoTable stg_stop_thread_info;
-EXTFUN(stg_stop_thread_entry);
-EXTFUN(stg_returnToStackTop);
-EXTFUN(stg_enterStackTop);
-
-EXTFUN(stg_init_ret);
-EXTFUN(stg_init);
-EXTFUN(__stginit_GHCziPrim);
diff --git a/ghc/rts/StgStdThunks.cmm b/ghc/rts/StgStdThunks.cmm
new file mode 100644 (file)
index 0000000..f1e4f08
--- /dev/null
@@ -0,0 +1,273 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The University of Glasgow, 1998-2004
+ *
+ * Canned "Standard Form" Thunks
+ *
+ * This file is written in a subset of C--, extended with various
+ * features specific to GHC.  It is compiled by GHC directly.  For the
+ * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "Cmm.h"
+
+/* -----------------------------------------------------------------------------
+   The code for a thunk that simply extracts a field from a
+   single-constructor datatype depends only on the offset of the field
+   to be selected.
+
+   Here we define some canned "selector" thunks that do just that; any
+   selector thunk appearing in a program will refer to one of these
+   instead of being compiled independently.
+
+   The garbage collector spots selector thunks and reduces them if
+   possible, in order to avoid space leaks resulting from lazy pattern
+   matching.
+   -------------------------------------------------------------------------- */
+
+#define WITHUPD_FRAME_SIZE  (SIZEOF_StgUpdateFrame + SIZEOF_StgHeader)
+#define NOUPD_FRAME_SIZE    (SIZEOF_StgHeader)
+
+#ifdef PROFILING
+#define SAVE_CCCS(fs)          StgHeader_ccs(Sp-fs) = W_[CCCS]
+#define GET_SAVED_CCCS  W_[CCCS] = StgHeader_ccs(Sp)
+#define RET_BITMAP    3
+#define RET_FRAMESIZE 2
+#else
+#define SAVE_CCCS(fs)   /* empty */
+#define GET_SAVED_CCCS  /* empty */
+#define RET_BITMAP    0
+#define RET_FRAMESIZE 0
+#endif
+
+#define SELECTOR_CODE_UPD(offset) \
+  INFO_TABLE_RET(stg_sel_ret_##offset##_upd, RET_FRAMESIZE, RET_BITMAP, RET_SMALL)     \
+  {                                                                    \
+      R1 = StgClosure_payload(R1,offset);                                              \
+      GET_SAVED_CCCS;                                                  \
+      Sp = Sp + SIZEOF_StgHeader;                                      \
+      ENTER();                                                         \
+  }                                                                    \
+                                                                       \
+  INFO_TABLE_SELECTOR(stg_sel_##offset##_upd, offset, THUNK_SELECTOR, "stg_sel_upd", "stg_sel_upd") \
+  {                                                                    \
+      TICK_ENT_DYN_THK();                                              \
+      STK_CHK_NP(WITHUPD_FRAME_SIZE);                                  \
+      UPD_BH_UPDATABLE();                                              \
+      LDV_ENTER(R1);                                                   \
+      PUSH_UPD_FRAME(Sp - SIZEOF_StgUpdateFrame, R1);                  \
+      ENTER_CCS_THUNK(R1);                                                     \
+      SAVE_CCCS(WITHUPD_FRAME_SIZE);                                   \
+      W_[Sp-WITHUPD_FRAME_SIZE] = stg_sel_ret_##offset##_upd_info;     \
+      R1 = StgClosure_payload(R1,0);                                           \
+      Sp = Sp - WITHUPD_FRAME_SIZE;                                    \
+      ENTER();                                                         \
+  }
+
+SELECTOR_CODE_UPD(0)
+SELECTOR_CODE_UPD(1)
+SELECTOR_CODE_UPD(2)
+SELECTOR_CODE_UPD(3)
+SELECTOR_CODE_UPD(4)
+SELECTOR_CODE_UPD(5)
+SELECTOR_CODE_UPD(6)
+SELECTOR_CODE_UPD(7)
+SELECTOR_CODE_UPD(8)
+SELECTOR_CODE_UPD(9)
+SELECTOR_CODE_UPD(10)
+SELECTOR_CODE_UPD(11)
+SELECTOR_CODE_UPD(12)
+SELECTOR_CODE_UPD(13)
+SELECTOR_CODE_UPD(14)
+SELECTOR_CODE_UPD(15)
+
+#define SELECTOR_CODE_NOUPD(offset) \
+  INFO_TABLE_RET(stg_sel_ret_##offset##_noupd, RET_FRAMESIZE, RET_BITMAP, RET_SMALL)   \
+  {                                                                    \
+      R1 = StgClosure_payload(R1,offset);                                              \
+      GET_SAVED_CCCS;                                                  \
+      Sp = Sp + SIZEOF_StgHeader;                                      \
+      jump %GET_ENTRY(R1);                                             \
+  }                                                                    \
+                                                                       \
+  INFO_TABLE_SELECTOR(stg_sel_##offset##_noupd, offset, THUNK_SELECTOR, "stg_sel_noupd", "stg_sel_noupd")\
+  {                                                                    \
+      TICK_ENT_DYN_THK();                                              \
+      STK_CHK_NP(NOUPD_FRAME_SIZE);                                    \
+      UPD_BH_SINGLE_ENTRY();                                           \
+      LDV_ENTER(R1);                                                   \
+      TICK_UPDF_OMITTED();                                             \
+      ENTER_CCS_THUNK(R1);                                                     \
+      SAVE_CCCS(NOUPD_FRAME_SIZE);                                     \
+      W_[Sp-NOUPD_FRAME_SIZE] = stg_sel_ret_##offset##_noupd_info;     \
+      R1 = StgClosure_payload(R1,0);                                           \
+      Sp = Sp - NOUPD_FRAME_SIZE;                                      \
+      jump %GET_ENTRY(R1);                                             \
+  }
+
+SELECTOR_CODE_NOUPD(0)
+SELECTOR_CODE_NOUPD(1)
+SELECTOR_CODE_NOUPD(2)
+SELECTOR_CODE_NOUPD(3)
+SELECTOR_CODE_NOUPD(4)
+SELECTOR_CODE_NOUPD(5)
+SELECTOR_CODE_NOUPD(6)
+SELECTOR_CODE_NOUPD(7)
+SELECTOR_CODE_NOUPD(8)
+SELECTOR_CODE_NOUPD(9)
+SELECTOR_CODE_NOUPD(10)
+SELECTOR_CODE_NOUPD(11)
+SELECTOR_CODE_NOUPD(12)
+SELECTOR_CODE_NOUPD(13)
+SELECTOR_CODE_NOUPD(14)
+SELECTOR_CODE_NOUPD(15)
+
+/* -----------------------------------------------------------------------------
+   Apply thunks
+
+   An apply thunk is a thunk of the form
+       
+               let z = [x1...xn] \u x1...xn
+               in ...
+
+   We pre-compile some of these because the code is always the same.
+
+   These have to be independent of the update frame size, so the code
+   works when profiling etc.
+   -------------------------------------------------------------------------- */
+
+/* stg_ap_1_upd_info is a bit redundant, but there appears to be a bug
+ * in the compiler that means stg_ap_1 is generated occasionally (ToDo)
+ */
+
+INFO_TABLE(stg_ap_1_upd,1,1,THUNK_1_0,"stg_ap_1_upd_info","stg_ap_1_upd_info")
+{
+  TICK_ENT_DYN_THK();
+  STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(1));
+  UPD_BH_UPDATABLE();
+  LDV_ENTER(R1);
+  ENTER_CCS_THUNK(R1);
+  PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
+  R1 = StgClosure_payload(R1,0);
+  Sp = Sp - SIZEOF_StgUpdateFrame;
+  Sp_adj(-1); // for stg_ap_0_ret
+  jump RET_LBL(stg_ap_0);
+}
+
+INFO_TABLE(stg_ap_2_upd,2,0,THUNK_2_0,"stg_ap_2_upd_info","stg_ap_2_upd_info")
+{
+  TICK_ENT_DYN_THK();
+  STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(2));
+  UPD_BH_UPDATABLE();
+  LDV_ENTER(R1);
+  ENTER_CCS_THUNK(R1);
+  PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,1);
+  R1 = StgClosure_payload(R1,0);
+  Sp = Sp - SIZEOF_StgUpdateFrame - WDS(1);
+  Sp_adj(-1); // for stg_ap_0_ret
+  TICK_UNKNOWN_CALL();
+  TICK_SLOW_CALL_p();
+  jump RET_LBL(stg_ap_p);
+}
+
+INFO_TABLE(stg_ap_3_upd,3,0,THUNK,"stg_ap_3_upd_info","stg_ap_3_upd_info")
+{
+  TICK_ENT_DYN_THK();
+  STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(3));
+  UPD_BH_UPDATABLE();
+  LDV_ENTER(R1);
+  ENTER_CCS_THUNK(R1);
+  PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,2);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,1);
+  R1 = StgClosure_payload(R1,0);
+  Sp = Sp - SIZEOF_StgUpdateFrame - WDS(2);
+  Sp_adj(-1); // for stg_ap_0_ret
+  TICK_UNKNOWN_CALL();
+  TICK_SLOW_CALL_pp();
+  jump RET_LBL(stg_ap_pp);
+}
+
+INFO_TABLE(stg_ap_4_upd,4,0,THUNK,"stg_ap_4_upd_info","stg_ap_4_upd_info")
+{
+  TICK_ENT_DYN_THK();
+  STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(4));
+  UPD_BH_UPDATABLE();
+  LDV_ENTER(R1);
+  ENTER_CCS_THUNK(R1);
+  PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,3);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,2);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgClosure_payload(R1,1);
+  R1 = StgClosure_payload(R1,0);
+  Sp = Sp - SIZEOF_StgUpdateFrame - WDS(3);
+  Sp_adj(-1); // for stg_ap_0_ret
+  TICK_UNKNOWN_CALL();
+  TICK_SLOW_CALL_ppp();
+  jump RET_LBL(stg_ap_ppp);
+}
+
+INFO_TABLE(stg_ap_5_upd,5,0,THUNK,"stg_ap_5_upd_info","stg_ap_5_upd_info")
+{
+  TICK_ENT_DYN_THK();
+  STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(5));
+  UPD_BH_UPDATABLE();
+  LDV_ENTER(R1);
+  ENTER_CCS_THUNK(R1);
+  PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,4);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,3);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgClosure_payload(R1,2);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgClosure_payload(R1,1);
+  R1 = StgClosure_payload(R1,0);
+  Sp = Sp - SIZEOF_StgUpdateFrame - WDS(4);
+  Sp_adj(-1); // for stg_ap_0_ret
+  TICK_UNKNOWN_CALL();
+  TICK_SLOW_CALL_pppp();
+  jump RET_LBL(stg_ap_pppp);
+}
+
+INFO_TABLE(stg_ap_6_upd,6,0,THUNK,"stg_ap_6_upd_info","stg_ap_6_upd_info")
+{
+  TICK_ENT_DYN_THK();
+  STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(6));
+  UPD_BH_UPDATABLE();
+  LDV_ENTER(R1);
+  ENTER_CCS_THUNK(R1);
+  PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,5);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,4);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgClosure_payload(R1,3);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgClosure_payload(R1,2);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgClosure_payload(R1,1);
+  R1 = StgClosure_payload(R1,0);
+  Sp = Sp - SIZEOF_StgUpdateFrame - WDS(5);
+  Sp_adj(-1); // for stg_ap_0_ret
+  TICK_UNKNOWN_CALL();
+  TICK_SLOW_CALL_ppppp();
+  jump RET_LBL(stg_ap_ppppp);
+}
+
+INFO_TABLE(stg_ap_7_upd,7,0,THUNK,"stg_ap_7_upd_info","stg_ap_7_upd_info")
+{
+  TICK_ENT_DYN_THK();
+  STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(7));
+  UPD_BH_UPDATABLE();
+  LDV_ENTER(R1);
+  ENTER_CCS_THUNK(R1);
+  PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,6);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,5);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgClosure_payload(R1,4);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgClosure_payload(R1,3);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgClosure_payload(R1,2);
+  W_[Sp-SIZEOF_StgUpdateFrame-WDS(6)] = StgClosure_payload(R1,1);
+  R1 = StgClosure_payload(R1,0);
+  Sp = Sp - SIZEOF_StgUpdateFrame - WDS(6);
+  Sp_adj(-1); // for stg_ap_0_ret
+  TICK_UNKNOWN_CALL();
+  TICK_SLOW_CALL_pppppp();
+  jump RET_LBL(stg_ap_pppppp);
+}
diff --git a/ghc/rts/StgStdThunks.hc b/ghc/rts/StgStdThunks.hc
deleted file mode 100644 (file)
index e8829b2..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: StgStdThunks.hc,v 1.22 2003/04/18 09:40:10 simonmar Exp $
- *
- * (c) The GHC Team, 1998-2000
- *
- * Canned "Standard Form" Thunks
- *
- * ---------------------------------------------------------------------------*/
-
-#include "Stg.h"
-#include "Rts.h"
-#include "StoragePriv.h"
-
-/* -----------------------------------------------------------------------------
-   The code for a thunk that simply extracts a field from a
-   single-constructor datatype depends only on the offset of the field
-   to be selected.
-
-   Here we define some canned "selector" thunks that do just that; any
-   selector thunk appearing in a program will refer to one of these
-   instead of being compiled independently.
-
-   The garbage collector spots selector thunks and reduces them if
-   possible, in order to avoid space leaks resulting from lazy pattern
-   matching.
-   -------------------------------------------------------------------------- */
-
-#define UPD_FRAME_SIZE (sizeofW(StgUpdateFrame)+sizeofW(StgHeader))
-#define NOUPD_FRAME_SIZE (sizeofW(StgHeader))
-
-#ifdef PROFILING
-#define SAVE_CCCS(fs)          CCS_HDR(Sp-fs)=CCCS
-#define GET_SAVED_CCCS  RESTORE_CCCS(CCS_HDR(Sp))
-#define ENTER_CCS(p)    ENTER_CCS_TCL(p)
-#define RET_BITMAP    3
-#define RET_FRAMESIZE 2
-#else
-#define SAVE_CCCS(fs)   /* empty */
-#define GET_SAVED_CCCS  /* empty */
-#define ENTER_CCS(p)    /* empty */
-#define RET_BITMAP    0
-#define RET_FRAMESIZE 0
-#endif
-
-#define SELECTOR_CODE_UPD(offset) \
-  IF_(stg_sel_ret_##offset##_upd_ret);                                 \
-  INFO_TABLE_RET(stg_sel_ret_##offset##_upd_info,stg_sel_ret_##offset##_upd_ret, MK_SMALL_BITMAP(RET_FRAMESIZE, RET_BITMAP), 0, 0, 0, RET_SMALL, static, EF_, 0, 0);   \
-  EF_(stg_sel_ret_##offset##_upd_ret) {                                        \
-    FB_                                                                        \
-      R1.p=(P_)R1.cl->payload[offset];                                 \
-      GET_SAVED_CCCS;                                                  \
-      Sp=Sp+sizeofW(StgHeader);                                                \
-      ENTER();                                                         \
-    FE_                                                                        \
-  }                                                                    \
-                                                                       \
-  EF_(stg_sel_##offset##_upd_entry);                                   \
-  INFO_TABLE_SELECTOR(stg_sel_##offset##_upd_info, stg_sel_##offset##_upd_entry, offset,, EF_, "stg_sel" #offset "_upd_entry", "stg_sel" #offset "_upd_entry");\
-  EF_(stg_sel_##offset##_upd_entry) {                                  \
-    FB_                                                                        \
-      TICK_ENT_DYN_THK();  /* is it static or dynamic?? */              \
-      STK_CHK_NP(UPD_FRAME_SIZE,);                                     \
-      UPD_BH_UPDATABLE(&stg_sel_##offset##_upd_info);                  \
-      LDV_ENTER(R1.cl);                                                        \
-      PUSH_UPD_FRAME(R1.p,0);                                          \
-      ENTER_CCS(R1.p);                                                 \
-      SAVE_CCCS(UPD_FRAME_SIZE);                                       \
-      Sp[-UPD_FRAME_SIZE]=(W_)&stg_sel_ret_##offset##_upd_info;                \
-      R1.p = (P_)R1.cl->payload[0];                                    \
-      Sp=Sp-UPD_FRAME_SIZE;                                            \
-      ENTER();                                                         \
-    FE_                                                                        \
-  }
-
-SELECTOR_CODE_UPD(0);
-SELECTOR_CODE_UPD(1);
-SELECTOR_CODE_UPD(2);
-SELECTOR_CODE_UPD(3);
-SELECTOR_CODE_UPD(4);
-SELECTOR_CODE_UPD(5);
-SELECTOR_CODE_UPD(6);
-SELECTOR_CODE_UPD(7);
-SELECTOR_CODE_UPD(8);
-SELECTOR_CODE_UPD(9);
-SELECTOR_CODE_UPD(10);
-SELECTOR_CODE_UPD(11);
-SELECTOR_CODE_UPD(12);
-SELECTOR_CODE_UPD(13);
-SELECTOR_CODE_UPD(14);
-SELECTOR_CODE_UPD(15);
-
-#define SELECTOR_CODE_NOUPD(offset) \
-  IF_(stg_sel_ret_##offset##_noupd_ret); \
-  INFO_TABLE_RET(stg_sel_ret_##offset##_noupd_info, stg_sel_ret_##offset##_noupd_ret, MK_SMALL_BITMAP(RET_FRAMESIZE, RET_BITMAP), 0, 0, 0, RET_SMALL, static, EF_, 0, 0);      \
-  IF_(stg_sel_ret_##offset##_noupd_ret) {                                      \
-    FB_                                                                        \
-      R1.p=(P_)R1.cl->payload[offset];                                 \
-      GET_SAVED_CCCS;                                                  \
-      Sp=Sp+sizeofW(StgHeader);                                                \
-      JMP_(ENTRY_CODE(*R1.p));                                         \
-    FE_                                                                        \
-  }                                                                    \
-                                                                       \
-  EF_(stg_sel_##offset##_noupd_entry);                                 \
-  INFO_TABLE_SELECTOR(stg_sel_##offset##_noupd_info, stg_sel_##offset##_noupd_entry, offset,, EF_, "stg_sel" #offset "_noupd_entry", "stg_sel" #offset "_noupd_entry");\
-  EF_(stg_sel_##offset##_noupd_entry) {                                        \
-    FB_                                                                        \
-      TICK_ENT_DYN_THK();  /* is it static or dynamic?? */              \
-      STK_CHK_NP(NOUPD_FRAME_SIZE,)                                    \
-      UPD_BH_SINGLE_ENTRY(&stg_sel_##offset##_noupd_info);             \
-      LDV_ENTER(R1.cl);                                                        \
-      TICK_UPDF_OMITTED();                                             \
-      ENTER_CCS(R1.p);                                                 \
-      SAVE_CCCS(NOUPD_FRAME_SIZE);                                     \
-      Sp[-NOUPD_FRAME_SIZE]=(W_)&stg_sel_ret_##offset##_noupd_info;    \
-      R1.p = (P_)R1.cl->payload[0];                                    \
-      Sp=Sp-NOUPD_FRAME_SIZE;                                          \
-      JMP_(ENTRY_CODE(*R1.p));                                         \
-    FE_                                                                        \
-  }
-
-SELECTOR_CODE_NOUPD(0);
-SELECTOR_CODE_NOUPD(1);
-SELECTOR_CODE_NOUPD(2);
-SELECTOR_CODE_NOUPD(3);
-SELECTOR_CODE_NOUPD(4);
-SELECTOR_CODE_NOUPD(5);
-SELECTOR_CODE_NOUPD(6);
-SELECTOR_CODE_NOUPD(7);
-SELECTOR_CODE_NOUPD(8);
-SELECTOR_CODE_NOUPD(9);
-SELECTOR_CODE_NOUPD(10);
-SELECTOR_CODE_NOUPD(11);
-SELECTOR_CODE_NOUPD(12);
-SELECTOR_CODE_NOUPD(13);
-SELECTOR_CODE_NOUPD(14);
-SELECTOR_CODE_NOUPD(15);
-
-/* -----------------------------------------------------------------------------
-   Apply thunks
-
-   An apply thunk is a thunk of the form
-       
-               let z = [x1...xn] \u x1...xn
-               in ...
-
-   We pre-compile some of these because the code is always the same.
-
-   These have to be independent of the update frame size, so the code
-   works when profiling etc.
-   -------------------------------------------------------------------------- */
-
-FN_(stg_ap_1_upd_entry);
-FN_(stg_ap_2_upd_entry);
-FN_(stg_ap_3_upd_entry);
-FN_(stg_ap_4_upd_entry);
-FN_(stg_ap_5_upd_entry);
-FN_(stg_ap_6_upd_entry);
-FN_(stg_ap_7_upd_entry);
-FN_(stg_ap_8_upd_entry);
-
-#define UF_SIZE (sizeofW(StgUpdateFrame))
-
-/* stg_ap_1_upd_info is a bit redundant, but there appears to be a bug
- * in the compiler that means stg_ap_1 is generated occasionally (ToDo)
- */
-
-INFO_TABLE_THUNK(stg_ap_1_upd_info,stg_ap_1_upd_entry,1,1,0,0,0,THUNK_1_0,,EF_,"stg_ap_1_upd_info","stg_ap_1_upd_info");
-FN_(stg_ap_1_upd_entry) {
-  FB_
-  TICK_ENT_DYN_THK();  /* is it static or dynamic?? */
-  STK_CHK_NP(sizeofW(StgUpdateFrame)+1,);
-  UPD_BH_UPDATABLE(&stg_ap_1_upd_info);
-  LDV_ENTER(R1.cl);
-  ENTER_CCS(R1.p);
-  PUSH_UPD_FRAME(R1.p,0);
-  R1.p=(P_)(R1.cl->payload[0]);
-  Sp -= sizeofW(StgUpdateFrame);
-  Sp--; // for stg_ap_0_ret
-  JMP_(stg_ap_0_ret);
-  FE_
-}
-
-INFO_TABLE_THUNK(stg_ap_2_upd_info,stg_ap_2_upd_entry,2,0,0,0,0,THUNK_2_0,,EF_,"stg_ap_2_upd_info","stg_ap_2_upd_info");
-FN_(stg_ap_2_upd_entry) {
-  FB_
-  TICK_ENT_DYN_THK();  /* is it static or dynamic?? */
-  STK_CHK_NP(sizeofW(StgUpdateFrame)+2,);
-  UPD_BH_UPDATABLE(&stg_ap_2_upd_info);
-  LDV_ENTER(R1.cl);
-  ENTER_CCS(R1.p);
-  PUSH_UPD_FRAME(R1.p,0);
-  Sp[-UF_SIZE-1]=(W_)(R1.cl->payload[1]);
-  R1.p=(P_)(R1.cl->payload[0]);
-  Sp -= sizeofW(StgUpdateFrame)+1;
-  Sp--; // for stg_ap_1_ret
-  JMP_(stg_ap_p_ret);
-  FE_
-}
-
-INFO_TABLE_THUNK(stg_ap_3_upd_info,stg_ap_3_upd_entry,3,0,0,0,0,THUNK,,EF_,"stg_ap_3_upd_info","stg_ap_3_upd_info");
-FN_(stg_ap_3_upd_entry) {
-  FB_
-  TICK_ENT_DYN_THK();  /* is it static or dynamic?? */
-  STK_CHK_NP(sizeofW(StgUpdateFrame)+3,);
-  UPD_BH_UPDATABLE(&stg_ap_3_upd_info);
-  LDV_ENTER(R1.cl);
-  ENTER_CCS(R1.p);
-  PUSH_UPD_FRAME(R1.p,0);
-  Sp[-UF_SIZE-1]=(W_)(R1.cl->payload[2]);
-  Sp[-UF_SIZE-2]=(W_)(R1.cl->payload[1]);
-  R1.p=(P_)(R1.cl->payload[0]);
-  Sp -= sizeofW(StgUpdateFrame)+2;
-  Sp--; // for stg_ap_pp_ret
-  JMP_(stg_ap_pp_ret);
-  FE_
-}
-
-INFO_TABLE_THUNK(stg_ap_4_upd_info,stg_ap_4_upd_entry,4,0,0,0,0,THUNK,,EF_,"stg_ap_4_upd_info","stg_ap_4_upd_info");
-FN_(stg_ap_4_upd_entry) {
-  FB_
-  TICK_ENT_DYN_THK();  /* is it static or dynamic?? */
-  STK_CHK_NP(sizeofW(StgUpdateFrame)+4,);
-  UPD_BH_UPDATABLE(&stg_ap_4_upd_info);
-  LDV_ENTER(R1.cl);
-  ENTER_CCS(R1.p);
-  PUSH_UPD_FRAME(R1.p,0);
-  Sp[-UF_SIZE-1]=(W_)(R1.cl->payload[3]);
-  Sp[-UF_SIZE-2]=(W_)(R1.cl->payload[2]);
-  Sp[-UF_SIZE-3]=(W_)(R1.cl->payload[1]);
-  R1.p=(P_)(R1.cl->payload[0]);
-  Sp = Sp - (sizeofW(StgUpdateFrame)+3);
-  Sp--; // for stg_ap_ppp_ret
-  JMP_(stg_ap_ppp_ret);
-  FE_
-}
-
-INFO_TABLE_THUNK(stg_ap_5_upd_info,stg_ap_5_upd_entry,5,0,0,0,0,THUNK,,EF_,"stg_ap_5_upd_info","stg_ap_5_upd_info");
-FN_(stg_ap_5_upd_entry) {
-  FB_
-  TICK_ENT_DYN_THK();  /* is it static or dynamic?? */
-  STK_CHK_NP(sizeofW(StgUpdateFrame)+5,);
-  UPD_BH_UPDATABLE(&stg_ap_5_upd_info);
-  LDV_ENTER(R1.cl);
-  ENTER_CCS(R1.p);
-  PUSH_UPD_FRAME(R1.p,0);
-  Sp[-UF_SIZE-1]=(W_)(R1.cl->payload[4]);
-  Sp[-UF_SIZE-2]=(W_)(R1.cl->payload[3]);
-  Sp[-UF_SIZE-3]=(W_)(R1.cl->payload[2]);
-  Sp[-UF_SIZE-4]=(W_)(R1.cl->payload[1]);
-  R1.p=(P_)(R1.cl->payload[0]);
-  Sp = Sp - (sizeofW(StgUpdateFrame)+4);
-  Sp--; // for stg_ap_pppp_ret
-  JMP_(stg_ap_pppp_ret);
-  FE_
-}
-
-INFO_TABLE_THUNK(stg_ap_6_upd_info,stg_ap_6_upd_entry,6,0,0,0,0,THUNK,,EF_,"stg_ap_6_upd_info","stg_ap_6_upd_info");
-FN_(stg_ap_6_upd_entry) {
-  FB_
-  TICK_ENT_DYN_THK();  /* is it static or dynamic?? */
-  STK_CHK_NP(sizeofW(StgUpdateFrame)+6,);
-  UPD_BH_UPDATABLE(&stg_ap_6_upd_info);
-  LDV_ENTER(R1.cl);
-  ENTER_CCS(R1.p);
-  PUSH_UPD_FRAME(R1.p,0);
-  Sp[-UF_SIZE-1]=(W_)(R1.cl->payload[5]);
-  Sp[-UF_SIZE-2]=(W_)(R1.cl->payload[4]);
-  Sp[-UF_SIZE-3]=(W_)(R1.cl->payload[3]);
-  Sp[-UF_SIZE-4]=(W_)(R1.cl->payload[2]);
-  Sp[-UF_SIZE-5]=(W_)(R1.cl->payload[1]);
-  R1.p=(P_)(R1.cl->payload[0]);
-  Sp = Sp - (sizeofW(StgUpdateFrame)+5);
-  Sp--; // for stg_ap_ppppp_ret
-  JMP_(stg_ap_ppppp_ret);
-  FE_
-}
-
-INFO_TABLE_THUNK(stg_ap_7_upd_info,stg_ap_7_upd_entry,7,0,0,0,0,THUNK,,EF_,"stg_ap_7_upd_info","stg_ap_7_upd_info");
-FN_(stg_ap_7_upd_entry) {
-  FB_
-  TICK_ENT_DYN_THK();  /* is it static or dynamic?? */
-  STK_CHK_NP(sizeofW(StgUpdateFrame)+7,);
-  UPD_BH_UPDATABLE(&stg_ap_7_upd_info);
-  LDV_ENTER(R1.cl);
-  ENTER_CCS(R1.p);
-  PUSH_UPD_FRAME(R1.p,0);
-  Sp[-UF_SIZE-1]=(W_)(R1.cl->payload[6]);
-  Sp[-UF_SIZE-2]=(W_)(R1.cl->payload[5]);
-  Sp[-UF_SIZE-3]=(W_)(R1.cl->payload[4]);
-  Sp[-UF_SIZE-4]=(W_)(R1.cl->payload[3]);
-  Sp[-UF_SIZE-5]=(W_)(R1.cl->payload[2]);
-  Sp[-UF_SIZE-6]=(W_)(R1.cl->payload[1]);
-  R1.p=(P_)(R1.cl->payload[0]);
-  Sp = Sp - (sizeofW(StgUpdateFrame)+6);
-  Sp--; // for stg_ap_pppppp_ret
-  JMP_(stg_ap_pppppp_ret);
-  FE_
-}
-
-INFO_TABLE_THUNK(stg_ap_8_upd_info,stg_ap_8_upd_entry,8,0,0,0,0,THUNK,,EF_,"stg_ap_8_upd_info","stg_ap_8_upd_info");
-FN_(stg_ap_8_upd_entry) {
-  FB_
-  TICK_ENT_DYN_THK();  /* is it static or dynamic?? */
-  STK_CHK_NP(sizeofW(StgUpdateFrame)+8,);
-  UPD_BH_UPDATABLE(&stg_ap_8_upd_info);
-  LDV_ENTER(R1.cl);
-  ENTER_CCS(R1.p);
-  PUSH_UPD_FRAME(R1.p,0);
-  Sp[-UF_SIZE-1]=(W_)(R1.cl->payload[7]);
-  Sp[-UF_SIZE-2]=(W_)(R1.cl->payload[6]);
-  Sp[-UF_SIZE-3]=(W_)(R1.cl->payload[5]);
-  Sp[-UF_SIZE-4]=(W_)(R1.cl->payload[4]);
-  Sp[-UF_SIZE-5]=(W_)(R1.cl->payload[3]);
-  Sp[-UF_SIZE-6]=(W_)(R1.cl->payload[2]);
-  Sp[-UF_SIZE-7]=(W_)(R1.cl->payload[1]);
-  R1.p=(P_)(R1.cl->payload[0]);
-  Sp = Sp - (sizeofW(StgUpdateFrame)+7);
-  Sp--; // for stg_ap_ppppppp_ret
-  JMP_(stg_ap_ppppppp_ret);
-  FE_
-}
index f13f186..367530f 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Storage.c,v 1.83 2004/07/21 10:47:28 simonmar Exp $
+ * $Id: Storage.c,v 1.84 2004/08/13 13:11:01 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -22,7 +22,6 @@
 #include "Storage.h"
 #include "Schedule.h"
 #include "OSThreads.h"
-#include "StoragePriv.h"
 
 #include "RetainerProfile.h"   // for counting memory blocks (memInventory)
 
@@ -621,7 +620,7 @@ stgAllocForGMP (size_t size_in_bytes)
   SET_ARR_HDR(arr, &stg_ARR_WORDS_info, CCCS, data_size_in_words);
   
   /* and return a ptr to the goods inside the array */
-  return(BYTE_ARR_CTS(arr));
+  return arr->payload;
 }
 
 static void *
diff --git a/ghc/rts/StoragePriv.h b/ghc/rts/StoragePriv.h
deleted file mode 100644 (file)
index c829e78..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: StoragePriv.h,v 1.26 2004/07/21 10:47:29 simonmar Exp $
- *
- * (c) The GHC Team, 1998-1999
- *
- * Internal Storage Manger Interface
- *
- * ---------------------------------------------------------------------------*/
-
-#ifndef STORAGEPRIV_H
-#define STORAGEPRIV_H
-
-#include <stddef.h>
-
-#define END_OF_STATIC_LIST stgCast(StgClosure*,1)
-
-extern generation *generations;
-
-extern generation *g0;
-extern step *g0s0;
-extern generation *oldest_gen;
-
-extern void newCAF(StgClosure*);
-extern void newDynCAF(StgClosure *);
-
-extern void move_TSO(StgTSO *src, StgTSO *dest);
-extern StgTSO *relocate_stack(StgTSO *dest, ptrdiff_t diff);
-
-extern StgClosure *static_objects;
-extern StgClosure *scavenged_static_objects;
-
-extern StgWeak *old_weak_ptr_list;
-
-extern StgWeak    *weak_ptr_list;
-extern StgClosure *caf_list;
-
-extern StgTSO *resurrected_threads;
-
-extern bdescr *small_alloc_list;
-extern bdescr *large_alloc_list;
-extern bdescr *pinned_object_block;
-
-extern StgPtr alloc_Hp;
-extern StgPtr alloc_HpLim;
-
-extern bdescr *nursery;
-
-extern nat alloc_blocks;
-extern nat alloc_blocks_lim;
-
-extern ullong total_allocated;
-
-/* Nursery manipulation */
-extern void     allocNurseries ( void );
-extern void     resetNurseries ( void );
-extern bdescr * allocNursery   ( bdescr *last_bd, nat blocks );
-extern void     resizeNursery  ( nat blocks );
-extern void     tidyAllocateLists ( void );
-
-/* Stats 'n' stuff */
-extern lnat calcAllocated  ( void );
-extern lnat calcLive       ( void );
-extern lnat calcNeeded     ( void );
-
-INLINE_HEADER void
-dbl_link_onto(bdescr *bd, bdescr **list)
-{
-  bd->link = *list;
-  bd->u.back = NULL;
-  if (*list) {
-    (*list)->u.back = bd; /* double-link the list */
-  }
-  *list = bd;
-}
-
-/* MUTABLE LISTS
- * A mutable list is ended with END_MUT_LIST, so that we can use NULL
- * as an indication that an object is not on a mutable list.
- */
-#define END_MUT_LIST ((StgMutClosure *)(void *)&stg_END_MUT_LIST_closure)
-
-#ifdef DEBUG
-extern void memInventory(void);
-extern void checkSanity(void);
-extern nat  countBlocks(bdescr *);
-#endif
-
-/* Functions from GC.c 
- */
-extern void         threadPaused ( StgTSO * );
-extern StgClosure * isAlive      ( StgClosure *p );
-extern void         markCAFs     ( evac_fn evac );
-
-#endif /* STORAGEPRIV_H */
index 7d95b0c..92c18ea 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Ticky.c,v 1.17 2002/12/11 15:36:54 simonmar Exp $
+ * $Id: Ticky.c,v 1.18 2004/08/13 13:11:08 simonmar Exp $
  *
  * (c) The AQUA project, Glasgow University, 1992-1997
  * (c) The GHC Team, 1998-1999
@@ -33,36 +33,35 @@ PrintTickyInfo(void)
   unsigned long i;
   unsigned long tot_allocs = /* total number of things allocated */
        ALLOC_FUN_ctr + ALLOC_SE_THK_ctr + ALLOC_UP_THK_ctr + ALLOC_CON_ctr + ALLOC_TUP_ctr +
-       ALLOC_TSO_ctr +
+       + ALLOC_TSO_ctr + ALLOC_BH_ctr  + ALLOC_PAP_ctr + ALLOC_PRIM_ctr
 #ifdef PAR
-       ALLOC_FMBQ_ctr + ALLOC_FME_ctr + ALLOC_BF_ctr +
+       + ALLOC_FMBQ_ctr + ALLOC_FME_ctr + ALLOC_BF_ctr
 #endif
-       ALLOC_BH_ctr  + ALLOC_PAP_ctr + ALLOC_PRIM_ctr;
+      ;        
 
   unsigned long tot_adm_wds = /* total number of admin words allocated */
-       ALLOC_FUN_adm + ALLOC_THK_adm + ALLOC_CON_adm + ALLOC_TUP_adm +
-       ALLOC_TSO_adm +
+       ALLOC_FUN_adm + ALLOC_THK_adm + ALLOC_CON_adm + ALLOC_TUP_adm
+       + ALLOC_TSO_adm + ALLOC_BH_adm  + ALLOC_PAP_adm + ALLOC_PRIM_adm
 #ifdef PAR
-       ALLOC_FMBQ_adm + ALLOC_FME_adm + ALLOC_BF_adm +
+       + ALLOC_FMBQ_adm + ALLOC_FME_adm + ALLOC_BF_adm
 #endif
-       ALLOC_BH_adm  + ALLOC_PAP_adm + ALLOC_PRIM_adm;
+      ;
 
   unsigned long tot_gds_wds = /* total number of words of ``good stuff'' allocated */
-       ALLOC_FUN_gds + ALLOC_THK_gds + ALLOC_CON_gds + ALLOC_TUP_gds +
-       ALLOC_TSO_gds +
+       ALLOC_FUN_gds + ALLOC_THK_gds + ALLOC_CON_gds + ALLOC_TUP_gds
+       + ALLOC_TSO_gds + ALLOC_BH_gds  + ALLOC_PAP_gds + ALLOC_PRIM_gds
 #ifdef PAR
-       ALLOC_FMBQ_gds + ALLOC_FME_gds + ALLOC_BF_gds +
+       + ALLOC_FMBQ_gds + ALLOC_FME_gds + ALLOC_BF_gds
 #endif
-
-       ALLOC_BH_gds  + ALLOC_PAP_gds + ALLOC_PRIM_gds;
+      ;
 
   unsigned long tot_slp_wds = /* total number of ``slop'' words allocated */
-       ALLOC_FUN_slp + ALLOC_THK_slp + ALLOC_CON_slp + ALLOC_TUP_slp +
-       ALLOC_TSO_slp +
+       ALLOC_FUN_slp + ALLOC_THK_slp + ALLOC_CON_slp + ALLOC_TUP_slp
+       + ALLOC_TSO_slp + ALLOC_BH_slp  + ALLOC_PAP_slp + ALLOC_PRIM_slp
 #ifdef PAR
-       ALLOC_FMBQ_slp + ALLOC_FME_slp + ALLOC_BF_slp +
+       + ALLOC_FMBQ_slp + ALLOC_FME_slp + ALLOC_BF_slp
 #endif
-       ALLOC_BH_slp  + ALLOC_PAP_slp + ALLOC_PRIM_slp;
+      ;
 
   unsigned long tot_wds = /* total words */
        tot_adm_wds + tot_gds_wds + tot_slp_wds;
@@ -72,10 +71,19 @@ PrintTickyInfo(void)
   unsigned long tot_fun_direct_enters = ENT_STATIC_FUN_DIRECT_ctr + ENT_DYN_FUN_DIRECT_ctr;
   unsigned long tot_ind_enters = ENT_STATIC_IND_ctr + ENT_DYN_IND_ctr;
   
-  // This is the number of function calls which went via a
-  // slow/unknown application (one of the stg_ap_ functions).
-  unsigned long tot_fun_slow_enters =
-      SLOW_CALL_ctr - SLOW_CALL_BUILT_PAP_ctr - SLOW_CALL_NEW_PAP_ctr;
+  // This is the number of times we entered a function via some kind
+  // of slow call.  It amounts to all the slow applications, not
+  // counting those that were to too few arguments.
+  unsigned long tot_fun_slow_enters = 
+      SLOW_CALL_ctr - 
+      SLOW_CALL_FUN_TOO_FEW_ctr -
+      SLOW_CALL_PAP_TOO_FEW_ctr;
+
+  unsigned long tot_known_calls =
+      KNOWN_CALL_ctr + KNOWN_CALL_TOO_FEW_ARGS_ctr + 
+      + KNOWN_CALL_EXTRA_ARGS_ctr;
+  unsigned long tot_tail_calls =
+      UNKNOWN_CALL_ctr + tot_known_calls;
 
   unsigned long tot_enters =
        tot_con_enters + tot_fun_direct_enters +
@@ -201,11 +209,21 @@ PrintTickyInfo(void)
        ENT_PERM_IND_ctr,
        PC(INTAVG(ENT_PERM_IND_ctr,tot_enters)));
 
-  fprintf(tf,"\nCALLS: %ld  of which %ld (%.lf%%) were slow/unknown calls\n\t\t  [the rest went direct to the fast entry point]\n",
-         tot_fun_direct_enters,
-         tot_fun_slow_enters,
-         PC(INTAVG(tot_fun_slow_enters,tot_fun_direct_enters))
-      );
+  fprintf(tf,"\nFUNCTION ENTRIES: %ld\n", tot_fun_direct_enters);
+
+  fprintf(tf, "\nTAIL CALLS: %ld, of which %ld (%.lf%%) were to known functions\n", 
+         tot_tail_calls, tot_known_calls,
+         PC(INTAVG(tot_known_calls,tot_tail_calls)));
+
+  fprintf(tf, "\nSLOW APPLICATIONS: %ld evaluated, %ld unevaluated\n",
+         SLOW_CALL_ctr, SLOW_CALL_UNEVALD_ctr);
+  fprintf(tf, "\n");
+  fprintf(tf, "         Too few args   Correct args   Too many args\n");
+  fprintf(tf, "   FUN     %8ld       %8ld        %8ld\n", 
+         SLOW_CALL_FUN_TOO_FEW_ctr, SLOW_CALL_FUN_CORRECT_ctr, SLOW_CALL_FUN_TOO_MANY_ctr);
+  fprintf(tf, "   PAP     %8ld       %8ld        %8ld\n", 
+         SLOW_CALL_PAP_TOO_FEW_ctr, SLOW_CALL_PAP_CORRECT_ctr, SLOW_CALL_PAP_TOO_MANY_ctr);
+  fprintf(tf, "\n");
 
   fprintf(tf,"\nRETURNS: %ld\n", tot_returns);
   fprintf(tf,"%7ld (%5.1f%%) from entering a new constructor\n\t\t  [the rest from entering an existing constructor]\n",
@@ -434,9 +452,36 @@ PrintTickyInfo(void)
   PR_CTR(ENT_STATIC_THK_ctr);
   PR_CTR(ENT_DYN_THK_ctr);
 
+  PR_CTR(SLOW_CALL_v_ctr);
+  PR_CTR(SLOW_CALL_f_ctr);
+  PR_CTR(SLOW_CALL_d_ctr);
+  PR_CTR(SLOW_CALL_l_ctr);
+  PR_CTR(SLOW_CALL_n_ctr);
+  PR_CTR(SLOW_CALL_p_ctr);
+  PR_CTR(SLOW_CALL_pv_ctr);
+  PR_CTR(SLOW_CALL_pp_ctr);
+  PR_CTR(SLOW_CALL_ppv_ctr);
+  PR_CTR(SLOW_CALL_ppp_ctr);
+  PR_CTR(SLOW_CALL_pppv_ctr);
+  PR_CTR(SLOW_CALL_pppp_ctr);
+  PR_CTR(SLOW_CALL_ppppp_ctr);
+  PR_CTR(SLOW_CALL_pppppp_ctr);
+  PR_CTR(SLOW_CALL_OTHER_ctr);
+
+  PR_CTR(UNKNOWN_CALL_ctr);
+  PR_CTR(KNOWN_CALL_ctr);
+  PR_CTR(KNOWN_CALL_TOO_FEW_ARGS_ctr);
+  PR_CTR(KNOWN_CALL_EXTRA_ARGS_ctr);
+  PR_CTR(MULTI_CHUNK_SLOW_CALL_ctr);
+  PR_CTR(MULTI_CHUNK_SLOW_CALL_CHUNKS_ctr);
   PR_CTR(SLOW_CALL_ctr);
-  PR_CTR(SLOW_CALL_BUILT_PAP_ctr);
-  PR_CTR(SLOW_CALL_NEW_PAP_ctr);
+  PR_CTR(SLOW_CALL_FUN_TOO_FEW_ctr);
+  PR_CTR(SLOW_CALL_FUN_CORRECT_ctr);
+  PR_CTR(SLOW_CALL_FUN_TOO_MANY_ctr);
+  PR_CTR(SLOW_CALL_PAP_TOO_FEW_ctr);
+  PR_CTR(SLOW_CALL_PAP_CORRECT_ctr);
+  PR_CTR(SLOW_CALL_PAP_TOO_MANY_ctr);
+  PR_CTR(SLOW_CALL_UNEVALD_ctr);
   PR_HST(SLOW_CALL_hst,0);
   PR_HST(SLOW_CALL_hst,1);
   PR_HST(SLOW_CALL_hst,2);
@@ -553,8 +598,8 @@ printRegisteredCounterInfo (FILE *tf)
     if ( ticky_entry_ctrs != NULL ) {
       fprintf(tf,"\n**************************************************\n\n");
     }
-    fprintf(tf, "%11s%11s%11s %6s%6s    %-11s%-30s\n",
-           "Entries", "Slow ent", "Allocs", "Arity", "Stack", "Kinds", "Function");
+    fprintf(tf, "%11s%11s %6s%6s    %-11s%-30s\n",
+           "Entries", "Allocs", "Arity", "Stack", "Kinds", "Function");
     fprintf(tf, "--------------------------------------------------------------------------------\n");
     /* Function name at the end so it doesn't mess up the tabulation */
 
similarity index 55%
rename from ghc/rts/Updates.hc
rename to ghc/rts/Updates.cmm
index 5965ea9..02d1827 100644 (file)
@@ -1,20 +1,18 @@
 /* -----------------------------------------------------------------------------
- * $Id: Updates.hc,v 1.41 2003/07/28 15:57:40 simonmar Exp $
  *
- * (c) The GHC Team, 1998-2002
+ * (c) The GHC Team, 1998-2004
  *
  * Code to perform updates.
  *
+ * This file is written in a subset of C--, extended with various
+ * features specific to GHC.  It is compiled by GHC directly.  For the
+ * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
+ *
  * ---------------------------------------------------------------------------*/
 
-#include "Stg.h"
-#include "Rts.h"
-#include "RtsUtils.h"
-#include "RtsFlags.h"
-#include "Storage.h"
-#if defined(GRAN) || defined(PAR)
-# include "FetchMe.h"
-#endif
+#include "Cmm.h"
+#include "Updates.h"
+#include "StgLdvProf.h"
 
 /*
   The update frame return address must be *polymorphic*, that means
@@ -33,9 +31,9 @@
 /* on entry to the update code
    (1) R1 points to the closure being returned
    (2) Sp points to the update frame
-   */
+*/
 
-/* The update fragment has been tuned so as to generate reasonable
+/* The update fragment has been tuned so as to generate good
    code with gcc, which accounts for some of the strangeness in the
    way it is written.  
 
 */
 
 #define UPD_FRAME_ENTRY_TEMPLATE(label,ind_info,ret)                   \
-        STGFUN(label);                                                 \
-       STGFUN(label)                                                   \
+        label                                                          \
        {                                                               \
-          StgClosure *updatee;                                         \
-         FB_                                                           \
+          W_ updatee;                                                  \
                                                                        \
-          updatee = ((StgUpdateFrame *)Sp)->updatee;                   \
+          updatee = StgUpdateFrame_updatee(Sp);                                \
                                                                        \
          /* remove the update frame from the stack */                  \
-         Sp += sizeofW(StgUpdateFrame);                                \
+         Sp = Sp + SIZEOF_StgUpdateFrame;                              \
                                                                        \
          /* ToDo: it might be a PAP, so we should check... */          \
-         TICK_UPD_CON_IN_NEW(sizeW_fromITBL(get_itbl(updatee)));       \
+         TICK_UPD_CON_IN_NEW(sizeW_fromITBL(%GET_STD_INFO(updatee)));  \
                                                                        \
-         UPD_SPEC_IND(updatee, ind_info, R1.cl, JMP_(ret));            \
-         FE_                                                           \
+         UPD_SPEC_IND(updatee, ind_info, R1, jump (ret));              \
        }
 
-UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_ret,&stg_IND_direct_info,ENTRY_CODE(Sp[0]));
-UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_0_ret,&stg_IND_0_info,RET_VEC(Sp[0],0));
-UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_1_ret,&stg_IND_1_info,RET_VEC(Sp[0],1));
-UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_2_ret,&stg_IND_2_info,RET_VEC(Sp[0],2));
-UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_3_ret,&stg_IND_3_info,RET_VEC(Sp[0],3));
-UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_4_ret,&stg_IND_4_info,RET_VEC(Sp[0],4));
-UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_5_ret,&stg_IND_5_info,RET_VEC(Sp[0],5));
-UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_6_ret,&stg_IND_6_info,RET_VEC(Sp[0],6));
-UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_7_ret,&stg_IND_7_info,RET_VEC(Sp[0],7));
+UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_0_ret,stg_IND_0_info,%RET_VEC(Sp(0),0))
+UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_1_ret,stg_IND_1_info,%RET_VEC(Sp(0),1))
+UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_2_ret,stg_IND_2_info,%RET_VEC(Sp(0),2))
+UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_3_ret,stg_IND_3_info,%RET_VEC(Sp(0),3))
+UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_4_ret,stg_IND_4_info,%RET_VEC(Sp(0),4))
+UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_5_ret,stg_IND_5_info,%RET_VEC(Sp(0),5))
+UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_6_ret,stg_IND_6_info,%RET_VEC(Sp(0),6))
+UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_7_ret,stg_IND_7_info,%RET_VEC(Sp(0),7))
+
+#if MAX_VECTORED_RTN > 8
+#error MAX_VECTORED_RTN has changed: please modify stg_upd_frame too.
+#endif
 
 /*
   Make sure this table is big enough to handle the maximum vectored
@@ -91,10 +89,18 @@ UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_7_ret,&stg_IND_7_info,RET_VEC(Sp[0],7));
  * there's a cost-centre-stack in there too).
  */
 
-VEC_POLY_INFO_TABLE( stg_upd_frame, 
-                    MK_SMALL_BITMAP(UPD_FRAME_WORDS, UPD_FRAME_BITMAP),
-                    0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/,
-                    UPDATE_FRAME,, EF_);
+INFO_TABLE_RET( stg_upd_frame, 
+           UPD_FRAME_WORDS, UPD_FRAME_BITMAP, UPDATE_FRAME,
+           stg_upd_frame_0_ret,
+           stg_upd_frame_1_ret,
+           stg_upd_frame_2_ret,
+           stg_upd_frame_3_ret,
+           stg_upd_frame_4_ret,
+           stg_upd_frame_5_ret,
+           stg_upd_frame_6_ret,
+           stg_upd_frame_7_ret
+           )
+UPD_FRAME_ENTRY_TEMPLATE(,stg_IND_direct_info,%ENTRY_CODE(Sp(0)))
 
 /*-----------------------------------------------------------------------------
   Seq frames 
@@ -113,26 +119,21 @@ VEC_POLY_INFO_TABLE( stg_upd_frame,
   into a direct one.
   -------------------------------------------------------------------------- */
 
-IF_(stg_seq_frame_ret);
-
-#define stg_seq_frame_0_ret stg_seq_frame_ret
-#define stg_seq_frame_1_ret stg_seq_frame_ret
-#define stg_seq_frame_2_ret stg_seq_frame_ret
-#define stg_seq_frame_3_ret stg_seq_frame_ret
-#define stg_seq_frame_4_ret stg_seq_frame_ret
-#define stg_seq_frame_5_ret stg_seq_frame_ret
-#define stg_seq_frame_6_ret stg_seq_frame_ret
-#define stg_seq_frame_7_ret stg_seq_frame_ret
-
-VEC_POLY_INFO_TABLE( stg_seq_frame,
-                    MK_SMALL_BITMAP(0, 0),
-                    0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/,
-                    RET_SMALL,, EF_);
+#if MAX_VECTORED_RTN > 8
+#error MAX_VECTORED_RTN has changed: please modify stg_seq_frame too.
+#endif
 
-IF_(stg_seq_frame_ret)
+INFO_TABLE_RET( stg_seq_frame, 0/* words */, 0/* bitmap */, RET_SMALL,
+       RET_LBL(stg_seq_frame), /* 0 */
+       RET_LBL(stg_seq_frame), /* 1 */
+       RET_LBL(stg_seq_frame), /* 2 */
+       RET_LBL(stg_seq_frame), /* 3 */
+       RET_LBL(stg_seq_frame), /* 4 */
+       RET_LBL(stg_seq_frame), /* 5 */
+       RET_LBL(stg_seq_frame), /* 6 */
+       RET_LBL(stg_seq_frame)  /* 7 */
+       )
 {
-   FB_
-   Sp ++;
-   JMP_(ENTRY_CODE(Sp[0]));
-   FE_
+   Sp_adj(1);
+   jump %ENTRY_CODE(Sp(0));
 }
index 462cecc..ccb9eb2 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Weak.c,v 1.31 2003/10/24 09:00:59 simonmar Exp $
+ * $Id: Weak.c,v 1.32 2004/08/13 13:11:13 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -39,7 +39,7 @@ finalizeWeakPointersNow(void)
   while ((w = weak_ptr_list)) {
     weak_ptr_list = w->link;
     if (w->header.info != &stg_DEAD_WEAK_info) {
-       w->header.info = &stg_DEAD_WEAK_info;
+       SET_HDR(w, &stg_DEAD_WEAK_info, w->header.prof.ccs);
        IF_DEBUG(weak,fprintf(stderr,"Finalising weak pointer at %p -> %p\n", w, w->key));
        if (w->finalizer != &stg_NO_FINALIZER_closure) {
            rts_evalLazyIO(w->finalizer,NULL);
index f6dbef1..1cdb4d7 100644 (file)
@@ -1,16 +1,16 @@
 /* -----------------------------------------------------------------------------
- * $Id: Weak.h,v 1.4 1999/02/11 17:40:28 simonm Exp $
  *
- * (c) The GHC Team, 1998-1999
+ * (c) The GHC Team, 1998-2004
  *
  * Weak pointers / finalizers
  *
  * ---------------------------------------------------------------------------*/
 
-extern StgWeak *weak_ptr_list;
+#ifndef WEAK_H
+#define WEAK_H
 
 void finalizeWeakPointersNow(void);
 void scheduleFinalizers(StgWeak *w);
 void markWeakList(void);
 
-
+#endif
index 33f6791..e1af341 100644 (file)
@@ -1,5 +1,5 @@
-#include "config.h"
-#include "Derived.h"
+#include "ghcconfig.h"
+#include "RtsConfig.h"
 
 /* The RTS is just another package! */
 Package {
index 4cc2ad7..b64555e 100644 (file)
@@ -1,24 +1,28 @@
 {-# OPTIONS -cpp #-}
 module Main(main) where
 
-#include "../../includes/config.h"
+#include "../../includes/ghcconfig.h"
 #include "../../includes/MachRegs.h"
+#include "../../includes/Constants.h"
+
 
 #if __GLASGOW_HASKELL__ >= 504
 import Text.PrettyPrint
 import Data.Word
 import Data.Bits
 import Data.List       ( intersperse )
-import Data.Char       ( toUpper )
+import System.Exit
+import System.Environment
+import System.IO
 #else
+import System
+import IO
 import Bits
 import Word
 import Pretty
 import List            ( intersperse )
-import Char            ( toUpper )
 #endif
 
-
 -- -----------------------------------------------------------------------------
 -- Argument kinds (rougly equivalent to PrimRep)
 
@@ -55,10 +59,13 @@ isPtr _ = False
 -- -----------------------------------------------------------------------------
 -- Registers
 
+data RegStatus = Registerised | Unregisterised
+
 type Reg = String
 
-availableRegs :: ([Reg],[Reg],[Reg],[Reg])
-availableRegs = 
+availableRegs :: RegStatus -> ([Reg],[Reg],[Reg],[Reg])
+availableRegs Unregisterised = ([],[],[],[])
+availableRegs Registerised =
   ( vanillaRegs MAX_REAL_VANILLA_REG,
     floatRegs   MAX_REAL_FLOAT_REG,
     doubleRegs  MAX_REAL_DOUBLE_REG,
@@ -66,7 +73,7 @@ availableRegs =
   )
 
 vanillaRegs, floatRegs, doubleRegs, longRegs :: Int -> [Reg]
-vanillaRegs n = [ "R" ++ show m ++ ".w" | m <- [2..n] ]  -- never use R1
+vanillaRegs n = [ "R" ++ show m | m <- [2..n] ]  -- never use R1
 floatRegs   n = [ "F" ++ show m | m <- [1..n] ]
 doubleRegs  n = [ "D" ++ show m | m <- [1..n] ]
 longRegs    n = [ "L" ++ show m | m <- [1..n] ]
@@ -74,25 +81,29 @@ longRegs    n = [ "L" ++ show m | m <- [1..n] ]
 -- -----------------------------------------------------------------------------
 -- Loading/saving register arguments to the stack
 
-loadRegArgs :: Int -> [ArgRep] -> (Doc,Int)
-loadRegArgs sp args = (vcat (map (uncurry assign_stk_to_reg) reg_locs), sp')
+loadRegArgs :: RegStatus -> Int -> [ArgRep] -> (Doc,Int)
+loadRegArgs regstatus sp args 
+ = (vcat (map (uncurry assign_stk_to_reg) reg_locs), sp')
  where
-  (reg_locs, sp') = assignRegs sp args
+  (reg_locs, _leftovers, sp') = assignRegs regstatus sp args
 
 -- a bit like assignRegs in CgRetConv.lhs
 assignRegs
-       :: Int                  -- Sp of first arg
+       :: RegStatus            -- are we registerised?
+       -> Int                  -- Sp of first arg
        -> [ArgRep]             -- args
-       -> ([(Reg,Int)], Int)   -- Sp and rest of args
-assignRegs sp args = assign sp args availableRegs []
+       -> ([(Reg,Int)],        -- regs and offsets to load
+           [ArgRep],           -- left-over args
+           Int)                -- Sp of left-over args
+assignRegs regstatus sp args = assign sp args (availableRegs regstatus) []
 
-assign sp [] regs doc = (doc, sp)
+assign sp [] regs doc = (doc, [], sp)
 assign sp (V : args) regs doc = assign sp args regs doc
 assign sp (arg : args) regs doc
  = case findAvailableReg arg regs of
     Just (reg, regs') -> assign (sp + argSize arg)  args regs' 
                            ((reg, sp) : doc)
-    Nothing -> (doc, sp)
+    Nothing -> (doc, (arg:args), sp)
 
 findAvailableReg N (vreg:vregs, fregs, dregs, lregs) =
   Just (vreg, (vregs,fregs,dregs,lregs))
@@ -106,24 +117,19 @@ findAvailableReg L (vregs, fregs, dregs, lreg:lregs) =
   Just (lreg, (vregs,fregs,dregs,lregs))
 findAvailableReg _ _ = Nothing
 
-assign_reg_to_stk reg@('F':_) sp
-   = text "ASSIGN_FLT(Sp+" <> int sp <> comma <> text reg <> text ");"
-assign_reg_to_stk reg@('D':_) sp
-   = text "ASSIGN_DBL(Sp+" <> int sp <> comma <> text reg <> text ");"
-assign_reg_to_stk reg@('L':_) sp
-   = text "ASSIGN_Word64(Sp+" <> int sp <> comma <> text reg <> text ");"
 assign_reg_to_stk reg sp
-   = text "Sp[" <> int sp <> text "] = " <> text reg <> semi
-
-assign_stk_to_reg reg@('F':_) sp
-   = text reg <> text " = "  <> text "PK_FLT(Sp+" <> int sp <> text ");"
-assign_stk_to_reg reg@('D':_) sp
-   = text reg <> text " = "  <> text "PK_DBL(Sp+" <> int sp <> text ");"
-assign_stk_to_reg reg@('L':_) sp
-   = text reg <> text " = "  <> text "PK_Word64(Sp+" <> int sp <> text ");"
+   = loadSpWordOff (regRep reg) sp <> text " = " <> text reg <> semi
+
 assign_stk_to_reg reg sp
-   = text reg <> text " = Sp[" <> int sp <> text "];"
+   = text reg <> text " = " <> loadSpWordOff (regRep reg) sp <> semi
+
+regRep ('F':_) = "F_"
+regRep ('D':_) = "D_"
+regRep ('L':_) = "L_"
+regRep _       = "W_"
 
+loadSpWordOff :: String -> Int -> Doc
+loadSpWordOff rep off = text rep <> text "[Sp+WDS(" <> int off <> text ")]"
 
 -- make a ptr/non-ptr bitmap from a list of argument types
 mkBitmap :: [ArgRep] -> Word32
@@ -151,13 +157,17 @@ mkBitmap args = foldr f 0 args
 -- the args anyway (this might not be true of register-rich machines
 -- when we start passing args to stg_ap_* in regs).
 
+mkApplyName args
+  = text "stg_ap_" <> text (map showArg args)
+
 mkApplyRetName args
-  = text "stg_ap_" <> text (map showArg args) <> text "_ret"
+  = mkApplyName args <> text "_ret"
 
 mkApplyInfoName args
-  = text "stg_ap_" <> text (map showArg args) <> text "_info"
+  = mkApplyName args <> text "_info"
 
-genMkPAP macro jump stack_apply is_pap args all_args_size fun_info_label
+genMkPAP regstatus macro jump ticker disamb stack_apply 
+       is_pap args all_args_size fun_info_label
   =  smaller_arity_cases
   $$ exact_arity_case
   $$ larger_arity_case
@@ -181,21 +191,22 @@ genMkPAP macro jump stack_apply is_pap args all_args_size fun_info_label
           let
             (reg_doc, sp')
                | stack_apply = (empty, arg_sp_offset)
-               | otherwise   = loadRegArgs arg_sp_offset these_args
+               | otherwise   = loadRegArgs regstatus arg_sp_offset these_args
           in
            nest 4 (vcat [
+            text "TICK_SLOW_CALL_" <> text ticker <> text "_TOO_MANY();",
             reg_doc,
             vcat [ shuffle_down j | j <- [sp'..these_args_size] ],
-            text "Sp[" <> int these_args_size <>  text "] = (W_)&" <>
+            loadSpWordOff "W_" these_args_size <> text " = " <>
                 mkApplyInfoName rest_args <> semi,
-            text "Sp += " <> int (sp' -  1) <> semi,
+            text "Sp_adj(" <> int (sp' -  1) <> text ");",
                -- for a PAP, we have to arrange that the stack contains a
                -- return address in the even that stg_PAP_entry fails its
                -- heap check.  See stg_PAP_entry in Apply.hc for details.
             if is_pap 
-               then text "R2.w = (W_)&" <> mkApplyInfoName these_args <> semi
+               then text "R2 = " <> mkApplyInfoName these_args <> semi
                else empty,
-            text "JMP_" <> parens (text jump) <> semi
+            text "jump " <> text jump <> semi
            ]) $$
           text "}"
        where
@@ -203,8 +214,8 @@ genMkPAP macro jump stack_apply is_pap args all_args_size fun_info_label
                these_args_size = sum (map argSize these_args)
                
                shuffle_down i = 
-                 text "Sp[" <> int (i-1) <> text "] = Sp["
-                    <> int i <> text "];"
+                 loadSpWordOff "W_" (i-1) <> text " = " <>
+                 loadSpWordOff "W_" i <> semi
 
 -- The EXACT ARITY case
 --
@@ -217,15 +228,16 @@ genMkPAP macro jump stack_apply is_pap args all_args_size fun_info_label
          let
             (reg_doc, sp')
                | stack_apply = (empty, arg_sp_offset)
-               | otherwise   = loadRegArgs arg_sp_offset args
+               | otherwise   = loadRegArgs regstatus arg_sp_offset args
          in
          nest 4 (vcat [
+           text "TICK_SLOW_CALL_" <> text ticker <> text "_CORRECT();",
            reg_doc,
-           text "Sp += " <> int sp' <> semi,
+           text "Sp_adj(" <> int sp' <> text ");",
            if is_pap 
-               then text "R2.w = (W_)&" <> fun_info_label <> semi
+               then text "R2 = " <> fun_info_label <> semi
                else empty,
-           text "JMP_" <> parens (text jump) <> semi
+           text "jump " <> text jump <> semi
          ])
 
 -- The LARGER ARITY cases:
@@ -236,12 +248,14 @@ genMkPAP macro jump stack_apply is_pap args all_args_size fun_info_label
 
     larger_arity_case = 
           text "} else {" $$
-          nest 4 (
+          nest 4 (vcat [
+               text "TICK_SLOW_CALL_" <> text ticker <> text "_TOO_FEW();",
                text macro <> char '(' <> int n_args <> comma <> 
                                        int all_args_size <>  
-                                       text ",(W_)&" <> fun_info_label <>
+                                       text "," <> fun_info_label <>
+                                       text "," <> text disamb <>
                                        text ");"
-          ) $$
+          ]) $$
           char '}'
 
 -- -----------------------------------------------------------------------------
@@ -249,23 +263,20 @@ genMkPAP macro jump stack_apply is_pap args all_args_size fun_info_label
 
 -- args is a list of 'p', 'n', 'f', 'd' or 'l'
 
-genApply args =
+genApply regstatus args =
    let
     fun_ret_label  = mkApplyRetName args
     fun_info_label = mkApplyInfoName args
     all_args_size  = sum (map argSize args)
    in
     vcat [
-      text "INFO_TABLE_RET(" <> fun_info_label <> text "," <>
-       fun_ret_label <> text "," <>
-        text "MK_SMALL_BITMAP(" <> int all_args_size <> text "/*framsize*/," <>
-       int (fromIntegral (mkBitmap args)) <> text "/*bitmap*/), " <>
-        text "0,0,0,RET_SMALL,,EF_,0,0);",
-      text "",
-      text "F_ " <> fun_ret_label <> text "( void )\n{",
+      text "INFO_TABLE_RET(" <> mkApplyName args <> text ", " <>
+        int all_args_size <> text "/*framsize*/," <>
+       int (fromIntegral (mkBitmap args)) <> text "/*bitmap*/, " <>
+        text "RET_SMALL)\n{",
       nest 4 (vcat [
-       text "StgInfoTable *info;",
-       text "nat arity;",
+       text "W_ info;",
+       text "W_ arity;",
 
 --    if fast == 1:
 --        print "static void *lbls[] ="
@@ -292,13 +303,12 @@ genApply args =
 --        print "    [IND_OLDGEN_PERM] &&ind_lbl"
 --        print "  };"
     
-       text "FB_",
        text "",
-       text "IF_DEBUG(apply,fprintf(stderr, \"" <> fun_ret_label <> 
-         text "... \"); printClosure(R1.cl));",
+       text "IF_DEBUG(apply,foreign \"C\" fprintf(stderr, \"" <> fun_ret_label <> 
+         text "... \"); foreign \"C\" printClosure(R1 \"ptr\"));",
 
-       text "IF_DEBUG(sanity,checkStackFrame(Sp+" <> int (1 + all_args_size)
-       <> text "));",
+       text "IF_DEBUG(sanity,foreign \"C\" checkStackFrame(Sp+WDS(" <> int (1 + all_args_size)
+       <> text ")\"ptr\"));",
 
 --       text "IF_DEBUG(sanity,checkStackChunk(Sp+" <> int (1 + all_args_size) <>
 --       text ", CurrentTSO->stack + CurrentTSO->stack_size));",
@@ -309,115 +319,121 @@ genApply args =
           do_assert (arg:args) offset
                | isPtr arg = this : rest
                | otherwise = rest
-               where this = text "ASSERT(LOOKS_LIKE_CLOSURE_PTR(Sp[" 
-                                <> int offset <> text "]));"
+               where this = text "ASSERT(LOOKS_LIKE_CLOSURE_PTR(Sp(" 
+                                <> int offset <> text ")));"
                      rest = do_assert args (offset + argSize arg)
        in
        vcat (do_assert args 1),
-        
+
        text  "again:",
-       text  "info = get_itbl(R1.cl);",
+       text  "info = %GET_STD_INFO(R1);",
 
 --    if fast == 1:
 --        print "    goto *lbls[info->type];";
 --    else:
-        text "switch (info->type) {" $$
-        nest 4 (vcat [
+        text "switch [INVALID_OBJECT .. N_CLOSURE_TYPES] (%INFO_TYPE(info)) {",
+       nest 4 (vcat [
 
 --    if fast == 1:
 --        print "    bco_lbl:"
 --    else:
-       text "case BCO:",
+       text "case BCO: {",
        nest 4 (vcat [
-         text "arity = ((StgBCO *)R1.p)->arity;",
+         text "arity = TO_W_(StgBCO_arity(R1));",
          text "ASSERT(arity > 0);",
-         genMkPAP "BUILD_PAP" "stg_BCO_entry" 
+         genMkPAP regstatus "BUILD_PAP" "ENTRY_LBL(stg_BCO)" "FUN" "BCO"
                True{-stack apply-} False{-not a PAP-}
                args all_args_size fun_info_label
         ]),
+       text "}",
 
 --    if fast == 1:
 --        print "    fun_lbl:"
 --    else:
-        text "case FUN:",
-        text "case FUN_1_0:",
-        text "case FUN_0_1:",
-        text "case FUN_2_0:",
-        text "case FUN_1_1:",
-        text "case FUN_0_2:",
-        text "case FUN_STATIC:",
+        text "case FUN,",
+        text "     FUN_1_0,",
+        text "     FUN_0_1,",
+        text "     FUN_2_0,",
+        text "     FUN_1_1,",
+        text "     FUN_0_2,",
+        text "     FUN_STATIC: {",
        nest 4 (vcat [
-         text "arity = itbl_to_fun_itbl(info)->arity;",
+         text "arity = TO_W_(StgFunInfoExtra_arity(%GET_FUN_INFO(R1)));",
          text "ASSERT(arity > 0);",
-          genMkPAP "BUILD_PAP" "GET_ENTRY(R1.cl)" 
+          genMkPAP regstatus "BUILD_PAP" "%GET_ENTRY(R1)" "FUN" "FUN"
                False{-reg apply-} False{-not a PAP-}
                args all_args_size fun_info_label
         ]),
+       text "}",
 
 --    if fast == 1:
 --        print "    pap_lbl:"
 --    else:
 
-       text "case PAP:",
+       text "case PAP: {",
        nest 4 (vcat [
-         text "arity = ((StgPAP *)R1.p)->arity;",
+         text "arity = TO_W_(StgPAP_arity(R1));",
          text "ASSERT(arity > 0);",
-         genMkPAP "NEW_PAP" "stg_PAP_entry" 
+         genMkPAP regstatus "NEW_PAP" "ENTRY_LBL(stg_PAP)" "PAP" "PAP"
                True{-stack apply-} True{-is a PAP-}
                args all_args_size fun_info_label
         ]),
+       text "}",
 
        text "",
 
 --    if fast == 1:
 --        print "    thunk_lbl:"
 --    else:
-       text "case AP:",
-       text "case AP_STACK:",
-       text "case CAF_BLACKHOLE:",
-       text "case BLACKHOLE:",
-       text "case BLACKHOLE_BQ:",
-       text "case SE_BLACKHOLE:",
-       text "case SE_CAF_BLACKHOLE:",
-        text "case THUNK:",
-        text "case THUNK_1_0:",
-        text "case THUNK_0_1:",
-        text "case THUNK_2_0:",
-        text "case THUNK_1_1:",
-        text "case THUNK_0_2:",
-        text "case THUNK_STATIC:",
-        text "case THUNK_SELECTOR:",
+       text "case AP,",
+       text "     AP_STACK,",
+       text "     CAF_BLACKHOLE,",
+       text "     BLACKHOLE,",
+       text "     BLACKHOLE_BQ,",
+       text "     SE_BLACKHOLE,",
+       text "     SE_CAF_BLACKHOLE,",
+        text "     THUNK,",
+        text "     THUNK_1_0,",
+        text "     THUNK_0_1,",
+        text "     THUNK_2_0,",
+        text "     THUNK_1_1,",
+        text "     THUNK_0_2,",
+        text "     THUNK_STATIC,",
+        text "     THUNK_SELECTOR: {",
        nest 4 (vcat [
-         text "Sp[0] = (W_)&" <> fun_info_label <> text ";",
-         text "JMP_(GET_ENTRY(R1.cl));",
+          text "TICK_SLOW_CALL_UNEVALD(" <> int (length args) <> text ");",
+         text "Sp(0) = " <> fun_info_label <> text ";",
+         text "jump %GET_ENTRY(R1);",
          text ""
         ]),
+       text "}",
 
 --    if fast == 1:
 --        print "    ind_lbl:"
 --    else:
-        text "case IND:",
-        text "case IND_OLDGEN:",
-        text "case IND_STATIC:",
-        text "case IND_PERM:",
-        text "case IND_OLDGEN_PERM:",
+        text "case IND,",
+        text "     IND_OLDGEN,",
+        text "     IND_STATIC,",
+        text "     IND_PERM,",
+        text "     IND_OLDGEN_PERM: {",
        nest 4 (vcat [
-         text "R1.cl = ((StgInd *)R1.p)->indirectee;",
+         text "R1 = StgInd_indirectee(R1);",
          text "goto again;"
         ]),
+       text "}",
        text "",
 
 --    if fast == 0:
 
-       text "default:",
+       text "default: {",
        nest 4 (
-         text "barf(\"" <> fun_ret_label <> text "\");"
+         text "foreign \"C\" barf(\"" <> fun_ret_label <> text "\");"
        ),
        text "}"
        
-       ])
+       ]),
+       text "}"
       ]),
-      text "FE_",
       text "}"
     ]
 
@@ -439,20 +455,18 @@ genApply args =
 mkStackApplyEntryLabel:: [ArgRep] -> Doc
 mkStackApplyEntryLabel args = text "stg_ap_stk_" <> text (map showArg args)
 
-genStackApply :: [ArgRep] -> Doc
-genStackApply args = 
+genStackApply :: RegStatus -> [ArgRep] -> Doc
+genStackApply regstatus args = 
   let fn_entry_label = mkStackApplyEntryLabel args in
   vcat [
-    text "IF_" <> parens fn_entry_label,
-    text "{",
-    nest 4 (text "FB_" $$ body $$ text "FE_"),
-    text "}"
+    fn_entry_label,
+    text "{", nest 4 body, text "}"
    ]
  where
-   (assign_regs, sp') = loadRegArgs 0 args
+   (assign_regs, sp') = loadRegArgs regstatus 0 args
    body = vcat [assign_regs,
-               text "Sp += " <> int sp' <> semi,
-               text "JMP_(GET_ENTRY(R1.cl));"
+               text "Sp_adj" <> parens (int sp') <> semi,
+               text "jump %GET_ENTRY(R1);"
                ]
 
 -- -----------------------------------------------------------------------------
@@ -466,49 +480,51 @@ genStackApply args =
 mkStackSaveEntryLabel :: [ArgRep] -> Doc
 mkStackSaveEntryLabel args = text "stg_stk_save_" <> text (map showArg args)
 
-genStackSave :: [ArgRep] -> Doc
-genStackSave args =
+genStackSave :: RegStatus -> [ArgRep] -> Doc
+genStackSave regstatus args =
   let fn_entry_label= mkStackSaveEntryLabel args in
   vcat [
-    text "IF_" <> parens fn_entry_label,
-    text "{",
-    nest 4 (text "FB_" $$ body $$ text "FE_"),
-    text "}"
+    fn_entry_label,
+    text "{", nest 4 body, text "}"
    ]
  where
-   body = vcat [text "Sp -= " <> int sp_offset <> semi,
+   body = vcat [text "Sp_adj" <> parens (int (-sp_offset)) <> semi,
                vcat (map (uncurry assign_reg_to_stk) reg_locs),
-               text "Sp[2] = R1.w;",
-               text "Sp[1] =" <+> int (sp_offset - std_frame_size) <> semi,
-               text "Sp[0] = (W_)&stg_gc_fun_info;",
-               text "JMP_(stg_gc_noregs);"
+               text "Sp(2) = R1;",
+               text "Sp(1) =" <+> int stk_args <> semi,
+               text "Sp(0) = stg_gc_fun_info;",
+               text "jump stg_gc_noregs;"
                ]
 
    std_frame_size = 3 -- the std bits of the frame. See StgRetFun in Closures.h,
                      -- and the comment on stg_fun_gc_gen in HeapStackCheck.hc.
-   (reg_locs, sp_offset) = assignRegs std_frame_size args
+   (reg_locs, leftovers, sp_offset) = assignRegs regstatus std_frame_size args
+
+   -- number of words of arguments on the stack.
+   stk_args = sum (map argSize leftovers) + sp_offset - std_frame_size
 
 -- -----------------------------------------------------------------------------
 -- The prologue...
 
-main = putStr (render the_code)
-  where the_code = vcat [
+main = do
+  args <- getArgs
+  regstatus <- case args of
+                [] -> return Registerised
+                ["-u"] -> return Unregisterised
+                _other -> do hPutStrLn stderr "syntax: genapply [-u]"
+                             exitWith (ExitFailure 1)
+  let the_code = vcat [
                text "// DO NOT EDIT!",
                text "// Automatically generated by GenApply.hs",
                text "",
-               text "#include \"Stg.h\"",
-               text "#include \"Rts.h\"",
-               text "#include \"RtsFlags.h\"",
-               text "#include \"Storage.h\"",
-               text "#include \"RtsUtils.h\"",
-               text "#include \"Printer.h\"",
-               text "#include \"Sanity.h\"",
-               text "#include \"Apply.h\"",
+               text "#include \"Cmm.h\"",
+               text "#include \"AutoApply.h\"",
                text "",
-               text "#include <stdio.h>",
 
-               vcat (intersperse (text "") $ map genApply applyTypes),
-               vcat (intersperse (text "") $ map genStackFns stackApplyTypes),
+               vcat (intersperse (text "") $ 
+                  map (genApply regstatus) applyTypes),
+               vcat (intersperse (text "") $ 
+                  map (genStackFns regstatus) stackApplyTypes),
 
                genStackApplyArray stackApplyTypes,
                genStackSaveArray stackApplyTypes,
@@ -516,6 +532,8 @@ main = putStr (render the_code)
 
                text ""  -- add a newline at the end of the file
            ]
+  -- in
+  putStr (render the_code)
 
 -- These have been shown to cover about 99% of cases in practice...
 applyTypes = [
@@ -529,10 +547,10 @@ applyTypes = [
        [P,P],
        [P,P,V],
        [P,P,P],
+       [P,P,P,V],
        [P,P,P,P],
        [P,P,P,P,P],
-       [P,P,P,P,P,P],
-       [P,P,P,P,P,P,P]
+       [P,P,P,P,P,P]
    ]
 
 -- No need for V args in the stack apply cases.
@@ -564,36 +582,45 @@ stackApplyTypes = [
        [P,P,P,P,P,P,P,P]
    ]
 
-genStackFns args = genStackApply args $$ genStackSave args
+genStackFns regstatus args 
+  =  genStackApply regstatus args
+  $$ genStackSave regstatus args
 
 
 genStackApplyArray types =
-  text "StgFun *stg_ap_stack_entries[] = {" $$  
-  vcat (map arr_ent types) $$
-  text "};"
+  vcat [
+    text "section \"rodata\" {",
+    text "stg_ap_stack_entries:",
+    text "W_ 0; W_ 0; W_ 0;", -- ARG_GEN, ARG_GEN_BIG, ARG_BCO
+    vcat (map arr_ent types),
+    text "}"
+  ]
  where
-  arr_ent ty = brackets (arg_const ty) <+> mkStackApplyEntryLabel ty <> comma
+  arr_ent ty = text "W_" <+> mkStackApplyEntryLabel ty <> semi
 
 genStackSaveArray types =
-  text "StgFun *stg_stack_save_entries[] = {" $$  
-  vcat (map arr_ent types) $$
-  text "};"
+  vcat [
+    text "section \"rodata\" {",
+    text "stg_stack_save_entries:",
+    text "W_ 0; W_ 0; W_ 0;", -- ARG_GEN, ARG_GEN_BIG, ARG_BCO
+    vcat (map arr_ent types),
+    text "}"
+  ]
  where
-  arr_ent ty = brackets (arg_const ty) <+> mkStackSaveEntryLabel ty <> comma
+  arr_ent ty = text "W_" <+> mkStackSaveEntryLabel ty <> semi
 
 genBitmapArray :: [[ArgRep]] -> Doc
 genBitmapArray types =
   vcat [
-    text "StgWord stg_arg_bitmaps[] = {",
+    text "section \"rodata\" {",
+    text "stg_arg_bitmaps:",
+    text "W_ 0; W_ 0; W_ 0;", -- ARG_GEN, ARG_GEN_BIG, ARG_BCO
     vcat (map gen_bitmap types),
-    text "};"
+    text "}"
   ]
   where
-   gen_bitmap ty = brackets (arg_const ty) <+> 
-                  text "MK_SMALL_BITMAP" <> parens (
-                       int (sum (map argSize ty)) <> comma <>
-                       text (show (mkBitmap ty))) <>
-                  comma
-
-arg_const ty = text "ARG_" <> text (map toUpper (map showArg ty))
+   gen_bitmap ty = text "W_" <+> int bitmap_val <> semi
+       where bitmap_val = 
+               (fromIntegral (mkBitmap ty) `shiftL` BITMAP_BITS_SHIFT)
+                .|. sum (map argSize ty)
 
index 34b6f4d..954d1f6 100644 (file)
@@ -29,7 +29,7 @@ import List ( isPrefixOf, isSuffixOf )
 
 import ParsePkgConfLite
 
-#include "../../includes/config.h"
+#include "../../includes/ghcconfig.h"
 
 #ifdef mingw32_HOST_OS
 import Foreign
index efe520e..e25b562 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef MAIN_H
 #define MAIN_H
 
-#include "config.h"
+#include "../includes/ghcconfig.h"
 
 #ifdef __STDC__
 #define PROTO(x)       x
index b032553..e2cfbb7 100644 (file)
@@ -1,7 +1,7 @@
 {-# OPTIONS -fffi -cpp #-}
 
 ------------------------------------------------------------------------
--- $Id: Main.hs,v 1.59 2004/08/12 12:12:54 simonmar Exp $
+-- $Id: Main.hs,v 1.60 2004/08/13 13:11:21 simonmar Exp $
 --
 -- Program for converting .hsc files to .hs files, by converting the
 -- file into a C program which is run to generate the Haskell source.
index 0eb6ede..8ee66e1 100644 (file)
@@ -1,5 +1,5 @@
 /* ------------------------------------------------------------------------
- * $Id: cgprof.c,v 1.5 2004/07/09 16:47:59 sof Exp $
+ * $Id: cgprof.c,v 1.6 2004/08/13 13:11:22 simonmar Exp $
  *                                                                     
  *     Copyright (C) 1995-2000 University of Oxford
  *                                                                     
@@ -17,7 +17,7 @@
  *      form, be without fee and subject to these same conditions.
  * --------------------------------------------------------------------- */
 
-#include "config.h"
+#include "ghcconfig.h"
 #if HAVE_STRING_H
 #include <string.h>
 #endif
index ce3c0de..3b758d1 100644 (file)
@@ -1,5 +1,5 @@
 /* ------------------------------------------------------------------------
- * $Id: main.c,v 1.2 2003/08/01 14:50:50 panne Exp $
+ * $Id: main.c,v 1.3 2004/08/13 13:11:23 simonmar Exp $
  *                                                                     
  *     Copyright (C) 1995-2000 University of Oxford
  *                                                                     
@@ -17,7 +17,7 @@
  *      form, be without fee and subject to these same conditions.
  * --------------------------------------------------------------------- */
 
-#include "config.h"
+#include "ghcconfig.h"
 
 #include <stdio.h>