Newer
Older
(**************************************************************************)
(* *)
(* This file is part of WP plug-in of Frama-C. *)
(* *)
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
(* CEA (Commissariat a l'energie atomique et aux energies *)
(* alternatives) *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License as published by the Free Software *)
(* Foundation, version 2.1. *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)
(* GNU Lesser General Public License for more details. *)
(* *)
(* See the GNU Lesser General Public License version 2.1 *)
(* for more details (enclosed in the file licenses/LGPLv2.1). *)
(* *)
(**************************************************************************)
(* -------------------------------------------------------------------------- *)
(* --- ACSL Translation --- *)
(* --- LogicSemantics and LogicCompiler are mutually recursive (cycle --- *)
(* --- closed by "boostrap*" function --- *)
(* -------------------------------------------------------------------------- *)
open Cil_types
open Cil_datatype
open LogicBuiltins
open Clabels
open Ctypes
open Lang
open Lang.F
open Definitions
open Sigs
module Make(M : Sigs.Model) =
struct
module M = M
open M
type loc = M.loc
type value = loc Sigs.value
type logic = loc Sigs.logic
type result = loc Sigs.result
type region = loc Sigs.region
type sigma = Sigma.t
module L = Cvalues.Logic(M)
module C = LogicCompiler.Make(M)
(* -------------------------------------------------------------------------- *)
(* --- Frames --- *)
(* -------------------------------------------------------------------------- *)
type call = C.call
type frame = C.frame
let pp_frame = C.pp_frame
let get_frame = C.get_frame
let mk_frame = C.mk_frame
let in_frame = C.in_frame
let mem_frame = C.mem_frame
let mem_at_frame = C.mem_at_frame
let set_at_frame = C.set_at_frame
let mem_at = C.mem_at
let env_at = C.env_at
let local = C.local
let frame = C.frame
let call = C.call
let call_pre = C.call_pre
let call_post = C.call_post
let return = C.return
let result = C.result
let status = C.status
let guards = C.guards
(* -------------------------------------------------------------------------- *)
(* --- Translation Environment & Recursion --- *)
(* -------------------------------------------------------------------------- *)
type env = C.env
let mk_env = C.mk_env
let move_at = C.move_at
let current = C.current
let logic_of_value = function
| Val e -> Vexp e
| Loc l -> Vloc l
let loc_of_term env t =
match C.logic env t with
| Vexp e -> M.pointer_loc e
| Vloc l -> l
| _ ->
Warning.error "Non-expected set of locations (%a)" Printer.pp_term t
let val_of_term env t =
match C.logic env t with
| Vexp e -> e
| Vloc l -> M.pointer_val l
| Vset s -> Vset.concretize s
| Lset _ ->
Warning.error "Non-expected set of values (%a)" Printer.pp_term t
let set_of_term env t = L.vset (C.logic env t)
let collection_of_term env t =
let v = C.logic env t in
match v with
| Vexp s when Logic_typing.is_set_type t.term_type ->
let te = Logic_typing.type_of_set_elem t.term_type in
Vset [Vset.Set(tau_of_ltype te,s)]
| w -> w
let term env t =
match C.logic env t with
| Vexp e -> e
| Vloc l -> M.pointer_val l
| s -> Vset.concretize (L.vset s)
(* -------------------------------------------------------------------------- *)
(* --- Accessing an Offset (sub field-index in a compound) --- *)
(* -------------------------------------------------------------------------- *)
let rec access_offset env (v:logic) = function
| TNoOffset -> v
| TModel _ -> Wp_parameters.not_yet_implemented "Model field"
| TField(f,offset) ->
let v_f = L.map (fun r -> e_getfield r (Cfield (f, KValue))) v in
access_offset env v_f offset
let rk = C.logic env k in
let v_k = L.apply e_get v rk in
access_offset env v_k offset
(* -------------------------------------------------------------------------- *)
(* --- Updating an Offset (sub field-index in a compound) --- *)
(* -------------------------------------------------------------------------- *)
let rec update_offset env (r:term) offset (v:term) = match offset with
| TNoOffset -> v
| TModel _ -> Wp_parameters.not_yet_implemented "Model field"
| TField(f,offset) ->
let r_f = e_getfield r (Cfield (f, KValue)) in
let r_fv = update_offset env r_f offset v in
e_setfield r (Cfield (f, KValue)) r_fv
let k = val_of_term env k in
let r_kv = update_offset env (e_get r k) offset v in
e_set r k r_kv
(* -------------------------------------------------------------------------- *)
(* --- Shifting Location of an Offset (pointer shift) --- *)
(* -------------------------------------------------------------------------- *)
(* typ is logic-type of (load v) *)
let rec logic_offset env typ (v:logic) = function
| TNoOffset -> typ , v
| TModel _ -> Wp_parameters.not_yet_implemented "Model field"
| TField(f,offset) ->
logic_offset env f.ftype (L.field v f) offset
let te = Cil.typeOf_array_elem typ in
let size = Ctypes.get_array_size (Ctypes.object_of typ) in
let obj = Ctypes.object_of te in
let vloc = L.shift v obj ?size (C.logic env k) in
logic_offset env te vloc offset
(* -------------------------------------------------------------------------- *)
(* --- Logic Variable --- *)
(* -------------------------------------------------------------------------- *)
type lv_value =
| VAL of logic
| VAR of varinfo
let logic_var env lv =
match lv.lv_origin with
| None -> VAL (C.logic_var env lv)
| Some x ->
if x.vformal then match C.formal x with
| Some v -> VAL (logic_of_value v)
| None -> VAR x
else VAR x
(* -------------------------------------------------------------------------- *)
(* --- Term L-Values (this means 'loading' the l-value) --- *)
(* -------------------------------------------------------------------------- *)
let load_loc env typ loc loffset =
let te,lp = logic_offset env typ (Vloc loc) loffset in
L.load (C.current env) (Ctypes.object_of te) lp
let term_lval env (lhost,loffset) =
match lhost with
| TResult ty ->
begin match C.result () with
| Sigs.R_var x ->
access_offset env (Vexp (e_var x)) loffset
| Sigs.R_loc l ->
load_loc env ty l loffset
end
let te = Logic_typing.ctype_of_pointed e.term_type in
let te , lp = logic_offset env te (C.logic env e) loffset in
L.load (C.current env) (Ctypes.object_of te) lp
| TVar{lv_name="\\exit_status"} ->
assert (loffset = TNoOffset) ; (* int ! *)
Vexp (e_var (C.status ()))
begin
match logic_var env lv with
| VAL v -> access_offset env v loffset
| VAR x -> load_loc env x.vtype (M.cvar x) loffset
end
(* -------------------------------------------------------------------------- *)
(* --- Address of L-Values --- *)
(* -------------------------------------------------------------------------- *)
let logic_lval env (lhost,loffset) =
match lhost with
| TResult ty ->
begin match C.result () with
| R_loc l ->
logic_offset env ty (Vloc l) loffset
| R_var _ ->
Wp_parameters.abort ~current:true "Address of \\result"
end
let te = Logic_typing.ctype_of_pointed e.term_type in
logic_offset env te (C.logic env e) loffset
begin
match logic_var env lv with
| VAL v ->
Wp_parameters.abort ~current:true
"Address of logic value (%a)@." (Cvalues.pp_logic M.pretty) v
| VAR x ->
logic_offset env x.vtype (Vloc (M.cvar x)) loffset
end
let addr_lval env lv = snd (logic_lval env lv)
let lval env lv =
let te,ve = logic_lval env lv in
match ve with
| Vexp e -> te , M.pointer_loc e
| Vloc l -> te , l
| _ ->
Wp_parameters.abort ~current:true "Unexpected set (%a)"
Printer.pp_term_lval lv
(* -------------------------------------------------------------------------- *)
(* --- Unary Operators --- *)
(* -------------------------------------------------------------------------- *)
(* Only integral *)
let term_unop = function
| Neg -> L.map_opp
| BNot -> L.map Cint.l_not
| LNot -> L.map e_not
(* -------------------------------------------------------------------------- *)
(* --- Equality --- *)
(* -------------------------------------------------------------------------- *)
type eqsort =
| EQ_set
| EQ_loc
| EQ_plain
| EQ_comp of compinfo
| EQ_incomparable
and matrixinfo = c_object * int option list
let eqsort_of_type t =
match Logic_utils.unroll_type ~unroll_typedef:false t with
| Ltype({lt_name="set"},[_]) -> EQ_set
| Linteger | Lreal | Lvar _ | Larrow _ | Ltype _ -> EQ_plain
| Ctype t ->
match Ctypes.object_of t with
| C_pointer _ -> EQ_loc
| C_int _ -> EQ_plain
| C_float f -> EQ_float f
| C_comp c -> EQ_comp c
| C_array a -> EQ_array (Ctypes.array_dimensions a)
let eqsort_of_comparison a b =
match eqsort_of_type a.term_type , eqsort_of_type b.term_type with
| EQ_set , _ | _ , EQ_set -> EQ_set
| EQ_loc , EQ_loc -> EQ_loc
| EQ_comp c1 , EQ_comp c2 ->
if Compinfo.equal c1 c2 then EQ_comp c1 else EQ_incomparable
if Ctypes.equal t1 t2 then
match Matrix.merge d1 d2 with
| Some d -> EQ_array(t1,d)
| None -> EQ_incomparable
else EQ_incomparable
| EQ_plain , EQ_plain -> EQ_plain
| EQ_float f1 , EQ_float f2 when f1 = f2 -> EQ_float f1
| _ -> EQ_incomparable
let use_equal = function
| `Negative -> Wp_parameters.ExtEqual.get ()
| `Positive | `NoPolarity -> false
let term_equal polarity env a b =
match eqsort_of_comparison a b with
| EQ_set ->
let sa = set_of_term env a in
let sb = set_of_term env b in
(* TODO: should be parametric in the equality of elements *)
Vset.equal sa sb
let la = loc_of_term env a in
let lb = loc_of_term env b in
M.loc_eq la lb
let va = val_of_term env a in
let vb = val_of_term env b in
if use_equal polarity
then p_equal va vb
else Cvalues.equal_comp c va vb
let va = val_of_term env a in
let vb = val_of_term env b in
if use_equal polarity
then p_equal va vb
else Cvalues.equal_array m va vb
Cfloat.feq f (val_of_term env a) (val_of_term env b)
p_equal (val_of_term env a) (val_of_term env b)
(* incomparable terms *)
Warning.error
"@[Incomparable terms:@ type %a with@ type %a@]"
Printer.pp_logic_type a.term_type
Printer.pp_logic_type b.term_type
let term_diff polarity env a b =
p_not (term_equal (Cvalues.negate polarity) env a b)
let float_of_logic_type lt =
match Logic_utils.unroll_type lt with
| Ctype ty ->
(match Cil.unrollType ty with
| TFloat(f,_) -> Some (Ctypes.c_float f)
| _ -> None)
| _ -> None
let compare_term env vrel lrel frel a b =
if Logic_typing.is_pointer_type a.term_type then
lrel (loc_of_term env a) (loc_of_term env b)
else match float_of_logic_type a.term_type with
| Some f -> frel f (val_of_term env a) (val_of_term env b)
| None -> vrel (val_of_term env a) (val_of_term env b)
(* -------------------------------------------------------------------------- *)
(* --- Term Comparison --- *)
(* -------------------------------------------------------------------------- *)
let exp_equal env a b =
Vexp(e_prop (term_equal `NoPolarity env a b))
let exp_diff env a b =
Vexp(e_prop (term_diff `NoPolarity env a b))
let exp_compare env vrel lrel frel a b =
Vexp(e_prop (compare_term env vrel lrel frel a b))
(* -------------------------------------------------------------------------- *)
(* --- Binary Operators --- *)
(* -------------------------------------------------------------------------- *)
let toreal t v =
if t then L.map Cmath.real_of_int v else v
let arith env fint freal a b =
let va = C.logic env a in
let vb = C.logic env b in
let ta = Logic_typing.is_integral_type a.term_type in
let tb = Logic_typing.is_integral_type b.term_type in
if ta && tb
then fint va vb
else freal (toreal ta va) (toreal tb vb)
let rec fold_assoc bop acc ts =
match ts with
| [] -> acc
| t::others ->
match t.term_node with
| TBinOp(binop,a,b) when bop == binop ->
fold_assoc bop acc (a::b::others)
| _ -> fold_assoc bop (t::acc) others
let term_binop env binop a b =
match binop with
| PlusA -> arith env L.apply_add (L.apply F.e_add) a b
| MinusA -> arith env L.apply_sub (L.apply F.e_sub) a b
| Mult -> arith env (L.apply e_mul) (L.apply F.e_mul) a b
| Div -> arith env (L.apply e_div) (L.apply F.e_div) a b
| Mod -> L.apply e_mod (C.logic env a) (C.logic env b)
let va = C.logic env a in
let vb = C.logic env b in
let te = Logic_typing.ctype_of_pointed a.term_type in
L.shift va (Ctypes.object_of te) vb
let va = C.logic env a in
let vb = C.logic env b in
let te = Logic_typing.ctype_of_pointed a.term_type in
L.shift va (Ctypes.object_of te) (L.map_opp vb)
let te = Logic_typing.ctype_of_pointed a.term_type in
let la = loc_of_term env a in
let lb = loc_of_term env b in
Vexp(M.loc_diff (Ctypes.object_of te) la lb)
| Shiftlt -> L.apply Cint.l_lsl (C.logic env a) (C.logic env b)
| Shiftrt -> L.apply Cint.l_lsr (C.logic env a) (C.logic env b)
| BAnd -> L.apply Cint.l_and (C.logic env a) (C.logic env b)
| BXor -> L.apply Cint.l_xor (C.logic env a) (C.logic env b)
| BOr -> L.apply Cint.l_or (C.logic env a) (C.logic env b)
| LAnd -> Vexp(e_and (List.map (val_of_term env) (fold_assoc LAnd [] [a;b])))
| LOr -> Vexp(e_or (List.map (val_of_term env) (fold_assoc LOr [] [a;b])))
| Lt -> exp_compare env p_lt M.loc_lt Cfloat.flt a b
| Gt -> exp_compare env p_lt M.loc_lt Cfloat.flt b a
| Le -> exp_compare env p_leq M.loc_leq Cfloat.fle a b
| Ge -> exp_compare env p_leq M.loc_leq Cfloat.fle b a
| Eq -> exp_equal env a b
| Ne -> exp_diff env a b
(* -------------------------------------------------------------------------- *)
(* --- Term Cast --- *)
(* -------------------------------------------------------------------------- *)
type cvsort =
| L_bool
| L_real
| L_integer
| L_cint of c_int
| L_cfloat of c_float
| L_pointer of typ
| L_array of arrayinfo
let rec cvsort_of_ltype src_ltype =
match Logic_utils.unroll_type ~unroll_typedef:false src_ltype with
| Linteger -> L_integer
| Lreal -> L_real
| Ctype src_ctype ->
begin
match Ctypes.object_of src_ctype with
| C_int i -> L_cint i
| C_float f -> L_cfloat f
| C_pointer te -> L_pointer te
| C_array a -> L_array a (* into the logic, C array = logic array *)
| C_comp c when c.cstruct ->
Warning.error "@[Logic cast from struct (%a) not implemented yet@]"
Printer.pp_typ src_ctype
| C_comp _ ->
Warning.error "@[Logic cast from union (%a) not implemented yet@]"
Printer.pp_typ src_ctype
end
| Ltype _ as b when Logic_const.is_boolean_type b -> L_bool
| Ltype({lt_name="set"},[elt_ltype]) -> (* lifting or set of elements ? *)
| (Ltype _ | Lvar _ | Larrow _) as typ ->
Warning.error "@[Logic cast from (%a) not implemented yet@]"
Printer.pp_logic_type typ
(** cast to a C type *)
let term_cast_to_ctype env dst_ctype t =
let cast_ptr ty t0 =
let value = C.logic env t in
let o_src = Ctypes.object_of t0 in
let o_dst = Ctypes.object_of ty in
if Ctypes.compare o_src o_dst = 0
then value
else L.map_loc (M.cast { pre=o_src ; post=o_dst }) value
in
match Ctypes.object_of dst_ctype , cvsort_of_ltype t.term_type with
(* Cast to C integers from ...*)
| C_int _ , L_bool ->
let v = C.logic env t in
if (Ctypes.sub_c_int i0 i) then v
else L.map (Cint.convert i) v
L.map_l2t (M.int_of_loc i) (C.logic env t)
L.map (fun v -> Cint.of_real i (Cfloat.real_of_float f v)) (C.logic env t)
Warning.error "@[Logic cast to sized integer (%a) from (%a) not implemented yet@]"
Printer.pp_typ dst_ctype Printer.pp_logic_type t.term_type
(* Cast to C float from ... *)
| C_float f , L_real ->
L.map (Cfloat.float_of_real f) (C.logic env t)
let map v = if Ctypes.equal_float ff ft then v else Cfloat.float_of_real ft (Cfloat.real_of_float ff v) in
L.map map (C.logic env t)
| C_float f , (L_cint _ | L_integer) ->
L.map (Cfloat.float_of_int f) (C.logic env t)
| C_float _, (L_bool|L_pointer _|L_array _) ->
Warning.error "@[Logic cast to float (%a) from (%a) not implemented yet@]"
Printer.pp_typ dst_ctype Printer.pp_logic_type t.term_type
(* Cast to C pointer from ... *)
| C_pointer ty , (L_integer | L_cint _) ->
let obj = Ctypes.object_of ty in
L.map_t2l (M.loc_of_int obj) (C.logic env t)
| C_pointer _, (L_bool|L_real|L_cfloat _|L_array _) ->
Warning.error "@[Logic cast to pointer (%a) from (%a) not implemented yet@]"
Printer.pp_typ dst_ctype Printer.pp_logic_type t.term_type
(* Cast to C array from ... *)
| C_array _, L_pointer t0 ->
(* cast to an array `(T[])(p)` is equivalent
to a deref of a cast to a pointer `*(T( * )[])(p)` *)
let cast = cast_ptr dst_ctype t0 in
L.load (C.current env) (Ctypes.object_of dst_ctype) cast
| C_array dst_arr_info, L_array src_arr_info
when Ctypes.AinfoComparable.equal dst_arr_info src_arr_info ->
(* cast from/to the same type *)
C.logic env t
| C_array {arr_flat=Some _}, (L_integer|L_cint _|L_bool|L_real|L_cfloat _|L_array _) ->
Warning.error "@[Logic cast to sized array (%a) from (%a) not implemented yet@]"
Printer.pp_typ dst_ctype Printer.pp_logic_type t.term_type
| C_array {arr_flat=None}, (L_integer|L_cint _|L_bool|L_real|L_cfloat _|L_array _) ->
Warning.error "@[Logic cast to unsized array (%a) from (%a) not implemented yet@]"
Printer.pp_typ dst_ctype Printer.pp_logic_type t.term_type
(* Cast to C compound from ... *)
| C_comp c, (L_integer|L_cint _|L_bool|L_real|L_cfloat _|L_array _|L_pointer _) when c.cstruct ->
Warning.error "@[Logic cast to struct (%a) from (%a) not implemented yet@]"
Printer.pp_typ dst_ctype Printer.pp_logic_type t.term_type
| C_comp _, (L_integer|L_cint _|L_bool|L_real|L_cfloat _|L_array _|L_pointer _) ->
Warning.error "@[Logic cast to union (%a) from (%a) not implemented yet@]"
Printer.pp_typ dst_ctype Printer.pp_logic_type t.term_type
let term_cast_to_real env t =
let src_ltype = Logic_utils.unroll_type ~unroll_typedef:false t.term_type in
match cvsort_of_ltype src_ltype with
| L_cint _ ->
L.map (fun x -> Cmath.real_of_int (Cint.to_integer x)) (C.logic env t)
L.map Cmath.real_of_int (C.logic env t)
L.map (Cfloat.real_of_float f) (C.logic env t)
| L_real -> C.logic env t
| L_bool|L_pointer _|L_array _ ->
Warning.error "@[Logic cast from (%a) to (%a) not implemented yet@]"
Printer.pp_logic_type src_ltype Printer.pp_logic_type Lreal
let term_cast_to_integer env t =
let src_ltype = Logic_utils.unroll_type ~unroll_typedef:false t.term_type in
match cvsort_of_ltype src_ltype with
| L_real ->
L.map Cmath.int_of_real (C.logic env t)
L.map
(fun x -> Cmath.int_of_real (Cfloat.real_of_float f x))
(C.logic env t)
L.map Cmath.bool_of_int (C.logic env t)
Warning.error "@[Logic cast from (%a) to (%a) not implemented yet@]"
Printer.pp_logic_type src_ltype Printer.pp_logic_type Linteger
let term_cast_to_boolean env t =
let src_ltype = Logic_utils.unroll_type ~unroll_typedef:false t.term_type in
match cvsort_of_ltype src_ltype with
| L_bool -> C.logic env t
L.map Cmath.int_of_bool (C.logic env t)
| L_real | L_cfloat _ | L_pointer _ | L_array _ ->
Warning.error "@[Logic cast from (%a) to (%a) not implemented yet@]"
Printer.pp_logic_type src_ltype Printer.pp_logic_type Logic_const.boolean_type
let rec term_cast_to_ltype env dst_ltype t =
match Logic_utils.unroll_type ~unroll_typedef:false dst_ltype with
| Ctype typ-> term_cast_to_ctype env typ t
| Linteger -> term_cast_to_integer env t
| Lreal -> term_cast_to_real env t
| Ltype _ as b when Logic_const.is_boolean_type b -> term_cast_to_boolean env t
| Ltype({lt_name="set"},[elt_ltype]) -> (* lifting, set of elements ? *)
| (Ltype _ | Lvar _ | Larrow _) as dst_ltype ->
let src_ltype = Logic_utils.unroll_type ~unroll_typedef:false t.term_type in
Warning.error "@[Logic cast to (%a) from (%a) not implemented yet@]"
Printer.pp_logic_type dst_ltype Printer.pp_logic_type src_ltype
(* -------------------------------------------------------------------------- *)
(* --- Environment Binding --- *)
(* -------------------------------------------------------------------------- *)
let bind_quantifiers (env:env) qs =
let rec acc xs env hs = function
| [] -> List.rev xs , env , hs
| v::vs ->
let t = Lang.tau_of_ltype v.lv_type in
let x = Lang.freshvar ~basename:v.lv_name t in
let h =
if Wp_parameters.SimplifyForall.get ()
then F.p_true
else C.has_ltype v.lv_type (e_var x)
in
let e = C.env_let env v (Vexp (e_var x)) in
acc (x::xs) e (h::hs) vs in
acc [] env [] qs
(* -------------------------------------------------------------------------- *)
(* --- Undefined Term --- *)
(* -------------------------------------------------------------------------- *)
let term_undefined t =
let x = Lang.freshvar ~basename:"w" (Lang.tau_of_ltype t.term_type) in
Cvalues.plain t.term_type (e_var x)
(* -------------------------------------------------------------------------- *)
(* --- Term Nodes --- *)
(* -------------------------------------------------------------------------- *)
let term_node (env:env) t =
match t.term_node with
| TConst c -> Vexp (Cvalues.logic_constant c)
| TSizeOf _ | TSizeOfE _ | TSizeOfStr _ | TAlignOf _ | TAlignOfE _ ->
if Cil.isVolatileTermLval lval &&
Cvalues.volatile ~warn:"unsafe volatile access to (term) l-value" ()
then term_undefined t
else term_lval env lval
| TAddrOf lval -> addr_lval env lval
| TStartOf lval ->
begin
let lt = Cil.typeOfTermLval lval in
let base = addr_lval env lval in
match Logic_utils.unroll_type lt with
| Ctype ct ->
L.map_loc (fun l -> Cvalues.startof ~shift:M.shift l ct) base
| _ -> base
end
| TUnOp(Neg,t) when not (Logic_typing.is_integral_type t.term_type) ->
| TUnOp(unop,t) -> term_unop unop (C.logic env t)
| TBinOp(binop,a,b) -> term_binop env binop a b
| TCastE(ty,t) -> term_cast_to_ctype env ty t
| TLogic_coerce(typ,t) -> term_cast_to_ltype env typ t
| Tapp(f,ls,ts) ->
let vs = List.map (val_of_term env) ts in
let result = Lang.tau_of_ltype t.term_type in
let r = match LogicBuiltins.logic f with
| ACSLDEF -> C.call_fun env result f ls vs
| HACK phi -> phi vs
| LFUN f -> e_fun ~result f vs
in Vexp r
Warning.error "Lambda-functions not yet implemented"
| TDataCons({ctor_name="\\true"},_) -> Vexp(e_true)
| TDataCons({ctor_name="\\false"},_) -> Vexp(e_false)
| TDataCons(c,ts) ->
let es = List.map (val_of_term env) ts in
let r = match LogicBuiltins.ctor c with
| ACSLDEF -> e_fun (CTOR c) es
| HACK phi -> phi es
| LFUN f -> e_fun f es ~result:(Lang.tau_of_ltype t.term_type)
in Vexp r
let c = val_of_term env cond in
let a = val_of_term env a in
let b = val_of_term env b in
Vexp (e_if c a b)
let clabel = Clabels.of_logic label in
C.logic (C.env_at env clabel) t
ignore label ;
L.map_loc M.base_addr (C.logic env t)
ignore label ;
L.map_l2t M.base_offset (C.logic env t)
let obj = object_of (Logic_typing.ctype_of_pointed t.term_type) in
let sigma = C.mem_at env (of_logic label) in
L.map_l2t (M.block_length sigma obj) (C.logic env t)
Vexp (update_offset env (val_of_term env a) offset (val_of_term env b))
| Tempty_set -> Vset []
| Tunion ts ->
L.union t.term_type (List.map (collection_of_term env) ts)
L.inter t.term_type (List.map (collection_of_term env) ts)
begin
let xs,env,domain = bind_quantifiers env qs in
let condition = match cond with
| None -> p_conj domain
| Some p ->
let cc = C.pred `NoPolarity env in
let p = Lang.without_assume cc p in
p_conj (p :: domain)
in match C.logic env t with
| Vexp e -> Vset[Vset.Descr(xs,e,condition)]
| Vloc l -> Lset[Sdescr(xs,l,condition)]
| _ -> Wp_parameters.fatal "comprehension set of sets"
end
| Tlet( { l_var_info=v ; l_body=LBterm a } , b ) ->
let va = C.logic env a in
C.logic (C.env_let env v va) b
Warning.error "Complex let-binding not implemented yet (%a)"
Printer.pp_term t
let bound env = function
| None -> None
| Some x -> Some (val_of_term env x)
in Vset(Vset.range (bound env a) (bound env b))
Warning.error "Type tag not implemented yet"
(* -------------------------------------------------------------------------- *)
(* --- Separated --- *)
(* -------------------------------------------------------------------------- *)
let separated_terms env ts =
L.separated
begin
List.map
(fun t ->
let te = Logic_typing.ctype_of_pointed t.term_type in
let obj = Ctypes.object_of te in
L.region obj (C.logic env t)
) ts
end
(* -------------------------------------------------------------------------- *)
(* --- Relations --- *)
(* -------------------------------------------------------------------------- *)
let relation polarity env rel a b =
match rel with
| Rlt -> compare_term env p_lt M.loc_lt Cfloat.flt a b
| Rgt -> compare_term env p_lt M.loc_lt Cfloat.flt b a
| Rle -> compare_term env p_leq M.loc_leq Cfloat.fle a b
| Rge -> compare_term env p_leq M.loc_leq Cfloat.fle b a
| Req -> term_equal polarity env a b
| Rneq -> term_diff polarity env a b
(* -------------------------------------------------------------------------- *)
(* --- Predicates --- *)
(* -------------------------------------------------------------------------- *)
let valid env acs label t =
let te = Logic_typing.ctype_of_pointed t.term_type in
let sigma = C.mem_at env (Clabels.of_logic label) in
let addrs = C.logic env t in
p_all (L.valid sigma acs) (L.region (Ctypes.object_of te) addrs)
let initialized env label t =
let te = Logic_typing.ctype_of_pointed t.term_type in
let sigma = C.mem_at env (Clabels.of_logic label) in
let addrs = C.logic env t in
p_all (L.initialized sigma) (L.region (Ctypes.object_of te) addrs)
let call_pred env f ls es =
match C.logic_info env f with
| Some p ->
if ls <> [] || es <> [] then
Warning.error "Unexpected parameters for named predicate '%a'"
Logic_info.pretty f ; p
let empty ls =
if ls <> [] then
Warning.error "Unexpected labels for purely logic '%a'"
Logic_info.pretty f ;
in
match LogicBuiltins.logic f with
| ACSLDEF -> C.call_pred env f ls es
| HACK phi -> empty ls ; F.p_bool (phi es)
| LFUN p -> empty ls ; p_call p es
let predicate polarity env p =
match p.pred_content with
| Pfalse -> p_false
| Ptrue -> p_true
| Pseparated ts -> separated_terms env ts
| Prel(rel,a,b) -> relation polarity env rel a b
| Pand(a,b) -> p_and (C.pred polarity env a) (C.pred polarity env b)
| Por(a,b) -> p_or (C.pred polarity env a) (C.pred polarity env b)
| Pxor(a,b) -> p_not (p_equiv (C.pred `NoPolarity env a) (C.pred `NoPolarity env b))
| Pimplies(a,b) ->
let negated = Cvalues.negate polarity in
p_imply (C.pred negated env a) (C.pred polarity env b)
| Piff(a,b) -> p_equiv (C.pred `NoPolarity env a) (C.pred `NoPolarity env b)
| Pnot a -> p_not (C.pred (Cvalues.negate polarity) env a)
| Pif(t,a,b) ->
p_if (p_bool (val_of_term env t))
(C.pred polarity env a)
(C.pred polarity env b)
| Papp({l_var_info = {lv_name = "\\subset"}},_,ts) ->
begin match ts with
| [a;b] -> L.subset
a.term_type (C.logic env a)
b.term_type (C.logic env b)
| _ -> Warning.error "\\subset requires 2 arguments"
end
call_pred env f ls @@ List.map (val_of_term env) ts
| Plet( { l_var_info=v ; l_body=LBterm a } , p ) ->
let va = C.logic env a in
C.pred polarity (C.env_let env v va) p
| Plet( { l_var_info=v ; l_body=LBpred q } , p ) ->
let vq = C.pred `NoPolarity env q in
C.pred polarity (C.env_letp env v vq) p
Warning.error "Complex let-inding not implemented yet (%a)"
Printer.pp_predicate p
let xs,env,hs = bind_quantifiers env qs in
let p = Lang.without_assume (C.pred polarity env) p in
p_forall xs (p_hyps hs p)
let xs,env,hs = bind_quantifiers env qs in
let p = Lang.without_assume (C.pred polarity env) p in
p_exists xs (p_conj (p :: hs))
let clabel = Clabels.of_logic label in
C.pred polarity (C.env_at env clabel) p
| Pvalid(label,t) -> valid env RW label t
| Pvalid_read(label,t) -> valid env RD label t
| Pobject_pointer(label,t) -> valid env OBJ label t
| Pinitialized(label, t) -> initialized env label t
Warning.error
"\\valid_function not yet implemented@\n\
@[<hov 0>(%a)@]" Printer.pp_predicate p
| Pallocable _ | Pfreeable _ | Pfresh _ | Pdangling _ ->
Warning.error
"Allocation, initialization and danglingness not yet implemented@\n\
@[<hov 0>(%a)@]" Printer.pp_predicate p
(* -------------------------------------------------------------------------- *)
(* --- Set of locations for a term representing a set of l-values --- *)
(* -------------------------------------------------------------------------- *)
let assignable_lval env lv =
| TResult _ | TVar{lv_name="\\exit_status"} -> [] (* special case ! *)
let obj = Ctypes.object_of_logic_type (Cil.typeOfTermLval lv) in
L.region obj (addr_lval env lv)
let assignable env t =
match t.term_node with
| Tempty_set -> []
| TLval lv -> assignable_lval env lv
| Tunion ts -> List.concat (List.map (C.region env) ts)
| Tinter _ -> Warning.error "Intersection in assigns not implemented yet"
| Tcomprehension(t,qs,cond) ->
begin
let xs,env,domain = bind_quantifiers env qs in
let conditions = match cond with
| None -> domain
| Some p -> C.pred `NoPolarity env p :: domain
in
List.map
(function (obj,sloc) ->
obj , match sloc with
| Sloc l -> Sdescr(xs,l,p_conj conditions)
| (Sarray _ | Srange _ | Sdescr _) as sloc ->
let ys,l,extend = L.rdescr sloc in
Sdescr(xs@ys,l,p_conj (extend :: conditions))
) (C.region env t)
end
C.region (C.env_at env (Clabels.of_logic label)) t
| Tlet( { l_var_info=v ; l_body=LBterm a } , b ) ->
let va = C.logic env a in
C.region (C.env_let env v va) b
Warning.error "Complex let-binding not implemented yet (%a)"
Printer.pp_term t
| TLogic_coerce(_,t) -> C.region env t
| TBinOp _ | TUnOp _ | Trange _ | TUpdate _ | Tapp _ | Tif _
| TConst _ | Tnull | TDataCons _ | Tlambda _
| Ttype _ | Ttypeof _
| TAlignOfE _ | TAlignOf _ | TSizeOfStr _ | TSizeOfE _ | TSizeOf _
| Tblock_length _ | Tbase_addr _ | Toffset _ | TAddrOf _ | TStartOf _
-> Wp_parameters.abort ~current:true
"Non-assignable term (%a)" Printer.pp_term t
(* -------------------------------------------------------------------------- *)
(* --- Protection --- *)
(* -------------------------------------------------------------------------- *)
let term_protected env t =
Warning.handle
~handler:term_undefined
~severe:false
~effect:"Hide sub-term definition"
(term_node env) t
let pred_protected polarity env p =
match polarity with
| `Positive ->
Warning.handle
~effect:"Target turned to False"
~severe:true ~handler:(fun _ -> p_false)
(predicate `Positive env) p
Warning.handle
~effect:"Ignored Hypothesis"
~severe:false ~handler:(fun _ -> p_true)
(predicate `Negative env) p
(* -------------------------------------------------------------------------- *)
(* --- Boot Strapping --- *)
(* -------------------------------------------------------------------------- *)
let term_trigger env t =
let v = term_protected env t in
if List.mem "TRIGGER" t.term_name then
begin
match v with
| Vexp e -> C.trigger (Trigger.of_term e)
| Vloc l -> C.trigger (Trigger.of_term (M.pointer_val l))
| _ -> Wp_parameters.warning ~current:true
"Can not trigger on tset"
end ; v
let pred_trigger positive env np =
let p = pred_protected positive env np in
if List.mem "TRIGGER" np.Cil_types.pred_name then
C.trigger (Trigger.of_pred p);
p