summaryrefslogtreecommitdiff
path: root/backend/Unusedglob.ml
blob: 1a88ee9603026c6a449003620bcffd7dbd0b5019 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
(* *********************************************************************)
(*                                                                     *)
(*              The Compcert verified compiler                         *)
(*                                                                     *)
(*          Xavier Leroy, INRIA Paris-Rocquencourt                     *)
(*                                                                     *)
(*  Copyright Institut National de Recherche en Informatique et en     *)
(*  Automatique.  All rights reserved.  This file is distributed       *)
(*  under the terms of the INRIA Non-Commercial License Agreement.     *)
(*                                                                     *)
(* *********************************************************************)

(* Removing unused definitions of static functions and global variables *)

open Camlcoq
open Maps
open AST
open Asm
open Unusedglob1

module IdentSet = Set.Make(struct type t = ident let compare = compare end)

(* The set of globals referenced from a function definition *)

let add_referenced_instr rf i =
  List.fold_right IdentSet.add (referenced_instr i) rf

let referenced_function f =
  List.fold_left add_referenced_instr IdentSet.empty (code_of_function f)

(* The set of globals referenced from a variable definition (initialization) *)

let add_referenced_init_data rf = function
  | Init_addrof(id, ofs) -> IdentSet.add id rf
  | _ -> rf

let referenced_globvar gv =
  List.fold_left add_referenced_init_data IdentSet.empty gv.gvar_init

(* The map global |-> set of globals it references *)

let referenced_globdef gd =
  match gd with
  | Gfun(Internal f) -> referenced_function f
  | Gfun(External ef) -> IdentSet.empty
  | Gvar gv -> referenced_globvar gv

let use_map p =
  List.fold_left (fun m (id, gd) -> PTree.set id (referenced_globdef gd) m)
    PTree.empty p.prog_defs

(* Worklist algorithm computing the set of used globals *)

let rec used_idents usemap used wrk =
  match wrk with
  | [] -> used
  | id :: wrk ->
      if IdentSet.mem id used then used_idents usemap used wrk else
        match PTree.get id usemap with
        | None -> used_idents usemap used wrk
        | Some s -> used_idents usemap (IdentSet.add id used)
                                       (IdentSet.fold (fun id l -> id::l) s wrk)

(* The worklist is initially populated with all nonstatic globals *)

let add_nonstatic wrk id =
  if C2C.atom_is_static id then wrk else id :: wrk

let initial_worklist p =
  List.fold_left (fun wrk (id, gd) -> add_nonstatic wrk id)
    [] p.prog_defs

(* Eliminate unused definitions *)

let rec filter used = function
  | [] -> []
  | (id, def) :: rem ->
      if IdentSet.mem id used
      then (id, def) :: filter used rem
      else filter used rem

let filter_prog used p =
  { prog_defs = filter used p.prog_defs;
    prog_main = p.prog_main }

(* Entry point *)

let transf_program p =
  filter_prog (used_idents (use_map p) IdentSet.empty (initial_worklist p)) p