Home My Page Projects Code Snippets Project Openings SML/NJ
Summary Activity Forums Tracker Lists Tasks Docs Surveys News SCM Files

SCM Repository

[smlnj] Diff of /sml/trunk/src/MLRISC/x86/mltree/x86.sml
ViewVC logotype

Diff of /sml/trunk/src/MLRISC/x86/mltree/x86.sml

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 744, Fri Dec 8 04:11:42 2000 UTC revision 1156, Thu Mar 21 22:01:11 2002 UTC
# Line 1  Line 1 
1  (*  (* x86.sml
2   *   *
3   * COPYRIGHT (c) 1998 Bell Laboratories.   * COPYRIGHT (c) 1998 Bell Laboratories.
4   *   *
# Line 39  Line 39 
39    
40  functor X86  functor X86
41    (structure X86Instr : X86INSTR    (structure X86Instr : X86INSTR
42     structure X86MLTree : MLTREE     structure MLTreeUtils : MLTREE_UTILS
43                            where T = X86Instr.T
44     structure ExtensionComp : MLTREE_EXTENSION_COMP     structure ExtensionComp : MLTREE_EXTENSION_COMP
45       where I = X86Instr and T = X86MLTree                          where I = X86Instr and T = X86Instr.T
46       sharing X86MLTree.Region = X86Instr.Region     structure MLTreeStream : MLTREE_STREAM
47       sharing X86MLTree.LabelExp = X86Instr.LabelExp                          where T = ExtensionComp.T
48      datatype arch = Pentium | PentiumPro | PentiumII | PentiumIII      datatype arch = Pentium | PentiumPro | PentiumII | PentiumIII
49      val arch : arch ref      val arch : arch ref
50      val cvti2f :      val cvti2f :
51             {ty: X86Instr.T.ty,
52              src: X86Instr.operand,
53           (* source operand, guaranteed to be non-memory! *)           (* source operand, guaranteed to be non-memory! *)
54           {ty: X86MLTree.ty, src: X86Instr.operand} ->            an: Annotations.annotations ref (* cluster annotations *)
55             } ->
56           {instrs : X86Instr.instruction list,(* the instructions *)           {instrs : X86Instr.instruction list,(* the instructions *)
57            tempMem: X86Instr.operand,         (* temporary for CVTI2F *)            tempMem: X86Instr.operand,         (* temporary for CVTI2F *)
58            cleanup: X86Instr.instruction list (* cleanup code *)            cleanup: X86Instr.instruction list (* cleanup code *)
# Line 61  Line 65 
65            val rewriteMemReg : bool            val rewriteMemReg : bool
66        end =        end =
67  struct  struct
   structure T = X86MLTree  
   structure S = T.Stream  
68    structure I = X86Instr    structure I = X86Instr
69      structure T = I.T
70      structure TS = ExtensionComp.TS
71    structure C = I.C    structure C = I.C
72    structure Shuffle = Shuffle(I)    structure Shuffle = Shuffle(I)
73    structure W32 = Word32    structure W32 = Word32
   structure LE = I.LabelExp  
74    structure A = MLRiscAnnotations    structure A = MLRiscAnnotations
75      structure CFG = ExtensionComp.CFG
76      structure CB = CellsBasis
77    
78    type instrStream = (I.instruction,C.cellset) T.stream    type instrStream = (I.instruction,C.cellset,CFG.cfg) TS.stream
79    type mltreeStream = (T.stm,T.mlrisc list) T.stream    type mltreeStream = (T.stm,T.mlrisc list,CFG.cfg) TS.stream
80    
81    datatype kind = REAL | INTEGER    datatype kind = REAL | INTEGER
82    
83    structure Gen = MLTreeGen    structure Gen = MLTreeGen
84       (structure T = T       (structure T = T
85          structure Cells = C
86        val intTy = 32        val intTy = 32
87        val naturalWidths = [32]        val naturalWidths = [32]
88        datatype rep = SE | ZE | NEITHER        datatype rep = SE | ZE | NEITHER
# Line 92  Line 98 
98    
99    (* The following hardcoded *)    (* The following hardcoded *)
100    fun isMemReg r = rewriteMemReg andalso    fun isMemReg r = rewriteMemReg andalso
101                     let val r = C.registerNum r                     let val r = CB.registerNum r
102                     in  r >= 8 andalso r < 32                     in  r >= 8 andalso r < 32
103                     end                     end
104    fun isFMemReg r = if enableFastFPMode andalso !fast_floating_point    fun isFMemReg r = if enableFastFPMode andalso !fast_floating_point
105                      then let val r = C.registerNum r                      then let val r = CB.registerNum r
106                           in r >= 8 andalso r < 32 end                           in r >= 8 andalso r < 32 end
107                      else true                      else true
108    val isAnyFMemReg = List.exists (fn r =>    val isAnyFMemReg = List.exists (fn r =>
109                                    let val r = C.registerNum r                                    let val r = CB.registerNum r
110                                    in  r >= 8 andalso r < 32 end                                    in  r >= 8 andalso r < 32 end
111                                   )                                   )
112    
113    val ST0 = C.ST 0    val ST0 = C.ST 0
114    val ST7 = C.ST 7    val ST7 = C.ST 7
115      val one = T.I.int_1
116    
117      val opcodes8 = {INC=I.INCB,DEC=I.DECB,ADD=I.ADDB,SUB=I.SUBB,
118                      NOT=I.NOTB,NEG=I.NEGB,
119                      SHL=I.SHLB,SHR=I.SHRB,SAR=I.SARB,
120                      OR=I.ORB,AND=I.ANDB,XOR=I.XORB}
121      val opcodes16 = {INC=I.INCW,DEC=I.DECW,ADD=I.ADDW,SUB=I.SUBW,
122                       NOT=I.NOTW,NEG=I.NEGW,
123                       SHL=I.SHLW,SHR=I.SHRW,SAR=I.SARW,
124                       OR=I.ORW,AND=I.ANDW,XOR=I.XORW}
125      val opcodes32 = {INC=I.INCL,DEC=I.DECL,ADD=I.ADDL,SUB=I.SUBL,
126                       NOT=I.NOTL,NEG=I.NEGL,
127                       SHL=I.SHLL,SHR=I.SHRL,SAR=I.SARL,
128                       OR=I.ORL,AND=I.ANDL,XOR=I.XORL}
129    
130    (*    (*
131     * The code generator     * The code generator
132     *)     *)
133    fun selectInstructions    fun selectInstructions
134         (instrStream as         (instrStream as
135          S.STREAM{emit,defineLabel,entryLabel,pseudoOp,annotation,          TS.S.STREAM{emit=emitInstruction,defineLabel,entryLabel,pseudoOp,
136                   beginCluster,endCluster,exitBlock,comment,...}) =                      annotation,getAnnotations,beginCluster,endCluster,exitBlock,comment,...}) =
137    let exception EA    let
138          val emit = emitInstruction o I.INSTR
139          exception EA
140    
141        (* label where a trap is generated -- one per cluster *)        (* label where a trap is generated -- one per cluster *)
142        val trapLabel = ref (NONE: (I.instruction * Label.label) option)        val trapLabel = ref (NONE: (I.instruction * Label.label) option)
# Line 128  Line 150 
150    
151        (* Add an overflow trap *)        (* Add an overflow trap *)
152        fun trap() =        fun trap() =
153        let val jmp =        let
154              val jmp =
155              case !trapLabel of              case !trapLabel of
156                NONE => let val label = Label.newLabel "trap"                NONE => let val label = Label.label "trap" ()
157                            val jmp   = I.JCC{cond=I.O,                            val jmp   =
158                                              opnd=I.ImmedLabel(LE.LABEL label)}                                I.ANNOTATION{i=I.jcc{cond=I.O,
159                                                       opnd=I.ImmedLabel(T.LABEL label)},
160                                               a=MLRiscAnnotations.BRANCHPROB (Probability.unlikely)}
161                        in  trapLabel := SOME(jmp, label); jmp end                        in  trapLabel := SOME(jmp, label); jmp end
162              | SOME(jmp, _) => jmp              | SOME(jmp, _) => jmp
163        in  emit jmp end        in  emitInstruction jmp end
164    
165        val newReg  = C.newReg        val newReg  = C.newReg
166        val newFreg = C.newFreg        val newFreg = C.newFreg
# Line 146  Line 171 
171          | fsize _  = error "fsize"          | fsize _  = error "fsize"
172    
173        (* mark an expression with a list of annotations *)        (* mark an expression with a list of annotations *)
174        fun mark'(i,[]) = i        fun mark'(i,[]) = emitInstruction(i)
175          | mark'(i,a::an) = mark'(I.ANNOTATION{i=i,a=a},an)          | mark'(i,a::an) = mark'(I.ANNOTATION{i=i,a=a},an)
176    
177        (* annotate an expression and emit it *)        (* annotate an expression and emit it *)
178        fun mark(i,an) = emit(mark'(i,an))        fun mark(i,an) = mark'(I.INSTR i,an)
179    
180        val emits = app emit        val emits = app emitInstruction
181    
182        (* emit parallel copies for integers        (* emit parallel copies for integers
183         * Translates parallel copies that involve memregs into         * Translates parallel copies that involve memregs into
# Line 161  Line 186 
186        fun copy([], [], an) = ()        fun copy([], [], an) = ()
187          | copy(dst, src, an) =          | copy(dst, src, an) =
188            let fun mvInstr{dst as I.MemReg rd, src as I.MemReg rs} =            let fun mvInstr{dst as I.MemReg rd, src as I.MemReg rs} =
189                    if C.sameColor(rd,rs) then [] else                    if CB.sameColor(rd,rs) then [] else
190                    let val tmpR = I.Direct(newReg())                    let val tmpR = I.Direct(newReg())
191                    in  [I.MOVE{mvOp=I.MOVL, src=src, dst=tmpR},                    in  [I.move{mvOp=I.MOVL, src=src, dst=tmpR},
192                         I.MOVE{mvOp=I.MOVL, src=tmpR, dst=dst}]                         I.move{mvOp=I.MOVL, src=tmpR, dst=dst}]
193                    end                    end
194                  | mvInstr{dst=I.Direct rd, src=I.Direct rs} =                  | mvInstr{dst=I.Direct rd, src=I.Direct rs} =
195                      if C.sameColor(rd,rs) then []                      if CB.sameColor(rd,rs) then []
196                      else [I.COPY{dst=[rd], src=[rs], tmp=NONE}]                      else [I.COPY{k=CB.GP, sz=32, dst=[rd], src=[rs], tmp=NONE}]
197                  | mvInstr{dst, src} = [I.MOVE{mvOp=I.MOVL, src=src, dst=dst}]                  | mvInstr{dst, src} = [I.move{mvOp=I.MOVL, src=src, dst=dst}]
198            in            in
199               emits (Shuffle.shuffle{mvInstr=mvInstr, ea=IntReg}               emits (Shuffle.shuffle{mvInstr=mvInstr, ea=IntReg}
200                 {tmp=SOME(I.Direct(newReg())),                 {tmp=SOME(I.Direct(newReg())),
# Line 179  Line 204 
204        (* conversions *)        (* conversions *)
205        val itow = Word.fromInt        val itow = Word.fromInt
206        val wtoi = Word.toInt        val wtoi = Word.toInt
207        fun toInt32 i = Int32.fromLarge(Int.toLarge i)        fun toInt32 i = T.I.toInt32(32, i)
208        val w32toi32 = Word32.toLargeIntX        val w32toi32 = Word32.toLargeIntX
209        val i32tow32 = Word32.fromLargeInt        val i32tow32 = Word32.fromLargeInt
210    
# Line 191  Line 216 
216        val ecx = I.Direct(C.ecx)        val ecx = I.Direct(C.ecx)
217        val edx = I.Direct(C.edx)        val edx = I.Direct(C.edx)
218    
219        fun immedLabel lab = I.ImmedLabel(LE.LABEL lab)        fun immedLabel lab = I.ImmedLabel(T.LABEL lab)
220    
221        (* Is the expression zero? *)        (* Is the expression zero? *)
222        fun isZero(T.LI 0) = true        fun isZero(T.LI z) = T.I.isZero z
         | isZero(T.LI32 0w0) = true  
223          | isZero(T.MARK(e,a)) = isZero e          | isZero(T.MARK(e,a)) = isZero e
224          | isZero _ = false          | isZero _ = false
225         (* Does the expression set the zero bit?         (* Does the expression set the zero bit?
# Line 231  Line 255 
255         *)         *)
256        fun fcopy'(fty, [], [], _) = ()        fun fcopy'(fty, [], [], _) = ()
257          | fcopy'(fty, dst as [_], src as [_], an) =          | fcopy'(fty, dst as [_], src as [_], an) =
258              mark(I.FCOPY{dst=dst,src=src,tmp=NONE}, an)              mark'(I.COPY{k=CB.FP, sz=fty, dst=dst,src=src,tmp=NONE}, an)
259          | fcopy'(fty, dst, src, an) =          | fcopy'(fty, dst, src, an) =
260              mark(I.FCOPY{dst=dst,src=src,tmp=SOME(I.FDirect(newFreg()))}, an)              mark'(I.COPY{k=CB.FP, sz=fty, dst=dst,src=src,tmp=SOME(I.FDirect(newFreg()))}, an)
261    
262        (* emit parallel copies for floating point.        (* emit parallel copies for floating point.
263         * Fast version.         * Fast version.
# Line 245  Line 269 
269          | fcopy''(fty, dst, src, an) =          | fcopy''(fty, dst, src, an) =
270            if true orelse isAnyFMemReg dst orelse isAnyFMemReg src then            if true orelse isAnyFMemReg dst orelse isAnyFMemReg src then
271            let val fsize = fsize fty            let val fsize = fsize fty
272                fun mvInstr{dst, src} = [I.FMOVE{fsize=fsize, src=src, dst=dst}]                fun mvInstr{dst, src} = [I.fmove{fsize=fsize, src=src, dst=dst}]
273            in            in
274                emits (Shuffle.shuffle{mvInstr=mvInstr, ea=RealReg}                emits (Shuffle.shuffle{mvInstr=mvInstr, ea=RealReg}
275                  {tmp=case dst of                  {tmp=case dst of
# Line 254  Line 278 
278                   dst=dst, src=src})                   dst=dst, src=src})
279            end            end
280            else            else
281              mark(I.FCOPY{dst=dst,src=src,tmp=              mark'(I.COPY{k=CB.FP, sz=fty, dst=dst,
282                            src=src,tmp=
283                           case dst of                           case dst of
284                             [_] => NONE                             [_] => NONE
285                           | _   => SOME(I.FPR(newFreg()))}, an)                           | _   => SOME(I.FPR(newFreg()))}, an)
# Line 268  Line 293 
293          | cond T.EQ = I.EQ | cond T.NE  = I.NE          | cond T.EQ = I.EQ | cond T.NE  = I.NE
294          | cond T.GE = I.GE | cond T.GEU = I.AE          | cond T.GE = I.GE | cond T.GEU = I.AE
295          | cond T.GT = I.GT | cond T.GTU = I.A          | cond T.GT = I.GT | cond T.GTU = I.A
296            | cond cc = error(concat["cond(", T.Basis.condToString cc, ")"])
297    
298          fun zero dst = emit(I.BINARY{binOp=I.XORL, src=dst, dst=dst})
299    
300        (* Move and annotate *)        (* Move and annotate *)
301        fun move'(src as I.Direct s, dst as I.Direct d, an) =        fun move'(src as I.Direct s, dst as I.Direct d, an) =
302            if C.sameColor(s,d) then ()            if CB.sameColor(s,d) then ()
303            else mark(I.COPY{dst=[d], src=[s], tmp=NONE}, an)            else mark'(I.COPY{k=CB.GP, sz=32, dst=[d], src=[s], tmp=NONE}, an)
304            | move'(I.Immed 0, dst as I.Direct d, an) =
305                mark(I.BINARY{binOp=I.XORL, src=dst, dst=dst}, an)
306          | move'(src, dst, an) = mark(I.MOVE{mvOp=I.MOVL, src=src, dst=dst}, an)          | move'(src, dst, an) = mark(I.MOVE{mvOp=I.MOVL, src=src, dst=dst}, an)
307    
308        (* Move only! *)        (* Move only! *)
309        fun move(src, dst) = move'(src, dst, [])        fun move(src, dst) = move'(src, dst, [])
310    
       fun zero dst = emit(I.BINARY{binOp=I.XORL, src=dst, dst=dst})  
   
311        val readonly = I.Region.readonly        val readonly = I.Region.readonly
312    
313        (*        (*
314         * Compute an effective address.  This is a new version         * Compute an effective address.
315         *)         *)
316        fun address(ea, mem) =        fun address(ea, mem) = let
       let (* tricky way to negate without overflow! *)  
           fun neg32 w = Word32.notb w + 0w1  
   
317            (* Keep building a bigger and bigger effective address expressions            (* Keep building a bigger and bigger effective address expressions
318             * The input is a list of trees             * The input is a list of trees
319             * b -- base             * b -- base
# Line 299  Line 324 
324            fun doEA([], b, i, s, d) = makeAddressingMode(b, i, s, d)            fun doEA([], b, i, s, d) = makeAddressingMode(b, i, s, d)
325              | doEA(t::trees, b, i, s, d) =              | doEA(t::trees, b, i, s, d) =
326                (case t of                (case t of
327                   T.LI n   => doEAImmed(trees, n, b, i, s, d)                   T.LI n   => doEAImmed(trees, toInt32 n, b, i, s, d)
328                 | T.LI32 n => doEAImmedw(trees, n, b, i, s, d)                 | T.CONST _ => doEALabel(trees, t, b, i, s, d)
329                 | T.CONST c => doEALabel(trees, LE.CONST c, b, i, s, d)                 | T.LABEL _ => doEALabel(trees, t, b, i, s, d)
330                 | T.LABEL le => doEALabel(trees, le, b, i, s, d)                 | T.LABEXP le => doEALabel(trees, le, b, i, s, d)
331                 | T.ADD(32, t1, t2 as T.REG(_,r)) =>                 | T.ADD(32, t1, t2 as T.REG(_,r)) =>
332                      if isMemReg r then doEA(t2::t1::trees, b, i, s, d)                      if isMemReg r then doEA(t2::t1::trees, b, i, s, d)
333                      else doEA(t1::t2::trees, b, i, s, d)                      else doEA(t1::t2::trees, b, i, s, d)
334                 | T.ADD(32, t1, t2) => doEA(t1::t2::trees, b, i, s, d)                 | T.ADD(32, t1, t2) => doEA(t1::t2::trees, b, i, s, d)
335                 | T.SUB(32, t1, T.LI n) =>                 | T.SUB(32, t1, T.LI n) =>
336                      (* can't overflow here *)                      doEA(t1::T.LI(T.I.NEG(32,n))::trees, b, i, s, d)
337                      doEA(t1::T.LI32(neg32(Word32.fromInt n))::trees, b, i, s, d)                 | T.SLL(32, t1, T.LI n) => let
338                 | T.SUB(32, t1, T.LI32 n) =>                      val n = T.I.toInt(32, n)
339                      doEA(t1::T.LI32(neg32 n)::trees, b, i, s, d)                   in
340                 | T.SLL(32, t1, T.LI 0) => displace(trees, t1, b, i, s, d)                     case n
341                 | T.SLL(32, t1, T.LI 1) => indexed(trees, t1, t, 1, b, i, s, d)                     of 0 => displace(trees, t1, b, i, s, d)
342                 | T.SLL(32, t1, T.LI 2) => indexed(trees, t1, t, 2, b, i, s, d)                      | 1 => indexed(trees, t1, t, 1, b, i, s, d)
343                 | T.SLL(32, t1, T.LI 3) => indexed(trees, t1, t, 3, b, i, s, d)                      | 2 => indexed(trees, t1, t, 2, b, i, s, d)
344                 | T.SLL(32, t1, T.LI32 0w0) => displace(trees, t1, b, i, s, d)                      | 3 => indexed(trees, t1, t, 3, b, i, s, d)
345                 | T.SLL(32, t1, T.LI32 0w1) => indexed(trees,t1,t,1,b,i,s,d)                      | _ => displace(trees, t, b, i, s, d)
346                 | T.SLL(32, t1, T.LI32 0w2) => indexed(trees,t1,t,2,b,i,s,d)                   end
                | T.SLL(32, t1, T.LI32 0w3) => indexed(trees,t1,t,3,b,i,s,d)  
347                 | t => displace(trees, t, b, i, s, d)                 | t => displace(trees, t, b, i, s, d)
348                )                )
349    
350            (* Add an immed constant *)            (* Add an immed constant *)
351            and doEAImmed(trees, 0, b, i, s, d) = doEA(trees, b, i, s, d)            and doEAImmed(trees, 0, b, i, s, d) = doEA(trees, b, i, s, d)
352              | doEAImmed(trees, n, b, i, s, I.Immed m) =              | doEAImmed(trees, n, b, i, s, I.Immed m) =
353                   doEA(trees, b, i, s, (* no overflow! *)                   doEA(trees, b, i, s, I.Immed(n+m))
                        I.Immed(w32toi32(Word32.fromInt n + i32tow32 m)))  
354              | doEAImmed(trees, n, b, i, s, I.ImmedLabel le) =              | doEAImmed(trees, n, b, i, s, I.ImmedLabel le) =
                  doEA(trees, b, i, s, I.ImmedLabel(LE.PLUS(le,LE.INT n)))  
             | doEAImmed(trees, n, b, i, s, _) = error "doEAImmed"  
   
           (* Add an immed32 constant *)  
           and doEAImmedw(trees, 0w0, b, i, s, d) = doEA(trees, b, i, s, d)  
             | doEAImmedw(trees, n, b, i, s, I.Immed m) =  
                  (* no overflow! *)  
                  doEA(trees, b, i, s, I.Immed(w32toi32(i32tow32 m + n)))  
             | doEAImmedw(trees, n, b, i, s, I.ImmedLabel le) =  
355                   doEA(trees, b, i, s,                   doEA(trees, b, i, s,
356                        I.ImmedLabel(LE.PLUS(le,LE.INT(Word32.toIntX n)))                        I.ImmedLabel(T.ADD(32,le,T.LI(T.I.fromInt32(32, n)))))
357                        handle Overflow => error "doEAImmedw: constant too large")              | doEAImmed(trees, n, b, i, s, _) = error "doEAImmed"
             | doEAImmedw(trees, n, b, i, s, _) = error "doEAImmedw"  
358    
359            (* Add a label expression *)            (* Add a label expression *)
360            and doEALabel(trees, le, b, i, s, I.Immed 0) =            and doEALabel(trees, le, b, i, s, I.Immed 0) =
361                   doEA(trees, b, i, s, I.ImmedLabel le)                   doEA(trees, b, i, s, I.ImmedLabel le)
362              | doEALabel(trees, le, b, i, s, I.Immed m) =              | doEALabel(trees, le, b, i, s, I.Immed m) =
363                   doEA(trees, b, i, s,                   doEA(trees, b, i, s,
364                        I.ImmedLabel(LE.PLUS(le,LE.INT(Int32.toInt m)))                        I.ImmedLabel(T.ADD(32,le,T.LI(T.I.fromInt32(32, m))))
365                        handle Overflow => error "doEALabel: constant too large")                        handle Overflow => error "doEALabel: constant too large")
366              | doEALabel(trees, le, b, i, s, I.ImmedLabel le') =              | doEALabel(trees, le, b, i, s, I.ImmedLabel le') =
367                   doEA(trees, b, i, s, I.ImmedLabel(LE.PLUS(le,le')))                   doEA(trees, b, i, s, I.ImmedLabel(T.ADD(32,le,le')))
368              | doEALabel(trees, le, b, i, s, _) = error "doEALabel"              | doEALabel(trees, le, b, i, s, _) = error "doEALabel"
369    
370            and makeAddressingMode(NONE, NONE, _, disp) = disp            and makeAddressingMode(NONE, NONE, _, disp) = disp
# Line 364  Line 377 
377            (* generate code for tree and ensure that it is not in %esp *)            (* generate code for tree and ensure that it is not in %esp *)
378            and exprNotEsp tree =            and exprNotEsp tree =
379                let val r = expr tree                let val r = expr tree
380                in  if C.sameColor(r, C.esp) then                in  if CB.sameColor(r, C.esp) then
381                       let val tmp = newReg()                       let val tmp = newReg()
382                       in  move(I.Direct r, I.Direct tmp); tmp end                       in  move(I.Direct r, I.Direct tmp); tmp end
383                    else r                    else r
# Line 376  Line 389 
389              | displace(trees, t, b as SOME base, NONE, _, d) = (* no index *)              | displace(trees, t, b as SOME base, NONE, _, d) = (* no index *)
390                (* make t the index, but make sure that it is not %esp! *)                (* make t the index, but make sure that it is not %esp! *)
391                let val i = expr t                let val i = expr t
392                in  if C.sameColor(i, C.esp) then                in  if CB.sameColor(i, C.esp) then
393                      (* swap base and index *)                      (* swap base and index *)
394                      if C.sameColor(base, C.esp) then                      if CB.sameColor(base, C.esp) then
395                         doEA(trees, SOME i, b, 0, d)                         doEA(trees, SOME i, b, 0, d)
396                      else  (* base and index = %esp! *)                      else  (* base and index = %esp! *)
397                         let val index = newReg()                         let val index = newReg()
# Line 408  Line 421 
421        end (* address *)        end (* address *)
422    
423            (* reduce an expression into an operand *)            (* reduce an expression into an operand *)
424        and operand(T.LI i) = I.Immed(toInt32 i)        and operand(T.LI i) = I.Immed(toInt32(i))
425          | operand(T.LI32 w) = I.Immed(wToInt32 w)          | operand(x as (T.CONST _ | T.LABEL _)) = I.ImmedLabel x
426          | operand(T.CONST c) = I.ImmedLabel(LE.CONST c)          | operand(T.LABEXP le) = I.ImmedLabel le
         | operand(T.LABEL lab) = I.ImmedLabel lab  
427          | operand(T.REG(_,r)) = IntReg r          | operand(T.REG(_,r)) = IntReg r
428          | operand(T.LOAD(32,ea,mem)) = address(ea, mem)          | operand(T.LOAD(32,ea,mem)) = address(ea, mem)
429          | operand(t) = I.Direct(expr t)          | operand(t) = I.Direct(expr t)
# Line 454  Line 466 
466            * Compute an integer expression and put the result in            * Compute an integer expression and put the result in
467            * the destination register rd.            * the destination register rd.
468            *)            *)
469        and doExpr(exp, rd : I.C.cell, an) =        and doExpr(exp, rd : CB.cell, an) =
470            let val rdOpnd = IntReg rd            let val rdOpnd = IntReg rd
471    
472                fun equalRd(I.Direct r) = C.sameColor(r, rd)                fun equalRd(I.Direct r) = CB.sameColor(r, rd)
473                  | equalRd(I.MemReg r) = C.sameColor(r, rd)                  | equalRd(I.MemReg r) = CB.sameColor(r, rd)
474                  | equalRd _ = false                  | equalRd _ = false
475    
476                   (* Emit a binary operator.  If the destination is                   (* Emit a binary operator.  If the destination is
# Line 532  Line 544 
544                fun divrem(signed, overflow, e1, e2, resultReg) =                fun divrem(signed, overflow, e1, e2, resultReg) =
545                let val (opnd1, opnd2) = (operand e1, operand e2)                let val (opnd1, opnd2) = (operand e1, operand e2)
546                    val _ = move(opnd1, eax)                    val _ = move(opnd1, eax)
547                    val oper = if signed then (emit(I.CDQ); I.IDIVL)                    val oper = if signed then (emit(I.CDQ); I.IDIVL1)
548                               else (zero edx; I.DIVL)                               else (zero edx; I.DIVL1)
549                in  mark(I.MULTDIV{multDivOp=oper, src=regOrMem opnd2},an);                in  mark(I.MULTDIV{multDivOp=oper, src=regOrMem opnd2},an);
550                    move(resultReg, rdOpnd);                    move(resultReg, rdOpnd);
551                    if overflow then trap() else ()                    if overflow then trap() else ()
552                end                end
553    
554                    (* Optimize the special case for division *)                    (* Optimize the special case for division *)
555                fun divide(signed, overflow, e1, e2 as T.LI n) =                fun divide(signed, overflow, e1, e2 as T.LI n') = let
556                let fun isPowerOf2 w = Word.andb((w - 0w1), w) = 0w0                    val n = toInt32 n'
557                      val w = T.I.toWord32(32, n')
558                      fun isPowerOf2 w = W32.andb((w - 0w1), w) = 0w0
559                    fun log2 n =  (* n must be > 0!!! *)                    fun log2 n =  (* n must be > 0!!! *)
560                        let fun loop(0w1,pow) = pow                        let fun loop(0w1,pow) = pow
561                              | loop(w,pow) = loop(Word.>>(w, 0w1),pow+1)                              | loop(w,pow) = loop(W32.>>(w, 0w1),pow+1)
562                        in loop(n,0) end                        in loop(n,0) end
                   val w = Word.fromInt n  
563                in  if n > 1 andalso isPowerOf2 w then                in  if n > 1 andalso isPowerOf2 w then
564                       let val pow = T.LI(log2 w)                       let val pow = T.LI(T.I.fromInt(32,log2 w))
565                       in  if signed then                       in  if signed then
566                           (* signed; simulate round towards zero *)                           (* signed; simulate round towards zero *)
567                           let val label = Label.newLabel ""                           let val label = Label.anon()
568                               val reg1  = expr e1                               val reg1  = expr e1
569                               val opnd1 = I.Direct reg1                               val opnd1 = I.Direct reg1
570                           in  if setZeroBit e1 then ()                           in  if setZeroBit e1 then ()
# Line 561  Line 574 
574                                       I.UNARY{unOp=I.INCL, opnd=opnd1}                                       I.UNARY{unOp=I.INCL, opnd=opnd1}
575                                    else                                    else
576                                       I.BINARY{binOp=I.ADDL,                                       I.BINARY{binOp=I.ADDL,
577                                                src=I.Immed(toInt32 n - 1),                                                src=I.Immed(n - 1),
578                                                dst=opnd1});                                                dst=opnd1});
579                               defineLabel label;                               defineLabel label;
580                               shift(I.SARL, T.REG(32, reg1), pow)                               shift(I.SARL, T.REG(32, reg1), pow)
# Line 582  Line 595 
595                fun rem(signed, overflow, e1, e2) =                fun rem(signed, overflow, e1, e2) =
596                      divrem(signed, overflow, e1, e2, edx)                      divrem(signed, overflow, e1, e2, edx)
597    
598                      (* Makes sure the destination must be a register *)
599                  fun dstMustBeReg f =
600                      if isMemReg rd then
601                      let val tmpR = newReg()
602                          val tmp  = I.Direct(tmpR)
603                      in  f(tmpR, tmp); move(tmp, rdOpnd) end
604                      else f(rd, rdOpnd)
605    
606                    (* unsigned integer multiplication *)                    (* unsigned integer multiplication *)
607                fun uMultiply(e1, e2) =                fun uMultiply(e1, e2) =
608                    (* note e2 can never be (I.Direct edx) *)                    (* note e2 can never be (I.Direct edx) *)
609                    (move(operand e1, eax);                    (move(operand e1, eax);
610                     mark(I.MULTDIV{multDivOp=I.MULL,                     mark(I.MULTDIV{multDivOp=I.MULL1,
611                                    src=regOrMem(operand e2)},an);                                    src=regOrMem(operand e2)},an);
612                     move(eax, rdOpnd)                     move(eax, rdOpnd)
613                    )                    )
# Line 595  Line 616 
616                     * The only forms that are allowed that also sets the                     * The only forms that are allowed that also sets the
617                     * OF and CF flags are:                     * OF and CF flags are:
618                     *                     *
619                       *          (dst)  (src1)  (src2)
620                     *      imul r32, r32/m32, imm8                     *      imul r32, r32/m32, imm8
621                       *          (dst)  (src)
622                     *      imul r32, imm8                     *      imul r32, imm8
623                     *      imul r32, imm32                     *      imul r32, imm32
624                       *      imul r32, r32/m32
625                       * Note: destination must be a register!
626                     *)                     *)
627                fun multiply(e1, e2) =                fun multiply(e1, e2) =
628                let fun doit(i1 as I.Immed _, i2 as I.Immed _, dstR, dst) =                dstMustBeReg(fn (rd, rdOpnd) =>
629                        (move(i1, dst);                let fun doit(i1 as I.Immed _, i2 as I.Immed _) =
630                         mark(I.MUL3{dst=dstR, src1=i2, src2=NONE},an))                        (move(i1, rdOpnd);
631                      | doit(rm, i2 as I.Immed _, dstR, dst) =                         mark(I.BINARY{binOp=I.IMULL, dst=rdOpnd, src=i2},an))
632                          doit(i2, rm, dstR, dst)                      | doit(rm, i2 as I.Immed _) = doit(i2, rm)
633                      | doit(imm as I.Immed(i), rm, dstR, dst) =                      | doit(imm as I.Immed(i), rm) =
634                         mark(I.MUL3{dst=dstR, src1=rm, src2=SOME i},an)                             mark(I.MUL3{dst=rd, src1=rm, src2=i},an)
635                      | doit(r1 as I.Direct _, r2 as I.Direct _, dstR, dst) =                      | doit(r1 as I.Direct _, r2 as I.Direct _) =
636                        (move(r1, dst);                        (move(r1, rdOpnd);
637                         mark(I.MUL3{dst=dstR, src1=r2, src2=NONE},an))                         mark(I.BINARY{binOp=I.IMULL, dst=rdOpnd, src=r2},an))
638                      | doit(r1 as I.Direct _, rm, dstR, dst) =                      | doit(r1 as I.Direct _, rm) =
639                        (move(r1, dst);                        (move(r1, rdOpnd);
640                         mark(I.MUL3{dst=dstR, src1=rm, src2=NONE},an))                         mark(I.BINARY{binOp=I.IMULL, dst=rdOpnd, src=rm},an))
641                      | doit(rm, r as I.Direct _, dstR, dst) =                      | doit(rm, r as I.Direct _) = doit(r, rm)
642                         doit(r, rm, dstR, dst)                      | doit(rm1, rm2) =
                     | doit(rm1, rm2, dstR, dst) =  
643                         if equalRd rm2 then                         if equalRd rm2 then
644                         let val tmpR = newReg()                         let val tmpR = newReg()
645                             val tmp  = I.Direct tmpR                             val tmp  = I.Direct tmpR
646                         in move(rm1, tmp);                         in move(rm1, tmp);
647                            mark(I.MUL3{dst=tmpR, src1=rm2, src2=NONE},an);                            mark(I.BINARY{binOp=I.IMULL, dst=tmp, src=rm2},an);
648                            move(tmp, dst)                            move(tmp, rdOpnd)
649                         end                         end
650                         else                         else
651                           (move(rm1, dst);                           (move(rm1, rdOpnd);
652                            mark(I.MUL3{dst=dstR, src1=rm2, src2=NONE},an)                            mark(I.BINARY{binOp=I.IMULL, dst=rdOpnd, src=rm2},an)
653                           )                           )
654                    val (opnd1, opnd2) = (operand e1, operand e2)                    val (opnd1, opnd2) = (operand e1, operand e2)
655                in  if isMemReg rd then (* destination must be a real reg *)                in  doit(opnd1, opnd2)
                   let val tmpR = newReg()  
                       val tmp  = I.Direct tmpR  
                   in  doit(opnd1, opnd2, tmpR, tmp);  
                       move(tmp, rdOpnd)  
                   end  
                   else  
                       doit(opnd1, opnd2, rd, rdOpnd)  
656                end                end
657                  )
                  (* Makes sure the destination must be a register *)  
               fun dstMustBeReg f =  
                   if isMemReg rd then  
                   let val tmpR = newReg()  
                       val tmp  = I.Direct(tmpR)  
                   in  f(tmpR, tmp); move(tmp, rdOpnd) end  
                   else f(rd, rdOpnd)  
658    
659                   (* Emit a load instruction; makes sure that the destination                   (* Emit a load instruction; makes sure that the destination
660                    * is a register                    * is a register
# Line 755  Line 765 
765                let fun genCmov(dstR, _) =                let fun genCmov(dstR, _) =
766                    let val _ = doExpr(no, dstR, []) (* false branch *)                    let val _ = doExpr(no, dstR, []) (* false branch *)
767                        val cc = cmp(true, ty, cc, t1, t2, [])  (* compare *)                        val cc = cmp(true, ty, cc, t1, t2, [])  (* compare *)
768                    in  mark(I.CMOV{cond=cond cc, src=operand yes, dst=dstR}, an)                    in  mark(I.CMOV{cond=cond cc, src=regOrMem(operand yes),
769                                      dst=dstR}, an)
770                    end                    end
771                in  dstMustBeReg genCmov                in  dstMustBeReg genCmov
772                end                end
# Line 771  Line 782 
782                    (* Generate addition *)                    (* Generate addition *)
783                fun addition(e1, e2) =                fun addition(e1, e2) =
784                    case e1 of                    case e1 of
785                      T.REG(_,rs) => if C.sameColor(rs,rd) then addN e2                      T.REG(_,rs) => if CB.sameColor(rs,rd) then addN e2
786                                     else addition1(e1,e2)                                     else addition1(e1,e2)
787                    | _ => addition1(e1,e2)                    | _ => addition1(e1,e2)
788                and addition1(e1, e2) =                and addition1(e1, e2) =
789                    case e2 of                    case e2 of
790                      T.REG(_,rs) => if C.sameColor(rs,rd) then addN e1                      T.REG(_,rs) => if CB.sameColor(rs,rd) then addN e1
791                                     else addition2(e1,e2)                                     else addition2(e1,e2)
792                    | _ => addition2(e1,e2)                    | _ => addition2(e1,e2)
793                and addition2(e1,e2) =                and addition2(e1,e2) =
# Line 793  Line 804 
804                            move'(tmp, rdOpnd, [])                            move'(tmp, rdOpnd, [])
805                        end                        end
806                     else move'(IntReg rs, rdOpnd, an)                     else move'(IntReg rs, rdOpnd, an)
807               | (T.LI 0 | T.LI32 0w0) =>               | T.LI z => let
808                     val n = toInt32 z
809                   in
810                     if n=0 then
811                   (* As per Fermin's request, special optimization for rd := 0.                   (* As per Fermin's request, special optimization for rd := 0.
812                    * Currently we don't bother with the size.                    * Currently we don't bother with the size.
813                    *)                    *)
814                   if isMemReg rd then move'(I.Immed 0, rdOpnd, an)                   if isMemReg rd then move'(I.Immed 0, rdOpnd, an)
815                   else mark(I.BINARY{binOp=I.XORL, src=rdOpnd, dst=rdOpnd}, an)                   else mark(I.BINARY{binOp=I.XORL, src=rdOpnd, dst=rdOpnd}, an)
816               | T.LI n      => move'(I.Immed(toInt32 n), rdOpnd, an)                   else
817               | T.LI32 w    => move'(I.Immed(wToInt32 w), rdOpnd, an)                     move'(I.Immed(n), rdOpnd, an)
818               | T.CONST c   => move'(I.ImmedLabel(LE.CONST c), rdOpnd, an)                 end
819               | T.LABEL lab => move'(I.ImmedLabel lab, rdOpnd, an)               | (T.CONST _ | T.LABEL _) =>
820                     move'(I.ImmedLabel exp, rdOpnd, an)
821                 | T.LABEXP le => move'(I.ImmedLabel le, rdOpnd, an)
822    
823                 (* 32-bit addition *)                 (* 32-bit addition *)
824               | T.ADD(32, e, (T.LI 1|T.LI32 0w1)) => unary(I.INCL, e)               | T.ADD(32, e1, e2 as T.LI n) => let
825               | T.ADD(32, (T.LI 1|T.LI32 0w1), e) => unary(I.INCL, e)                   val n = toInt32 n
826               | T.ADD(32, e, T.LI ~1) => unary(I.DECL, e)                 in
827               | T.ADD(32, T.LI ~1, e) => unary(I.DECL, e)                   case n
828                     of 1  => unary(I.INCL, e1)
829                      | ~1 => unary(I.DECL, e1)
830                      | _ => addition(e1, e2)
831                   end
832                 | T.ADD(32, e1 as T.LI n, e2) => let
833                     val n = toInt32 n
834                   in
835                     case n
836                     of  1 => unary(I.INCL, e2)
837                      | ~1 => unary(I.DECL, e2)
838                      | _ => addition(e1, e2)
839                   end
840               | T.ADD(32, e1, e2) => addition(e1, e2)               | T.ADD(32, e1, e2) => addition(e1, e2)
841    
842                 (* 32-bit addition but set the flag!                 (* 32-bit addition but set the flag!
843                  * This is a stupid hack for now.                  * This is a stupid hack for now.
844                  *)                  *)
845               | T.ADD(0, e, (T.LI 1|T.LI32 0w1)) => unary(I.INCL, e)               | T.ADD(0, e, e1 as T.LI n) => let
846               | T.ADD(0, (T.LI 1|T.LI32 0w1), e) => unary(I.INCL, e)                   val n = T.I.toInt(32, n)
847               | T.ADD(0, e, T.LI ~1) => unary(I.DECL, e)                 in
848               | T.ADD(0, T.LI ~1, e) => unary(I.DECL, e)                   if n=1 then unary(I.INCL, e)
849                     else if n = ~1 then unary(I.DECL, e)
850                          else binaryComm(I.ADDL, e, e1)
851                   end
852                 | T.ADD(0, e1 as T.LI n, e) => let
853                     val n = T.I.toInt(32, n)
854                   in
855                     if n=1 then unary(I.INCL, e)
856                     else if n = ~1 then unary(I.DECL, e)
857                          else binaryComm(I.ADDL, e1, e)
858                   end
859               | T.ADD(0, e1, e2) => binaryComm(I.ADDL, e1, e2)               | T.ADD(0, e1, e2) => binaryComm(I.ADDL, e1, e2)
860    
861                 (* 32-bit subtraction *)                 (* 32-bit subtraction *)
862               | T.SUB(32, e, (T.LI 0 | T.LI32 0w0)) => doExpr(e, rd, an)               | T.SUB(32, e1, e2 as T.LI n) => let
863               | T.SUB(32, e, (T.LI 1 | T.LI32 0w1)) => unary(I.DECL, e)                   val n = toInt32 n
864               | T.SUB(32, e, T.LI ~1) => unary(I.INCL, e)                 in
865               | T.SUB(32, (T.LI 0 | T.LI32 0w0), e) => unary(I.NEGL, e)                   case n
866                     of 0 => doExpr(e1, rd, an)
867               (* Never mind:                    | 1 => unary(I.DECL, e1)
868                 | T.SUB(32, e1, e2 as T.LI n) =>                    | ~1 => unary(I.INCL, e1)
869                   (mark(I.LEA{r32=rd, addr=address(T.ADD(32, e1, T.LI(~n)),                    | _ => binary(I.SUBL, e1, e2)
870                                                    I.Region.readonly)}, an)                 end
871                    handle (Overflow|EA) => binary(I.SUBL, e1, e2))               | T.SUB(32, e1 as T.LI n, e2) =>
872               *)                   if T.I.isZero n then unary(I.NEGL, e2)
873                     else binary(I.SUBL, e1, e2)
874               | T.SUB(32, e1, e2) => binary(I.SUBL, e1, e2)               | T.SUB(32, e1, e2) => binary(I.SUBL, e1, e2)
875    
876               | T.MULU(32, x, y) => uMultiply(x, y)               | T.MULU(32, x, y) => uMultiply(x, y)
# Line 860  Line 899 
899               | T.LOAD(8, ea, mem) => load8(ea, mem)               | T.LOAD(8, ea, mem) => load8(ea, mem)
900               | T.LOAD(16, ea, mem) => load16(ea, mem)               | T.LOAD(16, ea, mem) => load16(ea, mem)
901               | T.LOAD(32, ea, mem) => load32(ea, mem)               | T.LOAD(32, ea, mem) => load32(ea, mem)
              | T.SX(_,_,T.LOAD(8,ea,mem)) => load8s(ea, mem)  
              | T.SX(_,_,T.LOAD(16,ea,mem)) => load16s(ea, mem)  
902    
903               | T.COND(32, T.CMP(ty, cc, t1, t2), T.LI yes, T.LI no) =>               | T.SX(32,8,T.LOAD(8,ea,mem)) => load8s(ea, mem)
904                   setcc(ty, cc, t1, t2, toInt32 yes, toInt32 no)               | T.SX(32,16,T.LOAD(16,ea,mem)) => load16s(ea, mem)
905               | T.COND(32, T.CMP(ty, cc, t1, t2), T.LI32 yes, T.LI32 no) =>               | T.ZX(32,8,T.LOAD(8,ea,mem)) => load8(ea, mem)
906                   setcc(ty, cc, t1, t2, Word32.toLargeIntX yes,               | T.ZX(32,16,T.LOAD(16,ea,mem)) => load16(ea, mem)
907                                         Word32.toLargeIntX no)  
908                 | T.COND(32, T.CMP(ty, cc, t1, t2), y as T.LI yes, n as T.LI no) =>
909                    (case !arch of (* PentiumPro and higher has CMOVcc *)
910                      Pentium => setcc(ty, cc, t1, t2, toInt32 yes, toInt32 no)
911                    | _ => cmovcc(ty, cc, t1, t2, y, n)
912                    )
913               | T.COND(32, T.CMP(ty, cc, t1, t2), yes, no) =>               | T.COND(32, T.CMP(ty, cc, t1, t2), yes, no) =>
914                  (case !arch of (* PentiumPro and higher has CMOVcc *)                  (case !arch of (* PentiumPro and higher has CMOVcc *)
915                     Pentium => unknownExp exp                     Pentium => unknownExp exp
# Line 935  Line 977 
977            in  mark(testopcode{lsrc=opnd1, rsrc=opnd2}, an)            in  mark(testopcode{lsrc=opnd1, rsrc=opnd2}, an)
978            end            end
979    
980              (* %eflags <- src *)
981          and moveToEflags src =
982              if CB.sameColor(src, C.eflags) then ()
983              else (move(I.Direct src, eax); emit(I.LAHF))
984    
985              (* dst <- %eflags *)
986          and moveFromEflags dst =
987              if CB.sameColor(dst, C.eflags) then ()
988              else (emit(I.SAHF); move(eax, I.Direct dst))
989    
990           (* generate a condition code expression           (* generate a condition code expression
991            * The zero is for setting the condition code!            * The zero is for setting the condition code!
992            * I have no idea why this is used.            * I have no idea why this is used.
993            *)            *)
994        and doCCexpr(T.CMP(ty, cc, t1, t2), rd, an) =        and doCCexpr(T.CMP(ty, cc, t1, t2), rd, an) =
995            if C.sameColor(rd, C.eflags) then            (cmp(false, ty, cc, t1, t2, an);
996               (cmp(false, ty, cc, t1, t2, an); ())             moveFromEflags rd
997              )
998            | doCCexpr(T.CC(cond,rs), rd, an) =
999              if CB.sameColor(rs,C.eflags) orelse CB.sameColor(rd,C.eflags) then
1000                 (moveToEflags rs; moveFromEflags rd)
1001            else            else
1002               error "doCCexpr: cmp"               move'(I.Direct rs, I.Direct rd, an)
1003          | doCCexpr(T.CCMARK(e,A.MARKREG f),rd,an) = (f rd; doCCexpr(e,rd,an))          | doCCexpr(T.CCMARK(e,A.MARKREG f),rd,an) = (f rd; doCCexpr(e,rd,an))
1004          | doCCexpr(T.CCMARK(e,a), rd, an) = doCCexpr(e,rd,a::an)          | doCCexpr(T.CCMARK(e,a), rd, an) = doCCexpr(e,rd,a::an)
1005          | doCCexpr(T.CCEXT e, cd, an) =          | doCCexpr(T.CCEXT e, cd, an) =
# Line 1003  Line 1059 
1059            end            end
1060    
1061            (* generate code for jumps *)            (* generate code for jumps *)
1062        and jmp(T.LABEL(lexp as LE.LABEL lab), labs, an) =        and jmp(lexp as T.LABEL lab, labs, an) =
1063               mark(I.JMP(I.ImmedLabel lexp, [lab]), an)               mark(I.JMP(I.ImmedLabel lexp, [lab]), an)
1064          | jmp(T.LABEL lexp, labs, an) = mark(I.JMP(I.ImmedLabel lexp, labs), an)          | jmp(T.LABEXP le, labs, an) = mark(I.JMP(I.ImmedLabel le, labs), an)
1065          | jmp(ea, labs, an)           = mark(I.JMP(operand ea, labs), an)          | jmp(ea, labs, an)           = mark(I.JMP(operand ea, labs), an)
1066    
1067         (* convert mlrisc to cellset:         (* convert mlrisc to cellset:
1068          *)          *)
1069         and cellset mlrisc =         and cellset mlrisc =
1070             let val addCCReg = C.CellSet.add             let val addCCReg = CB.CellSet.add
1071                 fun g([],acc) = acc                 fun g([],acc) = acc
1072                   | g(T.GPR(T.REG(_,r))::regs,acc)  = g(regs,C.addReg(r,acc))                   | g(T.GPR(T.REG(_,r))::regs,acc)  = g(regs,C.addReg(r,acc))
1073                   | g(T.FPR(T.FREG(_,f))::regs,acc) = g(regs,C.addFreg(f,acc))                   | g(T.FPR(T.FREG(_,f))::regs,acc) = g(regs,C.addFreg(f,acc))
# Line 1021  Line 1077 
1077             in  g(mlrisc, C.empty) end             in  g(mlrisc, C.empty) end
1078    
1079            (* generate code for calls *)            (* generate code for calls *)
1080        and call(ea, flow, def, use, mem, an) =        and call(ea, flow, def, use, mem, cutsTo, an, pops) =
1081            mark(I.CALL(operand ea,cellset(def),cellset(use),mem),an)        let fun return(set, []) = set
1082                | return(set, a::an) =
1083                  case #peek A.RETURN_ARG a of
1084                    SOME r => return(CB.CellSet.add(r, set), an)
1085                  | NONE => return(set, an)
1086          in
1087              mark(I.CALL{opnd=operand ea,defs=cellset(def),uses=cellset(use),
1088                          return=return(C.empty,an),cutsTo=cutsTo,mem=mem,
1089                          pops=pops},an)
1090          end
1091    
1092            (* generate code for integer stores *)            (* generate code for integer stores; first move data to %eax
1093        and store8(ea, d, mem, an) =             * This is mainly because we can't allocate to registers like
1094            let val src = (* movb has to use %eax as source. Stupid x86! *)             * ah, dl, dx etc.
1095               *)
1096          and genStore(mvOp, ea, d, mem, an) =
1097              let val src =
1098                   case immedOrReg(operand d) of                   case immedOrReg(operand d) of
1099                       src as I.Direct r =>                       src as I.Direct r =>
1100                         if C.sameColor(r,C.eax)                         if CB.sameColor(r,C.eax)
1101                         then src else (move(src, eax); eax)                         then src else (move(src, eax); eax)
1102                     | src => src                     | src => src
1103            in  mark(I.MOVE{mvOp=I.MOVB, src=src, dst=address(ea,mem)},an)            in  mark(I.MOVE{mvOp=mvOp, src=src, dst=address(ea,mem)},an)
1104            end            end
1105        and store16(ea, d, mem, an) = error "store16"  
1106              (* generate code for 8-bit integer stores *)
1107              (* movb has to use %eax as source. Stupid x86! *)
1108          and store8(ea, d, mem, an) = genStore(I.MOVB, ea, d, mem, an)
1109          and store16(ea, d, mem, an) =
1110            mark(I.MOVE{mvOp=I.MOVW, src=immedOrReg(operand d), dst=address(ea, mem)}, an)
1111        and store32(ea, d, mem, an) =        and store32(ea, d, mem, an) =
1112              move'(immedOrReg(operand d), address(ea, mem), an)              move'(immedOrReg(operand d), address(ea, mem), an)
1113    
# Line 1052  Line 1125 
1125    
1126            (* generate code for floating point compare and branch *)            (* generate code for floating point compare and branch *)
1127        and fbranch(fty, fcc, t1, t2, lab, an) =        and fbranch(fty, fcc, t1, t2, lab, an) =
1128              let fun j cc = mark(I.JCC{cond=cc, opnd=immedLabel lab},an)
1129              in  fbranching(fty, fcc, t1, t2, j)
1130              end
1131    
1132          and fbranching(fty, fcc, t1, t2, j) =
1133            let fun ignoreOrder (T.FREG _) = true            let fun ignoreOrder (T.FREG _) = true
1134                  | ignoreOrder (T.FLOAD _) = true                  | ignoreOrder (T.FLOAD _) = true
1135                  | ignoreOrder (T.FMARK(e,_)) = ignoreOrder e                  | ignoreOrder (T.FMARK(e,_)) = ignoreOrder e
# Line 1073  Line 1151 
1151                        val rsrc = foperand(fty, t2)                        val rsrc = foperand(fty, t2)
1152                        val fsize = fsize fty                        val fsize = fsize fty
1153                        fun cmp(lsrc, rsrc, fcc) =                        fun cmp(lsrc, rsrc, fcc) =
1154                            (emit(I.FCMP{fsize=fsize,lsrc=lsrc,rsrc=rsrc}); fcc)                        let val i = !arch <> Pentium
1155                          in  emit(I.FCMP{i=i,fsize=fsize,lsrc=lsrc,rsrc=rsrc});
1156                              fcc
1157                          end
1158                    in  case (lsrc, rsrc) of                    in  case (lsrc, rsrc) of
1159                           (I.FPR _, I.FPR _) => cmp(lsrc, rsrc, fcc)                           (I.FPR _, I.FPR _) => cmp(lsrc, rsrc, fcc)
1160                         | (I.FPR _, mem) => cmp(mem,lsrc,T.Basis.swapFcond fcc)                         | (I.FPR _, mem) => cmp(mem,lsrc,T.Basis.swapFcond fcc)
# Line 1094  Line 1175 
1175                fun testil i = emit(I.TESTL{lsrc=eax,rsrc=I.Immed(i)})                fun testil i = emit(I.TESTL{lsrc=eax,rsrc=I.Immed(i)})
1176                fun xoril i = emit(I.BINARY{binOp=I.XORL,src=I.Immed(i),dst=eax})                fun xoril i = emit(I.BINARY{binOp=I.XORL,src=I.Immed(i),dst=eax})
1177                fun cmpil i = emit(I.CMPL{rsrc=I.Immed(i), lsrc=eax})                fun cmpil i = emit(I.CMPL{rsrc=I.Immed(i), lsrc=eax})
               fun j(cc, lab) = mark(I.JCC{cond=cc, opnd=immedLabel lab},an)  
1178                fun sahf() = emit(I.SAHF)                fun sahf() = emit(I.SAHF)
1179                fun branch(fcc) =                fun branch(fcc) =
1180                    case fcc                    case fcc
1181                    of T.==   => (andil 0x4400; xoril 0x4000; j(I.EQ, lab))                    of T.==   => (andil 0x4400; xoril 0x4000; j(I.EQ))
1182                     | T.?<>  => (andil 0x4400; xoril 0x4000; j(I.NE, lab))                     | T.?<>  => (andil 0x4400; xoril 0x4000; j(I.NE))
1183                     | T.?    => (sahf(); j(I.P,lab))                     | T.?    => (sahf(); j(I.P))
1184                     | T.<=>  => (sahf(); j(I.NP,lab))                     | T.<=>  => (sahf(); j(I.NP))
1185                     | T.>    => (testil 0x4500;  j(I.EQ,lab))                     | T.>    => (testil 0x4500;  j(I.EQ))
1186                     | T.?<=  => (testil 0x4500;  j(I.NE,lab))                     | T.?<=  => (testil 0x4500;  j(I.NE))
1187                     | T.>=   => (testil 0x500; j(I.EQ,lab))                     | T.>=   => (testil 0x500; j(I.EQ))
1188                     | T.?<   => (testil 0x500; j(I.NE,lab))                     | T.?<   => (testil 0x500; j(I.NE))
1189                     | T.<    => (andil 0x4500; cmpil 0x100; j(I.EQ,lab))                     | T.<    => (andil 0x4500; cmpil 0x100; j(I.EQ))
1190                     | T.?>=  => (andil 0x4500; cmpil 0x100; j(I.NE,lab))                     | T.?>=  => (andil 0x4500; cmpil 0x100; j(I.NE))
1191                     | T.<=   => (andil 0x4100; cmpil 0x100; j(I.EQ,lab);                     | T.<=   => (andil 0x4100; cmpil 0x100; j(I.EQ);
1192                                  cmpil 0x4000; j(I.EQ,lab))                                  cmpil 0x4000; j(I.EQ))
1193                     | T.?>   => (sahf(); j(I.P,lab); testil 0x4100; j(I.EQ,lab))                     | T.?>   => (sahf(); j(I.P); testil 0x4100; j(I.EQ))
1194                     | T.<>   => (testil 0x4400; j(I.EQ,lab))                     | T.<>   => (testil 0x4400; j(I.EQ))
1195                     | T.?=   => (testil 0x4400; j(I.NE,lab))                     | T.?=   => (testil 0x4400; j(I.NE))
1196                     | _      => error "fbranch"                     | _      => error(concat[
1197                                      "fbranch(", T.Basis.fcondToString fcc, ")"
1198                                    ])
1199                     (*esac*)
1200    
1201                  (*
1202                   *             P  Z  C
1203                   * x < y       0  0  1
1204                   * x > y       0  0  0
1205                   * x = y       0  1  0
1206                   * unordered   1  1  1
1207                   * When it's unordered, all three flags, P, Z, C are set.
1208                   *)
1209    
1210                  fun fast_branch(fcc) =
1211                      case fcc
1212                      of T.==   => orderedOnly(I.EQ)
1213                       | T.?<>  => (j(I.P); j(I.NE))
1214                       | T.?    => j(I.P)
1215                       | T.<=>  => j(I.NP)
1216                       | T.>    => orderedOnly(I.A)
1217                       | T.?<=  => j(I.BE)
1218                       | T.>=   => orderedOnly(I.AE)
1219                       | T.?<   => j(I.B)
1220                       | T.<    => orderedOnly(I.B)
1221                       | T.?>=  => (j(I.P); j(I.AE))
1222                       | T.<=   => orderedOnly(I.BE)
1223                       | T.?>   => (j(I.P); j(I.A))
1224                       | T.<>   => orderedOnly(I.NE)
1225                       | T.?=   => j(I.EQ)
1226                       | _      => error(concat[
1227                                      "fbranch(", T.Basis.fcondToString fcc, ")"
1228                                    ])
1229                   (*esac*)                   (*esac*)
1230                  and orderedOnly fcc =
1231                  let val label = Label.anon()
1232                  in  emit(I.JCC{cond=I.P, opnd=immedLabel label});
1233                      j fcc;
1234                      defineLabel label
1235                  end
1236    
1237                val fcc = compare()                val fcc = compare()
1238            in  emit I.FNSTSW;            in  if !arch <> Pentium andalso
1239                     (enableFastFPMode andalso !fast_floating_point) then
1240                    fast_branch(fcc)
1241                  else
1242                    (emit I.FNSTSW;
1243                branch(fcc)                branch(fcc)
1244                    )
1245            end            end
1246    
1247        (*========================================================        (*========================================================
# Line 1144  Line 1268 
1268            in  if isMemOpnd opnd andalso (ty = 16 orelse ty = 32)            in  if isMemOpnd opnd andalso (ty = 16 orelse ty = 32)
1269                then (INTEGER, ty, opnd, [])                then (INTEGER, ty, opnd, [])
1270                else                else
1271                  let val {instrs, tempMem, cleanup} = cvti2f{ty=ty, src=opnd}                  let val {instrs, tempMem, cleanup} =
1272                            cvti2f{ty=ty, src=opnd, an=getAnnotations()}
1273                  in  emits instrs;                  in  emits instrs;
1274                      (INTEGER, 32, tempMem, cleanup)                      (INTEGER, 32, tempMem, cleanup)
1275                  end                  end
# Line 1185  Line 1310 
1310        and fload'(fty, ea, mem, fd, an) =        and fload'(fty, ea, mem, fd, an) =
1311              let val ea = address(ea, mem)              let val ea = address(ea, mem)
1312              in  mark(fld(fty, ea), an);              in  mark(fld(fty, ea), an);
1313                  if C.sameColor(fd,ST0) then ()                  if CB.sameColor(fd,ST0) then ()
1314                  else emit(fstp(fty, I.FDirect fd))                  else emit(fstp(fty, I.FDirect fd))
1315              end              end
1316    
# Line 1193  Line 1318 
1318    
1319            (* generate floating point expression and put the result in fd *)            (* generate floating point expression and put the result in fd *)
1320        and doFexpr'(fty, T.FREG(_, fs), fd, an) =        and doFexpr'(fty, T.FREG(_, fs), fd, an) =
1321              (if C.sameColor(fs,fd) then ()              (if CB.sameColor(fs,fd) then ()
1322               else mark(I.FCOPY{dst=[fd], src=[fs], tmp=NONE}, an)               else mark'(I.COPY{k=CB.FP, sz=64, dst=[fd], src=[fs], tmp=NONE}, an)
1323              )              )
1324          | doFexpr'(_, T.FLOAD(fty, ea, mem), fd, an) =          | doFexpr'(_, T.FLOAD(fty, ea, mem), fd, an) =
1325              fload'(fty, ea, mem, fd, an)              fload'(fty, ea, mem, fd, an)
1326          | doFexpr'(fty, T.FEXT fexp, fd, an) =          | doFexpr'(fty, T.FEXT fexp, fd, an) =
1327              (ExtensionComp.compileFext (reducer()) {e=fexp, fd=fd, an=an};              (ExtensionComp.compileFext (reducer()) {e=fexp, fd=fd, an=an};
1328               if C.sameColor(fd,ST0) then () else emit(fstp(fty, I.FDirect fd))               if CB.sameColor(fd,ST0) then () else emit(fstp(fty, I.FDirect fd))
1329              )              )
1330          | doFexpr'(fty, e, fd, an) =          | doFexpr'(fty, e, fd, an) =
1331              (reduceFexp(fty, e, []);              (reduceFexp(fty, e, []);
1332               if C.sameColor(fd,ST0) then ()               if CB.sameColor(fd,ST0) then ()
1333               else mark(fstp(fty, I.FDirect fd), an)               else mark(fstp(fty, I.FDirect fd), an)
1334              )              )
1335    
# Line 1286  Line 1411 
1411    
1412                and sameTree(LEAF(_, T.FREG(t1,f1), []),                and sameTree(LEAF(_, T.FREG(t1,f1), []),
1413                             LEAF(_, T.FREG(t2,f2), [])) =                             LEAF(_, T.FREG(t2,f2), [])) =
1414                          t1 = t2 andalso C.sameColor(f1,f2)                          t1 = t2 andalso CB.sameColor(f1,f2)
1415                  | sameTree _ = false                  | sameTree _ = false
1416    
1417                (* Traverse tree and generate code *)                (* Traverse tree and generate code *)
# Line 1443  Line 1568 
1568        and fbinop(targetFty,        and fbinop(targetFty,
1569                   binOp, binOpR, ibinOp, ibinOpR, lsrc, rsrc, fd, an) =                   binOp, binOpR, ibinOp, ibinOpR, lsrc, rsrc, fd, an) =
1570                (* Put the mem operand in rsrc *)                (* Put the mem operand in rsrc *)
1571            let val _ = floatingPointUsed := true;            let
1572                fun isMemOpnd(T.FREG(_, f)) = isFMemReg f                fun isMemOpnd(T.FREG(_, f)) = isFMemReg f
1573                  | isMemOpnd(T.FLOAD _) = true                  | isMemOpnd(T.FLOAD _) = true
1574                  | isMemOpnd(T.CVTI2F(_, (16 | 32), _)) = true                  | isMemOpnd(T.CVTI2F(_, (16 | 32), _)) = true
# Line 1484  Line 1609 
1609            end            end
1610    
1611        and doFexpr''(fty, e, fd, an) =        and doFexpr''(fty, e, fd, an) =
1612             (floatingPointUsed := true;
1613            case e of            case e of
1614              T.FREG(_,fs) => if C.sameColor(fs,fd) then ()              T.FREG(_,fs) => if CB.sameColor(fs,fd) then ()
1615                              else fcopy''(fty, [fd], [fs], an)                              else fcopy''(fty, [fd], [fs], an)
1616              (* Stupid x86 does everything as 80-bits internally. *)              (* Stupid x86 does everything as 80-bits internally. *)
1617    
# Line 1525  Line 1651 
1651            | T.FEXT fexp =>            | T.FEXT fexp =>
1652               ExtensionComp.compileFext (reducer()) {e=fexp, fd=fd, an=an}               ExtensionComp.compileFext (reducer()) {e=fexp, fd=fd, an=an}
1653            | _ => error("doFexpr''")            | _ => error("doFexpr''")
1654             )
1655    
1656         (*========================================================         (*========================================================
1657          * Tie the two styles of fp code generation together          * Tie the two styles of fp code generation together
# Line 1545  Line 1672 
1672            then doFexpr''(fty, e, fd, an)            then doFexpr''(fty, e, fd, an)
1673            else doFexpr'(fty, e, fd, an)            else doFexpr'(fty, e, fd, an)
1674    
1675          (*================================================================
1676           * Optimizations for x := x op y
1677           * Special optimizations:
1678           * Generate a binary operator, result must in memory.
1679           * The source must not be in memory
1680           *================================================================*)
1681          and binaryMem(binOp, src, dst, mem, an) =
1682              mark(I.BINARY{binOp=binOp, src=immedOrReg(operand src),
1683                            dst=address(dst,mem)}, an)
1684          and unaryMem(unOp, opnd, mem, an) =
1685              mark(I.UNARY{unOp=unOp, opnd=address(opnd,mem)}, an)
1686    
1687          and isOne(T.LI n) = n = one
1688            | isOne _ = false
1689    
1690          (*
1691           * Perform optimizations based on recognizing
1692           *    x := x op y    or
1693           *    x := y op x
1694           * first.
1695           *)
1696          and store(ty, ea, d, mem, an,
1697                    {INC,DEC,ADD,SUB,NOT,NEG,SHL,SHR,SAR,OR,AND,XOR},
1698                    doStore
1699                   ) =
1700              let fun default() = doStore(ea, d, mem, an)
1701                  fun binary1(t, t', unary, binary, ea', x) =
1702                      if t = ty andalso t' = ty then
1703                         if MLTreeUtils.eqRexp(ea, ea') then
1704                            if isOne x then unaryMem(unary, ea, mem, an)
1705                            else binaryMem(binary, x, ea, mem, an)
1706                          else default()
1707                      else default()
1708                  fun unary(t,unOp, ea') =
1709                      if t = ty andalso MLTreeUtils.eqRexp(ea, ea') then
1710                         unaryMem(unOp, ea, mem, an)
1711                      else default()
1712                  fun binary(t,t',binOp,ea',x) =
1713                      if t = ty andalso t' = ty andalso
1714                         MLTreeUtils.eqRexp(ea, ea') then
1715                          binaryMem(binOp, x, ea, mem, an)
1716                      else default()
1717    
1718                  fun binaryCom1(t,unOp,binOp,x,y) =
1719                  if t = ty then
1720                  let fun again() =
1721                        case y of
1722                          T.LOAD(ty',ea',_) =>
1723                            if ty' = ty andalso MLTreeUtils.eqRexp(ea, ea') then
1724                               if isOne x then unaryMem(unOp, ea, mem, an)
1725                               else binaryMem(binOp,x,ea,mem,an)
1726                            else default()
1727                        | _ => default()
1728                  in  case x of
1729                        T.LOAD(ty',ea',_) =>
1730                          if ty' = ty andalso MLTreeUtils.eqRexp(ea, ea') then
1731                             if isOne y then unaryMem(unOp, ea, mem, an)
1732                             else binaryMem(binOp,y,ea,mem,an)
1733                          else again()
1734                      | _ => again()
1735                  end
1736                  else default()
1737    
1738                  fun binaryCom(t,binOp,x,y) =
1739                  if t = ty then
1740                  let fun again() =
1741                        case y of
1742                          T.LOAD(ty',ea',_) =>
1743                            if ty' = ty andalso MLTreeUtils.eqRexp(ea, ea') then
1744                               binaryMem(binOp,x,ea,mem,an)
1745                            else default()
1746                        | _ => default()
1747                  in  case x of
1748                        T.LOAD(ty',ea',_) =>
1749                          if ty' = ty andalso MLTreeUtils.eqRexp(ea, ea') then
1750                             binaryMem(binOp,y,ea,mem,an)
1751                          else again()
1752                      | _ => again()
1753                  end
1754                  else default()
1755    
1756              in  case d of
1757                    T.ADD(t,x,y) => binaryCom1(t,INC,ADD,x,y)
1758                  | T.SUB(t,T.LOAD(t',ea',_),x) => binary1(t,t',DEC,SUB,ea',x)
1759                  | T.ORB(t,x,y) => binaryCom(t,OR,x,y)
1760                  | T.ANDB(t,x,y) => binaryCom(t,AND,x,y)
1761                  | T.XORB(t,x,y) => binaryCom(t,XOR,x,y)
1762                  | T.SLL(t,T.LOAD(t',ea',_),x) => binary(t,t',SHL,ea',x)
1763                  | T.SRL(t,T.LOAD(t',ea',_),x) => binary(t,t',SHR,ea',x)
1764                  | T.SRA(t,T.LOAD(t',ea',_),x) => binary(t,t',SAR,ea',x)
1765                  | T.NEG(t,T.LOAD(t',ea',_)) => unary(t,NEG,ea')
1766                  | T.NOTB(t,T.LOAD(t',ea',_)) => unary(t,NOT,ea')
1767                  | _ => default()
1768              end (* store *)
1769    
1770            (* generate code for a statement *)            (* generate code for a statement *)
1771        and stmt(T.MV(_, rd, e), an) = doExpr(e, rd, an)        and stmt(T.MV(_, rd, e), an) = doExpr(e, rd, an)
1772          | stmt(T.FMV(fty, fd, e), an) = doFexpr(fty, e, fd, an)          | stmt(T.FMV(fty, fd, e), an) = doFexpr(fty, e, fd, an)
# Line 1552  Line 1774 
1774          | stmt(T.COPY(_, dst, src), an) = copy(dst, src, an)          | stmt(T.COPY(_, dst, src), an) = copy(dst, src, an)
1775          | stmt(T.FCOPY(fty, dst, src), an) = fcopy(fty, dst, src, an)          | stmt(T.FCOPY(fty, dst, src), an) = fcopy(fty, dst, src, an)
1776          | stmt(T.JMP(e, labs), an) = jmp(e, labs, an)          | stmt(T.JMP(e, labs), an) = jmp(e, labs, an)
1777          | stmt(T.CALL{funct, targets, defs, uses, region, ...}, an) =          | stmt(T.CALL{funct, targets, defs, uses, region, pops, ...}, an) =
1778               call(funct,targets,defs,uses,region,an)               call(funct,targets,defs,uses,region,[],an, pops)
1779            | stmt(T.FLOW_TO(T.CALL{funct, targets, defs, uses, region, pops, ...},
1780                             cutTo), an) =
1781                 call(funct,targets,defs,uses,region,cutTo,an, pops)
1782          | stmt(T.RET _, an) = mark(I.RET NONE, an)          | stmt(T.RET _, an) = mark(I.RET NONE, an)
1783          | stmt(T.STORE(8, ea, d, mem), an) = store8(ea, d, mem, an)          | stmt(T.STORE(8, ea, d, mem), an)  =
1784          | stmt(T.STORE(16, ea, d, mem), an) = store16(ea, d, mem, an)               store(8, ea, d, mem, an, opcodes8, store8)
1785          | stmt(T.STORE(32, ea, d, mem), an) = store32(ea, d, mem, an)          | stmt(T.STORE(16, ea, d, mem), an) =
1786                 store(16, ea, d, mem, an, opcodes16, store16)
1787            | stmt(T.STORE(32, ea, d, mem), an) =
1788                 store(32, ea, d, mem, an, opcodes32, store32)
1789    
1790          | stmt(T.FSTORE(fty, ea, d, mem), an) = fstore(fty, ea, d, mem, an)          | stmt(T.FSTORE(fty, ea, d, mem), an) = fstore(fty, ea, d, mem, an)
1791          | stmt(T.BCC(cc, lab), an) = branch(cc, lab, an)          | stmt(T.BCC(cc, lab), an) = branch(cc, lab, an)
1792          | stmt(T.DEFINE l, _) = defineLabel l          | stmt(T.DEFINE l, _) = defineLabel l
# Line 1591  Line 1820 
1820           )           )
1821    
1822        and reducer() =        and reducer() =
1823            T.REDUCER{reduceRexp    = expr,            TS.REDUCER{reduceRexp    = expr,
1824                      reduceFexp    = fexpr,                      reduceFexp    = fexpr,
1825                      reduceCCexp   = ccExpr,                      reduceCCexp   = ccExpr,
1826                      reduceStm     = stmt,                      reduceStm     = stmt,
1827                      operand       = operand,                      operand       = operand,
1828                      reduceOperand = reduceOpnd,                      reduceOperand = reduceOpnd,
1829                      addressOf     = fn e => address(e, I.Region.memory), (*XXX*)                      addressOf     = fn e => address(e, I.Region.memory), (*XXX*)
1830                      emit          = mark,                      emit          = mark',
1831                      instrStream   = instrStream,                      instrStream   = instrStream,
1832                      mltreeStream  = self()                      mltreeStream  = self()
1833                     }                     }
1834    
1835        and self() =        and self() =
1836            S.STREAM            TS.S.STREAM
1837            {  beginCluster= beginCluster',            {  beginCluster= beginCluster',
1838               endCluster  = endCluster',               endCluster  = endCluster',
1839               emit        = doStmt,               emit        = doStmt,
# Line 1613  Line 1842 
1842               entryLabel  = entryLabel,               entryLabel  = entryLabel,
1843               comment     = comment,               comment     = comment,
1844               annotation  = annotation,               annotation  = annotation,
1845                 getAnnotations = getAnnotations,
1846               exitBlock   = fn mlrisc => exitBlock(cellset mlrisc)               exitBlock   = fn mlrisc => exitBlock(cellset mlrisc)
1847            }            }
1848    

Legend:
Removed from v.744  
changed lines
  Added in v.1156

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0