~ubuntu-branches/debian/sid/frama-c/sid

« back to all changes in this revision

Viewing changes to src/jessie/interp.ml

  • Committer: Bazaar Package Importer
  • Author(s): Mehdi Dogguy
  • Date: 2009-06-03 08:19:25 UTC
  • Revision ID: james.westby@ubuntu.com-20090603081925-kihvxvt0wy3zc4ar
Tags: upstream-20081201.dfsg
ImportĀ upstreamĀ versionĀ 20081201.dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(**************************************************************************)
 
2
(*                                                                        *)
 
3
(*  This file is part of Frama-C.                                         *)
 
4
(*                                                                        *)
 
5
(*  Copyright (C) 2007-2008                                               *)
 
6
(*    INRIA (Institut National de Recherche en Informatique et en         *)
 
7
(*           Automatique)                                                 *)
 
8
(*                                                                        *)
 
9
(*  you can redistribute it and/or modify it under the terms of the GNU   *)
 
10
(*  Lesser General Public License as published by the Free Software       *)
 
11
(*  Foundation, version 2.1.                                              *)
 
12
(*                                                                        *)
 
13
(*  It is distributed in the hope that it will be useful,                 *)
 
14
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
 
15
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
 
16
(*  GNU Lesser General Public License for more details.                   *)
 
17
(*                                                                        *)
 
18
(*  See the GNU Lesser General Public License version 2.1                 *)
 
19
(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
 
20
(**************************************************************************)
 
21
 
 
22
(* $Id: interp.ml,v 1.188 2008/12/09 10:36:46 uid525 Exp $ *)
 
23
 
 
24
(* Import from Cil *)
 
25
open Cil_types
 
26
open Cil
 
27
open Cilutil
 
28
open Ast_info
 
29
open Extlib
 
30
open Db_types
 
31
 
 
32
(* Import from Why *)
 
33
open Jc
 
34
open Jc_constructors
 
35
open Jc_ast
 
36
open Jc_env
 
37
open Jc_fenv
 
38
open Jc_pervasives
 
39
 
 
40
(* Utility functions *)
 
41
open Common
 
42
open Integer
 
43
open Format
 
44
 
 
45
 
 
46
(*****************************************************************************)
 
47
(* Smart constructors.                                                       *)
 
48
(*****************************************************************************)
 
49
 
 
50
let mktype tnode = new ptype tnode
 
51
 
 
52
let mkexpr enode pos = new pexpr ~pos enode
 
53
 
 
54
let void_expr = mkexpr (JCPEconst JCCvoid) Loc.dummy_position
 
55
let null_expr = mkexpr (JCPEconst JCCnull) Loc.dummy_position
 
56
let true_expr = mkexpr (JCPEconst(JCCboolean true)) Loc.dummy_position
 
57
let zero_expr = mkexpr (JCPEconst(JCCinteger "0")) Loc.dummy_position
 
58
let one_expr = mkexpr (JCPEconst(JCCinteger "1")) Loc.dummy_position
 
59
 
 
60
let mktag tag_node pos = new ptag ~pos tag_node
 
61
 
 
62
let mkidentifier name pos = new identifier ~pos name
 
63
 
 
64
let rec mkconjunct elist pos =
 
65
  match elist with
 
66
    | [] -> true_expr
 
67
    | [e] -> e
 
68
    | e::el -> mkexpr (JCPEbinary(e,`Bland,mkconjunct el pos)) pos
 
69
 
 
70
let mkdecl dnode pos = new decl ~pos dnode
 
71
 
 
72
 
 
73
(*****************************************************************************)
 
74
(* Locate Jessie expressions on source program.                              *)
 
75
(*****************************************************************************)
 
76
 
 
77
let reg_pos ?id ?kind ?name pos = Output.reg_pos "C" ?id ?kind ?name pos
 
78
 
 
79
(* [locate] should be called on every Jessie expression which we would like to
 
80
 * locate in the original source program.
 
81
 *)
 
82
let locate ?alarm ?pos e =
 
83
  (* Recursively label conjuncts so that splitting conjuncts in Why still
 
84
   * allows to locate the resulting VC.
 
85
   *)
 
86
  let rec dopos ~toplevel e =
 
87
    (* Generate (and store) a label associated to this source location *)
 
88
    let pos = match pos with
 
89
      | None -> e#pos
 
90
      | Some pos ->
 
91
          if is_unknown_location e#pos then pos else e#pos
 
92
    in
 
93
    let lab = match alarm with
 
94
      | None ->
 
95
          reg_pos pos
 
96
      | Some Alarms.Division_alarm ->
 
97
          reg_pos ~kind:Output.DivByZero pos
 
98
      | Some Alarms.Memory_alarm ->
 
99
          reg_pos ~kind:Output.PointerDeref pos
 
100
      | Some Alarms.Shift_alarm ->
 
101
          reg_pos ~kind:Output.ArithOverflow pos
 
102
      | Some Alarms.Pointer_compare_alarm
 
103
      | Some Alarms.Using_nan_or_infinite_alarm
 
104
      | Some Alarms.Result_is_nan_or_infinite_alarm ->
 
105
          reg_pos pos
 
106
      | Some Alarms.Separation_alarm -> reg_pos pos
 
107
      | Some Alarms.Other_alarm -> reg_pos pos
 
108
    in
 
109
    let e = match e#node with
 
110
      | JCPEbinary(e1,`Bland,e2) ->
 
111
          begin match e1#node,e2#node with
 
112
            | JCPElabel _,JCPElabel _ -> e (* already labelled *)
 
113
            | JCPElabel _,_ -> (* [e1] already labelled *)
 
114
                let e2 = dopos ~toplevel:false e2 in
 
115
                mkexpr (JCPEbinary(e1,`Bland,e2)) pos
 
116
            | _,JCPElabel _ -> (* [e2] already labelled *)
 
117
                let e1 = dopos ~toplevel:false e1 in
 
118
                mkexpr (JCPEbinary(e1,`Bland,e2)) pos
 
119
            | _,_ -> (* none already labelled *)
 
120
                let e1 = dopos ~toplevel:false e1 in
 
121
                let e2 = dopos ~toplevel:false e2 in
 
122
                mkexpr (JCPEbinary(e1,`Bland,e2)) pos
 
123
          end
 
124
      | _ -> e
 
125
    in
 
126
    (* Do not generate a label for every intermediate conjunct *)
 
127
    match e#node with
 
128
      | JCPEbinary(_e1,`Bland,_e2) when not toplevel -> e
 
129
      | _ ->
 
130
          (* Label the expression accordingly *)
 
131
          mkexpr (JCPElabel(lab,e)) pos
 
132
  in
 
133
  dopos ~toplevel:true e
 
134
 
 
135
 
 
136
(*****************************************************************************)
 
137
(* Cil to Jessie translation of operators                                    *)
 
138
(*****************************************************************************)
 
139
 
 
140
let unop = function
 
141
  | Neg -> `Uminus
 
142
  | BNot -> `Ubw_not
 
143
  | LNot -> `Unot
 
144
 
 
145
let binop = function
 
146
  | PlusA -> `Badd
 
147
  | PlusPI -> `Badd
 
148
  | IndexPI -> `Badd
 
149
  | MinusA -> `Bsub
 
150
  | MinusPI -> `Bsub
 
151
  | MinusPP -> `Bsub
 
152
  | Mult -> `Bmul
 
153
  | Div -> `Bdiv
 
154
  | Mod -> `Bmod
 
155
  | Shiftlt -> `Bshift_left
 
156
  | Shiftrt -> assert false (* Should be decided at point used *)
 
157
  | Lt -> `Blt
 
158
  | Gt -> `Bgt
 
159
  | Le -> `Ble
 
160
  | Ge -> `Bge
 
161
  | Eq -> `Beq
 
162
  | Ne -> `Bneq
 
163
  | BAnd -> `Bbw_and
 
164
  | BXor -> `Bbw_xor
 
165
  | BOr -> `Bbw_or
 
166
  | LAnd -> `Bland
 
167
  | LOr -> `Blor
 
168
 
 
169
let relation = function
 
170
  | Rlt -> `Blt
 
171
  | Rgt -> `Bgt
 
172
  | Rle -> `Ble
 
173
  | Rge -> `Bge
 
174
  | Req -> `Beq
 
175
  | Rneq -> `Bneq
 
176
 
 
177
 
 
178
(*****************************************************************************)
 
179
(* Cil to Jessie translation of types                                        *)
 
180
(*****************************************************************************)
 
181
 
 
182
let type_of_padding = mktype (JCPTidentifier name_of_padding_type)
 
183
 
 
184
let type_conversion_table = Hashtbl.create 0
 
185
 
 
186
let type_conversion ty1 ty2 =
 
187
  let ty1 = typeRemoveAttributes ["const";"volatile"] (unrollType ty1) in
 
188
  let ty2 = typeRemoveAttributes ["const";"volatile"] (unrollType ty2) in
 
189
  let sig1 = typeSig ty1 and sig2 = typeSig ty2 in
 
190
  try
 
191
    let _,_,ty1_to_ty2,ty2_to_ty1 =
 
192
      Hashtbl.find type_conversion_table (sig1,sig2)
 
193
    in
 
194
    ty1_to_ty2,ty2_to_ty1
 
195
  with Not_found ->
 
196
    try
 
197
      let _,_,ty2_to_ty1,ty1_to_ty2 =
 
198
        Hashtbl.find type_conversion_table (sig2,sig1)
 
199
      in
 
200
      ty1_to_ty2,ty2_to_ty1
 
201
    with Not_found ->
 
202
      let n1 = type_name ty1 and n2 = type_name ty2 in
 
203
      let ty1_to_ty2 = unique_logic_name (n1 ^ "_to_" ^ n2) in
 
204
      let ty2_to_ty1 = unique_logic_name (n2 ^ "_to_" ^ n1) in
 
205
      Hashtbl.add
 
206
        type_conversion_table (sig1,sig2) (ty1,ty2,ty1_to_ty2,ty2_to_ty1);
 
207
      ty1_to_ty2,ty2_to_ty1
 
208
 
 
209
type float_model = [ `Real | `Strict | `Full ]
 
210
 
 
211
let float_model : float_model ref = ref `Real
 
212
 
 
213
let ctype ?bitsize ty =
 
214
  let tnode = match unrollType ty with
 
215
    | TVoid _attr -> JCPTnative Tunit
 
216
 
 
217
    | TInt(_ik,_attr) ->
 
218
        if Cmdline.Jessie.IntModel.get_val () = Cmdline.Jessie.IMexact then
 
219
          JCPTnative Tinteger
 
220
        else
 
221
          JCPTidentifier (name_of_integral_type ?bitsize ty)
 
222
 
 
223
    | TFloat(fk,_attr) ->
 
224
        begin
 
225
          match !float_model with
 
226
            | `Real -> 
 
227
                (* RealMode floats interpreted as reals *) 
 
228
                JCPTnative Treal
 
229
            | `Strict | `Full ->
 
230
                  begin
 
231
                    match fk with
 
232
                      | FFloat -> JCPTnative Tfloat
 
233
                      | FDouble -> JCPTnative Tdouble
 
234
                      | FLongDouble -> failwith "Jessie does not handle long double yet"
 
235
                  end
 
236
        end
 
237
    | TPtr(_elemty,_attr) ->
 
238
        if is_reference_type ty then
 
239
          (* Do not use [_elemty] directly but rather [pointed_type ty] in order
 
240
           * to get to the array element in references, i.e. pointers to arrays.
 
241
           *)
 
242
          begin match unrollType (pointed_type ty) with
 
243
            | TComp(compinfo,_attr) ->
 
244
                let min_bound = Num.num_of_string "0" in
 
245
                let max_bound =
 
246
                  Num.num_of_string (Int64.to_string (reference_size ty - 1L))
 
247
                in
 
248
                JCPTpointer(compinfo.cname,[],Some min_bound,Some max_bound)
 
249
            | _ -> assert false
 
250
          end
 
251
        else
 
252
          begin match unrollType (pointed_type ty) with
 
253
            | TComp(compinfo,_attr) ->
 
254
                JCPTpointer(compinfo.cname,[],None,None)
 
255
            | _ ->
 
256
                Format.eprintf "%a@." !Ast_printer.d_type ty;
 
257
                assert false
 
258
          end
 
259
 
 
260
    | TArray _ -> assert false (* Removed by translation *)
 
261
 
 
262
    | TFun _ ->
 
263
        Errormsg.s
 
264
          (Cil.error "Function pointer type %a not allowed" !Ast_printer.d_type ty)
 
265
 
 
266
    | TNamed _ -> assert false (* Removed by call to [unrollType] *)
 
267
 
 
268
    | TComp(compinfo,_attr) -> JCPTidentifier compinfo.cname
 
269
 
 
270
    | TEnum(enuminfo,_attr) -> JCPTidentifier enuminfo.ename
 
271
 
 
272
    | TBuiltin_va_list _ ->
 
273
        Errormsg.s (Cil.error "Type builtin_va_list not allowed")
 
274
  in
 
275
  mktype tnode
 
276
 
 
277
let ltype = function
 
278
  | Ctype ty -> ctype ty
 
279
  | Ltype (s,[]) -> mktype (JCPTidentifier s)
 
280
  | Linteger -> mktype (JCPTnative Tinteger)
 
281
  | Lreal -> mktype (JCPTnative Treal)
 
282
  | Ltype(_,_) | Lvar _ | Larrow _ -> assert false (* TODO *)
 
283
 
 
284
 
 
285
(*****************************************************************************)
 
286
(* Cil to Jessie translation of constants                                    *)
 
287
(*****************************************************************************)
 
288
 
 
289
let native_type_of_fkind x : Jc_env.native_type =
 
290
  match x with
 
291
    | FFloat -> Tfloat
 
292
    | FDouble -> Tdouble
 
293
    | FLongDouble -> failwith "Jessie does not handle long double yet"
 
294
 
 
295
let strip_float_suffix s =
 
296
  let l = pred(String.length s)  in
 
297
    match String.get s l with
 
298
      | 'f' | 'F' | 'l' | 'L' -> String.sub s 0 l
 
299
      | _ -> s
 
300
 
 
301
let rec const ~in_code pos = function
 
302
  | CInt64(_i,_ik,Some s) -> JCPEconst(JCCinteger s)
 
303
      (* Use the textual representation if available *)
 
304
 
 
305
  | CInt64(i,_ik,None) -> JCPEconst(JCCinteger(Int64.to_string i))
 
306
 
 
307
  | CStr _ | CWStr _ -> assert false  (* Should have been rewritten *)
 
308
 
 
309
  | CChr c -> JCPEconst(JCCinteger(string_of_int (Char.code c)))
 
310
 
 
311
  | CReal(_f,fk,Some s) -> 
 
312
      (* Use the textual representation if available *)
 
313
      let s = strip_float_suffix s in
 
314
      begin match in_code,!float_model with
 
315
        | false,_ | _,`Real -> JCPEconst(JCCreal s)
 
316
        | true, (`Strict | `Full) ->
 
317
            (* add a cast to float or double depending on the value of fk *)
 
318
            JCPEcast(mkexpr (JCPEconst(JCCreal s)) pos, mktype (JCPTnative (native_type_of_fkind fk)))
 
319
      end
 
320
  | CReal(f,_fk,None) -> 
 
321
      (* otherwise use the float value *)
 
322
      JCPEconst(JCCreal(string_of_float f))
 
323
 
 
324
  | CEnum item ->
 
325
      let e = mkexpr (const_of_expr ~in_code pos item.eival) pos in
 
326
      JCPEcast(e,ctype (TEnum(item.eihost,[])))
 
327
 
 
328
and const_of_expr ~in_code pos e =
 
329
  match stripInfo e with Const c -> const ~in_code pos c | _ -> assert false
 
330
 
 
331
and boolean_const = function
 
332
  | CInt64(i,_ik,_text) ->
 
333
      if i = Int64.zero then JCCboolean false else JCCboolean true
 
334
 
 
335
  | CStr _ | CWStr _ -> JCCboolean true
 
336
 
 
337
  | CChr c ->
 
338
      if Char.code c = 0 then JCCboolean false else JCCboolean true
 
339
 
 
340
  | CReal(f,_fk,_text) ->
 
341
      if f = 0.0 then JCCboolean false else JCCboolean true
 
342
 
 
343
  | CEnum {eival = e} -> boolean_const_of_expr e
 
344
 
 
345
and boolean_const_of_expr e =
 
346
  match stripInfo e with Const c -> boolean_const c | _ -> assert false
 
347
 
 
348
 
 
349
(*****************************************************************************)
 
350
(* Cil to Jessie translation of logic constructs                             *)
 
351
(*****************************************************************************)
 
352
 
 
353
let label = function
 
354
  | Label(lab,_,_) -> lab
 
355
  | Case _ | Default _ -> assert false
 
356
 
 
357
let logic_label lab =
 
358
  let label_name s =
 
359
    LabelName {
 
360
      label_info_name = s;
 
361
      label_info_final_name = s;
 
362
      times_used = 0;
 
363
    }
 
364
  in
 
365
  match lab with
 
366
    | LogicLabel s -> label_name s
 
367
    | StmtLabel sref ->
 
368
        let labels = filter_out is_case_label !sref.labels in
 
369
        assert (not (labels = []));
 
370
        label_name (label (List.hd labels))
 
371
 
 
372
let logic_labels = List.map logic_label
 
373
 
 
374
let logic_labels_assoc =
 
375
  List.map (fun (_,l) -> logic_label l)
 
376
 
 
377
let term_lhost pos = function
 
378
  | TVar v -> mkexpr (JCPEvar v.lv_name) pos
 
379
  | TResult -> mkexpr (JCPEvar "\\result") pos
 
380
  | TMem _ -> assert false (* Should have been rewritten *)
 
381
 
 
382
let isLogicConstant t = match t.term_node with
 
383
    TConst _ -> true
 
384
  | _ -> false
 
385
 
 
386
let rec coerce_floats t =
 
387
  match !float_model with
 
388
    | `Real -> term t
 
389
    | `Strict | `Full ->
 
390
        if isLogicFloatType t.term_type then 
 
391
          mkexpr (JCPEcast(term t, mktype (JCPTnative Treal))) t.term_loc
 
392
        else term t
 
393
      
 
394
and term t =
 
395
  let enode = match t.term_node with
 
396
    | TConst c -> const ~in_code:false t.term_loc c
 
397
 
 
398
    | TDataCons({ctor_type = Ltype ("boolean",[])} as d,_args) ->
 
399
        JCPEconst (JCCboolean (d.ctor_name = "\\true"))
 
400
 
 
401
    | TDataCons _ | TUpdate _ ->
 
402
        (* TODO, but only when we have real concrete
 
403
         * types in the Frama-C annotation grammar
 
404
         *)
 
405
        assert false
 
406
 
 
407
    | TLval lv -> (term_lval t.term_loc lv)#node
 
408
 
 
409
    | TSizeOf _ | TSizeOfE _ | TSizeOfStr _ | TAlignOf _ | TAlignOfE _ ->
 
410
        assert false (* Should be removed by constant folding *)
 
411
 
 
412
    | TUnOp(op,t) -> JCPEunary(unop op,term t)
 
413
 
 
414
    | TBinOp((Lt | Gt | Le | Ge as op),t1,t2)
 
415
        when app_term_type isPointerType false t1.term_type ->
 
416
        (* Pointer comparison is translated as subtraction *)
 
417
        let sube = mkexpr (JCPEbinary(term t1,`Bsub,term t2)) t.term_loc in
 
418
        JCPEbinary(sube,binop op,zero_expr)
 
419
 
 
420
(*     | TBinOp((Eq | Ne as op),t1,t2)  *)
 
421
(*      when app_term_type isPointerType false t1.term_type *)
 
422
(*        && (not (is_null_term t1 || is_null_term t2))  *)
 
423
(*        && (not (is_base_addr t1 || is_base_addr t2)) -> *)
 
424
(*      (\* Pointer (dis-)equality is translated as subtraction *\) *)
 
425
(*      let sube = mkexpr (JCPEbinary(term t1,`Bsub,term t2)) t.term_loc in *)
 
426
(*      JCPEbinary(sube,binop op,zero_expr) *)
 
427
 
 
428
    | TBinOp(Shiftrt,t1,t2) ->
 
429
        begin match possible_value_of_integral_term t2 with
 
430
          | Some i when i >= 0L && i < 63L ->
 
431
              (* Right shift by constant is division by constant *)
 
432
              let pow = constant_term t2.term_loc (power_of_two i) in
 
433
              JCPEbinary(term t1,`Bdiv,term pow)
 
434
          | _ ->
 
435
              let op = match t1.term_type with
 
436
                | Ctype ty1 ->
 
437
                    if isSignedInteger ty1 then `Barith_shift_right
 
438
                    else `Blogical_shift_right
 
439
                | Linteger -> `Barith_shift_right
 
440
                | _ -> assert false
 
441
              in
 
442
              JCPEbinary(term t1,op,term t2)
 
443
        end
 
444
 
 
445
    | TBinOp(Shiftlt as op,t1,t2) ->
 
446
        begin match possible_value_of_integral_term t2 with
 
447
          | Some i when i >= 0L && i < 63L ->
 
448
              (* Left shift by constant is multiplication by constant *)
 
449
              let pow = constant_term t2.term_loc (power_of_two i) in
 
450
              JCPEbinary(term t1,`Bmul,term pow)
 
451
          | _ ->
 
452
              JCPEbinary(term t1,binop op,term t2)
 
453
        end
 
454
 
 
455
    | TBinOp((Lt | Gt | Le | Ge) as op,t1,t2) ->
 
456
        JCPEbinary(term t1,binop op,term t2)
 
457
 
 
458
    | TBinOp(op,t1,t2) ->
 
459
        JCPEbinary(coerce_floats t1,binop op,coerce_floats t2)
 
460
 
 
461
    | TCastE(ty,t)
 
462
        when isIntegralType ty && isLogicArithmeticType t.term_type ->
 
463
        if Cmdline.Jessie.IntModel.get_val () = Cmdline.Jessie.IMexact then
 
464
          (term t)#node
 
465
        else
 
466
          JCPEcast(term t,ctype ty)
 
467
 
 
468
    | TCastE(ty,t)
 
469
        when isFloatingType ty && isLogicArithmeticType t.term_type ->
 
470
        JCPEcast(term t,ctype ty)
 
471
 
 
472
    | TCastE(ty,t)
 
473
        when isIntegralType ty && app_term_type isPointerType false t.term_type ->
 
474
(*        && bits_sizeof ty = force_app_term_type bits_sizeof t.term_type -> *)
 
475
(*      let _,ptr_to_int = force_app_term_type (type_conversion ty) t.term_type in *)
 
476
(*      JCPEapp(ptr_to_int,[],[term t]) *)
 
477
        Errormsg.s
 
478
          (Cil.error "Casting from type %a to type %a not allowed"
 
479
             !Ast_printer.d_logic_type t.term_type !Ast_printer.d_type ty)
 
480
 
 
481
    | TCastE(ptrty,_t1) when isPointerType ptrty ->
 
482
        let t = stripTermCasts t in
 
483
        begin match t.term_node with
 
484
          | Tnull ->
 
485
              JCPEconst JCCnull
 
486
          | TConst c
 
487
              when is_integral_const c && value_of_integral_const c = Int64.zero ->
 
488
              JCPEconst JCCnull
 
489
          | _ ->
 
490
(*            if isLogicIntegralType t.term_type then *)
 
491
(*              let addr = *)
 
492
(*                mkexpr (JCPEaddress(Addr_absolute,term t)) t.term_loc *)
 
493
(*              in *)
 
494
(*              JCPEcast(addr,ctype ptrty) *)
 
495
(*            else if force_app_term_type isIntegralType t.term_type *)
 
496
(*              && *)
 
497
(*              force_app_term_type bits_sizeof t.term_type *)
 
498
(*              = bits_sizeof ptrty *)
 
499
(*            then *)
 
500
(*              let _,int_to_ptr = *)
 
501
(*                force_app_term_type (type_conversion ptrty) t.term_type *)
 
502
(*              in *)
 
503
(*              JCPEapp(int_to_ptr,[],[term t]) *)
 
504
(*             else if force_app_term_type isPointerType t.term_type then *)
 
505
(*              let destty = pointed_type ptrty in *)
 
506
(*              let srcty = force_app_term_type pointed_type t.term_type in *)
 
507
(*              if Retype.subtype srcty destty then *)
 
508
(*                (term t)#node *)
 
509
(*              else if Retype.TypeUnion.same_class destty srcty then *)
 
510
(*                JCPEcast(term t,ctype ptrty) *)
 
511
(*              else *)
 
512
                  (* bitwise cast *)
 
513
(*                JCPEcast(term t,ctype ptrty) *)
 
514
(*                let _,ptr_to_ptr = *)
 
515
(*                  force_app_term_type (type_conversion ptrty) t.term_type *)
 
516
(*                in *)
 
517
(*                JCPEapp(ptr_to_ptr,[],[term t]) *)
 
518
(*            else *)
 
519
              (* Only hierarchical types are available in Jessie. It
 
520
               * should have been encoded as the use of pointer types
 
521
               * on structure type.
 
522
               *)
 
523
 
 
524
(*            match unrollType ty with *)
 
525
(*              | TComp(compinfo,_) -> *)
 
526
(*                  JCPEcast(term t,compinfo.cname) *)
 
527
(*              | _ -> assert false *)
 
528
              Errormsg.s
 
529
                (Cil.error "Casting from type %a to type %a not allowed in logic"
 
530
                  !Ast_printer.d_logic_type t.term_type !Ast_printer.d_type ptrty)
 
531
        end
 
532
 
 
533
    | TCastE(ty,t) ->
 
534
        (* TODO: support other casts in Jessie as well, through low-level
 
535
         * memory model
 
536
         *)
 
537
        Errormsg.s
 
538
          (Cil.error "Casting from type %a to type %a not allowed"
 
539
            !Ast_printer.d_logic_type t.term_type !Ast_printer.d_type ty)
 
540
 
 
541
    | TAddrOf _tlv -> assert false (* Should have been rewritten *)
 
542
 
 
543
    | TStartOf tlv -> (term_lval t.term_loc tlv)#node
 
544
 
 
545
    | Tapp(linfo,labels,tlist) ->
 
546
        let name = linfo.l_name in
 
547
        JCPEapp(name,logic_labels_assoc labels,List.map coerce_floats tlist)
 
548
 
 
549
    | Tif(t1,t2,t3) -> JCPEif(term t1,term t2,term t3)
 
550
 
 
551
    | Told t -> JCPEold(term t)
 
552
 
 
553
    | Tat(t,lab) -> JCPEat(term t,logic_label lab)
 
554
 
 
555
    | Tbase_addr t -> JCPEbase_block(term t)
 
556
 
 
557
    | Tblock_length _t -> assert false (* TODO: memory model for Jessie *)
 
558
 
 
559
    | Tnull -> JCPEconst JCCnull
 
560
 
 
561
    | TCoerce(_t,_typ) -> assert false (* TODO: see if useful *)
 
562
 
 
563
    | TCoerceE(_t1,_t2) -> assert false (* TODO: see if useful *)
 
564
    | Tlambda _ -> assert false (* TODO: does not exist in Jessie *)
 
565
 
 
566
    | Ttypeof _ | Ttype _ -> assert false (* Should have been treated *)
 
567
    | Ttsets _ -> assert false
 
568
  in
 
569
  mkexpr enode t.term_loc
 
570
 
 
571
and tag t =
 
572
  let tag_node = match t.term_node with
 
573
    | Ttypeof t -> JCPTtypeof (term t)
 
574
    | Ttype ty ->
 
575
        let id = mkidentifier (get_struct_name (pointed_type ty)) t.term_loc in
 
576
        JCPTtag id
 
577
    | _ -> assert false (* Not a tag *)
 
578
  in
 
579
  mktag tag_node t.term_loc
 
580
 
 
581
and term_lval pos lv =
 
582
  match lv with
 
583
    | lhost, TNoOffset -> term_lhost pos lhost
 
584
 
 
585
    | (TVar _ | TResult), _off ->
 
586
        assert false (* Should have been rewritten *)
 
587
 
 
588
    | TMem t, TField(fi,toff) ->
 
589
        assert (toff = TNoOffset); (* Others should have been rewritten *)
 
590
        let e = term t in
 
591
        if not fi.fcomp.cstruct then (* field of union *)
 
592
          mkexpr (JCPEcast(e,ctype fi.ftype)) pos
 
593
        else
 
594
          let repfi = Retype.FieldUnion.repr fi in
 
595
          let e,fi =
 
596
            if FieldinfoComparable.equal fi repfi then
 
597
              e,fi
 
598
            else
 
599
              let caste =
 
600
                mkexpr (JCPEcast(e,ctype (TPtr(TComp(repfi.fcomp,[]),[])))) pos
 
601
              in
 
602
              caste,repfi
 
603
          in
 
604
          mkexpr (JCPEderef(e,fi.fname)) pos
 
605
 
 
606
    | TMem t, TIndex(it,TField(fi,toff)) ->
 
607
        assert (toff = TNoOffset); (* Others should have been rewritten *)
 
608
        (* Normalization made it equivalent to simple add *)
 
609
        let e = mkexpr (JCPEbinary(term t,`Badd,term it)) pos in
 
610
        if not fi.fcomp.cstruct then (* field of union *)
 
611
          mkexpr (JCPEcast(e,ctype fi.ftype)) pos
 
612
        else
 
613
          let repfi = Retype.FieldUnion.repr fi in
 
614
          let e,fi =
 
615
            if FieldinfoComparable.equal fi repfi then
 
616
              e,fi
 
617
            else
 
618
              let caste =
 
619
                mkexpr (JCPEcast(e,ctype (TPtr(TComp(repfi.fcomp,[]),[])))) pos
 
620
              in
 
621
              caste,repfi
 
622
          in
 
623
          mkexpr (JCPEderef(e,fi.fname)) pos
 
624
 
 
625
    | TMem _e, TIndex _ ->
 
626
        Format.eprintf "%a@." !Ast_printer.d_term_lval lv;
 
627
        assert false (* Should have been rewritten *)
 
628
 
 
629
let tsets_lhost = function
 
630
  | TSVar lv -> mkexpr (JCPEvar lv.lv_name) Loc.dummy_position
 
631
  | TSResult -> mkexpr (JCPEvar "\\result") Loc.dummy_position
 
632
  | TSMem _ as lhost ->
 
633
      Format.eprintf "[Interp.tsets_lhost] unexpected %a@."
 
634
        !Ast_printer.d_tsets_lhost lhost;
 
635
      assert false (* Should have been rewritten *)
 
636
 
 
637
let rec tsets_elem ts =
 
638
  let enode = match ts with
 
639
    | TSLval lv -> (tsets_lval lv)#node
 
640
 
 
641
    | TSStartOf lv -> (tsets_lval lv)#node
 
642
 
 
643
    | TSAddrOf _ -> assert false (* Should have been rewritten *)
 
644
 
 
645
    | TSConst c -> const ~in_code:false Loc.dummy_position c
 
646
 
 
647
    | TSat(ts,lab) -> JCPEat(tsets_elem ts,logic_label lab)
 
648
 
 
649
    | TSAdd_index(base,idx) ->
 
650
        JCPEbinary(tsets_elem base,`Badd,term idx)
 
651
 
 
652
    | TSAdd_range(base,low,high) ->
 
653
        let e =
 
654
          mkexpr (JCPErange(opt_map term low,opt_map term high)) Loc.dummy_position
 
655
        in
 
656
        JCPEbinary(tsets_elem base,`Badd,e)
 
657
 
 
658
    | TSCastE(ty,ts)
 
659
        when isIntegralType ty && isLogicArithmeticType (typeOfTsetsElem ts) ->
 
660
        if Cmdline.Jessie.IntModel.get_val () = Cmdline.Jessie.IMexact then
 
661
          (tsets_elem ts)#node
 
662
        else
 
663
          JCPEcast(tsets_elem ts,ctype ty)
 
664
 
 
665
    | TSCastE(ty,ts)
 
666
        when isFloatingType ty && isLogicArithmeticType (typeOfTsetsElem ts) ->
 
667
        JCPEcast(tsets_elem ts,ctype ty)
 
668
 
 
669
    | TSCastE(ptrty,_ts1) when isPointerType ptrty ->
 
670
        begin match stripTsetsCasts ts with
 
671
          | TSConst c
 
672
              when is_integral_const c && value_of_integral_const c = Int64.zero ->
 
673
              JCPEconst JCCnull
 
674
          | ts ->
 
675
(*            let ety = typeOfTsetsElem ts in *)
 
676
(*            if isLogicIntegralType ety then *)
 
677
(*              let addr = *)
 
678
(*                mkexpr (JCPEaddress(Addr_absolute,tsets_elem ts)) *)
 
679
(*                  Loc.dummy_position *)
 
680
(*              in *)
 
681
(*              JCPEcast(addr,ctype ptrty) *)
 
682
(*            else if force_app_term_type isIntegralType ety then *)
 
683
(*              && *)
 
684
(*              force_app_term_type bits_sizeof ety *)
 
685
(*              = bits_sizeof ptrty *)
 
686
(*            then *)
 
687
(*              let _,int_to_ptr = *)
 
688
(*                force_app_term_type (type_conversion ptrty) ety *)
 
689
(*              in *)
 
690
(*              JCPEapp(int_to_ptr,[],[tsets_elem ts]) *)
 
691
(*            else if force_app_term_type isPointerType ety then *)
 
692
(*              let destty = pointed_type ptrty in *)
 
693
(*              let srcty = force_app_term_type pointed_type ety in *)
 
694
(*              if Retype.subtype srcty destty then *)
 
695
(*                (tsets_elem ts)#node *)
 
696
(*              else if Retype.TypeUnion.same_class destty srcty then *)
 
697
(*                JCPEcast(tsets_elem ts,ctype ptrty) *)
 
698
(*              else *)
 
699
(*                let _,ptr_to_ptr = *)
 
700
(*                  force_app_term_type (type_conversion ptrty) ety *)
 
701
(*                in *)
 
702
(*                JCPEapp(ptr_to_ptr,[],[tsets_elem ts]) *)
 
703
(*            else *)
 
704
              (* Only hierarchical types are available in Jessie. It
 
705
               * should have been encoded as the use of pointer types
 
706
               * on strucure type.
 
707
               *)
 
708
(*            match unrollType ty with *)
 
709
(*              | TComp(compinfo,_) -> JCPEcast(tsets_elem ts,compinfo.cname) *)
 
710
(*              | _ -> assert false *)
 
711
              Errormsg.s
 
712
                (Cil.error "Casting from type %a to type %a not allowed in logic"
 
713
                  !Ast_printer.d_logic_type (typeOfTsetsElem ts) !Ast_printer.d_type ptrty)
 
714
        end
 
715
 
 
716
    | TSCastE(ty,ts) ->
 
717
        (* TODO: support other casts in Jessie as well, through low-level
 
718
         * memory model
 
719
         *)
 
720
        Errormsg.s
 
721
          (Cil.error "Casting from type %a to type %a not allowed"
 
722
            !Ast_printer.d_logic_type (typeOfTsetsElem ts) !Ast_printer.d_type ty)
 
723
    | TSapp _ -> assert false
 
724
  in
 
725
  mkexpr enode Loc.dummy_position
 
726
 
 
727
and tsets_lval = function
 
728
  | lhost, TSNoOffset -> tsets_lhost lhost
 
729
 
 
730
  | (TSVar _ | TSResult), _off ->
 
731
      assert false (* Should have been rewritten *)
 
732
 
 
733
  | TSMem ts, TSField(fi,tsoff) ->
 
734
      assert (tsoff = TSNoOffset); (* Others should have been rewritten *)
 
735
      let e = tsets_elem ts in
 
736
      if not fi.fcomp.cstruct then (* field of union *)
 
737
        mkexpr (JCPEcast(e,ctype fi.ftype)) Loc.dummy_position
 
738
      else
 
739
        let repfi = Retype.FieldUnion.repr fi in
 
740
        let e,fi =
 
741
          if FieldinfoComparable.equal fi repfi then
 
742
            e,fi
 
743
          else
 
744
            let caste =
 
745
              mkexpr (JCPEcast(e,ctype (TPtr(TComp(repfi.fcomp,[]),[]))))
 
746
                Loc.dummy_position
 
747
            in
 
748
            caste,repfi
 
749
        in
 
750
        mkexpr (JCPEderef(e,fi.fname)) Loc.dummy_position
 
751
 
 
752
  | TSMem ts, TSIndex(it,TSField(fi,tsoff)) ->
 
753
      assert (tsoff = TSNoOffset); (* Others should have been rewritten *)
 
754
      (* Normalization made it equivalent to simple add *)
 
755
      let e =
 
756
        mkexpr (JCPEbinary(tsets_elem ts,`Badd,term it)) Loc.dummy_position
 
757
      in
 
758
      if not fi.fcomp.cstruct then (* field of union *)
 
759
        mkexpr (JCPEcast(e,ctype fi.ftype)) Loc.dummy_position
 
760
      else
 
761
        let repfi = Retype.FieldUnion.repr fi in
 
762
        let e,fi =
 
763
          if FieldinfoComparable.equal fi repfi then
 
764
            e,fi
 
765
          else
 
766
            let caste =
 
767
              mkexpr (JCPEcast(e,ctype (TPtr(TComp(repfi.fcomp,[]),[]))))
 
768
                Loc.dummy_position
 
769
            in
 
770
            caste,repfi
 
771
        in
 
772
        mkexpr (JCPEderef(e,fi.fname)) Loc.dummy_position
 
773
 
 
774
  | TSMem _ts, TSIndex _ -> assert false (* Should have been rewritten *)
 
775
 
 
776
  | TSMem ts, TSRange(low,high,TSField(fi,tsoff)) ->
 
777
      assert (tsoff = TSNoOffset); (* Others should have been rewritten *)
 
778
      (* Normalization made it equivalent to simple add *)
 
779
      let enode = JCPErange(opt_map term low,opt_map term high) in
 
780
      let e = mkexpr enode Loc.dummy_position in
 
781
      let e =
 
782
        mkexpr (JCPEbinary(tsets_elem ts,`Badd,e)) Loc.dummy_position
 
783
      in
 
784
      if not fi.fcomp.cstruct then (* field of union *)
 
785
        mkexpr (JCPEcast(e,ctype fi.ftype)) Loc.dummy_position
 
786
      else
 
787
        let repfi = Retype.FieldUnion.repr fi in
 
788
        let e,fi =
 
789
          if FieldinfoComparable.equal fi repfi then
 
790
            e,fi
 
791
          else
 
792
            let caste =
 
793
              mkexpr (JCPEcast(e,ctype (TPtr(TComp(repfi.fcomp,[]),[]))))
 
794
                Loc.dummy_position
 
795
            in
 
796
            caste,repfi
 
797
        in
 
798
        mkexpr (JCPEderef(e,fi.fname)) Loc.dummy_position
 
799
 
 
800
  | TSMem _ts, TSRange _ -> assert false (* Should have been rewritten *)
 
801
 
 
802
let rec tsets = function
 
803
  | TSSingleton ts -> [tsets_elem ts]
 
804
  | TSEmpty -> []
 
805
  | TSUnion locs -> List.flatten (List.map tsets locs)
 
806
  | TSInter _locs -> assert false (* TODO *)
 
807
  | TSComprehension(_t,_q,_p) -> assert false (* TODO *)
 
808
 
 
809
 
 
810
let rec pred p =
 
811
  let enode = match p.content with
 
812
    | Pfalse -> JCPEconst(JCCboolean false)
 
813
 
 
814
    | Ptrue -> JCPEconst(JCCboolean true)
 
815
 
 
816
    | Papp(pinfo,labels,tl) ->
 
817
        JCPEapp(pinfo.l_name,logic_labels_assoc labels,List.map term tl)
 
818
 
 
819
    | Prel((Rlt | Rgt | Rle | Rge as rel),t1,t2)
 
820
        when app_term_type isPointerType false t1.term_type ->
 
821
        (* Pointer comparison is translated as subtraction *)
 
822
        let sube = mkexpr (JCPEbinary(term t1,`Bsub,term t2)) p.loc in
 
823
        JCPEbinary(sube,relation rel,zero_expr)
 
824
 
 
825
(*     | Prel((Req | Rneq as rel),t1,t2)  *)
 
826
(*      when app_term_type isPointerType false t1.term_type *)
 
827
(*        && (not (is_null_term t1 || is_null_term t2)) *)
 
828
(*        && (not (is_base_addr t1 || is_base_addr t2)) -> *)
 
829
(*      (\* Pointer (dis-)equality is translated as subtraction *\) *)
 
830
(*      let sube = mkexpr (JCPEbinary(term t1,`Bsub,term t2)) p.loc in *)
 
831
(*      JCPEbinary(sube,relation rel,zero_expr) *)
 
832
 
 
833
    | Prel(Req,t1,t2) when isTypeTagType t1.term_type ->
 
834
        JCPEeqtype(tag t1,tag t2)
 
835
 
 
836
    | Prel(Rneq,t1,t2) when isTypeTagType t1.term_type ->
 
837
        let eq = mkexpr (JCPEeqtype(tag t1,tag t2)) p.loc in
 
838
        JCPEunary(`Unot,eq)
 
839
 
 
840
    | Prel(rel,t1,t2) ->
 
841
        JCPEbinary(coerce_floats t1,relation rel,coerce_floats t2)
 
842
 
 
843
    | Pand(p1,p2) ->
 
844
        JCPEbinary(pred p1,`Bland,pred p2)
 
845
 
 
846
    | Por(p1,p2) ->
 
847
        JCPEbinary(pred p1,`Blor,pred p2)
 
848
 
 
849
    | Pxor(p1,p2) ->
 
850
        let notp2 = { p2 with content = Pnot p2; } in
 
851
        let p1notp2 = { p with content = Pand(p1,notp2); } in
 
852
        let notp1 = { p1 with content = Pnot p1; } in
 
853
        let p2notp1 = { p with content = Pand(p2,notp1); } in
 
854
        JCPEbinary(pred p1notp2,`Blor,pred p2notp1)
 
855
 
 
856
    | Pimplies(p1,p2) ->
 
857
        JCPEbinary(pred p1,`Bimplies,pred p2)
 
858
 
 
859
    | Piff(p1,p2) ->
 
860
        JCPEbinary(pred p1,`Biff,pred p2)
 
861
 
 
862
    | Pnot p -> JCPEunary(`Unot,pred p)
 
863
 
 
864
    | Pif(t,p1,p2) -> JCPEif(term t,pred p1,pred p2)
 
865
 
 
866
    | Plet(_v,_t,_p) -> assert false (* TODO *)
 
867
 
 
868
    | Pforall([],p) -> (pred p)#node
 
869
 
 
870
    | Pforall([v],p) ->
 
871
        JCPEquantifier(Forall,ltype v.lv_type,[v.lv_name],pred p)
 
872
 
 
873
    | Pforall(v::q,subp) ->
 
874
        let newp = { p with content = Pforall(q,subp) } in
 
875
        JCPEquantifier(Forall,ltype v.lv_type,[v.lv_name],pred newp)
 
876
 
 
877
    | Pexists([],p) -> (pred p)#node
 
878
 
 
879
    | Pexists([v],p) ->
 
880
        JCPEquantifier(Exists,ltype v.lv_type,[v.lv_name],pred p)
 
881
 
 
882
    | Pexists(v::q,subp) ->
 
883
        let newp = { p with content = Pexists(q,subp) } in
 
884
        JCPEquantifier(Exists,ltype v.lv_type,[v.lv_name],pred newp)
 
885
 
 
886
    | Pold p -> JCPEold(pred p)
 
887
 
 
888
    | Pat(p,lab) -> JCPEat(pred p,logic_label lab)
 
889
 
 
890
    | Pvalid_index(t1,t2) ->
 
891
        let e1 = term t1 in
 
892
        let e2 = term t2 in
 
893
        let eoffmin = mkexpr (JCPEoffset(Offset_min,e1)) p.loc in
 
894
        let emin = mkexpr (JCPEbinary(eoffmin,`Ble,e2)) p.loc in
 
895
        let eoffmax = mkexpr (JCPEoffset(Offset_max,e1)) p.loc in
 
896
        let emax = mkexpr (JCPEbinary(eoffmax,`Bge,e2)) p.loc in
 
897
        (mkconjunct [emin; emax] p.loc)#node
 
898
 
 
899
    | Pvalid(TSSingleton(TSAdd_index(t1,t2))) ->
 
900
        let e1 = tsets_elem t1 in
 
901
        let e2 = term t2 in
 
902
        let eoffmin = mkexpr (JCPEoffset(Offset_min,e1)) p.loc in
 
903
        let emin = mkexpr (JCPEbinary(eoffmin,`Ble,e2)) p.loc in
 
904
        let eoffmax = mkexpr (JCPEoffset(Offset_max,e1)) p.loc in
 
905
        let emax = mkexpr (JCPEbinary(eoffmax,`Bge,e2)) p.loc in
 
906
        (mkconjunct [emin; emax] p.loc)#node
 
907
 
 
908
    | Pvalid_range(t1,t2,t3) ->
 
909
        let e1 = term t1 in
 
910
        let e2 = term t2 in
 
911
        let e3 = term t3 in
 
912
        let eoffmin = mkexpr (JCPEoffset(Offset_min,e1)) p.loc in
 
913
        let emin = mkexpr (JCPEbinary(eoffmin,`Ble,e2)) p.loc in
 
914
        let eoffmax = mkexpr (JCPEoffset(Offset_max,e1)) p.loc in
 
915
        let emax = mkexpr (JCPEbinary(eoffmax,`Bge,e3)) p.loc in
 
916
        (mkconjunct [emin; emax] p.loc)#node
 
917
 
 
918
    | Pvalid(TSSingleton(TSAdd_range(t1,t2,t3))) ->
 
919
        let e1 = tsets_elem t1 in
 
920
        begin match t2,t3 with
 
921
          | None,None -> true_expr#node
 
922
          | Some t2,None ->
 
923
              let e2 = term t2 in
 
924
              let eoffmin = mkexpr (JCPEoffset(Offset_min,e1)) p.loc in
 
925
              JCPEbinary(eoffmin,`Ble,e2)
 
926
          | None, Some t3 ->
 
927
              let e3 = term t3 in
 
928
              let eoffmax = mkexpr (JCPEoffset(Offset_max,e1)) p.loc in
 
929
              JCPEbinary(eoffmax,`Bge,e3)
 
930
          | Some t2,Some t3 ->
 
931
              let e2 = term t2 in
 
932
              let e3 = term t3 in
 
933
              let eoffmin = mkexpr (JCPEoffset(Offset_min,e1)) p.loc in
 
934
              let emin = mkexpr (JCPEbinary(eoffmin,`Ble,e2)) p.loc in
 
935
              let eoffmax = mkexpr (JCPEoffset(Offset_max,e1)) p.loc in
 
936
              let emax = mkexpr (JCPEbinary(eoffmax,`Bge,e3)) p.loc in
 
937
              (mkconjunct [emin; emax] p.loc)#node
 
938
        end
 
939
 
 
940
    | Pvalid t ->
 
941
        let elist =
 
942
          List.flatten (List.map (fun e ->
 
943
            let eoffmin = mkexpr (JCPEoffset(Offset_min,e)) p.loc in
 
944
            let emin = mkexpr (JCPEbinary(eoffmin,`Ble,zero_expr)) p.loc in
 
945
            let eoffmax = mkexpr (JCPEoffset(Offset_max,e)) p.loc in
 
946
            let emax = mkexpr (JCPEbinary(eoffmax,`Bge,zero_expr)) p.loc in
 
947
            [emin; emax]
 
948
          ) (tsets t))
 
949
        in
 
950
        (mkconjunct elist p.loc)#node
 
951
 
 
952
    | Pfresh _t -> assert false (* TODO: add to memory model for Jessie *)
 
953
 
 
954
    | Psubtype({term_node = Ttypeof t},{term_node = Ttype ty}) ->
 
955
        JCPEinstanceof(term t,get_struct_name (pointed_type ty))
 
956
 
 
957
    | Psubtype(_t1,_t2) -> assert false (* TODO *)
 
958
    | Pseparated(_seps) -> assert false (* TODO *)
 
959
  in
 
960
  mkexpr enode p.loc
 
961
 
 
962
(* Keep names associated to predicate *)
 
963
let named_pred p =
 
964
  List.fold_right
 
965
    (fun lab p -> mkexpr (JCPElabel(lab,p)) p#pos) p.name (pred p)
 
966
 
 
967
let pred_has_name p n =
 
968
  List.exists (fun n2 -> n = n2) p.name
 
969
 
 
970
let remove_pred_name p n =
 
971
  { p with name = List.filter (fun n2 -> not (n = n2)) p.name }
 
972
 
 
973
let conjunct pos pl =
 
974
  mkconjunct (List.map (pred $ Logic_const.pred_of_id_pred) pl) pos
 
975
 
 
976
let zone = function
 
977
  | Location tset,_from -> tsets tset.its_content
 
978
  | Nothing,_from -> []
 
979
 
 
980
(* Distinguish between:
 
981
 * - no assign, which is the empty list in Cil and None in Jessie
 
982
 * - assigns nothing, which is [Nothing] in Cil and the Some[] in Jessie
 
983
 *)
 
984
let assigns = function
 
985
  | [] -> None
 
986
  | assign_list ->
 
987
      let assign_list =
 
988
        List.filter
 
989
          (function
 
990
               Location out,_ ->
 
991
                 not (Logic_const.tsets_is_result out.its_content)
 
992
             | Nothing, _ -> false)
 
993
          assign_list
 
994
      in
 
995
      let assign_list = List.flatten (List.map zone assign_list) in
 
996
      Some(Loc.dummy_position,assign_list)
 
997
 
 
998
let spec funspec =
 
999
  let require p =
 
1000
    JCCrequires(locate (pred (Logic_const.pred_of_id_pred p)))
 
1001
  in
 
1002
  let requires = List.map require funspec.spec_requires in
 
1003
  let behavior b =
 
1004
    JCCbehavior(
 
1005
      Loc.dummy_position,
 
1006
      b.b_name,
 
1007
      None, (* throws *)
 
1008
      Some(conjunct Loc.dummy_position b.b_assumes),
 
1009
      None, (* requires *)
 
1010
      assigns b.b_assigns,
 
1011
      locate (conjunct Loc.dummy_position b.b_ensures))
 
1012
  in
 
1013
  let behaviors = List.map behavior funspec.spec_behavior in
 
1014
 
 
1015
  if funspec.spec_complete_behaviors <> [] then
 
1016
    Errormsg.warn "[Jessie plugin] complete behaviors specification ignored";
 
1017
  if funspec.spec_disjoint_behaviors <> [] then
 
1018
    Errormsg.warn "[Jessie plugin] disjoint behaviors specification ignored";
 
1019
  if funspec.spec_variant <> None then
 
1020
    Errormsg.warn "[Jessie plugin] variant for recursive function ignored";
 
1021
  if funspec.spec_terminates <> None then
 
1022
    Errormsg.warn "[Jessie plugin] termination condition ignored";
 
1023
 
 
1024
  (* TODO: translate function spec variant, terminates and complete/disjoint
 
1025
     behaviors *)
 
1026
  requires @ behaviors
 
1027
 
 
1028
(* Depending on the argument status, an assertion with this status may
 
1029
   not generate any PO but still be used as an hypothesis. *)
 
1030
let assertion = function
 
1031
  | { status = Checked { valid = True } } -> Aassume
 
1032
  | _ -> Aassert
 
1033
 
 
1034
let assert_ pos = function
 
1035
  | WP _ -> []
 
1036
  | User annot ->
 
1037
      begin match annot.annot_content with
 
1038
        | AAssert (behav,p,status) ->
 
1039
            let asrt = assertion status in
 
1040
            [mkexpr (JCPEassert (behav,asrt,locate ~pos (named_pred p))) pos]
 
1041
        | AInvariant(behav,_,p) ->
 
1042
            [mkexpr (JCPEassert
 
1043
                       (behav,Aassert,locate ~pos (named_pred p))) pos]
 
1044
        | _ -> assert false
 
1045
      end
 
1046
  | AI(alarm,annot) ->
 
1047
      begin match annot.annot_content with
 
1048
        | AAssert (behav,p,status) ->
 
1049
            let asrt =
 
1050
              if pred_has_name p name_of_hint_assertion then Ahint
 
1051
              else assertion status
 
1052
            in
 
1053
            let p = remove_pred_name p name_of_hint_assertion in
 
1054
            let behav =
 
1055
              if behav = [] then [ name_of_default_behavior ] else behav
 
1056
            in
 
1057
            [mkexpr (JCPEassert (behav,asrt,locate ~alarm ~pos (named_pred p))) pos]
 
1058
        | AInvariant(behav,_,p) ->
 
1059
            let behav =
 
1060
              if behav = [] then [ name_of_default_behavior ] else behav
 
1061
            in
 
1062
            [mkexpr (JCPEassert
 
1063
                       (behav,Aassert,locate ~alarm ~pos (named_pred p))) pos]
 
1064
        | _ -> assert false
 
1065
      end
 
1066
 
 
1067
let invariant annot =
 
1068
  match annot.annot_content with
 
1069
    | AInvariant(behav,_loopinv,p) -> behav, locate (pred p)
 
1070
    | _ -> assert false
 
1071
 
 
1072
let variant annot =
 
1073
  match annot.annot_content with
 
1074
    | AVariant(t,_) -> locate (term t)
 
1075
    | _ -> assert false
 
1076
 
 
1077
 
 
1078
(*****************************************************************************)
 
1079
(* Cil to Jessie translation of coding constructs                            *)
 
1080
(*****************************************************************************)
 
1081
 
 
1082
let set_curFundec, get_curFundec =
 
1083
  let cf = ref None in
 
1084
  ((fun f -> cf := Some f),
 
1085
   (fun () ->
 
1086
      match !cf with
 
1087
          None ->
 
1088
            let res = emptyFunction "@empty@" in cf := Some res; res
 
1089
        | Some res -> res))
 
1090
 
 
1091
let rec expr pos e =
 
1092
  (* Precise the location if possible *)
 
1093
  let pos = match e with Info(_,einfo) -> einfo.exp_loc | _ -> pos in
 
1094
 
 
1095
  let expr = expr pos in
 
1096
  let integral_expr = integral_expr pos in
 
1097
 
 
1098
  let enode = match stripInfo e with
 
1099
    | Info _ -> assert false
 
1100
 
 
1101
    | Const c -> const ~in_code:true pos c
 
1102
 
 
1103
    | Lval lv -> (lval pos lv)#node
 
1104
 
 
1105
    | SizeOf _ | SizeOfE _ | SizeOfStr _ | AlignOf _ | AlignOfE _ ->
 
1106
        assert false (* Should be removed by constant folding *)
 
1107
 
 
1108
    | UnOp(_op,_e,ty) when isIntegralType ty ->
 
1109
        (integral_expr e)#node
 
1110
 
 
1111
    | UnOp(op,e,_ty) ->
 
1112
        let e =
 
1113
          locate (mkexpr (JCPEunary(unop op,expr e)) pos)
 
1114
        in
 
1115
        e#node
 
1116
 
 
1117
    | BinOp(_op,_e1,_e2,ty) when isIntegralType ty ->
 
1118
        (integral_expr e)#node
 
1119
 
 
1120
    | BinOp(op,e1,e2,_ty) ->
 
1121
        let e =
 
1122
          locate (mkexpr (JCPEbinary(expr e1,binop op,expr e2)) pos)
 
1123
        in
 
1124
        e#node
 
1125
 
 
1126
    | CastE(ty,e') when isIntegralType ty && isArithmeticType (typeOf e') ->
 
1127
        (integral_expr e)#node
 
1128
 
 
1129
    | CastE(ty,e) when isFloatingType ty && isArithmeticType (typeOf e) ->
 
1130
        let e = locate (mkexpr (JCPEcast(expr e,ctype ty)) pos) in
 
1131
        e#node
 
1132
 
 
1133
    | CastE(ty,e') when isIntegralType ty && isPointerType (typeOf e') ->
 
1134
(*      && bits_sizeof ty = bits_sizeof (typeOf e') -> *)
 
1135
(*      let _,ptr_to_int = type_conversion ty (typeOf e') in *)
 
1136
(*      JCPEapp(ptr_to_int,[],[expr e']) *)
 
1137
        Errormsg.s
 
1138
          (Cil.error "Casting from type %a to type %a not allowed"
 
1139
             !Ast_printer.d_type (typeOf e') !Ast_printer.d_type ty)
 
1140
 
 
1141
    | CastE(ptrty,_e1) when isPointerType ptrty ->
 
1142
        begin match stripCastsAndInfo e with
 
1143
          | Const c
 
1144
              when is_integral_const c
 
1145
                && value_of_integral_const c = Int64.zero ->
 
1146
              JCPEconst JCCnull
 
1147
          | e ->
 
1148
              let ety = typeOf e in
 
1149
              if isIntegralType ety(*  && bits_sizeof ety = bits_sizeof ptrty *) then
 
1150
(*              let _,int_to_ptr = type_conversion ptrty ety in *)
 
1151
(*              JCPEapp(int_to_ptr,[],[integral_expr e]) *)
 
1152
                Errormsg.s
 
1153
                  (Cil.error "Casting from type %a to type %a not allowed"
 
1154
                     !Ast_printer.d_type (typeOf e) !Ast_printer.d_type ptrty)
 
1155
              else if isPointerType ety then
 
1156
(*              let destty = pointed_type ptrty in *)
 
1157
(*              let srcty = pointed_type ety in *)
 
1158
(*              if Retype.subtype srcty destty then *)
 
1159
(*                (expr e)#node *)
 
1160
(*              else if Retype.TypeUnion.same_class destty srcty then *)
 
1161
(*                let enode = JCPEcast(expr e,ctype ptrty) in *)
 
1162
(*                let e = locate (mkexpr enode pos) in *)
 
1163
(*                e#node *)
 
1164
(*              else *)
 
1165
                  (* bitwise cast *)
 
1166
                  let enode = JCPEcast(expr e,ctype ptrty) in
 
1167
                  let e = locate (mkexpr enode pos) in
 
1168
                  e#node
 
1169
(*                let _,ptr_to_ptr = type_conversion ptrty ety in *)
 
1170
(*                JCPEapp(ptr_to_ptr,[],[expr e]) *)
 
1171
              else
 
1172
                (* Only hierarchical types are available in Jessie. It
 
1173
                 * should have been encoded as the use of pointer types
 
1174
                 * on structure type.
 
1175
                 *)
 
1176
(*            match unrollType ty with *)
 
1177
(*              | TComp(compinfo,_) -> *)
 
1178
(*                  JCPEcast(expr (stripCasts e),compinfo.cname) *)
 
1179
(*              | _ -> assert false *)
 
1180
                Errormsg.s
 
1181
                  (Cil.error "Casting from type %a to type %a not allowed"
 
1182
                     !Ast_printer.d_type (typeOf e) !Ast_printer.d_type ptrty)
 
1183
        end
 
1184
 
 
1185
    | CastE(ty,e) as caste ->
 
1186
        (* TODO: support other casts in Jessie as well, through low-level
 
1187
         * memory model
 
1188
         *)
 
1189
        Errormsg.s
 
1190
          (Cil.error "Casting from type %a to type %a not allowed in %a with size %Ld and %Ld"
 
1191
             !Ast_printer.d_type (typeOf e) !Ast_printer.d_type ty
 
1192
             !Ast_printer.d_exp caste
 
1193
           ( bits_sizeof ty) ( bits_sizeof (typeOf e))
 
1194
)
 
1195
 
 
1196
    | AddrOf _lv ->
 
1197
        Format.printf "%a@." !Ast_printer.d_lval _lv;
 
1198
assert false (* Should have been rewritten *)
 
1199
 
 
1200
    | StartOf lv -> (lval pos lv)#node
 
1201
  in
 
1202
  mkexpr enode pos
 
1203
 
 
1204
(* Function called when expecting a boolean in Jessie, i.e. when translating
 
1205
   a test or a sub-expression of an "or" or "and".
 
1206
*)
 
1207
and boolean_expr pos e =
 
1208
  (* Precise the posation if possible *)
 
1209
  let pos = match e with Info(_,einfo) -> einfo.exp_loc | _ -> pos in
 
1210
 
 
1211
  let expr = expr pos in
 
1212
  let boolean_expr = boolean_expr pos in
 
1213
  let boolean_node_from_expr ty e =
 
1214
    if isPointerType ty then JCPEbinary(e,`Bneq,null_expr)
 
1215
    else if isArithmeticType ty then JCPEbinary (e,`Bneq,zero_expr)
 
1216
    else assert false
 
1217
  in
 
1218
 
 
1219
  let enode = match stripInfo e with
 
1220
    | Info _ -> assert false
 
1221
 
 
1222
    | Const c -> JCPEconst(boolean_const c)
 
1223
 
 
1224
    | UnOp(LNot,e,_typ) -> JCPEunary(unop LNot,boolean_expr e)
 
1225
 
 
1226
    | BinOp((LAnd | LOr) as op,e1,e2,_typ) ->
 
1227
        JCPEbinary(boolean_expr e1,binop op,boolean_expr e2)
 
1228
 
 
1229
    | BinOp((Eq | Ne) as op,e1,e2,_typ) ->
 
1230
        JCPEbinary(expr e1,binop op,expr e2)
 
1231
 
 
1232
    | BinOp((Lt | Gt | Le | Ge) as op,e1,e2,_typ) ->
 
1233
        let ty = typeOf e1 in
 
1234
        if isArithmeticType ty then
 
1235
          JCPEbinary(expr e1,binop op,expr e2)
 
1236
        else
 
1237
          (* Pointer comparison is translated as subtraction *)
 
1238
          let sube = mkexpr (JCPEbinary(expr e1,`Bsub,expr e2)) pos in
 
1239
          JCPEbinary(sube,binop op,zero_expr)
 
1240
 
 
1241
    | _ -> boolean_node_from_expr (typeOf e) (expr e)
 
1242
  in
 
1243
  mkexpr enode pos
 
1244
 
 
1245
(* Function called instead of plain [expr] when the evaluation result should
 
1246
 * fit in a C integral type.
 
1247
 *)
 
1248
and integral_expr pos e =
 
1249
 
 
1250
  let rec int_expr pos e =
 
1251
    let expr = expr pos in
 
1252
    let int_expr = int_expr pos in
 
1253
    let boolean_expr = boolean_expr pos in
 
1254
    let node_from_boolean_expr e = JCPEif(e,one_expr,zero_expr) in
 
1255
 
 
1256
    let enode = match e with
 
1257
      | UnOp(LNot,e,_ty) ->
 
1258
          let e = mkexpr (JCPEunary(unop LNot,boolean_expr e)) pos in
 
1259
          node_from_boolean_expr e
 
1260
 
 
1261
      | UnOp(op,e,_ty) ->
 
1262
          let e =
 
1263
            locate (mkexpr (JCPEunary(unop op,expr e)) pos)
 
1264
          in
 
1265
          e#node
 
1266
 
 
1267
      | BinOp((LAnd | LOr) as op,e1,e2,_ty) ->
 
1268
          let e =
 
1269
            mkexpr (JCPEbinary(boolean_expr e1,binop op,boolean_expr e2)) pos
 
1270
          in
 
1271
          node_from_boolean_expr e
 
1272
 
 
1273
      | BinOp((Lt | Gt | Le | Ge as op),e1,e2,_ty)
 
1274
          when isPointerType (typeOf e1) ->
 
1275
          (* Pointer comparison is translated as subtraction *)
 
1276
          let sube = mkexpr (JCPEbinary(expr e1,`Bsub,expr e2)) pos in
 
1277
          let e = mkexpr (JCPEbinary(sube,binop op,zero_expr)) pos in
 
1278
          node_from_boolean_expr e
 
1279
 
 
1280
(*       | BinOp((Eq | Ne as op),e1,e2,_ty) *)
 
1281
(*        when isPointerType (typeOf e1) && *)
 
1282
(*          not (is_null_expr e2 || is_null_expr e1) -> *)
 
1283
(*        (\* Pointer (dis-)equality is translated as subtraction *\) *)
 
1284
(*        let sube = mkexpr (JCPEbinary(expr e1,`Bsub,expr e2)) pos in *)
 
1285
(*        let e = mkexpr (JCPEbinary(sube,binop op,zero_expr)) pos in *)
 
1286
(*        node_from_boolean_expr e *)
 
1287
 
 
1288
      | BinOp((Eq | Ne) as op,e1,e2,_ty) ->
 
1289
          let e = mkexpr (JCPEbinary(expr e1,binop op,expr e2)) pos in
 
1290
          node_from_boolean_expr e
 
1291
 
 
1292
      | BinOp((Lt | Gt | Le | Ge) as op,e1,e2,_ty) ->
 
1293
          let e = mkexpr (JCPEbinary(expr e1,binop op,expr e2)) pos in
 
1294
          node_from_boolean_expr e
 
1295
 
 
1296
      | BinOp(Shiftrt,e1,e2,_ty) ->
 
1297
          let e = match possible_value_of_integral_expr e2 with
 
1298
            | Some i when i >= 0L && i < 63L ->
 
1299
                (* Right shift by constant is division by constant *)
 
1300
                let pow = constant_expr (power_of_two i) in
 
1301
                locate (mkexpr (JCPEbinary(expr e1,`Bdiv,expr pow)) pos)
 
1302
            | _ ->
 
1303
                let op =
 
1304
                  if isSignedInteger (typeOf e1) then `Barith_shift_right
 
1305
                  else `Blogical_shift_right
 
1306
                in
 
1307
                locate (mkexpr (JCPEbinary(expr e1,op,expr e2)) pos)
 
1308
          in
 
1309
          e#node
 
1310
 
 
1311
      | BinOp(Shiftlt as op,e1,e2,_ty) ->
 
1312
          let e = match possible_value_of_integral_expr e2 with
 
1313
            | Some i when i >= 0L && i < 63L ->
 
1314
                (* Left shift by constant is multiplication by constant *)
 
1315
                let pow = constant_expr (power_of_two i) in
 
1316
                locate (mkexpr (JCPEbinary(expr e1,`Bmul,expr pow)) pos)
 
1317
            | _ ->
 
1318
                locate (mkexpr (JCPEbinary(expr e1,binop op,expr e2)) pos)
 
1319
          in
 
1320
          e#node
 
1321
 
 
1322
      | BinOp(op,e1,e2,_ty) ->
 
1323
          let e =
 
1324
            locate (mkexpr (JCPEbinary(expr e1,binop op,expr e2)) pos)
 
1325
          in
 
1326
          e#node
 
1327
 
 
1328
      | CastE(ty,e1) when isFloatingType (typeOf e1) ->
 
1329
          let e1' = locate (mkexpr (JCPEcast(expr e1,ltype Linteger)) pos) in
 
1330
          if Cmdline.Jessie.IntModel.get_val () = Cmdline.Jessie.IMexact then
 
1331
            e1'#node
 
1332
          else
 
1333
            let e2' = locate (mkexpr (JCPEcast(e1',ctype ty)) pos) in
 
1334
            e2'#node
 
1335
 
 
1336
      | CastE(ty,e) when isIntegralType (typeOf e) ->
 
1337
          if Cmdline.Jessie.IntModel.get_val () = Cmdline.Jessie.IMexact then
 
1338
            (int_expr e)#node
 
1339
          else
 
1340
            let e = locate (mkexpr (JCPEcast(int_expr e,ctype ty)) pos) in
 
1341
            e#node
 
1342
 
 
1343
      | _ -> (expr e)#node
 
1344
    in
 
1345
    mkexpr enode pos
 
1346
  in
 
1347
 
 
1348
  match e with
 
1349
    | CastE _ -> int_expr pos e
 
1350
    | _ -> int_expr pos (CastE(typeOf e,e))
 
1351
 
 
1352
and lval pos = function
 
1353
  | Var v, NoOffset -> mkexpr (JCPEvar v.vname) pos
 
1354
 
 
1355
  | Var _v, _off -> assert false (* Should have been rewritten *)
 
1356
 
 
1357
  | Mem _e, NoOffset -> assert false (* Should have been rewritten *)
 
1358
 
 
1359
  | Mem e, Field(fi,off) ->
 
1360
      assert (off = NoOffset); (* Others should have been rewritten *)
 
1361
      let e = expr pos e in
 
1362
      if not fi.fcomp.cstruct then (* field of union *)
 
1363
        locate (mkexpr (JCPEcast(e,ctype fi.ftype)) pos)
 
1364
      else
 
1365
        let repfi = Retype.FieldUnion.repr fi in
 
1366
        let e,fi =
 
1367
          if FieldinfoComparable.equal fi repfi then
 
1368
            e,fi
 
1369
          else
 
1370
            let caste =
 
1371
              locate
 
1372
                (mkexpr
 
1373
                   (JCPEcast(e,ctype (TPtr(TComp(repfi.fcomp,[]),[])))) pos)
 
1374
            in
 
1375
            caste,repfi
 
1376
        in
 
1377
        locate (mkexpr (JCPEderef(e,fi.fname)) pos)
 
1378
 
 
1379
  | Mem e, Index(ie,Field(fi,off)) ->
 
1380
      assert (off = NoOffset); (* Others should have been rewritten *)
 
1381
      (* Normalization made it equivalent to simple add *)
 
1382
      let e = mkexpr (JCPEbinary(expr pos e,`Badd,expr pos ie)) pos in
 
1383
      if not fi.fcomp.cstruct then (* field of union *)
 
1384
        locate (mkexpr (JCPEcast(e,ctype fi.ftype)) pos)
 
1385
      else
 
1386
        let repfi = Retype.FieldUnion.repr fi in
 
1387
        let e,fi =
 
1388
          if FieldinfoComparable.equal fi repfi then
 
1389
            e,fi
 
1390
          else
 
1391
            let caste =
 
1392
              locate
 
1393
                (mkexpr
 
1394
                   (JCPEcast(e,ctype (TPtr(TComp(repfi.fcomp,[]),[])))) pos)
 
1395
            in
 
1396
            caste,repfi
 
1397
        in
 
1398
        locate (mkexpr (JCPEderef(e,fi.fname)) pos)
 
1399
 
 
1400
  | Mem _e, Index _ as lv ->
 
1401
      Format.printf "lval %a@." !Ast_printer.d_lval lv;
 
1402
      assert false (* Should have been rewritten *)
 
1403
 
 
1404
let keep_only_declared_nb_of_arguments vi l =
 
1405
  let _,args,is_variadic, _ = splitFunctionTypeVI vi in
 
1406
  if args=None then
 
1407
    (warn "skipping all arguments of implicit prototype %s" vi.vname;
 
1408
     [])
 
1409
  else if is_variadic then bug "unsupported variadic functions"
 
1410
  else l
 
1411
 
 
1412
let rec instruction = function
 
1413
  | Set(lv,e,pos) ->
 
1414
      let enode = JCPEassign(lval pos lv,expr pos e) in
 
1415
      (locate (mkexpr enode pos))#node
 
1416
 
 
1417
  | Call(None,Lval(Var v,NoOffset),eargs,pos) ->
 
1418
      if is_assert_function v then
 
1419
        JCPEassert([],Aassert,locate (boolean_expr pos (as_singleton eargs)))
 
1420
      else
 
1421
        let enode =
 
1422
          if is_free_function v then
 
1423
            let arg = as_singleton eargs in
 
1424
            let subarg = stripCasts arg in
 
1425
            let arg = if isPointerType (typeOf subarg) then subarg else arg in
 
1426
            JCPEfree(expr pos arg)
 
1427
          else
 
1428
            JCPEapp(v.vname,[],
 
1429
                    keep_only_declared_nb_of_arguments
 
1430
                      v
 
1431
                      (List.map (expr pos) eargs))
 
1432
        in
 
1433
        (locate (mkexpr enode pos))#node
 
1434
 
 
1435
  | Call(Some lv,Lval(Var v,NoOffset),eargs,pos) ->
 
1436
      let enode =
 
1437
        if is_malloc_function v || is_realloc_function v then
 
1438
          let lvtyp = pointed_type (typeOfLval lv) in
 
1439
          let lvsiz = (bits_sizeof lvtyp) lsr 3 in
 
1440
          let arg =
 
1441
            if is_malloc_function v then as_singleton eargs
 
1442
            else (* realloc *)
 
1443
              match eargs with [ _; arg ] -> arg | _ -> assert false
 
1444
          in
 
1445
          let ty,arg = match stripInfo arg with
 
1446
            | Info _ -> assert false
 
1447
            | Const c as arg when is_integral_const c ->
 
1448
                let allocsiz = (value_of_integral_expr arg) / lvsiz in
 
1449
                let siznode = JCPEconst(JCCinteger(Int64.to_string allocsiz)) in
 
1450
                lvtyp, mkexpr siznode pos
 
1451
            | BinOp(Mult,(Const c as arg),nelem,_ty)
 
1452
            | BinOp(Mult,nelem,(Const c as arg),_ty) when is_integral_const c ->
 
1453
                let factor = (value_of_integral_expr arg) / lvsiz in
 
1454
                let siz =
 
1455
                  if factor = Int64.one then
 
1456
                    expr pos nelem
 
1457
                  else
 
1458
                    let factor = constant_expr factor in
 
1459
                    expr pos (BinOp(Mult,nelem,factor,typeOf arg))
 
1460
                in
 
1461
                lvtyp, siz
 
1462
            | arg ->
 
1463
                if lvsiz = Int64.one then
 
1464
                  lvtyp, expr pos arg
 
1465
                else
 
1466
                  let esiz = constant_expr lvsiz in
 
1467
                  lvtyp, expr pos (BinOp(Div,arg,esiz,typeOf arg))
 
1468
          in
 
1469
          let name_of_type = match unrollType ty with
 
1470
            | TComp(compinfo,_) -> compinfo.cname
 
1471
            | _ -> assert false
 
1472
          in
 
1473
          JCPEalloc(arg,name_of_type)
 
1474
        else if is_calloc_function v then
 
1475
          let nelem,elsize = match eargs with
 
1476
            | [nelem;elsize] -> nelem,elsize
 
1477
            | _ -> assert false
 
1478
          in
 
1479
          let ty,arg = match stripInfo elsize with
 
1480
            | Info _ -> assert false
 
1481
            | Const c as arg when is_integral_const c ->
 
1482
                let lvtyp = pointed_type (typeOfLval lv) in
 
1483
                let lvsiz = (bits_sizeof lvtyp) lsr 3 in
 
1484
                let factor = (value_of_integral_expr arg) / lvsiz in
 
1485
                let siz =
 
1486
                  if factor = Int64.one then
 
1487
                    expr pos nelem
 
1488
                  else
 
1489
                    let factor = constant_expr factor in
 
1490
                    expr pos (BinOp(Mult,nelem,factor,typeOf arg))
 
1491
                in
 
1492
                lvtyp, siz
 
1493
            | arg ->
 
1494
                let lvtyp = pointed_type (typeOfLval lv) in
 
1495
                let lvsiz = (bits_sizeof lvtyp) lsr 3 in
 
1496
                let esiz = constant_expr lvsiz in
 
1497
                lvtyp, expr pos (BinOp(Div,
 
1498
                                       BinOp(Mult,nelem,elsize,typeOf arg),
 
1499
                                       esiz,typeOf arg))
 
1500
          in
 
1501
          let name_of_type = match unrollType ty with
 
1502
            | TComp(compinfo,_) -> compinfo.cname
 
1503
            | _ -> assert false
 
1504
          in
 
1505
          JCPEalloc(arg,name_of_type)
 
1506
        else
 
1507
          JCPEapp(v.vname,[],
 
1508
                  keep_only_declared_nb_of_arguments
 
1509
                    v
 
1510
                    (List.map (expr pos) eargs))
 
1511
      in
 
1512
      let lvty = typeOfLval lv in
 
1513
      let call = locate (mkexpr enode pos) in
 
1514
      let enode =
 
1515
        if TypeComparable.equal lvty (getReturnType v.vtype)
 
1516
          || is_malloc_function v
 
1517
          || is_realloc_function v
 
1518
          || is_calloc_function v
 
1519
        then
 
1520
          JCPEassign(lval pos lv,call)
 
1521
        else
 
1522
          let tmpv = makeTempVar (get_curFundec()) (getReturnType v.vtype) in
 
1523
          let tmplv = Var tmpv, NoOffset in
 
1524
          let cast = CastE(lvty,Lval tmplv) in
 
1525
          let tmpassign = JCPEassign(lval pos lv,expr pos cast) in
 
1526
          JCPElet(None,tmpv.vname,Some call,locate (mkexpr tmpassign pos))
 
1527
      in
 
1528
      (locate (mkexpr enode pos))#node
 
1529
 
 
1530
  | Call _ -> assert false
 
1531
 
 
1532
  | Asm _ -> assert false
 
1533
 
 
1534
  | Skip _pos -> JCPEconst JCCvoid
 
1535
 
 
1536
  | Code_annot _ -> JCPEconst JCCvoid
 
1537
      (* Annotations should be retrieved from Db *)
 
1538
 
 
1539
let rec statement s =
 
1540
  let pos = get_stmtLoc s.skind in
 
1541
 
 
1542
  let assert_list =
 
1543
    Annotations.get_filter Logic_const.is_assert s
 
1544
    @ Annotations.get_filter Logic_const.is_stmt_invariant s
 
1545
  in
 
1546
  let assert_before,assert_after =
 
1547
    List.partition (function Before _ -> true | After _ -> false) assert_list
 
1548
  in
 
1549
  let assert_before =
 
1550
    List.flatten (List.map ((assert_ pos) $ before_after_content) assert_before)
 
1551
  in
 
1552
  let assert_after =
 
1553
    List.flatten (List.map ((assert_ pos) $ before_after_content) assert_after)
 
1554
  in
 
1555
 
 
1556
  let snode = match s.skind with
 
1557
    | Instr i -> instruction i
 
1558
 
 
1559
    | Return(Some e,pos) ->
 
1560
        JCPEreturn(expr pos e)
 
1561
 
 
1562
    | Return(None,_pos) ->
 
1563
        JCPEreturn(mkexpr (JCPEconst JCCvoid) pos)
 
1564
 
 
1565
    | Goto(sref,_pos) ->
 
1566
        (* Pick the first non-case label in the list of labels associated to
 
1567
         * the target statement
 
1568
         *)
 
1569
        let labels = filter_out is_case_label !sref.labels in
 
1570
        assert (not (labels = []));
 
1571
        JCPEgoto(label (List.hd labels))
 
1572
 
 
1573
    | Break _pos ->
 
1574
        assert false (* Should not occur after [prepareCFG] *)
 
1575
 
 
1576
    | Continue _pos ->
 
1577
        assert false (* Should not occur after [prepareCFG] *)
 
1578
 
 
1579
    | If(e,bl1,bl2,pos) ->
 
1580
        JCPEif(boolean_expr pos e,block bl1,block bl2)
 
1581
 
 
1582
    | Switch(e,bl,slist,pos) ->
 
1583
        let case_blocks stat_list case_list =
 
1584
          let rec next_case curr_list final_list stat_list case_list =
 
1585
            match stat_list,case_list with
 
1586
              | curr_stat :: rest_stat, curr_case :: rest_case ->
 
1587
                  if curr_case.sid = curr_stat.sid then
 
1588
                    (* Beginning of a new case. Add previous case to list
 
1589
                       if not empty. *)
 
1590
                    let add_to_list cond e l = if cond e then e::l else l in
 
1591
                    let not_empty_list = function [] -> false | _ -> true in
 
1592
                    let final_list =
 
1593
                      add_to_list not_empty_list (List.rev curr_list) final_list
 
1594
                    in
 
1595
                    let curr_list = [curr_stat] in
 
1596
                    next_case curr_list final_list rest_stat rest_case
 
1597
                  else
 
1598
                    let curr_list = curr_stat :: curr_list in
 
1599
                    next_case curr_list final_list rest_stat case_list
 
1600
              | [], [] ->
 
1601
                  if List.length curr_list <> 0 then
 
1602
                    List.rev curr_list :: final_list
 
1603
                  else
 
1604
                    final_list
 
1605
              | [], _ ->
 
1606
                  (* More cases than available. *)
 
1607
                  assert false
 
1608
              | stat_list, [] ->
 
1609
                  (List.rev_append curr_list stat_list) :: final_list
 
1610
          in
 
1611
          List.rev (next_case [] [] stat_list case_list)
 
1612
        in
 
1613
        let switch_label = function
 
1614
          | Label _ -> assert false
 
1615
          | Case(e,pos) -> Some(expr pos e)
 
1616
          | Default _ -> None
 
1617
        in
 
1618
        let case = function
 
1619
          | [] -> assert false
 
1620
          | case_stmt :: _ as slist ->
 
1621
              let switch_labels = List.filter is_case_label case_stmt.labels in
 
1622
              let labs = List.map switch_label switch_labels in
 
1623
              let slist = mkexpr (JCPEblock(statement_list slist)) pos in
 
1624
              labs, slist
 
1625
        in
 
1626
        let case_list = List.map case (case_blocks bl.bstmts slist) in
 
1627
        JCPEswitch(expr pos e,case_list)
 
1628
 
 
1629
    | Loop (_,bl,_pos,_continue_stmt,_break_stmt) ->
 
1630
        let invariant_list =
 
1631
          Annotations.get_filter Logic_const.is_invariant s
 
1632
        in
 
1633
        let invariant_list =
 
1634
          lift_annot_list_func (List.map invariant) invariant_list
 
1635
        in
 
1636
 
 
1637
        let variant_list = Annotations.get_filter Logic_const.is_variant s in
 
1638
        let variant_list =
 
1639
          lift_annot_list_func (List.map variant) variant_list
 
1640
        in
 
1641
        (* At most one variant *)
 
1642
        let variant = match variant_list with
 
1643
          | [] -> None
 
1644
          | [e] -> Some e
 
1645
          | _ -> assert false
 
1646
        in
 
1647
        (* Issue a warning on loop assigns not yet supported *)
 
1648
        let assigns_list = Annotations.get_filter Logic_const.is_assigns s in
 
1649
        if assigns_list <> [] then
 
1650
          Errormsg.warn "[Jessie plugin] loop assigns are ignored";
 
1651
 
 
1652
        (* Locate the beginning of the loop, to serve as location for generated
 
1653
         * invariants and variants.
 
1654
         *)
 
1655
(*      let lab = reg_pos pos in *)
 
1656
        (* TODO: add loop-assigns to Jessie *)
 
1657
        JCPEwhile(true_expr,invariant_list,variant,block bl)
 
1658
 
 
1659
    | Block bl ->
 
1660
        JCPEblock(statement_list bl.bstmts)
 
1661
 
 
1662
    | UnspecifiedSequence seq ->
 
1663
        (*[VP]TODO: take into account undefined behavior tied to the
 
1664
          effects of the statements...
 
1665
         *)
 
1666
        JCPEblock(statement_list (List.map (fun (x,_,_) -> x) seq))
 
1667
 
 
1668
    | TryFinally _ | TryExcept _ -> assert false
 
1669
  in
 
1670
  (* Prefix statement by all non-case labels *)
 
1671
  let labels = filter_out is_case_label s.labels in
 
1672
  let s = mkexpr snode pos in
 
1673
  let s = match assert_before @ s :: assert_after with
 
1674
    | [s] -> s
 
1675
    | slist -> mkexpr (JCPEblock slist) pos
 
1676
  in
 
1677
  List.fold_left (fun s lab -> mkexpr (JCPElabel(label lab,s)) pos) s labels
 
1678
 
 
1679
and statement_list slist = List.rev (List.rev_map statement slist)
 
1680
 
 
1681
and block bl =
 
1682
  match bl.bstmts with
 
1683
    | [] -> mkexpr (JCPEconst JCCvoid) Loc.dummy_position
 
1684
    | [s] -> statement s
 
1685
    | slist -> mkexpr (JCPEblock(statement_list slist)) Loc.dummy_position
 
1686
 
 
1687
 
 
1688
(*****************************************************************************)
 
1689
(* Cil to Jessie translation of global declarations                          *)
 
1690
(*****************************************************************************)
 
1691
 
 
1692
let logic_variable v =
 
1693
  let name = opt_app (fun v -> v.vname) v.lv_name v.lv_origin in
 
1694
  ltype v.lv_type, name
 
1695
 
 
1696
let rec annotation = function
 
1697
  | Dfun_or_pred info ->
 
1698
      begin try
 
1699
        let params = List.map logic_variable info.l_profile in
 
1700
        let body =
 
1701
          match info.l_body with
 
1702
            | LBreads reads_tsets ->
 
1703
                let reads = List.flatten (List.map tsets reads_tsets) in
 
1704
                JCreads reads
 
1705
            | LBpred p -> JCexpr(pred p)
 
1706
            | LBinductive indcases ->
 
1707
                let l = List.map
 
1708
                  (fun (id,labs,_poly,p) ->
 
1709
                     (new identifier id,logic_labels labs,pred p)) indcases
 
1710
                in
 
1711
                JCinductive l
 
1712
            | LBterm t -> JCexpr(term t)
 
1713
        in
 
1714
        [JCDlogic(Option_misc.map ltype info.l_type,
 
1715
                  info.l_name,
 
1716
                  logic_labels info.l_labels,
 
1717
                  params,body)]
 
1718
      with Errormsg.Error ->
 
1719
        Format.printf "Dropping declaration of predicate %s@." info.l_name;
 
1720
        []
 
1721
      end
 
1722
 
 
1723
(*
 
1724
  | Dpredicate_reads(info,_poly,params,reads_tsets) ->
 
1725
      begin try
 
1726
        let params = List.map logic_variable params in
 
1727
        let reads = List.flatten (List.map tsets reads_tsets) in
 
1728
        [JCDlogic(None,info.p_name,logic_labels info.p_labels,params,JCreads reads)]
 
1729
      with Errormsg.Error ->
 
1730
        Format.printf "Dropping declaration of predicate %s@." info.p_name;
 
1731
        []
 
1732
      end
 
1733
 
 
1734
  | Dpredicate_def(info,_poly,params,def) ->
 
1735
      begin try
 
1736
        let params = List.map logic_variable params in
 
1737
        [JCDlogic(None,info.p_name,logic_labels info.p_labels,params,JCexpr(pred def))]
 
1738
      with Errormsg.Error ->
 
1739
        Format.printf "Dropping definition of predicate %s@." info.p_name;
 
1740
        []
 
1741
      end
 
1742
 
 
1743
  | Dinductive_def(info,_poly,params,indcases) ->
 
1744
      begin try
 
1745
        let params = List.map logic_variable params in
 
1746
        let l = List.map
 
1747
          (fun (id,p) ->
 
1748
             (new identifier id,pred p)) indcases
 
1749
        in
 
1750
        [JCDlogic(None,info.p_name,logic_labels info.p_labels,params,JCinductive l)]
 
1751
      with Errormsg.Error ->
 
1752
        Format.printf "Dropping definition of predicate %s@." info.p_name;
 
1753
        []
 
1754
      end
 
1755
 
 
1756
  | Dlogic_reads(info,_poly,params,return_type,reads_tsets) ->
 
1757
      begin try
 
1758
        let params = List.map logic_variable params in
 
1759
        let reads = List.flatten (List.map tsets reads_tsets) in
 
1760
        [JCDlogic(
 
1761
           Some(ltype return_type),
 
1762
           info.l_name,logic_labels info.l_labels,params,JCreads reads)]
 
1763
      with Errormsg.Error ->
 
1764
        Format.printf "Dropping declaration of logic function %s@." info.l_name;
 
1765
        []
 
1766
      end
 
1767
 
 
1768
  | Dlogic_def(info,_poly,params,return_type,def) ->
 
1769
      begin try
 
1770
        let params = List.map logic_variable params in
 
1771
        [JCDlogic(
 
1772
           Some(ltype return_type),info.l_name,logic_labels info.l_labels,params,
 
1773
           JCexpr(term def))]
 
1774
      with Errormsg.Error ->
 
1775
        Format.printf "Dropping definition of logic function %s@." info.l_name;
 
1776
        []
 
1777
      end
 
1778
 
 
1779
  | Dlogic_axiomatic(info,_poly,params,return_type,axioms) ->
 
1780
      begin try
 
1781
        let params = List.map logic_variable params in
 
1782
        let l = List.map
 
1783
          (fun (id,p) ->
 
1784
             (new identifier id,pred p)) axioms
 
1785
        in
 
1786
        [JCDlogic(
 
1787
           Some(ltype return_type),info.l_name,logic_labels info.l_labels,
 
1788
           params, JCaxiomatic l)]
 
1789
      with Errormsg.Error ->
 
1790
        Format.printf "Dropping definition of logic function %s@." info.l_name;
 
1791
        []
 
1792
      end
 
1793
*)
 
1794
  | Dlemma(name,is_axiom,labels,_poly,property) ->
 
1795
      begin try
 
1796
        [JCDlemma(name,is_axiom,logic_labels labels,pred property)]
 
1797
      with Errormsg.Error ->
 
1798
        Format.printf "Dropping lemma %s@." name;
 
1799
        []
 
1800
      end
 
1801
 
 
1802
  | Dinvariant property ->
 
1803
      begin try
 
1804
        [JCDglobal_inv(property.l_name,
 
1805
                       pred (Logic_const.get_pred_body property))]
 
1806
      with Errormsg.Error ->
 
1807
        Format.printf "Dropping invariant %s@." property.l_name;
 
1808
        []
 
1809
      end
 
1810
 
 
1811
  | Dtype_annot annot ->
 
1812
      begin try
 
1813
        [JCDlogic(
 
1814
           None,annot.l_name, logic_labels annot.l_labels,
 
1815
           List.map logic_variable annot.l_profile,
 
1816
           JCexpr(pred (Logic_const.get_pred_body annot)))]
 
1817
      with Errormsg.Error ->
 
1818
        Format.printf "Dropping type invariant %s@." annot.l_name;
 
1819
        []
 
1820
      end
 
1821
 
 
1822
  | Dtype(name,[]) -> [JCDlogic_type name]
 
1823
 
 
1824
  | Dtype(_name,_) -> assert false (* TODO *)
 
1825
 
 
1826
  | Daxiomatic(id,l) ->
 
1827
(*
 
1828
      Format.eprintf "Translating axiomatic %s into jessie code@." id;
 
1829
*)
 
1830
      let l = List.fold_left (fun acc d -> (annotation d)@acc) [] l in
 
1831
      [JCDaxiomatic(id,List.map (fun d -> mkdecl  d Loc.dummy_position )
 
1832
                      (List.rev l))]
 
1833
 
 
1834
let global vardefs g =
 
1835
  let dnodes = match g with
 
1836
    | GType _ -> [] (* No typedef in Jessie *)
 
1837
 
 
1838
    | GCompTag(compinfo,pos) when compinfo.cstruct -> (* struct type *)
 
1839
        let field fi =
 
1840
          let this = 
 
1841
            false, ctype ?bitsize:fi.fsize_in_bits fi.ftype, 
 
1842
            fi.fname, fi.fsize_in_bits 
 
1843
          in
 
1844
          let padding_size =
 
1845
            match fi.fpadding_in_bits with None -> assert false | Some i -> i
 
1846
          in
 
1847
          if padding_size = 0 then [this] else
 
1848
            let padding =
 
1849
              false, type_of_padding, unique_name "padding", fi.fpadding_in_bits
 
1850
            in
 
1851
            [this;padding]
 
1852
        in
 
1853
        let fields =
 
1854
          List.fold_right (fun fi acc ->
 
1855
                             let repfi = Retype.FieldUnion.repr fi in
 
1856
                             if FieldinfoComparable.equal fi repfi then
 
1857
                               field fi @ acc
 
1858
                             else acc
 
1859
                          ) compinfo.cfields []
 
1860
        in
 
1861
        let _parent = None in
 
1862
(*        find_or_none (Hashtbl.find Norm.type_to_parent_type) compinfo.cname *)
 
1863
(*      in *)
 
1864
        let ty = TComp(compinfo,[]) in
 
1865
        begin try
 
1866
          let parentty = TypeHashtbl.find Retype.type_to_parent_type ty in
 
1867
          let parent = get_struct_name parentty in
 
1868
          [
 
1869
            JCDtag(compinfo.cname,[],Some (parent,[]),fields,[])
 
1870
          ]
 
1871
        with Not_found ->
 
1872
          try
 
1873
            ignore(TypeHashtbl.find Norm.generated_union_types ty);
 
1874
            [JCDtag(compinfo.cname,[],None,fields,[])]
 
1875
          with Not_found ->
 
1876
            let id = mkidentifier compinfo.cname pos in
 
1877
            [
 
1878
              JCDtag(compinfo.cname,[],None,fields,[]);
 
1879
              JCDvariant_type(compinfo.cname,[id])
 
1880
            ]
 
1881
        end
 
1882
 
 
1883
    | GCompTag(compinfo,pos) -> (* union type *)
 
1884
        assert (not compinfo.cstruct);
 
1885
        let field fi =
 
1886
          let ty = pointed_type fi.ftype in
 
1887
          mkidentifier (get_struct_name ty) pos
 
1888
        in
 
1889
(*        match pointed_type fi.ftype with *)
 
1890
(*          | TComp(compinfo,_) -> *)
 
1891
(*              let field fi = false, ctype fi.ftype, fi.fname in *)
 
1892
(*              let fields = List.map field compinfo.cfields in *)
 
1893
(* (\*          let parent = *\) *)
 
1894
(* (\*            find_or_none (Hashtbl.find Norm.type_to_parent_type) *\) *)
 
1895
(* (\*              compinfo.cname *\) *)
 
1896
(* (\*          in *\) *)
 
1897
(*              mkidentifier fi.fname fi.floc,  *)
 
1898
(*              JCDtag(fi.fname,[],None,fields,[]) *)
 
1899
(*          | _ ->  *)
 
1900
(*              assert false *)
 
1901
(*      in *)
 
1902
        let union_id = mkidentifier compinfo.cname pos in
 
1903
        let union_size = match compinfo.cfields with
 
1904
          | [] -> 0
 
1905
          | fi::_ ->
 
1906
              Pervasives.(+) (the fi.fsize_in_bits) (the fi.fpadding_in_bits)
 
1907
        in
 
1908
        let padding =
 
1909
          if union_size = 0 then [] else
 
1910
            [false, type_of_padding, unique_name "padding", Some union_size]
 
1911
        in
 
1912
        let union_tag = JCDtag(compinfo.cname,[],None,padding,[]) in
 
1913
        let fields = List.map field compinfo.cfields in
 
1914
        let rec has_pointer ty =
 
1915
          match unrollType ty with
 
1916
            | TComp(compinfo,_attr) ->
 
1917
                List.exists (fun fi -> has_pointer fi.ftype) compinfo.cfields
 
1918
            | TPtr _ ->
 
1919
                if is_reference_type ty then 
 
1920
                  (* Possibly skip intermediate array type *)
 
1921
                  has_pointer (pointed_type ty) 
 
1922
                else true
 
1923
            | TVoid _
 
1924
            | TInt _
 
1925
            | TFloat _
 
1926
            | TEnum _ -> false
 
1927
            | TArray _ -> assert false (* Removed by translation *)
 
1928
            | TFun _ ->
 
1929
                Errormsg.s
 
1930
                  (Cil.error "Function pointer type %a not allowed"
 
1931
                     !Ast_printer.d_type ty)
 
1932
            | TNamed _ -> assert false
 
1933
            | TBuiltin_va_list _ -> assert false (* not supported *)
 
1934
        in
 
1935
        (* Union type with pointer as sub-field should be used as a
 
1936
           discriminated union *)
 
1937
        let discr = has_pointer (TComp(compinfo,[])) in
 
1938
        [JCDunion_type(compinfo.cname,discr,union_id :: fields); union_tag]
 
1939
 
 
1940
    | GCompTagDecl _ -> [] (* No struct/union declaration in Jessie *)
 
1941
 
 
1942
    | GEnumTag(enuminfo,_pos) ->
 
1943
        assert (not (enuminfo.eitems = []));
 
1944
        let enums =
 
1945
          List.map
 
1946
            (fun {eival = enum} -> value_of_integral_expr enum) enuminfo.eitems
 
1947
        in
 
1948
        let emin =
 
1949
          List.fold_left (fun acc enum ->
 
1950
                            if acc < enum then acc else enum) (List.hd enums) enums
 
1951
        in
 
1952
        let min = Num.num_of_string (Int64.to_string emin) in
 
1953
        let emax =
 
1954
          List.fold_left (fun acc enum ->
 
1955
                            if acc > enum then acc else enum) (List.hd enums) enums
 
1956
        in
 
1957
        let max = Num.num_of_string (Int64.to_string emax) in
 
1958
        [JCDenum_type(enuminfo.ename,min,max)]
 
1959
 
 
1960
    | GEnumTagDecl _ -> [] (* No enumeration declaration in Jessie *)
 
1961
 
 
1962
    | GVarDecl(_,v,pos) ->
 
1963
        (* Keep only declarations for which there is no definition *)
 
1964
        if List.mem v vardefs
 
1965
          || (isFunctionType v.vtype &&
 
1966
                (v.vname = name_of_assert
 
1967
                    || v.vname = name_of_free
 
1968
                    || v.vname = name_of_malloc))
 
1969
        then []
 
1970
        else if isFunctionType v.vtype then
 
1971
          let rtyp = match unrollType v.vtype with
 
1972
            | TFun(rt,_,_,_) -> rt
 
1973
            | _ -> assert false
 
1974
          in
 
1975
          let id = mkidentifier v.vname pos in
 
1976
          let kf = Globals.Functions.get v in
 
1977
          let funspec = Kernel_function.get_spec kf in
 
1978
          let params = Globals.Functions.get_params kf in
 
1979
          let formal v = ctype v.vtype, unique_name_if_empty v.vname in
 
1980
          let formals = List.map formal params in
 
1981
          [JCDfun(ctype rtyp,id,formals,spec funspec,None)]
 
1982
        else
 
1983
          [JCDvar(ctype v.vtype,v.vname,None)]
 
1984
 
 
1985
    | GVar(v,{init=None},_pos) ->
 
1986
        [JCDvar(ctype v.vtype,v.vname,None)]
 
1987
 
 
1988
    | GVar(_v,_iinfo,_pos) ->
 
1989
        (* Initialization should have been rewritten as code in an
 
1990
         * initialization function, that is called by the main function in
 
1991
         * global analyses and ignored otherwise.
 
1992
         *)
 
1993
        assert false
 
1994
 
 
1995
    | GFun(f,pos) ->
 
1996
        set_curFundec f;
 
1997
        if f.svar.vname = name_of_assert
 
1998
          || f.svar.vname = name_of_free then []
 
1999
        else
 
2000
          let rty = match unrollType f.svar.vtype with
 
2001
            | TFun(ty,_,_,_) -> ty
 
2002
            | _ -> assert false
 
2003
          in
 
2004
          let formal v = ctype v.vtype, v.vname in
 
2005
          let formals = List.map formal f.sformals in
 
2006
          let id = mkidentifier f.svar.vname f.svar.vdecl in
 
2007
          let funspec =
 
2008
            Kernel_function.get_spec (Globals.Functions.get f.svar)
 
2009
          in
 
2010
          begin try
 
2011
            let local v =
 
2012
              mkexpr (JCPEdecl(ctype v.vtype,v.vname,None)) v.vdecl
 
2013
            in
 
2014
            let locals = List.rev (List.rev_map local f.slocals) in
 
2015
            let body = mkexpr (JCPEblock(statement_list f.sbody.bstmts)) pos in
 
2016
            let body = locals @ [body] in
 
2017
            let body = mkexpr (JCPEblock body) pos in
 
2018
            ignore
 
2019
              (reg_pos ~id:f.svar.vname
 
2020
                 ~name:("Function " ^ f.svar.vname) f.svar.vdecl);
 
2021
            [JCDfun(ctype rty,id,formals,spec funspec,Some body)]
 
2022
          with Errormsg.Error ->
 
2023
            Format.printf "Dropping definition of function %s@." f.svar.vname;
 
2024
            [JCDfun(ctype rty,id,formals,spec funspec,None)]
 
2025
          end
 
2026
 
 
2027
    | GAsm _ -> [] (* No assembly in Jessie *)
 
2028
 
 
2029
    | GPragma _ -> [] (* Pragmas treated separately *)
 
2030
 
 
2031
    | GText _ -> [] (* Ignore text in Jessie *)
 
2032
 
 
2033
    | GAnnot(la,_pos) -> annotation la
 
2034
 
 
2035
  in
 
2036
  let pos = get_globalLoc g in
 
2037
  List.map (fun dnode -> mkdecl dnode pos) dnodes
 
2038
 
 
2039
let integral_type name ty bitsize =
 
2040
  let min = Num.num_of_big_int (min_value_of_integral_type ~bitsize ty) in
 
2041
  let max = Num.num_of_big_int (max_value_of_integral_type ~bitsize ty) in
 
2042
  mkdecl (JCDenum_type(name,min,max)) Loc.dummy_position
 
2043
 
 
2044
(* let all_integral_kinds = *)
 
2045
(*   let rec all_ik = function *)
 
2046
(*     | IBool -> IBool :: (all_ik IChar) *)
 
2047
(*     | IChar -> IChar :: (all_ik ISChar) *)
 
2048
(*     | ISChar -> ISChar :: (all_ik IUChar) *)
 
2049
(*     | IUChar -> IUChar :: (all_ik IInt) *)
 
2050
(*     | IInt -> IInt :: (all_ik IUInt) *)
 
2051
(*     | IUInt -> IUInt :: (all_ik IShort) *)
 
2052
(*     | IShort -> IShort :: (all_ik IUShort) *)
 
2053
(*     | IUShort -> IUShort :: (all_ik ILong) *)
 
2054
(*     | ILong -> ILong :: (all_ik IULong) *)
 
2055
(*     | IULong -> IULong :: (all_ik ILongLong) *)
 
2056
(*     | ILongLong -> ILongLong :: (all_ik IULongLong) *)
 
2057
(*     | IULongLong -> IULongLong :: [] *)
 
2058
(*   in *)
 
2059
(*   all_ik IBool *)
 
2060
 
 
2061
let integral_types () =
 
2062
  if Cmdline.Jessie.IntModel.get_val () = Cmdline.Jessie.IMexact then
 
2063
    []
 
2064
  else
 
2065
    Hashtbl.fold
 
2066
      (fun name (ty,bitsize) acc -> integral_type name ty bitsize :: acc)
 
2067
      all_integral_types []
 
2068
 
 
2069
let type_conversions () =
 
2070
  let typconv_axiom ty1 ty1_to_ty2 ty2_to_ty1 =
 
2071
    let x = PExpr.mkvar ~name:"x" () in
 
2072
    let app1 = PExpr.mkapp ~fun_name:ty1_to_ty2 ~args:[x] () in
 
2073
    let app2 = PExpr.mkapp ~fun_name:ty2_to_ty1 ~args:[app1] () in
 
2074
    let eq = PExpr.mkeq ~expr1:x ~expr2:app2 () in
 
2075
    let forall = PExpr.mkforall ~typ:(ctype ty1) ~vars:["x"] ~body:eq () in
 
2076
    PDecl.mklemma_def ~name:(unique_logic_name (ty1_to_ty2 ^ "_axiom")) ~axiom:true
 
2077
      ~body:forall ()
 
2078
  in
 
2079
  Hashtbl.fold
 
2080
    (fun _ (ty1,ty2,ty1_to_ty2,ty2_to_ty1) acc ->
 
2081
       [
 
2082
         PDecl.mklogic_def ~typ:(ctype ty2) ~name:ty1_to_ty2
 
2083
           ~params:[ctype ty1, "x"] ~reads:[] ();
 
2084
         PDecl.mklogic_def ~typ:(ctype ty1) ~name:ty2_to_ty1
 
2085
           ~params:[ctype ty2, "x"] ~reads:[] ();
 
2086
         typconv_axiom ty1 ty1_to_ty2 ty2_to_ty1;
 
2087
         typconv_axiom ty2 ty2_to_ty1 ty1_to_ty2
 
2088
       ] @ acc
 
2089
    ) type_conversion_table []
 
2090
 
 
2091
let file f =
 
2092
  let filter_defined = function GFun _ | GVar _ -> true | _ -> false in
 
2093
  let defined_var =
 
2094
    function GFun(f,_) -> f.svar | GVar(vi,_,_) -> vi | _ -> assert false
 
2095
  in
 
2096
  let globals =
 
2097
(* AVOID CHECKING THE GLOBAL INITIALIZATION FUNCTION, WHICH IS GUARANTEED *)
 
2098
(*     if Globals.has_entry_point () then *)
 
2099
(*       let gif = *)
 
2100
(*      Kernel_function.get_definition (Globals.Functions.get_glob_init f) *)
 
2101
(*       in *)
 
2102
(*       f.globals @ [GFun(gif,Loc.dummy_position)] *)
 
2103
(*     else  *)f.globals
 
2104
  in
 
2105
  let vardefs =
 
2106
    List.rev (List.rev_map defined_var (List.filter filter_defined globals))
 
2107
  in
 
2108
  (* Compute translation of [globals] before [integral_types] so that types 
 
2109
     used are known *)
 
2110
  let globals' = 
 
2111
    List.flatten (List.rev (List.rev_map (global vardefs) globals))
 
2112
  in
 
2113
  mkdecl (JCDaxiomatic("Padding",
 
2114
                       [mkdecl (JCDlogic_type name_of_padding_type)
 
2115
                          Loc.dummy_position]))
 
2116
    Loc.dummy_position
 
2117
  (* Define all integral types as enumerated types in Jessie *)
 
2118
  :: integral_types ()
 
2119
  (* Define conversion functions and identity axiom for back
 
2120
     and forth conversion *)
 
2121
  @ type_conversions ()
 
2122
  @ globals'
 
2123
 
 
2124
(* Translate pragmas separately as their is no declaration for pragmas in
 
2125
 * the parsed AST of Jessie, only in its types AST.
 
2126
 *)
 
2127
let pragma = function
 
2128
  | GPragma(Attr(name,[AStr arg]),_)
 
2129
  | GPragma(Attr(name,[ACons(arg,[])]),_) ->
 
2130
      begin match name with
 
2131
        | "InvariantPolicy" ->
 
2132
            begin match String.lowercase arg with
 
2133
              | "none" -> [Jc_output.JCinvariant_policy Jc_env.InvNone]
 
2134
              | "arguments" ->
 
2135
                  [Jc_output.JCinvariant_policy Jc_env.InvArguments]
 
2136
              | "ownership" ->
 
2137
                  [Jc_output.JCinvariant_policy Jc_env.InvOwnership]
 
2138
              | _ -> assert false
 
2139
            end
 
2140
        | "SeparationPolicy" ->
 
2141
            begin match String.lowercase arg with
 
2142
              | "none" -> [Jc_output.JCseparation_policy Jc_env.SepNone]
 
2143
              | "regions" -> [Jc_output.JCseparation_policy Jc_env.SepRegions]
 
2144
              | _ -> assert false
 
2145
            end
 
2146
        | "AnnotationPolicy" ->
 
2147
            begin match String.lowercase arg with
 
2148
              | "none" -> [Jc_output.JCannotation_policy Jc_env.AnnotNone]
 
2149
              | "invariants" ->
 
2150
                  [Jc_output.JCannotation_policy Jc_env.AnnotInvariants]
 
2151
              | "weakpre" ->
 
2152
                  [Jc_output.JCannotation_policy Jc_env.AnnotWeakPre]
 
2153
              | "strongpre" ->
 
2154
                  [Jc_output.JCannotation_policy Jc_env.AnnotStrongPre]
 
2155
              | _ -> assert false
 
2156
            end
 
2157
        | "AbstractDomain" ->
 
2158
            begin match String.lowercase arg with
 
2159
              | "none" -> [Jc_output.JCabstract_domain Jc_env.AbsNone]
 
2160
              | "box" -> [Jc_output.JCabstract_domain Jc_env.AbsBox]
 
2161
              | "oct" -> [Jc_output.JCabstract_domain Jc_env.AbsOct]
 
2162
              | "pol" -> [Jc_output.JCabstract_domain Jc_env.AbsPol]
 
2163
              | _ -> assert false
 
2164
            end
 
2165
        | "FloatModel" ->
 
2166
            begin match String.lowercase arg with
 
2167
              | "real" -> float_model := `Real
 
2168
              | "strict" -> float_model := `Strict
 
2169
              | "full" -> float_model := `Full
 
2170
              | s ->
 
2171
                  Format.eprintf
 
2172
                    "Warning: pragma %s: identifier %s is not a valid value.\npragma is ignored.@." name s
 
2173
            end; []
 
2174
        | "JessieIntegerModel" ->
 
2175
            begin match String.lowercase arg with
 
2176
              | "exact" | "math" ->
 
2177
                  Cmdline.Jessie.IntModel.set "exact"
 
2178
              | "strict" ->
 
2179
                  Cmdline.Jessie.IntModel.set "strict"
 
2180
              | "modulo" ->
 
2181
                  Cmdline.Jessie.IntModel.set "modulo"
 
2182
              | s ->
 
2183
                  Format.eprintf
 
2184
                    "Warning: pragma %s: identifier %s is not a valid value.\npragma is ignored.@." name s
 
2185
            end;
 
2186
            []
 
2187
        | _ ->
 
2188
            Format.eprintf
 
2189
              "Warning: pragma %s is ignored by Jessie plugin.@." name;
 
2190
            []
 
2191
      end
 
2192
  | GPragma _ -> []
 
2193
  | _ -> []
 
2194
 
 
2195
let pragmas f =
 
2196
  (match Cmdline.Jessie.IntModel.get_val () with
 
2197
    | Cmdline.Jessie.IMexact -> []
 
2198
    | Cmdline.Jessie.IMbounded -> [Jc_output.JCint_model Jc_env.IMbounded]
 
2199
    | Cmdline.Jessie.IMmodulo -> [Jc_output.JCint_model Jc_env.IMmodulo])
 
2200
  @ Jc_output.JCinvariant_policy Jc_env.InvArguments
 
2201
  :: (if Cmdline.Jessie.SepRegions.get () then
 
2202
        Jc_output.JCseparation_policy Jc_env.SepRegions
 
2203
      else
 
2204
        Jc_output.JCseparation_policy Jc_env.SepNone)
 
2205
  :: (match Cmdline.Jessie.InferAnnot.get () with
 
2206
        | "" -> Jc_output.JCannotation_policy Jc_env.AnnotNone
 
2207
        | "inv" -> Jc_output.JCannotation_policy Jc_env.AnnotInvariants
 
2208
        | "pre" -> Jc_output.JCannotation_policy Jc_env.AnnotElimPre
 
2209
        | "spre" -> Jc_output.JCannotation_policy Jc_env.AnnotStrongPre
 
2210
        | "wpre" -> Jc_output.JCannotation_policy Jc_env.AnnotWeakPre
 
2211
        | s ->
 
2212
            Format.eprintf "unknown inference technique %s@." s; assert false)
 
2213
  :: (match Cmdline.Jessie.AbsDomain.get () with
 
2214
        | "box" -> Jc_output.JCabstract_domain Jc_env.AbsBox
 
2215
        | "oct" -> Jc_output.JCabstract_domain Jc_env.AbsOct
 
2216
        | "poly" -> Jc_output.JCabstract_domain Jc_env.AbsPol
 
2217
        | s -> Format.eprintf "unknown abstract domain %s@." s; assert false)
 
2218
  :: List.flatten (List.rev (List.rev_map pragma f.globals))
 
2219
 
 
2220
 
 
2221
(*
 
2222
Local Variables:
 
2223
compile-command: "LC_ALL=C make -C ../.. -j bin/toplevel.byte"
 
2224
End:
 
2225
*)