summaryrefslogtreecommitdiff
path: root/compiler/cmm/cmm-notes
blob: 0e6a2341f2c3f88c7137336b419c57e5904d03d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
More notes (Aug 11)
~~~~~~~~~~~~~~~~~~
* CmmInfo.cmmToRawCmm expands info tables to their representations
  (needed for .cmm files as well as the code generators)

* Why is FCode a lazy monad?  That makes it inefficient.
  We want laziness to get code out one procedure at a time,
  but not at the instruction level.

Things we did
  * Remove CmmCvt.graphToZgraph (Conversion from old to new Cmm reps)
  * Remove HscMain.optionallyConvertAndOrCPS (converted old Cmm to
    new, ran pipeline, and converted back)
  * Remove CmmDecl. Put its types in Cmm.  Import Cmm into OldCmm
    so it can get those types.


More notes (June 11)
~~~~~~~~~~~~~~~~~~~~

* In CmmContFlowOpts.branchChainElim, can a single block be the
  successor of two calls?

* Check in ClosureInfo:
     -- NB: Results here should line up with the results of SMRep.rtsClosureType

* "Remove redundant reloads" in CmmSpillReload should be redundant; since
  insertLateReloads is now gone, every reload is reloading a live variable.
  Test and nuke.

* When stubbing dead slots be careful not to write into an area that
  overlaps with an area that's in use.  So stubbing needs to *follow* 
  stack layout.


More notes (May 11)
~~~~~~~~~~~~~~~~~~~
In CmmNode, consider spliting CmmCall into two: call and jump

Notes on new codegen (Aug 10)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Things to do:
 - We insert spills for variables before the stack check! This is the reason for
   some fishy code in StgCmmHeap.entryHeapCheck where we are doing some strange
	things to fix up the stack pointer before GC calls/jumps.

	The reason spills are inserted before the sp check is that at the entry to a
	function we always store the parameters passed in registers to local variables.
	The spill pass simply inserts spills at variable definitions. We instead should
	sink the spills so that we can avoid spilling them on branches that never
	reload them.

	This will fix the spill before stack check problem but only really as a side
	effect. A 'real fix' probably requires making the spiller know about sp checks.

   EZY: I don't understand this comment. David Terei, can you clarify?

 - Proc points pass all arguments on the stack, adding more code and
   slowing down things a lot. We either need to fix this or even better
   would be to get rid of proc points.

 - CmmInfo.cmmToRawCmm uses Old.Cmm, so it is called after converting Cmm.Cmm to
   Old.Cmm. We should abstract it to work on both representations, it needs only to
   convert a CmmInfoTable to [CmmStatic].

 - Improve performance of Hoopl.

   A nofib comparison of -fasm vs -fnewcodegen nofib compilation parameters
   (using the same ghc-cmm branch +libraries compiled by the old codegenerator)
   is at http://fox.auryn.cz/msrc/0517_hoopl/32bit.oldghcoldgen.oldghchoopl.txt
   - the code produced is 10.9% slower, the compilation is +118% slower!

   The same comparison with ghc-head with zip representation is at
   http://fox.auryn.cz/msrc/0517_hoopl/32bit.oldghcoldgen.oldghczip.txt
   - the code produced is 11.7% slower, the compilation is +78% slower.

   When compiling nofib, ghc-cmm + libraries compiled with -fnew-codegen
   is 23.7% slower (http://fox.auryn.cz/msrc/0517_hoopl/32bit.oldghcoldgen.hooplghcoldgen.txt).
   When compiling nofib, ghc-head + libraries compiled with -fnew-codegen
   is 31.4% slower (http://fox.auryn.cz/msrc/0517_hoopl/32bit.oldghcoldgen.zipghcoldgen.txt).

   EZY: Also importantly, Hoopl uses dramatically more memory than the
   old code generator.

 - Are all blockToNodeList and blockOfNodeList really needed? Maybe we could
   splice blocks instead?

 - lowerSafeForeignCall seems too lowlevel. Just use Dataflow. After that
   delete splitEntrySeq from HooplUtils.

 - manifestSP seems to touch a lot of the graph representation. It is
   also slow for CmmSwitch nodes O(block_nodes * switch_statements).
   Maybe rewrite manifestSP to use Dataflow?

 - Sort out Label, LabelMap, LabelSet versus BlockId, BlockEnv, BlockSet
   dichotomy. Mostly this means global replace, but we also need to make
   Label an instance of Outputable (probably in the Outputable module).

   EZY: We should use Label, since that's the terminology Hoopl uses.

 - NB that CmmProcPoint line 283 has a hack that works around a GADT-related
   bug in 6.10.

 - AsmCodeGen has a generic Cmm optimiser; move this into new pipeline
   EZY (2011-04-16): The mini-inliner has been generalized and ported,
   but the constant folding and other optimizations need to still be
   ported.

 - AsmCodeGen has post-native-cg branch eliminator (shortCutBranches);
   we ultimately want to share this with the Cmm branch eliminator.

 - At the moment, references to global registers like Hp are "lowered" 
   late (in CgUtils.fixStgRegisters). We should do this early, in the
	new native codegen, much in the way that we lower calling conventions.
	Might need to be a bit sophisticated about aliasing.

 - Question: currently we lift procpoints to become separate
   CmmProcs.  Do we still want to do this?
    
   NB: and advantage of continuing to do this is that
   we can do common-proc elimination!

 - Move to new Cmm rep:
     * Make native CG consume New Cmm; 
     * Convert Old Cmm->New Cmm to keep old path alive
     * Produce New Cmm when reading in .cmm files

 - Consider module names

 - Top-level SRT threading is a bit ugly

 - See "CAFs" below; we want to totally refactor the way SRTs are calculated

 - Pull out Areas into its own module
   Parameterise AreaMap (note there are type synonyms in CmmStackLayout!)
   Add ByteWidth = Int
   type SubArea    = (Area, ByteOff, ByteWidth) 
   ByteOff should not be defined in SMRep -- that is too high up the hierarchy
   
 - SMRep should not be imported by any module in cmm/!  Make it so.
	-- ByteOff etc   ==>  CmmExpr
        -- rET_SMALL etc ==> CmmInfo
   Check that there are no other imports from codeGen in cmm/

 - If you eliminate a label by branch chain elimination,
   what happens if there's an Area associated with that label?

 - Think about a non-flattened representation?

 - LastCall: 
    * Use record fields for LastCall!
    * cml_ret_off should be a ByteOff
    * Split into 
         LastCall (which has a successor) and
         LastJump (which does not, includes return?)
	   - does not have cml_cont, cml_ret_args, cml_ret_off
	 LastForeignCall 
           - safe! 
           - expands into save/MidForeignCall/restore/goto
	   - like any LastCall, target of the call gets an info table

 - JD: remind self of what goes wrong if you turn off the 
   liveness of the update frame

 - Garbage-collect http://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/CPS
   moving good stuff into 
   http://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/NewCodeGenPipeline


 - We believe that all of CmmProcPoint.addProcPointProtocols is dead.  What
   goes wrong if we simply never call it?

 - Something fishy in CmmStackLayout.hs
   * In particular, 'getAreaSize' returns an AreaMap, but we *know* the width of
	LocalRegs, so it'd be better to return FiniteMap AreaId ByteWidth
   * setSuccSPs looks fishy.  Rather than lookin in procPoints, it could
	just lookup the block in areaSize which, after all, has a binding
	for precisely successors of calls.  All other blocks (including proc
        points that are not successors of a call, we think) can be treated
        uniformly: zero-size Area, and use inSP.


 - Currently AsmCodeGen top level calls AsmCodeGen.cmmToCmm, which is a small
   C-- optimiser.  It has quite a lot of boilerplate folding code in AsmCodeGen
   (cmmBlockConFold, cmmStmtConFold, cmmExprConFold), before calling out to
   CmmOpt.  ToDo: see what optimisations are being done; and do them before
   AsmCodeGen.

 - Modularise the CPS pipeline; instead of ...; A;B;C; ...
                                use  ..; ABC; ....

 - Most of HscMain.tryNewCodeGen does not belong in HscMain.  Instead
	if new_cg then
             StgCmm.codeGen
             processCmm  [including generating "raw" cmm]
        else
             CodeGen.codeGen
             cmmToRawCmm


 - If we stick CAF and stack liveness info on a LastCall node (not LastRet/Jump)
   then all CAF and stack liveness stuff be completed before we split
   into separate C procedures.

   Short term:
     compute and attach liveness into to LastCall
     right at end, split, cvt to old rep
     [must split before cvt, because old rep is not expressive enough]

   Longer term: 
     when old rep disappears, 
     move the whole splitting game into the C back end *only*
	 (guided by the procpoint set)

----------------------------------------------------
	Modules in codeGen/
----------------------------------------------------


------- Shared ---------
Bitmap.hs
SMRep.lhs

CmmParse.y
CgExtCode.hs   used in CmmParse.y

------- New codegen ---------

StgCmm.hs
StgCmmBind.hs
StgCmmClosure.hs     (corresponds to old ClosureInfo)
StgCmmCon.hs
StgCmmEnv.hs
StgCmmExpr.hs
StgCmmForeign.hs
StgCmmGran.hs
StgCmmHeap.hs
StgCmmHpc.hs
StgCmmLayout.hs
StgCmmMonad.hs
StgCmmPrim.hs
StgCmmProf.hs
StgCmmTicky.hs
StgCmmUtils.hs

------- Old codegen (moribund) ---------
CodeGen.lhs
CgBindery.lhs
CgCallConv.hs
CgCase.lhs
CgClosure.lhs
CgCon.lhs
CgExpr.lhs
CgLetNoEscape.lhs
CgForeignCall.hs
CgHeapery.lhs
CgHpc.hs
CgInfoTbls.hs
CgMonad.lhs
CgParallel.hs
CgPrimOp.hs
CgProf.hs
CgStackery.lhs
CgTailCall.lhs
CgTicky.hs
CgUtils.hs
ClosureInfo.lhs

----------------------------------------------------
	Modules in cmm/
----------------------------------------------------

-------- Testing stuff ------------
DynFlags: -frun-cpsz

-------- Moribund stuff ------------
OldCmm.hs      Definition of flowgraph of old representation
               Imports some data types from (new) Cmm
OldCmmUtil.hs  Utilites that operates mostly on on CmmStmt
OldPprCmm.hs   Pretty print for CmmStmt, GenBasicBlock and ListGraph
CmmOpt.hs      Hopefully-redundant optimiser

-------- Stuff to keep ------------
CmmPipeline.hs            Driver for new pipeline

CmmLive.hs                Liveness analysis, dead code elim
CmmProcPoint.hs           Identifying and splitting out proc-points

CmmSpillReload.hs         Save and restore across calls

CmmCommonBlockElim.hs     Common block elim
CmmContFlowOpt.hs         Other optimisations (branch-chain, merging)

CmmBuildInfoTables.hs     New info-table 
CmmStackLayout.hs         and stack layout 
CmmCallConv.hs
CmmInfo.hs                Defn of InfoTables, and conversion to exact byte layout

---------- Cmm data types --------------
Cmm.hs              Cmm instantiations of dataflow graph framework
  CmmExpr.hs        Type of Cmm expression
  CmmType.hs        Type of Cmm types and their widths
  CmmMachOp.hs      MachOp type and accompanying utilities

PprCmm.hs	    Pretty printer for Cmm
  PprCmmExpr.hs     Pretty printer for CmmExpr

MkGraph.hs          Interface for building Cmm for codeGen/Stg*.hs modules

CmmUtils.hs
CmmLint.hs

PprC.hs	            Pretty print Cmm in C syntax

CLabel.hs           CLabel
BlockId.hs          BlockId, BlockEnv, BlockSet

----------------------------------------------------
      Top-level structure
----------------------------------------------------

* New codgen called in HscMain.hscGenHardCode, by calling HscMain.tryNewCodeGen, 
  enabled by -fnew-codegen (Opt_TryNewCodeGen)

  THEN it calls CmmInfo.cmmToRawCmm to lay out the details of info tables
      type Cmm    = GenCmm CmmStatic CmmInfo     (ListGraph CmmStmt)
      type RawCmm = GenCmm CmmStatic [CmmStatic] (ListGraph CmmStmt)

* HscMain.tryNewCodeGen
    - STG->Cmm:         StgCmm.codeGen (new codegen)
    - Optimize and CPS: CmmPipeline.cmmPipeline
    - Convert:          CmmCvt.cmmOfZgraph (convert to old rep) very self contained

* StgCmm.hs  The new STG -> Cmm conversion code generator
  Lots of modules StgCmmXXX


----------------------------------------------------
      CmmPipeline.cmmPipeline   The new pipeline
----------------------------------------------------

CmmPipeline.cmmPipeline:
   1. Do control flow optimization
   2. Do cpsTop for each procedures separately
   3. Build SRT representation; this spans multiple procedures
        (unless split-objs)
   4. Do control flow optimization on all resulting procedures

cpsTop:
  * CmmCommonBlockElim.elimCommonBlocks:
	eliminate common blocks 

  * CmmProcPoint.minimalProcPointSet
	identify proc-points
        no change to graph

  * CmmProcPoint.addProcPointProtocols
	something to do with the MA optimisation
        probably entirely unnecessary

  * Spill and reload:
     - CmmSpillReload.dualLivenessWithInsertion
       insert spills/reloads across 
	   LastCalls, and 
	   Branches to proc-points
     Now sink those reloads (and other instructions):
     - CmmSpillReload.rewriteAssignments
     - CmmSpillReload.removeDeadAssignmentsAndReloads

  * CmmStackLayout.stubSlotsOnDeath
	debug only: zero out dead slots when they die

  * Stack layout
     - CmmStackLayout.lifeSlotAnal: 
       find which sub-areas are live on entry to each block

     - CmmStackLayout.layout
       Lay out the stack, returning an AreaMap
         type AreaMap = FiniteMap Area ByteOff
          -- Byte offset of the oldest byte of the Area, 
          -- relative to the oldest byte of the Old Area

     - CmmStackLayout.manifestSP
       Manifest the stack pointer

   * Split into separate procedures

      - CmmProcPoint.procPointAnalysis
        Given set of proc points (computed earlier by
           CmmProcPoint.minimalProcPointSet) find which blocks 
           are reachable from each
	Each block should be reachable from *one* proc point, so 
	  the blocks reachable from P are the internal nodes of 
	  the final procedure P
        NB: if we the earlier analysis had produced too few proc-points 
            we should nevertheless be fine by code duplication; but
	    that is not implemented

      - CmmProcPoint.splitAtProcPoints
	Using this info, split into separate procedures

      - CmmBuildInfoTables.setInfoTableStackMap
	Attach stack maps to each info table


----------------------------------------------------
	Proc-points
----------------------------------------------------

Consider this program, which has a diamond control flow, 
with a call on one branch
 fn(p,x) {
        h()
	if b then { ... f(x) ...; q=5; goto J }
             else { ...; q=7; goto J }
     J: ..p...q...
  }
then the join point J is a "proc-point".  So, is 'p' passed to J
as a parameter?  Or, if 'p' was saved on the stack anyway, perhaps
to keep it alive across the call to h(), maybe 'p' gets communicated
to J that way. This is an awkward choice.  (We think that we currently
never pass variables to join points via arguments.)

Furthermore, there is *no way* to pass q to J in a register (other
than a parameter register).

What we want is to do register allocation across the whole caboodle.
Then we could drop all the code that deals with the above awkward
decisions about spilling variables across proc-points.

Note that J doesn't need an info table.

What we really want is for each LastCall (not LastJump/Ret) 
to have an info table.   Note that ProcPoints that are not successors
of calls don't need an info table.

Figuring out proc-points
~~~~~~~~~~~~~~~~~~~~~~~~
Proc-points are identified by
CmmProcPoint.minimalProcPointSet/extendPPSet Although there isn't
that much code, JD thinks that it could be done much more nicely using
a dominator analysis, using the Dataflow Engine.

----------------------------------------------------
		CAFs
----------------------------------------------------

* The code for a procedure f may refer to either the *closure* 
  or the *entry point* of another top-level procedure g.  
  If f is live, then so is g.  f's SRT must include g's closure.

* The CLabel for the entry-point/closure reveals whether g is 
  a CAF (or refers to CAFs).  See the IdLabel constructor of CLabel.

* The CAF-ness of the original top-level defininions is figured out
  (by TidyPgm) before we generate C--.  This CafInfo is only set for
  top-level Ids; nested bindings stay with MayHaveCafRefs.

* Currently an SRT contains (only) pointers to (top-level) closures.

* Consider this Core code
	f = \x -> let g = \y -> ...x...y...h1...
                  in ...h2...g...
  and suppose that h1, h2 have IdInfo of MayHaveCafRefs.
  Therefore, so will f,  But g will not (since it's nested).

  This generates C-- roughly like this:
     f_closure: .word f_entry
     f_entry() [info-tbl-for-f] { ...jump g_entry...jump h2... }
     g_entry() [info-tbl-for-g] { ...jump h1... }

  Note that there is no top-level closure for g (only an info table).
  This fact (whether or not there is a top-level closure) is recorded
  in the InfoTable attached to the CmmProc for f, g
  INVARIANT: 
     Any out-of-Group references to an IdLabel goes to
     a Proc whose InfoTable says "I have a top-level closure".
  Equivalently: 
     A CmmProc whose InfoTable says "I do not have a top-level
     closure" is referred to only from its own Group.

* So:   info-tbl-for-f must have an SRT that keeps h1,h2 alive
        info-tbl-for-g must have an SRT that keeps h1 (only) alive

  But if we just look for the free CAF refs, we get:
	f   h2 (only)
        g   h1

  So we need to do a transitive closure thing to flesh out 
  f's keep-alive refs to include h1.

* The SRT info is the C_SRT field of Cmm.ClosureTypeInfo in a
  CmmInfoTable attached to each CmmProc.  CmmPipeline.toTops actually does
  the attaching, right at the end of the pipeline.  The C_SRT part
  gives offsets within a single, shared table of closure pointers.

* DECIDED: we can generate SRTs based on the final Cmm program
  without knowledge of how it is generated.

----------------------------------------------------
		Foreign calls
----------------------------------------------------

See Note [Foreign calls] in CmmNode!  This explains that a safe
foreign call must do this:
  save thread state
  push info table (on thread stack) to describe frame
  make call (via C stack)
  pop info table
  restore thread state
and explains why this expansion must be done late in the day.

Hence, 
  - Every foreign call is represented as a middle node

  - *Unsafe* foreign calls are simply "fat machine instructions"
      and are passed along to the native code generator

  - *Safe* foreign calls are "lowered" to unsafe calls by wrapping
      them in the above save/restore sequence. This step is done
      very late in the pipeline, just before handing to the native
      code gen.   
  
      This lowering is done by BuildInfoTables.lowerSafeForeignCalls


NEW PLAN for foreign calls:
  - Unsafe foreign calls remain as a middle node (fat machine instruction)
    Even the parameter passing is not lowered (just as machine instrs
    get arguments).

  - Initially, safe foreign calls appear as LastCalls with 
	

----------------------------------------------------
		Cmm representations
----------------------------------------------------

* CmmDecl.hs
     The type [GenCmm d h g] represents a whole module, 
	** one list element per .o file **
	Without SplitObjs, the list has exactly one element

     newtype GenCmm d h g = Cmm [GenCmmTop d h g]  -- A whole .o file
     data GenCmmTop d h g
         = CmmProc h g           -- One procedure, graph d
         | CmmData <stuff> [d]   -- Initialised data, items d

  Old and new piplines use different representations
  	(CmmCvt.hs converts between the two)


-------------
OLD BACK END representations (OldCmm.hs):  
      type Cmm = GenCmm CmmStatic CmmInfo (ListGraph CmmStmt)
				-- A whole module
      newtype ListGraph i = ListGraph [GenBasicBlock i]

      data CmmStmt = Assign | Store | Return etc -- OLD BACK END ONLY


   Once the info tables are laid out, we replace CmmInfo with [CmmStatic]
      type RawCmm    = GenCmm CmmStatic [CmmStatic] (ListGraph CmmStmt)
   which represents the info tables as data, that should 
   immediately precede the code
  
-------------
NEW BACK END representations 
* Uses Hoopl library, a zero-boot package
* CmmNode defines a node of a flow graph.
* Cmm defines CmmGraph, CmmTop, Cmm
   - CmmGraph is a closed/closed graph + an entry node.

       data CmmGraph = CmmGraph { g_entry :: BlockId
                                , g_graph :: Graph CmmNode C C }

   - CmmTop is a top level chunk, specialization of GenCmmTop from CmmDecl.hs
       with CmmGraph as a flow graph.
   - Cmm is a collection of CmmTops.

       type Cmm          = GenCmm    CmmStatic CmmTopInfo CmmGraph
       type CmmTop       = GenCmmTop CmmStatic CmmTopInfo CmmGraph

   - CmmTop uses CmmTopInfo, which is a CmmInfoTable and CmmStackInfo

       data CmmTopInfo   = TopInfo {info_tbl :: CmmInfoTable, stack_info :: CmmStackInfo}

   - CmmStackInfo

       data CmmStackInfo = StackInfo {arg_space :: ByteOff, updfr_space :: Maybe ByteOff}

         * arg_space = SP offset on entry
         * updfr_space space = SP offset on exit
       Once the staci is manifested, we could drom CmmStackInfo, ie. get
         GenCmm CmmStatic CmmInfoTable CmmGraph, but we do not do that currently.


* MkGraph.hs: smart constructors for Cmm.hs
  Beware, the CmmAGraph defined here does not use AGraph from Hoopl,
  as CmmAGraph can be opened or closed at exit, See the notes in that module.

-------------
* SHARED stuff
  CmmDecl.hs - GenCmm and GenCmmTop types
  CmmExpr.hs - defines the Cmm expression types
             - CmmExpr, CmmReg, CmmLit, LocalReg, GlobalReg
             - Area, AreaId etc     (separate module?)
  CmmType.hs - CmmType, Width etc   (saparate module?)
  CmmMachOp.hs - MachOp and CallishMachOp types

  BlockId.hs defines  BlockId, BlockEnv, BlockSet
-------------