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 565, Sun Mar 5 04:10:18 2000 UTC
# 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 tempMem : X86Instr.operand (* temporary for CVTI2F *)
     (* val memRegsUsed : word ref *)    (* bit mask of memRegs used *)  
41    ) : sig include MLTREECOMP    ) : sig include MLTREECOMP
42            val rewriteMemReg : bool            val rewriteMemReg : bool
43        end =        end =
# Line 54  Line 52 
52    structure A = MLRiscAnnotations    structure A = MLRiscAnnotations
53    
54    type instrStream = (I.instruction,C.regmap,C.cellset) T.stream    type instrStream = (I.instruction,C.regmap,C.cellset) T.stream
55    type ('s,'r,'f,'c) mltreeStream =    type mltreeStream = (T.stm,C.regmap,T.mlrisc list) T.stream
56       (('s,'r,'f,'c) T.stm,C.regmap,('s,'r,'f,'c) T.mlrisc list) T.stream  
57    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  
58    
59    structure Gen = MLTreeGen    structure Gen = MLTreeGen
60       (structure T = T       (structure T = T
# Line 79  Line 72 
72    val rewriteMemReg = rewriteMemReg    val rewriteMemReg = rewriteMemReg
73    fun isMemReg r = rewriteMemReg andalso r >= 8 andalso r < 32    fun isMemReg r = rewriteMemReg andalso r >= 8 andalso r < 32
74    
75      val ST0 = C.ST 0
76      val ST7 = C.ST 7
77    
78    (*    (*
79     * The code generator     * The code generator
80     *)     *)
81    fun selectInstructions    fun selectInstructions
        (T.EXTENDER{compileStm,compileRexp,compileFexp,compileCCexp,...})  
82         (instrStream as         (instrStream as
83          S.STREAM{emit,defineLabel,entryLabel,pseudoOp,annotation,          S.STREAM{emit,defineLabel,entryLabel,pseudoOp,annotation,
84                   beginCluster,endCluster,exitBlock,alias,phi,comment,...}) =                   beginCluster,endCluster,exitBlock,alias,phi,comment,...}) =
# Line 368  Line 363 
363            | I.Indexed _  => true            | I.Indexed _  => true
364            | I.MemReg _   => true            | I.MemReg _   => true
365            | I.LabelEA _  => true            | I.LabelEA _  => true
366              | I.FDirect f  => true
367            | _            => false            | _            => false
368            )            )
369    
# Line 741  Line 737 
737               | T.MARK(e, A.MARKREG f) => (f rd; doExpr(e, rd, an))               | T.MARK(e, A.MARKREG f) => (f rd; doExpr(e, rd, an))
738               | T.MARK(e, a) => doExpr(e, rd, a::an)               | T.MARK(e, a) => doExpr(e, rd, a::an)
739               | T.PRED(e,c) => doExpr(e, rd, A.CTRLUSE c::an)               | T.PRED(e,c) => doExpr(e, rd, A.CTRLUSE c::an)
740               | T.REXT e => compileRexp (reducer()) {e=e, rd=rd, an=an}               | T.REXT e =>
741                     ExtensionComp.compileRext (reducer()) {e=e, rd=rd, an=an}
742                 (* simplify and try again *)                 (* simplify and try again *)
743               | exp => unknownExp exp               | exp => unknownExp exp
744            end (* doExpr *)            end (* doExpr *)
# Line 802  Line 799 
799          | 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))
800          | doCCexpr(T.CCMARK(e,a), rd, an) = doCCexpr(e,rd,a::an)          | doCCexpr(T.CCMARK(e,a), rd, an) = doCCexpr(e,rd,a::an)
801          | doCCexpr(T.CCEXT e, cd, an) =          | doCCexpr(T.CCEXT e, cd, an) =
802             compileCCexp (reducer()) {e=e, cd=cd, an=an}             ExtensionComp.compileCCext (reducer()) {e=e, ccd=cd, an=an}
803          | doCCexpr _ = error "doCCexpr"          | doCCexpr _ = error "doCCexpr"
804    
805       and ccExpr e = error "ccExpr"       and ccExpr e = error "ccExpr"
# Line 943  Line 940 
940    
941        and fld(32, opnd) = I.FLDS opnd        and fld(32, opnd) = I.FLDS opnd
942          | fld(64, opnd) = I.FLDL opnd          | fld(64, opnd) = I.FLDL opnd
943            | fld(80, opnd) = I.FLDT opnd
944          | fld _         = error "fld"          | fld _         = error "fld"
945    
946          and fild(16, opnd) = I.FILD opnd
947            | fild(32, opnd) = I.FILDL opnd
948            | fild(64, opnd) = I.FILDLL opnd
949            | fild _         = error "fild"
950    
951          and fxld(INTEGER, ty, opnd) = fild(ty, opnd)
952            | fxld(REAL, fty, opnd) = fld(fty, opnd)
953    
954        and fstp(32, opnd) = I.FSTPS opnd        and fstp(32, opnd) = I.FSTPS opnd
955          | fstp(64, opnd) = I.FSTPL opnd          | fstp(64, opnd) = I.FSTPL opnd
956            | fstp(80, opnd) = I.FSTPT opnd
957          | fstp _         = error "fstp"          | fstp _         = error "fstp"
958    
959            (* generate code for floating point stores *)            (* generate code for floating point stores *)
# Line 980  Line 987 
987             * and put result in %ST(0).             * and put result in %ST(0).
988             *)             *)
989        and reduceFexp(fty, fexp, an)  =        and reduceFexp(fty, fexp, an)  =
990            let val ST = I.FDirect(C.ST 0)            let val ST = I.ST(C.ST 0)
991                val ST1 = I.FDirect(C.ST 1)                val ST1 = I.ST(C.ST 1)
   
               datatype su_numbers =  
                 LEAF of int  
               | BINARY of int * su_numbers * su_numbers  
               | UNARY of int * su_numbers  
   
               datatype direction = LEFT | RIGHT  
   
               fun label(LEAF n) = n  
                 | label(BINARY(n, _, _)) = n  
                 | label(UNARY(n, _)) = n  
   
              (* Generate tree of sethi-ullman numbers *)  
               fun suBinary(t1, t2) =  
                   let val su1 = suNumbering(t1, LEFT)  
                       val su2 = suNumbering(t2, RIGHT)  
                       val n1 = label su1  
                       val n2 = label su2  
                   in  BINARY(if n1=n2 then n1+1 else Int.max(n1, n2), su1, su2)  
                   end  
   
               and suUnary(t) =  
                   let val su = suNumbering(t, LEFT)  
                   in  UNARY(label su, su)  
                   end  
   
               and suNumbering(T.FREG _, LEFT) = LEAF 1  
                 | suNumbering(T.FREG _, RIGHT) = LEAF 0  
                 | suNumbering(T.FLOAD _, LEFT) = LEAF 1  
                 | suNumbering(T.FLOAD _, RIGHT) = LEAF 0  
                 | suNumbering(T.FADD(_, t1, t2), _) = suBinary(t1, t2)  
                 | suNumbering(T.FMUL(_, t1, t2), _) = suBinary(t1, t2)  
                 | suNumbering(T.FSUB(_, t1, t2), _) = suBinary(t1, t2)  
                 | suNumbering(T.FDIV(_, t1, t2), _) = suBinary(t1, t2)  
                 | suNumbering(T.FABS(_,t), _) = suUnary(t)  
                 | suNumbering(T.FNEG(_,t), _) = suUnary(t)  
                 | suNumbering(T.CVTI2F _, _) = UNARY(1, LEAF 0)  
                 | suNumbering(T.CVTF2F(_,_,t), _) = suUnary t  
                 | suNumbering(T.FMARK(e,a),x) = suNumbering(e,x)  
                 | suNumbering _ = error "suNumbering"  
   
               fun leafEA(T.FREG(fty, f)) = (fty, I.FDirect f)  
                 | leafEA(T.FLOAD(fty, ea, mem)) = (fty, address(ea, mem))  
                 | leafEA _ = error "leafEA"  
992    
993                fun cvti2d(t,an) =                datatype su_tree =
994                let val opnd = operand t                  LEAF of int * T.fexp * ans
995                    fun doMemOpnd () =                | BINARY of int * T.fty * fbinop * su_tree * su_tree * ans
996                        (emit(I.MOVE{mvOp=I.MOVL, src=opnd, dst=tempMem});                | UNARY of int * T.fty * I.funOp * su_tree * ans
997                         mark(I.FILD tempMem,an))                and fbinop = FADD | FSUB | FMUL | FDIV
998                in  case opnd of                           | FIADD | FISUB | FIMUL | FIDIV
999                      I.Direct _ => doMemOpnd()                withtype ans = Annotations.annotations
1000                    | I.Immed _ => doMemOpnd()  
1001                    | _ => mark(I.FILD opnd, an)                fun label(LEAF(n, _, _)) = n
1002                end                  | label(BINARY(n, _, _, _, _, _)) = n
1003                    | label(UNARY(n, _, _, _, _)) = n
1004                (* traverse expression and su-number tree *)  
1005                fun gencode(_, LEAF 0, an) = ()                fun annotate(LEAF(n, x, an), a)  = LEAF(n,x,a::an)
1006                  | gencode(T.FMARK(e,a), x, an) = gencode(e, x, a::an)                  | annotate(BINARY(n,t,b,x,y,an), a) = BINARY(n,t,b,x,y,a::an)
1007                  | gencode(f, LEAF 1, an) = mark(fld(leafEA f), an)                  | annotate(UNARY(n,t,u,x,an), a) = UNARY(n,t,u,x,a::an)
1008                  | gencode(t, BINARY(_, su1, LEAF 0), an) =  
1009                    let (* optimize the common case when both operands                (* Generate expression tree with sethi-ullman numbers *)
1010                         * are equal *)                fun su(e as T.FREG _)       = LEAF(1, e, [])
1011                        fun sameEA(T.FREG(t1, f1), T.FREG(t2, f2)) =                  | su(e as T.FLOAD _)      = LEAF(1, e, [])
1012                              t1 = t2 andalso f1 = f2                  | su(e as T.CVTI2F _)     = LEAF(1, e, [])
1013                          | sameEA _ = false                  | su(T.CVTF2F(_, _, t))   = su t
1014                        fun doit(oper, t1, t2) =                  | su(T.FMARK(t, a))       = annotate(su t, a)
1015                           (gencode(t1, su1, []);                  | su(T.FABS(fty, t))      = suUnary(fty, I.FABS, t)
1016                            mark(I.FBINARY{binOp=oper,                  | su(T.FNEG(fty, t))      = suUnary(fty, I.FCHS, t)
1017                                           src=if sameEA(t1, t2) then ST                  | su(T.FSQRT(fty, t))     = suUnary(fty, I.FSQRT, t)
1018                                               else #2(leafEA t2),                  | su(T.FADD(fty, t1, t2)) = suComBinary(fty,FADD,FIADD,t1,t2)
1019                                           dst=ST}, an)                  | su(T.FMUL(fty, t1, t2)) = suComBinary(fty,FMUL,FIMUL,t1,t2)
1020                           )                  | su(T.FSUB(fty, t1, t2)) = suBinary(fty,FSUB,FISUB,t1,t2)
1021                    in                  | su(T.FDIV(fty, t1, t2)) = suBinary(fty,FDIV,FIDIV,t1,t2)
1022                      case t of                  | su _ = error "su"
1023                         T.FADD(_, t1, t2) => doit(I.FADD, t1, t2)  
1024                       | T.FMUL(_, t1, t2) => doit(I.FMUL, t1, t2)                (* Try to fold the the memory operand or integer conversion *)
1025                       | T.FSUB(_, t1, t2) => doit(I.FSUB, t1, t2)                and suFold(e as T.FREG _) = (LEAF(0, e, []), false)
1026                       | T.FDIV(_, t1, t2) => doit(I.FDIV, t1, t2)                  | suFold(e as T.FLOAD _) = (LEAF(0, e, []), false)
1027                       | _ => error "gencode.BINARY"                  | suFold(e as T.CVTI2F(_,(16 | 32),_)) = (LEAF(0, e, []), true)
1028                    end                  | suFold(T.CVTF2F(_, _, t)) = suFold t
1029                  | gencode(fexp, BINARY(fty, su1, su2), an) =                  | suFold(T.FMARK(t, a)) =
1030                    let fun doit(t1, t2, oper, operP, operRP) = let                    let val (t, integer) = suFold t
1031                       (* oper[P] =>  ST(1) := ST oper ST(1); [pop]                    in  (annotate(t, a), integer) end
1032                    | suFold e = (su e, false)
1033    
1034                  (* Can the tree be folded into the src operand? *)
1035                  and foldable(T.FREG _) = true
1036                    | foldable(T.FLOAD _) = true
1037                    | foldable(T.CVTI2F(_, (16 | 32), _)) = true
1038                    | foldable(T.CVTF2F(_, _, t)) = foldable t
1039                    | foldable(T.FMARK(t, _)) = foldable t
1040                    | foldable _ = false
1041    
1042                  (* Form unary tree *)
1043                  and suUnary(fty, funary, t) =
1044                      let val t = su t
1045                      in  UNARY(label t, fty, funary, t, [])
1046                      end
1047    
1048                  (* Form binary tree *)
1049                  and suBinary(fty, binop, ibinop, t1, t2) =
1050                      let val t1 = su t1
1051                          val (t2, integer) = suFold t2
1052                          val n1 = label t1
1053                          val n2 = label t2
1054                          val n  = if n1=n2 then n1+1 else Int.max(n1,n2)
1055                          val myOp = if integer then ibinop else binop
1056                      in  BINARY(n, fty, myOp, t1, t2, [])
1057                      end
1058    
1059                  (* Try to fold in the operand if possible.
1060                   * This only applies to commutative operations.
1061                   *)
1062                  and suComBinary(fty, binop, ibinop, t1, t2) =
1063                      let val (t1, t2) = if foldable t2 then (t1, t2) else (t2, t1)
1064                      in  suBinary(fty, binop, ibinop, t1, t2) end
1065    
1066                  and sameTree(LEAF(_, T.FREG(t1,f1), []),
1067                               LEAF(_, T.FREG(t2,f2), [])) = t1=t2 andalso f1=f2
1068                    | sameTree _ = false
1069    
1070                  (* Traverse tree and generate code *)
1071                  fun gencode(LEAF(_, t, an)) = mark(fxld(leafEA t), an)
1072                    | gencode(BINARY(_, _, binop, x, t2 as LEAF(0, y, a1), a2)) =
1073                      let val _          = gencode x
1074                          val (_, fty, src) = leafEA y
1075                          fun gen(code) = mark(code, a1 @ a2)
1076                          fun binary(oper32, oper64) =
1077                              if sameTree(x, t2) then
1078                                 gen(I.FBINARY{binOp=oper64, src=ST, dst=ST})
1079                              else
1080                                 let val oper =
1081                                       if isMemOpnd src then
1082                                          case fty of
1083                                            32 => oper32
1084                                          | 64 => oper64
1085                                          | _  => error "gencode: BINARY"
1086                                       else oper64
1087                                 in gen(I.FBINARY{binOp=oper, src=src, dst=ST}) end
1088                          fun ibinary(oper16, oper32) =
1089                              let val oper = case fty of
1090                                               16 => oper16
1091                                             | 32 => oper32
1092                                             | _  => error "gencode: IBINARY"
1093                              in  gen(I.FIBINARY{binOp=oper, src=src}) end
1094                      in  case binop of
1095                            FADD => binary(I.FADDS, I.FADDL)
1096                          | FSUB => binary(I.FDIVS, I.FSUBL)
1097                          | FMUL => binary(I.FMULS, I.FMULL)
1098                          | FDIV => binary(I.FDIVS, I.FDIVL)
1099                          | FIADD => ibinary(I.FIADDS, I.FIADDL)
1100                          | FISUB => ibinary(I.FIDIVS, I.FISUBL)
1101                          | FIMUL => ibinary(I.FIMULS, I.FIMULL)
1102                          | FIDIV => ibinary(I.FIDIVS, I.FIDIVL)
1103                      end
1104                    | gencode(BINARY(_, fty, binop, t1, t2, an)) =
1105                      let fun doit(t1, t2, oper, operP, operRP) =
1106                          let (* oper[P] =>  ST(1) := ST oper ST(1); [pop]
1107                        * operR[P] => ST(1) := ST(1) oper ST; [pop]                        * operR[P] => ST(1) := ST(1) oper ST; [pop]
1108                        *)                        *)
1109                        val n1 = label su1                             val n1 = label t1
1110                        val n2 = label su2                             val n2 = label t2
1111                      in                        in if n1 < n2 andalso n1 <= 7 then
1112                        if n1 < n2 andalso n1 <= 7 then                             (gencode t2;
1113                          (gencode(t2, su2, []);                              gencode t1;
                          gencode(t1, su1, []);  
1114                           mark(I.FBINARY{binOp=operP, src=ST, dst=ST1}, an))                           mark(I.FBINARY{binOp=operP, src=ST, dst=ST1}, an))
1115                        else if n2 <= n1 andalso n2 <= 7 then                        else if n2 <= n1 andalso n2 <= 7 then
1116                          (gencode(t1, su1, []);                             (gencode t1;
1117                           gencode(t2, su2, []);                              gencode t2;
1118                           mark(I.FBINARY{binOp=operRP, src=ST, dst=ST1}, an))                           mark(I.FBINARY{binOp=operRP, src=ST, dst=ST1}, an))
1119                        else let (* both labels > 7 *)                           else
1120                             let (* both labels > 7 *)
1121                            val fs = I.FDirect(newFreg())                            val fs = I.FDirect(newFreg())
1122                          in                           in  gencode t2;
                           gencode (t2, su2, []);  
1123                            emit(fstp(fty, fs));                            emit(fstp(fty, fs));
1124                            gencode (t1, su1, []);                               gencode t1;
1125                            mark(I.FBINARY{binOp=oper, src=fs, dst=ST}, an)                            mark(I.FBINARY{binOp=oper, src=fs, dst=ST}, an)
1126                          end                          end
1127                      end                      end
1128                    in                    in case binop of
1129                      case fexp                         FADD => doit(t1,t2,I.FADDL,I.FADDP,I.FADDP)
1130                      of T.FADD(_, t1, t2) => doit(t1, t2,I.FADD,I.FADDP,I.FADDP)                       | FMUL => doit(t1,t2,I.FMULL,I.FMULP,I.FMULP)
1131                       | T.FMUL(_, t1, t2) => doit(t1, t2,I.FMUL,I.FMULP,I.FMULP)                       | FSUB => doit(t1,t2,I.FSUBL,I.FSUBP,I.FSUBRP)
1132                       | 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)  
1133                       | _ => error "gencode.BINARY"                       | _ => error "gencode.BINARY"
1134                    end                    end
1135                  | gencode(fexp, UNARY(_, LEAF 0), an) =                  | gencode(UNARY(_, _, unaryOp, su, an)) =
1136                    (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"  
1137    
1138                val labels = suNumbering(fexp, LEFT)                (* Generate code for a leaf.
1139            in  gencode(fexp, labels, an)                 * Returns the type and an effective address
1140                   *)
1141                  and leafEA(T.FREG(fty, f)) = (REAL, fty, I.FDirect f)
1142                    | leafEA(T.FLOAD(fty, ea, mem)) = (REAL, fty, address(ea, mem))
1143                    | leafEA(T.CVTI2F(_, 32, t)) = int2real(32, I.MOVL, t)
1144                    | leafEA(T.CVTI2F(_, 16, t)) = int2real(16, I.MOVSWL, t)
1145                    | leafEA(T.CVTI2F(_, 8, t))  = int2real(8, I.MOVSBL, t)
1146                    | leafEA _ = error "leafEA"
1147    
1148                  (* Move integer t of size ty into a memory location *)
1149                  and int2real(ty, mov, t) =
1150                      let val opnd = operand t
1151                      in  if isMemOpnd opnd andalso (ty = 16 orelse ty = 32)
1152                          then (INTEGER, ty, opnd)
1153                          else (emit(I.MOVE{mvOp=mov, src=opnd, dst=tempMem});
1154                                (INTEGER, 32, tempMem))
1155                      end
1156              in  gencode(su fexp)
1157            end (*reduceFexp*)            end (*reduceFexp*)
1158    
1159            (* generate code for a statement *)            (* generate code for a statement *)
# Line 1138  Line 1173 
1173          | stmt(T.BCC(ctrl, cc, lab), an) = branch(cc, lab, an)          | stmt(T.BCC(ctrl, cc, lab), an) = branch(cc, lab, an)
1174          | stmt(T.DEFINE l, _) = defineLabel l          | stmt(T.DEFINE l, _) = defineLabel l
1175          | stmt(T.ANNOTATION(s, a), an) = stmt(s, a::an)          | stmt(T.ANNOTATION(s, a), an) = stmt(s, a::an)
1176            | stmt(T.EXT s, an) =
1177                 ExtensionComp.compileSext (reducer()) {stm=s, an=an}
1178          | stmt(s, _) = doStmts(Gen.compileStm s)          | stmt(s, _) = doStmts(Gen.compileStm s)
1179    
1180        and doStmt s = stmt(s, [])        and doStmt s = stmt(s, [])

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

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