1
(**************************************************************************)
3
(* Copyright (C) 2001-2003, *)
4
(* George C. Necula <necula@cs.berkeley.edu> *)
5
(* Scott McPeak <smcpeak@cs.berkeley.edu> *)
6
(* Wes Weimer <weimer@cs.berkeley.edu> *)
7
(* Ben Liblit <liblit@cs.berkeley.edu> *)
8
(* All rights reserved. *)
10
(* Redistribution and use in source and binary forms, with or without *)
11
(* modification, are permitted provided that the following conditions *)
14
(* 1. Redistributions of source code must retain the above copyright *)
15
(* notice, this list of conditions and the following disclaimer. *)
17
(* 2. Redistributions in binary form must reproduce the above copyright *)
18
(* notice, this list of conditions and the following disclaimer in the *)
19
(* documentation and/or other materials provided with the distribution. *)
21
(* 3. The names of the contributors may not be used to endorse or *)
22
(* promote products derived from this software without specific prior *)
23
(* written permission. *)
25
(* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *)
26
(* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *)
27
(* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *)
28
(* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *)
29
(* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *)
30
(* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *)
31
(* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; *)
32
(* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *)
33
(* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *)
34
(* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *)
35
(* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *)
36
(* POSSIBILITY OF SUCH DAMAGE. *)
38
(* File modified by CEA (Commissariat ļæ½ l'ļæ½nergie Atomique). *)
39
(**************************************************************************)
42
* CIL: An intermediate language for analyzing C progams.
44
* Version Tue Dec 12 15:21:52 PST 2000
45
* Scott McPeak, George Necula, Wes Weimer
54
open Trace (* sm: 'trace' function *)
60
(* ************************************************************************* *)
61
(* Reporting messages *)
62
(* ************************************************************************* *)
64
(* A reference to the current location *)
65
module CurrentLoc = Logic_env.CurrentLoc
67
(* Some error reporting functions *)
69
fprintf fmt "%s:%d" (fst loc).Lexing.pos_fname (fst loc).Lexing.pos_lnum
70
(* fprintf fmt "File %S, line %d, characters %d-%d"
71
(fst loc).Lexing.pos_fname (fst loc).Lexing.pos_lnum
72
((fst loc).Lexing.pos_cnum - (fst loc).Lexing.pos_bol)
73
((snd loc).Lexing.pos_cnum - (fst loc).Lexing.pos_bol)
75
let rec fprintfList ~sep (f:formatter -> 'a -> unit) fmt l =
79
| x::r -> fprintf fmt ("%a" ^^ sep ^^ "%a") f x (fprintfList ~sep f) r
81
(*Ok for ocaml >= 3.09.3 : fprintf fmt "%a%(%)%a" f x sep (fprintfList ~sep f) r *)
83
let d_thisloc (fmt: formatter) : unit = d_loc fmt (CurrentLoc.get ())
85
let generic_report_error msg fmt =
88
fprintf fmt (fstring ^^ "@]@.")
90
kfprintf f fmt "@[%t: %s: " d_thisloc msg
92
let error_loc (file,line,start_byte,stop_byte) msg =
94
fprintf fmt (fstring ^^ "@]@.")
96
kfprintf f err_formatter "@[File %S, line %d, characters %d-%d: " file line start_byte stop_byte msg
98
let error fstring = generic_report_error "Error" err_formatter fstring
100
let unimp fstring = generic_report_error "Unimplemented" err_formatter fstring
102
let generic_bug s fstring =
105
kfprintf (fun _ -> E.showContext (); raise E.Error) fmt (fstring ^^ "@]@.")
107
kfprintf f err_formatter "@[%t: %s: " d_thisloc s
109
let bug fstring = generic_bug "Bug" fstring
110
let fatal_error fstring = generic_bug "Fatal error" fstring
111
let fatal_unimp fstring = generic_bug "Fatal unimplemented" fstring
113
let errorLoc loc fstring =
116
kfprintf (fun _ -> E.showContext ()) fmt (fstring ^^ "@]@.")
118
kfprintf f err_formatter "@[%a: Error: " d_loc loc
120
let do_not_fprintf fstring =
121
kfprintf (fun _ -> ()) (Format.make_formatter (fun _ _ _ -> ()) (fun _ -> ())) fstring
123
let fprintf_to_string fstring =
124
let b = Buffer.create 17 in
125
let fmt = formatter_of_buffer b in
126
kfprintf (fun fmt -> pp_print_flush fmt ();
127
Buffer.contents b) fmt fstring
129
let warn fstring = Messages_manager.emit (CurrentLoc.get ()) `Warning fstring
131
let warnOpt fstring =
135
do_not_fprintf fstring
137
let warnContext fstring =
139
kfprintf (fun _ -> E.showContext ()) fmt (fstring ^^ "@]@.")
141
kfprintf f err_formatter "@[%t: Warning: " d_thisloc
143
let warnContextOpt fstring =
147
do_not_fprintf fstring
149
let warnLoc loc fstring = Messages_manager.emit loc `Warning fstring
151
let logLoc loc fstring = Messages_manager.emit loc `Info fstring
153
(*let log fstring = Messages_manager.emit (CurrentLoc.get()) `Info fstring*)
154
let log fstring = Format.eprintf ("@[" ^^ fstring ^^ "@]@.")
156
(* ************************************************************************* *)
157
(* ************************************************************************* *)
158
(* ************************************************************************* *)
160
let print_utf8 = ref true
163
pp_set_margin err_formatter max_int
165
(* The module Cilversion is generated automatically by Makefile from
166
* information in configure.in *)
167
let cilVersion = Cilversion.cilVersion
168
let cilVersionMajor = Cilversion.cilVersionMajor
169
let cilVersionMinor = Cilversion.cilVersionMinor
170
let cilVersionRevision = Cilversion.cilVersionRev
172
module Build_BoolRef(X:sig val default:bool val name:string end) =
174
(struct include Datatype.Bool let default = X.default end)
176
let name = Project.Computation.Name.make X.name
177
let dependencies = []
185
let voidType = TVoid([])
186
let intType = TInt(IInt,[])
187
let uintType = TInt(IUInt,[])
188
let longType = TInt(ILong,[])
189
let ulongType = TInt(IULong,[])
190
let charType = TInt(IChar, [])
192
let charPtrType = TPtr(charType,[])
193
let charConstPtrType = TPtr(TInt(IChar, [Attr("const", [])]),[])
195
let voidPtrType = TPtr(voidType, [])
196
let intPtrType = TPtr(intType, [])
197
let uintPtrType = TPtr(uintType, [])
199
let doubleType = TFloat(FDouble, [])
202
{ mutable msvcMode: bool; (** Whether the pretty printer should
203
print output for the MS VC
204
compiler. Default is GCC *)
205
mutable useLogicalOperators: bool;
206
mutable theMachine: mach;
207
(** Cil.initCil will set this to the current machine description. *)
208
mutable lowerConstants: bool; (** Do lower constants (default true) *)
209
mutable insertImplicitCasts: bool; (** Do insert implicit casts
211
mutable little_endian: bool;
212
mutable char_is_unsigned: bool;
213
mutable underscore_name: bool;
214
mutable enum_are_signed: bool;
215
mutable stringLiteralType: typ;
216
mutable upointType: typ;
217
mutable wcharKind: ikind; (** An integer type that fits wchar_t. *)
218
mutable wcharType: typ;
219
mutable ptrdiffKind: ikind; (** An integer type that fits ptrdiff_t. *)
220
mutable ptrdiffType: typ;
221
mutable typeOfSizeOf: typ; (** An integer type that is the type of
223
mutable kindOfSizeOf: ikind }
225
type lineDirectiveStyle =
226
| LineComment (** Before every element, print the line
227
* number in comments. This is ignored by
228
* processing tools (thus errors are reproted
229
* in the CIL output), but useful for
230
* visual inspection *)
231
| LineCommentSparse (** Like LineComment but only print a line
232
* directive for a new source line *)
233
| LinePreprocessorInput (** Use #line directives *)
234
| LinePreprocessorOutput (** Use # nnn directives (in gcc mode) *)
237
{ mutable lineDirectiveStyle: lineDirectiveStyle option;
238
mutable print_CIL_Input: bool;
239
mutable printCilAsIs: bool;
240
mutable lineLength: int;
241
mutable warnTruncate: bool }
243
let createMachine () =
245
useLogicalOperators = false;
246
theMachine = Machdep.state.Machdep.gcc;
247
lowerConstants = false(*true*);
248
insertImplicitCasts = true;
249
little_endian = true;
250
char_is_unsigned = false;
251
underscore_name = true;
252
enum_are_signed = true;
253
stringLiteralType = charPtrType;
254
upointType = voidType;
256
wcharType = voidType;
258
ptrdiffType = voidType;
259
typeOfSizeOf = voidType;
260
kindOfSizeOf = IUInt }
262
let copyMachine src dst =
263
dst.msvcMode <- src.msvcMode;
264
dst.useLogicalOperators <- src.useLogicalOperators;
265
dst.theMachine <- src.theMachine;
266
dst.lowerConstants <- src.lowerConstants;
267
dst.insertImplicitCasts <- src.insertImplicitCasts;
268
dst.little_endian <- src.little_endian;
269
dst.char_is_unsigned <- src.char_is_unsigned;
270
dst.underscore_name <- src.underscore_name;
271
dst.enum_are_signed <- src.enum_are_signed;
272
dst.stringLiteralType <- src.stringLiteralType;
273
dst.upointType <- src.upointType;
274
dst.wcharKind <- src.wcharKind;
275
dst.wcharType <- src.wcharType;
276
dst.ptrdiffKind <- src.ptrdiffKind;
277
dst.ptrdiffType <- src.ptrdiffType;
278
dst.typeOfSizeOf <- src.typeOfSizeOf;
279
dst.kindOfSizeOf <- src.kindOfSizeOf
281
(* A few globals that control the interpretation of C source *)
282
let theMachine = createMachine ()
284
let theMachineProject = ref (createMachine ())
286
Project.Computation.Register
287
(Project.Datatype.Imperative
291
let m = createMachine () in
294
let name = "theMachine"
298
let create = createMachine
299
let get () = !theMachineProject
301
theMachineProject := m;
302
copyMachine !theMachineProject theMachine
303
let clear m = copyMachine (createMachine ()) m
306
let name = "theMachine"
307
let dependencies = []
310
Project.Selection.iter
311
(fun k _ -> Project.Computation.add_dependency k TheMachine.self)
312
Logic_env.builtin_states
314
let selfMachine = TheMachine.self
316
let set_msvcMode b = theMachine.msvcMode <- b
319
{ lineDirectiveStyle = Some LinePreprocessorInput;
320
print_CIL_Input = false;
321
printCilAsIs = false;
323
warnTruncate = true }
325
(* sm: return the string 's' if we're printing output for gcc, suppres
326
* it if we're printing for CIL to parse back in. the purpose is to
327
* hide things from gcc that it complains about, but still be able
328
* to do lossless transformations when CIL is the consumer *)
329
let forgcc (s: string) : string = if miscState.print_CIL_Input then "" else s
332
let debugConstFold = false
334
module Build_Counter(Name:sig val name:string end) : sig
335
val next: unit -> int
336
val reset: unit -> unit
339
include Computation.Ref
340
(struct include Datatype.Int let default () = 0 end)
342
let dependencies = []
348
bug "Too many values for counter %s. Please report.@." Name.name;
354
module Sid = Build_Counter(struct let name = "sid" end)
356
(** The Abstract Syntax of CIL *)
358
(** To be able to add/remove features easily, each feature should be packaged
359
* as an interface with the following interface. These features should be *)
360
type featureDescr = {
361
fd_enabled: bool ref;
362
(** The enable flag. Set to default value *)
365
(** This is used to construct an option "--doxxx" and "--dontxxx" that
366
* enable and disable the feature *)
368
fd_description: string;
369
(* A longer name that can be used to document the new options *)
371
fd_extraopt: (string * Arg.spec * string) list;
372
(** Additional command line options. The description strings should
373
usually start with a space for Arg.align to print the --help nicely. *)
375
fd_doit: (file -> unit);
376
(** This performs the transformation *)
379
(* Whether to perform a CIL consistency checking after this stage, if
380
* checking is enabled (--check is passed to cilly) *)
383
(* A reference to the current global being visited *)
384
let currentGlobal: global ref = ref (GText "dummy")
387
let compareLoc (a: location) (b: location) : int = Pervasives.compare a b
388
(* let namecmp = compare a.file b.file in *)
389
(* if namecmp != 0 *)
392
(* let linecmp = a.line - b.line in *)
393
(* if linecmp != 0 *)
395
(* else a.byte - b.byte *)
397
let argsToList : (string * typ * attributes) list option
398
-> (string * typ * attributes) list
404
(* A hack to allow forward reference of d_exp *)
405
let pd_exp : (formatter -> exp -> unit) ref =
406
ref (fun _ -> E.s (E.bug "pd_exp not initialized"))
407
let pd_global : (formatter -> global -> unit) ref =
408
ref (fun _ -> E.s (E.bug "pd_global not initialized"))
411
ref (fun _ _ -> E.s (E.bug "d_annotation not initialized"))
412
let d_code_annotation =
413
ref (fun _ _ -> E.s (E.bug "d_code_annotation not initialized"))
414
let d_loop_annotation =
415
ref (fun _ _ -> E.s (E.bug "d_loop_annotation not initialized"))
417
ref (fun _ _ -> E.s (E.bug "d_funspec not initialized"))
420
(** Different visiting actions. 'a will be instantiated with [exp], [instr],
422
type 'a visitAction =
423
SkipChildren (** Do not visit the children. Return
424
the node as it is. *)
425
| DoChildren (** Continue with the children of this
426
node. Rebuild the node on return
427
if any of the children changes
429
| ChangeTo of 'a (** Replace the expression with the
431
| ChangeToPost of 'a * ('a -> 'a)
433
| ChangeDoChildrenPost of 'a * ('a -> 'a) (** First consider that the entire
434
exp is replaced by the first
435
parameter. Then continue with
436
the children. On return rebuild
437
the node if any of the children
438
has changed and then apply the
439
function on the node *)
441
type visitor_behavior =
443
(* copy mutable structure which are not shared across the AST*)
445
cinitinfo: initinfo -> initinfo;
446
cfundec: fundec -> fundec;
447
cblock: block -> block;
448
cfunspec: funspec -> funspec;
449
cfunbehavior: funbehavior -> funbehavior;
450
(* get the copy of a shared value *)
451
get_stmt: stmt -> stmt;
452
get_compinfo: compinfo -> compinfo;
453
get_fieldinfo: fieldinfo -> fieldinfo;
454
get_enuminfo: enuminfo -> enuminfo;
455
get_enumitem: enumitem -> enumitem;
456
get_typeinfo: typeinfo -> typeinfo;
457
get_varinfo: varinfo -> varinfo;
458
get_logic_info: logic_info -> logic_info;
460
get_predicate_info: predicate_info -> predicate_info;
462
get_logic_var: logic_var -> logic_var;
463
(* get the original value tied to a copy *)
464
get_original_stmt: stmt -> stmt;
465
get_original_compinfo: compinfo -> compinfo;
466
get_original_fieldinfo: fieldinfo -> fieldinfo;
467
get_original_enuminfo: enuminfo -> enuminfo;
468
get_original_enumitem: enumitem -> enumitem;
469
get_original_typeinfo: typeinfo -> typeinfo;
470
get_original_varinfo: varinfo -> varinfo;
471
get_original_logic_info: logic_info -> logic_info;
473
get_original_predicate_info: predicate_info -> predicate_info;
475
get_original_logic_var: logic_var -> logic_var;
476
(* change a binding... use with care *)
477
set_stmt: stmt -> stmt -> unit;
478
set_compinfo: compinfo -> compinfo -> unit;
479
set_fieldinfo: fieldinfo -> fieldinfo -> unit;
480
set_enuminfo: enuminfo -> enuminfo -> unit;
481
set_enumitem: enumitem -> enumitem -> unit;
482
set_typeinfo: typeinfo -> typeinfo -> unit;
483
set_varinfo: varinfo -> varinfo -> unit;
484
set_logic_info: logic_info -> logic_info -> unit;
486
set_predicate_info: predicate_info -> predicate_info -> unit;
488
set_logic_var: logic_var -> logic_var -> unit;
489
(* change a reference... use with care *)
490
set_orig_stmt: stmt -> stmt -> unit;
491
set_orig_compinfo: compinfo -> compinfo -> unit;
492
set_orig_fieldinfo: fieldinfo -> fieldinfo -> unit;
493
set_orig_enuminfo: enuminfo -> enuminfo -> unit;
494
set_orig_enumitem: enumitem -> enumitem -> unit;
495
set_orig_typeinfo: typeinfo -> typeinfo -> unit;
496
set_orig_varinfo: varinfo -> varinfo -> unit;
497
set_orig_logic_info: logic_info -> logic_info -> unit;
499
set_orig_predicate_info: predicate_info -> predicate_info -> unit;
501
set_orig_logic_var: logic_var -> logic_var -> unit;
502
(* copy fields that can referenced in other places of the AST*)
503
memo_stmt: stmt -> stmt;
504
memo_varinfo: varinfo -> varinfo;
505
memo_compinfo: compinfo -> compinfo;
506
memo_enuminfo: enuminfo -> enuminfo;
507
memo_enumitem: enumitem -> enumitem;
508
memo_typeinfo: typeinfo -> typeinfo;
509
memo_logic_info: logic_info -> logic_info;
511
memo_predicate_info: predicate_info -> predicate_info;
513
memo_fieldinfo: fieldinfo -> fieldinfo;
514
memo_logic_var: logic_var -> logic_var;
515
(* is the behavior a copy behavior *)
516
is_copy_behavior: bool;
517
(* reset memoizing tables *)
518
reset_behavior_varinfo: unit -> unit;
519
reset_behavior_compinfo: unit -> unit;
520
reset_behavior_enuminfo: unit -> unit;
521
reset_behavior_enumitem: unit -> unit;
522
reset_behavior_typeinfo: unit -> unit;
523
reset_behavior_logic_info: unit -> unit;
525
reset_behavior_predicate_info: unit -> unit;
527
reset_behavior_fieldinfo: unit -> unit;
528
reset_behavior_stmt: unit -> unit;
529
reset_logic_var: unit -> unit;
532
let is_copy_behavior b = b.is_copy_behavior
534
let reset_behavior_varinfo b = b.reset_behavior_varinfo ()
535
let reset_behavior_compinfo b = b.reset_behavior_compinfo ()
536
let reset_behavior_enuminfo b = b.reset_behavior_enuminfo ()
537
let reset_behavior_enumitem b = b.reset_behavior_enumitem ()
538
let reset_behavior_typeinfo b = b.reset_behavior_typeinfo ()
539
let reset_behavior_logic_info b = b.reset_behavior_logic_info ()
541
let reset_behavior_predicate_info b = b.reset_behavior_predicate_info ()
543
let reset_behavior_fieldinfo b = b.reset_behavior_fieldinfo ()
544
let reset_behavior_stmt b = b.reset_behavior_stmt ()
545
let reset_logic_var b = b.reset_logic_var ()
547
let get_varinfo b = b.get_varinfo
548
let get_compinfo b = b.get_compinfo
549
let get_fieldinfo b = b.get_fieldinfo
550
let get_enuminfo b = b.get_enuminfo
551
let get_enumitem b = b.get_enumitem
552
let get_stmt b = b.get_stmt
553
let get_typeinfo b = b.get_typeinfo
554
let get_logic_info b = b.get_logic_info
556
let get_predicate_info b = b.get_predicate_info
558
let get_logic_var b = b.get_logic_var
560
let get_original_varinfo b = b.get_original_varinfo
561
let get_original_compinfo b = b.get_original_compinfo
562
let get_original_fieldinfo b = b.get_original_fieldinfo
563
let get_original_enuminfo b = b.get_original_enuminfo
564
let get_original_enumitem b = b.get_original_enumitem
565
let get_original_stmt b = b.get_original_stmt
566
let get_original_typeinfo b = b.get_original_typeinfo
567
let get_original_logic_info b = b.get_original_logic_info
569
let get_original_predicate_info b = b.get_original_predicate_info
571
let get_original_logic_var b = b.get_original_logic_var
573
let set_varinfo b = b.set_varinfo
574
let set_compinfo b = b.set_compinfo
575
let set_fieldinfo b = b.set_fieldinfo
576
let set_enuminfo b = b.set_enuminfo
577
let set_enumitem b = b.set_enumitem
578
let set_stmt b = b.set_stmt
579
let set_typeinfo b = b.set_typeinfo
580
let set_logic_info b = b.set_logic_info
582
let set_predicate_info b = b.set_predicate_info
584
let set_logic_var b = b.set_logic_var
586
let set_orig_varinfo b = b.set_orig_varinfo
587
let set_orig_compinfo b = b.set_orig_compinfo
588
let set_orig_fieldinfo b = b.set_orig_fieldinfo
589
let set_orig_enuminfo b = b.set_orig_enuminfo
590
let set_orig_enumitem b = b.set_orig_enumitem
591
let set_orig_stmt b = b.set_orig_stmt
592
let set_orig_typeinfo b = b.set_orig_typeinfo
593
let set_orig_logic_info b = b.set_orig_logic_info
595
let set_orig_predicate_info b = b.set_orig_predicate_info
597
let set_orig_logic_var b = b.set_orig_logic_var
599
let inplace_visit () =
600
{ cfile = (fun x -> x);
601
get_compinfo = (fun x -> x);
602
get_fieldinfo = (fun x -> x);
603
get_enuminfo = (fun x -> x);
604
get_enumitem = (fun x -> x);
605
get_typeinfo = (fun x -> x);
606
get_varinfo = (fun x -> x);
607
get_logic_var = (fun x -> x);
608
get_stmt = (fun x -> x);
609
get_logic_info = (fun x -> x);
611
get_predicate_info = (fun x -> x);
613
get_original_compinfo = (fun x -> x);
614
get_original_fieldinfo = (fun x -> x);
615
get_original_enuminfo = (fun x -> x);
616
get_original_enumitem = (fun x -> x);
617
get_original_typeinfo = (fun x -> x);
618
get_original_varinfo = (fun x -> x);
619
get_original_logic_var = (fun x -> x);
620
get_original_stmt = (fun x -> x);
621
get_original_logic_info = (fun x -> x);
623
get_original_predicate_info = (fun x -> x);
625
cinitinfo = (fun x -> x);
626
cfundec = (fun x -> x);
627
cblock = (fun x -> x);
628
cfunspec = (fun x -> x);
629
cfunbehavior = (fun x -> x);
630
is_copy_behavior = false;
631
memo_varinfo = (fun x -> x);
632
memo_compinfo = (fun x -> x);
633
memo_enuminfo = (fun x -> x);
634
memo_enumitem = (fun x -> x);
635
memo_typeinfo = (fun x -> x);
636
memo_logic_info = (fun x -> x);
638
memo_predicate_info = (fun x -> x);
640
memo_stmt = (fun x -> x);
641
memo_fieldinfo = (fun x -> x);
642
memo_logic_var = (fun x -> x);
643
set_varinfo = (fun _ _ -> ());
644
set_compinfo = (fun _ _ -> ());
645
set_enuminfo = (fun _ _ -> ());
646
set_enumitem = (fun _ _ -> ());
647
set_typeinfo = (fun _ _ -> ());
648
set_logic_info = (fun _ _ -> ());
650
set_predicate_info = (fun _ _ -> ());
652
set_stmt = (fun _ _ -> ());
653
set_fieldinfo = (fun _ _ -> ());
654
set_logic_var = (fun _ _ -> ());
655
set_orig_varinfo = (fun _ _ -> ());
656
set_orig_compinfo = (fun _ _ -> ());
657
set_orig_enuminfo = (fun _ _ -> ());
658
set_orig_enumitem = (fun _ _ -> ());
659
set_orig_typeinfo = (fun _ _ -> ());
660
set_orig_logic_info = (fun _ _ -> ());
662
set_orig_predicate_info = (fun _ _ -> ());
664
set_orig_stmt = (fun _ _ -> ());
665
set_orig_fieldinfo = (fun _ _ -> ());
666
set_orig_logic_var = (fun _ _ -> ());
667
reset_behavior_varinfo = (fun () -> ());
668
reset_behavior_compinfo = (fun () -> ());
669
reset_behavior_enuminfo = (fun () -> ());
670
reset_behavior_enumitem = (fun () -> ());
671
reset_behavior_typeinfo = (fun () -> ());
672
reset_behavior_logic_info = (fun () -> ());
674
reset_behavior_predicate_info = (fun () -> ());
676
reset_behavior_fieldinfo = (fun () -> ());
677
reset_behavior_stmt = (fun () -> ());
678
reset_logic_var = (fun () -> ());
682
let varinfos = Inthash.create 103 in
683
let compinfos = Inthash.create 17 in
684
let enuminfos = Hashtbl.create 17 in
685
let enumitems = Hashtbl.create 17 in
686
let typeinfos = Hashtbl.create 17 in
687
let logic_infos = Hashtbl.create 17 in
689
let predicate_infos = Hashtbl.create 17 in
691
let fieldinfos = Hashtbl.create 17 in
692
let stmts = Inthash.create 103 in
693
let logic_vars = Inthash.create 17 in
694
let orig_varinfos = Inthash.create 103 in
695
let orig_compinfos = Inthash.create 17 in
696
let orig_enuminfos = Hashtbl.create 17 in
697
let orig_enumitems = Hashtbl.create 17 in
698
let orig_typeinfos = Hashtbl.create 17 in
699
let orig_logic_infos = Hashtbl.create 17 in
701
let orig_predicate_infos = Hashtbl.create 17 in
703
let orig_fieldinfos = Hashtbl.create 17 in
704
let orig_stmts = Inthash.create 103 in
705
let orig_logic_vars = Inthash.create 17 in
706
{ cfile = (fun x -> { x with fileName = x.fileName });
708
(fun x -> try Inthash.find compinfos x.ckey with Not_found -> x);
710
(fun x -> try Hashtbl.find fieldinfos (x.fname,x.fcomp.ckey)
711
with Not_found -> x);
713
(fun x -> try Hashtbl.find enuminfos x.ename with Not_found -> x);
715
(fun x -> try Hashtbl.find enumitems x.einame with Not_found -> x);
717
(fun x -> try Hashtbl.find typeinfos x.tname with Not_found -> x);
719
(fun x -> try Inthash.find varinfos x.vid with Not_found -> x);
720
get_stmt = (fun x -> try Inthash.find stmts x.sid with Not_found -> x);
722
(fun x -> try Hashtbl.find logic_infos x.l_name with Not_found -> x);
725
(fun x -> try Hashtbl.find predicate_infos x.p_name with Not_found -> x);
727
get_logic_var = (fun x -> try Inthash.find logic_vars x.lv_id
728
with Not_found -> x);
729
get_original_compinfo =
730
(fun x -> try Inthash.find orig_compinfos x.ckey with Not_found -> x);
731
get_original_fieldinfo =
732
(fun x -> try Hashtbl.find orig_fieldinfos (x.fname,x.fcomp.ckey)
733
with Not_found -> x);
734
get_original_enuminfo =
735
(fun x -> try Hashtbl.find orig_enuminfos x.ename with Not_found -> x);
736
get_original_enumitem =
737
(fun x -> try Hashtbl.find orig_enumitems x.einame with Not_found -> x);
738
get_original_typeinfo =
739
(fun x -> try Hashtbl.find orig_typeinfos x.tname with Not_found -> x);
740
get_original_varinfo =
741
(fun x -> try Inthash.find orig_varinfos x.vid with Not_found -> x);
743
(fun x -> try Inthash.find orig_stmts x.sid with Not_found -> x);
744
get_original_logic_var =
745
(fun x -> try Inthash.find orig_logic_vars x.lv_id with Not_found -> x);
746
get_original_logic_info =
747
(fun x -> try Hashtbl.find orig_logic_infos x.l_name with Not_found -> x);
749
get_original_predicate_info =
751
try Hashtbl.find orig_predicate_infos x.p_name with Not_found -> x);
753
cinitinfo = (fun x -> { init = x.init });
754
cfundec = ( fun x -> { x with svar = x.svar });
755
cblock = (fun x -> { x with battrs = x.battrs });
756
cfunspec = (fun x -> { x with spec_requires = x.spec_requires});
757
cfunbehavior = (fun x -> { x with b_name = x.b_name});
758
is_copy_behavior = true;
759
reset_behavior_varinfo =
760
(fun () -> Inthash.clear varinfos; Inthash.clear orig_varinfos);
761
reset_behavior_compinfo =
762
(fun () -> Inthash.clear compinfos; Inthash.clear orig_compinfos);
763
reset_behavior_enuminfo =
764
(fun () -> Hashtbl.clear enuminfos; Hashtbl.clear orig_enuminfos);
765
reset_behavior_enumitem =
766
(fun () -> Hashtbl.clear enumitems; Hashtbl.clear orig_enumitems);
767
reset_behavior_typeinfo =
768
(fun () -> Hashtbl.clear typeinfos; Hashtbl.clear orig_typeinfos);
769
reset_behavior_logic_info =
770
(fun () -> Hashtbl.clear logic_infos; Hashtbl.clear orig_logic_infos);
772
reset_behavior_predicate_info =
774
Hashtbl.clear predicate_infos; Hashtbl.clear orig_predicate_infos);
776
reset_behavior_fieldinfo =
777
(fun () ->Hashtbl.clear fieldinfos; Hashtbl.clear orig_fieldinfos);
778
reset_behavior_stmt =
779
(fun () -> Inthash.clear stmts; Inthash.clear orig_stmts);
781
(fun () -> Inthash.clear logic_vars; Inthash.clear orig_logic_vars);
784
try Inthash.find varinfos x.vid
786
let new_x = { x with vid = x.vid } in
787
Inthash.add varinfos x.vid new_x;
788
Inthash.add orig_varinfos new_x.vid x;
792
try Inthash.find compinfos x.ckey
794
let new_x = { x with ckey = x.ckey } in
795
Inthash.add compinfos x.ckey new_x;
796
Inthash.add orig_compinfos new_x.ckey x;
800
try Hashtbl.find enuminfos x.ename
802
let new_x = { x with ename = x.ename } in
803
Hashtbl.add enuminfos x.ename new_x;
804
Hashtbl.add orig_enuminfos new_x.ename x;
808
try Hashtbl.find enumitems x.einame
810
let new_x = { x with einame = x.einame } in
811
Hashtbl.add enumitems x.einame new_x;
812
Hashtbl.add orig_enumitems new_x.einame x;
816
try Hashtbl.find typeinfos x.tname
818
let new_x = { x with tname = x.tname } in
819
Hashtbl.add typeinfos x.tname new_x;
820
Hashtbl.add orig_typeinfos new_x.tname x;
824
try Hashtbl.find logic_infos x.l_name
826
let new_x = { x with l_name = x.l_name } in
827
Hashtbl.add logic_infos x.l_name new_x; new_x);
829
memo_predicate_info =
831
try Hashtbl.find predicate_infos x.p_name
833
let new_x = { x with p_name = x.p_name } in
834
Hashtbl.add predicate_infos x.p_name new_x;
835
Hashtbl.add orig_predicate_infos new_x.p_name x;
840
try Inthash.find stmts x.sid
842
let new_x = { x with sid = x.sid } in
843
Inthash.add stmts x.sid new_x;
844
Inthash.add orig_stmts new_x.sid x;
848
try Hashtbl.find fieldinfos (x.fname,x.fcomp.ckey)
850
let new_x = { x with fname = x.fname } in
851
Hashtbl.add fieldinfos (x.fname, x.fcomp.ckey) new_x;
852
Hashtbl.add orig_fieldinfos (new_x.fname, new_x.fcomp.ckey) x;
856
try Inthash.find logic_vars x.lv_id
858
let new_x = { x with lv_id = x.lv_id } in
859
Inthash.add logic_vars x.lv_id new_x;
860
Inthash.add orig_logic_vars new_x.lv_id x;
862
set_varinfo = (fun x y -> Inthash.replace varinfos x.vid y);
863
set_compinfo = (fun x y -> Inthash.replace compinfos x.ckey y);
864
set_enuminfo = (fun x y -> Hashtbl.replace enuminfos x.ename y);
865
set_enumitem = (fun x y -> Hashtbl.replace enumitems x.einame y);
866
set_typeinfo = (fun x y -> Hashtbl.replace typeinfos x.tname y);
867
set_logic_info = (fun x y -> Hashtbl.replace logic_infos x.l_name y);
869
set_predicate_info = (fun x y ->Hashtbl.replace predicate_infos x.p_name y);
871
set_stmt = (fun x y -> Inthash.replace stmts x.sid y);
873
(fun x y -> Hashtbl.replace fieldinfos (x.fname,x.fcomp.ckey) y);
874
set_logic_var = (fun x y -> Inthash.replace logic_vars x.lv_id y);
875
set_orig_varinfo = (fun x y -> Inthash.replace orig_varinfos x.vid y);
876
set_orig_compinfo = (fun x y -> Inthash.replace orig_compinfos x.ckey y);
877
set_orig_enuminfo = (fun x y -> Hashtbl.replace orig_enuminfos x.ename y);
878
set_orig_enumitem = (fun x y -> Hashtbl.replace orig_enumitems x.einame y);
879
set_orig_typeinfo = (fun x y -> Hashtbl.replace orig_typeinfos x.tname y);
880
set_orig_logic_info =
881
(fun x y -> Hashtbl.replace orig_logic_infos x.l_name y);
883
set_orig_predicate_info =
884
(fun x y -> Hashtbl.replace orig_predicate_infos x.p_name y);
886
set_orig_stmt = (fun x y -> Inthash.replace orig_stmts x.sid y);
888
(fun x y -> Hashtbl.replace orig_fieldinfos (x.fname,x.fcomp.ckey) y);
889
set_orig_logic_var = (fun x y -> Inthash.replace orig_logic_vars x.lv_id y);
892
(* sm/gn: cil visitor interface for traversing Cil trees. *)
893
(* Use visitCilStmt and/or visitCilFile to use this. *)
894
(* Some of the nodes are changed in place if the children are changed. Use
895
* one of Change... actions if you want to copy the node *)
897
(** A visitor interface for traversing CIL trees. Create instantiations of
898
* this type by specializing the class {!Cil.nopCilVisitor}. *)
899
class type cilVisitor = object
901
method behavior: visitor_behavior
903
method vfile: file -> file visitAction
906
method vvdec: varinfo -> varinfo visitAction
907
(** Invoked for each variable declaration. The subtrees to be traversed
908
* are those corresponding to the type and attributes of the variable.
909
* Note that variable declarations are all the [GVar], [GVarDecl], [GFun],
910
* all the [varinfo] in formals of function types, and the formals and
911
* locals for function definitions. This means that the list of formals
912
* in a function definition will be traversed twice, once as part of the
913
* function type and second as part of the formals in a function
916
method vvrbl: varinfo -> varinfo visitAction
917
(** Invoked on each variable use. Here only the [SkipChildren] and
918
* [ChangeTo] actions make sense since there are no subtrees. Note that
919
* the type and attributes of the variable are not traversed for a
922
method vexpr: exp -> exp visitAction
923
(** Invoked on each expression occurence. The subtrees are the
924
* subexpressions, the types (for a [Cast] or [SizeOf] expression) or the
927
method vlval: lval -> lval visitAction
928
(** Invoked on each lvalue occurence *)
930
method voffs: offset -> offset visitAction
931
(** Invoked on each offset occurrence that is *not* as part
932
* of an initializer list specification, i.e. in an lval or
933
* recursively inside an offset. *)
935
method vinitoffs: offset -> offset visitAction
936
(** Invoked on each offset appearing in the list of a
937
* CompoundInit initializer. *)
939
method vinst: instr -> instr list visitAction
940
(** Invoked on each instruction occurrence. The [ChangeTo] action can
941
* replace this instruction with a list of instructions *)
943
method vstmt: stmt -> stmt visitAction
944
(** Control-flow statement. *)
946
method vblock: block -> block visitAction (** Block. Replaced in
948
method vfunc: fundec -> fundec visitAction (** Function definition.
949
Replaced in place. *)
950
method vglob: global -> global list visitAction (** Global (vars, types,
952
method vinit: varinfo -> offset -> init -> init visitAction
953
(** Initializers for globals,
954
* pass the global where this
955
* occurs, and the offset *)
956
method vtype: typ -> typ visitAction (** Use of some type. Note
957
* that for structure/union
958
* and enumeration types the
960
* composite type is not
961
* visited. Use [vglob] to
964
method vcompinfo: compinfo -> compinfo visitAction
966
method venuminfo: enuminfo -> enuminfo visitAction
968
method vfieldinfo: fieldinfo -> fieldinfo visitAction
970
method venumitem: enumitem -> enumitem visitAction
972
method vattr: attribute -> attribute list visitAction
973
(** Attribute. Each attribute can be replaced by a list *)
974
method vattrparam: attrparam -> attrparam visitAction
975
(** Attribute parameters. *)
977
(** Add here instructions while visiting to queue them to
978
* preceede the current statement or instruction being processed *)
979
method queueInstr: instr list -> unit
981
(** Gets the queue of instructions and resets the queue *)
982
method unqueueInstr: unit -> instr list
984
val current_stmt : stmt Stack.t
985
method push_stmt: stmt -> unit
986
method pop_stmt: stmt -> unit
987
method current_stmt: stmt option
989
method current_func: fundec option
990
method set_current_func: fundec -> unit
991
method reset_current_func: unit -> unit
993
(*VP: annotation visitor. *)
995
method vlogic_type: logic_type -> logic_type visitAction
997
method vtsets_elem: tsets_elem -> tsets_elem visitAction
999
method vtsets_lval: tsets_lval -> tsets_lval visitAction
1001
method vtsets_lhost: tsets_lhost -> tsets_lhost visitAction
1003
method vtsets_offset: tsets_offset -> tsets_offset visitAction
1005
method vtsets: tsets -> tsets visitAction
1007
method vterm: term -> term visitAction
1009
method vterm_node: term_node -> term_node visitAction
1011
method vterm_lval: term_lval -> term_lval visitAction
1013
method vterm_lhost: term_lhost -> term_lhost visitAction
1015
method vterm_offset: term_offset -> term_offset visitAction
1017
method vlogic_info_decl: logic_info -> logic_info visitAction
1019
method vlogic_info_use: logic_info -> logic_info visitAction
1021
method vlogic_var_use: logic_var -> logic_var visitAction
1023
method vlogic_var_decl: logic_var -> logic_var visitAction
1025
method vquantifiers: quantifiers -> quantifiers visitAction
1027
method vpredicate: predicate -> predicate visitAction
1029
method vpredicate_named: predicate named -> predicate named visitAction
1032
method vpredicate_info_decl: predicate_info -> predicate_info visitAction
1034
method vpredicate_info_use: predicate_info -> predicate_info visitAction
1037
method vbehavior: funbehavior -> funbehavior visitAction
1039
method vspec: funspec -> funspec visitAction
1042
identified_tsets assigns -> identified_tsets assigns visitAction
1044
method vloop_pragma: term loop_pragma -> term loop_pragma visitAction
1046
method vslice_pragma: term slice_pragma -> term slice_pragma visitAction
1047
method vimpact_pragma: term impact_pragma -> term impact_pragma visitAction
1050
identified_tsets zone -> identified_tsets zone visitAction
1052
method vcode_annot: code_annotation -> code_annotation visitAction
1054
method vannotation: global_annotation -> global_annotation visitAction
1055
method fill_global_tables: unit
1056
method get_filling_actions: (unit -> unit) Queue.t
1057
method set_logic_tables: unit -> unit
1060
(* the default visitor does nothing at each node, but does *)
1061
(* not stop; hence they return true *)
1062
class genericCilVisitor ?prj behavior: cilVisitor =
1064
method behavior = behavior
1066
(* list of things to perform on the new project. Done at the end
1067
of the analysis in order to minimize the number of project changes.
1069
val global_tables_action = Queue.create ()
1071
method fill_global_tables =
1072
let prj = match prj with None -> Project.current () | Some prj -> prj in
1074
(fun () -> Queue.iter (fun f -> f()) global_tables_action) ();
1075
Queue.clear global_tables_action
1077
method get_filling_actions = global_tables_action
1079
method set_logic_tables () =
1080
if is_copy_behavior self#behavior then begin
1081
Queue.add Logic_env.LogicInfo.clear global_tables_action;
1083
Queue.add Logic_env.PredicateInfo.clear global_tables_action;
1085
Logic_env.LogicInfo.iter
1087
let x' = self#behavior.memo_logic_info x in
1088
Queue.add (fun () -> Logic_env.add_logic_function x')
1089
global_tables_action);
1091
Logic_env.PredicateInfo.iter
1093
let x' = self#behavior.memo_predicate_info x in
1094
Queue.add (fun () -> Logic_env.add_predicate x')
1095
global_tables_action);
1099
method vfile _f = DoChildren
1100
val current_stmt = Stack.create ()
1101
method private push_stmt s = Stack.push s current_stmt
1102
method private pop_stmt _s = ignore (Stack.pop current_stmt)
1103
method current_stmt =
1104
try Some (Stack.top current_stmt) with Stack.Empty -> None
1106
val mutable current_func = None
1107
method current_func = current_func
1108
method set_current_func f = current_func <- Some f
1109
method reset_current_func () = current_func <- None
1111
method vvrbl (_v:varinfo) = DoChildren
1112
method vvdec (_v:varinfo) = DoChildren
1113
method vexpr (_e:exp) = DoChildren
1114
method vlval (_l:lval) = DoChildren
1115
method voffs (_o:offset) = DoChildren
1116
method vinitoffs (_o:offset) = DoChildren
1117
method vinst (_i:instr) = DoChildren
1118
method vstmt (_s:stmt) = DoChildren
1119
method vblock (_b: block) = DoChildren
1120
method vfunc (_f:fundec) = DoChildren
1121
method vglob (_g:global) = DoChildren
1122
method vinit (_forg: varinfo) (_off: offset) (_i:init) = DoChildren
1123
method vtype (_t:typ) = DoChildren
1124
method vcompinfo _ = DoChildren
1125
method venuminfo _ = DoChildren
1126
method vfieldinfo _ = DoChildren
1127
method venumitem _ = DoChildren
1128
method vattr (_a: attribute) = DoChildren
1129
method vattrparam (_a: attrparam) = DoChildren
1131
val mutable instrQueue = []
1133
method queueInstr (il: instr list) =
1134
List.iter (fun i -> instrQueue <- i :: instrQueue) il
1136
method unqueueInstr () =
1137
let res = List.rev instrQueue in
1141
method vlogic_type _lt = DoChildren
1143
method vtsets_lhost _ = DoChildren
1145
method vtsets_elem _ = DoChildren
1147
method vtsets_lval _ = DoChildren
1149
method vtsets_offset _ = DoChildren
1151
method vtsets _l = DoChildren
1153
method vterm _t = DoChildren
1155
method vterm_node _tn = DoChildren
1157
method vterm_lval _tl = DoChildren
1159
method vterm_lhost _tl = DoChildren
1161
method vterm_offset _vo = DoChildren
1163
method vlogic_info_decl _li = DoChildren
1165
method vlogic_info_use _li = DoChildren
1167
method vlogic_var_decl _lv = DoChildren
1169
method vlogic_var_use _lv = DoChildren
1171
method vquantifiers _q = DoChildren
1173
method vpredicate _p = DoChildren
1175
method vpredicate_named _p = DoChildren
1178
method vpredicate_info_decl _pi = DoChildren
1180
method vpredicate_info_use _pi = DoChildren
1183
method vbehavior _b = DoChildren
1185
method vspec _s = DoChildren
1187
method vassigns _s = DoChildren
1189
method vloop_pragma _ = DoChildren
1191
method vslice_pragma _ = DoChildren
1192
method vimpact_pragma _ = DoChildren
1194
method vzone _ = DoChildren
1196
method vcode_annot _ca = DoChildren
1198
method vannotation _a = DoChildren
1202
class nopCilVisitor = object
1203
inherit genericCilVisitor (inplace_visit ())
1206
let assertEmptyQueue vis =
1207
if vis#unqueueInstr () <> [] then
1208
(* Either a visitor inserted an instruction somewhere that it shouldn't
1209
have (i.e. at the top level rather than inside of a statement), or
1210
there's a bug in the visitor engine. *)
1211
E.s (E.bug "Visitor's instruction queue is not empty.\n You should only use queueInstr inside a function body!");
1215
let startsWith prefix s =
1216
let prefixLen = String.length prefix in
1217
String.length s >= prefixLen && String.sub s 0 prefixLen = prefix
1220
Computation.Make_Hashtbl
1222
(Cil_datatype.Varinfo)
1224
let name = "VarInfos"
1225
let dependencies = []
1229
let varinfos_self = VarInfos.self
1230
let varinfo_from_vid = VarInfos.find
1232
let set_vid, copy_with_new_vid, copy_with_new_lvid, new_raw_id =
1233
(* [new_vid] should never be used by foreign functions *)
1235
let module M = Build_Counter(struct let name = "vid" end) in
1239
let n = new_vid () in
1241
ignore (VarInfos.memo ~change:(fun _ -> assert false) (fun _ -> v) n)),
1243
let n = new_vid () in
1244
let v' = { v with vid = n } in
1245
VarInfos.memo ~change:(fun _ -> assert false) (fun _ -> v') n),
1246
(fun lv -> { lv with lv_id = new_vid () }),
1249
(* The next compindo identifier to use. Counts up. *)
1250
let nextCompinfoKey =
1251
let module M = Build_Counter(struct let name = "compinfokey" end) in
1254
let bytesSizeOfInt (ik: ikind): int =
1256
| IChar | ISChar | IUChar -> 1
1257
| IBool | IInt | IUInt -> theMachine.theMachine.sizeof_int
1258
| IShort | IUShort -> theMachine.theMachine.sizeof_short
1259
| ILong | IULong -> theMachine.theMachine.sizeof_long
1260
| ILongLong | IULongLong -> theMachine.theMachine.sizeof_longlong
1262
(** Returns true if and only if the given integer type is signed. *)
1263
let isSigned = function
1277
not theMachine.theMachine.Cil_types.char_is_unsigned
1279
(* Represents an integer as for a given kind.
1280
Returns a flag saying whether the value was changed
1281
during truncation (because it was too large to fit in k). *)
1282
let truncateInteger64 (k: ikind) (i: int64) : int64 * bool =
1283
let nrBits = 8 * (bytesSizeOfInt k) in
1284
let signed = isSigned k in
1288
let i1 = Int64.shift_left i (64 - nrBits) in
1290
if signed then Int64.shift_right i1 (64 - nrBits)
1291
else Int64.shift_right_logical i1 (64 - nrBits)
1294
if i2 = i then false
1296
(* Examine the bits that we chopped off. If they are all zero, then
1297
* any difference between i2 and i is due to a simple sign-extension.
1298
* e.g. casting the constant 0x80000000 to int makes it
1299
* 0xffffffff80000000.
1300
* Suppress the truncation warning in this case. *)
1301
let chopped = Int64.shift_right_logical i (64 - nrBits)
1302
in chopped <> Int64.zero
1307
(* Construct an integer constant with possible truncation *)
1308
let kinteger64 (k: ikind) (i: int64) : exp =
1309
let i', truncated = truncateInteger64 k i in
1311
ignore (warnOpt "Truncating integer %s to %s\n"
1312
(Int64.format "0x%x" i) (Int64.format "0x%x" i'));
1313
(* Format.printf "kint64:%Lx %Ld@\n" i' i';*)
1314
Const (CInt64(i' , k, None))
1316
(* Construct an integer of a given kind. *)
1317
let kinteger (k: ikind) (i: int) = kinteger64 k (Int64.of_int i)
1319
(* Construct an integer. Use only for values that fit on 31 bits *)
1320
let integer (i: int) = Const (CInt64(Int64.of_int i, IInt, None))
1322
let zero = integer 0
1324
let mone = integer (-1)
1326
let lconstant ?(loc=locUnknown) v =
1327
{ term_node = TConst (CInt64(v, IInt, None)); term_loc = loc;
1328
term_name = []; term_type = Ctype (TInt (IInt,[]));}
1330
let lzero ?(loc=locUnknown) () = lconstant ~loc Int64.zero
1331
let lone ?(loc=locUnknown) () = lconstant ~loc Int64.one
1332
let lmone ?(loc=locUnknown) () = lconstant ~loc (Int64.minus_one)
1334
(** Given the character c in a (CChr c), sign-extend it to 32 bits.
1335
(This is the official way of interpreting character constants, according to
1336
ISO C 6.4.4.4.10, which says that character constants are chars cast to ints)
1337
Returns CInt64(sign-extened c, IInt, None) *)
1338
let charConstToInt (c: char) : constant =
1339
let c' = Char.code c in
1342
then Int64.of_int c'
1343
else Int64.of_int (c' - 256)
1345
CInt64(value, IInt, None)
1348
let rec isInteger : exp -> int64 option = function
1349
| Const(CInt64 (n,_,_)) -> Some n
1350
| Const(CChr c) -> isInteger (Const (charConstToInt c)) (* sign-extend *)
1351
| Const(CEnum {eival = v}) -> isInteger v
1352
| CastE(_, e) -> isInteger e
1355
(** Convert a 64-bit int to an OCaml int, or raise an exception if that
1357
let i64_to_int (i: int64) : int =
1358
let i': int = Int64.to_int i in (* i.e. i' = i mod 2^31 *)
1359
if i = Int64.of_int i' then i'
1360
else E.s (E.error "Int constant too large: %Ld\n" i)
1363
let rec isZero (e: exp) : bool = isInteger e = Some Int64.zero
1365
let rec isLogicZero t = match t.term_node with
1366
| TConst (CInt64 (n,_,_)) -> n = 0L
1367
| TConst (CChr c) -> Char.code c = 0
1368
| TCastE(_, t) -> isLogicZero t
1373
(let rec aux t = match t.term_node with
1375
| TCastE(_, t) -> aux t
1379
let parseInt (str: string) : exp =
1381
let l = String.length str in
1383
let ls = String.length s in
1384
l >= ls && s = String.uppercase (String.sub str (l - ls) ls)
1386
let l = String.length str in
1387
(* See if it is octal or hex *)
1388
let octalhex = (l >= 1 && String.get str 0 = '0') in
1389
(* The length of the suffix and a list of possible kinds. See ISO
1391
let hasSuffix = hasSuffix str in
1392
let suffixlen, kinds =
1393
if hasSuffix "ULL" || hasSuffix "LLU" then
1395
else if hasSuffix "LL" then
1396
2, if octalhex then [ILongLong; IULongLong] else [ILongLong]
1397
else if hasSuffix "UL" || hasSuffix "LU" then
1398
2, [IULong; IULongLong]
1399
else if hasSuffix "L" then
1400
1, if octalhex then [ILong; IULong; ILongLong; IULongLong]
1401
else [ILong; ILongLong]
1402
else if hasSuffix "U" then
1403
1, [IUInt; IULong; IULongLong]
1405
0, if octalhex || true (* !!! This is against the ISO but it
1406
* is what GCC and MSVC do !!! *)
1407
then [IInt; IUInt; ILong; IULong; ILongLong; IULongLong]
1408
else [IInt; ILong; IUInt; ILongLong]
1410
(* Convert to integer. To prevent overflow we do the arithmetic
1411
* on Int64 and we take care of overflow. We work only with
1412
* positive integers since the lexer takes care of the sign *)
1413
let rec toInt (base: int64) (acc: int64) (idx: int) : int64 =
1414
(*Format.printf "toInt base=%Ld acc=%Ld idx=%d@." base acc idx;*)
1415
let doAcc (what: int) =
1417
Int64.add (Int64.mul base acc) (Int64.of_int what) in
1418
if acc < Int64.zero || (* We clearly overflow since base >= 2
1420
(acc' > Int64.zero && acc' < acc) then
1421
E.s (unimp "Cannot represent on 64 bits the integer %s\n"
1424
toInt base acc' (idx + 1)
1426
if idx >= l - suffixlen then begin
1429
let ch = String.get str idx in
1430
if ch >= '0' && ch <= '9' then
1431
doAcc (Char.code ch - Char.code '0')
1432
else if ch >= 'a' && ch <= 'f' then
1433
doAcc (10 + Char.code ch - Char.code 'a')
1434
else if ch >= 'A' && ch <= 'F' then
1435
doAcc (10 + Char.code ch - Char.code 'A')
1437
E.s (bug "Invalid integer constant: %s" str)
1443
(let c = String.get str 1 in c = 'x' || c = 'X') then
1444
toInt (Int64.of_int 16) Int64.zero 2
1446
toInt (Int64.of_int 8) Int64.zero 1
1448
toInt (Int64.of_int 10) Int64.zero 0
1450
(* Format.printf "Got i =%Ld@." i;*)
1451
(* Construct an integer of the first kinds that fits. i must be
1453
(* assert (Int64.zero <= i);*)
1455
let rec loop = function
1458
let unsignedbits = 8 * (bytesSizeOfInt k) in
1464
(* Will i fit in nrBits bits? *)
1465
let bound : int64 = Int64.shift_left 1L nrBits in
1466
(* toInt has ensured that 0 <= i < 263.
1467
So if nrBits >=63, i fits *)
1468
if (nrBits >= 63) || (i < bound) then
1472
| [] -> E.s (E.unimp "Cannot represent the integer %s\n"
1473
(Int64.to_string i))
1476
let rec loop = function
1477
| ((IInt | ILong) as k) :: _
1478
when i < Int64.shift_left (Int64.of_int 1) 31 ->
1480
| ((IUInt | IULong) as k) :: _
1481
when i < Int64.shift_left (Int64.of_int 1) 32
1483
| (ILongLong as k) :: _
1484
when i <= Int64.sub (Int64.shift_left
1485
(Int64.of_int 1) 63)
1489
| (IULongLong as k) :: _ -> kinteger64 k i
1490
| _ :: rest -> loop rest
1491
| [] -> E.s (E.unimp "Cannot represent the integer %s\n"
1492
(Int64.to_string i))
1498
with Failure _ as e -> begin
1499
ignore (log "int_of_string %s (%s)\n" str
1500
(Printexc.to_string e));
1504
let mkStmt ?(valid_sid=false) (sk: stmtkind) : stmt =
1507
(* It is better to create statements with a valid sid, so that they can
1508
be safely be used in tables. I only do it when performing Jessie
1509
analysis, as other plugins rely on specific sid values for their tests
1511
sid = if valid_sid then Sid.next () else -1;
1512
succs = []; preds = [];
1515
let mkStmtCfg ~before ~(new_stmtkind:stmtkind) ~(ref_stmt:stmt) : stmt =
1516
let new_ = { skind = new_stmtkind;
1518
sid = -1; succs = []; preds = []; ghost = false }
1520
new_.sid <- Sid.next ();
1521
if before then begin
1522
new_.succs <- [ref_stmt];
1523
let old_preds = ref_stmt.preds in
1524
ref_stmt.preds <- [new_];
1525
new_.preds <- old_preds;
1530
(fun a_succ -> if a_succ.sid = ref_stmt.sid then new_ else a_succ)
1534
let old_succs = ref_stmt.succs in
1535
ref_stmt.succs <- [new_];
1536
new_.preds <- [ref_stmt];
1537
new_.succs <- old_succs;
1542
(fun a_pred -> if a_pred.sid = ref_stmt.sid then new_ else a_pred)
1549
let mkBlock (slst: stmt list) : block =
1550
let slst = List.filter
1551
(fun st -> match st.skind with
1552
| Instr (Skip _) when st.labels = [] -> false
1556
{ battrs = []; bstmts = slst; }
1558
let mkStmtCfgBlock sl =
1559
let sid = Sid.next () in
1560
let n = mkStmt (Block (mkBlock sl)) in
1565
let old_preds = s.preds in
1572
(fun a_succ -> if a_succ.sid = s.sid then
1579
let stmt_of_instr_list ?(loc=locUnknown) = function
1580
| [] -> Instr (Skip loc)
1583
let b = mkBlock (List.map (fun i -> mkStmt (Instr i)) il) in
1585
| [] -> Instr (Skip loc)
1586
| [s] when b.battrs = [] -> s.skind
1589
let mkEmptyStmt ?(loc=locUnknown) () = mkStmt (Instr (Skip loc))
1590
let mkStmtOneInstr (i: instr) = mkStmt (Instr i)
1592
let dummyInstr = Asm([], ["dummy statement!!"], [], [], [], locUnknown)
1593
let dummyStmt = mkStmt (Instr dummyInstr)
1596
let compactStmts (b: stmt list) : stmt list =
1597
(* Try to compress statements. Scan the list of statements and remember
1598
* the last instrunction statement encountered, along with a Clist of
1599
* instructions in it. *)
1600
let rec compress (lastinstrstmt: stmt) (* Might be dummStmt *)
1601
(lastinstrs: instr Clist.clist)
1603
let finishLast (tail: stmt list) : stmt list =
1604
if lastinstrstmt == dummyStmt then tail
1606
lastinstrstmt.skind <- Instr (Clist.toList lastinstrs);
1607
lastinstrstmt :: tail
1612
| ({skind=Instr il} as s) :: rest ->
1613
let ils = Clist.fromList il in
1614
if lastinstrstmt != dummyStmt && s.labels == [] then
1615
compress lastinstrstmt (Clist.append lastinstrs ils) rest
1617
finishLast (compress s ils rest)
1620
let res = s :: compress dummyStmt Clist.empty rest in
1623
compress dummyStmt Clist.empty b
1626
(**** ATTRIBUTES ****)
1629
(* JS: build an attribute annotation from [s]. *)
1630
let mkAttrAnnot s = "/*@ " ^ s ^ " */"
1633
let attributeName = function Attr(a, _) | AttrAnnot a -> a
1635
(* Internal attributes. Won't be pretty-printed *)
1636
let reserved_attributes = ["FRAMA_C_KEEP_BLOCK"]
1638
(** Construct sorted lists of attributes ***)
1639
let rec addAttribute
1640
(Attr(an, _) | AttrAnnot an as a: attribute) (al: attributes) =
1641
let rec insertSorted = function
1643
| ((Attr(an0, _) | AttrAnnot an0 as a0) :: rest) as l ->
1644
if an < an0 then a :: l
1645
else if equals a a0 then l (* Do not add if already in there *)
1646
else a0 :: insertSorted rest (* Make sure we see all attributes with
1651
(** The second attribute list is sorted *)
1652
and addAttributes al0 (al: attributes) : attributes =
1653
if al0 == [] then al else
1654
List.fold_left (fun acc a -> addAttribute a acc) al al0
1656
and dropAttribute (an: string) (al: attributes) =
1657
List.filter (fun a -> attributeName a <> an) al
1659
and dropAttributes (anl: string list) (al: attributes) =
1660
List.fold_left (fun acc an -> dropAttribute an acc) al anl
1662
and filterAttributes (s: string) (al: attribute list) : attribute list =
1663
List.filter (fun a -> attributeName a = s) al
1665
and findAttribute (s: string) (al: attribute list) : attrparam list =
1667
(fun acc -> function
1668
| Attr (an, param) when an = s -> param @ acc
1673
let hasAttribute s al =
1674
(filterAttributes s al <> [])
1676
type attributeClass =
1678
(* Attribute of a name. If argument is true and we are on MSVC then
1679
* the attribute is printed using __declspec as part of the storage
1681
| AttrFunType of bool
1682
(* Attribute of a function type. If argument is true and we are on
1683
* MSVC then the attribute is printed just before the function name *)
1685
| AttrType (* Attribute of a type *)
1687
(* This table contains the mapping of predefined attributes to classes.
1688
* Extend this table with more attributes as you need. This table is used to
1689
* determine how to associate attributes with names or type during cabs2cil
1691
let attributeHash: (string, attributeClass) H.t =
1692
let table = H.create 13 in
1693
List.iter (fun a -> H.add table a (AttrName false))
1694
[ "section"; "constructor"; "destructor"; "unused"; "used"; "weak";
1695
"no_instrument_function"; "alias"; "no_check_memory_usage";
1696
"exception"; "model"; (* "restrict"; *)
1697
"aconst"; "__asm__" (* Gcc uses this to specifiy the name to be used in
1698
* assembly for a global *)];
1699
(* Now come the MSVC declspec attributes *)
1700
List.iter (fun a -> H.add table a (AttrName true))
1701
[ "thread"; "naked"; "dllimport"; "dllexport";
1702
"selectany"; "allocate"; "nothrow"; "novtable"; "property"; "noreturn";
1704
List.iter (fun a -> H.add table a (AttrFunType false))
1705
[ "format"; "regparm"; "longcall"; "noinline"; "always_inline" ];
1706
List.iter (fun a -> H.add table a (AttrFunType true))
1707
[ "stdcall";"cdecl"; "fastcall" ];
1708
List.iter (fun a -> H.add table a AttrType)
1709
[ "const"; "volatile"; "restrict"; "mode" ];
1712
let attributeClass = H.find attributeHash
1714
let registerAttribute = H.add attributeHash
1715
let removeAttribute = H.remove attributeHash
1717
(** Partition the attributes into classes *)
1718
let partitionAttributes
1719
~(default:attributeClass)
1720
(attrs: attribute list) :
1721
attribute list * attribute list * attribute list =
1722
let rec loop (n,f,t) = function
1724
| (Attr(an, _) | AttrAnnot an as a) :: rest ->
1725
match (try H.find attributeHash an with Not_found -> default) with
1726
AttrName _ -> loop (addAttribute a n, f, t) rest
1728
loop (n, addAttribute a f, t) rest
1729
| AttrType -> loop (n, f, addAttribute a t) rest
1731
loop ([], [], []) attrs
1734
(** Get the full name of a comp *)
1735
let compFullName comp =
1736
(if comp.cstruct then "struct " else "union ") ^ comp.cname
1739
let missingFieldName = "_" (* "___missing_field_name"*)
1741
(** Creates a (potentially recursive) composite type. Make sure you add a
1742
* GTag for it to the file! **)
1746
(* fspec is a function that when given a forward
1747
* representation of the structure type constructs the type of
1748
* the fields. The function can ignore this argument if not
1749
* constructing a recursive type. *)
1750
(mkfspec: compinfo -> (string * typ * int option * attribute list *
1752
(a: attribute list) : compinfo =
1754
(* make a new name for anonymous structs *)
1756
E.s (E.bug "mkCompInfo: missing structure name\n");
1757
(* Make a new self cell and a forward reference *)
1759
{ cstruct = isstruct; cname = ""; ckey = 0; cfields = [];
1760
cattr = a; creferenced = false;
1761
(* Make this compinfo undefined by default *)
1765
comp.ckey <- nextCompinfoKey ();
1767
List.map (fun (fn, ft, fb, fa, fl) ->
1775
fsize_in_bits = None;
1776
foffset_in_bits = None;
1777
fpadding_in_bits = None;
1778
}) (mkfspec comp) in
1779
comp.cfields <- flds;
1780
if flds <> [] then comp.cdefined <- true;
1783
(** Make a copy of a compinfo, changing the name and the key *)
1784
let copyCompInfo (ci: compinfo) (n: string) : compinfo =
1785
let ci' = {ci with cname = n; ckey = nextCompinfoKey (); } in
1786
(* Copy the fields and set the new pointers to parents *)
1787
ci'.cfields <- List.map (fun f -> {f with fcomp = ci'}) ci'.cfields;
1790
(**** Utility functions ******)
1792
let rec typeAttrs = function
1795
| TFloat (_, a) -> a
1796
| TNamed (t, a) -> addAttributes a (typeAttrs t.ttype)
1798
| TArray (_, _, a) -> a
1799
| TComp (comp, a) -> addAttributes comp.cattr a
1800
| TEnum (enum, a) -> addAttributes enum.eattr a
1801
| TFun (_, _, _, a) -> a
1802
| TBuiltin_va_list a -> a
1805
let typeAttr = function
1815
| TBuiltin_va_list a -> a
1818
let setTypeAttrs t a =
1821
| TInt (i, _) -> TInt (i, a)
1822
| TFloat (f, _) -> TFloat (f, a)
1823
| TNamed (t, _) -> TNamed(t, a)
1824
| TPtr (t', _) -> TPtr(t', a)
1825
| TArray (t', l, _) -> TArray(t', l, a)
1826
| TComp (comp, _) -> TComp (comp, a)
1827
| TEnum (enum, _) -> TEnum (enum, a)
1828
| TFun (r, args, v, _) -> TFun(r,args,v,a)
1829
| TBuiltin_va_list _ -> TBuiltin_va_list a
1832
let typeAddAttributes a0 t =
1836
(* no attributes, keep same type *)
1839
(* anything else: add a0 to existing attributes *)
1840
let add (a: attributes) = addAttributes a0 a in
1842
TVoid a -> TVoid (add a)
1843
| TInt (ik, a) -> TInt (ik, add a)
1844
| TFloat (fk, a) -> TFloat (fk, add a)
1845
| TEnum (enum, a) -> TEnum (enum, add a)
1846
| TPtr (t, a) -> TPtr (t, add a)
1847
| TArray (t, l, a) -> TArray (t, l, add a)
1848
| TFun (t, args, isva, a) -> TFun(t, args, isva, add a)
1849
| TComp (comp, a) -> TComp (comp, add a)
1850
| TNamed (t, a) -> TNamed (t, add a)
1851
| TBuiltin_va_list a -> TBuiltin_va_list (add a)
1854
let typeRemoveAttributes (anl: string list) t =
1855
let drop (al: attributes) = dropAttributes anl al in
1857
TVoid a -> TVoid (drop a)
1858
| TInt (ik, a) -> TInt (ik, drop a)
1859
| TFloat (fk, a) -> TFloat (fk, drop a)
1860
| TEnum (enum, a) -> TEnum (enum, drop a)
1861
| TPtr (t, a) -> TPtr (t, drop a)
1862
| TArray (t, l, a) -> TArray (t, l, drop a)
1863
| TFun (t, args, isva, a) -> TFun(t, args, isva, drop a)
1864
| TComp (comp, a) -> TComp (comp, drop a)
1865
| TNamed (t, a) -> TNamed (t, drop a)
1866
| TBuiltin_va_list a -> TBuiltin_va_list (drop a)
1868
let unrollType (t: typ) : typ =
1869
let rec withAttrs (al: attributes) (t: typ) : typ =
1871
TNamed (r, a') -> withAttrs (addAttributes al a') r.ttype
1872
| x -> typeAddAttributes al x
1876
let rec unrollTypeDeep (t: typ) : typ =
1877
let rec withAttrs (al: attributes) (t: typ) : typ =
1879
TNamed (r, a') -> withAttrs (addAttributes al a') r.ttype
1880
| TPtr(t, a') -> TPtr(unrollTypeDeep t, addAttributes al a')
1881
| TArray(t, l, a') -> TArray(unrollTypeDeep t, l, addAttributes al a')
1882
| TFun(rt, args, isva, a') ->
1883
TFun (unrollTypeDeep rt,
1887
Some (List.map (fun (an,at,aa) ->
1888
(an, unrollTypeDeep at, aa)) argl)),
1890
addAttributes al a')
1891
| x -> typeAddAttributes al x
1896
match unrollType t with
1899
let isVoidPtrType t =
1900
match unrollType t with
1901
TPtr(tau,_) when isVoidType tau -> true
1904
let isSignedInteger ty =
1905
match unrollType ty with
1906
| TInt(ik,_attr) -> isSigned ik
1907
| TEnum _ -> theMachine.theMachine.Cil_types.enum_are_signed
1910
let var vi : lval = (Var vi, NoOffset)
1911
(* let assign vi e = Instrs(Set (var vi, e), lu) *)
1913
let mkString s = Const(CStr s)
1915
let mkWhile ~(guard:exp) ~(body: stmt list) : stmt list =
1916
(* Do it like this so that the pretty printer recognizes it *)
1922
mkBlock [ mkEmptyStmt () ],
1923
mkBlock [ mkStmt (Break locUnknown)], locUnknown)) ::
1924
body), locUnknown, None, None)) ]
1928
let mkFor ~(start: stmt list) ~(guard: exp) ~(next: stmt list)
1929
~(body: stmt list) : stmt list =
1931
(mkWhile guard (body @ next)))
1934
let mkForIncr ~(iter : varinfo) ~(first: exp) ~stopat:(past: exp) ~(incr: exp)
1935
~(body: stmt list) : stmt list =
1936
(* See what kind of operator we need *)
1937
let compop, nextop =
1938
match unrollType iter.vtype with
1939
TPtr _ -> Lt, PlusPI
1943
[ mkStmt (Instr (Set (var iter, first, locUnknown))) ]
1944
(BinOp(compop, Lval(var iter), past, intType))
1945
[ mkStmt (Instr (Set (var iter,
1946
(BinOp(nextop, Lval(var iter), incr, iter.vtype)),
1950
let block_from_unspecified_sequence us =
1951
{ battrs = []; bstmts = List.map (fun (x,_,_) ->x) us }
1953
let rec stripCasts (e: exp) =
1954
match e with CastE(_, e') -> stripCasts e' | _ -> e
1956
let rec stripInfo (e: exp) =
1957
match e with Info(e',_) -> stripInfo e' | _ -> e
1959
let rec stripCastsAndInfo (e: exp) =
1960
match e with Info(e',_) | CastE(_,e') -> stripCastsAndInfo e' | _ -> e
1962
let rec stripCastsButLastInfo (e: exp) =
1964
Info((Info _ | CastE _ as e'),_) | CastE(_,e') -> stripCastsButLastInfo e'
1967
let rec stripTermCasts (t: term) =
1968
match t.term_node with TCastE(_, t') -> stripTermCasts t' | _ -> t
1970
let rec stripTsetsCasts (ts: tsets_elem) =
1971
match ts with TSCastE(_ty,ts') -> stripTsetsCasts ts' | _ -> ts
1973
let exp_info_of_term t =
1975
exp_loc = t.term_loc;
1976
exp_type = t.term_type;
1977
exp_name = t.term_name;
1980
let term_of_exp_info tnode einfo =
1983
term_loc = einfo.exp_loc;
1984
term_type = einfo.exp_type;
1985
term_name = einfo.exp_name;
1988
let map_under_info f = function
1989
| Info(e,einfo) -> Info(f e,einfo)
1992
let app_under_info f = function
1993
| Info(e,_) | e -> f e
1995
(* the name of the C function we call to get ccgr ASTs
1996
external parse : string -> file = "cil_main"
2007
| ISChar -> "signed char"
2008
| IUChar -> "unsigned char"
2010
| IUInt -> "unsigned int"
2012
| IUShort -> "unsigned short"
2014
| IULong -> "unsigned long"
2016
if theMachine.msvcMode then "__int64" else "long long"
2018
if theMachine.msvcMode then "unsigned __int64"
2019
else "unsigned long long")
2021
let d_fkind fmt = function
2022
FFloat -> fprintf fmt "float"
2023
| FDouble -> fprintf fmt "double"
2024
| FLongDouble -> fprintf fmt "long double"
2026
let d_storage fmt c =
2030
| Static -> "static "
2031
| Extern -> "extern "
2032
| Register -> "register ")
2034
(* sm: need this value below *)
2035
let mostNeg32BitInt : int64 = (Int64.of_string "-0x80000000")
2036
let mostNeg64BitInt : int64 = (Int64.of_string "-0x8000000000000000")
2041
CInt64(_, _, Some s) -> fprintf fmt "%s" s (* Always print the text if there is one *)
2042
| CInt64(i, ik, None) ->
2043
(*fprintf fmt "/* %Lx */" i;*)
2044
(** We must make sure to capture the type of the constant. For some
2045
* constants this is done with a suffix, for others with a cast prefix.*)
2046
let suffix : string =
2051
| ILongLong -> if theMachine.msvcMode then "L" else "LL"
2052
| IULongLong -> if theMachine.msvcMode then "UL" else "ULL"
2055
let prefix : string =
2056
if suffix <> "" then ""
2057
else if ik = IInt then ""
2058
else fprintf_to_string "(%a)" d_ikind ik
2060
(* Watch out here for negative integers that we should be printing as
2061
* large positive ones *)
2065
IUInt | IULong | IULongLong | IUChar | IUShort -> true | _ -> false) then
2066
let high = Int64.shift_right i 32 in
2067
if ik <> IULongLong && ik <> ILongLong && high = Int64.of_int (-1) then
2068
(* Print only the low order 32 bits *)
2071
(Int64.logand i (Int64.shift_right_logical high 32))
2074
(prefix ^ "0x" ^ Int64.format "%x" i ^ suffix)
2076
if (i = mostNeg32BitInt) then
2077
(* sm: quirk here: if you print -2147483648 then this is two tokens *)
2078
(* in C, and the second one is too large to represent in a signed *)
2079
(* int.. so we do what's done in limits.h, and print (-2147483467-1); *)
2080
(* in gcc this avoids a warning, but it might avoid a real problem *)
2081
(* on another compiler or a 64-bit architecture *)
2082
(prefix ^ "(-0x7FFFFFFF-1)")
2083
else if (i = mostNeg64BitInt) then
2084
(* The same is true of the largest 64-bit negative. *)
2085
(prefix ^ "(-0x7FFFFFFFFFFFFFFF-1)")
2087
(prefix ^ (Int64.to_string i ^ suffix))
2090
| CStr(s) -> fprintf fmt "\"%s\"" (escape_string s)
2092
(* text ("L\"" ^ escape_string s ^ "\"") *)
2096
if (elt >= Int64.zero &&
2097
elt <= (Int64.of_int 255)) then
2098
fprintf fmt "%S" (escape_char (Char.chr (Int64.to_int elt)))
2100
fprintf fmt "\"\\x%LX\"" elt;
2103
(* we cannot print L"\xabcd" "feedme" as L"\xabcdfeedme" --
2104
* the former has 7 wide characters and the later has 3. *)
2106
| CChr(c) -> fprintf fmt "'%s'" (escape_char c)
2107
| CReal(_, _, Some s) -> fprintf fmt "%s" s
2108
| CReal(f, fsize, None) ->
2109
fprintf fmt "%s%s" (string_of_float f)
2113
| FLongDouble -> "L")
2114
| CEnum {einame = s} -> fprintf fmt "%s" s
2117
(* Parentheses/precedence level. An expression "a op b" is printed
2118
* parenthesized if its parentheses level is >= that that of its context.
2119
* Identifiers have the lowest level and weakly binding operators (e.g. |)
2120
* have the largest level. The correctness criterion is that a smaller level
2121
* MUST correspond to a stronger precedence! *)
2123
let derefStarLevel = 20
2126
let addrOfLevel = 30
2127
let additiveLevel = 60
2128
let comparativeLevel = 70
2129
let bitwiseLevel = 75
2130
let questionLevel = 100
2132
let logic_level = 77
2134
let getParenthLevel e = match stripInfo e with
2135
| Info _ -> assert false
2136
| BinOp((LAnd | LOr), _,_,_) -> 80
2137
(* Bit operations. *)
2138
| BinOp((BOr|BXor|BAnd),_,_,_) -> bitwiseLevel (* 75 *)
2141
| BinOp((Eq|Ne|Gt|Lt|Ge|Le),_,_,_) ->
2142
comparativeLevel (* 70 *)
2143
(* Additive. Shifts can have higher
2144
* level than + or - but I want
2145
* parentheses around them *)
2146
| BinOp((MinusA|MinusPP|MinusPI|PlusA|
2147
PlusPI|IndexPI|Shiftlt|Shiftrt),_,_,_)
2148
-> additiveLevel (* 60 *)
2150
(* Multiplicative *)
2151
| BinOp((Div|Mod|Mult),_,_,_) -> 40
2157
| UnOp((Neg|BNot|LNot),_,_) -> 30
2160
| Lval(Mem _ , _) -> derefStarLevel (* 20 *)
2161
| Lval(Var _, (Field _|Index _)) -> indexLevel (* 20 *)
2162
| SizeOf _ | SizeOfE _ | SizeOfStr _ -> 20
2163
| AlignOf _ | AlignOfE _ -> 20
2165
| Lval(Var _, NoOffset) -> 0 (* Plain variables *)
2166
| Const _ -> 0 (* Constants *)
2168
let getParenthLevelLogic = function
2170
(* TODO: remove spurious parentheses with prec mechanism
2173
| TBinOp((LAnd | LOr), _,_) -> 80
2174
(* Bit operations. *)
2175
| TBinOp((BOr|BXor|BAnd),_,_) -> bitwiseLevel (* 75 *)
2178
| TBinOp((Eq|Ne|Gt|Lt|Ge|Le),_,_) ->
2179
comparativeLevel (* 70 *)
2180
(* Additive. Shifts can have higher
2181
* level than + or - but I want
2182
* parentheses around them *)
2183
| TBinOp((MinusA|MinusPP|MinusPI|PlusA|
2184
PlusPI|IndexPI|Shiftlt|Shiftrt),_,_)
2185
-> additiveLevel (* 60 *)
2187
(* Multiplicative *)
2188
| TBinOp((Div|Mod|Mult),_,_) -> 40
2192
| TAddrOf(_) -> addrOfLevel
2193
| TStartOf(_) -> addrOfLevel
2194
| TUnOp((Neg|BNot|LNot),_) -> 30
2196
| TCoerce _ | TCoerceE _ -> 25
2199
| TLval(TMem _ , _) -> derefStarLevel
2200
| TLval(TVar _, (TField _|TIndex _)) -> indexLevel
2201
| TLval(TResult,(TField _|TIndex _)) -> indexLevel
2202
| TSizeOf _ | TSizeOfE _ | TSizeOfStr _ -> 20
2203
| TAlignOf _ | TAlignOfE _ -> 20
2204
(* VP: I'm not sure I understand why sizeof(x) and f(x) should
2205
have a separated treatment wrt parentheses. *)
2206
(* application and applications-like constructions *)
2207
| Tapp (_, _,_)|TDataCons _
2208
| Tblock_length _ | Tbase_addr _ | Tat (_, _) | Told _
2209
| TUpdate _ | Ttypeof _ | Ttype _ -> 10
2210
| TLval(TVar _, TNoOffset) -> 0 (* Plain variables *)
2211
(* Constructions that do not require parentheses *)
2213
| Tnull | TLval (TResult,TNoOffset) -> 0
2214
| Tif (_, _, _) -> logic_level
2217
let getParenthLevelTsetsElem = function
2218
TSLval(TSMem _,_) -> derefStarLevel
2219
| TSLval((TSVar _ | TSResult) , (TSField _ | TSIndex _ | TSRange _)) ->
2221
| TSAdd_range _ | TSAdd_index _ -> additiveLevel
2223
| TSStartOf _ | TSAddrOf _ -> addrOfLevel
2224
| TSConst _ | TSLval _ | TSat _ | TSapp _ -> 0
2226
let getParenthLevelAttrParam (a: attrparam) =
2227
(* Create an expression of the same shape, and use {!getParenthLevel} *)
2229
AInt _ | AStr _ | ACons _ -> 0
2230
| ASizeOf _ | ASizeOfE _ | ASizeOfS _ -> 20
2231
| AAlignOf _ | AAlignOfE _ | AAlignOfS _ -> 20
2232
| AUnOp (uo, _) -> getParenthLevel (UnOp(uo, zero, intType))
2233
| ABinOp (bo, _, _) -> getParenthLevel (BinOp(bo, zero, zero, intType))
2235
| ADot _ | AIndex _ | AStar _ -> 20
2236
| AQuestion _ -> questionLevel
2239
(* Separate out the storage-modifier name attributes *)
2240
let separateStorageModifiers (al: attribute list) =
2241
let isstoragemod (Attr(an, _) | AttrAnnot an : attribute) : bool =
2243
match H.find attributeHash an with
2244
AttrName issm -> issm
2246
with Not_found -> false
2248
let stom, rest = List.partition isstoragemod al in
2249
if not theMachine.msvcMode then
2252
(* Put back the declspec. Put it without the leading __ since these will
2257
| Attr(an, args) -> Attr("declspec", [ACons(an, args)])
2258
| AttrAnnot _ -> assert false)
2265
match unrollType t with
2266
| TInt((IChar|ISChar|IUChar),_) -> true
2269
let isCharPtrType t =
2270
match unrollType t with
2271
TPtr(tau,_) when isCharType tau -> true
2274
let isIntegralType t =
2275
match unrollType t with
2276
(TInt _ | TEnum _) -> true
2279
let isLogicIntegralType t =
2281
| Ctype t -> isIntegralType t
2284
| Lvar _ | Ltype _ | Larrow _ -> false
2286
let isFloatingType t =
2287
match unrollType t with
2291
let isLogicFloatType t =
2293
| Ctype t -> isFloatingType t
2296
| Lvar _ | Ltype _ | Larrow _ -> false
2298
let isLogicRealOrFloatType t =
2300
| Ctype t -> isFloatingType t
2303
| Lvar _ | Ltype _ | Larrow _ -> false
2305
let isArithmeticType t =
2306
match unrollType t with
2307
(TInt _ | TEnum _ | TFloat _) -> true
2310
let isLogicArithmeticType t =
2312
| Ctype t -> isArithmeticType t
2313
| Linteger | Lreal -> true
2314
| Lvar _ | Ltype _ | Larrow _ -> false
2316
let isPointerType t =
2317
match unrollType t with
2321
let isTypeTagType t =
2323
Ltype("typetag",[]) -> true
2326
let isFunctionType t =
2327
match unrollType t with
2331
let getReturnType t =
2332
match unrollType t with
2333
| TFun(rt,_,_,_) -> rt
2334
| _ -> E.s (E.bug "getReturnType: not a function type")
2336
let setReturnTypeVI (v: varinfo) (t: typ) =
2337
match unrollType v.vtype with
2338
| TFun (_, args, va, a) ->
2339
v.vtype <- TFun (t, args, va, a)
2340
| _ -> E.s (E.bug "setReturnType: not a function type")
2342
let setReturnType (f:fundec) (t:typ) =
2343
setReturnTypeVI f.svar t
2345
(** Returns the type pointed by the given type. Asserts it is a pointer type *)
2346
let typeOf_pointed typ =
2347
match unrollType typ with
2348
| TPtr (typ,_) -> typ
2351
(**** Compute the type of an expression ****)
2352
let rec typeOf (e: exp) : typ =
2353
match stripInfo e with
2354
| Info _ -> assert false
2355
| Const(CInt64 (_, ik, _)) -> TInt(ik, [])
2357
(* Character constants have type int. ISO/IEC 9899:1999 (E),
2358
* section 6.4.4.4 [Character constants], paragraph 10, if you
2359
* don't believe me. *)
2360
| Const(CChr _) -> intType
2362
(* The type of a string is a pointer to characters ! The only case when
2363
* you would want it to be an array is as an argument to sizeof, but we
2364
* have SizeOfStr for that *)
2365
| Const(CStr _s) -> theMachine.stringLiteralType
2367
| Const(CWStr _s) -> TPtr(theMachine.wcharType,[])
2369
| Const(CReal (_, fk, _)) -> TFloat(fk, [])
2371
| Const(CEnum {eihost = ei}) -> TEnum(ei, [])
2373
| Lval(lv) -> typeOfLval lv
2374
| SizeOf _ | SizeOfE _ | SizeOfStr _ -> theMachine.typeOfSizeOf
2375
| AlignOf _ | AlignOfE _ -> theMachine.typeOfSizeOf
2376
| UnOp (_, _, t) -> t
2377
| BinOp (_, _, _, t) -> t
2379
| AddrOf (lv) -> TPtr(typeOfLval lv, [])
2380
| StartOf (lv) -> begin
2381
match unrollType (typeOfLval lv) with
2382
TArray (t,_, _) -> TPtr(t, [])
2383
| _ -> E.s (E.bug "typeOf: StartOf on a non-array")
2386
and typeOfInit (i: init) : typ =
2388
SingleInit e -> typeOf e
2389
| CompoundInit (t, _) -> t
2391
and typeOfLval = function
2392
Var vi, off -> typeOffset vi.vtype off
2393
| Mem addr, off -> begin
2394
match unrollType (typeOf addr) with
2395
TPtr (t, _) -> typeOffset t off
2396
| _ -> E.s (bug "typeOfLval: Mem on a non-pointer (%a)" !pd_exp addr)
2399
and typeOffset basetyp =
2400
let blendAttributes baseAttrs =
2401
let (_, _, contageous) =
2402
partitionAttributes ~default:(AttrName false) baseAttrs in
2403
typeAddAttributes contageous
2407
| Index (_, o) -> begin
2408
match unrollType basetyp with
2409
TArray (t, _, baseAttrs) ->
2410
let elementType = typeOffset t o in
2411
blendAttributes baseAttrs elementType
2412
| _ -> E.s (E.bug "typeOffset: Index on a non-array")
2415
match unrollType basetyp with
2416
TComp (_, baseAttrs) ->
2417
let fieldType = typeOffset fi.ftype o in
2418
let typ = blendAttributes baseAttrs fieldType in
2419
(match fi.fbitfield with
2421
typeAddAttributes [Attr ("FRAMA_C_BITFIELD_SIZE", [AInt s])] typ
2423
| _ -> E.s (bug "typeOffset: Field on a non-compound")
2425
(**** Compute the type of a term lval ****)
2426
let rec typeOfTermLval = function
2428
let ty = match vi.lv_origin with
2429
| Some v -> Ctype v.vtype
2430
| None -> vi.lv_type
2432
typeTermOffset ty off
2434
begin match !currentGlobal with
2435
| GFun(f,_loc) -> Ctype (getReturnType f.svar.vtype)
2436
| _ -> E.s (bug "typeOfTermLval: Can not compute type of result")
2438
| TMem addr, off -> begin
2439
match addr.term_type with
2441
begin match unrollType typ with
2442
TPtr (t, _) -> typeTermOffset (Ctype t) off
2443
| _ -> E.s (bug "typeOfTermLval: Mem on a non-pointer")
2445
| Linteger | Lreal ->
2446
E.s (bug "typeOfTermLval: Mem on a logic type")
2447
| Ltype (s,_) -> E.s (bug "typeOfTermLval: Mem on a non-C type (%s)" s)
2448
| Lvar s -> E.s (bug "typeOfTermLval: Mem on a non-C type ('%s)" s)
2449
| Larrow _ -> E.s (bug "typeOfTermLval: Mem on a function type")
2452
and typeTermOffset basetyp =
2453
let blendAttributes baseAttrs =
2454
let (_, _, contageous) =
2455
partitionAttributes ~default:(AttrName false) baseAttrs in
2458
Ctype (typeAddAttributes contageous typ)
2459
| Linteger | Lreal ->
2460
E.s (bug "typeTermOffset: Attribute on a logic type")
2462
E.s (bug "typeTermOffset: Attribute on a non-C type (%s)" s)
2464
E.s (bug "typeTermOffset: Attribute on a non-C type ('%s)" s)
2466
E.s (bug "typeTermOffset: Attribute on a function type")
2469
TNoOffset -> basetyp
2470
| TIndex (_, o) -> begin
2473
begin match unrollType typ with
2474
TArray (t, _, baseAttrs) ->
2475
let elementType = typeTermOffset (Ctype t) o in
2476
blendAttributes baseAttrs elementType
2477
| _ -> E.s (E.bug "typeTermOffset: Index on a non-array")
2479
| Linteger | Lreal ->
2480
E.s (bug "typeTermOffset: Index on a logic type")
2482
E.s (bug "typeTermOffset: Index on a non-C type (%s)" s)
2484
E.s (bug "typeTermOffset: Index on a non-C type ('%s)" s)
2486
E.s (bug "typeTermOffset: Index on a function type")
2491
begin match unrollType typ with
2492
TComp (_, baseAttrs) ->
2493
let fieldType = typeTermOffset (Ctype fi.ftype) o in
2494
blendAttributes baseAttrs fieldType
2495
| _ -> E.s (bug "typeTermOffset: Field on a non-compound")
2497
| Linteger | Lreal ->
2498
E.s (bug "typeTermOffset: Field on a logic type")
2500
E.s (bug "typeTermOffset: Field on a non-C type (%s)" s)
2501
| Lvar s -> E.s (bug "typeTermOffset: Field on a non-C type ('%s)" s)
2502
| Larrow _ -> E.s (bug "typeTermOffset: Field on a function type")
2504
let rec typeOfTsetsLval = function
2506
let ty = match vi.lv_origin with
2507
| Some v -> Ctype v.vtype
2508
| None -> vi.lv_type
2510
typeTsetsOffset ty off
2512
begin match !currentGlobal with
2513
| GFun(f,_loc) -> Ctype (getReturnType f.svar.vtype)
2514
| _ -> E.s (bug "typeOfTsetsLval: Can not compute type of result")
2516
| TSMem addr, off -> begin
2517
match typeOfTsetsElem addr with
2519
begin match unrollType typ with
2520
TPtr (t, _) -> typeTsetsOffset (Ctype t) off
2521
| _ -> E.s (bug "typeOfTsetsLval: Mem on a non-pointer")
2523
| Linteger | Lreal ->
2524
E.s (bug "typeOfTsetsLval: Mem on a logic type")
2525
| Ltype (s,_) -> E.s (bug "typeOfTsetsLval: Mem on a non-C type (%s)" s)
2526
| Lvar s -> E.s (bug "typeOfTsetsLval: Mem on a non-C type ('%s)" s)
2527
| Larrow _ -> E.s (bug "typeOfTsetsLval: Mem on a function type")
2530
and typeTsetsOffset basetyp =
2531
let blendAttributes baseAttrs =
2532
let (_, _, contageous) =
2533
partitionAttributes ~default:(AttrName false) baseAttrs in
2536
Ctype (typeAddAttributes contageous typ)
2537
| Linteger | Lreal ->
2538
E.s (bug "typeTsetsOffset: Attribute on a logic type")
2540
E.s (bug "typeTsetsOffset: Attribute on a non-C type (%s)" s)
2542
E.s (bug "typeTsetsOffset: Attribute on a non-C type ('%s)" s)
2544
E.s (bug "typeTsetsOffset: Attribute on a function type")
2547
TSNoOffset -> basetyp
2548
| TSIndex (_, o) | TSRange(_,_,o) -> begin
2551
begin match unrollType typ with
2552
TArray (t, _, baseAttrs) ->
2553
let elementType = typeTsetsOffset (Ctype t) o in
2554
blendAttributes baseAttrs elementType
2555
| _ -> E.s (E.bug "typeTsetsOffset: Index on a non-array")
2557
| Linteger | Lreal ->
2558
E.s (bug "typeTsetsOffset: Index on a logic type")
2560
E.s (bug "typeTsetsOffset: Index on a non-C type (%s)" s)
2562
E.s (bug "typeTsetsOffset: Index on a non-C type ('%s)" s)
2564
E.s (bug "typeTsetsOffset: Index on a function type")
2566
| TSField (fi, o) ->
2569
begin match unrollType typ with
2570
TComp (_, baseAttrs) ->
2571
let fieldType = typeTsetsOffset (Ctype fi.ftype) o in
2572
blendAttributes baseAttrs fieldType
2573
| _ -> E.s (bug "typeTsetsOffset: Field on a non-compound")
2575
| Linteger | Lreal ->
2576
E.s (bug "typeTsetsOffset: Field on a logic type")
2578
E.s (bug "typeTsetsOffset: Field on a non-C type (%s)" s)
2579
| Lvar s -> E.s (bug "typeTsetsOffset: Field on a non-C type ('%s)" s)
2580
| Larrow _ -> E.s (bug "typeTsetsOffset: Field on a function type")
2582
and typeOfTsetsElem = function
2583
TSLval lv -> typeOfTsetsLval lv
2585
(match typeOfTsetsLval lv with
2587
(match unrollType t with
2588
| TArray(t,_,attrs) ->
2589
Ctype (TPtr(t,attrs))
2590
| _ -> E.s (bug "typeOfTsetsElem: TStartOf on non array type"))
2591
| _ -> E.s (bug "typeOfTsetsElem: TStartOf on non array type"))
2593
(match typeOfTsetsLval lv with
2594
Ctype t -> Ctype(TPtr(t,[]))
2595
| _ -> E.s (bug "typeOfTsetsElem: TAddrOf on logical type"))
2596
| TSConst (CInt64 _ ) -> Linteger
2597
| TSConst _ -> assert false (* cannot appear in tsets *)
2598
| TSAdd_index (t,_) | TSAdd_range(t,_,_) -> typeOfTsetsElem t
2599
| TSCastE(typ,_) -> Ctype typ
2600
| TSat(elem,_) -> typeOfTsetsElem elem
2603
(* until now, we only have complete applications*)
2606
| None -> assert false (* cannot appear in tsets *)
2611
** MACHINE DEPENDENT PART
2614
exception SizeOfError of string * typ
2617
(* Get the minimum aligment in bytes for a given type *)
2618
let rec alignOf_int = function
2619
| TInt((IChar|ISChar|IUChar|IBool), _) -> 1
2620
| TInt((IShort|IUShort), _) -> theMachine.theMachine.alignof_short
2621
| TInt((IInt|IUInt), _) -> theMachine.theMachine.alignof_int
2622
| TInt((ILong|IULong), _) -> theMachine.theMachine.alignof_long
2623
| TInt((ILongLong|IULongLong), _) ->
2624
theMachine.theMachine.alignof_longlong
2625
| TEnum _ -> theMachine.theMachine.alignof_enum
2626
| TFloat(FFloat, _) -> theMachine.theMachine.alignof_float
2627
| TFloat(FDouble, _) -> theMachine.theMachine.alignof_double
2628
| TFloat(FLongDouble, _) ->
2629
theMachine.theMachine.alignof_longdouble
2630
| TNamed (t, _) -> alignOf_int t.ttype
2631
| TArray (t, _, _) -> (* Be careful for char[] of Diab-C like compilers. *)
2633
match unrollType t with
2634
| TInt((IChar|ISChar|IUChar),_) ->
2635
theMachine.theMachine.alignof_char_array
2636
| _ -> alignOf_int t
2639
| TPtr _ | TBuiltin_va_list _ ->
2640
theMachine.theMachine.alignof_ptr
2642
(* For composite types get the maximum alignment of any field inside *)
2644
(* On GCC the zero-width fields do not contribute to the alignment. On
2645
* MSVC only those zero-width that _do_ appear after other
2646
* bitfields contribute to the alignment. So we drop those that
2647
* do not occur after othe bitfields *)
2648
(* This is not correct for Diab-C compiler. *)
2649
let rec dropZeros (afterbitfield: bool) = function
2650
| f :: rest when f.fbitfield = Some 0 && not afterbitfield ->
2651
dropZeros afterbitfield rest
2652
| f :: rest -> f :: dropZeros (f.fbitfield <> None) rest
2655
let fields = dropZeros false c.cfields in
2658
(* Bitfields with zero width do not contribute to the alignment in
2660
if not theMachine.msvcMode && f.fbitfield = Some 0 then sofar else
2661
max sofar (alignOf_int f.ftype)) 1 fields
2662
(* These are some error cases *)
2663
| TFun _ when not theMachine.msvcMode ->
2664
theMachine.theMachine.alignof_fun
2665
| TFun _ as t -> raise (SizeOfError ("function", t))
2666
| TVoid _ as t -> raise (SizeOfError ("void", t))
2669
let bitsSizeOfInt (ik: ikind): int =
2671
| IBool | IChar | ISChar | IUChar -> 8
2672
| IInt | IUInt -> 8 * theMachine.theMachine.sizeof_int
2673
| IShort | IUShort -> 8 * theMachine.theMachine.sizeof_short
2674
| ILong | IULong -> 8 * theMachine.theMachine.sizeof_long
2675
| ILongLong | IULongLong ->
2676
8 * theMachine.theMachine.sizeof_longlong
2678
let unsignedVersionOf (ik:ikind): ikind =
2680
| ISChar | IChar -> IUChar
2684
| ILongLong -> IULongLong
2687
(* Represents an integer as for a given kind.
2688
Returns a flag saying whether the value was changed
2689
during truncation (because it was too large to fit in k). *)
2690
let truncateInteger64 (k: ikind) (i: int64) : int64 * bool =
2691
let nrBits = bitsSizeOfInt k in
2692
let signed = isSigned k in
2696
let i1 = Int64.shift_left i (64 - nrBits) in
2698
if signed then Int64.shift_right i1 (64 - nrBits)
2699
else Int64.shift_right_logical i1 (64 - nrBits)
2702
if i2 = i then false
2704
(* Examine the bits that we chopped off. If they are all zero, then
2705
* any difference between i2 and i is due to a simple sign-extension.
2706
* e.g. casting the constant 0x80000000 to int makes it
2707
* 0xffffffff80000000.
2708
* Suppress the truncation warning in this case. *)
2709
let chopped = Int64.shift_right_logical i (64 - nrBits)
2710
in chopped <> Int64.zero
2715
(* Construct an integer constant with possible truncation *)
2716
let kinteger64 (k: ikind) (i: int64) : exp =
2717
let i', truncated = truncateInteger64 k i in
2718
if truncated && miscState.warnTruncate then
2719
ignore (warnOpt "Truncating integer %s to %s\n"
2720
(Int64.format "0x%x" i) (Int64.format "0x%x" i'));
2721
Const (CInt64(i', k, None))
2723
(* Construct an integer of a given kind. *)
2724
let kinteger (k: ikind) (i: int) = kinteger64 k (Int64.of_int i)
2726
(* Convert 2 integer constants to integers with the same type, in preparation
2727
for a binary operation. See ISO C 6.3.1.8p1 *)
2728
let convertInts (i1:int64) (ik1:ikind) (i2:int64) (ik2:ikind)
2729
: int64 * int64 * ikind =
2730
if ik1 = ik2 then (* nothing to do *)
2733
let rank : ikind -> int = function
2734
(* these are just unique numbers representing the integer
2736
| IBool | IChar | ISChar | IUChar -> 1
2737
| IShort | IUShort -> 2
2739
| ILong | IULong -> 4
2740
| ILongLong | IULongLong -> 5
2742
let r1 = rank ik1 in
2743
let r2 = rank ik2 in
2745
if (isSigned ik1) = (isSigned ik2) then begin
2746
(* Both signed or both unsigned. *)
2747
if r1 > r2 then ik1 else ik2
2750
let signedKind, unsignedKind, signedRank, unsignedRank =
2751
if isSigned ik1 then ik1, ik2, r1, r2 else ik2, ik1, r2, r1
2753
(* The rules for signed + unsigned get hairy.
2754
(unsigned short + long) is converted to signed long,
2755
but (unsigned int + long) is converted to unsigned long.*)
2756
if unsignedRank >= signedRank then unsignedKind
2757
else if (bytesSizeOfInt signedKind) > (bytesSizeOfInt unsignedKind) then
2760
unsignedVersionOf signedKind
2763
let i1',_ = truncateInteger64 ik' i1 in
2764
let i2',_ = truncateInteger64 ik' i2 in
2769
{ oaFirstFree: int; (* The first free bit *)
2770
oaLastFieldStart: int; (* Where the previous field started *)
2771
oaLastFieldWidth: int; (* The width of the previous field. Might not
2772
* be same as FirstFree - FieldStart because
2773
* of internal padding *)
2774
oaPrevBitPack: (int * ikind * int) option; (* If the previous fields
2775
* were packed bitfields,
2776
* the bit where packing
2777
* has started, the ikind
2778
* of the bitfield and the
2779
* width of the ikind *)
2784
(* Does not use the sofar.oaPrevBitPack *)
2785
let rec offsetOfFieldAcc_GCC (fi: fieldinfo)
2786
(sofar: offsetAcc) : offsetAcc =
2788
let ftype = unrollType fi.ftype in
2789
let ftypeAlign = 8 * alignOf_int ftype in
2790
let ftypeBits = bitsSizeOf ftype in
2792
if fi.fcomp.cname = "comp2468" ||
2793
fi.fcomp.cname = "comp2469" ||
2794
fi.fcomp.cname = "comp2470" ||
2795
fi.fcomp.cname = "comp2471" ||
2796
fi.fcomp.cname = "comp2472" ||
2797
fi.fcomp.cname = "comp2473" ||
2798
fi.fcomp.cname = "comp2474" ||
2799
fi.fcomp.cname = "comp2475" ||
2800
fi.fcomp.cname = "comp2476" ||
2801
fi.fcomp.cname = "comp2477" ||
2802
fi.fcomp.cname = "comp2478" then
2804
ignore (E.log "offsetOfFieldAcc_GCC(%s of %s:%a%a,firstFree=%d,pack=%a)\n"
2805
fi.fname fi.fcomp.cname
2808
(match fi.fbitfield with
2810
| Some wdthis -> dprintf ":%d" wdthis)
2813
(match sofar.oaPrevBitPack with
2815
| Some (packstart, _, wdpack) ->
2816
dprintf "Some(packstart=%d,wd=%d)"
2819
match ftype, fi.fbitfield with
2820
(* A width of 0 means that we must end the current packing. It seems that
2821
* GCC pads only up to the alignment boundary for the type of this field.
2824
let firstFree = addTrailing sofar.oaFirstFree ftypeAlign in
2825
{ oaFirstFree = firstFree;
2826
oaLastFieldStart = firstFree;
2827
oaLastFieldWidth = 0;
2828
oaPrevBitPack = None }
2830
(* A bitfield cannot span more alignment boundaries of its type than the
2833
when (sofar.oaFirstFree + wdthis + ftypeAlign - 1) / ftypeAlign
2834
- sofar.oaFirstFree / ftypeAlign > ftypeBits / ftypeAlign ->
2835
let start = addTrailing sofar.oaFirstFree ftypeAlign in
2836
{ oaFirstFree = start + wdthis;
2837
oaLastFieldStart = start;
2838
oaLastFieldWidth = wdthis;
2839
oaPrevBitPack = None }
2841
(* Try a simple method. Just put the field down *)
2843
{ oaFirstFree = sofar.oaFirstFree + wdthis;
2844
oaLastFieldStart = sofar.oaFirstFree;
2845
oaLastFieldWidth = wdthis;
2846
oaPrevBitPack = None
2851
(* Align this field *)
2852
let newStart = addTrailing sofar.oaFirstFree ftypeAlign in
2853
{ oaFirstFree = newStart + ftypeBits;
2854
oaLastFieldStart = newStart;
2855
oaLastFieldWidth = ftypeBits;
2856
oaPrevBitPack = None;
2860
and offsetOfFieldAcc_MSVC (fi: fieldinfo)
2861
(sofar: offsetAcc) : offsetAcc =
2863
let ftype = unrollType fi.ftype in
2864
let ftypeAlign = 8 * alignOf_int ftype in
2865
let ftypeBits = bitsSizeOf ftype in
2867
ignore (E.log "offsetOfFieldAcc_MSVC(%s of %s:%a%a,firstFree=%d, pack=%a)\n"
2868
fi.fname fi.fcomp.cname
2871
(match fi.fbitfield with
2873
| Some wdthis -> dprintf ":%d" wdthis)
2876
(match sofar.oaPrevBitPack with
2878
| Some (prevpack, _, wdpack) -> dprintf "Some(prev=%d,wd=%d)"
2881
match ftype, fi.fbitfield, sofar.oaPrevBitPack with
2882
(* Ignore zero-width bitfields that come after non-bitfields *)
2883
| TInt (_ikthis, _), Some 0, None ->
2884
let firstFree = sofar.oaFirstFree in
2885
{ oaFirstFree = firstFree;
2886
oaLastFieldStart = firstFree;
2887
oaLastFieldWidth = 0;
2888
oaPrevBitPack = None }
2890
(* If we are in a bitpack and we see a bitfield for a type with the
2891
* different width than the pack, then we finish the pack and retry *)
2892
| _, Some _, Some (packstart, _, wdpack) when wdpack != ftypeBits ->
2894
if sofar.oaFirstFree = packstart then packstart else
2897
offsetOfFieldAcc_MSVC fi
2898
{ oaFirstFree = addTrailing firstFree ftypeAlign;
2899
oaLastFieldStart = sofar.oaLastFieldStart;
2900
oaLastFieldWidth = sofar.oaLastFieldWidth;
2901
oaPrevBitPack = None }
2903
(* A width of 0 means that we must end the current packing. *)
2904
| TInt (ikthis, _), Some 0, Some (packstart, _, wdpack) ->
2906
if sofar.oaFirstFree = packstart then packstart else
2909
let firstFree = addTrailing firstFree ftypeAlign in
2910
{ oaFirstFree = firstFree;
2911
oaLastFieldStart = firstFree;
2912
oaLastFieldWidth = 0;
2913
oaPrevBitPack = Some (firstFree, ikthis, ftypeBits) }
2915
(* Check for a bitfield that fits in the current pack after some other
2917
| TInt(_ikthis, _), Some wdthis, Some (packstart, _ikprev, wdpack)
2918
when packstart + wdpack >= sofar.oaFirstFree + wdthis ->
2919
{ oaFirstFree = sofar.oaFirstFree + wdthis;
2920
oaLastFieldStart = sofar.oaFirstFree;
2921
oaLastFieldWidth = wdthis;
2922
oaPrevBitPack = sofar.oaPrevBitPack
2926
| _, _, Some (packstart, _, wdpack) -> (* Finish up the bitfield pack and
2929
if sofar.oaFirstFree = packstart then packstart else
2932
offsetOfFieldAcc_MSVC fi
2933
{ oaFirstFree = addTrailing firstFree ftypeAlign;
2934
oaLastFieldStart = sofar.oaLastFieldStart;
2935
oaLastFieldWidth = sofar.oaLastFieldWidth;
2936
oaPrevBitPack = None }
2938
(* No active bitfield pack. But we are seeing a bitfield. *)
2939
| TInt(ikthis, _), Some wdthis, None ->
2940
let firstFree = addTrailing sofar.oaFirstFree ftypeAlign in
2941
{ oaFirstFree = firstFree + wdthis;
2942
oaLastFieldStart = firstFree;
2943
oaLastFieldWidth = wdthis;
2944
oaPrevBitPack = Some (firstFree, ikthis, ftypeBits); }
2946
(* No active bitfield pack. Non-bitfield *)
2948
(* Align this field *)
2949
let firstFree = addTrailing sofar.oaFirstFree ftypeAlign in
2950
{ oaFirstFree = firstFree + ftypeBits;
2951
oaLastFieldStart = firstFree;
2952
oaLastFieldWidth = ftypeBits;
2953
oaPrevBitPack = None;
2956
| _, Some _, None -> E.s (E.bug "offsetAcc")
2959
and offsetOfFieldAcc ~(fi: fieldinfo)
2960
~(sofar: offsetAcc) : offsetAcc =
2961
if theMachine.msvcMode then offsetOfFieldAcc_MSVC fi sofar
2962
else offsetOfFieldAcc_GCC fi sofar
2964
(* The size of a type, in bits. If struct or array then trailing padding is
2967
if not (TheMachine.is_computed ()) then
2968
E.s (E.error "You did not call Cil.initCIL before using the CIL library");
2970
| TInt (ik,_) -> 8 * (bytesSizeOfInt ik)
2971
| TFloat(FDouble, _) -> 8 * theMachine.theMachine.sizeof_double
2972
| TFloat(FLongDouble, _) ->
2973
8 * theMachine.theMachine.sizeof_longdouble
2974
| TFloat _ -> 8 * theMachine.theMachine.sizeof_float
2975
| TEnum _ -> 8 * theMachine.theMachine.sizeof_enum
2976
| TPtr _ -> 8 * theMachine.theMachine.sizeof_ptr
2977
| TBuiltin_va_list _ -> 8 * theMachine.theMachine.sizeof_ptr
2978
| TNamed (t, _) -> bitsSizeOf t.ttype
2979
| TComp (comp, _) when comp.cfields == [] -> begin
2980
(* Empty structs are allowed in msvc mode *)
2981
if not comp.cdefined && not theMachine.msvcMode then
2985
"abstract type: empty struct exist only with MSVC (comp %s)"
2986
(compFullName comp),
2987
t)) (*abstract type*)
2992
| TComp (comp, _) when comp.cstruct -> (* Struct *)
2993
(* Go and get the last offset *)
2996
oaLastFieldStart = 0;
2997
oaLastFieldWidth = 0;
2998
oaPrevBitPack = None;
3001
List.fold_left (fun acc fi -> offsetOfFieldAcc ~fi ~sofar:acc)
3002
startAcc comp.cfields
3004
if theMachine.msvcMode && lastoff.oaFirstFree = 0 && comp.cfields <> []
3006
(* On MSVC if we have just a zero-width bitfields then the length
3007
* is 32 and is not padded *)
3010
addTrailing lastoff.oaFirstFree (8 * alignOf_int t)
3012
| TComp (comp, _) -> (* when not comp.cstruct *)
3013
(* Get the maximum of all fields *)
3016
oaLastFieldStart = 0;
3017
oaLastFieldWidth = 0;
3018
oaPrevBitPack = None;
3021
List.fold_left (fun acc fi ->
3022
let lastoff = offsetOfFieldAcc ~fi ~sofar:startAcc in
3023
if lastoff.oaFirstFree > acc then
3024
lastoff.oaFirstFree else acc) 0 comp.cfields in
3025
(* Add trailing by simulating adding an extra field *)
3026
addTrailing max (8 * alignOf_int t)
3028
| TArray(bt, Some len, _) -> begin
3029
match constFold true len with
3030
Const(CInt64(l,_,_)) ->
3031
let sz = Int64.mul (Int64.of_int (bitsSizeOf bt)) l in
3032
let sz' = Int64.to_int sz in
3033
(* Check for overflow.
3034
There are other places in these cil.ml that overflow can occur,
3035
but this multiplication is the most likely to be a problem. *)
3036
if (Int64.of_int sz') <> sz then
3037
raise (SizeOfError ("Array is so long that its size can't be "
3038
^"represented with an OCaml int.", t))
3041
sz' (*WAS: addTrailing sz' (8 * alignOf_int t)*)
3043
| _ -> raise (SizeOfError ("array non-constant length", t))
3046
| TVoid _ -> 8 * theMachine.theMachine.sizeof_void
3047
| TFun _ when not theMachine.msvcMode ->
3048
(* On GCC the size of a function is defined *)
3049
8 * theMachine.theMachine.sizeof_fun
3051
| TArray (_, None, _) -> (* it seems that on GCC the size of such an
3055
| TFun _ -> raise (SizeOfError ("function", t))
3058
and addTrailing nrbits roundto =
3059
(nrbits + roundto - 1) land (lnot (roundto - 1))
3061
and sizeOf_int t = (bitsSizeOf t) lsr 3
3065
integer ((bitsSizeOf t) lsr 3)
3066
with SizeOfError _ -> SizeOf(t)
3069
and bitsOffset (baset: typ) (off: offset) : int * int =
3070
let rec loopOff (baset: typ) (width: int) (start: int) = function
3071
NoOffset -> start, width
3072
| Index(e, off) -> begin
3074
match isInteger e with
3075
Some i64 -> Int64.to_int i64
3076
| None -> raise (SizeOfError ("index not constant", baset))
3079
match unrollType baset with
3080
TArray(bt, _, _) -> bt
3081
| _ -> E.s (E.bug "bitsOffset: Index on a non-array")
3083
let bitsbt = bitsSizeOf bt in
3084
loopOff bt bitsbt (start + ei * bitsbt) off
3086
| Field(f, off) when not f.fcomp.cstruct ->
3087
(* All union fields start at offset 0 *)
3088
loopOff f.ftype (bitsSizeOf f.ftype) start off
3091
(* Construct a list of fields preceeding and including this one *)
3093
let rec loop = function
3094
[] -> E.s (E.bug "bitsOffset: Cannot find field %s in %s\n"
3095
f.fname f.fcomp.cname)
3096
| fi' :: _ when fi' == f -> [fi']
3097
| fi' :: rest -> fi' :: loop rest
3099
loop f.fcomp.cfields
3102
List.fold_left (fun acc fi' -> offsetOfFieldAcc ~fi:fi' ~sofar:acc)
3103
{ oaFirstFree = 0; (* Start at 0 because each struct is done
3105
oaLastFieldStart = 0;
3106
oaLastFieldWidth = 0;
3107
oaPrevBitPack = None } prevflds
3109
(* ignore (E.log "Field %s of %s: start=%d, lastFieldStart=%d\n"
3110
f.fname f.fcomp.cname start lastoff.oaLastFieldStart); *)
3111
loopOff f.ftype lastoff.oaLastFieldWidth
3112
(start + lastoff.oaLastFieldStart) off
3114
loopOff baset (bitsSizeOf baset) 0 off
3119
(** Do constant folding on an expression. If the first argument is true then
3120
will also compute compiler-dependent expressions such as sizeof.
3121
See also {!Cil.constFoldVisitor}, which will run constFold on all
3122
expressions in a given AST node.*)
3123
and constFold (machdep: bool) (e: exp) : exp =
3125
BinOp(bop, e1, e2, tres) -> constFoldBinOp machdep bop e1 e2 tres
3126
| UnOp(unop, e1, tres) -> begin
3129
match unrollType tres with
3132
| _ -> raise Not_found (* probably a float *)
3134
match constFold machdep e1 with
3135
Const(CInt64(i,_ik,_)) -> begin
3137
Neg -> kinteger64 tk (Int64.neg i)
3138
| BNot -> kinteger64 tk (Int64.lognot i)
3139
| LNot -> if i = Int64.zero then one else zero
3141
| e1c -> UnOp(unop, e1c, tres)
3144
(* Characters are integers *)
3145
| Const(CChr c) -> Const(charConstToInt c)
3146
| Const(CEnum {eival = v}) -> constFold machdep v
3147
| SizeOf t when machdep -> begin
3149
let bs = bitsSizeOf t in
3150
kinteger theMachine.kindOfSizeOf (bs / 8)
3151
with SizeOfError _ -> e
3153
| SizeOfE e when machdep -> constFold machdep (SizeOf (typeOf e))
3154
| SizeOfStr s when machdep ->
3155
kinteger theMachine.kindOfSizeOf (1 + String.length s)
3156
| AlignOf t when machdep -> kinteger theMachine.kindOfSizeOf (alignOf_int t)
3157
| AlignOfE e when machdep -> begin
3158
(* The alignment of an expression is not always the alignment of its
3159
* type. I know that for strings this is not true *)
3161
Const (CStr _) when not theMachine.msvcMode ->
3162
kinteger theMachine.kindOfSizeOf theMachine.theMachine.alignof_str
3163
(* For an array, it is the alignment of the array ! *)
3164
| _ -> constFold machdep (AlignOf (typeOf e))
3168
AddrOf (Mem (CastE(TPtr(bt, _), z)), off))
3169
when machdep && isZero z -> begin
3171
let start, _width = bitsOffset bt off in
3172
if start mod 8 <> 0 then
3173
E.s (error "Using offset of bitfield\n");
3174
constFold machdep (CastE(it, (integer (start / 8))))
3175
with SizeOfError _ -> e
3179
| CastE (t, e) -> begin
3180
match constFold machdep e, unrollType t with
3181
(* Might truncate silently *)
3182
Const(CInt64(i,_k,_)), TInt(nk,a)
3183
(* It's okay to drop a cast to const.
3184
If the cast has any other attributes, leave the cast alone. *)
3185
when (dropAttributes ["const"] a) = [] ->
3186
let i', _ = truncateInteger64 nk i in
3187
Const(CInt64(i', nk, None))
3188
| e', _ -> CastE (t, e')
3190
| Lval lv -> Lval (constFoldLval machdep lv)
3191
| AddrOf lv -> AddrOf (constFoldLval machdep lv)
3192
| StartOf lv -> StartOf (constFoldLval machdep lv)
3195
and constFoldLval machdep (host,offset) =
3198
| Mem e -> Mem (constFold machdep e)
3201
let rec constFoldOffset machdep = function
3202
| NoOffset -> NoOffset
3203
| Field (fi,offset) -> Field (fi, constFoldOffset machdep offset)
3204
| Index (exp,offset) -> Index (constFold machdep exp,
3205
constFoldOffset machdep offset)
3207
(newhost, constFoldOffset machdep offset)
3209
and constFoldBinOp (machdep: bool) bop e1 e2 tres =
3210
let e1' = constFold machdep e1 in
3211
let e2' = constFold machdep e2 in
3212
if isIntegralType tres then begin
3214
let rec mkInt = function
3215
Const(CChr c) -> Const(charConstToInt c)
3216
| Const(CEnum {eival = v}) -> mkInt v
3217
| CastE(TInt (ik, ta), e) -> begin
3219
Const(CInt64(i, _, _)) ->
3220
let i', _ = truncateInteger64 ik i in
3221
Const(CInt64(i', ik, None))
3223
| e' -> CastE(TInt(ik, ta), e')
3228
match unrollType tres with
3231
| _ -> E.s (bug "constFoldBinOp")
3233
(* See if the result is unsigned *)
3234
let isunsigned typ = not (isSigned typ) in
3235
let ge (unsigned: bool) (i1: int64) (i2: int64) : bool =
3237
let l1 = Int64.shift_right_logical i1 1 in
3238
let l2 = Int64.shift_right_logical i2 1 in (* Both positive now *)
3239
(l1 > l2) || (l1 = l2 &&
3240
Int64.logand i1 Int64.one >= Int64.logand i2 Int64.one)
3243
let shiftInBounds i2 =
3244
(* We only try to fold shifts if the second arg is positive and
3245
less than the size of the type of the first argument.
3246
Otherwise, the semantics are processor-dependent, so let the compiler sort it out. *)
3247
(* We only try to fold shifts if the second arg is positive and
3248
less than the size of the type of the first argument.
3249
Otherwise, the semantics are processor-dependent, so let the
3250
compiler sort it out. *)
3253
i2 >= Int64.zero && i2 < (Int64.of_int (bitsSizeOf (typeOf e1')))
3254
with SizeOfError _ -> false
3257
(* Assume that the necessary promotions have been done *)
3258
match bop, mkInt e1', mkInt e2' with
3259
| PlusA, Const(CInt64(z,_,_)), e2'' when z = Int64.zero -> e2''
3260
| PlusA, e1'', Const(CInt64(z,_,_)) when z = Int64.zero -> e1''
3261
| PlusPI, e1'', Const(CInt64(z,_,_)) when z = Int64.zero -> e1''
3262
| IndexPI, e1'', Const(CInt64(z,_,_)) when z = Int64.zero -> e1''
3263
| MinusPI, e1'', Const(CInt64(z,_,_)) when z = Int64.zero -> e1''
3264
| PlusA, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
3265
kinteger64 tk (Int64.add i1 i2)
3266
| MinusA, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
3267
kinteger64 tk (Int64.sub i1 i2)
3268
| Mult, Const(CInt64(i1,ik1,_)), Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
3269
kinteger64 tk (Int64.mul i1 i2)
3270
| Mult, Const(CInt64(0L,_,_)), _ -> zero
3271
| Mult, Const(CInt64(1L,_,_)), e2'' -> e2''
3272
| Mult, _, Const(CInt64(0L,_,_)) -> zero
3273
| Mult, e1'', Const(CInt64(1L,_,_)) -> e1''
3274
| Div, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 -> begin
3275
try kinteger64 tk (Int64.div i1 i2)
3276
with Division_by_zero -> BinOp(bop, e1', e2', tres)
3278
| Div, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_))
3279
when bytesSizeOfInt ik1 = bytesSizeOfInt ik2 -> begin
3280
try kinteger64 tk (Int64.div i1 i2)
3281
with Division_by_zero -> BinOp(bop, e1', e2', tres)
3283
| Div, e1'', Const(CInt64(1L,_,_)) -> e1''
3285
| Mod, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 -> begin
3286
try kinteger64 tk (Int64.rem i1 i2)
3287
with Division_by_zero -> BinOp(bop, e1', e2', tres)
3289
| BAnd, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
3290
kinteger64 tk (Int64.logand i1 i2)
3291
| BAnd, Const(CInt64(0L,_,_)), _ -> zero
3292
| BAnd, _, Const(CInt64(0L,_,_)) -> zero
3293
| BOr, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
3294
kinteger64 tk (Int64.logor i1 i2)
3295
| BOr, _, _ when isZero e1' -> e2'
3296
| BOr, _, _ when isZero e2' -> e1'
3297
| BXor, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
3298
kinteger64 tk (Int64.logxor i1 i2)
3300
| Shiftlt, Const(CInt64(i1,_ik1,_)),Const(CInt64(i2,_,_)) when shiftInBounds i2 ->
3301
kinteger64 tk (Int64.shift_left i1 (Int64.to_int i2))
3302
| Shiftlt, Const(CInt64(0L,_,_)), _ -> zero
3303
| Shiftlt, e1'', Const(CInt64(0L,_,_)) -> e1''
3305
| Shiftrt, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,_,_)) when shiftInBounds i2 ->
3306
if isunsigned ik1 then
3307
kinteger64 tk (Int64.shift_right_logical i1 (Int64.to_int i2))
3309
kinteger64 tk (Int64.shift_right i1 (Int64.to_int i2))
3310
| Shiftrt, Const(CInt64(0L,_,_)), _ -> zero
3311
| Shiftrt, e1'', Const(CInt64(0L,_,_)) -> e1''
3313
| Eq, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) ->
3314
let i1', i2', _ = convertInts i1 ik1 i2 ik2 in
3315
if i1' = i2' then one else zero
3316
| Ne, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) ->
3317
let i1', i2', _ = convertInts i1 ik1 i2 ik2 in
3318
if i1' <> i2' then one else zero
3319
| Le, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) ->
3320
let i1', i2', ik' = convertInts i1 ik1 i2 ik2 in
3321
if ge (isunsigned ik') i2' i1' then one else zero
3323
| Ge, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) ->
3324
let i1', i2', ik' = convertInts i1 ik1 i2 ik2 in
3325
if ge (isunsigned ik') i1' i2' then one else zero
3327
| Lt, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) ->
3328
let i1', i2', ik' = convertInts i1 ik1 i2 ik2 in
3329
if i1' <> i2' && ge (isunsigned ik') i2' i1' then one else zero
3331
| Gt, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) ->
3332
let i1', i2', ik' = convertInts i1 ik1 i2 ik2 in
3333
if i1 <> i2 && ge (isunsigned ik') i1' i2' then one else zero
3335
(* We rely on the fact that LAnd/LOr appear in global initializers
3336
and should not have side effects. *)
3337
| LAnd, _, _ when isZero e1' || isZero e2' -> zero
3338
| LAnd, _, _ when isInteger e1' <> None -> e2' (* e1' is TRUE *)
3339
| LAnd, _, _ when isInteger e2' <> None -> e1' (* e2' is TRUE *)
3340
| LOr, _, _ when isZero e1' -> e2'
3341
| LOr, _, _ when isZero e2' -> e1'
3342
| LOr, _, _ when isInteger e1' <> None || isInteger e2' <> None ->
3343
(* One of e1' or e2' is a nonzero constant *)
3345
| _ -> BinOp(bop, e1', e2', tres)
3347
if debugConstFold then
3348
ignore (log "Folded %a to %a\n"
3349
(!pd_exp) (BinOp(bop, e1', e2', tres)) (!pd_exp) newe);
3352
BinOp(bop, e1', e2', tres)
3354
(* CEA: moved from cabs2cil.ml. See cil.mli for infos *)
3356
* multi-character character constants
3357
* In MSCV, this code works:
3359
* long l1 = 'abcd'; // note single quotes
3360
* char * s = "dcba";
3361
* long * lptr = ( long * )s;
3365
* We need to change a multi-character character literal into the
3366
* appropriate integer constant. However, the plot sickens: we
3367
* must also be able to handle things like 'ab\nd' (value = * "d\nba")
3368
* and 'abc' (vale = *"cba").
3370
* First we convert 'AB\nD' into the list [ 65 ; 66 ; 10 ; 68 ], then we
3371
* multiply and add to get the desired value.
3374
(* Given a character constant (like 'a' or 'abc') as a list of 64-bit
3375
* values, turn it into a CIL constant. Multi-character constants are
3376
* treated as multi-digit numbers with radix given by the bit width of
3377
* the specified type (either char or wchar_t). *)
3378
let reduce_multichar typ : int64 list -> int64 =
3379
let radix = bitsSizeOf typ in
3381
(fun acc -> Int64.add (Int64.shift_left acc radix))
3384
let interpret_character_constant char_list =
3385
let value = reduce_multichar charType char_list in
3386
if value < (Int64.of_int 256) then
3387
(* ISO C 6.4.4.4.10: single-character constants have type int *)
3388
(CChr(Char.chr (Int64.to_int value))), intType
3390
let orig_rep = None (* Some("'" ^ (String.escaped str) ^ "'") *) in
3391
if value <= (Int64.of_int32 Int32.max_int) then
3392
(CInt64(value,IULong,orig_rep)),(TInt(IULong,[]))
3394
(CInt64(value,IULongLong,orig_rep)),(TInt(IULongLong,[]))
3410
PlusA | PlusPI | IndexPI -> "+"
3411
| MinusA | MinusPP | MinusPI -> "-"
3429
let d_term_binop fmt b =
3432
PlusA | PlusPI | IndexPI -> "+"
3433
| MinusA | MinusPP | MinusPI -> "-"
3441
| Le -> if !print_utf8 then Utf8_logic.le else "<="
3442
| Ge -> if !print_utf8 then Utf8_logic.ge else ">="
3443
| Eq -> if !print_utf8 then Utf8_logic.eq else "=="
3444
| Ne -> if !print_utf8 then Utf8_logic.neq else "!="
3448
| LAnd -> if !print_utf8 then Utf8_logic.conj else "&&"
3449
| LOr -> if !print_utf8 then Utf8_logic.disj else "||")
3451
let d_relation fmt b =
3456
| Rle -> if !print_utf8 then Utf8_logic.le else "<="
3457
| Rge -> if !print_utf8 then Utf8_logic.ge else ">="
3458
| Req -> if !print_utf8 then Utf8_logic.eq else "=="
3459
| Rneq -> if !print_utf8 then Utf8_logic.neq else "!=")
3461
let invalidStmt = mkStmt (Instr (Skip locUnknown))
3463
module BuiltinFunctions =
3465
(struct type t = string let equal = (=) let hash = Hashtbl.hash end)
3466
(Project.Datatype.Imperative
3468
type t = typ * typ list * bool
3469
let copy _ = assert false (* TODO *)
3470
let name = "builtinFunctions"
3473
let name = "BuiltinFunctions"
3474
let dependencies = [ TheMachine.self ]
3478
(* Initialize the builtin functions after the machine has been initialized. *)
3479
let initGccBuiltins () : unit =
3480
if not (TheMachine.is_computed ()) then
3481
E.s (bug "Call initCIL before initGccBuiltins");
3482
if BuiltinFunctions.length () <> 0 then
3483
E.s (bug "builtins already initialized.");
3484
(* See if we have builtin_va_list *)
3485
let hasbva = Machdep.state.Machdep.gccHas__builtin_va_list in
3486
let ulongLongType = TInt(IULongLong, []) in
3487
let floatType = TFloat(FFloat, []) in
3488
let longDoubleType = TFloat (FLongDouble, []) in
3489
let voidConstPtrType = TPtr(TVoid [Attr ("const", [])], []) in
3490
let sizeType = theMachine.upointType in
3492
BuiltinFunctions.add "__builtin___fprintf_chk" (intType, [ voidPtrType; intType; charConstPtrType ], true) (* first argument is really FILE*, not void*, but we don't want to build in the definition for FILE *);
3493
BuiltinFunctions.add "__builtin___memcpy_chk" (voidPtrType, [ voidPtrType; voidConstPtrType; sizeType; sizeType ], false);
3494
BuiltinFunctions.add "__builtin___memmove_chk" (voidPtrType, [ voidPtrType; voidConstPtrType; sizeType; sizeType ], false);
3495
BuiltinFunctions.add "__builtin___mempcpy_chk" (voidPtrType, [ voidPtrType; voidConstPtrType; sizeType; sizeType ], false);
3496
BuiltinFunctions.add "__builtin___memset_chk" (voidPtrType, [ voidPtrType; intType; sizeType; sizeType ], false);
3497
BuiltinFunctions.add "__builtin___printf_chk" (intType, [ intType; charConstPtrType ], true);
3498
BuiltinFunctions.add "__builtin___snprintf_chk" (intType, [ charPtrType; sizeType; intType; sizeType; charConstPtrType ], true);
3499
BuiltinFunctions.add "__builtin___sprintf_chk" (intType, [ charPtrType; intType; sizeType; charConstPtrType ], true);
3500
BuiltinFunctions.add "__builtin___stpcpy_chk" (charPtrType, [ charPtrType; charConstPtrType; sizeType ], false);
3501
BuiltinFunctions.add "__builtin___strcat_chk" (charPtrType, [ charPtrType; charConstPtrType; sizeType ], false);
3502
BuiltinFunctions.add "__builtin___strcpy_chk" (charPtrType, [ charPtrType; charConstPtrType; sizeType ], false);
3503
BuiltinFunctions.add "__builtin___strncat_chk" (charPtrType, [ charPtrType; charConstPtrType; sizeType; sizeType ], false);
3504
BuiltinFunctions.add "__builtin___strncpy_chk" (charPtrType, [ charPtrType; charConstPtrType; sizeType; sizeType ], false);
3505
BuiltinFunctions.add "__builtin___vfprintf_chk" (intType, [ voidPtrType; intType; charConstPtrType; TBuiltin_va_list [] ], false) (* first argument is really FILE*, not void*, but we don't want to build in the definition for FILE *);
3506
BuiltinFunctions.add "__builtin___vprintf_chk" (intType, [ intType; charConstPtrType; TBuiltin_va_list [] ], false);
3507
BuiltinFunctions.add "__builtin___vsnprintf_chk" (intType, [ charPtrType; sizeType; intType; sizeType; charConstPtrType; TBuiltin_va_list [] ], false);
3508
BuiltinFunctions.add "__builtin___vsprintf_chk" (intType, [ charPtrType; intType; sizeType; charConstPtrType; TBuiltin_va_list [] ], false);
3510
BuiltinFunctions.add "__builtin_acos" (doubleType, [ doubleType ], false);
3511
BuiltinFunctions.add "__builtin_acosf" (floatType, [ floatType ], false);
3512
BuiltinFunctions.add "__builtin_acosl" (longDoubleType, [ longDoubleType ], false);
3514
BuiltinFunctions.add "__builtin_alloca" (voidPtrType, [ sizeType ], false);
3516
BuiltinFunctions.add "__builtin_asin" (doubleType, [ doubleType ], false);
3517
BuiltinFunctions.add "__builtin_asinf" (floatType, [ floatType ], false);
3518
BuiltinFunctions.add "__builtin_asinl" (longDoubleType, [ longDoubleType ], false);
3520
BuiltinFunctions.add "__builtin_atan" (doubleType, [ doubleType ], false);
3521
BuiltinFunctions.add "__builtin_atanf" (floatType, [ floatType ], false);
3522
BuiltinFunctions.add "__builtin_atanl" (longDoubleType, [ longDoubleType ], false);
3524
BuiltinFunctions.add "__builtin_atan2" (doubleType, [ doubleType; doubleType ], false);
3525
BuiltinFunctions.add "__builtin_atan2f" (floatType, [ floatType; floatType ], false);
3526
BuiltinFunctions.add "__builtin_atan2l" (longDoubleType, [ longDoubleType;
3527
longDoubleType ], false);
3529
BuiltinFunctions.add "__builtin_ceil" (doubleType, [ doubleType ], false);
3530
BuiltinFunctions.add "__builtin_ceilf" (floatType, [ floatType ], false);
3531
BuiltinFunctions.add "__builtin_ceill" (longDoubleType, [ longDoubleType ], false);
3533
BuiltinFunctions.add "__builtin_cos" (doubleType, [ doubleType ], false);
3534
BuiltinFunctions.add "__builtin_cosf" (floatType, [ floatType ], false);
3535
BuiltinFunctions.add "__builtin_cosl" (longDoubleType, [ longDoubleType ], false);
3537
BuiltinFunctions.add "__builtin_cosh" (doubleType, [ doubleType ], false);
3538
BuiltinFunctions.add "__builtin_coshf" (floatType, [ floatType ], false);
3539
BuiltinFunctions.add "__builtin_coshl" (longDoubleType, [ longDoubleType ], false);
3541
BuiltinFunctions.add "__builtin_clz" (intType, [ uintType ], false);
3542
BuiltinFunctions.add "__builtin_clzl" (intType, [ ulongType ], false);
3543
BuiltinFunctions.add "__builtin_clzll" (intType, [ ulongLongType ], false);
3544
BuiltinFunctions.add "__builtin_constant_p" (intType, [ intType ], false);
3545
BuiltinFunctions.add "__builtin_ctz" (intType, [ uintType ], false);
3546
BuiltinFunctions.add "__builtin_ctzl" (intType, [ ulongType ], false);
3547
BuiltinFunctions.add "__builtin_ctzll" (intType, [ ulongLongType ], false);
3549
BuiltinFunctions.add "__builtin_exp" (doubleType, [ doubleType ], false);
3550
BuiltinFunctions.add "__builtin_expf" (floatType, [ floatType ], false);
3551
BuiltinFunctions.add "__builtin_expl" (longDoubleType, [ longDoubleType ], false);
3553
BuiltinFunctions.add "__builtin_expect" (longType, [ longType; longType ], false);
3555
BuiltinFunctions.add "__builtin_fabs" (doubleType, [ doubleType ], false);
3556
BuiltinFunctions.add "__builtin_fabsf" (floatType, [ floatType ], false);
3557
BuiltinFunctions.add "__builtin_fabsl" (longDoubleType, [ longDoubleType ], false);
3559
BuiltinFunctions.add "__builtin_ffs" (intType, [ uintType ], false);
3560
BuiltinFunctions.add "__builtin_ffsl" (intType, [ ulongType ], false);
3561
BuiltinFunctions.add "__builtin_ffsll" (intType, [ ulongLongType ], false);
3562
BuiltinFunctions.add "__builtin_frame_address" (voidPtrType, [ uintType ], false);
3564
BuiltinFunctions.add "__builtin_floor" (doubleType, [ doubleType ], false);
3565
BuiltinFunctions.add "__builtin_floorf" (floatType, [ floatType ], false);
3566
BuiltinFunctions.add "__builtin_floorl" (longDoubleType, [ longDoubleType ], false);
3568
BuiltinFunctions.add "__builtin_huge_val" (doubleType, [], false);
3569
BuiltinFunctions.add "__builtin_huge_valf" (floatType, [], false);
3570
BuiltinFunctions.add "__builtin_huge_vall" (longDoubleType, [], false);
3571
BuiltinFunctions.add "__builtin_inf" (doubleType, [], false);
3572
BuiltinFunctions.add "__builtin_inff" (floatType, [], false);
3573
BuiltinFunctions.add "__builtin_infl" (longDoubleType, [], false);
3574
BuiltinFunctions.add "__builtin_memcpy" (voidPtrType, [ voidPtrType; voidConstPtrType; sizeType ], false);
3575
BuiltinFunctions.add "__builtin_mempcpy" (voidPtrType, [ voidPtrType; voidConstPtrType; sizeType ], false);
3576
BuiltinFunctions.add "__builtin_memset" (voidPtrType,
3577
[ voidPtrType; intType; intType ], false);
3579
BuiltinFunctions.add "__builtin_fmod" (doubleType, [ doubleType ], false);
3580
BuiltinFunctions.add "__builtin_fmodf" (floatType, [ floatType ], false);
3581
BuiltinFunctions.add "__builtin_fmodl" (longDoubleType, [ longDoubleType ], false);
3583
BuiltinFunctions.add "__builtin_frexp" (doubleType, [ doubleType; intPtrType ], false);
3584
BuiltinFunctions.add "__builtin_frexpf" (floatType, [ floatType; intPtrType ], false);
3585
BuiltinFunctions.add "__builtin_frexpl" (longDoubleType, [ longDoubleType;
3586
intPtrType ], false);
3588
BuiltinFunctions.add "__builtin_ldexp" (doubleType, [ doubleType; intType ], false);
3589
BuiltinFunctions.add "__builtin_ldexpf" (floatType, [ floatType; intType ], false);
3590
BuiltinFunctions.add "__builtin_ldexpl" (longDoubleType, [ longDoubleType;
3593
BuiltinFunctions.add "__builtin_log" (doubleType, [ doubleType ], false);
3594
BuiltinFunctions.add "__builtin_logf" (floatType, [ floatType ], false);
3595
BuiltinFunctions.add "__builtin_logl" (longDoubleType, [ longDoubleType ], false);
3597
BuiltinFunctions.add "__builtin_log10" (doubleType, [ doubleType ], false);
3598
BuiltinFunctions.add "__builtin_log10f" (floatType, [ floatType ], false);
3599
BuiltinFunctions.add "__builtin_log10l" (longDoubleType, [ longDoubleType ], false);
3601
BuiltinFunctions.add "__builtin_modff" (floatType, [ floatType;
3602
TPtr(floatType,[]) ], false);
3603
BuiltinFunctions.add "__builtin_modfl" (longDoubleType, [ longDoubleType;
3604
TPtr(longDoubleType, []) ],
3607
BuiltinFunctions.add "__builtin_nan" (doubleType, [ charConstPtrType ], false);
3608
BuiltinFunctions.add "__builtin_nanf" (floatType, [ charConstPtrType ], false);
3609
BuiltinFunctions.add "__builtin_nanl" (longDoubleType, [ charConstPtrType ], false);
3610
BuiltinFunctions.add "__builtin_nans" (doubleType, [ charConstPtrType ], false);
3611
BuiltinFunctions.add "__builtin_nansf" (floatType, [ charConstPtrType ], false);
3612
BuiltinFunctions.add "__builtin_nansl" (longDoubleType, [ charConstPtrType ], false);
3613
BuiltinFunctions.add "__builtin_next_arg" ((if hasbva then TBuiltin_va_list [] else voidPtrType), [], false) (* When we parse builtin_next_arg we drop the second argument *);
3614
BuiltinFunctions.add "__builtin_object_size" (sizeType, [ voidPtrType; intType ], false);
3616
BuiltinFunctions.add "__builtin_parity" (intType, [ uintType ], false);
3617
BuiltinFunctions.add "__builtin_parityl" (intType, [ ulongType ], false);
3618
BuiltinFunctions.add "__builtin_parityll" (intType, [ ulongLongType ], false);
3620
BuiltinFunctions.add "__builtin_popcount" (intType, [ uintType ], false);
3621
BuiltinFunctions.add "__builtin_popcountl" (intType, [ ulongType ], false);
3622
BuiltinFunctions.add "__builtin_popcountll" (intType, [ ulongLongType ], false);
3624
BuiltinFunctions.add "__builtin_powi" (doubleType, [ doubleType; intType ], false);
3625
BuiltinFunctions.add "__builtin_powif" (floatType, [ floatType; intType ], false);
3626
BuiltinFunctions.add "__builtin_powil" (longDoubleType, [ longDoubleType; intType ], false);
3627
BuiltinFunctions.add "__builtin_prefetch" (voidType, [ voidConstPtrType ], true);
3628
BuiltinFunctions.add "__builtin_return" (voidType, [ voidConstPtrType ], false);
3629
BuiltinFunctions.add "__builtin_return_address" (voidPtrType, [ uintType ], false);
3631
BuiltinFunctions.add "__builtin_sin" (doubleType, [ doubleType ], false);
3632
BuiltinFunctions.add "__builtin_sinf" (floatType, [ floatType ], false);
3633
BuiltinFunctions.add "__builtin_sinl" (longDoubleType, [ longDoubleType ], false);
3635
BuiltinFunctions.add "__builtin_sinh" (doubleType, [ doubleType ], false);
3636
BuiltinFunctions.add "__builtin_sinhf" (floatType, [ floatType ], false);
3637
BuiltinFunctions.add "__builtin_sinhl" (longDoubleType, [ longDoubleType ], false);
3639
BuiltinFunctions.add "__builtin_sqrt" (doubleType, [ doubleType ], false);
3640
BuiltinFunctions.add "__builtin_sqrtf" (floatType, [ floatType ], false);
3641
BuiltinFunctions.add "__builtin_sqrtl" (longDoubleType, [ longDoubleType ], false);
3643
BuiltinFunctions.add "__builtin_stpcpy" (charPtrType, [ charPtrType; charConstPtrType ], false);
3644
BuiltinFunctions.add "__builtin_strchr" (charPtrType, [ charPtrType; intType ], false);
3645
BuiltinFunctions.add "__builtin_strcmp" (intType, [ charConstPtrType; charConstPtrType ], false);
3646
BuiltinFunctions.add "__builtin_strcpy" (charPtrType, [ charPtrType; charConstPtrType ], false);
3647
BuiltinFunctions.add "__builtin_strcspn" (sizeType, [ charConstPtrType; charConstPtrType ], false);
3648
BuiltinFunctions.add "__builtin_strncat" (charPtrType, [ charPtrType; charConstPtrType; sizeType ], false);
3649
BuiltinFunctions.add "__builtin_strncmp" (intType, [ charConstPtrType; charConstPtrType; sizeType ], false);
3650
BuiltinFunctions.add "__builtin_strncpy" (charPtrType, [ charPtrType; charConstPtrType; sizeType ], false);
3651
BuiltinFunctions.add "__builtin_strspn" (sizeType, [ charConstPtrType; charConstPtrType ], false);
3652
BuiltinFunctions.add "__builtin_strpbrk" (charPtrType, [ charConstPtrType; charConstPtrType ], false);
3653
(* When we parse builtin_types_compatible_p, we change its interface *)
3654
BuiltinFunctions.add "__builtin_types_compatible_p"
3655
(intType, [ theMachine.typeOfSizeOf;(* Sizeof the type *)
3656
theMachine.typeOfSizeOf (* Sizeof the type *) ],
3658
BuiltinFunctions.add "__builtin_tan" (doubleType, [ doubleType ], false);
3659
BuiltinFunctions.add "__builtin_tanf" (floatType, [ floatType ], false);
3660
BuiltinFunctions.add "__builtin_tanl" (longDoubleType, [ longDoubleType ], false);
3662
BuiltinFunctions.add "__builtin_tanh" (doubleType, [ doubleType ], false);
3663
BuiltinFunctions.add "__builtin_tanhf" (floatType, [ floatType ], false);
3664
BuiltinFunctions.add "__builtin_tanhl" (longDoubleType, [ longDoubleType ], false);
3667
if hasbva then begin
3668
BuiltinFunctions.add "__builtin_va_end" (voidType, [ TBuiltin_va_list [] ], false);
3669
BuiltinFunctions.add "__builtin_varargs_start"
3670
(voidType, [ TBuiltin_va_list [] ], false);
3671
(* When we parse builtin_{va,stdarg}_start, we drop the second argument *)
3672
BuiltinFunctions.add "__builtin_va_start" (voidType, [ TBuiltin_va_list [] ], false);
3673
BuiltinFunctions.add "__builtin_stdarg_start" (voidType, [ TBuiltin_va_list []; ],
3675
(* When we parse builtin_va_arg we change its interface *)
3676
BuiltinFunctions.add "__builtin_va_arg"
3677
(voidType, [ TBuiltin_va_list [];
3678
theMachine.typeOfSizeOf;(* Sizeof the type *)
3679
voidPtrType; (* Ptr to res *) ],
3681
BuiltinFunctions.add "__builtin_va_copy" (voidType, [ TBuiltin_va_list [];
3682
TBuiltin_va_list [] ],
3687
(** Construct a hash with the builtins *)
3688
let initMsvcBuiltins () : unit =
3689
if not (TheMachine.is_computed ()) then
3690
E.s (bug "Call initCIL before initGccBuiltins");
3691
if BuiltinFunctions.length () <> 0 then
3692
E.s (bug "builtins already initialized.");
3693
(** Take a number of wide string literals *)
3694
BuiltinFunctions.add "__annotation" (voidType, [ ], true);
3697
(** This is used as the location of the prototypes of builtin functions. *)
3698
let builtinLoc: location = locUnknown
3700
let range_loc loc1 loc2 = fst loc1, snd loc2
3702
let pred_body = function
3707
bug "definition expected in Cil.pred_body"
3711
(** A printer interface for CIL trees. Create instantiations of
3712
* this type by specializing the class {!Cil.defaultCilPrinter}. *)
3713
class type cilPrinter = object
3715
(** Local logical annotation (function specifications and code annotations
3716
are printed only if [logic_printer_enabled] is set to true
3718
val mutable logic_printer_enabled : bool
3720
(** more info is displayed on verbose mode. *)
3721
val mutable verbose: bool
3723
method current_function: varinfo option
3724
(** Returns the [varinfo] corresponding to the function being printed *)
3726
method current_stmt: stmt option
3727
(** Returns the stmt being printed *)
3729
method may_be_skipped: stmt -> bool
3731
method setPrintInstrTerminator : string -> unit
3732
method getPrintInstrTerminator : unit -> string
3734
method pVarName: Format.formatter -> string -> unit
3735
(** Invoked each time an identifier name is to be printed. Allows for
3736
various manipulation of the name, such as unmangling. *)
3738
method pVDecl: Format.formatter -> varinfo -> unit
3739
(** Invoked for each variable declaration. Note that variable
3740
* declarations are all the [GVar], [GVarDecl], [GFun], all the [varinfo]
3741
* in formals of function types, and the formals and locals for function
3744
method pVar: Format.formatter -> varinfo -> unit
3745
(** Invoked on each variable use. *)
3747
method pLval: Format.formatter -> lval -> unit
3748
(** Invoked on each lvalue occurence *)
3750
method pOffset: Format.formatter -> offset -> unit
3751
(** Invoked on each offset occurence. The second argument is the base. *)
3753
method pInstr: Format.formatter -> instr -> unit
3754
(** Invoked on each instruction occurrence. *)
3756
method pStmt: Format.formatter -> stmt -> unit
3757
(** Control-flow statement. This is used by
3758
* {!Cil.printGlobal} and by [Cil.dumpGlobal]. *)
3760
method pStmtNext : stmt -> Format.formatter -> stmt -> unit
3762
method pBlock: ?toplevel:bool -> Format.formatter -> block -> unit
3763
(** Print a block. *)
3765
method pGlobal: Format.formatter -> global -> unit
3766
(** Global (vars, types, etc.). This can be slow and is used only by
3767
* {!Cil.printGlobal} but by {!Cil.dumpGlobal} for everything else except
3768
* [GVar] and [GFun]. *)
3770
method pFieldDecl: Format.formatter -> fieldinfo -> unit
3771
(** A field declaration *)
3773
method pType: (Format.formatter -> unit) option -> Format.formatter -> typ -> unit
3774
(** Use of some type in some declaration. The first argument is used to print
3775
the declared element, or is None if we are just printing a type with no
3776
name being declared. Note that for structure/union and enumeration types
3777
the definition of the composite type is not visited. Use [vglob] to
3780
method pAttr: Format.formatter -> attribute -> bool
3781
(** Attribute. Also return an indication whether this attribute must be
3782
* printed inside the __attribute__ list or not. *)
3784
method pAttrParam: Format.formatter -> attrparam -> unit
3785
(** Attribute paramter *)
3787
method pAttrs: Format.formatter -> attributes -> unit
3788
(** Attribute lists *)
3790
method pLabel: Format.formatter -> label -> unit
3793
method pLineDirective: ?forcefile:bool -> Format.formatter -> location -> unit
3794
(** Print a line-number. This is assumed to come always on an empty line.
3795
* If the forcefile argument is present and is true then the file name
3796
* will be printed always. Otherwise the file name is printed only if it
3797
* is different from the last time time this function is called. The last
3798
* file name is stored in a private field inside the cilPrinter object. *)
3800
method pAnnotatedStmt : stmt -> Format.formatter -> stmt -> unit
3801
(** Print an annotated statement. The code to be printed is given in the
3802
* last {!stmt} argument. The initial {!stmt} argument
3803
* records the statement which follows the one being printed;
3804
* {!Cil.defaultCilPrinterClass} uses this information to prettify
3805
* statement printing in certain special cases. *)
3807
method pStmtKind : stmt -> Format.formatter -> stmtkind -> unit
3808
(** Print a statement kind. The code to be printed is given in the
3809
* {!stmtkind} argument. The initial {!Cil.stmt} argument
3810
* records the statement which follows the one being printed;
3811
* {!Cil.defaultCilPrinterClass} uses this information to prettify
3812
* statement printing in certain special cases.
3815
method pExp: Format.formatter -> exp -> unit
3816
(** Print expressions *)
3818
method pInit: Format.formatter -> init -> unit
3819
(** Print initializers. This can be slow and is used by
3820
* {!Cil.printGlobal} but not by {!Cil.dumpGlobal}. *)
3822
method pLogic_type: Format.formatter -> logic_type -> unit
3824
method pTsets_elem: Format.formatter -> tsets_elem -> unit
3826
method pTsets_lhost: Format.formatter -> tsets_lhost -> unit
3828
method pTsets_offset: Format.formatter -> tsets_offset -> unit
3830
method pTsets_lval: Format.formatter -> tsets_lval -> unit
3832
method pTsets: Format.formatter -> tsets -> unit
3834
method pTerm: Format.formatter -> term -> unit
3836
method pTerm_node: Format.formatter -> term -> unit
3838
method pTerm_lval: Format.formatter -> term_lval -> unit
3840
method pTerm_offset: Format.formatter -> term_offset -> unit
3842
method pLogic_info_use: Format.formatter -> logic_info -> unit
3844
method pLogic_var: Format.formatter -> logic_var -> unit
3846
method pQuantifiers: Format.formatter -> quantifiers -> unit
3848
method pPredicate: Format.formatter -> predicate -> unit
3850
method pPredicate_named: Format.formatter -> predicate named -> unit
3853
method pPredicate_info_use: Format.formatter -> predicate_info -> unit
3856
method pBehavior: Format.formatter -> funbehavior -> unit
3858
method pSpec: Format.formatter -> funspec -> unit
3860
method pZone: Format.formatter -> identified_tsets zone -> unit
3863
string -> Format.formatter -> identified_tsets assigns -> unit
3865
method pStatus : Format.formatter -> Cil_types.annot_status -> unit
3867
method pCode_annot: Format.formatter -> code_annotation -> unit
3869
method pAnnotation: Format.formatter -> global_annotation -> unit
3873
let is_skip = function Instr (Skip _) -> true | _ -> false
3875
let empty_funspec () =
3876
{spec_requires = [];
3878
spec_variant = None;
3879
spec_terminates = None;
3880
spec_complete_behaviors = [];
3881
spec_disjoint_behaviors = [];
3884
let is_empty_funspec spec =
3885
spec.spec_requires = [] && spec.spec_behavior = [] &&
3886
spec.spec_variant = None && spec.spec_terminates = None &&
3887
spec.spec_complete_behaviors = [] && spec.spec_disjoint_behaviors = []
3890
class defaultCilPrinterClass : cilPrinter = object (self)
3891
val mutable logic_printer_enabled = true
3892
val mutable verbose = false
3894
val current_stmt = Stack.create ()
3895
val mutable current_function = None
3897
method private in_current_function vi =
3898
assert (current_function = None);
3899
current_function <- Some vi
3900
method private out_current_function =
3901
assert (current_function <> None);
3902
current_function <- None
3904
method current_function = current_function
3905
method private push_stmt s = Stack.push s current_stmt
3906
method private pop_stmt s = ignore (Stack.pop current_stmt); s
3907
method current_stmt =
3908
try Some (Stack.top current_stmt) with Stack.Empty -> None
3910
method may_be_skipped s = s.labels = []
3912
(** Returns the stmt being printed *)
3914
val mutable currentFormals : varinfo list = []
3915
method private getLastNamedArgument (s: string) : exp =
3916
match List.rev currentFormals with
3917
f :: _ -> Lval (var f)
3919
E.s (warn "Cannot find the last named argument when printing call to %s\n" s)
3922
method pVarName fmt v = pp_print_string fmt v
3924
method private pVarString v =
3925
fprintf_to_string "%a" self#pVar v
3928
method pVar fmt (v:varinfo) = Format.fprintf fmt "%a" self#pVarName v.vname
3930
(* variable declaration *)
3931
method pVDecl fmt (v:varinfo) =
3932
let stom, rest = separateStorageModifiers v.vattr in
3933
(* First the storage modifiers *)
3934
fprintf fmt "%s%a%a%a %a"
3935
(if v.vinline then "__inline " else "")
3936
d_storage v.vstorage
3938
(self#pType (Some (fun fmt -> self#pVar fmt v))) v.vtype
3942
method pLval fmt (lv:lval) = (* lval (base is 1st field) *)
3944
Var vi, o -> fprintf fmt "%a%a" self#pVar vi self#pOffset o
3945
| Mem e, Field(fi, o) ->
3946
fprintf fmt "%a->%a%a"
3947
(self#pExpPrec arrowLevel) e
3948
self#pVarName fi.fname
3950
| Mem e, NoOffset ->
3952
(self#pExpPrec derefStarLevel) e
3954
fprintf fmt "(*%a)%a"
3955
(self#pExpPrec derefStarLevel) e
3959
method pOffset fmt = function
3963
self#pVarName fi.fname
3966
fprintf fmt "[%a]%a"
3970
method private pLvalPrec (contextprec: int) fmt lv =
3971
if getParenthLevel (Lval(lv)) >= contextprec then
3972
fprintf fmt "(%a)" self#pLval lv
3976
(*** EXPRESSIONS ***)
3977
method pExp fmt (e: exp) =
3978
let level = getParenthLevel e in
3979
match stripInfo e with
3980
| Info _ -> assert false
3981
| Const(c) -> d_const fmt c
3982
| Lval(l) -> self#pLval fmt l
3986
(self#pExpPrec level) e1
3988
| BinOp(b,e1,e2,_) ->
3989
fprintf fmt "@[%a %a %a@]"
3990
(self#pExpPrec level) e1
3992
(self#pExpPrec level) e2
3995
fprintf fmt "(%a)%a"
3997
(self#pExpPrec level) e
4000
fprintf fmt "sizeof(%a)"
4004
fprintf fmt "sizeof(%a)"
4008
fprintf fmt "sizeof(%a)"
4012
fprintf fmt "__alignof__(%a)"
4015
fprintf fmt "__alignof__(%a)"
4019
(self#pLvalPrec addrOfLevel) lv
4021
| StartOf(lv) -> self#pLval fmt lv
4023
(* Print an expression, given the precedence of the context in which it
4025
method private pExpPrec (contextprec: int) fmt (e: exp) =
4026
let thisLevel = getParenthLevel e in
4028
if thisLevel >= contextprec then
4030
else if contextprec == bitwiseLevel then
4031
(* quiet down some GCC warnings *)
4032
thisLevel == additiveLevel || thisLevel == comparativeLevel
4037
fprintf fmt "(%a)" self#pExp e
4041
method pInit fmt = function
4042
SingleInit e -> self#pExp fmt e
4043
| CompoundInit (t, initl) ->
4044
(* We do not print the type of the Compound *)
4046
let dinit e = d_init () e in
4048
(docList ~sep:(chr ',' ++ break) dinit) initl
4050
let printDesignator =
4051
if not theMachine.msvcMode then begin
4052
(* Print only for union when we do not initialize the first field *)
4053
match unrollType t, initl with
4054
TComp(ci, _), [(Field(f, NoOffset), _)] ->
4055
if not (ci.cstruct) && ci.cfields != [] &&
4056
(List.hd ci.cfields) != f then
4064
let d_oneInit fmt = function
4065
Field(f, NoOffset), i ->
4066
if printDesignator then
4067
fprintf fmt ".%a = "
4068
self#pVarName f.fname;
4070
| Index(e, NoOffset), i ->
4071
if printDesignator then
4072
fprintf fmt "[%a] = "
4075
| _ -> E.s (unimp "Trying to print malformed initializer")
4077
fprintf fmt "{@[%a@]}"
4078
(fprintfList ~sep:",@ " d_oneInit) initl
4081
(** What terminator to print after an instruction. sometimes we want to
4082
* print sequences of instructions separated by comma *)
4083
val mutable printInstrTerminator = ";"
4085
method private setPrintInstrTerminator (term : string) =
4086
printInstrTerminator <- term
4088
method private getPrintInstrTerminator () = printInstrTerminator
4090
(*** INSTRUCTIONS ****)
4091
method pInstr fmt (i:instr) = (* imperative instruction *)
4092
fprintf fmt "%a" (self#pLineDirective ~forcefile:false) (get_instrLoc i);
4094
| Skip _ -> fprintf fmt ";"
4095
| Set(lv,e,_) -> begin
4096
(* Be nice to some special cases *)
4098
BinOp((PlusA|PlusPI|IndexPI),Lval(lv'),Const(CInt64(one,_,_)),_)
4099
when equals lv lv' && one = Int64.one
4100
&& not miscState.printCilAsIs ->
4101
fprintf fmt "%a ++%s"
4102
(self#pLvalPrec indexLevel) lv
4103
printInstrTerminator
4104
| BinOp((MinusA|MinusPI),Lval(lv'),
4105
Const(CInt64(one,_,_)), _)
4106
when equals lv lv' && one = Int64.one
4107
&& not miscState.printCilAsIs ->
4108
fprintf fmt "%a --%s"
4109
(self#pLvalPrec indexLevel) lv
4110
printInstrTerminator
4112
| BinOp((PlusA|PlusPI|IndexPI),Lval(lv'),Const(CInt64(mone,_,_)),_)
4113
when equals lv lv' && mone = Int64.minus_one
4114
&& not miscState.printCilAsIs ->
4115
fprintf fmt "%a --%s"
4116
(self#pLvalPrec indexLevel) lv
4117
printInstrTerminator
4119
| BinOp((PlusA|PlusPI|IndexPI|MinusA|MinusPP|MinusPI|BAnd|BOr|BXor|
4120
Mult|Div|Mod|Shiftlt|Shiftrt) as bop,
4121
Lval(lv'),e,_) when equals lv lv' ->
4122
fprintf fmt "%a %a= %a%s"
4126
printInstrTerminator
4129
fprintf fmt "%a = %a%s"
4132
printInstrTerminator
4135
(* In cabs2cil we have turned the call to builtin_va_arg into a
4136
* three-argument call: the last argument is the address of the
4138
| Call(None, Lval(Var vi, NoOffset), [dest; SizeOf t; adest], l)
4139
when vi.vname = "__builtin_va_arg" && not miscState.printCilAsIs ->
4140
let destlv = match stripCasts adest with
4141
AddrOf destlv -> destlv
4142
(* If this fails, it's likely that an extension interfered
4145
"%a: Encountered unexpected call to %s with dest %a\n"
4146
d_loc l vi.vname self#pExp adest)
4148
fprintf fmt "%a = __builtin_va_arg (@[%a,@ %a@])%s"
4150
(* Now the arguments *)
4153
printInstrTerminator
4155
(* In cabs2cil we have dropped the last argument in the call to
4156
* __builtin_va_start and __builtin_stdarg_start. *)
4157
| Call(None, Lval(Var vi, NoOffset), [marker], l)
4158
when ((vi.vname = "__builtin_stdarg_start" ||
4159
vi.vname = "__builtin_va_start")
4160
&& not miscState.printCilAsIs) ->
4162
let last = self#getLastNamedArgument vi.vname in
4163
self#pInstr fmt (Call(None,Lval(Var vi,NoOffset),[marker; last],l))
4166
(* In cabs2cil we have dropped the last argument in the call to
4167
* __builtin_next_arg. *)
4168
| Call(res, Lval(Var vi, NoOffset), [ ], l)
4169
when vi.vname = "__builtin_next_arg" && not miscState.printCilAsIs ->
4171
let last = self#getLastNamedArgument vi.vname in
4172
self#pInstr fmt (Call(res,Lval(Var vi,NoOffset),[last],l))
4175
(* In cparser we have turned the call to
4176
* __builtin_types_compatible_p(t1, t2) into
4177
* __builtin_types_compatible_p(sizeof t1, sizeof t2), so that we can
4178
* represent the types as expressions.
4179
* Remove the sizeofs when printing. *)
4180
| Call(dest, Lval(Var vi, NoOffset), [SizeOf t1; SizeOf t2], _)
4181
when vi.vname = "__builtin_types_compatible_p"
4182
&& not miscState.printCilAsIs ->
4183
(* Print the destination *)
4186
| Some lv -> fprintf fmt "%a = " self#pLval lv );
4187
(* Now the call itself *)
4188
fprintf fmt "%a(%a, %a)%s"
4189
self#pVarName vi.vname
4190
(self#pType None) t1
4191
(self#pType None) t2
4192
printInstrTerminator
4193
| Call(_, Lval(Var vi, NoOffset), _, _)
4194
when vi.vname = "__builtin_types_compatible_p"
4195
&& not miscState.printCilAsIs ->
4196
E.s (bug "__builtin_types_compatible_p: cabs2cil should have added sizeof to the arguments.")
4198
| Call(dest,e,args,_) ->
4204
(* Maybe we need to print a cast *)
4205
(let destt = typeOfLval lv in
4206
match unrollType (typeOf e) with
4208
when not (equals (!pTypeSig rt)
4209
(!pTypeSig destt)) ->
4211
(self#pType None) destt
4213
(* Now the function name *)
4215
Lval(Var _, _) -> self#pExp fmt e
4216
| _ -> fprintf fmt "(%a)" self#pExp e);
4217
fprintf fmt "(@[%a@])%s"
4218
(* Now the arguments *)
4219
(fprintfList ~sep:",@ " self#pExp)
4221
printInstrTerminator
4224
| Asm(attrs, tmpls, outs, ins, clobs, l) ->
4225
self#pLineDirective fmt l;
4226
if theMachine.msvcMode then
4227
fprintf fmt "__asm {@[%a@]}%s"
4228
(fprintfList ~sep:"@\n" (fun fmt s -> fprintf fmt "%s" s)) tmpls
4229
printInstrTerminator
4231
fprintf fmt "__asm__ %a (@[%a"
4233
(fprintfList ~sep:"@\n" (fun fmt x -> fprintf fmt "\"%s\"" (escape_string x))) tmpls;
4235
if outs = [] && ins = [] && clobs = [] then
4239
(fprintfList ~sep:",@ "
4240
(fun fmt (idopt, c, lv) ->
4241
fprintf fmt "%s\"%s\" (%a)"
4244
| Some id -> "[" ^ id ^ "] "
4250
if ins = [] && clobs = [] then
4254
(fprintfList ~sep:",@ "
4255
(fun fmt (idopt, c, e) ->
4256
fprintf fmt "%s\"%s\"(%a)"
4259
| Some id -> "[" ^ id ^ "] "
4266
if clobs = [] then ()
4269
(fprintfList ~sep:",@ "
4270
(fun fmt c -> fprintf fmt "\"%s\"" (escape_string c)))
4273
fprintf fmt "@])%s" printInstrTerminator
4275
| Code_annot (annot, l) ->
4276
if logic_printer_enabled then
4277
fprintf fmt "%a@[/*@@ %a*/@]"
4278
(self#pLineDirective ~forcefile:false) l
4279
self#pCode_annot annot
4281
(**** STATEMENTS ****)
4282
method pStmt fmt (s:stmt) = (* control-flow statement *)
4284
self#pop_stmt (self#pStmtNext invalidStmt fmt s)
4286
method pStmtNext (next: stmt) fmt (s: stmt) =
4288
self#pop_stmt (self#pAnnotatedStmt next fmt s)
4290
method pAnnotatedStmt (next: stmt) fmt (s: stmt) =
4291
if false then (* CEA: to debug location setting *)
4292
(let loc = fst (get_stmtLoc s.skind) in
4293
fprintf fmt "/*Loc=%s:%d*/" loc.Lexing.pos_fname loc.Lexing.pos_lnum);
4294
(* print the labels *)
4295
fprintfList ~sep:"@\n" (fun fmt l -> self#pLabel fmt l) fmt s.labels;
4297
(* print the statement itself. If the labels are non-empty and the
4298
* statement is empty, print a semicolon *)
4299
if is_skip s.skind && not s.ghost then
4300
(if verbose || s.labels <> [] then fprintf fmt ";")
4302
(if s.labels <> [] then fprintf fmt "@\n";
4303
if s.ghost then fprintf fmt "@[/*@@ @[ghost ";
4304
self#pStmtKind next fmt s.skind ;
4305
if s.ghost then fprintf fmt "@]*/@]";)
4306
(* OLD value : if is_skip s.skind && s.labels <> [] then
4307
text ";" else (if s.labels <> [] then line else nil) ++
4308
self#pStmtKind next () s.skind *);
4309
if s.ghost then fprintf fmt "@]*/@]"
4311
method private pLabel fmt = function
4312
Label (s, _, true) -> fprintf fmt "%s: " s
4313
| Label (s, _, false) -> fprintf fmt "%s: /* CIL Label */ " s
4314
| Case (e, _) -> fprintf fmt "case %a: " self#pExp e
4315
| Default _ -> fprintf fmt "default: "
4317
(* The pBlock will put the unalign itself *)
4318
method pBlock ?(toplevel=true) fmt (blk: block) =
4321
match blk.bstmts with
4326
let rec dofirst () = function
4328
| [x] -> self#pStmtNext invalidStmt fmt x
4329
| x :: rest -> dorest x rest
4330
and dorest prev = function
4331
[] -> self#pStmtNext invalidStmt fmt prev
4333
fprintf fmt "%a@\n" (self#pStmtNext x) prev;
4336
(* Let the host of the block decide on the alignment. The d_block will
4337
* pop the alignment as well *)
4338
if force_paren then fprintf fmt "{";
4339
if blk.battrs <> [] then
4340
self#pAttrsGen true fmt blk.battrs;
4341
dofirst () blk.bstmts;
4342
if force_paren then fprintf fmt "}";
4346
(* Store here the name of the last file printed in a line number. This is
4347
* private to the object *)
4348
val mutable lastFileName = ""
4349
val mutable lastLineNumber = -1
4351
(* Make sure that you only call self#pLineDirective on an empty line *)
4352
method pLineDirective ?(forcefile=false) fmt l =
4354
match miscState.lineDirectiveStyle with
4356
| Some _ when (fst l).Lexing.pos_lnum <= 0 -> ()
4358
(* Do not print lineComment if the same line as above *)
4359
| Some LineCommentSparse when (fst l).Lexing.pos_lnum = lastLineNumber -> ()
4364
| LineComment | LineCommentSparse -> "//#line "
4365
| LinePreprocessorOutput when not theMachine.msvcMode -> "#"
4366
| LinePreprocessorOutput | LinePreprocessorInput -> "#line"
4368
lastLineNumber <- (fst l).Lexing.pos_lnum;
4370
if forcefile || (fst l).Lexing.pos_fname <> lastFileName then
4372
lastFileName <- (fst l).Lexing.pos_fname;
4373
" \"" ^ (fst l).Lexing.pos_fname ^ "\""
4378
fprintf fmt "@<0>\n@<0>%s@<0> @<0>%d@<0> @<0>%s@\n" directive (fst l).Lexing.pos_lnum filename
4381
method pStmtKind (next: stmt) fmt kind =
4383
| UnspecifiedSequence seq ->
4384
let print_stmt pstmt fmt (stmt, writes, reads) =
4389
Format.fprintf fmt "/*@ @[%a@ <-@ %a@]*/"
4390
(pretty_list (space_sep ",") self#pLval) writes
4391
(pretty_list (space_sep ",") self#pLval) reads)
4394
let rec dofirst () = function
4396
| [x] -> print_stmt (self#pStmtNext invalidStmt) fmt x
4397
| x :: rest -> dorest x rest
4398
and dorest ((p,_,_) as prev) = function
4399
[] -> print_stmt (self#pStmtNext invalidStmt) fmt prev
4400
| (s,_,_) as x :: rest ->
4403
not (is_skip p.skind) || p.ghost || p.labels <> []
4405
fprintf fmt "%a%a" (print_stmt (self#pStmtNext s)) prev
4406
(print_if newline_cond) newline;
4409
fprintf fmt "@[<1>{%a"
4411
(fun fmt () -> fprintf fmt "/*unspecified sequence*/@\n");
4414
| Return(None, l) ->
4415
self#pLineDirective fmt l;
4416
fprintf fmt "return;"
4418
| Return(Some e, l) ->
4419
self#pLineDirective fmt l;
4420
fprintf fmt "return (%a);"
4423
| Goto (sref, _) -> begin
4424
(* Grab one of the labels *)
4425
let rec pickLabel = function
4427
| Label (l, _, _) :: _ -> Some l
4428
| _ :: rest -> pickLabel rest
4430
match pickLabel !sref.labels with
4431
Some l -> fprintf fmt "goto %s;" l
4433
ignore (error "Cannot find label for target of goto\n");
4434
fprintf fmt "goto __invalid_label;"
4438
self#pLineDirective fmt l;
4439
fprintf fmt "break;"
4442
self#pLineDirective fmt l;
4443
fprintf fmt "continue;"
4446
fprintf fmt "@[%a@]"
4449
| If(be,t,{bstmts=[];battrs=[]},l) when not miscState.printCilAsIs ->
4450
fprintf fmt "%aif@[ (%a) %a"
4451
(self#pLineDirective ~forcefile:false) l
4453
(self#pBlock ~toplevel:true) t
4455
| If(be,t,{bstmts=[{skind=Goto(gref,_);labels=[]}];
4457
when !gref == next && not miscState.printCilAsIs ->
4458
fprintf fmt "%aif@[ (%a) %a"
4459
(self#pLineDirective ~forcefile:false) l
4461
(self#pBlock ~toplevel:true) t
4463
| If(be,{bstmts=[];battrs=[]},e,l) when not miscState.printCilAsIs ->
4464
fprintf fmt "%aif@[ (%a) %a"
4465
(self#pLineDirective ~forcefile:false) l
4466
self#pExp (UnOp(LNot,be,intType))
4467
(self#pBlock ~toplevel:true) e
4469
| If(be,{bstmts=[{skind=Goto(gref,_);labels=[]}];
4471
when !gref == next && not miscState.printCilAsIs ->
4472
fprintf fmt "%aif@[ (%a) %a"
4473
(self#pLineDirective ~forcefile:false) l
4474
self#pExp (UnOp(LNot,be,intType))
4475
(self#pBlock ~toplevel:true) e
4478
fprintf fmt "%a@[@[if (%a)@ %aelse %a"
4479
(self#pLineDirective ~forcefile:false) l
4481
(self#pBlock ~toplevel:true) t
4482
(self#pBlock ~toplevel:true) e
4484
| Switch(e,b,_,l) ->
4485
fprintf fmt "%a@[switch (%a) %a"
4486
(self#pLineDirective ~forcefile:false) l
4488
(self#pBlock ~toplevel:true) b
4490
| Loop(annot, b, l, _, _) ->
4491
if logic_printer_enabled then
4493
(swap fprintf "@[@[<4>/*@@@ ")
4494
(swap fprintf "@\n@]@ */@]@\n")
4495
nl_sep self#pCode_annot fmt annot;
4497
(* Maybe the first thing is a conditional. Turn it into a WHILE *)
4499
let term, bodystmts =
4500
let rec skipEmpty = function
4502
| {skind=Instr (Skip _);labels=[]} :: rest -> skipEmpty rest
4505
(* Bill McCloskey: Do not remove the If if it has labels *)
4506
match skipEmpty b.bstmts with
4507
{skind=If(e,tb,fb,_)} as to_skip :: rest
4509
not miscState.printCilAsIs && self#may_be_skipped to_skip ->
4511
match skipEmpty tb.bstmts, skipEmpty fb.bstmts with
4512
[], {skind=Break _; labels=[]} :: _ -> e, rest
4513
| {skind=Break _; labels=[]} :: _, []
4514
-> UnOp(LNot, e, intType), rest
4515
| _ -> raise Not_found
4517
| _ -> raise Not_found
4519
self#pLineDirective fmt l;
4520
fprintf fmt "@[<2>while (%a) %a"
4522
(self#pBlock ~toplevel:true) {bstmts=bodystmts; battrs=b.battrs}
4525
self#pLineDirective fmt l;
4526
fprintf fmt "@[<2>while (1) %a"
4527
(self#pBlock ~toplevel:true) b
4530
| Block b -> fprintf fmt "@[%a" (self#pBlock ~toplevel:false) b
4532
| TryFinally (b, h, l) ->
4533
self#pLineDirective fmt l;
4534
fprintf fmt "__try @[%a @[<5>__finally%a"
4535
(self#pBlock ~toplevel:true) b
4536
(self#pBlock ~toplevel:true) h
4538
| TryExcept (b, (il, e), h, l) ->
4539
self#pLineDirective fmt l;
4540
fprintf fmt "__try @[%a __except(@\n@["
4541
(self#pBlock ~toplevel:true) b;
4543
(* Print the instructions but with a comma at the end, instead of
4545
printInstrTerminator <- ",";
4546
fprintfList ~sep:"@\n" self#pInstr fmt il;
4547
printInstrTerminator <- ";";
4548
fprintf fmt "%a) @]%a"
4550
(self#pBlock ~toplevel:true) h
4553
method pGlobal fmt (g:global) = (* global (vars, types, etc.) *)
4555
| GFun (fundec, l) ->
4556
self#in_current_function fundec.svar;
4557
(* If the function has attributes then print a prototype because
4558
* GCC cannot accept function attributes in a definition *)
4559
let oldattr = fundec.svar.vattr in
4560
(* Always pring the file name before function declarations *)
4561
(* Prototype first *)
4562
if oldattr <> [] then
4563
(self#pLineDirective fmt l;
4564
fprintf fmt "%a;@\n"
4565
self#pVDecl fundec.svar);
4566
(* Temporarily remove the function attributes *)
4567
fundec.svar.vattr <- [];
4569
self#pLineDirective ~forcefile:true fmt l;
4570
self#pFunDecl fmt fundec;
4571
fundec.svar.vattr <- oldattr;
4573
self#out_current_function
4577
self#pLineDirective ~forcefile:true fmt l;
4578
fprintf fmt "typedef %a;@\n"
4579
(self#pType (Some (fun fmt -> fprintf fmt "%s" typ.tname))) typ.ttype
4581
| GEnumTag (enum, l) ->
4582
self#pLineDirective fmt l;
4583
fprintf fmt "enum@[ %a {@\n%a@]@\n} %a;@\n"
4584
self#pVarName enum.ename
4585
(fprintfList ~sep:",@\n"
4587
fprintf fmt "%s = %a"
4589
self#pExp item.eival))
4591
self#pAttrs enum.eattr
4593
| GEnumTagDecl (enum, l) -> (* This is a declaration of a tag *)
4594
self#pLineDirective fmt l;
4595
fprintf fmt "enum %a;@\n" self#pVarName enum.ename
4597
| GCompTag (comp, l) -> (* This is a definition of a tag *)
4598
let n = comp.cname in
4600
if comp.cstruct then "struct"
4603
let sto_mod, rest_attr = separateStorageModifiers comp.cattr in
4604
self#pLineDirective ~forcefile:true fmt l;
4605
fprintf fmt "@[<3>%s %a%a {@\n%a@]@\n}%a;@\n"
4609
(fprintfList ~sep:"@\n" self#pFieldDecl)
4611
self#pAttrs rest_attr
4613
| GCompTagDecl (comp, l) -> (* This is a declaration of a tag *)
4614
self#pLineDirective fmt l;
4615
fprintf fmt "%s;@\n" (compFullName comp)
4617
| GVar (vi, io, l) ->
4618
self#pLineDirective ~forcefile:true fmt l;
4627
CompoundInit (_, il) when List.length il >= 8 -> true
4631
begin self#pLineDirective fmt l;
4632
fprintf fmt " @[@\n"
4639
(* print global variable 'extern' declarations, and function prototypes *)
4640
| GVarDecl (funspec, vi, l) ->
4641
self#opt_funspec fmt funspec;
4642
if isFunctionType vi.vtype then self#in_current_function vi;
4643
if not miscState.printCilAsIs && BuiltinFunctions.mem vi.vname then
4645
(* Compiler builtins need no prototypes. Just print them in
4647
fprintf fmt "/* compiler builtin: @\n %a; */@\n"
4650
self#pLineDirective fmt l;
4651
fprintf fmt "%a;@\n" self#pVDecl vi
4653
if isFunctionType vi.vtype then self#out_current_function
4657
self#pLineDirective fmt l;
4658
fprintf fmt "__asm__(\"%s\");@\n" (escape_string s)
4660
| GPragma (Attr(an, args), l) ->
4661
(* sm: suppress printing pragmas that gcc does not understand *)
4662
(* assume anything starting with "ccured" is ours *)
4663
(* also don't print the 'combiner' pragma *)
4664
(* nor 'cilnoremove' *)
4666
not miscState.print_CIL_Input &&
4667
not theMachine.msvcMode &&
4668
((startsWith "box" an) ||
4669
(startsWith "ccured" an) ||
4671
(an = "cilnoremove"))
4673
self#pLineDirective fmt l;
4674
if suppress then fprintf fmt "/* ";
4675
fprintf fmt "#pragma ";
4680
| "weak", [ACons (varinfo, [])] ->
4681
fprintf fmt "weak %s" varinfo
4683
fprintf fmt "%s(%a)"
4685
(fprintfList ~sep:"," self#pAttrParam) args
4688
if suppress then fprintf fmt " */@\n" else fprintf fmt "@\n"
4690
| GPragma (AttrAnnot _, _) ->
4692
(* self#pLineDirective fmt l;
4693
fprintf fmt "/* #pragma %s */@\n" a*)
4695
| GAnnot (decl,l) ->
4696
(*if logic_printer_enabled then*)
4698
self#pLineDirective fmt l;
4699
fprintf fmt "/*@@@ %a@ */@\n"
4700
self#pAnnotation decl
4705
fprintf fmt "%s@\n" s
4707
method pFieldDecl fmt fi =
4708
fprintf fmt "%a %s%a;"
4710
(Some (fun fmt -> if fi.fname <> missingFieldName then fprintf fmt "%s" fi.fname)))
4712
(match fi.fbitfield with
4714
| Some i -> ": " ^ string_of_int i ^ " ")
4715
self#pAttrs fi.fattr
4718
method private opt_funspec fmt funspec =
4719
if logic_printer_enabled && not (is_empty_funspec funspec) then
4720
fprintf fmt "/*@[@@ %a@]@\n*/@\n" self#pSpec funspec
4722
method private pFunDecl fmt f =
4723
fprintf fmt "%a%a@\n{ @[%a@\n@\n"
4724
self#opt_funspec f.sspec
4727
(fprintfList ~sep:"@\n" (fun fmt vi -> fprintf fmt "%a;" self#pVDecl vi))
4730
(* remember the declaration *)
4731
currentFormals <- f.sformals;
4732
self#pBlock ~toplevel:false fmt f.sbody;
4733
currentFormals <- [];
4737
(***** PRINTING DECLARATIONS and TYPES ****)
4739
method pType nameOpt (* Whether we are declaring a name or
4740
* we are just printing a type *)
4741
fmt (t:typ) = (* use of some type *)
4742
let name = match nameOpt with None -> (fun _ -> ()) | Some d -> d in
4743
let printAttributes fmt (a: attributes) =
4745
| None when not miscState.print_CIL_Input && not theMachine.msvcMode ->
4746
(* Cannot print the attributes in this case because gcc does not
4747
* like them here, except if we are printing for CIL, or for MSVC.
4748
* In fact, for MSVC we MUST print attributes such as __stdcall *)
4749
(* if pa = nil then nil else
4750
text "/*" ++ pa ++ text "*/"*) ()
4751
| _ -> self#pAttrs fmt a
4755
fprintf fmt "void%a %t"
4760
fprintf fmt "%a%a %t"
4765
| TFloat(fkind, a) ->
4766
fprintf fmt "%a%a %t"
4771
| TComp (comp, a) -> (* A reference to a struct *)
4774
(if comp.cstruct then "struct" else "union")
4775
self#pVarName comp.cname
4779
| TEnum (enum, a) ->
4780
fprintf fmt "enum %a %a%t"
4781
self#pVarName enum.ename
4786
(* Parenthesize the ( * attr name) if a pointer to a function or an
4787
* array. However, on MSVC the __stdcall modifier must appear right
4788
* before the pointer constructor "(__stdcall *f)". We push them into
4789
* the parenthesis. *)
4790
let (paren: (formatter -> unit) option), (bt': typ) =
4792
TFun(rt, args, isva, fa) when theMachine.msvcMode ->
4793
let an, af', at = partitionAttributes ~default:AttrType fa in
4794
(* We take the af' and we put them into the parentheses *)
4799
printAttributes af'),
4800
TFun(rt, args, isva, addAttributes an at)
4802
| TFun _ | TArray _ -> (Some (fun fmt -> fprintf fmt "(")), bt
4806
let name' = fun fmt ->
4813
(* Put the parenthesis *)
4815
Some p -> fprintf fmt "%t%t)" p name'
4816
| _ -> fprintf fmt "%t" name'
4823
| TArray (elemt, lo, a) ->
4824
(* ignore the const attribute for arrays *)
4825
let a' = dropAttributes [ "const" ] a in
4826
let name' = fun fmt ->
4827
if a' == [] then name fmt else
4828
if nameOpt == None then
4840
fprintf fmt "%t[%t]"
4853
| TFun (restyp, args, isvararg, a) ->
4855
if a == [] then name fmt else
4856
if nameOpt == None then
4872
(fun fmt -> if args = Some [] && isvararg then
4875
(if args = None then ()
4876
else if args = Some [] then fprintf fmt "void"
4878
let pArg fmt (aname, atype, aattr) =
4879
let stom, rest = separateStorageModifiers aattr in
4880
(* First the storage modifiers *)
4884
(self#pType (Some (fun fmt -> fprintf fmt "%s" aname))) atype
4887
(fprintfList ~sep:",@ " pArg)
4890
if isvararg then fprintf fmt "@ , ...";
4896
fprintf fmt "%a%a %t"
4897
self#pVarName t.tname
4901
| TBuiltin_va_list a ->
4902
fprintf fmt "__builtin_va_list%a %t"
4907
(**** PRINTING ATTRIBUTES *********)
4908
method pAttrs fmt (a: attributes) =
4909
self#pAttrsGen false fmt a
4912
(* Print one attribute. Return also an indication whether this attribute
4913
* should be printed inside the __attribute__ list *)
4914
method pAttr fmt = function
4916
(* Recognize and take care of some known cases *)
4917
(match an, args with
4918
"const", [] -> fprintf fmt "const"; false
4919
(* Put the aconst inside the attribute list *)
4920
| "aconst", [] when not theMachine.msvcMode ->
4921
fprintf fmt "__const__"; true
4922
| "thread", [] when not theMachine.msvcMode ->
4923
fprintf fmt "__thread"; false
4925
| "used", [] when not !msvcMode -> text "__attribute_used__", false
4927
| "volatile", [] -> fprintf fmt "volatile"; false
4928
| "restrict", [] -> fprintf fmt "__restrict"; false
4929
| "missingproto", [] -> fprintf fmt "/* missing proto */"; false
4930
| "cdecl", [] when theMachine.msvcMode -> fprintf fmt "__cdecl"; false
4931
| "stdcall", [] when theMachine.msvcMode ->
4932
fprintf fmt "__stdcall"; false
4933
| "fastcall", [] when theMachine.msvcMode -> fprintf fmt "__fastcall"; false
4934
| "declspec", args when theMachine.msvcMode ->
4935
fprintf fmt "__declspec(%a)"
4936
(fprintfList ~sep:"" self#pAttrParam) args;
4938
| "w64", [] when theMachine.msvcMode -> fprintf fmt "__w64"; false
4940
fprintf fmt "__asm__(%a)"
4941
(fprintfList ~sep:"" self#pAttrParam) args;
4943
(* we suppress printing mode(__si__) because it triggers an *)
4944
(* internal compiler error in all current gcc versions *)
4945
(* sm: I've now encountered a problem with mode(__hi__)... *)
4946
(* I don't know what's going on, but let's try disabling all "mode"..*)
4947
| "mode", [ACons(tag,[])] ->
4948
fprintf fmt "/* mode(%s) */" tag;
4951
(* sm: also suppress "format" because we seem to print it in *)
4952
(* a way gcc does not like *)
4953
| "format", _ -> fprintf fmt "/* format attribute */";
4956
(* sm: here's another one I don't want to see gcc warnings about.. *)
4957
| "mayPointToStack", _ when not miscState.print_CIL_Input
4958
(* [matth: may be inside another comment.]
4959
-> text "/*mayPointToStack*/", false
4961
-> fprintf fmt ""; false
4963
| "arraylen", [a] ->
4964
fprintf fmt "/*[%a]*/" self#pAttrParam a;
4967
| _ -> (* This is the dafault case *)
4968
(* Add underscores to the name *)
4970
if theMachine.msvcMode then "__" ^ an else "__" ^ an ^ "__"
4973
(fprintf fmt "%s" an';
4976
(fprintf fmt "%s(%a)"
4978
(fprintfList ~sep:"," self#pAttrParam) args;
4981
fprintf fmt "%s" (mkAttrAnnot s); false
4983
method private pAttrPrec (contextprec: int) fmt (a: attrparam) =
4984
let thisLevel = getParenthLevelAttrParam a in
4986
if thisLevel >= contextprec then
4988
else if contextprec == bitwiseLevel then
4989
(* quiet down some GCC warnings *)
4990
thisLevel == additiveLevel || thisLevel == comparativeLevel
4995
fprintf fmt "(%a)" self#pAttrParam a
4997
self#pAttrParam fmt a
5000
method pAttrParam fmt a =
5001
let level = getParenthLevelAttrParam a in
5003
| AInt n -> fprintf fmt "%d" n
5004
| AStr s -> fprintf fmt "\"%s\"" (escape_string s)
5005
| ACons(s, []) -> fprintf fmt "%s" s
5007
fprintf fmt "%s(%a)"
5009
(fprintfList ~sep:"" self#pAttrParam) al
5010
| ASizeOfE a -> fprintf fmt "sizeof(%a)" self#pAttrParam a
5011
| ASizeOf t -> fprintf fmt "sizeof(%a)" (self#pType None) t
5012
| ASizeOfS _ts -> fprintf fmt "sizeof(<typsig>)"
5013
| AAlignOfE a -> fprintf fmt "__alignof__(%a)" self#pAttrParam a
5014
| AAlignOf t -> fprintf fmt "__alignof__(%a)" (self#pType None) t
5015
| AAlignOfS _ts -> fprintf fmt "__alignof__(<typsig>)"
5019
(self#pAttrPrec level) a1
5021
| ABinOp(b,a1,a2) ->
5022
fprintf fmt "@[(%a)%a@ (%a) @]"
5023
(self#pAttrPrec level) a1
5025
(self#pAttrPrec level) a2
5033
(self#pAttrPrec derefStarLevel) a1
5035
fprintf fmt "& %a" (self#pAttrPrec addrOfLevel) a1
5036
| AIndex (a1, a2) ->
5037
fprintf fmt "%a[%a]"
5040
| AQuestion (a1, a2, a3) ->
5041
fprintf fmt "%a ? %a : %a"
5047
(* A general way of printing lists of attributes *)
5048
method private pAttrsGen (block: bool) fmt (a: attributes) =
5049
(* Scan all the attributes and separate those that must be printed inside
5050
* the __attribute__ list *)
5051
let rec loop (in__attr__: string list) = function
5053
match in__attr__ with
5056
(* sm: added 'forgcc' calls to not comment things out
5057
* if CIL is the consumer; this is to address a case
5058
* Daniel ran into where blockattribute(nobox) was being
5059
* dropped by the merger
5062
fprintf fmt " %s __blockattribute__("
5065
fprintf fmt "__attribute__((");
5066
fprintfList ~sep:",@ "
5067
(fun fmt a -> fprintf fmt "%s" a)
5071
(if block then forgcc "*/" else ")")
5074
let buff = Buffer.create 17 in
5075
let local_fmt = formatter_of_buffer buff in
5076
let ina = self#pAttr local_fmt x in
5077
pp_print_flush local_fmt ();
5078
let dx = Buffer.contents buff in
5080
loop (dx :: in__attr__) rest
5081
else if dx = "" then
5082
loop in__attr__ rest
5084
(fprintf fmt "%s " dx;
5085
loop in__attr__ rest)
5088
List.filter (function Attr (s,_) -> not (List.mem s reserved_attributes)
5089
| AttrAnnot _ -> true) a
5098
(* Logic annotations printer *)
5100
method pLogic_type fmt = function
5101
| Ctype typ -> self#pType None fmt typ
5102
| Linteger -> pp_print_string fmt "integer"
5103
| Lreal -> pp_print_string fmt "real"
5105
fprintf fmt "%a%a" self#pVarName s
5106
(pretty_list_del (fun fmt -> fprintf fmt "<@[")
5107
(fun fmt -> fprintf fmt "@]>@ ")
5108
(* the space avoids the issue of list<list<int>> where the double >
5109
would be read as a shift. It could be optimized away in most of
5112
(space_sep ",") self#pLogic_type) l
5113
| Larrow (args,rt) ->
5114
fprintf fmt "@[@[<2>{@ %a@]@}@]%a"
5115
(pretty_list (space_sep ",") self#pLogic_type) args
5117
| Lvar s -> fprintf fmt "%a" self#pVarName s
5119
method pTsets_lval fmt (h,o) =
5121
TSMem t, TSField (f,o) ->
5122
fprintf fmt "%a->@,%a@,%a"
5123
(self#pTsets_elemPrec arrowLevel) t
5124
self#pVarName f.fname self#pTsets_offset o
5125
| _ -> fprintf fmt "@[%a%a@]" self#pTsets_lhost h self#pTsets_offset o
5127
method private pTsets_elemPrec contextprec fmt e =
5128
let thisLevel = getParenthLevelTsetsElem e in
5130
if thisLevel >= contextprec then true
5131
else if contextprec == bitwiseLevel then
5132
(* quiet down some GCC warnings *)
5133
thisLevel == additiveLevel || thisLevel == comparativeLevel
5138
fprintf fmt "@[<hov 1>(%a)@]" self#pTsets_elem e
5140
self#pTsets_elem fmt e
5142
method pTsets_elem fmt lv =
5143
let level = getParenthLevelTsetsElem lv in
5145
TSLval lv | TSStartOf lv -> self#pTsets_lval fmt lv
5146
(*TODO: take into account priority in ts_lvals *)
5147
| TSAddrOf lv -> fprintf fmt "&%a" self#pTsets_lval lv
5148
| TSConst s -> d_const fmt s
5149
| TSAdd_range(t,low,high) ->
5150
fprintf fmt "@[%a@ +@ (@[%a..@,%a@])@]"
5151
(self#pTsets_elemPrec level) t
5153
(fun fmt t -> fprintf fmt "%a@ " self#pTerm t)) low
5155
(fun fmt t ->fprintf fmt "@ %a" self#pTerm t)) high
5156
| TSAdd_index(t,i) ->
5157
fprintf fmt "@[%a@ +@ %a@]"
5158
(self#pTsets_elemPrec level) t
5159
(self#pTermPrec level) i
5160
| TSCastE(typ,elem) ->
5161
fprintf fmt "@[(%a)@,%a@]"
5162
(self#pType None) typ (self#pTsets_elemPrec level) elem
5164
fprintf fmt "@[<hov 2>\\at(%a,%a)@]"
5165
self#pTsets_elem l self#pLogicLabel lab
5166
| TSapp(f,labs,args) ->
5167
fprintf fmt "@[<hov 2>%a@,%a@,%a@]"
5168
self#pLogic_info_use f
5170
(fun fmt -> pp_print_string fmt "<")
5171
(fun fmt -> pp_print_string fmt ">")
5173
(fun fmt (_,y) -> self#pLogicLabel fmt y)) labs
5175
(fun fmt -> pp_print_string fmt "(")
5176
(fun fmt -> pp_print_string fmt ")")
5177
(space_sep ",") self#pTerm) args
5179
method pTsets_lhost fmt h =
5181
| TSVar lv -> self#pLogic_var fmt lv
5182
| TSResult -> pp_print_string fmt "\\result"
5183
| TSMem (TSAdd_index(t,i)) ->
5184
fprintf fmt "@[<2>%a[%a]@]"
5185
(self#pTsets_elemPrec derefStarLevel) t
5187
| TSMem (TSAdd_range(t,low,high)) ->
5188
fprintf fmt "@[<2>%a[%a..%a]@]"
5189
(self#pTsets_elemPrec derefStarLevel) t
5190
(pretty_opt self#pTerm) low
5191
(pretty_opt self#pTerm) high
5192
| TSMem t -> fprintf fmt "@[<1>*%a@]"
5193
(self#pTsets_elemPrec derefStarLevel) t
5195
method pTsets_offset fmt o =
5199
fprintf fmt "@,@[<1>[%a]@]%a" self#pTerm t self#pTsets_offset o
5200
| TSRange (t1,t2,o) ->
5201
fprintf fmt "@,@[<1>[%a..%a]@]%a"
5202
(pretty_opt self#pTerm) t1
5203
(pretty_opt self#pTerm) t2
5204
self#pTsets_offset o
5206
fprintf fmt "@,@[<1>.%a@]%a"
5207
self#pVarName f.fname self#pTsets_offset o
5209
method pTsets fmt loc = (* to be rewritten *)
5211
| TSSingleton t -> self#pTsets_elem fmt t
5213
fprintf fmt "@[<hov 2>\\union(@,%a)@]"
5214
(pretty_list (space_sep ",") self#pTsets) locs
5216
fprintf fmt "@[<hov 2>\\inter(@,%a)@]"
5217
(pretty_list (space_sep ",") self#pTsets) locs
5218
| TSEmpty -> pp_print_string fmt "\\empty"
5219
| TSComprehension(lv,quant,pred) ->
5220
fprintf fmt "{@[%a@ |@ %a%a@]}"
5221
self#pTsets lv self#pQuantifiers quant
5222
(pretty_opt (fun fmt p -> fprintf fmt ";@ %a"
5223
self#pPredicate_named p))
5226
method private pTermPrec contextprec fmt e =
5227
let thisLevel = getParenthLevelLogic e.term_node in
5229
if thisLevel >= contextprec then
5231
else if contextprec == bitwiseLevel then
5232
(* quiet down some GCC warnings *)
5233
thisLevel == additiveLevel || thisLevel == comparativeLevel
5238
fprintf fmt "@[<hov 2>(%a)@]" self#pTerm e
5242
method pTerm fmt t =
5243
match t.term_name with
5244
[] -> self#pTerm_node fmt t
5246
fprintf fmt "(@[%a:@ %a@])"
5247
(pretty_list (swap fprintf ":@ ") pp_print_string) t.term_name
5250
method pTerm_node fmt t =
5251
let current_level = getParenthLevelLogic t.term_node in
5252
match t.term_node with
5253
| TConst s -> fprintf fmt "%a" d_const s
5254
| TDataCons(ci,args) ->
5255
fprintf fmt "%a%a" self#pVarName ci.ctor_name
5256
(pretty_list_del (swap fprintf "(@[") (swap fprintf "@])")
5257
(space_sep ",") self#pTerm) args
5258
| TLval lv -> fprintf fmt "%a" (self#pTerm_lvalPrec current_level) lv
5259
| TSizeOf t -> fprintf fmt "sizeof(%a)" (self#pType None) t
5260
| TSizeOfE e -> fprintf fmt "sizeof(%a)" self#pTerm e
5261
| TSizeOfStr s -> fprintf fmt "sizeof(%S)" s
5262
| TAlignOf e -> fprintf fmt "alignof(%a)" (self#pType None) e
5263
| TAlignOfE e -> fprintf fmt "alignof(%a)" self#pTerm e
5264
| TUnOp (op,e) -> fprintf fmt "%a%a"
5265
d_unop op (self#pTermPrec current_level) e
5266
| TBinOp (op,l,r) ->
5267
fprintf fmt "%a%a%a"
5268
(self#pTermPrec current_level) l
5270
(self#pTermPrec current_level) r
5272
fprintf fmt "(%a)%a" (self#pType None) ty
5273
(self#pTermPrec current_level) e
5274
| TAddrOf lv -> fprintf fmt "&%a" (self#pTerm_lvalPrec addrOfLevel) lv
5275
| TStartOf lv -> fprintf fmt "%a" (self#pTerm_lvalPrec current_level) lv
5276
| Tapp (f, labels, tl) -> fprintf fmt "%a%a%a"
5277
self#pLogic_info_use f
5278
self#pLabels (List.map snd labels)
5280
(fun fmt -> Format.fprintf fmt "@[(")
5281
(fun fmt -> Format.fprintf fmt ")@]")
5282
(space_sep ",") self#pTerm) tl
5283
| Tif (cond,th,el) ->
5284
fprintf fmt "@[<2>%a?@;%a:@;%a@]"
5285
(self#pTermPrec current_level) cond
5286
(self#pTermPrec current_level) th
5287
(self#pTermPrec current_level) el
5288
| Told e -> fprintf fmt "\\old(%a)" self#pTerm e
5291
let rec pickLabel = function
5293
| Label (l, _, _) :: _ -> Some l
5294
| _ :: rest -> pickLabel rest
5296
let l = match lab with
5299
match pickLabel !sref.labels with
5302
error "Cannot find label for \\at@.";
5305
fprintf fmt "@[\\at(@[@[%a@],@,@[%s@]@])@]" self#pTerm t l
5307
| Tbase_addr t -> fprintf fmt "\\base_addr(%a)" self#pTerm t
5308
| Tblock_length t -> fprintf fmt "\\block_length(%a)" self#pTerm t
5309
| Tnull -> fprintf fmt "\\null"
5311
fprintf fmt "%a@ :>@ %a"
5312
(self#pTermPrec current_level) e (self#pType None) ty
5313
| TCoerceE (e,ce) ->
5314
fprintf fmt "%a :> %a"
5315
(self#pTermPrec current_level) e (self#pTermPrec current_level) ce
5316
| TUpdate (t,f,v) ->
5317
fprintf fmt "{%a for %s = %a}"
5321
| Tlambda(prms,expr) ->
5322
fprintf fmt "@[<2>\\lambda@ %a;@ %a@]"
5323
self#pQuantifiers prms (self#pTermPrec current_level) expr
5324
| Ttypeof t -> fprintf fmt "\\typeof(%a)" self#pTerm t
5325
| Ttype ty -> fprintf fmt "\\type(%a)" (self#pType None) ty
5327
self#pTsets fmt tsets
5329
method private pTerm_lvalPrec contextprec fmt lv =
5330
if getParenthLevelLogic (TLval lv) > contextprec then
5331
fprintf fmt "(%a)" self#pTerm_lval lv
5333
fprintf fmt "%a" self#pTerm_lval lv
5335
method pTerm_lval fmt lv = match lv with
5336
| TVar vi, o -> fprintf fmt "%a%a" self#pLogic_var vi self#pTerm_offset o
5337
| TResult, o -> fprintf fmt "\\result%a" self#pTerm_offset o
5338
| TMem ({term_node=TBinOp((PlusPI|IndexPI),base,off)}), o ->
5339
fprintf fmt "%a[%a]%a"
5340
(self#pTermPrec derefStarLevel) base
5343
| TMem e, TField(fi,o) ->
5344
fprintf fmt "%a->%a%a" (self#pTermPrec arrowLevel) e
5345
self#pVarName fi.fname self#pTerm_offset o
5346
| TMem e, TNoOffset ->
5347
fprintf fmt "*%a" (self#pTermPrec derefStarLevel) e
5349
fprintf fmt "(*%a)%a"
5350
(self#pTermPrec derefStarLevel) e self#pTerm_offset o
5352
method pTerm_offset fmt o = match o with
5355
fprintf fmt ".%a%a" self#pVarName fi.fname self#pTerm_offset o
5356
| TIndex(e,o) -> fprintf fmt "[%a]%a" self#pTerm e self#pTerm_offset o
5358
method pLogic_info_use fmt li = self#pVarName fmt li.l_name
5360
method pLogic_var fmt v = self#pVarName fmt v.lv_name
5362
method pQuantifiers fmt l =
5363
pretty_list (space_sep ",")
5365
fprintf fmt "%a@ %a" self#pLogic_type lv.lv_type self#pLogic_var lv)
5368
method pPredicate fmt p =
5369
(* TODO: get a real priority level for predicates and use it to
5370
pretty_print subterms.
5372
let term = self#pTermPrec logic_level in
5374
| Pfalse -> fprintf fmt "\\false"
5375
| Ptrue -> fprintf fmt "\\true"
5376
| Papp (p,labels,l) -> fprintf fmt "@[%a%a%a@]"
5377
self#pLogic_info_use p
5378
self#pLabels (List.map snd labels)
5380
(fun fmt -> Format.fprintf fmt "@[(")
5381
(fun fmt -> Format.fprintf fmt ")@]")
5382
(space_sep ",") self#pTerm) l
5384
fprintf fmt "@[(@[%a@]@ %a@ @[%a@])@]" term l d_relation rel term r
5386
fprintf fmt "@[(@[%a@]@ %a@ @[%a@])@]"
5387
self#pPredicate_named p1
5389
self#pPredicate_named p2
5391
fprintf fmt "@[(@[%a@]@ %a@ @[%a@])@]"
5392
self#pPredicate_named p1
5394
self#pPredicate_named p2
5396
fprintf fmt "@[(@[%a@]@ %s@ @[%a@])@]"
5397
self#pPredicate_named p1
5398
(if !print_utf8 then Utf8_logic.x_or else "^^")
5399
self#pPredicate_named p2
5400
| Pimplies (p1,p2) ->
5401
fprintf fmt "@[(@[%a@]@ %s@ @[%a@])@]"
5402
self#pPredicate_named p1
5403
(if !print_utf8 then Utf8_logic.implies else "==>")
5404
self#pPredicate_named p2
5406
fprintf fmt "@[(@[%a@]@ %s@ @[%a@])@]"
5407
self#pPredicate_named p1
5408
(if !print_utf8 then Utf8_logic.iff else "<==>")
5409
self#pPredicate_named p2
5410
| Pnot a -> fprintf fmt "@[%s(@[%a@])@]"
5411
(if !print_utf8 then Utf8_logic.neg else "!")
5412
self#pPredicate_named a
5413
| Pif (e, p1, p2) ->
5414
fprintf fmt "@[<2>(%a?@ %a:@ %a)@]"
5415
term e self#pPredicate_named p1 self#pPredicate_named p2
5417
fprintf fmt "@[(@[let %a =@]@ @[%a@]@ @[in %a@])@]"
5418
self#pLogic_var v term t self#pPredicate_named p
5419
| Pforall (quant,pred) ->
5420
fprintf fmt "@[(@[%s %a;@]@ %a)@]"
5421
(if !print_utf8 then Utf8_logic.forall else "\\forall")
5422
self#pQuantifiers quant self#pPredicate_named pred
5423
| Pexists (quant,pred) ->
5424
fprintf fmt "@[(@[%s %a;@]@ %a)@]"
5425
(if !print_utf8 then Utf8_logic.exists else "\\exists")
5426
self#pQuantifiers quant self#pPredicate_named pred
5427
| Pold a -> fprintf fmt "@[\\old(@[%a@])@]" self#pPredicate_named a
5428
| Pvalid p -> fprintf fmt "@[\\valid(@[%a@])@]" self#pTsets p
5429
| Pseparated seps ->
5430
fprintf fmt "@[<2>\\separated(@,%a@,)@]"
5431
(pretty_list (space_sep ",") self#pTsets) seps
5432
| Pat (p,StmtLabel sref) ->
5434
let rec pickLabel = function
5436
| Label (l, _, _) :: _ -> Some l
5437
| _ :: rest -> pickLabel rest
5439
let l = match pickLabel !sref.labels with
5442
error "Cannot find label for \\at@.";
5446
fprintf fmt "@[\\at(@[@[%a@],@,@[%s@]@])@]"
5447
self#pPredicate_named p l
5449
| Pat(p,LogicLabel s) ->
5450
fprintf fmt "@[\\at(@[@[%a@],@,%s@])@]"
5451
self#pPredicate_named p s
5452
| Pfresh e -> fprintf fmt "@[\\fresh(@[%a@])@]" self#pTerm e
5453
| Pvalid_index (e1,e2) ->
5454
fprintf fmt "@[\\valid_index(@[@[%a@],@,@[%a@]@])@]"
5455
self#pTerm e1 self#pTerm e2
5456
| Pvalid_range (e1,e2,e3) ->
5457
fprintf fmt "@[\\valid_range(@[@[%a@],@,@[%a@],@,@[%a@]@])@]"
5458
self#pTerm e1 self#pTerm e2 self#pTerm e3
5459
| Psubtype (e,ce) ->
5460
fprintf fmt "%a <: %a" term e term ce
5462
method pPredicate_named fmt p =
5464
[] -> self#pPredicate fmt p.content
5466
fprintf fmt "(@[%a:@ %a@])"
5467
(pretty_list (swap fprintf ":@ ") pp_print_string) p.name
5468
self#pPredicate p.content
5471
method pPredicate_info_use fmt pi = self#pVarName fmt pi.p_name
5474
method private preds kw fmt l =
5475
pretty_list_del ignore nl_sep nl_sep
5477
fprintf fmt "@[%s @[%a@];@]" kw
5478
self#pPredicate_named
5479
({name = p.ip_name; loc = p.ip_loc; content = p.ip_content})) fmt l
5481
method private pDecrement kw fmt (t, rel) =
5483
None -> fprintf fmt "@[<2>%s@ %a;@]@\n" kw self#pTerm t
5485
(*TODO: replace this string with an interpreted variable*)
5486
fprintf fmt "@[<2>%s@ %a@ for@ %s;@]@\n" kw self#pTerm t str
5488
method pBehavior fmt b =
5489
fprintf fmt "@[behavior %s:@\n @[%a%a%a@]@]"
5490
b.b_name (self#preds "assumes") b.b_assumes
5491
(self#preds "ensures") b.b_ensures
5492
(pretty_list (fun _ -> ()) (self#pAssigns "assigns")) b.b_assigns
5494
method pSpec fmt { spec_requires = requires;
5495
spec_behavior = behaviors;
5496
spec_variant = variant;
5497
spec_terminates = terminates;
5498
spec_complete_behaviors = complete;
5499
spec_disjoint_behaviors = disjoint;
5501
fprintf fmt "@[%a%a%a%a%a%a@]"
5502
(self#preds "requires") requires
5504
(fun fmt p -> fprintf fmt "@[<2>terminates@ %a;@]@\n"
5505
self#pPredicate_named {name = p.ip_name; loc = p.ip_loc;
5506
content = p.ip_content})) terminates
5507
(pretty_list nl_sep self#pBehavior) behaviors
5508
(pretty_list_del nl_sep nl_sep nl_sep
5510
(space_sep "complete behaviors")
5513
Format.pp_print_string)) complete
5514
(pretty_list_del nl_sep nl_sep nl_sep
5516
(space_sep "disjoint behaviors")
5519
Format.pp_print_string)) disjoint
5520
(pretty_opt (self#pDecrement "decreases")) variant
5522
method private pAssigns kw fmt (base,deps) =
5523
fprintf fmt "@[%s@ %a%a;@]@\n" kw self#pZone base
5524
(pretty_list_del (swap fprintf "@ \\from@ ") (fun _ -> ())
5525
(space_sep ",") self#pZone) deps
5527
method pZone fmt locs =
5530
pp_print_string fmt "\\nothing"
5531
| Location loc -> self#pTsets fmt loc.its_content
5533
method private pLoop_pragma fmt = function
5534
| Widen_hints terms -> fprintf fmt "WIDEN_HINTS @[%a@]"
5536
(fun _ -> ()) (fun _ -> ())
5537
(space_sep ",") self#pTerm) terms
5538
| Widen_variables terms -> fprintf fmt "WIDEN_VARIABLES @[%a@]"
5540
(fun _ -> ()) (fun _ -> ())
5541
(space_sep ",") self#pTerm) terms
5542
| Unroll_level t -> fprintf fmt "UNROLL @[%a@]" self#pTerm t
5544
method private pSlice_pragma fmt = function
5546
fprintf fmt "expr @[%a@]" self#pTerm t
5547
| SPctrl -> pp_print_string fmt "ctrl"
5548
| SPstmt -> pp_print_string fmt "stmt"
5550
method private pImpact_pragma fmt = function
5551
| IPexpr t -> fprintf fmt "expr @[%a@]" self#pTerm t
5552
| IPstmt -> pp_print_string fmt "stmt"
5554
method pStatus fmt s =
5556
| Unknown -> fprintf fmt "No proof attempted@\n"
5557
| Checked {emitter=s; valid=True} ->
5558
fprintf fmt "Valid according to %s@\n" s
5559
| Checked {emitter=s; valid=False} ->
5560
fprintf fmt "NOT valid according to %s@\n" s
5561
| Checked {emitter=s; valid=Maybe} ->
5562
fprintf fmt "Unknown (%s could not decide the status for this property)@\n" s
5564
(* TODO: add the annot ID in debug mode?*)
5565
method pCode_annot fmt ca =
5566
match ca.annot_content with
5567
| AAssert (behav,p,_status) -> fprintf fmt "@[%aassert@ %a;@]@\n"
5569
(fun fmt -> fprintf fmt "for ") (fun fmt -> fprintf fmt ": ")
5570
(space_sep ",") pp_print_string)
5572
self#pPredicate_named p
5573
| AAssume p -> fprintf fmt "@[assume@ %a;@]@\n"
5574
self#pPredicate_named p
5575
| APragma (Slice_pragma sp) ->
5576
fprintf fmt "@[slice pragma@ %a;@]@\n" self#pSlice_pragma sp
5577
| APragma (Impact_pragma sp) ->
5578
fprintf fmt "@[impact pragma@ %a;@]@\n" self#pImpact_pragma sp
5579
| APragma (Loop_pragma lp) ->
5580
fprintf fmt "@[loop pragma@ %a;@]@\n" self#pLoop_pragma lp
5581
| AStmtSpec sp -> self#pSpec fmt sp
5582
| AAssigns a -> self#pAssigns "loop assigns" fmt a
5583
| AInvariant(behav,true, i) -> fprintf fmt "@[<2>%aloop invariant@ %a;@]@\n"
5585
(fun fmt -> fprintf fmt "for ") (fun fmt -> fprintf fmt ": ")
5586
(space_sep ",") pp_print_string)
5588
self#pPredicate_named i
5589
| AInvariant(behav,false,i) -> fprintf fmt "@[<2>%ainvariant@ %a;@]@\n"
5591
(fun fmt -> fprintf fmt "for ") (fun fmt -> fprintf fmt ": ")
5592
(space_sep ",") pp_print_string)
5594
self#pPredicate_named i
5595
| AVariant v -> self#pDecrement "loop variant" fmt v
5597
method private pLogicPrms fmt arg =
5598
fprintf fmt "%a@ %a" self#pLogic_type arg.lv_type self#pLogic_var arg
5600
method private pTypeParameters fmt tvars =
5602
(fun fmt -> fprintf fmt "<@[") (fun fmt -> fprintf fmt "@]>")
5603
(space_sep ",") pp_print_string fmt tvars
5605
method private pLogicLabel fmt lab =
5610
let rec pickLabel = function
5612
| Label (l, _, _) :: _ -> Some l
5613
| _ :: rest -> pickLabel rest
5615
match pickLabel !sref.labels with
5617
| None -> "__invalid_label"
5618
in pp_print_string fmt s
5620
method private pLabels fmt labels =
5622
(fun fmt -> fprintf fmt "{@[") (fun fmt -> fprintf fmt "@]}")
5623
(space_sep ",") self#pLogicLabel fmt labels
5625
method pAnnotation fmt = function
5627
fprintf fmt "@[type invariant @[%a%a=@ %a@,;@]@]@\n"
5628
self#pVarName a.l_name
5630
(fun fmt -> Format.fprintf fmt "@[(")
5631
(fun fmt -> Format.fprintf fmt ")@]@ ")
5632
(space_sep ",") self#pLogicPrms) a.l_profile
5633
self#pPredicate_named (pred_body a.l_body)
5634
| Dinvariant pred ->
5635
fprintf fmt "@[global@ invariant %a:@[@ %a;@]@]@\n"
5636
self#pVarName pred.l_name
5637
self#pPredicate_named (pred_body pred.l_body)
5638
| Dlemma(name, is_axiom, labels, tvars, pred) ->
5639
fprintf fmt "@[%s@ %a%a%a:@[@ %a;@]@]@\n"
5640
(if is_axiom then "axiom" else "lemma")
5643
self#pTypeParameters tvars
5644
self#pPredicate_named pred
5645
| Dtype(name,prms) ->
5646
fprintf fmt "@[logic@ type@ %a%a;@]@\n"
5647
self#pVarName name self#pTypeParameters prms
5648
| Dfun_or_pred li ->
5650
match li.l_type with
5652
fprintf fmt "@[<hov 2>logic %a"
5655
fprintf fmt "@[<hov 2>predicate"
5657
fprintf fmt " %a%a%a%a"
5658
self#pVarName li.l_name
5659
self#pLabels li.l_labels
5660
self#pTypeParameters li.l_tparams
5662
(fun fmt -> Format.fprintf fmt "@[(")
5663
(fun fmt -> Format.fprintf fmt ")@]@ ")
5664
(space_sep ",") self#pLogicPrms) li.l_profile;
5666
match li.l_body with
5670
(fun fmt -> Format.fprintf fmt "@\n@[reads@ ")
5671
(fun fmt -> Format.fprintf fmt "@]")
5672
(space_sep ",") self#pTsets) reads
5674
fprintf fmt "=@ %a;"
5675
self#pPredicate_named def
5677
| LBaxiomatic axioms ->
5678
fprintf fmt "{@ %a}"
5680
(fun fmt -> Format.fprintf fmt "@[<v 0>")
5681
(fun fmt -> Format.fprintf fmt "@]@\n")
5684
Format.fprintf fmt "axiom %s: %a;" id
5685
self#pPredicate_named p)) axioms
5687
| LBinductive indcases ->
5688
fprintf fmt "{@ %a}"
5690
(fun fmt -> Format.fprintf fmt "@[<v 0>")
5691
(fun fmt -> Format.fprintf fmt "@]@\n")
5693
(fun fmt (id,labels,tvars,p) ->
5694
Format.fprintf fmt "case %s%a%a: %a;" id
5696
self#pTypeParameters tvars
5697
self#pPredicate_named p)) indcases
5699
fprintf fmt "=@ %a;"
5703
| Daxiomatic(id,decls) ->
5705
Format.eprintf "cil.pAnnotation on axiomatic %s@." id;
5707
fprintf fmt "@[<v 2>axiomatic@ %s {@\n%a@]}@]@\n" id
5709
(fun fmt -> Format.fprintf fmt "@[<v 0>")
5710
(fun fmt -> Format.fprintf fmt "@]@\n")
5717
| Dlogic_reads (name, tvars, args, rt, reads) ->
5718
fprintf fmt "@[logic %a %a%a%a%a%a;@]@\n"
5719
self#pLogic_type rt self#pVarName name.l_name
5720
self#pLabels name.l_labels
5721
self#pTypeParameters tvars
5723
(fun fmt -> Format.fprintf fmt "@[(")
5724
(fun fmt -> Format.fprintf fmt ")@]@ ")
5725
(space_sep ",") self#pLogicPrms) args
5727
(fun fmt -> Format.fprintf fmt "@[reads@ ")
5728
(fun fmt -> Format.fprintf fmt "@]")
5729
(space_sep ",") self#pTsets) reads
5730
| Dlogic_def (name, tvars, args, rt, def) ->
5731
fprintf fmt "@[logic@[ %a %a%a%a%a=@ %a;@]@]@\n"
5732
self#pLogic_type rt self#pVarName name.l_name
5733
self#pLabels name.l_labels
5734
self#pTypeParameters tvars
5736
(fun fmt -> Format.fprintf fmt "@[(")
5737
(fun fmt -> Format.fprintf fmt ")@]@ ")
5739
self#pLogicPrms) args
5741
| Dlogic_axiomatic (name, tvars, args, rt, axioms) ->
5742
fprintf fmt "@[logic@[ %a %a%a%a%a{@ %a}@]@]@\n"
5743
self#pLogic_type rt self#pVarName name.l_name
5744
self#pLabels name.l_labels
5745
self#pTypeParameters tvars
5747
(fun fmt -> Format.fprintf fmt "@[(")
5748
(fun fmt -> Format.fprintf fmt ")@]@ ")
5750
self#pLogicPrms) args
5752
(fun fmt -> Format.fprintf fmt "@[<v 0>")
5753
(fun fmt -> Format.fprintf fmt "@]@\n")
5756
Format.fprintf fmt "axiom %s: %a;" id
5757
self#pPredicate_named p)) axioms
5758
| Dinductive_def (name, tvars, args, indcases) ->
5759
fprintf fmt "@[predicate@[ %a%a%a%a{@ %a}@]@]@\n"
5760
self#pVarName name.p_name
5761
self#pLabels name.p_labels
5762
self#pTypeParameters tvars
5764
(fun fmt -> Format.fprintf fmt "@[(")
5765
(fun fmt -> Format.fprintf fmt ")@]@ ")
5767
self#pLogicPrms) args
5769
(fun fmt -> Format.fprintf fmt "@[<v 0>")
5770
(fun fmt -> Format.fprintf fmt "@]@\n")
5773
Format.fprintf fmt "case %s: %a;" id
5774
self#pPredicate_named p)) indcases
5775
| Dpredicate_def (info, tvars, args, def) ->
5776
fprintf fmt "@[predicate@[ %a%a%a%a=@ %a;@]@]@\n"
5777
self#pVarName info.p_name
5778
self#pLabels info.p_labels
5779
self#pTypeParameters tvars
5781
(fun fmt -> Format.fprintf fmt "@[(")
5782
(fun fmt -> Format.fprintf fmt ")@]@ ")
5783
(space_sep ",") self#pLogicPrms) args
5784
self#pPredicate_named def
5785
| Dpredicate_reads (info, tvars, args, reads) ->
5786
fprintf fmt "@[predicate %a%a%a%a%a;@]@\n"
5787
self#pVarName info.p_name
5788
self#pLabels info.p_labels
5789
self#pTypeParameters tvars
5791
(fun fmt -> Format.fprintf fmt "@[(")
5792
(fun fmt -> Format.fprintf fmt ")@]")
5793
(space_sep ",") self#pLogicPrms) args
5795
(fun fmt -> Format.fprintf fmt "@\n @[reads@ ")
5796
(fun fmt -> Format.fprintf fmt "@]")
5797
(space_sep ",") self#pTsets) reads
5799
end (* class defaultCilPrinterClass *)
5801
let defaultCilPrinter = new defaultCilPrinterClass
5803
(* Top-level printing functions *)
5804
let printType (pp: cilPrinter) fmt (t: typ) =
5807
let printExp (pp: cilPrinter) fmt (e: exp) =
5810
let printLval (pp: cilPrinter) fmt (lv: lval) =
5813
let printGlobal (pp: cilPrinter) fmt (g: global) =
5816
let printAttr (pp: cilPrinter) fmt (a: attribute) =
5817
ignore (pp#pAttr fmt a)
5819
let printAttrs (pp: cilPrinter) fmt (a: attributes) =
5822
let printInstr (pp: cilPrinter) fmt (i: instr) =
5825
let printStmt (pp: cilPrinter) fmt (s: stmt) =
5828
let printBlock (pp: cilPrinter) fmt (b: block) =
5829
(* We must add the alignment ourselves, beucase pBlock will pop it *)
5830
fprintf fmt "@[%a" (pp#pBlock ~toplevel:true) b
5832
let printInit (pp: cilPrinter) fmt (i: init) =
5835
let printTerm_lval pp fmt lv = pp#pTerm_lval fmt lv
5837
let printLogic_var pp fmt lv = pp#pLogic_var fmt lv
5839
let printLogic_type pp fmt lv = pp#pLogic_type fmt lv
5841
let printTerm pp fmt t = pp#pTerm fmt t
5843
let printTerm_offset pp fmt o = pp#pTerm_offset fmt o
5845
let printTsets pp fmt o = pp#pTsets fmt o
5847
let printTsets_elem pp fmt o = pp#pTsets_elem fmt o
5849
let printTsets_lhost pp fmt o = pp#pTsets_lhost fmt o
5851
let printTsets_offset pp fmt o = pp#pTsets_offset fmt o
5853
let printTsets_lval pp fmt o = pp#pTsets_lval fmt o
5855
let printPredicate_named pp fmt p = pp#pPredicate_named fmt p
5857
let printCode_annotation pp fmt ca = pp#pCode_annot fmt ca
5858
let printStatus pp fmt s = pp#pStatus fmt s
5860
let printFunspec pp fmt s = pp#pSpec fmt s
5862
let printAnnotation pp fmt a = pp#pAnnotation fmt a
5864
(* Now define some short cuts *)
5865
let d_exp fmt e = printExp defaultCilPrinter fmt e
5866
let _ = pd_exp := d_exp
5867
let d_lval fmt lv = printLval defaultCilPrinter fmt lv
5868
let d_offset fmt off = defaultCilPrinter#pOffset fmt off
5869
let d_init fmt i = printInit defaultCilPrinter fmt i
5870
let d_type fmt t = printType defaultCilPrinter fmt t
5871
let d_global fmt g = printGlobal defaultCilPrinter fmt g
5872
let _ = pd_global := d_global
5873
let d_attrlist fmt a = printAttrs defaultCilPrinter fmt a
5874
let d_attr fmt a = printAttr defaultCilPrinter fmt a
5875
let d_attrparam fmt e = defaultCilPrinter#pAttrParam fmt e
5876
let d_label fmt l = defaultCilPrinter#pLabel fmt l
5877
let d_stmt fmt s = printStmt defaultCilPrinter fmt s
5878
let d_block fmt b = printBlock defaultCilPrinter fmt b
5879
let d_instr fmt i = printInstr defaultCilPrinter fmt i
5881
let d_term_lval fmt lv = printTerm_lval defaultCilPrinter fmt lv
5882
let d_logic_var fmt lv = printLogic_var defaultCilPrinter fmt lv
5883
let d_logic_type fmt lv = printLogic_type defaultCilPrinter fmt lv
5884
let d_term fmt lv = printTerm defaultCilPrinter fmt lv
5885
let d_term_offset fmt lv = printTerm_offset defaultCilPrinter fmt lv
5886
let d_tsets fmt lv = printTsets defaultCilPrinter fmt lv
5887
let d_tsets_elem fmt lv = printTsets_elem defaultCilPrinter fmt lv
5888
let d_tsets_lhost fmt lv = printTsets_lhost defaultCilPrinter fmt lv
5889
let d_tsets_lval fmt lv = printTsets_lval defaultCilPrinter fmt lv
5890
let d_tsets_offset fmt lv = printTsets_offset defaultCilPrinter fmt lv
5892
let d_status fmt s = printStatus defaultCilPrinter fmt s
5893
let d_predicate_named fmt lv = printPredicate_named defaultCilPrinter fmt lv
5894
let d_code_annotation fmt lv = printCode_annotation defaultCilPrinter fmt lv
5895
let d_funspec fmt lv = printFunspec defaultCilPrinter fmt lv
5896
let d_annotation fmt lv = printAnnotation defaultCilPrinter fmt lv
5898
(* sm: given an ordinary CIL object printer, yield one which
5899
* behaves the same, except it never prints #line directives
5900
* (this is useful for debugging printfs) *)
5901
let dn_obj (func: formatter -> 'a -> unit) : (formatter -> 'a -> unit) =
5903
(* construct the closure to return *)
5904
let theFunc fmt (obj:'a) =
5906
let prevStyle = miscState.lineDirectiveStyle in
5907
miscState.lineDirectiveStyle <- None;
5908
func fmt obj; (* call underlying printer *)
5909
miscState.lineDirectiveStyle <- prevStyle
5914
(* now define shortcuts for the non-location-printing versions,
5915
* with the naming prefix "dn_" *)
5916
let dn_exp = (dn_obj d_exp)
5917
let dn_lval = (dn_obj d_lval)
5918
(* dn_offset is missing because it has a different interface *)
5919
let dn_init = (dn_obj d_init)
5920
let dn_type = (dn_obj d_type)
5921
let dn_global = (dn_obj d_global)
5922
let dn_attrlist = (dn_obj d_attrlist)
5923
let dn_attr = (dn_obj d_attr)
5924
let dn_attrparam = (dn_obj d_attrparam)
5925
let dn_stmt = (dn_obj d_stmt)
5926
let dn_instr = (dn_obj d_instr)
5930
(* Now define a cilPlainPrinter *)
5931
class plainCilPrinterClass =
5932
(* We keep track of the composite types that we have done to avoid
5934
let donecomps : (int, unit) H.t = H.create 13 in
5937
inherit defaultCilPrinterClass as super
5939
(*** PLAIN TYPES ***)
5940
method pType (dn: doc option) () (t: typ) =
5942
None -> self#pOnlyType () t
5943
| Some d -> d ++ text " : " ++ self#pOnlyType () t
5945
method private pOnlyType () = function
5946
TVoid a -> dprintf "TVoid(@[%a@])" self#pAttrs a
5947
| TInt(ikind, a) -> dprintf "TInt(@[%a,@?%a@])"
5948
d_ikind ikind self#pAttrs a
5949
| TFloat(fkind, a) ->
5950
dprintf "TFloat(@[%a,@?%a@])" d_fkind fkind self#pAttrs a
5952
dprintf "TNamed(@[%a,@?%a,@?%a@])"
5953
self#pVarName t.tname self#pOnlyType t.ttype self#pAttrs a
5954
| TPtr(t, a) -> dprintf "TPtr(@[%a,@?%a@])" self#pOnlyType t self#pAttrs a
5956
let dl = match l with
5957
None -> text "None" | Some l -> dprintf "Some(@[%a@])" self#pExp l in
5958
dprintf "TArray(@[%a,@?%a,@?%a@])"
5959
self#pOnlyType t insert dl self#pAttrs a
5960
| TEnum(enum,a) -> dprintf "Enum(%a,@[%a@])"
5961
self#pVarName enum.ename self#pAttrs a
5962
| TFun(tr,args,isva,a) ->
5963
dprintf "TFun(@[%a,@?%a%s,@?%a@])"
5966
(if args = None then text "None"
5967
else (docList ~sep:(chr ',' ++ break)
5969
dprintf "%s: %a" an self#pOnlyType at))
5972
(if isva then "..." else "") self#pAttrs a
5973
| TComp (comp, a) ->
5974
if H.mem donecomps comp.ckey then
5975
dprintf "TCompLoop(%s %a, _, %a)"
5976
(if comp.cstruct then "struct" else "union")
5977
self#pVarName comp.cname self#pAttrs comp.cattr
5979
H.add donecomps comp.ckey (); (* Add it before we do the fields *)
5980
dprintf "TComp(@[%s %a,@?%a,@?%a,@?%a@])"
5981
(if comp.cstruct then "struct" else "union")
5982
self#pVarName comp.cname
5983
(docList ~sep:(chr ',' ++ break)
5984
(fun f -> dprintf "%a : %a"
5985
self#pVarName f.fname self#pOnlyType f.ftype))
5987
self#pAttrs comp.cattr
5990
| TBuiltin_va_list a ->
5991
dprintf "TBuiltin_va_list(%a)" self#pAttrs a
5994
(* Some plain pretty-printers. Unlike the above these expose all the
5995
* details of the internal representation *)
5996
method pExp () = function
5998
let d_plainconst () c =
6000
CInt64(i, ik, so) ->
6001
dprintf "Int64(%s,%a,%s)"
6002
(Int64.format "%d" i)
6004
(match so with Some s -> s | _ -> "None")
6006
text ("CStr(\"" ^ escape_string s ^ "\")")
6008
dprintf "CWStr(%a)" d_const c
6010
| CChr(c) -> text ("CChr('" ^ escape_char c ^ "')")
6011
| CReal(f, fk, so) ->
6012
dprintf "CReal(%f, %a, %s)"
6015
(match so with Some s -> s | _ -> "None")
6016
| CEnum(_, s, _) -> text s
6018
text "Const(" ++ d_plainconst () c ++ text ")"
6028
| CastE(t,e) -> dprintf "CastE(@[%a,@?%a@])" self#pOnlyType t self#pExp e
6031
dprintf "UnOp(@[%a,@?%a@])"
6032
d_unop u self#pExp e1
6034
| BinOp(b,e1,e2,_) ->
6035
let d_plainbinop () b =
6037
PlusA -> text "PlusA"
6038
| PlusPI -> text "PlusPI"
6039
| IndexPI -> text "IndexPI"
6040
| MinusA -> text "MinusA"
6041
| MinusPP -> text "MinusPP"
6042
| MinusPI -> text "MinusPI"
6045
dprintf "%a(@[%a,@?%a@])" d_plainbinop b
6046
self#pExp e1 self#pExp e2
6049
text "sizeof(" ++ self#pType None () t ++ chr ')'
6051
text "sizeofE(" ++ self#pExp () e ++ chr ')'
6053
text "sizeofStr(" ++ d_const () (CStr s) ++ chr ')'
6055
text "__alignof__(" ++ self#pType None () t ++ chr ')'
6057
text "__alignof__(" ++ self#pExp () e ++ chr ')'
6059
| StartOf lv -> dprintf "StartOf(%a)" self#pLval lv
6060
| AddrOf (lv) -> dprintf "AddrOf(%a)" self#pLval lv
6064
method private d_plainoffset () = function
6065
NoOffset -> text "NoOffset"
6067
dprintf "Field(@[%a:%a,@?%a@])"
6068
self#pVarName fi.fname self#pOnlyType fi.ftype self#d_plainoffset o
6070
dprintf "Index(@[%a,@?%a@])" self#pExp e self#d_plainoffset o
6072
method pInit () = function
6073
SingleInit e -> dprintf "SI(%a)" d_exp e
6074
| CompoundInit (t, initl) ->
6075
let d_plainoneinit (o, i) =
6076
self#d_plainoffset () o ++ text " = " ++ self#pInit () i
6078
dprintf "CI(@[%a,@?%a@])" self#pOnlyType t
6079
(docList ~sep:(chr ',' ++ break) d_plainoneinit) initl
6081
| ArrayInit (t, len, initl) ->
6082
let idx = ref (- 1) in
6083
let d_plainoneinit i =
6085
text "[" ++ num !idx ++ text "] = " ++ self#pInit () i
6087
dprintf "AI(@[%a,%d,@?%a@])" self#pOnlyType t len
6088
(docList ~sep:(chr ',' ++ break) d_plainoneinit) initl
6090
method pLval () (lv: lval) =
6092
| Var vi, o -> dprintf "Var(@[%a,@?%a@])"
6093
self#pVarName vi.vname self#d_plainoffset o
6094
| Mem e, o -> dprintf "Mem(@[%a,@?%a@])" self#pExp e self#d_plainoffset o
6098
let plainCilPrinter = new plainCilPrinterClass
6100
(* And now some shortcuts *)
6101
let d_plainexp fmt e = defaultCilPrinter#pExp fmt e
6102
let d_plaintype fmt t = defaultCilPrinter#pType None fmt t
6103
let d_plaininit fmt i = defaultCilPrinter#pInit fmt i
6104
let d_plainlval fmt l = defaultCilPrinter#pLval fmt l
6105
class type descriptiveCilPrinter = object
6108
method startTemps: unit -> unit
6109
method stopTemps: unit -> unit
6110
method pTemps: Format.formatter -> unit
6113
class descriptiveCilPrinterClass : descriptiveCilPrinter = object (self)
6114
(** Like defaultCilPrinterClass, but instead of temporary variable
6115
names it prints the description that was provided when the temp was
6116
created. This is usually better for messages that are printed for end
6117
users, although you may want the temporary names for debugging. *)
6118
inherit defaultCilPrinterClass as super
6120
val mutable temps: (varinfo * string * string option) list = []
6121
val mutable useTemps: bool = false
6123
method startTemps () : unit =
6127
method stopTemps () : unit =
6135
fprintf fmt "@\nWhere:@\n %a"
6136
(fprintfList ~sep:"\n "
6137
(let f fmt v = match v with
6138
| (_, s, Some d) -> fprintf fmt "%s = %s" s d
6139
|(_, s, None) -> fprintf fmt "%s = " s in f))
6142
method private pVarDescriptive fmt (vi: varinfo) =
6143
match vi.vdescr with
6145
if vi.vdescrpure || not useTemps then
6149
let _, name, _ = List.find (fun (vi', _, _) -> vi == vi') temps in
6150
fprintf fmt "%s" name
6152
let name = "tmp" ^ string_of_int (List.length temps) in
6153
temps <- (vi, name, vi.vdescr) :: temps;
6154
fprintf fmt "%s" name
6159
(* Only substitute temp vars that appear in expressions.
6160
(Other occurrences of lvalues are the left-hand sides of assignments,
6161
but we shouldn't substitute there since "foo(a,b) = foo(a,b)"
6162
would make no sense to the user.) *)
6163
method pExp fmt (e:exp) =
6166
| StartOf (Var vi, o) ->
6167
fprintf fmt "%a%a" self#pVarDescriptive vi self#pOffset o
6168
| AddrOf (Var vi, o) ->
6169
(* No parens needed, since offsets have higher precedence than & *)
6170
fprintf fmt "& %a%a" self#pVarDescriptive vi self#pOffset o
6171
| _ -> super#pExp fmt e
6174
let descriptiveCilPrinter: descriptiveCilPrinter =
6175
((new descriptiveCilPrinterClass) :> descriptiveCilPrinter)
6177
let dd_exp = descriptiveCilPrinter#pExp
6178
let dd_lval = descriptiveCilPrinter#pLval
6181
(* zra: this allows pretty printers not in cil.ml to
6182
be exposed to cilmain.ml *)
6183
let printerForMaincil = ref defaultCilPrinter
6185
let rec d_typsig () = function
6186
TSArray (ts, eo, al) ->
6187
dprintf "TSArray(@[%a,@?%a,@?%a@])"
6189
insert (text (match eo with None -> "None"
6190
| Some e -> "Some " ^ Int64.to_string e))
6193
dprintf "TSPtr(@[%a,@?%a@])"
6194
d_typsig ts d_attrlist al
6195
| TSComp (iss, name, al) ->
6196
dprintf "TSComp(@[%s %s,@?%a@])"
6197
(if iss then "struct" else "union") name
6199
| TSFun (rt, args, isva, al) ->
6200
dprintf "TSFun(@[%a,@?%a,%b,@?%a@])"
6202
(docList ~sep:(chr ',' ++ break) (d_typsig ())) args isva
6205
dprintf "TSEnum(@[%s,@?%a@])"
6207
| TSBase t -> dprintf "TSBase(%a)" d_type t
6210
(* Make a varinfo. Used mostly as a helper function below *)
6211
let makeVarinfo ?(logic=false) global formal name typ =
6212
(* Strip const from type for locals *)
6214
{ vorig_name = name;
6220
vtype = if formal || global then typ
6221
else typeRemoveAttributes ["const"] typ;
6225
vstorage = NoStorage;
6227
vreferenced = false;
6232
vlogic_var_assoc = None
6238
let cvar_to_lvar vi =
6239
(*Format.printf "Converting cvar %s(%d) to logic var@." vi.vname vi.vid;*)
6240
match vi.vlogic_var_assoc with
6243
{ lv_name = vi.vname;
6245
lv_type = Ctype vi.vtype ;
6246
lv_origin = Some vi}
6247
in vi.vlogic_var_assoc <- Some lv; lv
6250
let copyVarinfo (vi: varinfo) (newname: string) : varinfo =
6251
let vi' = copy_with_new_vid vi in
6252
vi'.vname <- newname;
6253
(match vi.vlogic_var_assoc with
6256
vi'.vlogic_var_assoc <- None;
6257
ignore(cvar_to_lvar vi'));
6260
let makeLocal ?(formal=false) fdec name typ = (* a helper function *)
6261
fdec.smaxid <- 1 + fdec.smaxid;
6262
let vi = makeVarinfo false formal name typ in
6265
(* Make a local variable and add it to a function *)
6266
let makeLocalVar fdec ?(insert = true) name typ =
6267
let vi = makeLocal fdec name typ in
6268
if insert then fdec.slocals <- fdec.slocals @ [vi];
6271
let makeTempVar fdec ?(name = "__cil_tmp") ?descr ?(descrpure = true)
6273
let rec findUniqueName () : string=
6274
let n = name ^ (string_of_int (1 + fdec.smaxid)) in
6275
(* Is this check a performance problem? We could bring the old
6276
unchecked makeTempVar back as a separate function that assumes
6277
the prefix name does not occur in the original program. *)
6278
if (List.exists (fun vi -> vi.vname = n) fdec.slocals)
6279
|| (List.exists (fun vi -> vi.vname = n) fdec.sformals) then begin
6280
fdec.smaxid <- 1 + fdec.smaxid;
6285
let name = findUniqueName () in
6286
let vi = makeLocalVar fdec name typ in
6288
vi.vdescrpure <- descrpure;
6292
let counter = ref 0 in
6295
let name = "@" ^ (string_of_int !counter) in
6296
makeVarinfo ~logic:true (* global= *)false (* formal= *)false name ty
6298
(* Set the formals and re-create the function name based on the information*)
6299
let setFormals (f: fundec) (forms: varinfo list) =
6300
List.iter (fun v -> v.vformal <- true) forms;
6301
f.sformals <- forms; (* Set the formals *)
6302
match unrollType f.svar.vtype with
6303
TFun(rt, _, isva, fa) ->
6306
Some (List.map (fun a -> (a.vname, a.vtype, a.vattr)) forms),
6308
| _ -> E.s (E.bug "Set formals. %s does not have function type\n"
6311
(* Set the types of arguments and results as given by the function type
6312
* passed as the second argument *)
6313
let setFunctionType (f: fundec) (t: typ) =
6314
match unrollType t with
6315
TFun (_rt, Some args, _va, _a) ->
6316
if List.length f.sformals <> List.length args then
6317
E.s (E.bug "setFunctionType: number of arguments differs from the number of formals");
6318
(* Change the function type. *)
6320
(* Change the sformals and we know that indirectly we'll change the
6323
(fun (_an,at,aa) f ->
6324
f.vtype <- at; f.vattr <- aa)
6327
| _ -> E.s (E.bug "setFunctionType: not a function type")
6330
(* Set the types of arguments and results as given by the function type
6331
* passed as the second argument *)
6332
let setFunctionTypeMakeFormals (f: fundec) (t: typ) =
6333
match unrollType t with
6334
TFun (_rt, Some args, _va, _a) ->
6335
if f.sformals <> [] then
6336
E.s (E.warn "setFunctionTypMakeFormals called on function %s with some formals already"
6338
(* Change the function type. *)
6342
f.sformals <- List.map (fun (n,t,_a) -> makeLocal ~formal:true f n t) args;
6346
| _ -> E.s (bug "setFunctionTypeMakeFormals: not a function type: %a"
6350
let setMaxId (f: fundec) =
6351
f.smaxid <- List.length f.sformals + List.length f.slocals
6354
(* Make a formal variable for a function. Insert it in both the sformals
6355
* and the type of the function. You can optionally specify where to insert
6356
* this one. If where = "^" then it is inserted first. If where = "$" then
6357
* it is inserted last. Otherwise where must be the name of a formal after
6358
* which to insert this. By default it is inserted at the end. *)
6359
let makeFormalVar fdec ?(where = "$") name typ : varinfo =
6360
(* Search for the insertion place *)
6361
let thenewone = ref fdec.svar in (* Just a placeholder *)
6362
let makeit () : varinfo =
6363
let vi = makeLocal ~formal:true fdec name typ in
6367
let rec loopFormals = function
6369
if where = "$" then [makeit ()]
6370
else E.s (E.error "makeFormalVar: cannot find insert-after formal %s"
6372
| f :: rest when f.vname = where -> f :: makeit () :: rest
6373
| f :: rest -> f :: loopFormals rest
6376
if where = "^" then makeit () :: fdec.sformals else
6377
loopFormals fdec.sformals in
6378
setFormals fdec newformals;
6381
(* Make a global variable. Your responsibility to make sure that the name
6383
let makeGlobalVar ?logic name typ =
6384
let vi = makeVarinfo ?logic true false name typ in
6387
module FormalsDecl =
6388
Computation.Make_Hashtbl
6389
(Cilutil.VarinfoHashtbl)
6390
(Datatype.List(Cil_datatype.Varinfo))
6392
let name = "FormalsDecl"
6393
let dependencies = [] (* depends on file in Frama-C kernel *)
6397
let selfFormalsDecl = FormalsDecl.self
6399
let makeFormalsVarDecl (n,t,a) =
6400
let vi = makeVarinfo false true n t in
6404
let setFormalsDecl vi typ =
6405
match unrollType typ with
6406
| TFun(_, Some args, _, _) ->
6407
FormalsDecl.replace vi (List.map makeFormalsVarDecl args)
6408
| TFun(_,None,_,_) -> ()
6410
"trying to assigns formal parameters to an object which is \
6411
not a function prototype"
6413
let getFormalsDecl vi = FormalsDecl.find vi
6415
let unsafeSetFormalsDecl vi args = FormalsDecl.replace vi args
6418
(* Make an empty function *)
6419
let emptyFunction name =
6420
let r = { svar = makeGlobalVar name (TFun(voidType, Some [], false,[]));
6427
sspec = empty_funspec ()
6430
setFormalsDecl r.svar r.svar.vtype;
6435
fileName = "<dummy>";
6437
globinitcalled = false;}
6440
(* Take the name of a file and make a valid varinfo name out of it. There are
6441
* a few characters that are not valid in varinfos *)
6442
let makeValidVarinfoName (s: string) =
6443
let s = String.copy s in (* So that we can update in place *)
6444
let l = String.length s in
6445
for i = 0 to l - 1 do
6446
let c = String.get s i in
6457
let rec lastOffset (off: offset) : offset =
6459
| NoOffset | Field(_,NoOffset) | Index(_,NoOffset) -> off
6460
| Field(_,off) | Index(_,off) -> lastOffset off
6462
let rec lastTermOffset (off: term_offset) : term_offset =
6464
| TNoOffset | TField(_,TNoOffset) | TIndex(_,TNoOffset) -> off
6465
| TField(_,off) | TIndex(_,off) -> lastTermOffset off
6467
let rec lastTsetsOffset off =
6469
| TSNoOffset | TSField(_,TSNoOffset) | TSIndex(_,TSNoOffset)
6470
| TSRange(_,_,TSNoOffset) -> off
6471
| TSField(_,off) | TSIndex(_,off) | TSRange(_,_,off) -> lastTsetsOffset off
6473
let rec addOffset (toadd: offset) (off: offset) : offset =
6476
| Field(fid', offset) -> Field(fid', addOffset toadd offset)
6477
| Index(e, offset) -> Index(e, addOffset toadd offset)
6479
let rec addTermOffset (toadd: term_offset) (off: term_offset) : term_offset =
6482
| TField(fid', offset) -> TField(fid', addTermOffset toadd offset)
6483
| TIndex(t, offset) -> TIndex(t, addTermOffset toadd offset)
6485
let rec addTsetsOffset toadd off =
6488
| TSField(fid, offset) -> TSField(fid, addTsetsOffset toadd offset)
6489
| TSIndex(t,offset) -> TSIndex(t,addTsetsOffset toadd offset)
6490
| TSRange(t1,t2,offset) -> TSRange(t1,t2,addTsetsOffset toadd offset)
6492
(* Add an offset at the end of an lv *)
6493
let addOffsetLval toadd (b, off) : lval =
6494
b, addOffset toadd off
6496
let addTermOffsetLval toadd (b, off) : term_lval =
6497
b, addTermOffset toadd off
6499
let addTsetsOffsetLval toadd (b, off) : tsets_lval =
6500
b, addTsetsOffset toadd off
6502
let rec removeOffset (off: offset) : offset * offset =
6504
NoOffset -> NoOffset, NoOffset
6505
| Field(_f, NoOffset) -> NoOffset, off
6506
| Index(_i, NoOffset) -> NoOffset, off
6507
| Field(f, restoff) ->
6508
let off', last = removeOffset restoff in
6509
Field(f, off'), last
6510
| Index(i, restoff) ->
6511
let off', last = removeOffset restoff in
6512
Index(i, off'), last
6514
let removeOffsetLval ((b, off): lval) : lval * offset =
6515
let off', last = removeOffset off in
6519
(*** Define the visiting engine ****)
6520
(* visit all the nodes in a Cil expression *)
6521
let doVisit (vis: 'visitor)
6522
(previsit: 'a -> 'a)
6523
(startvisit: 'a -> 'a visitAction)
6524
(children: 'visitor -> 'a -> 'a)
6526
let node' = previsit node in
6527
let action = startvisit node' in
6529
SkipChildren -> node'
6530
| ChangeTo node' -> node'
6531
| ChangeToPost (node',f) -> f node'
6532
| _ -> (* DoChildren and ChangeDoChildrenPost *)
6533
let nodepre = match action with
6534
ChangeDoChildrenPost (node', _) -> node'
6537
let nodepost = children vis nodepre in
6539
ChangeDoChildrenPost (_, f) -> f nodepost
6546
| i'::_ when i' == i -> acc
6547
| i'::l -> aux (i'::acc) l
6550
(* mapNoCopy is like map but avoid copying the list if the function does not
6551
* change the elements. *)
6552
let mapNoCopy (f: 'a -> 'a) orig =
6553
let rec aux ((acc,has_changed) as res) l =
6555
[] -> if has_changed then List.rev acc else orig
6559
aux (i'::acc,true) resti
6560
else if i' != i then
6561
aux (i'::rev_until i orig,true) resti
6564
in aux ([],false) orig
6566
let mapNoCopyList (f: 'a -> 'a list) orig =
6567
let rec aux ((acc,has_changed) as res) l =
6569
[] -> if has_changed then List.rev acc else orig
6573
aux (List.rev_append l' acc,true) resti
6576
[i'] when i' == i -> aux res resti
6577
| _ -> aux (List.rev_append l' (rev_until i orig), true) resti)
6578
in aux ([],false) orig
6580
(* A visitor for lists *)
6581
let doVisitList (vis: 'visit)
6582
(previsit: 'a -> 'a)
6583
(startvisit: 'a -> 'a list visitAction)
6584
(children: 'visit -> 'a -> 'a)
6585
(node: 'a) : 'a list =
6586
let node' = previsit node in
6587
let action = startvisit node' in
6589
SkipChildren -> [node']
6590
| ChangeTo nodes' -> nodes'
6591
| ChangeToPost (nodes',f) -> f nodes'
6593
let nodespre = match action with
6594
ChangeDoChildrenPost (nodespre, _) -> nodespre
6597
let nodespost = mapNoCopy (children vis) nodespre in
6599
ChangeDoChildrenPost (_, f) -> f nodespost
6607
let x' = f x in if x' != x then Some x' else o
6614
| Some x' as o' -> if x != x' then o else o'
6616
let doVisitOption (vis: #cilVisitor as 'visit)
6617
(previsit: 'a -> 'a)
6618
(startvisit: 'a -> 'a option visitAction)
6619
(children: 'visit -> 'a -> 'a)
6620
(node: 'a) : 'a option =
6621
let node' = previsit node in
6622
let action = startvisit node' in
6624
SkipChildren -> Some node'
6625
| ChangeTo node' -> node'
6626
| ChangeToPost (node',f) -> f node'
6628
let nodepre = match action with
6629
ChangeDoChildrenPost(nodepre,_) -> nodepre
6631
in let nodepost = opt_map (children vis) nodepre in
6633
ChangeDoChildrenPost(_,f) -> f nodepost
6636
let debugVisit = false
6638
let rec visitCilTerm vis t =
6639
doVisit vis (fun x-> x) vis#vterm childrenTerm t
6640
and childrenTerm vis t =
6641
let tn' = visitCilTermNode vis t.term_node in
6642
let tt' = visitCilLogicType vis t.term_type in
6643
if tn' != t.term_node || tt' != t.term_type then
6644
{ t with term_node = tn'; term_type = tt' }
6646
and visitCilTermNode vis tn =
6647
doVisit vis (fun x -> x) vis#vterm_node childrenTermNode tn
6648
and childrenTermNode vis tn =
6649
let vTerm t = visitCilTerm vis t in
6650
let vTermLval tl = visitCilTermLval vis tl in
6651
let vTyp t = visitCilType vis t in
6653
doVisit vis vis#behavior.get_logic_info
6654
vis#vlogic_info_use (fun _ x ->x) li
6657
| TConst _ -> tn (*enum constants are visited at their declaration site*)
6658
| TDataCons (ci,args) ->
6659
let args' = mapNoCopy vTerm args in
6660
if args != args' then TDataCons(ci,args') else tn
6662
let tl' = vTermLval tl in
6663
if tl' != tl then TLval tl' else tn
6665
let t' = vTyp t in if t' != t then TSizeOf t' else tn
6667
let t' = vTerm t in if t' != t then TSizeOfE t' else tn
6668
| TSizeOfStr _ -> tn
6670
let t' = vTyp t in if t' != t then TAlignOf t' else tn
6672
let t' = vTerm t in if t' != t then TAlignOfE t' else tn
6674
let t' = vTerm t in if t' != t then TUnOp (op,t') else tn
6675
| TBinOp(op,t1,t2) ->
6676
let t1' = vTerm t1 in
6677
let t2' = vTerm t2 in
6678
if t1' != t1 || t2' != t2 then TBinOp(op,t1',t2') else tn
6680
let ty' = vTyp ty in
6681
let te' = vTerm te in
6682
if ty' != ty || te' != te then TCastE(ty',te') else tn
6684
let tl' = vTermLval tl in
6685
if tl' != tl then TAddrOf tl' else tn
6687
let tl' = vTermLval tl in
6688
if tl' != tl then TStartOf tl' else tn
6689
| Tapp(li,labels,args) ->
6690
let li' = vLogicInfo li in
6691
let args' = mapNoCopy vTerm args in
6692
if li' != li || args' != args then Tapp(li',labels,args') else tn
6693
| Tif(test,ttrue,tfalse) ->
6694
let test' = vTerm test in
6695
let ttrue' = vTerm ttrue in
6696
let tfalse' = vTerm tfalse in
6697
if test' != test || ttrue' != ttrue || tfalse' != tfalse then
6698
Tif(test',ttrue',tfalse')
6701
let t' = vTerm t in if t' != t then Told t' else tn
6704
let s' = visitCilLogicLabel vis s in
6705
if t' != t || s' != s then Tat (t',s') else tn
6707
let t' = vTerm t in if t' != t then Tbase_addr t' else tn
6708
| Tblock_length t ->
6709
let t' = vTerm t in if t' != t then Tblock_length t' else tn
6712
let ty' = vTyp ty in
6713
let te' = vTerm te in
6714
if ty' != ty || te' != te then TCoerce(te',ty') else tn
6715
| TCoerceE(te,tc) ->
6716
let tc' = vTerm tc in
6717
let te' = vTerm te in
6718
if tc' != tc || te' != te then TCoerceE(te',tc') else tn
6719
| TUpdate (tc,f,te) ->
6720
let tc' = vTerm tc in
6721
let te' = vTerm te in
6722
if tc' != tc || te' != te then TUpdate(tc',f,te') else tn
6723
| Tlambda(prms,te) ->
6724
let prms' = visitCilQuantifiers vis prms in
6725
let te' = vTerm te in
6726
if prms' != prms || te' != te then Tlambda(prms',te') else tn
6728
let t' = vTerm t in if t' != t then Ttypeof t' else tn
6730
let ty' = vTyp ty in if ty' != ty then Ttype ty' else tn
6732
let ts' = visitCilTsets vis ts in if ts != ts' then Ttsets ts' else tn
6734
and visitCilLogicLabel vis l =
6736
StmtLabel s -> s := vis#behavior.get_stmt !s; l
6739
and visitCilTermLval vis tl =
6740
doVisit vis (fun x -> x) vis#vterm_lval childrenTermLval tl
6742
and childrenTermLval vis ((tlv,toff) as tl)=
6743
let tlv' = visitCilTermLhost vis tlv in
6744
let toff' = visitCilTermOffset vis toff in
6745
if tlv' != tlv || toff' != toff then (tlv',toff') else tl
6747
and visitCilTermLhost vis tl =
6748
doVisit vis (fun x -> x) vis#vterm_lhost childrenTermLhost tl
6750
and childrenTermLhost vis tl = match tl with
6752
let v' = visitCilLogicVarUse vis v in if v' != v then TVar v' else tl
6755
let t' = visitCilTerm vis t in if t' != t then TMem t' else tl
6757
and visitCilTermOffset vis toff =
6758
doVisit vis (fun x -> x)
6759
vis#vterm_offset childrenTermOffset toff
6761
and childrenTermOffset vis toff =
6762
let vOffset o = visitCilTermOffset vis o in
6763
let vTerm t = visitCilTerm vis t in
6767
let t' = vOffset t in
6768
let fi' = vis#behavior.get_fieldinfo fi in
6769
if t' != t || fi != fi' then TField(fi',t') else toff
6771
let t' = vTerm t in let o' = vOffset o in
6772
if t' != t || o' != o then TIndex(t',o') else toff
6774
and visitCilTsets vis loc =
6775
doVisit vis (fun x -> x) vis#vtsets childrenTsets loc
6776
and childrenTsets vis loc =
6779
let lval' = visitCilTsetsElem vis lval in
6780
if lval' != lval then TSSingleton lval' else loc
6782
let locs' = mapNoCopy (visitCilTsets vis) locs in
6783
if locs != locs' then TSUnion(locs') else loc
6785
let locs' = mapNoCopy (visitCilTsets vis) locs in
6786
if locs != locs' then TSInter(locs') else loc
6787
| TSComprehension(lval,quant,pred) ->
6788
let quant' = visitCilQuantifiers vis quant in
6789
let lval' = visitCilTsets vis lval in
6790
let pred' = (opt_map (visitCilPredicateNamed vis)) pred in
6791
if lval' != lval || quant' != quant || pred' != pred
6793
TSComprehension(lval',quant',pred')
6798
and visitCilTsetsLhost vis h =
6799
doVisit vis (fun x -> x) vis#vtsets_lhost childrenTsetsLhost h
6801
and childrenTsetsLhost vis h =
6804
let v' = visitCilLogicVarUse vis v in if v != v' then TSVar v' else h
6807
let m' = visitCilTsetsElem vis m in if m != m' then TSMem m' else h
6809
and visitCilTsetsElem vis lv =
6810
doVisit vis (fun x->x) vis#vtsets_elem childrenTsetsElem lv
6812
and childrenTsetsElem vis e =
6815
let lv' = visitCilTsetsLval vis lv in
6816
if lv' != lv then TSLval lv' else e
6818
let lv' = visitCilTsetsLval vis lv in
6819
if lv' != lv then TSStartOf lv' else e
6821
let lv' = visitCilTsetsLval vis lv in
6822
if lv' != lv then TSAddrOf lv' else e
6824
| TSCastE(typ,elem) ->
6825
let typ' = visitCilType vis typ in
6826
let elem' = visitCilTsetsElem vis elem in
6827
if typ' != typ || elem' != elem then TSCastE(typ', elem') else e
6828
| TSAdd_range(ts,low,high) ->
6829
let ts' = visitCilTsetsElem vis ts in
6830
let low' = (opt_map (visitCilTerm vis)) low in
6831
let high' = (opt_map (visitCilTerm vis)) high in
6832
if ts' != ts || low' != low || high' != high then
6833
TSAdd_range(ts',low',high')
6835
| TSAdd_index(ts,i) ->
6836
let ts' = visitCilTsetsElem vis ts in
6837
let i' = visitCilTerm vis i in
6838
if ts' != ts || i' != i then TSAdd_index(ts',i') else e
6840
let locs' = visitCilTsetsElem vis locs in
6841
let lab' = visitCilLogicLabel vis lab in
6842
if locs != locs' || lab != lab' then TSat(locs',lab') else e
6843
| TSapp(f,labs,args) ->
6844
let f' = visitCilLogicInfo vis f in
6846
mapNoCopy (function (x,y) as orig ->
6847
let x' = visitCilLogicLabel vis x in
6848
let y' = visitCilLogicLabel vis y in
6849
if x' != x || y' != y then (x',y') else orig) labs
6851
let args' = mapNoCopy (visitCilTerm vis) args in
6852
if f != f' || labs' != labs || args' != args then
6853
TSapp(f',labs',args')
6856
and visitCilTsetsLval vis lv =
6857
doVisit vis (fun x -> x) vis#vtsets_lval childrenTsetsLval lv
6858
and childrenTsetsLval vis (h,o as lv) =
6859
let h' = visitCilTsetsLhost vis h in
6860
let o' = visitCilTsetsOffset vis o in
6861
if h' != h || o' != o then h',o' else lv
6863
and visitCilTsetsOffset vis o =
6864
doVisit vis (fun x -> x) vis#vtsets_offset childrenTsetsOffset o
6866
and childrenTsetsOffset vis o =
6869
| TSIndex (i,next) ->
6870
let i' = visitCilTerm vis i in
6871
let next' = visitCilTsetsOffset vis next in
6872
if i != i' || next != next' then TSIndex (i',next') else o
6873
| TSRange (i1,i2,next) ->
6874
let i1' = (opt_map (visitCilTerm vis)) i1 in
6875
let i2' = (opt_map (visitCilTerm vis)) i2 in
6876
let next' = visitCilTsetsOffset vis next in
6877
if i1' != i1 || i2' != i2 || next' != next then
6878
TSRange(i1',i2',next')
6880
| TSField (f,next) ->
6881
let next' = visitCilTsetsOffset vis next in
6882
let f' = vis#behavior.get_fieldinfo f in
6883
if next' != next || f != f' then TSField(f',next') else o
6885
and visitCilLogicInfo vis li =
6887
vis vis#behavior.memo_logic_info
6888
vis#vlogic_info_decl childrenLogicInfo li
6890
and childrenLogicInfo vis li =
6891
let lt = opt_map (visitCilLogicType vis) li.l_type in
6892
let lp = mapNoCopy (visitCilLogicVarDecl vis) li.l_profile in
6894
let lt' = visitCilLogicType vis p.lv_type in
6895
if lt' != p.lv_type then { p with lv_type = lt'} else p)
6904
match li.l_body with
6906
let l = mapNoCopy (visitCilTsets vis) ol in
6907
if l != ol then LBreads l else li.l_body
6909
let t = visitCilTerm vis ot in
6910
if t != ot then LBterm t else li.l_body
6911
| LBinductive inddef ->
6914
(fun (id,labs,tvars,p) ->
6915
(id, labs, tvars, visitCilPredicateNamed vis p))
6918
if i != inddef then LBinductive i else li.l_body
6920
let def = visitCilPredicateNamed vis odef in
6921
if def != odef then LBpred def else li.l_body
6925
and visitCilLogicType vis t =
6926
doVisit vis (fun x -> x) vis#vlogic_type childrenLogicType t
6928
and childrenLogicType vis ty =
6931
let t' = visitCilType vis t in
6932
if t != t' then Ctype t' else ty
6933
| Linteger | Lreal -> ty
6935
let l' = mapNoCopy (visitCilLogicType vis) l in
6936
if l' != l then Ltype (s,l') else ty
6937
| Larrow(args,rttyp) ->
6938
let args' = mapNoCopy(visitCilLogicType vis) args in
6939
let rttyp' = visitCilLogicType vis rttyp in
6940
if args' != args || rttyp' != rttyp then Larrow(args',rttyp') else ty
6943
and visitCilLogicVarDecl vis lv =
6944
(* keep names in C and logic worlds in sync *)
6945
(match lv.lv_origin with
6947
| Some cv -> lv.lv_name <- cv.vname);
6948
doVisit vis vis#behavior.memo_logic_var vis#vlogic_var_decl
6949
childrenLogicVarDecl lv
6951
and childrenLogicVarDecl vis lv =
6952
lv.lv_type <- visitCilLogicType vis lv.lv_type;
6954
opt_map (visitCilVarUse vis) lv.lv_origin;
6957
and visitCilLogicVarUse vis lv =
6958
doVisit vis vis#behavior.get_logic_var vis#vlogic_var_use
6959
childrenLogicVarUse lv
6961
and childrenLogicVarUse vis lv =
6962
lv.lv_origin <- opt_map (visitCilVarUse vis) lv.lv_origin; lv
6964
and visitCilQuantifiers vis lv =
6965
doVisit vis (fun x -> x) vis#vquantifiers
6966
(fun vis l -> mapNoCopy (visitCilLogicVarDecl vis) l) lv
6968
and visitCilPredicate vis p =
6969
doVisit vis (fun x -> x) vis#vpredicate childrenPredicate p
6971
and visitCilPredicateNamed vis p =
6973
(fun x -> x) vis#vpredicate_named childrenPredicateNamed p
6975
and childrenPredicateNamed vis p =
6976
let content = visitCilPredicate vis p.content in
6977
if content != p.content then { p with content = content} else p
6979
and childrenPredicate vis p =
6980
let vPred p = visitCilPredicateNamed vis p in
6982
doVisit vis vis#behavior.get_logic_info
6983
vis#vlogic_info_use (fun _ x ->x) li
6988
vis#behavior.get_logic_f vis#vpredicate_info_use (fun _ x -> x) p
6991
let vTerm t = visitCilTerm vis t in
6992
let vTsets t = visitCilTsets vis t in
6995
| Papp (pred,labels,args) ->
6996
let pred' = vLogicInfo pred in
6997
let args' = mapNoCopy vTerm args in
6998
if pred' != pred || args' != args then
6999
Papp(pred',labels,args')
7001
| Prel(rel,t1,t2) ->
7002
let t1' = vTerm t1 in
7003
let t2' = vTerm t2 in
7004
if t1' != t1 || t2' != t2 then
7008
let p1' = vPred p1 in
7009
let p2' = vPred p2 in
7010
if p1' != p1 || p2' != p2 then
7014
let p1' = vPred p1 in
7015
let p2' = vPred p2 in
7016
if p1' != p1 || p2' != p2 then
7020
let p1' = vPred p1 in
7021
let p2' = vPred p2 in
7022
if p1' != p1 || p2' != p2 then
7025
| Pimplies(p1,p2) ->
7026
let p1' = vPred p1 in
7027
let p2' = vPred p2 in
7028
if p1' != p1 || p2' != p2 then
7032
let p1' = vPred p1 in
7033
let p2' = vPred p2 in
7034
if p1' != p1 || p2' != p2 then
7038
let p1' = vPred p1 in
7039
if p1' != p1 then Pnot p1' else p
7040
| Pif(t,ptrue,pfalse) ->
7042
let ptrue' = vPred ptrue in
7043
let pfalse' = vPred pfalse in
7044
if t' != t || ptrue' != ptrue || pfalse' != pfalse then
7045
Pif(t', ptrue',pfalse')
7048
let var' = visitCilLogicVarDecl vis var in
7050
let p1' = vPred p1 in
7051
if var' != var || t' != t || p1' != p1 then
7054
| Pforall(quant,p1) ->
7055
let quant' = visitCilQuantifiers vis quant in
7056
let p1' = vPred p1 in
7057
if quant' != quant || p1' != p1 then
7058
Pforall(quant', p1')
7060
| Pexists(quant,p1) ->
7061
let quant' = visitCilQuantifiers vis quant in
7062
let p1' = vPred p1 in
7063
if quant' != quant || p1' != p1 then
7064
Pexists(quant', p1')
7067
let p1' = vPred p1 in if p1' != p1 then Pold p1' else p
7069
let p1' = vPred p1 in
7070
let s' = visitCilLogicLabel vis s in
7071
if p1' != p1 then Pat(p1',s') else p
7073
let t' = vTsets t in if t' != t then Pvalid t' else p
7074
| Pvalid_index (t1,t2) ->
7075
let t1' = vTerm t1 in
7076
let t2' = vTerm t2 in
7077
if t1' != t1 || t2' != t2 then Pvalid_index (t1',t2') else p
7078
| Pvalid_range(t1,t2,t3) ->
7079
let t1' = vTerm t1 in
7080
let t2' = vTerm t2 in
7081
let t3' = vTerm t3 in
7082
if t1' != t1 || t2' != t2 || t3' != t3 then
7083
Pvalid_range (t1',t2',t3') else p
7084
| Pseparated seps ->
7085
let seps' = mapNoCopy vTsets seps in
7086
if seps' != seps then Pseparated seps' else p
7088
let t' = vTerm t in if t' != t then Pfresh t' else p
7089
(* | Pnamed(s,p1) ->
7090
let p1' = vPred p1 in if p1' != p1 then Pnamed (s,p1') else p *)
7091
| Psubtype(te,tc) ->
7092
let tc' = vTerm tc in
7093
let te' = vTerm te in
7094
if tc' != tc || te' != te then Psubtype(te',tc') else p
7097
and visitCilPredicateInfo vis pi =
7098
doVisit vis vis#behavior.memo_predicate_info
7099
vis#vpredicate_info_decl childrenPredicateInfo pi
7103
and visitCilIdLocations vis loc =
7104
let loc' = visitCilTsets vis loc.its_content in
7105
if loc' != loc.its_content then { loc with its_content = loc' } else loc
7107
and visitCilZone vis z =
7108
doVisit vis (fun x -> x) vis#vzone childrenZone z
7109
and childrenZone vis z =
7113
let loc' = visitCilIdLocations vis loc in
7114
if loc' != loc then Location loc' else z
7116
and visitCilAssigns vis a =
7117
doVisit vis (fun x -> x) vis#vassigns childrenAssigns a
7118
and childrenAssigns vis ((z,l) as a)=
7119
let z' = visitCilZone vis z in
7120
let l' = mapNoCopy (visitCilZone vis) l in
7121
if z' != z || l' != l then (z',l') else a
7123
and visitCilBehavior vis b =
7124
doVisit vis vis#behavior.cfunbehavior
7125
vis#vbehavior childrenBehavior b
7127
and childrenBehavior vis b =
7128
b.b_assumes <- visitCilPredicates vis b.b_assumes;
7129
b.b_ensures <- visitCilPredicates vis b.b_ensures;
7130
b.b_assigns <- mapNoCopy (visitCilAssigns vis) b.b_assigns;
7133
and visitCilPredicates vis ps = mapNoCopy (visitCilIdPredicate vis) ps
7135
and visitCilIdPredicate vis ps =
7136
let p' = visitCilPredicate vis ps.ip_content in
7137
if p' != ps.ip_content then { ps with ip_content = p' } else ps
7139
and visitCilBehaviors vis bs = mapNoCopy (visitCilBehavior vis) bs
7141
and visitCilFunspec vis s =
7142
doVisit vis vis#behavior.cfunspec vis#vspec childrenSpec s
7144
and childrenSpec vis s =
7145
s.spec_requires <- visitCilPredicates vis s.spec_requires;
7146
s.spec_behavior <- visitCilBehaviors vis s.spec_behavior;
7148
opt_map (fun x -> (visitCilTerm vis (fst x), snd x)) s.spec_variant;
7149
s.spec_terminates <-
7150
opt_map (visitCilIdPredicate vis) s.spec_terminates;
7151
(* nothing is done now for behaviors names, no need to visit complete and
7152
disjoint behaviors clauses
7156
and visitCilSlicePragma vis p =
7157
doVisit vis (fun x -> x) vis#vslice_pragma childrenSlicePragma p
7159
and childrenSlicePragma vis p =
7162
let t' = visitCilTerm vis t in if t' != t then SPexpr t' else p
7163
| SPctrl | SPstmt -> p
7165
and visitCilImpactPragma vis p =
7166
doVisit vis (fun x -> x) vis#vimpact_pragma childrenImpactPragma p
7168
and childrenImpactPragma vis p = match p with
7169
| IPexpr t -> let t' = visitCilTerm vis t in if t' != t then IPexpr t' else p
7172
and visitCilLoopPragma vis p =
7174
(fun x -> x) vis#vloop_pragma childrenLoopPragma p
7176
and childrenLoopPragma vis p =
7178
| Unroll_level t -> let t' = visitCilTerm vis t in
7179
if t' != t then Unroll_level t' else p
7180
| Widen_hints lt -> let lt' = List.map (visitCilTerm vis) lt in
7181
if lt' != lt then Widen_hints lt' else p
7182
| Widen_variables lt -> let lt' = List.map (visitCilTerm vis) lt in
7183
if lt' != lt then Widen_variables lt' else p
7185
and visitCilAnnotation vis a =
7186
doVisit vis (fun x -> x) vis#vannotation childrenAnnotation a
7188
and visitCilAxiom vis ((id,p) as a) =
7189
let p' = visitCilPredicateNamed vis p in
7190
if p' != p then (id,p') else a
7192
and childrenAnnotation vis a =
7194
| Dfun_or_pred li ->
7195
let li' = visitCilLogicInfo vis li in
7196
if li' != li then Dfun_or_pred li' else a
7198
Dpredicate_reads (s, tvars, args,loc) ->
7199
let s' = visitCilPredicateInfo vis s in
7200
let args' = mapNoCopy (visitCilLogicVarDecl vis) args in
7201
let loc' = mapNoCopy (visitCilTsets vis) loc in
7202
if s'!=s || args' != args || loc' != loc then
7203
Dpredicate_reads(s',tvars,args',loc')
7205
| Dpredicate_def(s,tvars,args,def) ->
7206
let s' = visitCilPredicateInfo vis s in
7207
let args' = mapNoCopy (visitCilLogicVarDecl vis) args in
7208
let def' = visitCilPredicateNamed vis def in
7209
if s' != s || args' != args || def' != def then
7210
Dpredicate_def(s',tvars,args',def')
7212
| Dinductive_def(s,tvars,args,indcases) ->
7213
let s' = visitCilPredicateInfo vis s in
7214
let args' = mapNoCopy (visitCilLogicVarDecl vis) args in
7215
let indcases' = mapNoCopy (visitCilAxiom vis) indcases in
7216
if s' != s || args' != args || indcases' != indcases then
7217
Dinductive_def(s',tvars,args',indcases')
7221
| Dtype _ -> a (* nothing to visit here for now *)
7223
| Dlogic_reads(s,tvars,args,rt,loc) ->
7224
let s' = visitCilLogicInfo vis s in
7225
let args' = mapNoCopy (visitCilLogicVarDecl vis) args in
7226
let rt' = visitCilLogicType vis rt in
7227
let loc' = mapNoCopy (visitCilTsets vis) loc in
7228
if s'!= s || args' != args || rt' != rt || loc' != loc then
7229
Dlogic_reads(s',tvars,args',rt',loc')
7231
| Dlogic_def(s,tvars,args,rt,def) ->
7232
let s' = visitCilLogicInfo vis s in
7233
let args' = mapNoCopy (visitCilLogicVarDecl vis) args in
7234
let rt' = visitCilLogicType vis rt in
7235
let def' = visitCilTerm vis def in
7236
if s != s' || args' != args || rt' != rt || def' != def then
7237
Dlogic_def(s',tvars,args',rt',def')
7239
| Dlogic_axiomatic(s,tvars,args,rt,axioms) ->
7240
let s' = visitCilLogicInfo vis s in
7241
let args' = mapNoCopy (visitCilLogicVarDecl vis) args in
7242
let rt' = visitCilLogicType vis rt in
7243
let axioms' = mapNoCopy (visitCilAxiom vis) axioms in
7244
if s != s' || args' != args || rt' != rt || axioms' != axioms then
7245
Dlogic_axiomatic(s',tvars,args',rt',axioms')
7248
| Dlemma(s,is_axiom,labels,tvars,p) ->
7249
let p' = visitCilPredicateNamed vis p in
7250
if p' != p then Dlemma(s,is_axiom,labels,tvars,p') else a
7252
let p' = visitCilLogicInfo vis p in
7253
if p' != p then Dinvariant p' else a
7255
let ta' = visitCilLogicInfo vis ta in
7256
if ta' != ta then Dtype_annot ta' else a
7257
| Daxiomatic(id,l) ->
7259
Format.eprintf "cil.visitCilAnnotation on axiomatic %s@." id;
7261
let l' = mapNoCopy (visitCilAnnotation vis) l in
7262
if l' != l then Daxiomatic(id,l') else a
7264
and visitCilCodeAnnotation vis ca =
7265
doVisit vis (fun x -> x) vis#vcode_annot childrenCodeAnnot ca
7267
and childrenCodeAnnot vis ca =
7268
let vPred p = visitCilPredicateNamed vis p in
7269
let vTerm t = visitCilTerm vis t in
7270
let vSpec s = visitCilFunspec vis s in
7271
let change_content annot = { ca with annot_content = annot } in
7272
match ca.annot_content with
7273
AAssert (behav,p,_status) ->
7274
(* TODO: status is reset to Unkown if the predicate changed but
7275
remain unchanged otherwise. It should be visited. *)
7276
let p' = vPred p in if p' != p then
7277
change_content (AAssert (behav,p',{status=Unknown}))
7280
let p' = vPred p in if p' != p then change_content (AAssume p') else ca
7281
| APragma (Impact_pragma t) ->
7282
let t' = visitCilImpactPragma vis t in
7283
if t' != t then change_content (APragma (Impact_pragma t')) else ca
7284
| APragma (Slice_pragma t) ->
7285
let t' = visitCilSlicePragma vis t in
7286
if t' != t then change_content (APragma (Slice_pragma t')) else ca
7287
| APragma (Loop_pragma p) ->
7288
let p' = visitCilLoopPragma vis p in
7289
if p' != p then change_content (APragma (Loop_pragma p')) else ca
7292
if s' != s then change_content (AStmtSpec s') else ca
7293
| AInvariant(behav,f,p) ->
7295
if p' != p then change_content (AInvariant (behav,f,p')) else ca
7296
| AVariant ((t,s)) ->
7298
if t != t' then change_content (AVariant ((t',s))) else ca
7300
let a' = visitCilAssigns vis a in
7301
if a != a' then change_content (AAssigns a') else ca
7303
and visitCilExpr (vis: cilVisitor) (e: exp) : exp =
7304
doVisit vis (fun x -> x) vis#vexpr childrenExp e
7305
and childrenExp (vis: cilVisitor) (e: exp) : exp =
7306
let vExp e = visitCilExpr vis e in
7307
let vTyp t = visitCilType vis t in
7308
let vLval lv = visitCilLval vis lv in
7309
match stripInfo e with
7310
| Info _ -> assert false
7311
| Const _ -> e (* enum constants are visited at their declaration site *)
7314
if t' != t then SizeOf t' else e
7316
let e1' = vExp e1 in
7317
if e1' != e1 then SizeOfE e1' else e
7322
if t' != t then AlignOf t' else e
7324
let e1' = vExp e1 in
7325
if e1' != e1 then AlignOfE e1' else e
7327
let lv' = vLval lv in
7328
if lv' != lv then Lval lv' else e
7329
| UnOp (uo, e1, t) ->
7330
let e1' = vExp e1 in let t' = vTyp t in
7331
if e1' != e1 || t' != t then UnOp(uo, e1', t') else e
7332
| BinOp (bo, e1, e2, t) ->
7333
let e1' = vExp e1 in let e2' = vExp e2 in let t' = vTyp t in
7334
if e1' != e1 || e2' != e2 || t' != t then BinOp(bo, e1',e2',t') else e
7336
let t' = vTyp t in let e1' = vExp e1 in
7337
if t' != t || e1' != e1 then CastE(t', e1') else e
7339
let lv' = vLval lv in
7340
if lv' != lv then AddrOf lv' else e
7342
let lv' = vLval lv in
7343
if lv' != lv then StartOf lv' else e
7345
and visitCilInit (vis: cilVisitor) (forglob: varinfo)
7346
(atoff: offset) (i: init) : init =
7347
let rec childrenInit (vis: cilVisitor) (i: init) : init =
7348
let fExp e = visitCilExpr vis e in
7349
let fTyp t = visitCilType vis t in
7353
if e' != e then SingleInit e' else i
7354
| CompoundInit (t, initl) ->
7356
(* Collect the new initializer list, in reverse. We prefer two
7357
* traversals to ensure tail-recursion. *)
7358
let newinitl : (offset * init) list ref = ref [] in
7359
(* Keep track whether the list has changed *)
7360
let hasChanged = ref false in
7361
let doOneInit ((o, i) as oi) =
7362
let o' = visitCilInitOffset vis o in (* use initializer version *)
7363
let i' = visitCilInit vis forglob (addOffset o' atoff) i in
7365
if o' != o || i' != i then
7366
begin hasChanged := true; (o', i') end else oi
7368
newinitl := newio :: !newinitl
7370
List.iter doOneInit initl;
7371
let initl' = if !hasChanged then List.rev !newinitl else initl in
7372
if t' != t || initl' != initl then CompoundInit (t', initl') else i
7374
doVisit vis (fun x -> x) (vis#vinit forglob atoff) childrenInit i
7376
and visitCilLval (vis: cilVisitor) (lv: lval) : lval =
7377
doVisit vis (fun x -> x) vis#vlval childrenLval lv
7378
and childrenLval (vis: cilVisitor) (lv: lval) : lval =
7379
(* and visit its subexpressions *)
7380
let vExp e = visitCilExpr vis e in
7381
let vOff off = visitCilOffset vis off in
7384
let v'= visitCilVarUse vis v in
7385
let off' = vOff off in
7386
if v' != v || off' != off then Var v', off' else lv
7389
let off' = vOff off in
7390
if e' != e || off' != off then Mem e', off' else lv
7392
and visitCilOffset (vis: cilVisitor) (off: offset) : offset =
7393
doVisit vis (fun x -> x) vis#voffs childrenOffset off
7394
and childrenOffset (vis: cilVisitor) (off: offset) : offset =
7395
let vOff off = visitCilOffset vis off in
7399
let f' = vis#behavior.get_fieldinfo f in
7400
if o' != o || f' != f then Field (f', o') else off
7402
let e' = visitCilExpr vis e in
7404
if e' != e || o' != o then Index (e', o') else off
7407
(* sm: for offsets in initializers, the 'startvisit' will be the
7408
* vinitoffs method, but we can re-use the childrenOffset from
7409
* above since recursive offsets are visited by voffs. (this point
7410
* is moot according to cil.mli which claims the offsets in
7411
* initializers will never recursively contain offsets)
7413
and visitCilInitOffset (vis: cilVisitor) (off: offset) : offset =
7414
doVisit vis (fun x -> x) vis#vinitoffs childrenOffset off
7416
and visitCilInstr (vis: cilVisitor) (i: instr) : instr list =
7417
let oldloc = CurrentLoc.get () in
7418
CurrentLoc.set (get_instrLoc i);
7419
assertEmptyQueue vis;
7421
doVisitList vis (fun x -> x) vis#vinst childrenInstr i in
7422
CurrentLoc.set oldloc;
7423
(* See if we have accumulated some instructions *)
7424
vis#unqueueInstr () @ res
7426
and childrenInstr (vis: cilVisitor) (i: instr) : instr =
7427
let fExp = visitCilExpr vis in
7428
let fLval = visitCilLval vis in
7433
let lv' = fLval lv in let e' = fExp e in
7434
if lv' != lv || e' != e then Set(lv',e',l) else i
7435
| Call(None,f,args,l) ->
7436
let f' = fExp f in let args' = mapNoCopy fExp args in
7437
if f' != f || args' != args then Call(None,f',args',l) else i
7438
| Call(Some lv,fn,args,l) ->
7439
let lv' = fLval lv in let fn' = fExp fn in
7440
let args' = mapNoCopy fExp args in
7441
if lv' != lv || fn' != fn || args' != args
7442
then Call(Some lv', fn', args', l) else i
7444
| Asm(sl,isvol,outs,ins,clobs,l) ->
7445
let outs' = mapNoCopy (fun ((id,s,lv) as pair) ->
7446
let lv' = fLval lv in
7447
if lv' != lv then (id,s,lv') else pair) outs in
7448
let ins' = mapNoCopy (fun ((id,s,e) as pair) ->
7450
if e' != e then (id,s,e') else pair) ins in
7451
if outs' != outs || ins' != ins then
7452
Asm(sl,isvol,outs',ins',clobs,l) else i
7453
| Code_annot (a,l) ->
7454
let a' = visitCilCodeAnnotation vis a in Code_annot(a',l)
7457
(* visit all nodes in a Cil statement tree in preorder *)
7458
and visitCilStmt (vis:cilVisitor) (s: stmt) : stmt =
7459
let oldloc = CurrentLoc.get () in
7460
CurrentLoc.set (get_stmtLoc s.skind) ;
7461
vis#push_stmt s; (*(vis#behavior.memo_stmt s);*)
7462
assertEmptyQueue vis;
7463
let toPrepend : instr list ref = ref [] in (* childrenStmt may add to this *)
7466
vis#behavior.memo_stmt vis#vstmt (childrenStmt toPrepend) s in
7467
(* Now see if we have saved some instructions *)
7468
toPrepend := !toPrepend @ vis#unqueueInstr ();
7469
(match !toPrepend with
7470
[] -> () (* Return the same statement *)
7472
(* Make our statement contain the instructions to prepend *)
7474
Block { battrs = [];
7475
bstmts = (List.map (fun i -> mkStmt (Instr i)) !toPrepend) @
7476
[ mkStmt res.skind ] });
7477
CurrentLoc.set oldloc;
7481
and childrenStmt (toPrepend: instr list ref) (vis:cilVisitor) (s:stmt): stmt =
7482
let fExp e = (visitCilExpr vis e) in
7483
let fBlock b = visitCilBlock vis b in
7484
let fInst i = visitCilInstr vis i in
7485
let fLoopAnnot a = mapNoCopy (visitCilCodeAnnotation vis) a in
7486
(* Just change the statement kind *)
7489
Break _ | Continue _ | Return (None, _) -> s.skind
7490
| UnspecifiedSequence seq ->
7493
(function (stmt,writes,reads) as orig->
7494
let stmt' = visitCilStmt vis stmt in
7495
let writes' = mapNoCopy (visitCilLval vis) writes in
7496
let reads' = mapNoCopy (visitCilLval vis) reads in
7497
if stmt' != stmt || writes' != writes || reads' != reads then
7498
(stmt',writes',reads')
7502
if seq' != seq then UnspecifiedSequence seq' else s.skind
7504
if vis#behavior.is_copy_behavior then
7505
Goto(ref (vis#behavior.memo_stmt !sr),l)
7507
| Return (Some e, l) ->
7509
if e' != e then Return (Some e', l) else s.skind
7510
| Loop (a, b, l, s1, s2) ->
7511
let a' = fLoopAnnot a in
7512
let b' = fBlock b in
7513
if a' != a || b' != b then Loop (a', b', l, s1, s2) else s.skind
7514
| If(e, s1, s2, l) ->
7516
(*if e queued any instructions, pop them here and remember them so that
7517
they are inserted before the If stmt, not in the then block. *)
7518
toPrepend := vis#unqueueInstr ();
7519
let s1'= fBlock s1 in let s2'= fBlock s2 in
7520
(* the stmts in the blocks should have cleaned up after themselves.*)
7521
assertEmptyQueue vis;
7522
if e' != e || s1' != s1 || s2' != s2 then
7523
If(e', s1', s2', l) else s.skind
7524
| Switch (e, b, stmts, l) ->
7526
toPrepend := vis#unqueueInstr (); (* insert these before the switch *)
7527
let b' = fBlock b in
7528
(* the stmts in b should have cleaned up after themselves.*)
7529
assertEmptyQueue vis;
7530
(* Don't do stmts, but we better not change those *)
7531
if e' != e || b' != b then Switch (e', b', stmts, l) else s.skind
7533
begin match fInst i with
7534
| [i'] when i' == i -> s.skind
7535
| il -> stmt_of_instr_list ~loc:(get_instrLoc i) il
7538
let b' = fBlock b in
7539
if b' != b then Block b' else s.skind
7540
| TryFinally (b, h, l) ->
7541
let b' = fBlock b in
7542
let h' = fBlock h in
7543
if b' != b || h' != h then TryFinally(b', h', l) else s.skind
7544
| TryExcept (b, (il, e), h, l) ->
7545
let b' = fBlock b in
7546
assertEmptyQueue vis;
7547
(* visit the instructions *)
7548
let il' = mapNoCopyList fInst il in
7549
(* Visit the expression *)
7552
let more = vis#unqueueInstr () in
7558
let h' = fBlock h in
7559
(* Now collect the instructions *)
7560
if b' != b || il'' != il || e' != e || h' != h then
7561
TryExcept(b', (il'', e'), h', l)
7564
if skind' != s.skind then s.skind <- skind';
7565
(* Visit the labels *)
7567
let fLabel = function
7568
Case (e, l) as lb ->
7570
if e' != e then Case (e', l) else lb
7573
mapNoCopy fLabel s.labels
7575
if labels' != s.labels then s.labels <- labels';
7580
and visitCilBlock (vis: cilVisitor) (b: block) : block =
7581
doVisit vis vis#behavior.cblock vis#vblock childrenBlock b
7582
and childrenBlock (vis: cilVisitor) (b: block) : block =
7583
let fStmt s = visitCilStmt vis s in
7584
let stmts' = mapNoCopy fStmt b.bstmts in
7585
if stmts' != b.bstmts then { battrs = b.battrs; bstmts = stmts'} else b
7588
and visitCilType (vis : cilVisitor) (t : typ) : typ =
7589
doVisit vis (fun x -> x) vis#vtype childrenType t
7590
and childrenType (vis : cilVisitor) (t : typ) : typ =
7591
(* look for types referred to inside t's definition *)
7592
let fTyp t = visitCilType vis t in
7593
let fAttr a = visitCilAttributes vis a in
7596
let t1' = fTyp t1 in
7598
if t1' != t || a' != a then TPtr(t1', a') else t
7599
| TArray(t1, None, a) ->
7600
let t1' = fTyp t1 in
7602
if t1' != t || a' != a then TArray(t1', None, a') else t
7603
| TArray(t1, Some e, a) ->
7604
let t1' = fTyp t1 in
7605
let e' = visitCilExpr vis e in
7607
if t1' != t || e' != e || a' != a then TArray(t1', Some e', a') else t
7609
(* DON'T recurse into the compinfo, this is done in visitCilGlobal.
7610
User can iterate over cinfo.cfields manually, if desired.*)
7611
| TComp(cinfo, a) ->
7612
let cinfo' = vis#behavior.get_compinfo cinfo in
7614
if a != a' || cinfo' != cinfo then TComp(cinfo', a') else t
7616
| TFun(rettype, args, isva, a) ->
7617
let rettype' = fTyp rettype in
7618
(* iterate over formals, as variable declarations *)
7619
let argslist = argsToList args in
7620
let visitArg ((an,at,aa) as arg) =
7621
let at' = fTyp at in
7622
let aa' = fAttr aa in
7623
if at' != at || aa' != aa then (an,at',aa') else arg
7625
let argslist' = mapNoCopy visitArg argslist in
7627
if rettype' != rettype || argslist' != argslist || a' != a then
7628
let args' = if argslist' == argslist then args else Some argslist' in
7629
TFun(rettype', args', isva, a') else t
7633
let t1' = vis#behavior.get_typeinfo t1 in
7634
if a' != a || t1' != t1 then TNamed (t1', a') else t
7637
let enum' = vis#behavior.get_enuminfo enum in
7638
if a' != a || enum' != enum then TEnum(enum',a') else t
7639
| _ -> (* other types (TVoid, TInt, TFloat, TEnum, and TBuiltin_va_list)
7640
don't contain nested types, but they do have attributes. *)
7641
let a = typeAttrs t in
7643
if a' != a then setTypeAttrs t a' else t
7645
(* for declarations, we visit the types inside; but for uses, *)
7646
(* we just visit the varinfo node *)
7647
and visitCilVarDecl (vis : cilVisitor) (v : varinfo) : varinfo =
7648
doVisit vis vis#behavior.memo_varinfo
7649
vis#vvdec childrenVarDecl v
7650
and childrenVarDecl (vis : cilVisitor) (v : varinfo) : varinfo =
7651
v.vtype <- visitCilType vis v.vtype;
7652
v.vattr <- visitCilAttributes vis v.vattr;
7653
v.vlogic_var_assoc <-
7654
opt_map (visitCilLogicVarDecl vis) v.vlogic_var_assoc;
7657
and visitCilVarUse vis v =
7658
doVisit vis vis#behavior.get_varinfo vis#vvrbl (fun _ x -> x) v
7660
and visitCilAttributes (vis: cilVisitor) (al: attribute list) : attribute list=
7664
(fun x -> x) vis#vattr childrenAttribute) al in
7667
addAttributes al' []
7670
and childrenAttribute (vis: cilVisitor) (a: attribute) : attribute =
7671
let fAttrP a = visitCilAttrParams vis a in
7674
let args' = mapNoCopy fAttrP args in
7675
if args' != args then Attr(n, args') else a
7679
and visitCilAttrParams (vis: cilVisitor) (a: attrparam) : attrparam =
7680
doVisit vis (fun x -> x) vis#vattrparam childrenAttrparam a
7681
and childrenAttrparam (vis: cilVisitor) (aa: attrparam) : attrparam =
7682
let fTyp t = visitCilType vis t in
7683
let fAttrP a = visitCilAttrParams vis a in
7685
AInt _ | AStr _ -> aa
7687
let args' = mapNoCopy fAttrP args in
7688
if args' != args then ACons(n, args') else aa
7691
if t' != t then ASizeOf t' else aa
7693
let e' = fAttrP e in
7694
if e' != e then ASizeOfE e' else aa
7697
if t' != t then AAlignOf t' else aa
7699
let e' = fAttrP e in
7700
if e' != e then AAlignOfE e' else aa
7701
| ASizeOfS _ | AAlignOfS _ ->
7702
ignore (warn "Visitor inside of a type signature.");
7705
let e1' = fAttrP e1 in
7706
if e1' != e1 then AUnOp (uo, e1') else aa
7707
| ABinOp (bo, e1, e2) ->
7708
let e1' = fAttrP e1 in
7709
let e2' = fAttrP e2 in
7710
if e1' != e1 || e2' != e2 then ABinOp (bo, e1', e2') else aa
7712
let ap' = fAttrP ap in
7713
if ap' != ap then ADot (ap', s) else aa
7715
let ap' = fAttrP ap in
7716
if ap' != ap then AStar ap' else aa
7718
let ap' = fAttrP ap in
7719
if ap' != ap then AAddrOf ap' else aa
7720
| AIndex (e1, e2) ->
7721
let e1' = fAttrP e1 in
7722
let e2' = fAttrP e2 in
7723
if e1' != e1 || e2' != e2 then AIndex (e1', e2') else aa
7724
| AQuestion (e1, e2, e3) ->
7725
let e1' = fAttrP e1 in
7726
let e2' = fAttrP e2 in
7727
let e3' = fAttrP e3 in
7728
if e1' != e1 || e2' != e2 || e3' != e3
7729
then AQuestion (e1', e2', e3') else aa
7732
let rec fix_succs_preds_block b block =
7733
List.iter (fix_succs_preds b) block.bstmts
7734
and fix_succs_preds b stmt =
7735
stmt.succs <- mapNoCopy b.get_stmt stmt.succs;
7736
stmt.preds <- mapNoCopy b.get_stmt stmt.preds;
7737
match stmt.skind with
7738
If(_,bthen,belse,_) ->
7739
fix_succs_preds_block b bthen;
7740
fix_succs_preds_block b belse
7741
| Switch(e,cases,stmts,l) ->
7742
fix_succs_preds_block b cases;
7743
stmt.skind <- Switch(e,cases,List.map b.get_stmt stmts,l)
7744
| Loop(annot,block,loc,stmt1,stmt2) ->
7745
fix_succs_preds_block b block;
7746
let stmt1' = opt_map b.get_stmt stmt1 in
7747
let stmt2' = opt_map b.get_stmt stmt2 in
7748
stmt.skind <- Loop(annot,block,loc,stmt1',stmt2')
7749
| Block block -> fix_succs_preds_block b block
7750
| TryFinally(block1,block2,_) ->
7751
fix_succs_preds_block b block1;
7752
fix_succs_preds_block b block2
7753
| TryExcept(block1,_,block2,_) ->
7754
fix_succs_preds_block b block1;
7755
fix_succs_preds_block b block2
7758
let rec visitCilFunction (vis : cilVisitor) (f : fundec) : fundec =
7759
if debugVisit then ignore
7760
(E.log "Visiting function %s\n" f.svar.vname);
7761
assertEmptyQueue vis;
7762
vis#set_current_func f;
7763
let f = vis#behavior.cfundec f in
7764
f.svar <- vis#behavior.memo_varinfo f.svar; (* hit the function name *)
7766
doVisit vis (fun x -> x) (* copy has already been done *)
7767
vis#vfunc childrenFunction f
7769
let toPrepend = vis#unqueueInstr () in
7770
if toPrepend <> [] then
7772
(List.map (fun i -> mkStmt (Instr i)) toPrepend) @ f.sbody.bstmts;
7773
if vis#behavior.is_copy_behavior then begin
7774
fix_succs_preds_block vis#behavior f.sbody;
7775
f.sallstmts <- List.map vis#behavior.get_stmt f.sallstmts
7777
vis#reset_current_func ();
7780
and childrenFunction (vis : cilVisitor) (f : fundec) : fundec =
7781
f.svar <- visitCilVarDecl vis f.svar; (* hit the function name *)
7782
(* visit local declarations *)
7783
f.slocals <- mapNoCopy (visitCilVarDecl vis) f.slocals;
7784
(* visit the formals *)
7785
let newformals = mapNoCopy (visitCilVarDecl vis) f.sformals in
7786
(* Make sure the type reflects the formals *)
7787
setFormals f newformals;
7788
(* Remember any new instructions that were generated while visiting
7789
variable declarations. *)
7790
let toPrepend = vis#unqueueInstr () in
7791
f.sbody <- visitCilBlock vis f.sbody; (* visit the body *)
7792
if toPrepend <> [] then
7793
f.sbody.bstmts <- (List.map (fun i -> mkStmt (Instr i)) toPrepend) @ f.sbody.bstmts;
7794
f.sspec <- visitCilFunspec vis f.sspec;
7797
let childrenFieldInfo vis fi =
7798
fi.fcomp <- vis#behavior.get_compinfo fi.fcomp;
7799
fi.ftype <- visitCilType vis fi.ftype;
7800
fi.fattr <- visitCilAttributes vis fi.fattr;
7803
let visitCilFieldInfo vis f =
7804
doVisit vis vis#behavior.memo_fieldinfo vis#vfieldinfo childrenFieldInfo f
7806
let childrenCompInfo vis comp =
7807
comp.cfields <- mapNoCopy (visitCilFieldInfo vis) comp.cfields;
7808
comp.cattr <- visitCilAttributes vis comp.cattr;
7811
let visitCilCompInfo vis c =
7812
doVisit vis vis#behavior.memo_compinfo vis#vcompinfo childrenCompInfo c
7814
let childrenEnumItem vis e =
7815
e.eival <- visitCilExpr vis e.eival;
7816
e.eihost <- vis#behavior.get_enuminfo e.eihost;
7819
let visitCilEnumItem vis e =
7820
doVisit vis vis#behavior.memo_enumitem vis#venumitem childrenEnumItem e
7822
let childrenEnumInfo vis e =
7823
e.eitems <- mapNoCopy (visitCilEnumItem vis) e.eitems;
7824
e.eattr <- visitCilAttributes vis e.eattr;
7827
let visitCilEnumInfo vis e =
7828
doVisit vis vis#behavior.memo_enuminfo vis#venuminfo childrenEnumInfo e
7830
let rec visitCilGlobal (vis: cilVisitor) (g: global) : global list =
7831
(*(trace "visit" (dprintf "visitCilGlobal\n"));*)
7832
let oldloc = CurrentLoc.get () in
7833
CurrentLoc.set (get_globalLoc g) ;
7836
doVisitList vis (fun x -> x) vis#vglob childrenGlobal g in
7837
CurrentLoc.set oldloc;
7839
and childrenGlobal (vis: cilVisitor) (g: global) : global =
7842
let f' = visitCilFunction vis f in
7843
if f' != f then GFun (f', l) else g
7845
let t' = vis#behavior.memo_typeinfo t in
7846
t'.ttype <- visitCilType vis t'.ttype;
7847
if t' != t then GType(t,l) else g
7848
| GEnumTagDecl (enum,l) ->
7849
let enum' = vis#behavior.memo_enuminfo enum in
7850
if enum != enum' then GEnumTagDecl(enum',l) else g
7851
(* real visit'll be done in the definition *)
7852
| GCompTagDecl (comp,l) ->
7853
let comp' = vis#behavior.memo_compinfo comp in
7854
if comp != comp' then GCompTagDecl(comp',l) else g
7855
| GEnumTag (enum, l) ->
7856
let enum' = visitCilEnumInfo vis enum in
7857
if enum != enum' then GEnumTag(enum',l) else g
7858
| GCompTag (comp, l) ->
7859
let comp' = visitCilCompInfo vis comp in
7860
if comp != comp' then GCompTag(comp',l) else g
7861
| GVarDecl(spec, v, l) ->
7863
try Some (getFormalsDecl v) with Not_found -> None
7865
let v' = visitCilVarDecl vis v in
7866
let form' = opt_map (mapNoCopy (visitCilVarDecl vis)) form in
7868
if isFunctionType v.vtype then
7869
visitCilFunspec vis spec
7871
assert (is_empty_funspec spec);
7875
if v' != v || spec' != spec || form != form' then
7877
(match form' with None -> ()
7879
Queue.add (fun () -> unsafeSetFormalsDecl v' form')
7880
vis#get_filling_actions);
7881
GVarDecl (spec', v', l)
7884
| GVar (v, inito, l) ->
7885
let v' = visitCilVarDecl vis v in
7886
let inito' = vis#behavior.cinitinfo inito in
7887
(match inito'.init with
7889
| Some i -> let i' = visitCilInit vis v NoOffset i in
7890
if i' != i then inito'.init <- Some i');
7891
if v' != v || inito' != inito then GVar (v', inito', l) else g
7892
| GPragma (a, l) -> begin
7893
match visitCilAttributes vis [a] with
7894
[a'] -> if a' != a then GPragma (a', l) else g
7895
| _ -> E.s (E.unimp "visitCilAttributes returns more than one attribute")
7898
let a' = visitCilAnnotation vis a in
7899
if a' != a then GAnnot(a',l) else g
7900
| GText _ | GAsm _ -> g
7903
(** A visitor that does constant folding. If "machdep" is true then we do
7904
* machine dependent simplification (e.g., sizeof) *)
7905
class constFoldVisitorClass (machdep: bool) : cilVisitor = object
7906
inherit nopCilVisitor
7910
(* Skip two functions to which we add Sizeof to the type arguments.
7911
See the comments for these above. *)
7912
Call(_,(Lval (Var vi,NoOffset)),_,_)
7913
when ((vi.vname = "__builtin_va_arg")
7914
|| (vi.vname = "__builtin_types_compatible_p")) ->
7917
method vexpr (e: exp) =
7918
(* Do it bottom up *)
7919
ChangeDoChildrenPost (e, constFold machdep)
7922
let constFoldVisitor (machdep: bool) = new constFoldVisitorClass machdep
7924
(* Iterate over all globals, including the global initializer *)
7925
let iterGlobals (fl: file)
7926
(doone: global -> unit) : unit =
7928
CurrentLoc.set (get_globalLoc g);
7931
List.iter doone' fl.globals;
7932
(match fl.globinit with
7934
| Some g -> doone' (GFun(g, locUnknown)))
7936
(* Fold over all globals, including the global initializer *)
7937
let foldGlobals (fl: file)
7938
(doone: 'a -> global -> 'a)
7941
CurrentLoc.set (get_globalLoc g);
7944
let acc' = List.fold_left doone' acc fl.globals in
7945
(match fl.globinit with
7947
| Some g -> doone' acc' (GFun(g, locUnknown)))
7949
(** Find a function or function prototype with the given name in the file.
7950
* If it does not exist, create a prototype with the given type, and return
7951
* the new varinfo. This is useful when you need to call a libc function
7952
* whose prototype may or may not already exist in the file.
7954
* Because the new prototype is added to the start of the file, you shouldn't
7955
* refer to any struct or union types in the function type.*)
7956
let findOrCreateFunc (f:file) (name:string) (t:typ) : varinfo =
7957
let rec search glist =
7959
GVarDecl(_,vi,_) :: _rest when vi.vname = name ->
7960
if not (isFunctionType vi.vtype) then
7961
E.s (error ("findOrCreateFunc: can't create %s because another "
7962
^^"global exists with that name.") name);
7964
| _ :: rest -> search rest (* tail recursive *)
7965
| [] -> (*not found, so create one *)
7966
let t' = unrollTypeDeep t in
7967
let new_decl = makeGlobalVar name t' in
7968
setFormalsDecl new_decl t';
7969
f.globals <- GVarDecl(empty_funspec (), new_decl, locUnknown) :: f.globals;
7975
let childrenFileSameGlobals vis f =
7976
let fGlob g = visitCilGlobal vis g in
7980
[g'] when g' == g || equals g' g -> () (* Try to do the pointer check first *)
7982
ignore (log "You used visitCilFileSameGlobals but the global got changed:\n %a\nchanged to %a\n" d_global g (fprintfList ~sep:"@\n" d_global) gl);
7986
let post_file vis f =
7987
let res = vis#vfile f in
7989
SkipChildren -> ChangeToPost(f, fun res -> vis#fill_global_tables; res)
7990
| ChangeTo res -> ChangeToPost(res, fun res -> vis#fill_global_tables; res)
7991
| ChangeToPost (res, f) ->
7992
ChangeToPost(res, fun res -> vis#fill_global_tables; f res)
7994
ChangeDoChildrenPost(f, fun f -> vis#fill_global_tables; f)
7995
| ChangeDoChildrenPost(f,post) ->
7996
ChangeDoChildrenPost
7997
(f,fun f -> let f = post f in vis#fill_global_tables; f)
7999
(* A visitor for the whole file that does not change the globals *)
8000
let visitCilFileSameGlobals (vis : cilVisitor) (f : file) : unit =
8001
if vis#behavior.is_copy_behavior then
8002
ignore (log "You used visitCilFileSameGlobals with a copy visitor. \
8003
This is an error. Nothing is done")
8006
(doVisit vis vis#behavior.cfile (post_file vis) childrenFileSameGlobals f)
8008
let childrenFileCopy vis f =
8009
let fGlob g = visitCilGlobal vis g in
8010
(* Scan the globals. Make sure this is tail recursive. *)
8011
let rec loop (acc: global list) = function
8012
[] -> f.globals <- List.rev acc
8014
loop ((List.rev (fGlob g)) @ acc) restg
8017
(* the global initializer *)
8018
(match f.globinit with
8020
| Some g -> f.globinit <- Some (visitCilFunction vis g));
8023
(* Be careful with visiting the whole file because it might be huge. *)
8024
let visitCilFileCopy (vis : cilVisitor) (f : file) : file =
8025
vis#set_logic_tables ();
8026
doVisit vis vis#behavior.cfile (post_file vis) childrenFileCopy f
8028
let visitCilFile vis f =
8029
if vis#behavior.is_copy_behavior then
8030
ignore (log "You used visitCilFile with a copy visitor. \
8031
This is an error. Nothing is done")
8032
else ignore (visitCilFileCopy vis f)
8035
(** Create or fetch the global initializer. Tries to put a call to the
8036
* function with the main_name into it *)
8037
let getGlobInit ?(main_name="main") (fl: file) =
8038
match fl.globinit with
8041
(* Sadly, we cannot use the Filename library because it does not like
8042
* function names with multiple . in them *)
8044
let len = String.length fl.fileName in
8045
(* Find the last path separator and record the first . that we see,
8046
* going backwards *)
8047
let lastDot = ref len in
8048
let rec findLastPathSep i =
8049
if i < 0 then -1 else
8050
let c = String.get fl.fileName i in
8051
if c = '/' || c = '\\' then i
8053
if c = '.' && !lastDot = len then
8055
findLastPathSep (i - 1)
8058
let lastPathSep = findLastPathSep (len - 1) in
8060
String.sub fl.fileName (lastPathSep + 1) (!lastDot - lastPathSep - 1)
8063
(makeValidVarinfoName ("__globinit_" ^ basenoext))
8065
fl.globinit <- Some f;
8066
(* Now try to add a call to the global initialized at the beginning of
8068
let inserted = ref false in
8071
GFun(m, lm) when m.svar.vname = main_name ->
8072
(* Prepend a prototype to the global initializer *)
8073
fl.globals <- GVarDecl (empty_funspec (),f.svar, lm) :: fl.globals;
8075
mkStmt (Instr (Call(None,
8080
if !E.verboseFlag then
8081
ignore (E.log "Inserted the globinit\n");
8082
fl.globinitcalled <- true;
8086
(* YMo: remove useless warning that worries users *)
8087
(* if not !inserted then *)
8088
(* ignore (E.warn "Cannot find %s to add global initializer %s" *)
8089
(* main_name f.svar.vname); *)
8096
(* Fold over all globals, including the global initializer *)
8097
let mapGlobals (fl: file)
8098
(doone: global -> global) : unit =
8099
fl.globals <- List.map doone fl.globals;
8100
(match fl.globinit with
8103
match doone (GFun(g, locUnknown)) with
8104
GFun(g', _) -> fl.globinit <- Some g'
8105
| _ -> E.s (E.bug "mapGlobals: globinit is not a function")
8110
let dumpFile (pp: cilPrinter) (out : out_channel) (outfile: string) file =
8112
let fmt = formatter_of_out_channel out in
8113
pp_set_max_boxes fmt max_int; (* We don't want ... in the output *)
8114
pp_set_margin fmt 79;
8116
if !E.verboseFlag then
8117
ignore (log "printing file %s\n" outfile);
8120
"/* Generated by CIL v. %s */@\n/* print_CIL_Input is %b */@\n@\n"
8122
miscState.print_CIL_Input;
8123
iterGlobals file (fun g -> printGlobal pp fmt g);
8125
(* sm: we have to flush the output channel; if we don't then under *)
8126
(* some circumstances (I haven't figure out exactly when, but it happens *)
8127
(* more often with big inputs), we get a truncated output file *)
8128
pp_print_flush fmt ();
8131
let d_file (pp: cilPrinter) fmt file =
8133
"@[/* Generated by CIL v. %s */@\n/* print_CIL_Input is %b */@\n@\n"
8135
miscState.print_CIL_Input;
8136
iterGlobals file (fun g -> printGlobal pp fmt g);
8145
(* Convert an expression into an attribute, if possible. Otherwise raise
8147
exception NotAnAttrParam of exp
8148
let rec expToAttrParam (e: exp) : attrparam =
8150
Const(CInt64(i,k,_)) ->
8151
let i', trunc = truncateInteger64 k i in
8153
raise (NotAnAttrParam e);
8154
let i2 = Int64.to_int i' in
8155
if i' <> Int64.of_int i2 then
8156
raise (NotAnAttrParam e);
8158
| Lval (Var v, NoOffset) -> ACons(v.vname, [])
8159
| SizeOf t -> ASizeOf t
8160
| SizeOfE e' -> ASizeOfE (expToAttrParam e')
8162
| UnOp(uo, e', _) -> AUnOp (uo, expToAttrParam e')
8163
| BinOp(bo, e1',e2', _) -> ABinOp (bo, expToAttrParam e1',
8165
| _ -> raise (NotAnAttrParam e)
8168
(******************** OPTIMIZATIONS *****)
8169
let rec peepHole1 (* Process one statement and possibly replace it *)
8170
(doone: instr -> instr list option)
8171
(* Scan a block and recurse inside nested blocks *)
8172
(ss: stmt list) : unit =
8173
let rec doInstrList (il: instr list) : instr list =
8176
| i :: rest -> begin
8178
None -> i :: doInstrList rest
8179
| Some sl -> doInstrList (sl @ rest)
8186
| Instr i -> s.skind <- stmt_of_instr_list (doInstrList [i])
8187
| If (_e, tb, eb, _) ->
8188
peepHole1 doone tb.bstmts;
8189
peepHole1 doone eb.bstmts
8190
| Switch (_e, b, _, _) -> peepHole1 doone b.bstmts
8191
| Loop (_, b, _l, _, _) -> peepHole1 doone b.bstmts
8192
| Block b -> peepHole1 doone b.bstmts
8193
| UnspecifiedSequence seq ->
8194
peepHole1 doone (List.map (fun (x,_,_) -> x) seq)
8195
| TryFinally (b, h, _l) ->
8196
peepHole1 doone b.bstmts;
8197
peepHole1 doone h.bstmts
8198
| TryExcept (b, (il, e), h, l) ->
8199
peepHole1 doone b.bstmts;
8200
peepHole1 doone h.bstmts;
8201
s.skind <- TryExcept(b, (doInstrList il, e), h, l);
8202
| Return _ | Goto _ | Break _ | Continue _ -> ())
8205
let rec peepHole2 (* Process two statements and possibly replace them both *)
8206
(dotwo: stmt * stmt -> stmt list option)
8208
let rec doStmtList (il: stmt list) : stmt list =
8211
| [i] -> process i; il
8212
| (i1 :: ((i2 :: rest) as rest2)) ->
8214
match dotwo (i1,i2) with
8215
None -> process i1; i1 :: doStmtList rest2
8216
| Some sl -> doStmtList (sl @ rest)
8218
and doUnspecifiedStmtList il =
8221
| [ (s,_,_) ] -> process s; il
8222
| ((i1,w1,r1) as hd)::(((i2,w2,r2)::rest) as rest2) ->
8224
match dotwo (i1,i2) with
8225
None -> process i1; hd :: doUnspecifiedStmtList rest2
8226
| Some [] -> doUnspecifiedStmtList rest
8229
(hd, w1 @ w2, r1 @ r2) :: (List.map (fun x -> x,[],[]) tl)
8230
in doUnspecifiedStmtList (res @ rest)
8235
| If (_e, tb, eb, _) ->
8236
tb.bstmts <- peepHole2 dotwo tb.bstmts;
8237
eb.bstmts <- peepHole2 dotwo eb.bstmts
8238
| Switch (_e, b, _, _) -> b.bstmts <- peepHole2 dotwo b.bstmts
8239
| Loop (_, b, _l, _, _) -> b.bstmts <- peepHole2 dotwo b.bstmts
8240
| Block b -> b.bstmts <- doStmtList b.bstmts
8241
| TryFinally (b, h, _l) -> b.bstmts <- peepHole2 dotwo b.bstmts;
8242
b.bstmts <- peepHole2 dotwo h.bstmts
8243
| TryExcept (b, (_il, _e), h, _l) ->
8244
b.bstmts <- peepHole2 dotwo b.bstmts;
8245
h.bstmts <- peepHole2 dotwo h.bstmts;
8246
() (*s.skind <- TryExcept (b, (doInstrList il, e), h, l)*)
8248
| UnspecifiedSequence seq ->
8249
s.skind <- UnspecifiedSequence (doUnspecifiedStmtList seq)
8250
| Return _ | Goto _ | Break _ | Continue _ -> ()
8251
in List.iter process ss;
8254
(*** Type signatures ***)
8256
(* Helper class for typeSig: replace any types in attributes with typsigs *)
8257
class typeSigVisitor(typeSigConverter: typ->typsig) = object
8258
inherit nopCilVisitor
8259
method vattrparam ap =
8261
| ASizeOf t -> ChangeTo (ASizeOfS (typeSigConverter t))
8262
| AAlignOf t -> ChangeTo (AAlignOfS (typeSigConverter t))
8266
let typeSigAddAttrs a0 t =
8267
if a0 == [] then t else
8269
TSBase t -> TSBase (typeAddAttributes a0 t)
8270
| TSPtr (ts, a) -> TSPtr (ts, addAttributes a0 a)
8271
| TSArray (ts, l, a) -> TSArray(ts, l, addAttributes a0 a)
8272
| TSComp (iss, n, a) -> TSComp (iss, n, addAttributes a0 a)
8273
| TSEnum (n, a) -> TSEnum (n, addAttributes a0 a)
8274
| TSFun(ts, tsargs, isva, a) -> TSFun(ts, tsargs, isva, addAttributes a0 a)
8276
(* Compute a type signature.
8277
Use ~ignoreSign:true to convert all signed integer types to unsigned,
8278
so that signed and unsigned will compare the same. *)
8279
let rec typeSigWithAttrs ?(ignoreSign=false) doattr t =
8280
let typeSig = typeSigWithAttrs ~ignoreSign doattr in
8281
let attrVisitor = new typeSigVisitor typeSig in
8282
let doattr al = visitCilAttributes attrVisitor (doattr al) in
8286
if ignoreSign then unsignedVersionOf ik else ik
8288
TSBase (TInt (ik', doattr al))
8289
| TFloat (fk, al) -> TSBase (TFloat (fk, doattr al))
8290
| TVoid al -> TSBase (TVoid (doattr al))
8291
| TEnum (enum, a) -> TSEnum (enum.ename, doattr a)
8292
| TPtr (t, a) -> TSPtr (typeSig t, doattr a)
8293
| TArray (t,l,a) -> (* We do not want fancy expressions in array lengths.
8294
* So constant fold the lengths *)
8298
match constFold true l with
8299
Const(CInt64(i, _, _)) -> Some i
8300
| e -> E.s (bug "Invalid length in array type: %a\n"
8305
TSArray(typeSig t, l', doattr a)
8307
| TComp (comp, a) ->
8308
TSComp (comp.cstruct, comp.cname, doattr (addAttributes comp.cattr a))
8309
| TFun(rt,args,isva,a) ->
8311
List.map (fun (_, atype, _) -> (typeSig atype)) (argsToList args),
8313
| TNamed(t, a) -> typeSigAddAttrs (doattr a) (typeSig t.ttype)
8314
| TBuiltin_va_list al -> TSBase (TBuiltin_va_list (doattr al))
8317
typeSigWithAttrs (fun al -> al) t
8319
let _ = pTypeSig := typeSig
8321
(* Remove the attribute from the top-level of the type signature *)
8322
let setTypeSigAttrs (a: attribute list) = function
8323
TSBase t -> TSBase (setTypeAttrs t a)
8324
| TSPtr (ts, _) -> TSPtr (ts, a)
8325
| TSArray (ts, l, _) -> TSArray(ts, l, a)
8326
| TSComp (iss, n, _) -> TSComp (iss, n, a)
8327
| TSEnum (n, _) -> TSEnum (n, a)
8328
| TSFun (ts, tsargs, isva, _) -> TSFun (ts, tsargs, isva, a)
8331
let typeSigAttrs = function
8332
TSBase t -> typeAttrs t
8333
| TSPtr (_ts, a) -> a
8334
| TSArray (_ts, _l, a) -> a
8335
| TSComp (_iss, _n, a) -> a
8336
| TSEnum (_n, a) -> a
8337
| TSFun (_ts, _tsargs, _isva, a) -> a
8341
let dExp: string -> exp =
8342
fun d -> Const(CStr(d))
8344
let dInstr: string -> location -> instr =
8345
fun d l -> Asm([], [d], [], [], [], l)
8347
let dGlobal: string -> location -> global =
8348
fun d l -> GAsm(d, l)
8350
(* Make an AddrOf. Given an lval of type T will give back an expression of
8352
let mkAddrOf ((_b, _off) as lval) : exp =
8353
(* Never take the address of a register variable *)
8355
Var vi, _off when vi.vstorage = Register -> vi.vstorage <- NoStorage
8358
Mem e, NoOffset -> e
8359
| b, Index(z, NoOffset) when isZero z -> StartOf (b, NoOffset)(* array *)
8363
let mkAddrOrStartOf (lv: lval) : exp =
8364
match unrollType (typeOfLval lv) with
8365
TArray _ -> StartOf lv
8369
(* Make a Mem, while optimizing AddrOf. The type of the addr must be
8370
* TPtr(t) and the type of the resulting lval is t. Note that in CIL the
8371
* implicit conversion between a function and a pointer to a function does
8372
* not apply. You must do the conversion yourself using AddrOf *)
8373
let mkMem ~(addr: exp) ~(off: offset) : lval =
8375
match addr, off with
8376
AddrOf lv, _ -> addOffsetLval off lv
8377
| StartOf lv, _ -> (* Must be an array *)
8378
addOffsetLval (Index(zero, off)) lv
8379
| _, _ -> Mem addr, off
8381
(* ignore (E.log "memof : %a:%a\nresult = %a\n"
8382
d_plainexp addr d_plainoffset off d_plainexp res); *)
8385
let mkTermMem ~(addr: term) ~(off: term_offset) : term_lval =
8386
let loc = addr.term_loc in
8388
match addr.term_node, off with
8389
TAddrOf lv, _ -> addTermOffsetLval off lv
8390
| TStartOf lv, _ -> (* Must be an array *)
8391
addTermOffsetLval (TIndex(lzero ~loc (), off)) lv
8392
| _, _ -> TMem addr, off
8394
(* ignore (E.log "memof : %a:%a\nresult = %a\n"
8395
d_plainexp addr d_plainoffset off d_plainexp res); *)
8398
let splitFunctionType (ftype: typ)
8399
: typ * (string * typ * attributes) list option * bool * attributes =
8400
match unrollType ftype with
8401
TFun (rt, args, isva, a) -> rt, args, isva, a
8402
| _ -> E.s (bug "splitFunctionType invoked on a non function type %a"
8405
let splitFunctionTypeVI (fvi: varinfo)
8406
: typ * (string * typ * attributes) list option * bool * attributes =
8407
match unrollType fvi.vtype with
8408
TFun (rt, args, isva, a) -> rt, args, isva, a
8409
| _ -> E.s (bug "Function %s invoked on a non function type" fvi.vname)
8412
match unrollType t with
8416
let isCharArrayType t =
8417
match unrollType t with
8418
TArray(tau,_,_) when isCharType tau -> true
8421
let isStructOrUnionType t =
8422
match unrollType t with
8427
let rec isConstant e = match stripInfo e with
8428
| Info _ -> assert false
8430
| UnOp (_, e, _) -> isConstant e
8431
| BinOp (_, e1, e2, _) -> isConstant e1 && isConstant e2
8432
| Lval (Var vi, NoOffset) ->
8433
(vi.vglob && isArrayType vi.vtype || isFunctionType vi.vtype)
8435
| SizeOf _ | SizeOfE _ | SizeOfStr _ | AlignOf _ | AlignOfE _ -> true
8436
| CastE (_, e) -> isConstant e
8437
| AddrOf (Var vi, off) | StartOf (Var vi, off)
8438
-> vi.vglob && isConstantOffset off
8439
| AddrOf (Mem e, off) | StartOf(Mem e, off)
8440
-> isConstant e && isConstantOffset off
8442
and isConstantOffset = function
8444
| Field(_fi, off) -> isConstantOffset off
8445
| Index(e, off) -> isConstant e && isConstantOffset off
8447
let getCompField (cinfo:compinfo) (fieldName:string) : fieldinfo =
8448
(List.find (fun fi -> fi.fname = fieldName) cinfo.cfields)
8451
let rec mkCastT ~(e: exp) ~(oldt: typ) ~(newt: typ) =
8452
(* Do not remove old casts because they are conversions !!! *)
8453
(* TODO: remove ALL attributes including volatile...*)
8455
(typeSig (typeRemoveAttributes ["const"; "FRAMA_C_BITFIELD_SIZE"] oldt))
8456
(typeSig (typeRemoveAttributes ["const"; "FRAMA_C_BITFIELD_SIZE"] newt)) then begin
8459
(* Watch out for constants *)
8461
TInt(newik, []), Const(CInt64(i, _, _)) -> kinteger64 newik i
8462
| _ -> CastE((typeRemoveAttributes ["FRAMA_C_BITFIELD_SIZE"] newt),e)
8465
let mkCast ~(e: exp) ~(newt: typ) =
8466
mkCastT e (typeOf e) newt
8469
ExistsTrue (* We have found it *)
8470
| ExistsFalse (* Stop processing this branch *)
8471
| ExistsMaybe (* This node is not what we are
8472
* looking for but maybe its
8474
let existsType (f: typ -> existsAction) (t: typ) : bool =
8475
let memo : (int, unit) H.t = H.create 17 in (* Memo table *)
8479
| ExistsFalse -> false
8482
TNamed (t', _) -> loop t'.ttype
8483
| TComp (c, _) -> loopComp c
8484
| TArray (t', _, _) -> loop t'
8485
| TPtr (t', _) -> loop t'
8486
| TFun (rt, args, _, _) ->
8487
(loop rt || List.exists (fun (_, at, _) -> loop at)
8491
if H.mem memo c.ckey then
8492
(* We are looping, the answer must be false *)
8495
H.add memo c.ckey ();
8496
List.exists (fun f -> loop f.ftype) c.cfields
8502
(* Try to do an increment, with constant folding *)
8503
let increm (e: exp) (i: int) =
8504
let et = typeOf e in
8505
let bop = if isPointerType et then PlusPI else PlusA in
8506
constFold false (BinOp(bop, e, integer i, et))
8508
(* Try to do an increment, with constant folding *)
8509
let increm64 (e: exp) (i: int64) =
8510
let et = typeOf e in
8511
let bop = if isPointerType et then PlusPI else PlusA in
8512
constFold false (BinOp(bop, e, kinteger64 IULongLong i, et))
8514
exception LenOfArray
8515
let lenOfArray64 eo =
8517
None -> raise LenOfArray
8519
match constFold true e with
8520
| Const(CInt64(ni, _, _)) when ni >= Int64.zero ->
8522
| _ -> raise LenOfArray
8524
let lenOfArray eo = Int64.to_int (lenOfArray64 eo)
8527
(*** Make an initializer for zeroe-ing a data type ***)
8528
let rec makeZeroInit (t: typ) : init =
8529
match unrollType t with
8530
TInt (ik, _) -> SingleInit (Const(CInt64(Int64.zero, ik, None)))
8531
| TFloat(fk, _) -> SingleInit(Const(CReal(0.0, fk, None)))
8532
| TEnum _ -> SingleInit zero
8533
| TComp (comp, _) as t' when comp.cstruct ->
8537
if f.fname <> missingFieldName then
8538
(Field(f, NoOffset), makeZeroInit f.ftype) :: acc
8543
CompoundInit (t', inits)
8545
| TComp (comp, _) when not comp.cstruct ->
8546
let fstfield, rest =
8547
match comp.cfields with
8548
f :: rest -> f, rest
8549
| [] -> E.s (unimp "Cannot create init for empty union")
8552
if theMachine.msvcMode then
8553
(* ISO C99 [6.7.8.10] says that the first field of the union
8554
is the one we should initialize. *)
8557
(* gcc initializes the whole union to zero. So choose the largest
8558
field, and set that to zero. Choose the first field if possible.
8559
MSVC also initializes the whole union, but use the ISO behavior
8560
for MSVC because it only allows compound initializers to refer
8561
to the first union field. *)
8562
let fieldSize f = try bitsSizeOf f.ftype with SizeOfError _ -> 0 in
8563
let widestField, _widestFieldWidth =
8564
List.fold_left (fun acc thisField ->
8565
let _widestField, widestFieldWidth = acc in
8566
let thisSize = fieldSize thisField in
8567
if thisSize > widestFieldWidth then
8571
(fstfield, fieldSize fstfield)
8577
CompoundInit(t, [(Field(fieldToInit, NoOffset),
8578
makeZeroInit fieldToInit.ftype)])
8580
| TArray(bt, Some len, _) as t' ->
8582
match constFold true len with
8583
Const(CInt64(n, _, _)) -> Int64.to_int n
8584
| _ -> E.s (E.unimp "Cannot understand length of array")
8586
let initbt = makeZeroInit bt in
8587
let rec loopElems acc i =
8589
else loopElems ((Index(integer i, NoOffset), initbt) :: acc) (i - 1)
8591
CompoundInit(t', loopElems [] (n - 1))
8593
| TArray (_bt, None, _at) as t' ->
8594
(* Unsized array, allow it and fill it in later
8595
* (see cabs2cil.ml, collectInitializer) *)
8596
CompoundInit (t', [])
8599
SingleInit(if theMachine.insertImplicitCasts then mkCast zero t else zero)
8600
| x -> E.s (unimp "Cannot initialize type: %a" d_type x)
8603
(** Fold over the list of initializers in a Compound (not also the nested
8604
* ones). [doinit] is called on every present initializer, even if it is of
8605
* compound type. The parameters of [doinit] are: the offset in the compound
8606
* (this is [Field(f,NoOffset)] or [Index(i,NoOffset)]), the initializer
8607
* value, expected type of the initializer value, accumulator. In the case of
8608
* arrays there might be missing zero-initializers at the end of the list.
8609
* These are scanned only if [implicit] is true. This is much like
8610
* [List.fold_left] except we also pass the type of the initializer. *)
8611
let foldLeftCompound
8613
~(doinit: offset -> init -> typ -> 'a -> 'a)
8615
~(initl: (offset * init) list)
8617
match unrollType ct with
8618
TArray(bt, leno, _) -> begin
8619
(* Scan the existing initializer *)
8621
List.fold_left (fun acc (o, i) -> doinit o i bt acc) acc initl in
8622
(* See how many more we have to do *)
8624
Some lene when implicit -> begin
8625
match constFold true lene with
8626
Const(CInt64(i, _, _)) ->
8627
let len_array = Int64.to_int i in
8628
let len_init = List.length initl in
8629
if len_array > len_init then
8630
let zi = makeZeroInit bt in
8631
let rec loop acc i =
8632
if i >= len_array then acc
8634
loop (doinit (Index(integer i, NoOffset)) zi bt acc)
8637
loop part (len_init + 1)
8640
| _ -> E.s (unimp "foldLeftCompoundAll: array with initializer and non-constant length\n")
8643
| _ when not implicit -> part
8645
| _ -> E.s (unimp "foldLeftCompoundAll: TArray with initializer and no length")
8648
| TComp (_comp, _) ->
8649
let getTypeOffset = function
8650
Field(f, NoOffset) -> f.ftype
8651
| _ -> E.s (bug "foldLeftCompound: malformed initializer")
8654
(fun acc (o, i) -> doinit o i (getTypeOffset o) acc) acc initl
8656
| _ -> E.s (E.unimp "Type of Compound is not array or struct or union")
8661
let rec isCompleteType t =
8662
match unrollType t with
8663
| TArray(_t, None, _) -> false
8664
| TArray(_t, Some z, _) when isZero z -> false
8665
| TComp (comp, _) -> (* Struct or union *)
8666
List.for_all (fun fi -> isCompleteType fi.ftype) comp.cfields
8673
(** Uniquefy the variable names *)
8674
let uniqueVarNames (f: file) : unit =
8675
(* Setup the alpha conversion table for globals *)
8676
let gAlphaTable: (string,
8677
location A.alphaTableData ref) H.t = H.create 113 in
8678
(* Keep also track of the global names that we have used. Map them to the
8679
* variable ID. We do this only to check that we do not have two globals
8680
* with the same name. *)
8681
let globalNames: (string, int) H.t = H.create 113 in
8682
(* Scan the file and add the global names to the table *)
8687
| GFun({svar = vi}, _) ->
8688
(* See if we have used this name already for something else *)
8690
let oldid = H.find globalNames vi.vname in
8691
if oldid <> vi.vid && not vi.vinline then
8692
ignore (warn "The name %s is used for two distinct globals"
8694
(* Here if we have used this name already. Go ahead *)
8695
with Not_found -> begin
8696
(* Here if this is the first time we define a name *)
8697
H.add globalNames vi.vname vi.vid;
8698
(* And register it *)
8699
A.registerAlphaName gAlphaTable None vi.vname (CurrentLoc.get ())
8703
(* Now we must scan the function bodies and rename the locals *)
8706
GFun(fdec, l) -> begin
8708
(* Setup an undo list to be able to revert the changes to the
8709
* global alpha table *)
8710
let undolist = ref [] in
8711
(* Process one local variable *)
8712
let processLocal (v: varinfo) =
8713
let newname, oldloc =
8714
A.newAlphaName gAlphaTable (Some undolist) v.vname
8717
if false && newname <> v.vname then (* Disable this warning *)
8718
ignore (warn "uniqueVarNames: Changing the name of local %s in %s to %s (due to duplicate at %a)\n"
8721
newname d_loc oldloc);
8724
(* Do the formals first *)
8725
List.iter processLocal fdec.sformals;
8726
(* Fix the type again *)
8727
setFormals fdec fdec.sformals;
8728
(* And now the locals *)
8729
List.iter processLocal fdec.slocals;
8730
(* Undo the changes to the global table *)
8731
A.undoAlphaChanges gAlphaTable !undolist;
8738
(* A visitor that makes a deep copy of a function body *)
8739
class copyFunctionVisitor (newname: string) = object
8740
inherit nopCilVisitor
8742
(* Keep here a maping from locals to their copies *)
8743
val map : (string, varinfo) H.t = H.create 113
8744
(* Keep here a maping from statements to their copies *)
8745
val stmtmap : (int, stmt) H.t = H.create 113
8746
(*val sid = ref 0 (* Will have to assign ids to statements *) *)
8747
(* Keep here a list of statements to be patched *)
8748
val patches : stmt list ref = ref []
8752
(* This is the main function *)
8753
method vfunc (f: fundec) : fundec visitAction =
8754
(* We need a map from the old locals/formals to the new ones *)
8757
(* Make a copy of the fundec. *)
8758
let f' = {f with svar = f.svar} in
8759
let patchfunction (f' : fundec) =
8760
(* Change the name. Only this late to allow the visitor to copy the
8762
f'.svar.vname <- newname;
8763
let findStmt (i: int) =
8764
try H.find stmtmap i
8765
with Not_found -> E.s (bug "Cannot find the copy of stmt#%d" i)
8767
let patchstmt (s: stmt) =
8770
(* Make a copy of the reference *)
8771
let sr' = ref (findStmt !sr.sid) in
8772
s.skind <- Goto (sr',l)
8773
| Switch (e, body, cases, l) ->
8774
s.skind <- Switch (e, body,
8775
List.map (fun cs -> findStmt cs.sid) cases, l)
8778
List.iter patchstmt !patches;
8784
ChangeDoChildrenPost (f', patchfunction)
8786
(* We must create a new varinfo for each declaration. Memoize to
8787
* maintain sharing *)
8788
method vvdec (v: varinfo) =
8789
(* Some varinfo have empty names. Give them some name *)
8790
if v.vname = "" then begin
8791
v.vname <- "arg" ^ string_of_int !argid; incr argid
8794
ChangeTo (H.find map v.vname)
8795
with Not_found -> begin
8796
let v' = copy_with_new_vid v in
8797
H.add map v.vname v';
8798
ChangeDoChildrenPost (v', fun x -> x)
8801
(* We must replace references to local variables *)
8802
method vvrbl (v: varinfo) =
8803
if v.vglob then SkipChildren else
8805
ChangeTo (H.find map v.vname)
8807
E.s (bug "Cannot find the new copy of local variable %s" v.vname)
8810
(* Replace statements. *)
8811
method vstmt (s: stmt) : stmt visitAction =
8812
s.sid <- Sid.next ();
8813
let s' = {s with sid = s.sid} in
8814
H.add stmtmap s.sid s'; (* Remember where we copied this *)
8815
(* if we have a Goto or a Switch remember them to fixup at end *)
8816
(match s'.skind with
8817
(Goto _ | Switch _) -> patches := s' :: !patches
8819
(* Do the children *)
8820
ChangeDoChildrenPost (s', fun x -> x)
8822
(* Copy blocks since they are mutable *)
8823
method vblock (b: block) =
8824
ChangeDoChildrenPost ({b with bstmts = b.bstmts}, fun x -> x)
8827
method vglob _ = E.s (bug "copyFunction should not be used on globals")
8830
(* We need a function that copies a CIL function. *)
8831
let copyFunction (f: fundec) (newname: string) : fundec =
8832
visitCilFunction (new copyFunctionVisitor(newname)) f
8834
(********* Compute the CFG ********)
8836
let statements : stmt list ref = ref []
8837
(* Clear all info about the CFG in statements *)
8838
class clear : cilVisitor = object
8839
inherit nopCilVisitor
8840
method vstmt s = begin
8841
s.sid <- Sid.next ();
8842
statements := s :: !statements;
8847
method vexpr _ = SkipChildren
8848
method vtype _ = SkipChildren
8849
method vinst _ = SkipChildren
8852
let link source dest = begin
8853
if not (List.mem dest source.succs) then
8854
source.succs <- dest :: source.succs ;
8855
if not (List.mem source dest.preds) then
8856
dest.preds <- source :: dest.preds
8858
let trylink source dest_option = match dest_option with
8860
| Some(dest) -> link source dest
8863
(** Compute the successors and predecessors of a block, given a fallthrough *)
8864
let rec succpred_block b fallthrough =
8865
let rec handle sl = match sl with
8867
| [a] -> succpred_stmt a fallthrough
8868
| hd :: ((next :: _) as tl) ->
8869
succpred_stmt hd (Some next) ;
8874
and succpred_stmt s fallthrough =
8876
Instr _ -> trylink s fallthrough
8878
| Goto(dest,_) -> link s !dest
8882
failwith "computeCFGInfo: cannot be called on functions with break, continue or switch statements. Use prepareCFG first to remove them."
8884
| If(_e1,b1,b2,_) ->
8885
(match b1.bstmts with
8886
[] -> trylink s fallthrough
8887
| hd :: _ -> (link s hd ; succpred_block b1 fallthrough )) ;
8888
(match b2.bstmts with
8889
[] -> trylink s fallthrough
8890
| hd :: _ -> (link s hd ; succpred_block b2 fallthrough ))
8892
| Loop(_,b,_,_,_) ->
8893
begin match b.bstmts with
8894
[] -> failwith "computeCFGInfo: empty loop"
8897
succpred_block b (Some(hd))
8900
| Block(b) -> begin match b.bstmts with
8901
[] -> trylink s fallthrough
8902
| hd :: _ -> link s hd ;
8903
succpred_block b fallthrough
8905
| UnspecifiedSequence (((s1,_,_)::_) as seq) ->
8907
succpred_block (block_from_unspecified_sequence seq) fallthrough
8908
| UnspecifiedSequence [] ->
8909
trylink s fallthrough
8910
| TryExcept _ | TryFinally _ ->
8911
failwith "computeCFGInfo: structured exception handling not implemented"
8913
(* [weimer] Sun May 5 12:25:24 PDT 2002
8914
* This code was pulled from ext/switch.ml because it looks like we really
8915
* want it to be part of CIL.
8917
* Here is the magic handling to
8918
* (1) replace switch statements with if/goto
8919
* (2) remove "break"
8920
* (3) remove "default"
8921
* (4) remove "continue"
8923
let is_case_label l = match l with
8924
| Case _ | Default _ -> true
8927
let switch_count = ref (-1)
8928
let get_switch_count () =
8929
switch_count := 1 + !switch_count ;
8932
let switch_label = ref (-1)
8934
let rec xform_switch_stmt
8935
?(keepSwitch=false) s break_dest cont_dest label_index = begin
8936
if not keepSwitch then
8937
s.labels <- List.map (fun lab -> match lab with
8941
match isInteger e with
8943
if value < Int64.zero then
8944
"neg_" ^ Int64.to_string (Int64.neg value)
8946
Int64.to_string value
8949
"exp_" ^ string_of_int !switch_label
8951
let str = Pretty.sprint miscState.lineLength
8952
(Pretty.dprintf "switch_%d_%s" label_index suffix) in
8953
(Label(str,l,false))
8954
| Default(l) -> (Label(Printf.sprintf
8955
"switch_%d_default" label_index,l,false))
8958
| Instr _ | Return _ | Goto _ -> ()
8959
| Break(l) -> begin try
8960
s.skind <- Goto(break_dest (),l)
8962
ignore (error "@[prepareCFG: break: %a@\n@]" d_stmt s) ;
8965
| Continue(l) -> begin try
8966
s.skind <- Goto(cont_dest (),l)
8968
ignore (error "@[prepareCFG: continue: %a@\n@]" d_stmt s) ;
8972
xform_switch_block ~keepSwitch b1 break_dest cont_dest label_index ;
8973
xform_switch_block ~keepSwitch b2 break_dest cont_dest label_index
8974
| Switch(e,b,sl,l) ->
8976
let i = get_switch_count () in
8977
let break_stmt = mkStmt (Instr (Skip locUnknown)) in
8978
break_stmt.labels <-
8979
[Label((Printf.sprintf "switch_%d_break" i),l,false)] ;
8980
let switch_stmt = mkStmt s.skind in
8981
let break_block = mkBlock [ switch_stmt; break_stmt ] in
8982
s.skind <- Block break_block;
8983
xform_switch_block ~keepSwitch b (fun () -> ref break_stmt) cont_dest i
8988
* case 1: s1 ; break;
8994
* if (se == 0) goto label_0;
8995
* else if (se == 1) goto label_1;
8997
* else if (0) { // body_block
8999
* label_1: s1; goto label_break;
9001
* } else if (0) { // break_block
9002
* label_break: ; // break_stmt
9005
let i = get_switch_count () in
9006
let break_stmt = mkStmt (Instr (Skip locUnknown)) in
9007
break_stmt.labels <-
9008
[Label((Printf.sprintf "switch_%d_break" i),l,false)] ;
9009
let break_block = mkBlock [ break_stmt ] in
9010
let body_block = b in
9011
let body_if_stmtkind = (If(zero,body_block,break_block,l)) in
9013
(* The default case, if present, must be used only if *all*
9014
non-default cases fail [ISO/IEC 9899:1999, ļæ½6.8.4.2, ļæ½5]. As a
9015
result, we sort the order in which we handle the labels (but not the
9016
order in which we print out the statements, so fall-through still
9017
works as expected). *)
9018
let compare_choices s1 s2 = match s1.labels, s2.labels with
9019
| (Default(_) :: _), _ -> 1
9020
| _, (Default(_) :: _) -> -1
9024
let rec handle_choices sl = match sl with
9025
[] -> body_if_stmtkind
9026
| stmt_hd :: stmt_tl -> begin
9027
let rec handle_labels lab_list = begin
9029
[] -> handle_choices stmt_tl
9030
| Case(ce,cl) :: lab_tl ->
9031
let pred = BinOp(Eq,e,ce,intType) in
9032
let then_block = mkBlock [ mkStmt (Goto(ref stmt_hd,cl)) ] in
9033
let else_block = mkBlock [ mkStmt (handle_labels lab_tl) ] in
9034
If(pred,then_block,else_block,cl)
9035
| Default(dl) :: lab_tl ->
9036
(* ww: before this was 'if (1) goto label', but as Ben points
9037
out this might confuse someone down the line who doesn't have
9038
special handling for if(1) into thinking that there are two
9039
paths here. The simpler 'goto label' is what we want. *)
9040
Block(mkBlock [ mkStmt (Goto(ref stmt_hd,dl)) ;
9041
mkStmt (handle_labels lab_tl) ])
9042
| Label(_,_,_) :: lab_tl -> handle_labels lab_tl
9044
handle_labels stmt_hd.labels
9046
s.skind <- handle_choices (List.sort compare_choices sl) ;
9047
xform_switch_block ~keepSwitch b (fun () -> ref break_stmt) cont_dest i
9049
| Loop(a,b,l,_,_) ->
9050
let i = get_switch_count () in
9051
let break_stmt = mkStmt (Instr (Skip locUnknown)) in
9052
break_stmt.labels <-
9053
[Label((Printf.sprintf "while_%d_break" i),l,false)] ;
9054
let cont_stmt = mkStmt (Instr (Skip locUnknown)) in
9056
[Label((Printf.sprintf "while_%d_continue" i),l,false)] ;
9057
b.bstmts <- cont_stmt :: b.bstmts ;
9058
let this_stmt = mkStmt
9059
(Loop(a,b,l,Some(cont_stmt),Some(break_stmt))) in
9060
let break_dest () = ref break_stmt in
9061
let cont_dest () = ref cont_stmt in
9062
xform_switch_block ~keepSwitch b break_dest cont_dest label_index ;
9063
break_stmt.succs <- s.succs ;
9064
let new_block = mkBlock [ this_stmt ; break_stmt ] in
9065
s.skind <- Block new_block
9067
xform_switch_block ~keepSwitch b break_dest cont_dest label_index
9068
| UnspecifiedSequence seq ->
9069
xform_switch_block ~keepSwitch
9070
(block_from_unspecified_sequence seq) break_dest cont_dest label_index
9071
| TryExcept _ | TryFinally _ ->
9072
failwith "xform_switch_statement: structured exception handling not implemented"
9074
end and xform_switch_block
9075
?(keepSwitch=false) b break_dest cont_dest label_index =
9077
let rec link_succs sl = match sl with
9079
| hd :: tl -> (if hd.succs = [] then hd.succs <- tl) ; link_succs tl
9081
link_succs b.bstmts ;
9082
List.iter (fun stmt ->
9083
xform_switch_stmt ~keepSwitch stmt break_dest cont_dest label_index) b.bstmts ;
9085
List.iter (fun stmt -> ignore
9086
(warn "prepareCFG: %a@\n" d_stmt stmt)) b.bstmts ;
9089
(* prepare a function for computeCFGInfo by removing break, continue,
9090
* default and switch statements/labels and replacing them with Ifs and
9092
let prepareCFG ?(keepSwitch=false) (fd : fundec) : unit =
9093
xform_switch_block ~keepSwitch fd.sbody
9094
(fun () -> failwith "prepareCFG: break with no enclosing loop")
9095
(fun () -> failwith "prepareCFG: continue with no enclosing loop") (-1)
9097
(* make the cfg and return a list of statements *)
9098
let computeCFGInfo (f : fundec) (global_numbering : bool) : unit =
9099
if not global_numbering then Sid.reset ();
9101
let clear_it = new clear in
9102
ignore (visitCilBlock clear_it f.sbody) ;
9103
f.smaxstmtid <- Some (Sid.get ()) ;
9104
succpred_block f.sbody (None);
9105
let res = List.rev !statements in
9110
let make_logic_var x typ =
9111
{lv_name = x; lv_id = new_raw_id(); lv_type = typ; lv_origin = None }
9113
let initLogicBuiltins () =
9115
Logic_env.add_builtin_logic_type "boolean" { nb_params=0 };
9116
Logic_env.add_builtin_logic_type "set" { nb_params=1 };
9118
Logic_env.add_builtin_logic_ctor
9119
"\\true" { ctor_name = "\\true";
9120
ctor_type = Ltype("boolean",[]);
9123
Logic_env.add_builtin_logic_ctor
9125
{ ctor_name = "\\false";
9126
ctor_type = Ltype("boolean",[]);
9129
let min = make_logic_var "min" Linteger in
9130
let max = make_logic_var "max" Linteger in
9131
let f = make_logic_var "f" (Larrow ([Linteger],Linteger)) in
9132
Logic_env.add_builtin_logic_function
9135
l_type = Some Linteger;
9136
l_tparams = []; (* FIXME !!! *)
9137
l_profile = [ min; max; f ];
9140
[ TSSingleton (TSLval (TSVar min,TSNoOffset));
9141
TSSingleton (TSLval (TSVar max,TSNoOffset));
9142
TSSingleton (TSLval (TSVar f, TSNoOffset)) ];
9144
let min = make_logic_var "min" Linteger in
9145
let max = make_logic_var "max" Linteger in
9146
let f = make_logic_var "f" (Larrow ([Linteger],Linteger)) in
9147
Logic_env.add_builtin_logic_function
9149
l_name = "\\product";
9150
l_type = Some Linteger;
9151
l_tparams = []; (* FIXME !!! *)
9152
l_profile = [ min; max; f ];
9155
[ TSSingleton (TSLval (TSVar min,TSNoOffset));
9156
TSSingleton (TSLval (TSVar max,TSNoOffset));
9157
TSSingleton (TSLval (TSVar f, TSNoOffset)) ];
9159
let min = make_logic_var "min" Linteger in
9160
let max = make_logic_var "max" Linteger in
9161
let f = make_logic_var "f" (Larrow ([Linteger],Linteger)) in
9162
Logic_env.add_builtin_logic_function
9165
l_type = Some Linteger;
9166
l_tparams = []; (* FIXME !!! *)
9167
l_profile = [ min; max; f ];
9170
[ TSSingleton (TSLval (TSVar min,TSNoOffset));
9171
TSSingleton (TSLval (TSVar max,TSNoOffset));
9172
TSSingleton (TSLval (TSVar f, TSNoOffset)) ];
9174
let min = make_logic_var "min" Linteger in
9175
let max = make_logic_var "max" Linteger in
9176
let f = make_logic_var "f" (Larrow ([Linteger],Linteger)) in
9177
Logic_env.add_builtin_logic_function
9180
l_type = Some Linteger;
9181
l_tparams = []; (* FIXME !!! *)
9182
l_profile = [ min; max; f ];
9185
[ TSSingleton (TSLval (TSVar min,TSNoOffset));
9186
TSSingleton (TSLval (TSVar max,TSNoOffset));
9187
TSSingleton (TSLval (TSVar f, TSNoOffset)) ];
9189
let min = make_logic_var "min" Linteger in
9190
let max = make_logic_var "max" Linteger in
9193
(Larrow ([Linteger],Ltype("boolean",[])))
9195
Logic_env.add_builtin_logic_function
9198
l_type = Some Linteger;
9199
l_tparams = []; (* FIXME !! *)
9200
l_profile = [ min; max; f ];
9203
[ TSSingleton (TSLval (TSVar min,TSNoOffset));
9204
TSSingleton (TSLval (TSVar max,TSNoOffset));
9205
TSSingleton (TSLval (TSVar f, TSNoOffset)) ];
9209
if not (TheMachine.is_computed ()) then begin
9211
(* Set the machine *)
9212
theMachine.theMachine <-
9213
if theMachine.msvcMode then Machdep.state.Machdep.msvc
9214
else Machdep.state.Machdep.gcc;
9215
(* Pick type for string literals *)
9216
theMachine.stringLiteralType <-
9217
if theMachine.theMachine.const_string_literals then
9221
(* Find the right ikind given the size *)
9222
let findIkindSz (unsigned: bool) (sz: int) : ikind =
9223
(* Test the most common sizes first *)
9224
if sz = theMachine.theMachine.sizeof_int then
9225
if unsigned then IUInt else IInt
9226
else if sz = theMachine.theMachine.sizeof_long then
9227
if unsigned then IULong else ILong
9229
if unsigned then IUChar else IChar
9230
else if sz = theMachine.theMachine.sizeof_short then
9231
if unsigned then IUShort else IShort
9232
else if sz = theMachine.theMachine.sizeof_longlong then
9233
if unsigned then IULongLong else ILongLong
9235
E.s(E.unimp "initCIL: cannot find the right ikind for size %d\n" sz)
9237
(* Find the right ikind given the name *)
9238
let findIkindName (name: string) : ikind =
9239
(* Test the most common sizes first *)
9240
if name = "int" then IInt
9241
else if name = "unsigned int" then IUInt
9242
else if name = "long" then ILong
9243
else if name = "unsigned long" then IULong
9244
else if name = "short" then IShort
9245
else if name = "unsigned short" then IUShort
9246
else if name = "char" then IChar
9247
else if name = "unsigned char" then IUChar
9249
E.s(E.unimp "initCIL: cannot find the right ikind for type %s\n" name)
9251
theMachine.upointType <-
9252
TInt(findIkindSz true theMachine.theMachine.sizeof_ptr, []);
9253
theMachine.kindOfSizeOf <-
9254
findIkindName theMachine.theMachine.size_t;
9255
theMachine.typeOfSizeOf <- TInt(theMachine.kindOfSizeOf, []);
9256
theMachine.wcharKind <- findIkindName theMachine.theMachine.wchar_t;
9257
theMachine.wcharType <- TInt(theMachine.wcharKind, []);
9258
theMachine.ptrdiffKind <- findIkindName theMachine.theMachine.ptrdiff_t;
9259
theMachine.ptrdiffType <- TInt(theMachine.ptrdiffKind, []);
9260
theMachine.char_is_unsigned <-
9261
theMachine.theMachine.Cil_types.char_is_unsigned;
9262
theMachine.little_endian <- theMachine.theMachine.Cil_types.little_endian;
9263
theMachine.underscore_name <-
9264
theMachine.theMachine.Cil_types.underscore_name;
9265
theMachine.enum_are_signed <-
9266
theMachine.theMachine.Cil_types.enum_are_signed;
9267
(* do not use lazy LAND and LOR *)
9268
theMachine.useLogicalOperators <- false;
9269
(*nextGlobalVID <- 1 ;
9270
nextCompinfoKey <- 1;*)
9272
(* Have to be mark before calling [init*Builtins] below. *)
9273
TheMachine.mark_as_computed ();
9275
if theMachine.msvcMode then
9280
Logic_env.Builtins.extend initLogicBuiltins;
9282
(* projectify theMachine *)
9283
copyMachine theMachine !theMachineProject;
9288
(* We want to bring all type declarations before the data declarations. This
9289
* is needed for code of the following form:
9291
int f(); // Prototype without arguments
9293
int f(FOO x) { ... }
9295
In CIL the prototype also lists the type of the argument as being FOO,
9298
There is one catch with this scheme. If the type contains an array whose
9299
length refers to variables then those variables must be declared before
9302
let pullTypesForward = true
9305
(* Scan a type and collect the variables that are refered *)
9306
class getVarsInGlobalClass (pacc: varinfo list ref) = object
9307
inherit nopCilVisitor
9308
method vvrbl (vi: varinfo) =
9309
pacc := vi :: !pacc;
9312
method vglob = function
9313
GType _ | GCompTag _ -> DoChildren
9318
let getVarsInGlobal (g : global) : varinfo list =
9319
let pacc : varinfo list ref = ref [] in
9320
let v : cilVisitor = new getVarsInGlobalClass pacc in
9321
ignore (visitCilGlobal v g);
9325
let pl = String.length p in
9326
(String.length s >= pl) && String.sub s 0 pl = p
9328
let pushGlobal (g: global)
9329
~(types:global list ref)
9330
~(variables: global list ref) =
9331
if not pullTypesForward then
9332
variables := g :: !variables
9335
(* Collect a list of variables that are refered from the type. Return
9336
* Some if the global should go with the types and None if it should go
9337
* to the variables. *)
9338
let varsintype : (varinfo list * location) option =
9340
GType (_, l) | GCompTag (_, l) -> Some (getVarsInGlobal g, l)
9341
| GEnumTag (_, l) | GPragma (Attr("pack", _), l)
9342
| GCompTagDecl (_, l) | GEnumTagDecl (_, l) -> Some ([], l)
9343
(** Move the warning pragmas early
9344
| GPragma(Attr(s, _), l) when hasPrefix "warning" s -> Some ([], l)
9346
| _ -> None (* Does not go with the types *)
9348
match varsintype with
9349
None -> variables := g :: !variables
9352
(* insert declarations for referred variables ('vl'), before
9353
* the type definition 'g' itself *)
9354
g :: (List.fold_left (fun acc v -> GVarDecl(empty_funspec (),v, loc) :: acc)
9361
| Feo of exp option (** For array lengths *)
9365
| FE of exp list (** For arguments in a function call *)
9366
| Ff of (string * typ * attributes) (** For a formal argument *)
9367
| FF of (string * typ * attributes) list (* For formal argument lists *)
9368
| Fva of bool (** For the ellipsis in a function type *)
9371
| Flo of lval option (** For the result of a function call *)
9384
| FP of attrparam list
9388
let d_formatarg fmt = function
9389
Fe e -> fprintf fmt "Fe(%a)" d_exp e
9390
| Feo None -> fprintf fmt "Feo(None)"
9391
| Feo (Some e) -> fprintf fmt "Feo(%a)" d_exp e
9392
| FE _ -> fprintf fmt "FE()"
9393
| Fk _ik -> fprintf fmt "Fk()"
9394
| Fva b -> fprintf fmt "Fva(%b)" b
9395
| Ff (an, _, _) -> fprintf fmt "Ff(%s)" an
9396
| FF _ -> fprintf fmt "FF(...)"
9397
| FA _ -> fprintf fmt "FA(...)"
9398
| Fu _uo -> fprintf fmt "Fu()"
9399
| Fb _bo -> fprintf fmt "Fb()"
9400
| Fv v -> fprintf fmt "Fv(%s)" v.vname
9401
| Fl l -> fprintf fmt "Fl(%a)" d_lval l
9402
| Flo None -> fprintf fmt "Flo(None)"
9403
| Flo (Some l) -> fprintf fmt "Flo(%a)" d_lval l
9404
| Fo _o -> fprintf fmt "Fo"
9405
| Fc ci -> fprintf fmt "Fc(%s)" ci.cname
9406
| Fi _i -> fprintf fmt "Fi(...)"
9407
| FI _i -> fprintf fmt "FI(...)"
9408
| Ft t -> fprintf fmt "Ft(%a)" d_type t
9409
| Fd n -> fprintf fmt "Fd(%d)" n
9410
| Fg s -> fprintf fmt "Fg(%s)" s
9411
| Fp _ -> fprintf fmt "Fp(...)"
9412
| FP _n -> fprintf fmt "FP(...)"
9413
| Fs _ -> fprintf fmt "FS"
9414
| FS _ -> fprintf fmt "FS"
9416
| FX _ -> fprintf fmt "FX()"
9418
let pretty_loc fmt kinstr =
9419
let loc = Instr.loc kinstr in
9420
fprintf fmt "Location: %a" d_loc loc
9422
let pretty_loc_simply fmt kinstr =
9423
let loc = Instr.loc kinstr in
9424
fprintf fmt "%a" d_loc loc
9426
let make_temp_logic_var =
9427
let counter = ref 0 in
9430
let name = "__framac_tmp" ^ (string_of_int !counter) in
9431
make_logic_var name ty
9433
let extract_varinfos_from_exp vexp =
9434
let visitor = object
9435
inherit nopCilVisitor
9436
val mutable varinfos = C.VarinfoSet.empty;
9437
method varinfos = varinfos
9438
method vvrbl (symb:varinfo) =
9440
varinfos <- C.VarinfoSet.add symb varinfos;
9444
in ignore (visitCilExpr (visitor :> nopCilVisitor) vexp) ;
9447
let extract_varinfos_from_lval vlval =
9448
let visitor = object
9449
inherit nopCilVisitor
9450
val mutable varinfos = C.VarinfoSet.empty;
9451
method varinfos = varinfos
9452
method vvrbl (symb:varinfo) =
9454
varinfos <- C.VarinfoSet.add symb varinfos;
9458
in ignore (visitCilLval (visitor :> nopCilVisitor) vlval) ;
9461
let rec free_vars_term bound_vars t = match t.term_node with
9462
| TConst _ | TSizeOf _
9463
| TSizeOfStr _ | TAlignOf _
9466
-> C.LogicVarSet.empty
9470
-> free_vars_lval bound_vars lv
9481
-> free_vars_term bound_vars t
9485
-> C.LogicVarSet.union
9486
(free_vars_term bound_vars t1)
9487
(free_vars_term bound_vars t2)
9490
(free_vars_term bound_vars t1)
9491
(C.LogicVarSet.union
9492
(free_vars_term bound_vars t2)
9493
(free_vars_term bound_vars t3))
9494
| TDataCons(_,t) | Tapp (_,_,t) ->
9496
(fun acc t -> C.LogicVarSet.union (free_vars_term bound_vars t) acc)
9497
C.LogicVarSet.empty t
9498
| Tlambda(prms,expr) ->
9500
List.fold_left (Extlib.swap C.LogicVarSet.add) bound_vars prms
9501
in free_vars_term bound_vars expr
9502
| Ttsets ts -> free_vars_tsets bound_vars ts
9503
and free_vars_lval bv (h,o) =
9504
C.LogicVarSet.union (free_vars_lhost bv h) (free_vars_term_offset bv o)
9505
and free_vars_lhost bv = function
9506
| TVar log_v -> if C.LogicVarSet.mem log_v bv then C.LogicVarSet.empty else
9507
C.LogicVarSet.singleton log_v
9508
| TResult -> C.LogicVarSet.empty
9509
| TMem t -> free_vars_term bv t
9510
and free_vars_term_offset bv = function
9511
| TNoOffset -> C.LogicVarSet.empty
9512
| TField (_,o) -> free_vars_term_offset bv o
9513
| TIndex (t,o) -> C.LogicVarSet.union (free_vars_term bv t) (free_vars_term_offset bv o)
9515
and free_vars_tsets_offset bv = function
9516
TSNoOffset -> C.LogicVarSet.empty
9518
C.LogicVarSet.union (free_vars_term bv t) (free_vars_tsets_offset bv o)
9519
| TSRange(i1,i2,o) ->
9522
None -> C.LogicVarSet.empty
9523
| Some i -> free_vars_term bv i
9528
| Some i -> C.LogicVarSet.union fv (free_vars_term bv i)
9529
in C.LogicVarSet.union fv (free_vars_tsets_offset bv o)
9530
| TSField(_,o) -> free_vars_tsets_offset bv o
9532
and free_vars_tsets_elem bv = function
9533
TSLval lv | TSStartOf lv | TSAddrOf lv -> free_vars_tsets_lval bv lv
9534
| TSConst _ -> C.LogicVarSet.empty
9535
| TSAdd_index(t,i) ->
9536
C.LogicVarSet.union (free_vars_tsets_elem bv t) (free_vars_term bv i)
9537
| TSAdd_range(t,i1,i2) ->
9538
let fv = free_vars_tsets_elem bv t in
9542
| Some i -> C.LogicVarSet.union fv (free_vars_term bv i)
9545
| Some i -> C.LogicVarSet.union fv (free_vars_term bv i))
9546
| TSCastE(_,t) -> free_vars_tsets_elem bv t
9547
| TSat (t,_) -> free_vars_tsets_elem bv t
9548
| TSapp(_,_,args) ->
9550
(fun set arg -> C.LogicVarSet.union set (free_vars_term bv arg))
9551
C.LogicVarSet.empty args
9552
and free_vars_tsets_lval bv (h,o) =
9553
C.LogicVarSet.union (free_vars_tsets_lhost bv h) (free_vars_tsets_offset bv o)
9555
and free_vars_tsets_lhost bv = function
9556
TSVar v when C.LogicVarSet.mem v bv -> C.LogicVarSet.empty
9557
| TSVar v -> C.LogicVarSet.singleton v
9558
| TSResult -> C.LogicVarSet.empty
9559
| TSMem t -> free_vars_tsets_elem bv t
9561
and free_vars_tsets bound_vars = function
9562
TSSingleton t -> free_vars_tsets_elem bound_vars t
9563
| TSEmpty -> C.LogicVarSet.empty
9564
| TSUnion l | TSInter l ->
9566
(fun acc t -> C.LogicVarSet.union (free_vars_tsets bound_vars t) acc)
9567
C.LogicVarSet.empty l
9568
| TSComprehension(t,q,p) ->
9570
List.fold_left (fun acc v -> C.LogicVarSet.add v acc) bound_vars q
9572
let fv = free_vars_tsets new_bv t in
9575
| Some p -> C.LogicVarSet.union fv (free_vars_predicate new_bv p)
9577
and free_vars_predicate bound_vars p = match p.content with
9578
| Pfalse | Ptrue -> C.LogicVarSet.empty
9582
(fun acc t -> C.LogicVarSet.union (free_vars_term bound_vars t) acc) C.LogicVarSet.empty tl
9583
| Pfresh t -> free_vars_term bound_vars t
9584
| Pvalid(t) -> free_vars_tsets bound_vars t
9585
| Pseparated seps ->
9587
(fun free_vars tset ->
9588
C.LogicVarSet.union (free_vars_tsets bound_vars tset) free_vars)
9589
C.LogicVarSet.empty seps
9591
| Pvalid_index (t1,t2)
9595
(free_vars_term bound_vars t1)
9596
(free_vars_term bound_vars t2)
9597
| Pvalid_range (t1,t2,t3) ->
9599
(C.LogicVarSet.union
9600
(free_vars_term bound_vars t1)
9601
(free_vars_term bound_vars t2))
9602
(free_vars_term bound_vars t3)
9609
(free_vars_predicate bound_vars p1)
9610
(free_vars_predicate bound_vars p2)
9614
(* | Pnamed (_,p) *) ->
9615
free_vars_predicate bound_vars p
9618
(free_vars_term bound_vars t)
9619
(C.LogicVarSet.union
9620
(free_vars_predicate bound_vars p1)
9621
(free_vars_predicate bound_vars p2))
9622
| Plet (log_v, t, p) ->
9623
let new_bv = C.LogicVarSet.add log_v bound_vars in
9625
(free_vars_term new_bv t)
9626
(free_vars_predicate new_bv p)
9629
| Pexists (lvs,p) ->
9630
let new_bv= List.fold_left (Extlib.swap C.LogicVarSet.add) bound_vars lvs in
9631
free_vars_predicate new_bv p
9633
let extract_free_logicvars_from_term t =
9634
free_vars_term C.LogicVarSet.empty t
9636
let extract_free_logicvars_from_predicate p =
9637
free_vars_predicate C.LogicVarSet.empty p
9639
let close_predicate p =
9640
let free_vars = free_vars_predicate C.LogicVarSet.empty p in
9641
if C.LogicVarSet.is_empty free_vars then p
9643
{name = []; loc = p.loc;
9644
content = Pforall ((C.LogicVarSet.elements free_vars),p)}
9646
class alpha_conv tbl ltbl =
9648
inherit nopCilVisitor
9651
let v' = Hashtbl.find tbl v.vid in ChangeTo v'
9652
with Not_found -> DoChildren
9653
method vlogic_var_use v =
9654
try let v' = Hashtbl.find ltbl v.lv_id in ChangeTo v'
9655
with Not_found -> DoChildren
9658
let create_alpha_renaming old_args new_args =
9659
let conversion = Hashtbl.create 7 in
9660
let lconversion = Hashtbl.create 7 in
9661
List.iter2 (fun old_vi new_vi ->
9662
Hashtbl.add conversion old_vi.vid new_vi;
9663
match old_vi.vlogic_var_assoc, new_vi.vlogic_var_assoc with
9664
None, _ -> () (* nothing to convert in logic spec. *)
9665
| Some old_lv, Some new_lv ->
9666
Hashtbl.add lconversion old_lv.lv_id new_lv
9667
| Some old_lv, None ->
9668
Hashtbl.add lconversion old_lv.lv_id (cvar_to_lvar new_vi)
9671
new alpha_conv conversion lconversion
9673
(** Returns [true] whenever the type contains only arithmetic types *)
9674
let is_fully_arithmetic ty =
9676
(fun typ -> match typ with
9679
| TArray _ -> ExistsMaybe
9680
| TPtr _ | TBuiltin_va_list _ | TFun _ | TVoid _ -> ExistsTrue
9681
| TEnum _ |TFloat _ | TInt _ -> ExistsFalse)
9685
exception Got of string list
9686
let exists_attribute_deep f typ =
9687
let tbl = Hashtbl.create 7 in
9688
let rec visitor l = object
9689
inherit nopCilVisitor
9691
if f a then raise (Got l);
9695
match unrollType t with
9696
| TComp (compinfo,_) ->
9697
(try Hashtbl.find tbl compinfo.ckey
9699
Hashtbl.add tbl compinfo.ckey () ;
9701
(fun finfo -> ignore (visitCilType (visitor (finfo.fname::l)) finfo.ftype))
9709
ignore (visitCilType (visitor []) typ);
9711
with Got l -> Some (List.rev l)
9714
match ca.annot_content with
9715
| AAssert (_,_,status) -> status
9716
| _ -> {status=Unknown}
9720
compile-command: "LC_ALL=C make -C ../.. -j"