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 545, Thu Feb 24 13:56:44 2000 UTC revision 695, Mon Aug 7 23:57:38 2000 UTC
# Line 1  Line 1 
1  (* X86.sml -- pattern matching version of x86 instruction set generation.  (*
2   *   *
3   * COPYRIGHT (c) 1998 Bell Laboratories.   * COPYRIGHT (c) 1998 Bell Laboratories.
4   *   *
# Line 31  Line 31 
31  functor X86  functor X86
32    (structure X86Instr : X86INSTR    (structure X86Instr : X86INSTR
33     structure X86MLTree : MLTREE     structure X86MLTree : MLTREE
34    (* structure PseudoInstrs : X86_PSEUDO_INSTR *)     structure ExtensionComp : MLTREE_EXTENSION_COMP
35         where I = X86Instr and T = X86MLTree
36       sharing X86MLTree.Region = X86Instr.Region       sharing X86MLTree.Region = X86Instr.Region
37       sharing X86MLTree.LabelExp = X86Instr.LabelExp       sharing X86MLTree.LabelExp = X86Instr.LabelExp
      (* sharing PseudoInstrs.I = X86Instr  
      sharing PseudoInstrs.T = X86MLTree *)  
38      datatype arch = Pentium | PentiumPro | PentiumII | PentiumIII      datatype arch = Pentium | PentiumPro | PentiumII | PentiumIII
39      val arch : arch ref      val arch : arch ref
40      val tempMem : X86Instr.operand (* temporary for CVTI2F *)      val cvti2f :
41      (* val memRegsUsed : word ref *)    (* bit mask of memRegs used *)           (* source operand, guaranteed to be non-memory! *)
42             {ty: X86MLTree.ty, src: X86Instr.operand} ->
43             {instrs : X86Instr.instruction list,(* the instructions *)
44              tempMem: X86Instr.operand,         (* temporary for CVTI2F *)
45              cleanup: X86Instr.instruction list (* cleanup code *)
46             }
47    ) : sig include MLTREECOMP    ) : sig include MLTREECOMP
48            val rewriteMemReg : bool            val rewriteMemReg : bool
49        end =        end =
# Line 54  Line 58 
58    structure A = MLRiscAnnotations    structure A = MLRiscAnnotations
59    
60    type instrStream = (I.instruction,C.regmap,C.cellset) T.stream    type instrStream = (I.instruction,C.regmap,C.cellset) T.stream
61    type ('s,'r,'f,'c) mltreeStream =    type mltreeStream = (T.stm,C.regmap,T.mlrisc list) T.stream
62       (('s,'r,'f,'c) T.stm,C.regmap,('s,'r,'f,'c) T.mlrisc list) T.stream  
63    type ('s,'r,'f,'c) reducer =    datatype kind = REAL | INTEGER
      (I.instruction,C.regmap,C.cellset,I.operand,I.addressing_mode,'s,'r,'f,'c)  
        T.reducer  
   type ('s,'r,'f,'c) extender =  
      (I.instruction,C.regmap,C.cellset,I.operand,I.addressing_mode,'s,'r,'f,'c)  
        T.extender  
64    
65    structure Gen = MLTreeGen    structure Gen = MLTreeGen
66       (structure T = T       (structure T = T
# Line 79  Line 78 
78    val rewriteMemReg = rewriteMemReg    val rewriteMemReg = rewriteMemReg
79    fun isMemReg r = rewriteMemReg andalso r >= 8 andalso r < 32    fun isMemReg r = rewriteMemReg andalso r >= 8 andalso r < 32
80    
81      val ST0 = C.ST 0
82      val ST7 = C.ST 7
83    
84    (*    (*
85     * The code generator     * The code generator
86     *)     *)
87    fun selectInstructions    fun selectInstructions
        (T.EXTENDER{compileStm,compileRexp,compileFexp,compileCCexp,...})  
88         (instrStream as         (instrStream as
89          S.STREAM{emit,defineLabel,entryLabel,pseudoOp,annotation,          S.STREAM{emit,defineLabel,entryLabel,pseudoOp,annotation,
90                   beginCluster,endCluster,exitBlock,alias,phi,comment,...}) =                   beginCluster,endCluster,exitBlock,alias,phi,comment,...}) =
# Line 174  Line 175 
175          | setZeroBit(T.SRA _)      = true          | setZeroBit(T.SRA _)      = true
176          | setZeroBit(T.SRL _)      = true          | setZeroBit(T.SRL _)      = true
177          | setZeroBit(T.SLL _)      = true          | setZeroBit(T.SLL _)      = true
178            | setZeroBit(T.SUB _)      = true
179            | setZeroBit(T.ADDT _)     = true
180            | setZeroBit(T.SUBT _)     = true
181          | setZeroBit(T.MARK(e, _)) = setZeroBit e          | setZeroBit(T.MARK(e, _)) = setZeroBit e
182          | setZeroBit _             = false          | setZeroBit _             = false
183    
184          fun setZeroBit2(T.ANDB _)     = true
185            | setZeroBit2(T.ORB _)      = true
186            | setZeroBit2(T.XORB _)     = true
187            | setZeroBit2(T.SRA _)      = true
188            | setZeroBit2(T.SRL _)      = true
189            | setZeroBit2(T.SLL _)      = true
190            | setZeroBit2(T.ADD(32, _, _)) = true (* can't use leal! *)
191            | setZeroBit2(T.SUB _)      = true
192            | setZeroBit2(T.ADDT _)     = true
193            | setZeroBit2(T.SUBT _)     = true
194            | setZeroBit2(T.MARK(e, _)) = setZeroBit2 e
195            | setZeroBit2 _             = false
196    
197        (* emit parallel copies for floating point *)        (* emit parallel copies for floating point *)
198        fun fcopy(fty, [], [], _) = ()        fun fcopy(fty, [], [], _) = ()
199          | fcopy(fty, dst as [_], src as [_], an) =          | fcopy(fty, dst as [_], src as [_], an) =
# Line 368  Line 385 
385            | I.Indexed _  => true            | I.Indexed _  => true
386            | I.MemReg _   => true            | I.MemReg _   => true
387            | I.LabelEA _  => true            | I.LabelEA _  => true
388              | I.FDirect f  => true
389            | _            => false            | _            => false
390            )            )
391    
# Line 453  Line 471 
471                fun divrem(signed, overflow, e1, e2, resultReg) =                fun divrem(signed, overflow, e1, e2, resultReg) =
472                let val (opnd1, opnd2) = (operand e1, operand e2)                let val (opnd1, opnd2) = (operand e1, operand e2)
473                    val _ = move(opnd1, eax)                    val _ = move(opnd1, eax)
474                    val oper = if signed then (emit(I.CDQ); I.IDIV)                    val oper = if signed then (emit(I.CDQ); I.IDIVL)
475                               else (zero edx; I.UDIV)                               else (zero edx; I.DIVL)
476                in  mark(I.MULTDIV{multDivOp=oper, src=regOrMem opnd2},an);                in  mark(I.MULTDIV{multDivOp=oper, src=regOrMem opnd2},an);
477                    move(resultReg, rdOpnd);                    move(resultReg, rdOpnd);
478                    if overflow then trap() else ()                    if overflow then trap() else ()
# Line 507  Line 525 
525                fun uMultiply(e1, e2) =                fun uMultiply(e1, e2) =
526                    (* note e2 can never be (I.Direct edx) *)                    (* note e2 can never be (I.Direct edx) *)
527                    (move(operand e1, eax);                    (move(operand e1, eax);
528                     mark(I.MULTDIV{multDivOp=I.UMUL,                     mark(I.MULTDIV{multDivOp=I.MULL,
529                                    src=regOrMem(operand e2)},an);                                    src=regOrMem(operand e2)},an);
530                     move(eax, rdOpnd)                     move(eax, rdOpnd)
531                    )                    )
# Line 585  Line 603 
603    
604                   (* Generate setcc instruction:                   (* Generate setcc instruction:
605                    *  semantics:  MV(rd, COND(_, T.CMP(ty, cc, t1, t2), yes, no))                    *  semantics:  MV(rd, COND(_, T.CMP(ty, cc, t1, t2), yes, no))
606                      * Bug, if eax is either t1 or t2 then problem will occur!!!
607                      * Note that we have to use eax as the destination of the
608                      * setcc because it only works on the registers
609                      * %al, %bl, %cl, %dl and %[abcd]h.  The last four registers
610                      * are inaccessible in 32 bit mode.
611                    *)                    *)
612                fun setcc(ty, cc, t1, t2, yes, no) =                fun setcc(ty, cc, t1, t2, yes, no) =
613                let val tmpR = newReg()                let val (cc, yes, no) =
614                    val tmp = I.Direct tmpR                           if yes > no then (cc, yes, no)
615                    (* We create a temporary here just in                           else (T.Basis.negateCond cc, no, yes)
                    * case t1 or t2 contains a use of rd.  
                    *)  
616                in  (* Clear the destination first.                in  (* Clear the destination first.
617                     * This this because stupid SETcc                     * This this because stupid SETcc
618                     * only writes to the low order                     * only writes to the low order
619                     * byte.  That's Intel architecture, folks.                     * byte.  That's Intel architecture, folks.
620                     *)                     *)
621                    zero tmp;                    case (yes, no, cc) of
622                    case (yes, no) of                      (1, 0, T.LT) =>
623                      (1, 0) => (* normal case *)                       let val tmp = I.Direct(expr(T.SUB(32,t1,t2)))
624                         in  move(tmp, rdOpnd);
625                             emit(I.BINARY{binOp=I.SHRL,src=I.Immed 31,dst=rdOpnd})
626                         end
627                      | (1, 0, T.GT) =>
628                         let val tmp = I.Direct(expr(T.SUB(32,t1,t2)))
629                         in  emit(I.UNARY{unOp=I.NOTL,opnd=tmp});
630                             move(tmp, rdOpnd);
631                             emit(I.BINARY{binOp=I.SHRL,src=I.Immed 31,dst=rdOpnd})
632                         end
633                      | (1, 0, _) => (* normal case *)
634                      let val cc = cmp(true, ty, cc, t1, t2, [])                      let val cc = cmp(true, ty, cc, t1, t2, [])
635                      in  mark(I.SET{cond=cond cc, opnd=tmp}, an) end                      in  mark(I.SET{cond=cond cc, opnd=eax}, an);
636                    | (0, 1) => (* flip *)                          emit(I.BINARY{binOp=I.ANDL,src=I.Immed 255, dst=eax});
637                      let val cc = cmp(true, ty,                          move(eax, rdOpnd)
638                                       T.Basis.negateCond cc, t1, t2, [])                      end
639                      in  mark(I.SET{cond=cond cc, opnd=tmp}, an) end                    | (C1, C2, _)  =>
                   | (C1, C2)  =>  
640                      (* general case;                      (* general case;
641                       * from the Intel optimization guide p3-5 *)                       * from the Intel optimization guide p3-5
642                      let val C1 = toInt32 C1                       *)
643                          val C2 = toInt32 C2                      let val _  = zero eax;
644                          val cc = cmp(true, ty, cc, t1, t2, [])                          val cc = cmp(true, ty, cc, t1, t2, [])
645                      in  emit(I.SET{cond=cond cc, opnd=tmp});                      in  case C1-C2 of
646                          case Int32.abs(C1-C2)-1 of                            D as (1 | 2 | 3 | 4 | 5 | 8 | 9) =>
647                            D as (1 | 2 | 4 | 8) =>                            let val (base,scale) =
648                            let val addr = I.Indexed{base=SOME tmpR,                                    case D of
649                                                     index=tmpR,                                      1 => (NONE, 0)
650                                                     scale=Int32.toInt D,                                    | 2 => (NONE, 1)
651                                                     disp=I.Immed(C1-C2),                                    | 3 => (SOME C.eax, 1)
652                                      | 4 => (NONE, 2)
653                                      | 5 => (SOME C.eax, 2)
654                                      | 8 => (NONE, 3)
655                                      | 9 => (SOME C.eax, 3)
656                                  val addr = I.Indexed{base=base,
657                                                       index=C.eax,
658                                                       scale=scale,
659                                                       disp=I.Immed C2,
660                                                     mem=readonly}                                                     mem=readonly}
661                            in  mark(I.LEA{r32=tmpR, addr=addr}, an) end                                val tmpR = newReg()
662                          | _ =>                                val tmp  = I.Direct tmpR
663                           (emit(I.UNARY{unOp=I.DECL, opnd=tmp});                            in  emit(I.SET{cond=cond cc, opnd=eax});
664                                  mark(I.LEA{r32=tmpR, addr=addr}, an);
665                                  move(tmp, rdOpnd)
666                              end
667                            | D =>
668                               (emit(I.SET{cond=cond(T.Basis.negateCond cc),
669                                           opnd=eax});
670                                emit(I.UNARY{unOp=I.DECL, opnd=eax});
671                            emit(I.BINARY{binOp=I.ANDL,                            emit(I.BINARY{binOp=I.ANDL,
672                                          src=I.Immed(C2-C1), dst=tmp});                                            src=I.Immed D, dst=eax});
673                            mark(I.BINARY{binOp=I.ADDL,                              if C2 = 0 then
674                                          src=I.Immed(Int32.min(C1,C2)),                                 move(eax, rdOpnd)
675                                          dst=tmp}, an)                              else
676                           )                                 let val tmpR = newReg()
677                      end;                                     val tmp  = I.Direct tmpR
678                                   in  mark(I.LEA{addr=
679                                             I.Displace{
680                                                 base=C.eax,
681                                                 disp=I.Immed C2,
682                                                 mem=readonly},
683                                                 r32=tmpR}, an);
684                    move(tmp, rdOpnd)                    move(tmp, rdOpnd)
685                                    end
686                               )
687                        end
688                end (* setcc *)                end (* setcc *)
689    
690                    (* Generate cmovcc instruction.                    (* Generate cmovcc instruction.
# Line 647  Line 701 
701    
702                fun unknownExp exp = doExpr(Gen.compileRexp exp, rd, an)                fun unknownExp exp = doExpr(Gen.compileRexp exp, rd, an)
703    
704                      (* Add n to rd *)
705                  fun addN n =
706                  let val n = operand n
707                      val src = if isMemReg rd then immedOrReg n else n
708                  in  mark(I.BINARY{binOp=I.ADDL, src=src, dst=rdOpnd}, an) end
709    
710                    (* Generate addition *)                    (* Generate addition *)
711                fun addition(e1, e2) =                fun addition(e1, e2) =
712                      case e1 of
713                        T.REG(_,rs) => if rs = rd then addN e2 else addition1(e1,e2)
714                      | _ => addition1(e1,e2)
715                  and addition1(e1, e2) =
716                      case e2 of
717                        T.REG(_,rs) => if rs = rd then addN e1 else addition2(e1,e2)
718                      | _ => addition2(e1,e2)
719                  and addition2(e1,e2) =
720                  (dstMustBeReg(fn (dstR, _) =>                  (dstMustBeReg(fn (dstR, _) =>
721                      mark(I.LEA{r32=dstR, addr=address(exp, readonly)}, an))                      mark(I.LEA{r32=dstR, addr=address(exp, readonly)}, an))
722                  handle EA => binaryComm(I.ADDL, e1, e2))                  handle EA => binaryComm(I.ADDL, e1, e2))
723    
                   (* Add n to rd *)  
               fun addN n =  
                 mark(I.BINARY{binOp=I.ADDL, src=I.Immed(toInt32 n),  
                               dst=rdOpnd}, an)  
724    
725            in  case exp of            in  case exp of
726                 T.REG(_,rs) =>                 T.REG(_,rs) =>
# Line 682  Line 746 
746               | T.ADD(32, (T.LI 1|T.LI32 0w1), e) => unary(I.INCL, e)               | T.ADD(32, (T.LI 1|T.LI32 0w1), e) => unary(I.INCL, e)
747               | T.ADD(32, e, T.LI ~1) => unary(I.DECL, e)               | T.ADD(32, e, T.LI ~1) => unary(I.DECL, e)
748               | T.ADD(32, T.LI ~1, e) => unary(I.DECL, e)               | T.ADD(32, T.LI ~1, e) => unary(I.DECL, e)
              | T.ADD(32, e1 as T.REG(_, rs), e2 as T.LI n) =>  
                   if rs = rd then addN n else addition(e1, e2)  
              | T.ADD(32, e1 as T.LI n, e2 as T.REG(_, rs)) =>  
                   if rs = rd then addN n else addition(e1, e2)  
749               | T.ADD(32, e1, e2) => addition(e1, e2)               | T.ADD(32, e1, e2) => addition(e1, e2)
750    
751                   (* 32-bit addition but set the flag!
752                    * This is a stupid hack for now.
753                    *)
754                 | T.ADD(0, e, (T.LI 1|T.LI32 0w1)) => unary(I.INCL, e)
755                 | T.ADD(0, (T.LI 1|T.LI32 0w1), e) => unary(I.INCL, e)
756                 | T.ADD(0, e, T.LI ~1) => unary(I.DECL, e)
757                 | T.ADD(0, T.LI ~1, e) => unary(I.DECL, e)
758                 | T.ADD(0, e1, e2) => binaryComm(I.ADDL, e1, e2)
759    
760                 (* 32-bit subtraction *)                 (* 32-bit subtraction *)
761                 | T.SUB(32, e, (T.LI 0 | T.LI32 0w0)) => doExpr(e, rd, an)
762               | T.SUB(32, e, (T.LI 1 | T.LI32 0w1)) => unary(I.DECL, e)               | T.SUB(32, e, (T.LI 1 | T.LI32 0w1)) => unary(I.DECL, e)
763               | T.SUB(32, e, T.LI ~1) => unary(I.INCL, e)               | T.SUB(32, e, T.LI ~1) => unary(I.INCL, e)
764               | T.SUB(32, (T.LI 0 | T.LI32 0w0), e) => unary(I.NEGL, e)               | T.SUB(32, (T.LI 0 | T.LI32 0w0), e) => unary(I.NEGL, e)
# Line 731  Line 801 
801               | T.CVTI2I(_,T.SIGN_EXTEND,_,T.LOAD(16,ea,mem)) => load16s(ea, mem)               | T.CVTI2I(_,T.SIGN_EXTEND,_,T.LOAD(16,ea,mem)) => load16s(ea, mem)
802    
803               | T.COND(32, T.CMP(ty, cc, t1, t2), T.LI yes, T.LI no) =>               | T.COND(32, T.CMP(ty, cc, t1, t2), T.LI yes, T.LI no) =>
804                   setcc(ty, cc, t1, t2, yes, no)                   setcc(ty, cc, t1, t2, toInt32 yes, toInt32 no)
805                 | T.COND(32, T.CMP(ty, cc, t1, t2), T.LI32 yes, T.LI32 no) =>
806                     setcc(ty, cc, t1, t2, Word32.toLargeIntX yes,
807                                           Word32.toLargeIntX no)
808               | T.COND(32, T.CMP(ty, cc, t1, t2), yes, no) =>               | T.COND(32, T.CMP(ty, cc, t1, t2), yes, no) =>
809                  (case !arch of (* PentiumPro and higher has CMOVcc *)                  (case !arch of (* PentiumPro and higher has CMOVcc *)
810                     Pentium => unknownExp exp                     Pentium => unknownExp exp
# Line 741  Line 814 
814               | T.MARK(e, A.MARKREG f) => (f rd; doExpr(e, rd, an))               | T.MARK(e, A.MARKREG f) => (f rd; doExpr(e, rd, an))
815               | T.MARK(e, a) => doExpr(e, rd, a::an)               | T.MARK(e, a) => doExpr(e, rd, a::an)
816               | T.PRED(e,c) => doExpr(e, rd, A.CTRLUSE c::an)               | T.PRED(e,c) => doExpr(e, rd, A.CTRLUSE c::an)
817               | T.REXT e => compileRexp (reducer()) {e=e, rd=rd, an=an}               | T.REXT e =>
818                     ExtensionComp.compileRext (reducer()) {e=e, rd=rd, an=an}
819                 (* simplify and try again *)                 (* simplify and try again *)
820               | exp => unknownExp exp               | exp => unknownExp exp
821            end (* doExpr *)            end (* doExpr *)
# Line 761  Line 835 
835            * On the x86, TEST is superior to AND for doing the same thing,            * On the x86, TEST is superior to AND for doing the same thing,
836            * since it doesn't need to write out the result in a register.            * since it doesn't need to write out the result in a register.
837            *)            *)
838       and cmpWithZero(cc as (T.EQ | T.NE), e as T.ANDB(ty, a, b))  =       and cmpWithZero(cc as (T.EQ | T.NE), e as T.ANDB(ty, a, b), an) =
839              (case ty of              (case ty of
840                 8 =>  test(I.TESTB, a, b)                 8  => test(I.TESTB, a, b, an)
841               | 16 => test(I.TESTW, a, b)               | 16 => test(I.TESTW, a, b, an)
842               | 32 => test(I.TESTL, a, b)               | 32 => test(I.TESTL, a, b, an)
843               | _  => (expr e; ())               | _  => doExpr(e, newReg(), an);
844               ; cc)               cc)
845          | cmpWithZero(cc, e) = (expr e; cc)          | cmpWithZero(cc, e, an) =
846              let val e =
847                    case e of (* hack to disable the lea optimization XXX *)
848                      T.ADD(_, a, b) => T.ADD(0, a, b)
849                    | e => e
850              in  doExpr(e, newReg(), an); cc end
851    
852            (* Emit a test.            (* Emit a test.
853             *   The available modes are             *   The available modes are
# Line 785  Line 864 
864             * are one of EAX, ECX, EBX, or EDX, replace the TESTL instruction             * are one of EAX, ECX, EBX, or EDX, replace the TESTL instruction
865             * by TESTB.             * by TESTB.
866             *)             *)
867        and test(testopcode, a, b) =        and test(testopcode, a, b, an) =
868            let val (_, opnd1, opnd2) = commuteComparison(T.EQ, true, a, b)            let val (_, opnd1, opnd2) = commuteComparison(T.EQ, true, a, b)
869                (* translate r, r/m => r/m, r *)                (* translate r, r/m => r/m, r *)
870                val (opnd1, opnd2) =                val (opnd1, opnd2) =
871                     if isMemOpnd opnd2 then (opnd2, opnd1) else (opnd1, opnd2)                     if isMemOpnd opnd2 then (opnd2, opnd1) else (opnd1, opnd2)
872            in  emit(testopcode{lsrc=opnd1, rsrc=opnd2})            in  mark(testopcode{lsrc=opnd1, rsrc=opnd2}, an)
873            end            end
874    
875           (* generate a condition code expression           (* generate a condition code expression
# Line 802  Line 881 
881          | 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))
882          | doCCexpr(T.CCMARK(e,a), rd, an) = doCCexpr(e,rd,a::an)          | doCCexpr(T.CCMARK(e,a), rd, an) = doCCexpr(e,rd,a::an)
883          | doCCexpr(T.CCEXT e, cd, an) =          | doCCexpr(T.CCEXT e, cd, an) =
884             compileCCexp (reducer()) {e=e, cd=cd, an=an}             ExtensionComp.compileCCext (reducer()) {e=e, ccd=cd, an=an}
885          | doCCexpr _ = error "doCCexpr"          | doCCexpr _ = error "doCCexpr"
886    
887       and ccExpr e = error "ccExpr"       and ccExpr e = error "ccExpr"
# Line 812  Line 891 
891             * we can also reorder the operands.             * we can also reorder the operands.
892             *)             *)
893        and cmp(swapable, ty, cc, t1, t2, an) =        and cmp(swapable, ty, cc, t1, t2, an) =
894            (case cc of                 (* == and <> can be always be reordered *)
895               (T.EQ | T.NE) =>            let val swapable = swapable orelse cc = T.EQ orelse cc = T.NE
896                (* Sometimes the comparison is not necessary because            in (* Sometimes the comparison is not necessary because
897                 * the bits are already set!                 * the bits are already set!
898                 *)                 *)
899                if isZero t1 andalso setZeroBit t2 then cmpWithZero(cc, t2)               if isZero t1 andalso setZeroBit2 t2 then
900                else if isZero t2 andalso setZeroBit t1 then cmpWithZero(cc, t1)                   if swapable then
901                     (* == and <> can be reordered *)                      cmpWithZero(T.Basis.swapCond cc, t2, an)
902                else genCmp(ty, true, cc, t1, t2, an)                   else (* can't reorder the comparison! *)
903             |  _ => genCmp(ty, swapable, cc, t1, t2, an)                      genCmp(ty, false, cc, t1, t2, an)
904            )               else if isZero t2 andalso setZeroBit2 t1 then
905                    cmpWithZero(cc, t1, an)
906                 else genCmp(ty, swapable, cc, t1, t2, an)
907              end
908    
909            (* Give a and b which are the operands to a comparison (or test)            (* Give a and b which are the operands to a comparison (or test)
910             * Return the appropriate condition code and operands.             * Return the appropriate condition code and operands.
# Line 915  Line 997 
997                    emit(I.FUCOMPP)                    emit(I.FUCOMPP)
998                end                end
999                fun andil i = emit(I.BINARY{binOp=I.ANDL,src=I.Immed(i),dst=eax})                fun andil i = emit(I.BINARY{binOp=I.ANDL,src=I.Immed(i),dst=eax})
1000                  fun testil i = emit(I.TESTL{lsrc=eax,rsrc=I.Immed(i)})
1001                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})
1002                fun cmpil i = emit(I.CMPL{rsrc=I.Immed(i), lsrc=eax})                fun cmpil i = emit(I.CMPL{rsrc=I.Immed(i), lsrc=eax})
1003                fun j(cc, lab) = mark(I.JCC{cond=cc, opnd=immedLabel lab},an)                fun j(cc, lab) = mark(I.JCC{cond=cc, opnd=immedLabel lab},an)
# Line 925  Line 1008 
1008                     | T.?<>  => (andil 0x4400; xoril 0x4000; j(I.NE, lab))                     | T.?<>  => (andil 0x4400; xoril 0x4000; j(I.NE, lab))
1009                     | T.?    => (sahf(); j(I.P,lab))                     | T.?    => (sahf(); j(I.P,lab))
1010                     | T.<=>  => (sahf(); j(I.NP,lab))                     | T.<=>  => (sahf(); j(I.NP,lab))
1011                     | T.>    => (andil 0x4500;  j(I.EQ,lab))                     | T.>    => (testil 0x4500;  j(I.EQ,lab))
1012                     | T.?<=  => (andil 0x4500;  j(I.NE,lab))                     | T.?<=  => (testil 0x4500;  j(I.NE,lab))
1013                     | T.>=   => (andil 0x500; j(I.EQ,lab))                     | T.>=   => (testil 0x500; j(I.EQ,lab))
1014                     | T.?<   => (andil 0x500; j(I.NE,lab))                     | T.?<   => (testil 0x500; j(I.NE,lab))
1015                     | T.<    => (andil 0x4500; cmpil 0x100; j(I.EQ,lab))                     | T.<    => (andil 0x4500; cmpil 0x100; j(I.EQ,lab))
1016                     | T.?>=  => (andil 0x4500; cmpil 0x100; j(I.NE,lab))                     | T.?>=  => (andil 0x4500; cmpil 0x100; j(I.NE,lab))
1017                     | T.<=   => (andil 0x4100; cmpil 0x100; j(I.EQ,lab);                     | T.<=   => (andil 0x4100; cmpil 0x100; j(I.EQ,lab);
1018                                  cmpil 0x4000; j(I.EQ,lab))                                  cmpil 0x4000; j(I.EQ,lab))
1019                     | T.?>   => (sahf(); j(I.P,lab); andil 0x4100; j(I.EQ,lab))                     | T.?>   => (sahf(); j(I.P,lab); testil 0x4100; j(I.EQ,lab))
1020                     | T.<>   => (andil 0x4400; j(I.EQ,lab))                     | T.<>   => (testil 0x4400; j(I.EQ,lab))
1021                     | T.?=   => (andil 0x4400; j(I.NE,lab))                     | T.?=   => (testil 0x4400; j(I.NE,lab))
1022                     | _      => error "fbranch"                     | _      => error "fbranch"
1023                   (*esac*)                   (*esac*)
1024            in  compare(); emit I.FNSTSW; branch()            in  compare(); emit I.FNSTSW; branch()
# Line 943  Line 1026 
1026    
1027        and fld(32, opnd) = I.FLDS opnd        and fld(32, opnd) = I.FLDS opnd
1028          | fld(64, opnd) = I.FLDL opnd          | fld(64, opnd) = I.FLDL opnd
1029            | fld(80, opnd) = I.FLDT opnd
1030          | fld _         = error "fld"          | fld _         = error "fld"
1031    
1032          and fild(16, opnd) = I.FILD opnd
1033            | fild(32, opnd) = I.FILDL opnd
1034            | fild(64, opnd) = I.FILDLL opnd
1035            | fild _         = error "fild"
1036    
1037          and fxld(INTEGER, ty, opnd) = fild(ty, opnd)
1038            | fxld(REAL, fty, opnd) = fld(fty, opnd)
1039    
1040        and fstp(32, opnd) = I.FSTPS opnd        and fstp(32, opnd) = I.FSTPS opnd
1041          | fstp(64, opnd) = I.FSTPL opnd          | fstp(64, opnd) = I.FSTPL opnd
1042            | fstp(80, opnd) = I.FSTPT opnd
1043          | fstp _         = error "fstp"          | fstp _         = error "fstp"
1044    
1045            (* generate code for floating point stores *)            (* generate code for floating point stores *)
# Line 957  Line 1050 
1050             mark(fstp(fty, address(ea, mem)), an)             mark(fstp(fty, address(ea, mem)), an)
1051            )            )
1052    
1053        and fexpr e = error "fexpr"        and fexpr e = (reduceFexp(64, e, []); C.ST(0))
1054    
1055            (* generate floating point expression and put the result in fd *)            (* generate floating point expression and put the result in fd *)
1056        and doFexpr(fty, T.FREG(_, fs), fd, an) =        and doFexpr(fty, T.FREG(_, fs), fd, an) =
# Line 967  Line 1060 
1060          | doFexpr(fty, T.FLOAD(fty', ea, mem), fd, an) =          | doFexpr(fty, T.FLOAD(fty', ea, mem), fd, an) =
1061              let val ea = address(ea, mem)              let val ea = address(ea, mem)
1062              in  mark(fld(fty', ea), an);              in  mark(fld(fty', ea), an);
1063                  emit(fstp(fty, I.FDirect fd))                  if fd = ST0 then () else emit(fstp(fty, I.FDirect fd))
1064              end              end
1065          | doFexpr(fty, e, fd, an) =          | doFexpr(fty, e, fd, an) =
1066              (reduceFexp(fty, e, []);              (reduceFexp(fty, e, []);
1067               mark(fstp(fty, I.FDirect fd), an)               if fd = ST0 then () else mark(fstp(fty, I.FDirect fd), an)
1068              )              )
1069    
1070            (*            (*
# Line 980  Line 1073 
1073             * and put result in %ST(0).             * and put result in %ST(0).
1074             *)             *)
1075        and reduceFexp(fty, fexp, an)  =        and reduceFexp(fty, fexp, an)  =
1076            let val ST = I.FDirect(C.ST 0)            let val ST = I.ST(C.ST 0)
1077                val ST1 = I.FDirect(C.ST 1)                val ST1 = I.ST(C.ST 1)
1078                  val cleanupCode = ref [] : I.instruction list ref
1079                datatype su_numbers =  
1080                  LEAF of int                datatype su_tree =
1081                | BINARY of int * su_numbers * su_numbers                  LEAF of int * T.fexp * ans
1082                | UNARY of int * su_numbers                | BINARY of int * T.fty * fbinop * su_tree * su_tree * ans
1083                  | UNARY of int * T.fty * I.funOp * su_tree * ans
1084                datatype direction = LEFT | RIGHT                and fbinop = FADD | FSUB | FMUL | FDIV
1085                             | FIADD | FISUB | FIMUL | FIDIV
1086                fun label(LEAF n) = n                withtype ans = Annotations.annotations
1087                  | label(BINARY(n, _, _)) = n  
1088                  | label(UNARY(n, _)) = n                fun label(LEAF(n, _, _)) = n
1089                    | label(BINARY(n, _, _, _, _, _)) = n
1090               (* Generate tree of sethi-ullman numbers *)                  | label(UNARY(n, _, _, _, _)) = n
1091                fun suBinary(t1, t2) =  
1092                    let val su1 = suNumbering(t1, LEFT)                fun annotate(LEAF(n, x, an), a)  = LEAF(n,x,a::an)
1093                        val su2 = suNumbering(t2, RIGHT)                  | annotate(BINARY(n,t,b,x,y,an), a) = BINARY(n,t,b,x,y,a::an)
1094                        val n1 = label su1                  | annotate(UNARY(n,t,u,x,an), a) = UNARY(n,t,u,x,a::an)
1095                        val n2 = label su2  
1096                    in  BINARY(if n1=n2 then n1+1 else Int.max(n1, n2), su1, su2)                (* Generate expression tree with sethi-ullman numbers *)
1097                    end                fun su(e as T.FREG _)       = LEAF(1, e, [])
1098                    | su(e as T.FLOAD _)      = LEAF(1, e, [])
1099                and suUnary(t) =                  | su(e as T.CVTI2F _)     = LEAF(1, e, [])
1100                    let val su = suNumbering(t, LEFT)                  | su(T.CVTF2F(_, _, t))   = su t
1101                    in  UNARY(label su, su)                  | su(T.FMARK(t, a))       = annotate(su t, a)
1102                    end                  | su(T.FABS(fty, t))      = suUnary(fty, I.FABS, t)
1103                    | su(T.FNEG(fty, t))      = suUnary(fty, I.FCHS, t)
1104                and suNumbering(T.FREG _, LEFT) = LEAF 1                  | su(T.FSQRT(fty, t))     = suUnary(fty, I.FSQRT, t)
1105                  | suNumbering(T.FREG _, RIGHT) = LEAF 0                  | su(T.FADD(fty, t1, t2)) = suComBinary(fty,FADD,FIADD,t1,t2)
1106                  | suNumbering(T.FLOAD _, LEFT) = LEAF 1                  | su(T.FMUL(fty, t1, t2)) = suComBinary(fty,FMUL,FIMUL,t1,t2)
1107                  | suNumbering(T.FLOAD _, RIGHT) = LEAF 0                  | su(T.FSUB(fty, t1, t2)) = suBinary(fty,FSUB,FISUB,t1,t2)
1108                  | suNumbering(T.FADD(_, t1, t2), _) = suBinary(t1, t2)                  | su(T.FDIV(fty, t1, t2)) = suBinary(fty,FDIV,FIDIV,t1,t2)
1109                  | suNumbering(T.FMUL(_, t1, t2), _) = suBinary(t1, t2)                  | su _ = error "su"
1110                  | suNumbering(T.FSUB(_, t1, t2), _) = suBinary(t1, t2)  
1111                  | suNumbering(T.FDIV(_, t1, t2), _) = suBinary(t1, t2)                (* Try to fold the the memory operand or integer conversion *)
1112                  | suNumbering(T.FABS(_,t), _) = suUnary(t)                and suFold(e as T.FREG _) = (LEAF(0, e, []), false)
1113                  | suNumbering(T.FNEG(_,t), _) = suUnary(t)                  | suFold(e as T.FLOAD _) = (LEAF(0, e, []), false)
1114                  | suNumbering(T.CVTI2F _, _) = UNARY(1, LEAF 0)                  | suFold(e as T.CVTI2F(_,(16 | 32),_)) = (LEAF(0, e, []), true)
1115                  | suNumbering(T.CVTF2F(_,_,t), _) = suUnary t                  | suFold(T.CVTF2F(_, _, t)) = suFold t
1116                  | suNumbering(T.FMARK(e,a),x) = suNumbering(e,x)                  | suFold(T.FMARK(t, a)) =
1117                  | suNumbering _ = error "suNumbering"                    let val (t, integer) = suFold t
1118                      in  (annotate(t, a), integer) end
1119                fun leafEA(T.FREG(fty, f)) = (fty, I.FDirect f)                  | suFold e = (su e, false)
1120                  | leafEA(T.FLOAD(fty, ea, mem)) = (fty, address(ea, mem))  
1121                  | leafEA _ = error "leafEA"                (* Can the tree be folded into the src operand? *)
1122                  and foldable(T.FREG _) = true
1123                fun cvti2d(t,an) =                  | foldable(T.FLOAD _) = true
1124                let val opnd = operand t                  | foldable(T.CVTI2F(_, (16 | 32), _)) = true
1125                    fun doMemOpnd () =                  | foldable(T.CVTF2F(_, _, t)) = foldable t
1126                        (emit(I.MOVE{mvOp=I.MOVL, src=opnd, dst=tempMem});                  | foldable(T.FMARK(t, _)) = foldable t
1127                         mark(I.FILD tempMem,an))                  | foldable _ = false
1128                in  case opnd of  
1129                      I.Direct _ => doMemOpnd()                (* Form unary tree *)
1130                    | I.Immed _ => doMemOpnd()                and suUnary(fty, funary, t) =
1131                    | _ => mark(I.FILD opnd, an)                    let val t = su t
1132                end                    in  UNARY(label t, fty, funary, t, [])
1133                      end
1134                (* traverse expression and su-number tree *)  
1135                fun gencode(_, LEAF 0, an) = ()                (* Form binary tree *)
1136                  | gencode(T.FMARK(e,a), x, an) = gencode(e, x, a::an)                and suBinary(fty, binop, ibinop, t1, t2) =
1137                  | gencode(f, LEAF 1, an) = mark(fld(leafEA f), an)                    let val t1 = su t1
1138                  | gencode(t, BINARY(_, su1, LEAF 0), an) =                        val (t2, integer) = suFold t2
1139                    let (* optimize the common case when both operands                        val n1 = label t1
1140                         * are equal *)                        val n2 = label t2
1141                        fun sameEA(T.FREG(t1, f1), T.FREG(t2, f2)) =                        val n  = if n1=n2 then n1+1 else Int.max(n1,n2)
1142                              t1 = t2 andalso f1 = f2                        val myOp = if integer then ibinop else binop
1143                          | sameEA _ = false                    in  BINARY(n, fty, myOp, t1, t2, [])
1144                        fun doit(oper, t1, t2) =                    end
1145                           (gencode(t1, su1, []);  
1146                            mark(I.FBINARY{binOp=oper,                (* Try to fold in the operand if possible.
1147                                           src=if sameEA(t1, t2) then ST                 * This only applies to commutative operations.
1148                                               else #2(leafEA t2),                 *)
1149                                           dst=ST}, an)                and suComBinary(fty, binop, ibinop, t1, t2) =
1150                           )                    let val (t1, t2) = if foldable t2 then (t1, t2) else (t2, t1)
1151                    in                    in  suBinary(fty, binop, ibinop, t1, t2) end
1152                      case t of  
1153                         T.FADD(_, t1, t2) => doit(I.FADD, t1, t2)                and sameTree(LEAF(_, T.FREG(t1,f1), []),
1154                       | T.FMUL(_, t1, t2) => doit(I.FMUL, t1, t2)                             LEAF(_, T.FREG(t2,f2), [])) = t1=t2 andalso f1=f2
1155                       | T.FSUB(_, t1, t2) => doit(I.FSUB, t1, t2)                  | sameTree _ = false
1156                       | T.FDIV(_, t1, t2) => doit(I.FDIV, t1, t2)  
1157                       | _ => error "gencode.BINARY"                (* Traverse tree and generate code *)
1158                    end                fun gencode(LEAF(_, t, an)) = mark(fxld(leafEA t), an)
1159                  | gencode(fexp, BINARY(fty, su1, su2), an) =                  | gencode(BINARY(_, _, binop, x, t2 as LEAF(0, y, a1), a2)) =
1160                    let fun doit(t1, t2, oper, operP, operRP) = let                    let val _          = gencode x
1161                       (* oper[P] =>  ST(1) := ST oper ST(1); [pop]                        val (_, fty, src) = leafEA y
1162                          fun gen(code) = mark(code, a1 @ a2)
1163                          fun binary(oper32, oper64) =
1164                              if sameTree(x, t2) then
1165                                 gen(I.FBINARY{binOp=oper64, src=ST, dst=ST})
1166                              else
1167                                 let val oper =
1168                                       if isMemOpnd src then
1169                                          case fty of
1170                                            32 => oper32
1171                                          | 64 => oper64
1172                                          | _  => error "gencode: BINARY"
1173                                       else oper64
1174                                 in gen(I.FBINARY{binOp=oper, src=src, dst=ST}) end
1175                          fun ibinary(oper16, oper32) =
1176                              let val oper = case fty of
1177                                               16 => oper16
1178                                             | 32 => oper32
1179                                             | _  => error "gencode: IBINARY"
1180                              in  gen(I.FIBINARY{binOp=oper, src=src}) end
1181                      in  case binop of
1182                            FADD => binary(I.FADDS, I.FADDL)
1183                          | FSUB => binary(I.FDIVS, I.FSUBL)
1184                          | FMUL => binary(I.FMULS, I.FMULL)
1185                          | FDIV => binary(I.FDIVS, I.FDIVL)
1186                          | FIADD => ibinary(I.FIADDS, I.FIADDL)
1187                          | FISUB => ibinary(I.FIDIVS, I.FISUBL)
1188                          | FIMUL => ibinary(I.FIMULS, I.FIMULL)
1189                          | FIDIV => ibinary(I.FIDIVS, I.FIDIVL)
1190                      end
1191                    | gencode(BINARY(_, fty, binop, t1, t2, an)) =
1192                      let fun doit(t1, t2, oper, operP, operRP) =
1193                          let (* oper[P] =>  ST(1) := ST oper ST(1); [pop]
1194                        * operR[P] => ST(1) := ST(1) oper ST; [pop]                        * operR[P] => ST(1) := ST(1) oper ST; [pop]
1195                        *)                        *)
1196                        val n1 = label su1                             val n1 = label t1
1197                        val n2 = label su2                             val n2 = label t2
1198                      in                        in if n1 < n2 andalso n1 <= 7 then
1199                        if n1 < n2 andalso n1 <= 7 then                             (gencode t2;
1200                          (gencode(t2, su2, []);                              gencode t1;
                          gencode(t1, su1, []);  
1201                           mark(I.FBINARY{binOp=operP, src=ST, dst=ST1}, an))                           mark(I.FBINARY{binOp=operP, src=ST, dst=ST1}, an))
1202                        else if n2 <= n1 andalso n2 <= 7 then                        else if n2 <= n1 andalso n2 <= 7 then
1203                          (gencode(t1, su1, []);                             (gencode t1;
1204                           gencode(t2, su2, []);                              gencode t2;
1205                           mark(I.FBINARY{binOp=operRP, src=ST, dst=ST1}, an))                           mark(I.FBINARY{binOp=operRP, src=ST, dst=ST1}, an))
1206                        else let (* both labels > 7 *)                           else
1207                             let (* both labels > 7 *)
1208                            val fs = I.FDirect(newFreg())                            val fs = I.FDirect(newFreg())
1209                          in                           in  gencode t2;
                           gencode (t2, su2, []);  
1210                            emit(fstp(fty, fs));                            emit(fstp(fty, fs));
1211                            gencode (t1, su1, []);                               gencode t1;
1212                            mark(I.FBINARY{binOp=oper, src=fs, dst=ST}, an)                            mark(I.FBINARY{binOp=oper, src=fs, dst=ST}, an)
1213                          end                          end
1214                      end                      end
1215                    in                    in case binop of
1216                      case fexp                         FADD => doit(t1,t2,I.FADDL,I.FADDP,I.FADDP)
1217                      of T.FADD(_, t1, t2) => doit(t1, t2,I.FADD,I.FADDP,I.FADDP)                       | FMUL => doit(t1,t2,I.FMULL,I.FMULP,I.FMULP)
1218                       | T.FMUL(_, t1, t2) => doit(t1, t2,I.FMUL,I.FMULP,I.FMULP)                       | FSUB => doit(t1,t2,I.FSUBL,I.FSUBP,I.FSUBRP)
1219                       | T.FSUB(_, t1, t2) => doit(t1, t2,I.FSUB,I.FSUBP,I.FSUBRP)                       | FDIV => doit(t1,t2,I.FDIVL,I.FDIVP,I.FDIVRP)
                      | T.FDIV(_, t1, t2) => doit(t1, t2,I.FDIV,I.FDIVP,I.FDIVRP)  
1220                       | _ => error "gencode.BINARY"                       | _ => error "gencode.BINARY"
1221                    end                    end
1222                  | gencode(fexp, UNARY(_, LEAF 0), an) =                  | gencode(UNARY(_, _, unaryOp, su, an)) =
1223                    (case fexp                     (gencode(su); mark(I.FUNARY(unaryOp),an))
                     of T.FABS(fty, t) =>  
                          (emit(fld(leafEA t)); mark(I.FUNARY(I.FABS),an))  
                      | T.FNEG(fty, t) =>  
                          (emit(fld(leafEA t)); mark(I.FUNARY(I.FCHS),an))  
                      | T.CVTI2F(_,_,t) => cvti2d(t,an) (* XXX *)  
                      | _ => error "gencode.UNARY"  
                    (*esac*))  
                 | gencode(fexp, UNARY(_, su), an) =  
                   let fun doit(oper, t) =  
                        (gencode(t, su, []); mark(I.FUNARY(oper),an))  
                   in case fexp  
                      of T.FABS(_, t) => doit(I.FABS, t)  
                       | T.FNEG(_, t) => doit(I.FCHS, t)  
                       | T.CVTF2F(_,_,t) => gencode(t, su, an)  
                       | T.CVTI2F _ => error "gencode:UNARY:cvti2f"  
                       | _ => error "gencode.UNARY"  
                   end  
                 | gencode _ = error "gencode"  
1224    
1225                val labels = suNumbering(fexp, LEFT)                (* Generate code for a leaf.
1226            in  gencode(fexp, labels, an)                 * Returns the type and an effective address
1227                   *)
1228                  and leafEA(T.FREG(fty, f)) = (REAL, fty, I.FDirect f)
1229                    | leafEA(T.FLOAD(fty, ea, mem)) = (REAL, fty, address(ea, mem))
1230                    | leafEA(T.CVTI2F(_, 32, t)) = int2real(32, t)
1231                    | leafEA(T.CVTI2F(_, 16, t)) = int2real(16, t)
1232                    | leafEA(T.CVTI2F(_, 8, t))  = int2real(8, t)
1233                    | leafEA _ = error "leafEA"
1234    
1235                  (* Move integer t of size ty into a memory location *)
1236                  and int2real(ty, t) =
1237                      let val opnd = operand t
1238                      in  if isMemOpnd opnd andalso (ty = 16 orelse ty = 32)
1239                          then (INTEGER, ty, opnd)
1240                          else
1241                            let val {instrs, tempMem, cleanup} =
1242                                       cvti2f{ty=ty, src=opnd}
1243                            in  app emit instrs;
1244                                cleanupCode := !cleanupCode @ cleanup;
1245                                (INTEGER, 32, tempMem)
1246                            end
1247                      end
1248              in  gencode(su fexp);
1249                  app emit(!cleanupCode)
1250            end (*reduceFexp*)            end (*reduceFexp*)
1251    
1252            (* generate code for a statement *)            (* generate code for a statement *)
# Line 1128  Line 1256 
1256          | stmt(T.COPY(_, dst, src), an) = copy(dst, src, an)          | stmt(T.COPY(_, dst, src), an) = copy(dst, src, an)
1257          | stmt(T.FCOPY(fty, dst, src), an) = fcopy(fty, dst, src, an)          | stmt(T.FCOPY(fty, dst, src), an) = fcopy(fty, dst, src, an)
1258          | stmt(T.JMP(ctrl, e, labs), an) = jmp(e, labs, an)          | stmt(T.JMP(ctrl, e, labs), an) = jmp(e, labs, an)
1259          | stmt(T.CALL(e, flow, def, use, cdef, cuse, mem), an) =          | stmt(T.CALL{funct, targets, defs, uses, cdefs, cuses, region}, an) =
1260               call(e,flow,def,use,mem,an)               call(funct,targets,defs,uses,region,an)
1261          | stmt(T.RET _, an) = mark(I.RET NONE, an)          | stmt(T.RET _, an) = mark(I.RET NONE, an)
1262          | stmt(T.STORE(8, ea, d, mem), an) = store8(ea, d, mem, an)          | stmt(T.STORE(8, ea, d, mem), an) = store8(ea, d, mem, an)
1263          | stmt(T.STORE(16, ea, d, mem), an) = store16(ea, d, mem, an)          | stmt(T.STORE(16, ea, d, mem), an) = store16(ea, d, mem, an)
# Line 1138  Line 1266 
1266          | stmt(T.BCC(ctrl, cc, lab), an) = branch(cc, lab, an)          | stmt(T.BCC(ctrl, cc, lab), an) = branch(cc, lab, an)
1267          | stmt(T.DEFINE l, _) = defineLabel l          | stmt(T.DEFINE l, _) = defineLabel l
1268          | stmt(T.ANNOTATION(s, a), an) = stmt(s, a::an)          | stmt(T.ANNOTATION(s, a), an) = stmt(s, a::an)
1269            | stmt(T.EXT s, an) =
1270                 ExtensionComp.compileSext (reducer()) {stm=s, an=an}
1271          | stmt(s, _) = doStmts(Gen.compileStm s)          | stmt(s, _) = doStmts(Gen.compileStm s)
1272    
1273        and doStmt s = stmt(s, [])        and doStmt s = stmt(s, [])

Legend:
Removed from v.545  
changed lines
  Added in v.695

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