diff --git a/drivers/c.drv b/drivers/c.drv index 9a4598a7e47d6f3ce6d2c931c19959d51abed04a..9617410814d787cb658a756db987adbcf9c29fcd 100644 --- a/drivers/c.drv +++ b/drivers/c.drv @@ -47,6 +47,47 @@ end module mach.int.UInt32 + prelude + +" +#define LOW_MASK 0x00000000FFFFFFFFULL + +void add_with_carry(uint32_t * res, uint32_t * carry, uint32_t x, uint32_t y, uint32_t c) +{ + uint64_t r = (uint64_t)x + (uint64_t)y + (uint64_t) c; + *res = (uint32_t)(r & LOW_MASK); + *carry = (uint32_t)(r >> 32); +} + +void sub_with_borrow(uint32_t * res, uint32_t * borrow, uint32_t x, uint32_t y, uint32_t b) +{ + uint64_t r = (uint64_t)x - (uint64_t)y - (uint64_t) b; + *res = (uint32_t)(r & LOW_MASK); + *borrow = (uint32_t)(r >> 63); +} + +void mul_double(uint32_t * low, uint32_t * high, uint32_t x, uint32_t y) +{ + uint64_t r = (uint64_t)x * (uint64_t)y; + *low = (uint32_t)(r & LOW_MASK); + *high = (uint32_t)(r >> 32); +} + +void add3(uint32_t * low, uint32_t * high, uint32_t x, uint32_t y, uint32_t z) +{ + uint64_t r = (uint64_t)x + (uint64_t)y + (uint64_t) z; + *low = (uint32_t)(r & LOW_MASK); + *high = (uint32_t)(r >> 32); +} + +void lsld(uint32_t * low, uint32_t * high, uint32_t x, uint32_t cnt) +{ + uint64_t r = (uint64_t)x << cnt; + *low = (uint32_t)(r & LOW_MASK); + *high = (uint32_t)(r >> 32); +} +" + syntax val of_int "%1" syntax converter of_int "%1" @@ -64,6 +105,10 @@ module mach.int.UInt32 syntax val (<) "%1 < %2" syntax val (>=) "%1 >= %2" syntax val (>) "%1 > %2" + + syntax val add_mod "%1 + %2" + syntax val sub_mod "%1 - %2" + syntax val mul_mod "%1 * %2" end diff --git a/examples/in_progress/multiprecision/Makefile b/examples/in_progress/multiprecision/Makefile index 39f706e750cfc9a9c40ab044e92bb8d032e0849d..e2a1f2b124aa55e5288dcec6137936230c0a6db0 100644 --- a/examples/in_progress/multiprecision/Makefile +++ b/examples/in_progress/multiprecision/Makefile @@ -1,2 +1,5 @@ +all: why3 extract +why3: + make -C ../../.. extract: - why3 extract -D c -o build mp2.mlw -T Main + why3 extract -D c -o build mp2.mlw -T N diff --git a/examples/in_progress/multiprecision/mp2.mlw b/examples/in_progress/multiprecision/mp2.mlw index 6e659ebf7d8fa10a7fb160133dc038dabac5af44..1470283790e440af201f7fe966a599401dc59367 100644 --- a/examples/in_progress/multiprecision/mp2.mlw +++ b/examples/in_progress/multiprecision/mp2.mlw @@ -1518,11 +1518,6 @@ module N = () - val lsld (x cnt:limb) : (limb,limb) - requires { 0 < l2i cnt < 32 } - returns { (r,d) -> l2i r + radix * l2i d = - (power 2 (l2i cnt)) * l2i x } - let lemma pow2_32 () ensures { power 2 32 = radix } = @@ -2110,30 +2105,21 @@ module N assert { l2i !qh * l2i d + l2i !r = l2i ul + radix * l2i uh }; (!qh,!r) -end - -module Main - - use import mach.c.C - use import N - use import mach.int.Int32 - use import int.Int - use import ref.Ref - + (** Tests *) let print (p:t) (m n:int32) : unit requires { 0 <= p.offset + p2i m <= p.offset + p2i n <= plength p } = let i = ref m in - let q = ref (incr p m) in + let q = ref (C.incr p m) in let one = Int32.of_int 1 in while (Int32.(<) !i n) do invariant { p2i m <= p2i !i <= p2i n } invariant { (!q).offset = p.offset + p2i !i } invariant { plength !q = plength p } variant { p2i n - p2i !i } - print_uint32 (get !q); + print_uint32 (C.get !q); print_space (); q := C.incr !q one; i := Int32.(+) !i one; @@ -2159,7 +2145,7 @@ module Main if not (is_null p) then begin C.set p l1; - C.set (incr p (Int32.of_int 1)) l2 + C.set (C.incr p (Int32.of_int 1)) l2 end; p @@ -2167,7 +2153,7 @@ module Main let p = from_limb (Limb.of_int 42) in if not (is_null p) then begin - print_uint32 (get p); + print_uint32 (C.get p); print_newline (); end; free p; diff --git a/modules/mach/int.mlw b/modules/mach/int.mlw index 8db904c8efda281538ab77dc0b0e5217ee4e51d4..edb865d997f604d210a7b4e7bd35476a4eb006e4 100644 --- a/modules/mach/int.mlw +++ b/modules/mach/int.mlw @@ -113,6 +113,7 @@ module Unsigned use import int.Int use import int.EuclideanDivision + use import int.Power let constant min_unsigned : int = 0 @@ -157,6 +158,11 @@ module Unsigned to_int r + (max+1) * to_int d = to_int x * to_int y } + val lsld (x cnt:t) : (t,t) + requires { 0 < to_int cnt < 32 } + returns { (r,d) -> to_int r + (max+1) * to_int d = + (power 2 (to_int cnt)) * to_int x } + end module Int31 diff --git a/src/mlw/cprinter.ml b/src/mlw/cprinter.ml index 4ff2eee3e6a980ef99d064eed88dc51f6e69c4ca..4d3e1ae362ab161d9aeec1dfa80766ceba62ba45 100644 --- a/src/mlw/cprinter.ml +++ b/src/mlw/cprinter.ml @@ -220,6 +220,15 @@ module C = struct d, Sfor(e1,e2,e3,s') | s -> d,s + let rec elim_empty_blocks = function + | Sblock ([], s) -> elim_empty_blocks s + | Sblock (d,s) -> Sblock (d, elim_empty_blocks s) + | Sseq (s1,s2) -> Sseq (elim_empty_blocks s1, elim_empty_blocks s2) + | Sif (c,t,e) -> Sif(c, elim_empty_blocks t, elim_empty_blocks e) + | Swhile (c,s) -> Swhile(c, elim_empty_blocks s) + | Sfor(e1,e2,e3,s) -> Sfor(e1,e2,e3,elim_empty_blocks s) + | s -> s + let rec elim_nop = function | Sseq (s1,s2) -> let s1 = elim_nop s1 in @@ -286,9 +295,9 @@ module Print = struct | Tvoid -> fprintf fmt "void" | Tsyntax (s, tl) -> syntax_arguments - (if paren then ("("^s^")") else s) + s (print_ty ~paren:false) fmt tl - | Tptr ty -> fprintf fmt "(%a)*" (print_ty ~paren:true) ty + | Tptr ty -> fprintf fmt "%a *" (print_ty ~paren:true) ty | Tarray (ty, expr) -> fprintf fmt (protect_on paren "%a[%a]") (print_ty ~paren:true) ty (print_expr ~paren:false) expr @@ -366,6 +375,7 @@ module Print = struct (print_expr ~paren:false) e (print_stmt ~braces:true) (Sblock([],b)) | Sfor _ -> raise (Unprinted "for loops") | Sbreak -> fprintf fmt "break;" + | Sreturn Enothing -> fprintf fmt "return;" | Sreturn e -> fprintf fmt "return %a;" (print_expr ~paren:true) e and print_def fmt def = @@ -442,6 +452,7 @@ module Translate = struct type syntax_env = { in_unguarded_loop : bool; computes_return_value : bool; + returns_tuple: bool * ident list; breaks : Sid.t; returns : Sid.t; } @@ -463,32 +474,50 @@ module Translate = struct begin match ce.c_node with | Cfun e -> expr info env e | Capp (rs, pvsl) -> - let e = match query_syntax info.syntax rs.rs_name with - | Some s -> - let params = - List.map (fun pv -> (C.Evar(pv_name pv), - ty_of_ty info (ty_of_ity pv.pv_ity))) - pvsl in - let rty = ty_of_ity e.e_ity in - let rtyargs = match rty.ty_node with - | Tyvar _ -> [||] - | Tyapp (_,args) -> Array.of_list (List.map (ty_of_ty info) args) - in - C.Esyntax(s,ty_of_ty info rty, rtyargs, params, - Mid.mem rs.rs_name info.converter) - | None -> - let args = List.filter - (fun pv -> not (pv.pv_ghost - || ity_equal pv.pv_ity ity_unit)) - pvsl in - C.(Ecall(Evar(rs.rs_name), - List.map (fun pv -> Evar(pv_name pv)) args)) - in - C.([], - if env.computes_return_value - && not (ity_equal rs.rs_cty.cty_result ity_unit) - then Sreturn e - else Sexpr e) + if is_rs_tuple rs && env.computes_return_value + then begin + match env.returns_tuple with + | true, rl -> + let args = List.filter (fun pv -> not (pv.pv_ghost + || ity_equal pv.pv_ity ity_unit)) + pvsl in + assert (List.length rl = List.length args); + C.([], + List.fold_right2 (fun res arg acc -> + Sseq(Sexpr(Ebinop(Bassign, + Eunop(Ustar,Evar(res)), + Evar(pv_name arg))), + acc)) + rl args (Sreturn(Enothing))) + | _ -> assert false + end + else + let e = match query_syntax info.syntax rs.rs_name with + | Some s -> + let params = + List.map (fun pv -> (C.Evar(pv_name pv), + ty_of_ty info (ty_of_ity pv.pv_ity))) + pvsl in + let rty = ty_of_ity e.e_ity in + let rtyargs = match rty.ty_node with + | Tyvar _ -> [||] + | Tyapp (_,args) -> Array.of_list (List.map (ty_of_ty info) args) + in + C.Esyntax(s,ty_of_ty info rty, rtyargs, params, + Mid.mem rs.rs_name info.converter) + | None -> + let args = List.filter + (fun pv -> not (pv.pv_ghost + || ity_equal pv.pv_ity ity_unit)) + pvsl in + C.(Ecall(Evar(rs.rs_name), + List.map (fun pv -> Evar(pv_name pv)) args)) + in + C.([], + if env.computes_return_value + && not (ity_equal rs.rs_cty.cty_result ity_unit) + then Sreturn e + else Sexpr e) | _ -> raise (Unsupported "Cpur/Cany") (*TODO clarify*) end | Eassign _ -> raise (Unsupported "mutable field assign") @@ -556,6 +585,7 @@ module Translate = struct let cd, cs = C.flatten_defs cd cs in let env' = { computes_return_value = false; in_unguarded_loop = true; + returns_tuple = env.returns_tuple; returns = env.returns; breaks = if env.in_unguarded_loop @@ -583,6 +613,7 @@ module Translate = struct in let env' = { computes_return_value = env.computes_return_value; in_unguarded_loop = false; + returns_tuple = env.returns_tuple; breaks = breaks; returns = returns; } in @@ -603,14 +634,15 @@ module Translate = struct match p.pat_node with Pvar _ -> true |_-> false) rets -> - let rets = List.map - (fun p -> match p.pat_node with - | Pvar vs -> C.(Eunop(Uaddr,Evar(vs.vs_name))) + let rets, defs = List.fold_right + (fun p (r, d)-> match p.pat_node with + | Pvar vs -> (C.(Eunop(Uaddr,Evar(vs.vs_name)))::r, + C.Ddecl(ty_of_ty info vs.vs_ty, [vs.vs_name, C.Enothing])::d) | _ -> assert false ) - rets in + rets ([], []) in let d,s = expr info {env with computes_return_value = false} e1 in let b = expr info env e2 in - d, C.(Sseq(add_to_last_call rets s, Sblock b)) + d@defs, C.(Sseq(add_to_last_call rets s, Sblock b)) | Ecase _ -> raise (Unsupported "pattern matching") | Eghost _ | Epure _ | Eabsurd -> assert false @@ -630,20 +662,58 @@ module Translate = struct && not (ity_equal pv.pv_ity ity_unit)) rs.rs_cty.cty_args) in begin match ce.c_node with - | Cfun e -> - let rity = rs.rs_cty.cty_result in - let rtype = - if ity_equal rity ity_unit - then C.Tvoid - else ty_of_ty info (ty_of_ity rity) in - let env = { computes_return_value = true; - in_unguarded_loop = false; - returns = Sid.empty; - breaks = Sid.empty; } in - let d,s = expr info env e in - let d,s = C.flatten_defs d s in - let s = C.elim_nop s in - [C.Dfun (fname, (rtype,params), (d,s))] + | Cfun e -> + let env = { computes_return_value = true; + in_unguarded_loop = false; + returns_tuple = false, []; + returns = Sid.empty; + breaks = Sid.empty; } in + let rity = rs.rs_cty.cty_result in + let is_simple_tuple ity = + let arity_zero = function + | Ityapp(_,a,r) -> a = [] && r = [] + | Ityreg { reg_args = a; reg_regs = r } -> a = [] && r = [] + | Ityvar _ -> true + in + (match ity.ity_node with + | Ityapp ({its_ts = s},_,_) | Ityreg { reg_its = {its_ts = s}; } + -> is_ts_tuple s + | _ -> false) + && (ity_fold (fun acc ity -> acc && arity_zero ity.ity_node) true ity) + in + (* FIXME is it necessary to have arity 0 in regions ?*) + let rtype = + if ity_equal rity ity_unit + then C.Tvoid + else ty_of_ty info (ty_of_ity rity) in + let env, rtype, params = match rtype with + | C.Tnosyntax when is_simple_tuple rity -> + (* instead of returning a tuple, return + void and assign the result to addresses + passed as parameters *) + let returns = + let f ity b acc = + if b + then (C.Tptr(ty_of_ty info (ty_of_ity ity)), + id_register (id_fresh "result"))::acc + else acc + in + match rity.ity_node with + | Ityapp(s, tl,_) + | Ityreg { reg_its = s; reg_args = tl } -> + List.fold_right2 f tl s.its_arg_vis [] + | Ityvar _ -> assert false + in + {env with returns_tuple = true, List.map snd returns}, + C.Tvoid, + returns@params + | _ -> env, rtype, params + in + let d,s = expr info env e in + (* let d,s = C.flatten_defs d s in *) + let s = C.elim_nop s in + let s = C.elim_empty_blocks s in + [C.Dfun (fname, (rtype,params), (d,s))] | _ -> raise (Unsupported "Non-function with no syntax in toplevel let") end