Changes between Version 14 and Version 15 of Commentary/Compiler/CmmType


Ignore:
Timestamp:
Jan 12, 2007 8:55:51 PM (8 years ago)
Author:
p_tanski
Comment:

cleanup; begin colour-code

Legend:

Unmodified
Added
Removed
Modified
  • Commentary/Compiler/CmmType

    v14 v15  
    147147Cmm modules contain static data elements (see [wiki:Commentary/Compiler/CmmType#LiteralsandLabels Literals and Labels]) and [wiki:Commentary/Compiler/CmmType#BasicBlocks:Procedures Basic Blocks], collected together in `Cmm`, a type synonym for `GenCmm`, defined in [[GhcFile(compiler/cmm/Cmm.hs)]]: 
    148148{{{ 
    149 newtype GenCmm d i = Cmm [GenCmmTop d i] 
    150   
    151 type Cmm = GenCmm CmmStatic CmmStmt 
    152  
    153 data GenCmmTop d i 
    154   = CmmProc 
    155      [d]               -- Info table, may be empty 
    156      CLabel            -- Used to generate both info & entry labels 
    157      [LocalReg]        -- Argument locals live on entry (C-- procedure params) 
    158      [GenBasicBlock i] -- Code, may be empty.  The first block is 
    159                        -- the entry point.  The order is otherwise initially  
    160                        -- unimportant, but at some point the code gen will 
    161                        -- fix the order. 
    162  
    163                        -- the BlockId of the first block does not give rise 
    164                        -- to a label.  To jump to the first block in a Proc, 
    165                        -- use the appropriate CLabel. 
    166  
    167   -- some static data. 
    168   | CmmData Section [d] -- constant values only 
    169  
    170 type CmmTop = GenCmmTop CmmStatic CmmStmt 
     149#!html 
     150<pre> 
     151<u><font color=Magenta>newtype</font></u> <font color=Green>GenCmm</font> <font color=Black>d</font> <font color=Black>i</font> <font color=Blue>=</font> <font color=Green>Cmm</font> <font color=Blue>[</font><font color=Green>GenCmmTop</font> <font color=Black>d</font> <font color=Black>i</font><font color=Blue>]</font> 
     152 
     153<u><font color=Magenta>type</font></u> <font color=Green>Cmm</font> <font color=Blue>=</font> <font color=Green>GenCmm</font> <font color=Green>CmmStatic</font> <font color=Green>CmmStmt</font> 
     154 
     155 
     156<u><font color=Magenta>data</font></u> <font color=Green>GenCmmTop</font> <font color=Black>d</font> <font color=Black>i</font> 
     157  <font color=Blue>=</font> <font color=Green>CmmProc</font> 
     158     <font color=Blue>[</font><font color=Black>d</font><font color=Blue>]</font>              <font color=Red>-- Info table, may be empty</font> 
     159     <font color=Green>CLabel</font>            <font color=Red>-- Used to generate both info &amp; entry labels</font> 
     160     <font color=Blue>[</font><font color=Green>LocalReg</font><font color=Blue>]</font>        <font color=Red>-- Argument locals live on entry (C-- procedure params)</font> 
     161     <font color=Blue>[</font><font color=Green>GenBasicBlock</font> <font color=Black>i</font><font color=Blue>]</font> <font color=Red>-- Code, may be empty.  The first block is</font> 
     162                       <font color=Red>-- the entry point.  The order is otherwise initially </font> 
     163                       <font color=Red>-- unimportant, but at some point the code gen will</font> 
     164                       <font color=Red>-- fix the order.</font> 
     165 
     166                       <font color=Red>-- the BlockId of the first block does not give rise</font> 
     167                       <font color=Red>-- to a label.  To jump to the first block in a Proc,</font> 
     168                       <font color=Red>-- use the appropriate CLabel.</font> 
     169 
     170  <font color=Red>-- some static data.</font> 
     171  <font color=Blue>|</font> <font color=Green>CmmData</font> <font color=Green>Section</font> <font color=Blue>[</font><font color=Black>d</font><font color=Blue>]</font>      <font color=Red>-- constant values only</font> 
     172 
     173<u><font color=Magenta>type</font></u> <font color=Green>CmmTop</font> <font color=Blue>=</font> <font color=Green>GenCmmTop</font> <font color=Green>CmmStatic</font> <font color=Green>CmmStmt</font> 
     174</pre> 
    171175}}} 
    172176`CmmStmt` is described in [wiki:Commentary/Compiler/CmmType#StatementsandCalls Statements and Calls];[[BR]] 
     
    179183Cmm procedures are represented by the first constructor in `GenCmmTop d i`: 
    180184{{{ 
    181     CmmProc [d] CLabel [LocalReg] [GenBasicBlock i] 
     185#!html 
     186<pre> 
     187    <font color=Green>CmmProc</font> <font color=Blue>[</font><font color=Black>d</font><font color=Blue>]</font> <font color=Green>CLabel</font> <font color=Blue>[</font><font color=Green>LocalReg</font><font color=Blue>]</font> <font color=Blue>[</font><font color=Green>GenBasicBlock</font> <font color=Black>i</font><font color=Blue>]</font> 
     188</pre> 
    182189}}} 
    183190For a description of Cmm labels and the `CLabel` data type, see the subsection [wiki:Commentary/Compiler/CmmType#LiteralsandLabels Literals and Labels], below. 
     
    185192Cmm Basic Blocks are labeled blocks of Cmm code ending in an explicit jump.  Sections (see [wiki:Commentary/Compiler/CmmType#SectionsandDirectives Sections and Directives]) have no jumps--in Cmm, Sections cannot contain nested Procedures (see, e.g., [wiki:Commentary/Compiler/CmmType#CompilingCmmwithGHC Compiling Cmm with GHC]).  Basic Blocks encapsulate parts of Procedures.  The data type `GenBasicBlock` and the type synonym `CmmBasicBlock` encapsulate Basic Blocks; they are defined in [[GhcFile(compiler/cmm/Cmm.hs)]]: 
    186193{{{ 
    187 data GenBasicBlock i = BasicBlock BlockId [i] 
    188  
    189 type CmmBasicBlock = GenBasicBlock CmmStmt 
    190  
    191 newtype BlockId = BlockId Unique 
    192   deriving (Eq,Ord) 
    193  
    194 instance Uniquable BlockId where 
    195   getUnique (BlockId u) = u 
     194#!html 
     195<pre> 
     196<u><font color=Magenta>data</font></u> <font color=Green>GenBasicBlock</font> <font color=Black>i</font> <font color=Blue>=</font> <font color=Green>BasicBlock</font> <font color=Green>BlockId</font> <font color=Blue>[</font><font color=Black>i</font><font color=Blue>]</font> 
     197 
     198<u><font color=Magenta>type</font></u> <font color=Green>CmmBasicBlock</font> <font color=Blue>=</font> <font color=Green>GenBasicBlock</font> <font color=Green>CmmStmt</font> 
     199 
     200<u><font color=Magenta>newtype</font></u> <font color=Green>BlockId</font> <font color=Blue>=</font> <font color=Green>BlockId</font> <font color=Green>Unique</font> 
     201  <u><font color=Magenta>deriving</font></u> <font color=Blue>(</font><font color=Green>Eq</font><font color=Blue>,</font><font color=Green>Ord</font><font color=Blue>)</font> 
     202 
     203<u><font color=Magenta>instance</font></u> <font color=Green>Uniquable</font> <font color=Green>BlockId</font> <u><font color=Magenta>where</font></u> 
     204  <font color=Orange>getUnique</font> <font color=Blue>(</font><font color=Green>BlockId</font> <font color=Black>u</font><font color=Blue>)</font> <font color=Blue>=</font> <font color=Black>u</font> 
     205</pre> 
    196206}}} 
    197207The `BlockId` data type simply carries a `Unique` with each Basic Block.  For descriptions of `Unique`, see  
     
    205215C-- and Cmm hide the actual number of registers available on a particular machine by assuming an "infinite" supply of registers.  A backend, such as the NCG or C compiler on GHC, will later optimise the number of registers used and assign the Cmm variables to actual machine registers; the NCG temporarily stores any overflow in a small memory stack called the ''spill stack'', while the C compiler relies on C's own runtime system.  Haskell handles Cmm registers with three data types: `LocalReg`, `GlobalReg` and `CmmReg`.  `LocalReg`s and `GlobalRegs` are collected together in a single `Cmm` data type: 
    206216{{{ 
    207 data CmmReg  
    208   = CmmLocal  LocalReg 
    209   | CmmGlobal GlobalReg 
     217#!html 
     218<pre> 
     219<u><font color=Magenta>data</font></u> <font color=Green>CmmReg</font>  
     220  <font color=Blue>=</font> <font color=Green>CmmLocal</font>  <font color=Green>LocalReg</font> 
     221  <font color=Blue>|</font> <font color=Green>CmmGlobal</font> <font color=Green>GlobalReg</font> 
     222  <u><font color=Magenta>deriving</font></u><font color=Blue>(</font> <font color=Green>Eq</font> <font color=Blue>)</font> 
     223</pre> 
    210224}}} 
    211225 
     
    213227Local Registers exist within the scope of a Procedure: 
    214228{{{ 
    215 data LocalReg 
    216   = LocalReg !Unique MachRep 
     229#!html 
     230<pre> 
     231<u><font color=Magenta>data</font></u> <font color=Green>LocalReg</font> 
     232  <font color=Blue>=</font> <font color=Green>LocalReg</font> <font color=Blue>!</font><font color=Green>Unique</font> <font color=Green>MachRep</font> 
     233</pre> 
    217234}}} 
    218235For a list of references with information on `Unique`, see the [wiki:Commentary/Compiler/CmmType#BasicBlocksandProcedures Basic Blocks and Procedures] section, above. 
     
    220237A `MachRep`, the type of a machine register, is defined in [[GhcFile(compiler/cmm/MachOp.hs)]]: 
    221238{{{ 
    222 data MachRep 
    223   = I8          -- integral type, 8 bits wide (a byte) 
    224   | I16         -- integral type, 16 bits wide 
    225   | I32         -- integral type, 32 bits wide 
    226   | I64         -- integral type, 64 bits wide 
    227   | I128        -- integral type, 128 bits wide (an integral vector register) 
    228   | F32         -- floating point type, 32 bits wide (float) 
    229   | F64         -- floating point type, 64 bits wide (double) 
    230   | F80         -- extended double-precision, used in x86 native codegen only. 
     239#!html 
     240<pre> 
     241<u><font color=Magenta>data</font></u> <font color=Green>MachRep</font> 
     242  <font color=Blue>=</font> <font color=Green>I8</font>         <font color=Red>-- integral type, 8 bits wide (a byte)</font> 
     243  <font color=Blue>|</font> <font color=Green>I16</font>                <font color=Red>-- integral type, 16 bits wide</font> 
     244  <font color=Blue>|</font> <font color=Green>I32</font>                <font color=Red>-- integral type, 32 bits wide</font> 
     245  <font color=Blue>|</font> <font color=Green>I64</font>                <font color=Red>-- integral type, 64 bits wide</font> 
     246  <font color=Blue>|</font> <font color=Green>I128</font>       <font color=Red>-- integral type, 128 bits wide (an integral vector register)</font> 
     247  <font color=Blue>|</font> <font color=Green>F32</font>                <font color=Red>-- floating point type, 32 bits wide (float)</font> 
     248  <font color=Blue>|</font> <font color=Green>F64</font>                <font color=Red>-- floating point type, 64 bits wide (double)</font> 
     249  <font color=Blue>|</font> <font color=Green>F80</font>                <font color=Red>-- extended double-precision, used in x86 native codegen only.</font> 
     250  <u><font color=Magenta>deriving</font></u> <font color=Blue>(</font><font color=Green>Eq</font><font color=Blue>,</font> <font color=Green>Ord</font><font color=Blue>,</font> <font color=Green>Show</font><font color=Blue>)</font> 
     251</pre> 
    231252}}} 
    232253There is currently no register for floating point vectors, such as `F128`.  The types of Cmm variables are defined in the Happy parser file [[GhcFile(compiler/cmm/CmmParse.y)]] and the Alex lexer file [[GhcFile(compiler/cmm/CmmLex.x)]].  (Happy and Alex will compile these into `CmmParse.hs` and `CmmLex.hs`, respectively.)  Cmm recognises the following `C--` types as parseable tokens, listed next to their corresponding {{{define}}}s in [[GhcFile(includes/Cmm.h)]] and their STG types: 
     
    248269These are universal both to a Cmm module and to the whole compiled program.  Variables are global if they are declared at the top-level of a compilation unit (outside any procedure).  Global Variables are marked as external symbols with the `.globl` assembler directive.  In Cmm, global registers are used for special STG registers and specific registers for passing arguments and returning values.  The Haskell representation of Global Variables (Registers) is the `GlobalReg` data type, defined in [[GhcFile(compiler/cmm/Cmm.hs)]]: 
    249270{{{ 
    250 data GlobalReg 
    251   -- Argument and return registers 
    252   = VanillaReg                  -- general registers (int, pointer, char values) 
    253         {-# UNPACK #-} !Int     -- the register number, such as R3, R11 
    254   | FloatReg            -- single-precision floating-point registers 
    255         {-# UNPACK #-} !Int     -- register number 
    256   | DoubleReg           -- double-precision floating-point registers 
    257         {-# UNPACK #-} !Int     -- register number 
    258   | LongReg             -- long int registers (64-bit, really) 
    259         {-# UNPACK #-} !Int     -- register number 
    260   -- STG registers 
    261   | Sp                  -- Stack ptr; points to last occupied stack location. 
    262   | SpLim               -- Stack limit 
    263   | Hp                  -- Heap ptr; points to last occupied heap location. 
    264   | HpLim               -- Heap limit register 
    265   | CurrentTSO          -- pointer to current thread's TSO 
    266   | CurrentNursery      -- pointer to allocation area 
    267   | HpAlloc             -- allocation count for heap check failure 
    268  
    269                 -- We keep the address of some commonly-called  
    270                 -- functions in the register table, to keep code 
    271                 -- size down: 
    272   | GCEnter1            -- stg_gc_enter_1 
    273   | GCFun               -- stg_gc_fun 
    274  
    275   -- Base offset for the register table, used for accessing registers 
    276   -- which do not have real registers assigned to them.  This register 
    277   -- will only appear after we have expanded GlobalReg into memory accesses 
    278   -- (where necessary) in the native code generator. 
    279   | BaseReg 
    280  
    281   -- Base Register for PIC (position-independent code) calculations 
    282   -- Only used inside the native code generator. It's exact meaning differs 
    283   -- from platform to platform (see compiler/nativeGen/PositionIndependentCode.hs). 
    284   | PicBaseReg 
     271#!html 
     272<pre> 
     273<u><font color=Magenta>data</font></u> <font color=Green>GlobalReg</font> 
     274  <font color=Red>-- Argument and return registers</font> 
     275  <font color=Blue>=</font> <font color=Green>VanillaReg</font>                 <font color=Red>-- pointers, unboxed ints and chars</font> 
     276        <font color=Red>{-# UNPACK #-}</font> <font color=Green>!</font><font color=Green>Int</font>    <font color=Red>-- register number, such as R3, R11</font> 
     277 
     278  <font color=Blue>|</font> <font color=Green>FloatReg</font>           <font color=Red>-- single-precision floating-point registers</font> 
     279        <font color=Red>{-# UNPACK #-}</font> <font color=Green>!</font><font color=Green>Int</font>    <font color=Red>-- register number</font> 
     280 
     281  <font color=Blue>|</font> <font color=Green>DoubleReg</font>          <font color=Red>-- double-precision floating-point registers</font> 
     282        <font color=Red>{-# UNPACK #-}</font> <font color=Green>!</font><font color=Green>Int</font>    <font color=Red>-- register number</font> 
     283 
     284  <font color=Blue>|</font> <font color=Green>LongReg</font>            <font color=Red>-- long int registers (64-bit, really)</font> 
     285        <font color=Red>{-# UNPACK #-}</font> <font color=Green>!</font><font color=Green>Int</font>    <font color=Red>-- register number</font> 
     286 
     287  <font color=Red>-- STG registers</font> 
     288  <font color=Blue>|</font> <font color=Green>Sp</font>                 <font color=Red>-- Stack ptr; points to last occupied stack location.</font> 
     289  <font color=Blue>|</font> <font color=Green>SpLim</font>              <font color=Red>-- Stack limit</font> 
     290  <font color=Blue>|</font> <font color=Green>Hp</font>                 <font color=Red>-- Heap ptr; points to last occupied heap location.</font> 
     291  <font color=Blue>|</font> <font color=Green>HpLim</font>              <font color=Red>-- Heap limit register</font> 
     292  <font color=Blue>|</font> <font color=Green>CurrentTSO</font>         <font color=Red>-- pointer to current thread's TSO</font> 
     293  <font color=Blue>|</font> <font color=Green>CurrentNursery</font>     <font color=Red>-- pointer to allocation area</font> 
     294  <font color=Blue>|</font> <font color=Green>HpAlloc</font>            <font color=Red>-- allocation count for heap check failure</font> 
     295 
     296                <font color=Red>-- We keep the address of some commonly-called </font> 
     297                <font color=Red>-- functions in the register table, to keep code</font> 
     298                <font color=Red>-- size down:</font> 
     299  <font color=Blue>|</font> <font color=Green>GCEnter1</font>           <font color=Red>-- stg_gc_enter_1</font> 
     300  <font color=Blue>|</font> <font color=Green>GCFun</font>              <font color=Red>-- stg_gc_fun</font> 
     301 
     302  <font color=Red>-- Base offset for the register table, used for accessing registers</font> 
     303  <font color=Red>-- which do not have real registers assigned to them.  This register</font> 
     304  <font color=Red>-- will only appear after we have expanded GlobalReg into memory accesses</font> 
     305  <font color=Red>-- (where necessary) in the native code generator.</font> 
     306  <font color=Blue>|</font> <font color=Green>BaseReg</font> 
     307 
     308  <font color=Red>-- Base Register for PIC (position-independent code) calculations</font> 
     309  <font color=Red>-- Only used inside the native code generator. It's exact meaning differs</font> 
     310  <font color=Red>-- from platform to platform  (see compiler/nativeGen/PositionIndependentCode.hs).</font> 
     311  <font color=Blue>|</font> <font color=Green>PicBaseReg</font> 
     312</pre> 
    285313}}} 
    286314For a description of the `Hp` and `Sp` ''virtual registers'', see [wiki:Commentary/Rts/HaskellExecution The Haskell Execution Model] page.  General `GlobalReg`s are clearly visible in Cmm code according to the following syntax defined in [[GhcFile(compiler/cmm/CmmLex.x)]]: 
     
    310338Hints are represented in Haskell as `MachHint`s, defined near `MachRep` in [[GhcFile(compiler/cmm/MachOp.hs)]]: 
    311339{{{ 
    312 data MachHint 
    313   = NoHint      -- string: "NoHint"     Cmm syntax: [empty]     (C-- uses "") 
    314   | PtrHint     -- string: "PtrHint"    Cmm syntax: "ptr"       (C-- uses "address") 
    315   | SignedHint  -- string: "SignedHint" Cmm syntax: "signed" 
    316   | FloatHint   -- string: "FloatHint"  Cmm syntax: "float" 
    317 }}} 
     340#!html 
     341<pre> 
     342<u><font color=Magenta>data</font></u> <font color=Green>MachHint</font> 
     343  <font color=Blue>=</font> <font color=Green>NoHint</font>     <font color=Red>-- string: "NoHint"     Cmm syntax: [empty]</font> 
     344  <font color=Blue>|</font> <font color=Green>PtrHint</font>    <font color=Red>-- string: "PtrHint"    Cmm syntax: "ptr"    (C-- uses "address")</font> 
     345  <font color=Blue>|</font> <font color=Green>SignedHint</font> <font color=Red>-- string: "SignedHint" Cmm syntax: "signed"</font> 
     346  <font color=Blue>|</font> <font color=Green>FloatHint</font>  <font color=Red>-- string: "FloatHint"  Cmm syntax: "float" </font> 
     347</pre> 
     348}}} 
     349 
    318350Although the C-- specification does not allow the C-- type system to statically distinguish between floats, signed ints, unsigned ints or pointers, Cmm does. Cmm `MachRep`s carry the float or int kind of a variable, either within a local block or in a global register.  `GlobalReg` includes separate constructors for `Vanilla`, `Float`, `Double` and `Long`.  Cmm still does not distinguish between signed ints, unsigned ints and pointers (addresses) at the register level, as these are given ''hint'' pseudo-types or their real type is determined as they run through primitive operations.  `MachHint`s still follow the C-- specification and carry kind information as an aide to the backend optimisers.   
    319351 
     
    406438Cmm literals are exactly like C-- literals, including the Haskell-style type syntax, for example: `0x00000001::bits32`.  Cmm literals may be used for initialisation by assignment or in expressions. The `CmmLit` and `CmmStatic` data types, defined in [[GhcFile(compiler/cmm/Cmm.hs)]] together represent Cmm literals, static information and Cmm labels: 
    407439{{{ 
    408 data CmmLit 
    409   = CmmInt Integer  MachRep 
    410         -- Interpretation: the 2's complement representation of the value 
    411         -- is truncated to the specified size.  This is easier than trying 
    412         -- to keep the value within range, because we don't know whether 
    413         -- it will be used as a signed or unsigned value (the MachRep doesn't 
    414         -- distinguish between signed & unsigned). 
    415   | CmmFloat  Rational MachRep 
    416   | CmmLabel    CLabel                  -- Address of label 
    417   | CmmLabelOff CLabel Int              -- Address of label + byte offset 
     440#!html 
     441<pre> 
     442<u><font color=Magenta>data</font></u> <font color=Green>CmmLit</font> 
     443  <font color=Blue>=</font> <font color=Green>CmmInt</font> <font color=Green>Integer</font>  <font color=Green>MachRep</font> 
     444        <font color=Red>-- Interpretation: the 2's complement representation of the value</font> 
     445        <font color=Red>-- is truncated to the specified size.  This is easier than trying</font> 
     446        <font color=Red>-- to keep the value within range, because we don't know whether</font> 
     447        <font color=Red>-- it will be used as a signed or unsigned value (the MachRep doesn't</font> 
     448        <font color=Red>-- distinguish between signed &amp; unsigned).</font> 
     449  <font color=Blue>|</font> <font color=Green>CmmFloat</font>  <font color=Green>Rational</font> <font color=Green>MachRep</font> 
     450  <font color=Blue>|</font> <font color=Green>CmmLabel</font>    <font color=Green>CLabel</font>                        <font color=Red>-- Address of label</font> 
     451  <font color=Blue>|</font> <font color=Green>CmmLabelOff</font> <font color=Green>CLabel</font> <font color=Green>Int</font>           <font color=Red>-- Address of label + byte offset</font> 
    418452   
    419         -- Due to limitations in the C backend, the following 
    420         -- MUST ONLY be used inside the info table indicated by label2 
    421         -- (label2 must be the info label), and label1 must be an 
    422         -- SRT, a slow entrypoint or a large bitmap (see the Mangler) 
    423         -- Don't use it at all unless tablesNextToCode. 
    424         -- It is also used inside the NCG when generating 
    425         -- position-independent code.  
    426   | CmmLabelDiffOff CLabel CLabel Int   -- label1 - label2 + offset 
     453        <font color=Red>-- Due to limitations in the C backend, the following</font> 
     454        <font color=Red>-- MUST ONLY be used inside the info table indicated by label2</font> 
     455        <font color=Red>-- (label2 must be the info label), and label1 must be an</font> 
     456        <font color=Red>-- SRT, a slow entrypoint or a large bitmap (see the Mangler)</font> 
     457        <font color=Red>-- Don't use it at all unless tablesNextToCode.</font> 
     458        <font color=Red>-- It is also used inside the NCG during when generating</font> 
     459        <font color=Red>-- position-independent code. </font> 
     460  <font color=Blue>|</font> <font color=Green>CmmLabelDiffOff</font> <font color=Green>CLabel</font> <font color=Green>CLabel</font> <font color=Green>Int</font>   <font color=Red>-- label1 - label2 + offset</font> 
     461</pre> 
    427462}}} 
    428463Note how the `CmmLit` constructor `CmmInt Integer MachRep` contains sign information in the `Integer`, the representation of the literal itself: this conforms to the C-- specification, where integral literals contain sign information. For an example of a function using `CmmInt` sign information, see `cmmMachOpFold` in [[GhcFile(compiler/cmm/CmmOpt.hs)]], where sign-operations are performed on the `Integer`. 
     
    675710 
    676711==== Quasi-operator Syntax ==== 
    677 If you read to the end of `expr` in [[GhcFile(compiler/cmm/CmmParse.y)]], you will notice that Cmm expressions also recognise a set of name (not symbol) based operators that would probably be better understood as ''quasi-operators'', listed in the next production rule: `expr0`.  The syntax for these quasi-operators is in some cases similar to syntax for Cmm statements and generally conform to the C-- specification, sections 3.3.2 (`expr`) and 7.4.1 (syntax of primitive operators), ''except that'' 3. ''and, by the equivalence of the two,'' 1. ''may return'' '''multiple''' '' arguments''. In Cmm, quasi-operators may have side effects. The syntax for quasi-operators may be: 
     712If you read to the end of `expr` in [[GhcFile(compiler/cmm/CmmParse.y)]], in the next production rule, `expr0`, you will notice that Cmm expressions also recognise a set of name (not symbol) based operators that would probably be better understood as ''quasi-operators''.  The syntax for these quasi-operators is in some cases similar to syntax for Cmm statements and generally conform to the C-- specification, sections 3.3.2 (`expr`) and 7.4.1 (syntax of primitive operators), ''except that'' 3. ''and, by the equivalence of the two,'' 1. ''may return'' '''multiple''' '' arguments''. In Cmm, quasi-operators may have side effects. The syntax for quasi-operators may be: 
    678713 1. `expr0` {{{`name`}}} `expr0`[[BR]](just like infix-functions in Haskell); 
    679714 1. `type[ expression ]`[[BR]](the memory access quasi-expression described in [wiki:Commentary/Compiler/CmmType#MemoryAccess Memory Access]; the Haskell representation of this syntax is `CmmLoad CmmExpr MachRep`);  
     
    711746Cmm Statements generally conform to the C-- specification, with a few exceptions noted below.  Cmm Statements implement: 
    712747 * no-op; the empty statement: `;` 
    713  * C-- (C99/C++ style) comments: `// ... /n` and `/* ... */` 
     748 * C-- (C99/C++ style) comments: `// ... \n` and `/* ... */` 
    714749 * the assignment operator: `=` 
    715750 * store operation (assignment to a memory location): `type[expr] =`