Comments and Cmm notes
authorsimonpj@microsoft.com <unknown>
Fri, 11 Sep 2009 13:35:13 +0000 (13:35 +0000)
committersimonpj@microsoft.com <unknown>
Fri, 11 Sep 2009 13:35:13 +0000 (13:35 +0000)
compiler/cmm/CmmContFlowOpt.hs
compiler/cmm/cmm-notes
compiler/main/HscMain.lhs

index e0d9555..64a2315 100644 (file)
@@ -36,6 +36,7 @@ cmmCfgOptsZ g =
         -- with a more exciting combination of optimisations
 
 runCmmOpts :: Tx g -> Tx (GenCmm d h g)
+-- Lifts a transformer on a single graph to one on the whole program
 runCmmOpts opt = mapProcs (optProc opt)
 
 optProc :: Tx g -> Tx (GenCmmTop d h g)
index ee51624..5ec4895 100644 (file)
@@ -2,6 +2,8 @@ Notes on new codegen (Sept 09)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
 \r
 Things to do:\r
+ - Consider module names\r
+\r
  - Top-level SRT threading is a bit ugly\r
 \r
  - Add type/newtype for CmmModule = [CmmGroup]    -- A module\r
@@ -12,6 +14,10 @@ Things to do:
    regardless of SplitObjs.   Question: can we *always* generate M.o if there\r
    is just one element in the list (rather than M/M1.o, M/M2.o etc)\r
 \r
+   One SRT per group.\r
+\r
+ - See "CAFs" below; we want to totally refactor the way SRTs are calculated\r
+\r
  - Change  \r
       type CmmZ = GenCmm CmmStatic CmmInfo (CmmStackInfo, CmmGraph)\r
    to\r
@@ -32,6 +38,11 @@ Things to do:
    type SubArea    = (Area, ByteOff, ByteWidth) \r
    ByteOff should not be defined in SMRep -- that is too high up the hierarchy\r
    \r
+ - SMRep should not be imported by any module in cmm/!  Make it so.\r
+       -- ByteOff etc   ==>  CmmExpr\r
+        -- rET_SMALL etc ==> CmmInfo\r
+   Check that there are no other imports from codeGen in cmm/\r
+\r
  - Think about a non-flattened representation?\r
 \r
  - LastCall: \r
@@ -66,48 +77,108 @@ Things to do:
         points that are not successors of a call, we think) can be treated\r
         uniformly: zero-size Area, and use inSP.\r
 \r
-Dead files\r
-~~~~~~~~~~\r
-CmmProcPoint (Michael Adams)\r
-CmmCPS (ditto)\r
+\r
+ - Currently AsmCodeGen top level calls AsmCodeGen.cmmToCmm, which is a small\r
+   C-- optimiser.  It has quite a lot of boilerplate folding code in AsmCodeGen\r
+   (cmmBlockConFold, cmmStmtConFold, cmmExprConFold), before calling out to\r
+   CmmOpt.  ToDo: see what optimisations are being done; and do them before\r
+   AsmCodeGen.\r
+\r
+ - Modularise the CPS pipeline; instead of ...; A;B;C; ...\r
+                                use  ..; ABC; ....\r
+\r
+ - Most of HscMain.tryNewCodeGen does not belong in HscMain.  Instead\r
+       if new_cg then\r
+             StgCmm.codeGen\r
+             processCmm  [including generating "raw" cmm]\r
+        else\r
+             CodeGen.codeGen\r
+             cmmToRawCmm\r
+\r
+\r
+ - If we stick CAF and stack liveness info on a LastCall node (not LastRet/Jump)\r
+   then all CAF and stack liveness stuff be completed before we split\r
+   into separate C procedures.\r
+\r
+   Short term:\r
+     compute and attach liveness into to LastCall\r
+     right at end, split, cvt to old rep\r
+     [must split before cvt, because old rep is not expressive enough]\r
+\r
+   Longer term: \r
+     when old rep disappears, \r
+     move the whole splitting game into the C back end *only*\r
+        (guided by the procpoint set)\r
+\r
+      \r
+----------------------------------------------------\r
+       Modules in cmm/\r
+----------------------------------------------------\r
+\r
+-------- Dead stuff ------------\r
+CmmProcPoint        Dead: Michael Adams\r
+CmmCPS              Dead: Michael Adams\r
+CmmCPSGen.hs        Dead: Michael Adams\r
+CmmBrokenBlock.hs   Dead: Michael Adams\r
+CmmLive.hs          Dead: Michael Adams\r
+CmmProcPoint.hs     Dead: Michael Adams\r
+Dataflow.hs         Dead: Michael Adams\r
+StackColor.hs       Norman?\r
+StackPlacements.hs  Norman?\r
+\r
 HscMain.optionallyConvertAndOrCPS\r
         testCmmConversion\r
 DynFlags:  -fconvert-to-zipper-and-back, -frun-cps, -frun-cpsz\r
 \r
-Proc-points\r
-~~~~~~~~~~~~\r
-Consider this program, which has a diamond control flow, \r
-with a call on one branch\r
- fn(p,x) {\r
-        h()\r
-       if b then { ... f(x) ...; q=5; goto J }\r
-             else { ...; q=7; goto J }\r
-     J: ..p...q...\r
-  }\r
-then the join point J is a "proc-point".  So, is 'p' passed to J\r
-as a parameter?  Or, if 'p' was saved on the stack anyway, perhaps\r
-to keep it alive across the call to h(), maybe 'p' gets communicated\r
-to J that way. This is an awkward choice.  (We think that we currently\r
-never pass variables to join points via arguments.)\r
+-------- Moribund stuff ------------\r
+CmmCvt.hs      Conversion between old and new Cmm reps\r
+CmmOpt.hs      Hopefully-redundant optimiser\r
+CmmZipUtil.hs  Only one function; move elsewhere\r
 \r
-Furthermore, there is *no way* to pass q to J in a register (other\r
-than a paramter register).\r
+-------- Stuff to keep ------------\r
+CmmCPSZ.hs               Driver for new pipeline\r
 \r
-What we want is to do register allocation across the whole caboodle.\r
-Then we could drop all the code that deals with the above awkward\r
-decisions about spilling variables across proc-points.\r
+CmmLiveZ.hs              Liveness analysis, dead code elim\r
+CmmProcPointZ.hs          Identifying and splitting out proc-points\r
 \r
-Note that J doesn't need an info table.\r
+CmmSpillReload.hs         Save and restore across calls\r
 \r
-What we really want is for each Block to have an optional info table.\r
-To do that, we need to be polymorphic over first nodes.\r
+CmmCommonBlockElimZ.hs    Common block elim\r
+CmmContFlowOpt.hs         Other optimisations (branch-chain, merging)\r
+\r
+CmmBuildInfoTables.hs     New info-table \r
+CmmStackLayout.hs         and stack layout \r
+CmmCallConv.hs\r
+CmmInfo.hs                Defn of InfoTables, and conversion to exact layout\r
+\r
+---------- Cmm data types --------------\r
+ZipCfgCmmRep.hs            Cmm instantiations of dataflow graph framework\r
+MkZipCfgCmm.hs      Cmm instantiations of dataflow graph framework\r
+\r
+Cmm.hs       Key module; a mix of old and new stuff\r
+                  so needs tidying up in due course\r
+CmmExpr.hs\r
+CmmUtils.hs\r
+CmmLint.hs\r
+\r
+PprC.hs                    Pretty print Cmm in C syntax\r
+PprCmm.hs          Pretty printer for Cmm\r
+PprCmmZ.hs         Additional stuff for zipper rep\r
+\r
+CLabel.hs     CLabel\r
+\r
+----------  Dataflow modules --------------\r
+   Goal: separate library; for now, separate directory\r
+\r
+MkZipCfg.hs\r
+ZipCfg.hs\r
+ZipCfgExtras.hs\r
+ZipDataflow.hs\r
+CmmTx.hs             Transactions\r
+OptimizationFuel.hs   Fuel\r
+BlockId.hs    BlockId, BlockEnv, BlockSet\r
+DFMonad.hs           \r
 \r
-Figuring out proc-points\r
-~~~~~~~~~~~~~~~~~~~~~~~~\r
-Proc-points are identified by\r
-CmmProcPointZ.minimalProcPointSet/extendPPSet Although there isn't\r
-that much code, JD thinks that it could be done much more nicely using\r
-a dominator analysis, using the Dataflow Engine.\r
 \r
 ----------------------------------------------------\r
       Top-level structure\r
@@ -146,12 +217,12 @@ cpsTop:
 \r
   * CmmProcPointZ.minimalProcPointSet\r
        identify proc-points\r
+        no change to graph\r
 \r
   * CmmProcPointZ.addProcPointProtocols\r
        something to do with the MA optimisation\r
         probably entirely unnecessary\r
 \r
-\r
   * Spill and reload:\r
      - CmmSpillReload.dualLivenessWithInsertion\r
        insert spills/reloads across \r
@@ -170,7 +241,7 @@ cpsTop:
 \r
      - CmmStackLayout.layout\r
        Lay out the stack, returning an AreaMap\r
-         type AreaMap    = FiniteMap Area ByteOff\r
+         type AreaMap = FiniteMap Area ByteOff\r
           -- Byte offset of the oldest byte of the Area, \r
           -- relative to the oldest byte of the Old Area\r
 \r
@@ -180,10 +251,53 @@ cpsTop:
    * Split into separate procedures\r
       - CmmProcPointZ.procPointAnalysis\r
         Given set of proc points, which blocks are reachable from each\r
+        Claim: too few proc-points => code duplication, but program still works??\r
 \r
       - CmmProcPointZ.splitAtProcPoints\r
        Using this info, split into separate procedures\r
 \r
+      - CmmBuildInfoTables.setInfoTableStackMap\r
+       Attach stack maps to each info table\r
+\r
+\r
+----------------------------------------------------\r
+       Proc-points\r
+----------------------------------------------------\r
+\r
+Consider this program, which has a diamond control flow, \r
+with a call on one branch\r
+ fn(p,x) {\r
+        h()\r
+       if b then { ... f(x) ...; q=5; goto J }\r
+             else { ...; q=7; goto J }\r
+     J: ..p...q...\r
+  }\r
+then the join point J is a "proc-point".  So, is 'p' passed to J\r
+as a parameter?  Or, if 'p' was saved on the stack anyway, perhaps\r
+to keep it alive across the call to h(), maybe 'p' gets communicated\r
+to J that way. This is an awkward choice.  (We think that we currently\r
+never pass variables to join points via arguments.)\r
+\r
+Furthermore, there is *no way* to pass q to J in a register (other\r
+than a paramter register).\r
+\r
+What we want is to do register allocation across the whole caboodle.\r
+Then we could drop all the code that deals with the above awkward\r
+decisions about spilling variables across proc-points.\r
+\r
+Note that J doesn't need an info table.\r
+\r
+What we really want is for each LastCall (not LastJump/Ret) \r
+to have an info table.   Note that ProcPoints that are not successors\r
+of calls don't need an info table.\r
+\r
+Figuring out proc-points\r
+~~~~~~~~~~~~~~~~~~~~~~~~\r
+Proc-points are identified by\r
+CmmProcPointZ.minimalProcPointSet/extendPPSet Although there isn't\r
+that much code, JD thinks that it could be done much more nicely using\r
+a dominator analysis, using the Dataflow Engine.\r
+\r
 ----------------------------------------------------\r
                CAFs\r
 ----------------------------------------------------\r
@@ -193,11 +307,11 @@ cpsTop:
   If f is live, then so is g.  f's SRT must include g's closure.\r
 \r
 * The CLabel for the entry-point/closure reveals whether g is \r
-  a CAF (or refers to CAFs).  See the IdLabell constructor of CLabel.\r
+  a CAF (or refers to CAFs).  See the IdLabel constructor of CLabel.\r
 \r
 * The CAF-ness of the original top-level defininions is figured out\r
   (by TidyPgm) before we generate C--.  This CafInfo is only set for\r
-  top-level Ids; nested bindings stay with NoCafRefs.\r
+  top-level Ids; nested bindings stay with MayHaveCafRefs.\r
 \r
 * Currently an SRT contains (only) pointers to (top-level) closures.\r
 \r
@@ -210,10 +324,19 @@ cpsTop:
   This generates C-- roughly like this:\r
      f_closure: .word f_entry\r
      f_entry() [info-tbl-for-f] { ...jump g_entry...jump h2... }\r
-     g_entry() [info-tbl-for-g] { ...jump h1 }\r
+     g_entry() [info-tbl-for-g] { ...jump h1... }\r
 \r
   Note that there is no top-level closure for g (only an info table).\r
-  So:   info-tbl-for-f must have an SRT that keeps h1,h2 alive\r
+  This fact (whether or not there is a top-level closure) is recorded\r
+  in the InfoTable attached to the CmmProc for f, g\r
+  INVARIANT: \r
+     Any out-of-Group references to an IdLabel goes to\r
+     a Proc whose InfoTable says "I have a top-level closure".\r
+  Equivalently: \r
+     A CmmProc whose InfoTable says "I do not have a top-level\r
+     closure" is referred to only from its own Group.\r
+\r
+* So:   info-tbl-for-f must have an SRT that keeps h1,h2 alive\r
         info-tbl-for-g must have an SRT that keeps h1 (only) alive\r
 \r
   But if we just look for the free CAF refs, we get:\r
@@ -228,6 +351,9 @@ cpsTop:
   the attaching, right at the end of the pipeline.  The C_SRT part\r
   gives offsets within a single, shared table of closure pointers.\r
 \r
+* DECIDED: we can generate SRTs based on the final Cmm program\r
+  without knowledge of how it is generated.\r
+\r
 ----------------------------------------------------\r
                Foreign calls\r
 ----------------------------------------------------\r
index a334c70..1f32c35 100644 (file)
@@ -802,8 +802,8 @@ tryNewCodeGen hsc_env this_mod data_tycons imported_mods
        ; prog <- return $ map (runTx $ runCmmOpts cmmCfgOptsZ) prog
                -- Control flow optimisation
 
-        -- Note: Have to thread the module's SRT through all the procedures
-        -- because we greedily build it as we go.
+        -- We are building a single SRT for the entire module, so
+        -- we must thread it through all the procedures as we cps-convert them.
         ; us <- mkSplitUniqSupply 'S'
         ; let topSRT = initUs_ us emptySRT
        ; (topSRT, prog) <- foldM (protoCmmCPSZ hsc_env) (topSRT, []) prog