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


Ignore:
Timestamp:
Jan 12, 2007 8:55:51 PM (9 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] =`