let rec translate_mexpr mexpr =
  let t_mexpr = mexpr.mexpr_type in
  match mexpr.mexpr_t with 
  | CTTMexpWrite(lv, fields, None, e2) ->
      let lv, i1 = translate_lvalue lv in
      let v2, i2 = translate_mexpr e2 in
      v2, make_il0 (IL0stmtWrite(lv,fields,v2)) :: (i1 @ i2)
  | CTTMexpWrite(lv, fields, Some(binop,tcast), e2) ->
      let lv, i1 = translate_lvalue lv in
      let v2, i2 = translate_mexpr e2 in
      let tv_pre, i3 = gentemp_read (lv,fields) t_mexpr in
      let (tv_pre_c, i4), tc = 
        match tcast with
          None -> (tv_pre, []), t_mexpr
        | Some tc ->
            let tv_pre_c, i4 = gentemp (ILexpCoerce(tc,tv_pre)) tc
            in (tv_pre_c, [i4]), tc
      in
      let tv, i5 = gentemp (ILexpBinop(cvt_binop binop,tv_pre_c,v2)) tc in
      let tv, i6 = match tcast with
        None -> tv, []
      |        Some _ -> let tv, i6 = gentemp (ILexpCoerce(t_mexpr,tv)) t_mexpr in
        tv, [i6]
      in
      let is = i5 :: i3 :: make_il0 (IL0stmtWrite(lv,fields,tv))::(i6 @ i4 @ i1 @ i2) in
      (match binop with
      | CTTbinPostPlusVV | CTTbinPostMinusVV 
      | CTTbinPostPlusPV | CTTbinPostMinusPV -> tv_pre
      |        _ -> tv), is
  | CTTMexpComma(e1,e2) ->
      let v1, i1 = translate_mexpr e1 in
      let v2, i2 = translate_mexpr e2 in
      v2, [enclose_sequence [enclose_parallel i1; enclose_parallel i2]]
  | CTTMexpRead(lv, fields) ->
      let lv, i1 = translate_lvalue ~allow_invoke:true lv in
      let tv_pre, i3 = gentemp_read (lv,fields) t_mexpr in
      tv_pre, i3::i1
  | CTTMexpConstant(c) ->
    let v, i = gentemp (ILexpConstant c) t_mexpr in
    v, [i]
  | CTTMexpBinExpr(binop, e1, e2) ->
      let v1, i1 = translate_mexpr e1 in
      let v2, i2 = translate_mexpr e2 in
      let v, i = gentemp (ILexpBinop (cvt_binop binop, v1, v2)) t_mexpr in
      v, (i :: i1) @ i2
  | CTTMexpCoerce (t1, e1) ->
      let v1, i1 = translate_mexpr e1 in
      let v, i = gentemp (ILexpCoerce (t1, v1)) t_mexpr in
      v, i :: i1
  | CTTMexpUnaryExpr (uop, e1) ->
      let v1, i1 = translate_mexpr e1 in
      let v, i = gentemp (ILexpUnaryop (uop, v1)) t_mexpr in
      v, i :: i1
  | CTTMexpConditional(e1,e2,e3) ->
      let v1, i1 = translate_mexpr e1 in
      let v2, i2 = translate_mexpr e2 in
      let v3, i3 = translate_mexpr e3 in
      let vt = new_tempid () in
      let s1, s2 = make_label(), make_label() in
      vt, [enclose_sequence 
             [enclose_parallel i1;
              make_il0 (IL0stmtIf(IFNOT, v1, s1));
              enclose_parallel i2;
              make_il0 (IL0stmtDefTemp(vt, e2.mexpr_type, ILexpIdent v2));
              make_il0 (IL0stmtGoto s2);
              make_il0 (IL0stmtLabel s1);
              enclose_parallel i3;
              make_il0 (IL0stmtDefTemp(vt, e2.mexpr_type, ILexpIdent v3));
              make_il0 (IL0stmtLabel s2)]]
  | CTTMexpInvoke(lhs,rhs) -> 
      let ts = List.map translate_mexpr rhs in
      let vs, is = List.split ts in
      let is = List.flatten is in
      let lv, ilv = translate_lvalue lhs in
      let v, i = gentemp (ILexpInvoke(lv, vs)) t_mexpr in
      v, [enclose_sequence
            [enclose_parallel (is @ ilv);
             i]]
  | CTTMexpAddress(lv,fields) ->
      let lv, i1 = translate_lvalue lv in
      let v, i = gentemp (ILexpAddress(lv,fields)) t_mexpr in
      v, i :: i1

and translate_lvalue ?(allow_invoke = false) lv = 
  match lv with
    CTTMlvPtr e1 ->
      let v1, i1 = translate_mexpr e1 in
      ILlvPtr(v1), i1
  | CTTMlvVar(v1,t1) ->
      ILlvVar(v1,t1), []
  | CTTMlvInvoke (lhs,rhs,t1) ->
      if allow_invoke then begin
        let ts = List.map translate_mexpr rhs in
        let vs, is = List.split ts in
        let is = List.flatten is in
        let lv, ilv = translate_lvalue lhs in
        let v, i = gentemp (ILexpInvoke(lv, vs)) t1 in
        ILlvTemp(v), [enclose_sequence
                        [enclose_parallel (is @ ilv);
                         i]]
      end else
        failwith "non-lvalue not allowed (result of function invocation)"