aboutsummaryrefslogtreecommitdiffstats
path: root/backend/Asmexpandaux.ml
blob: 5c3ac381382aeeaec3d0495912e2c1798d8d765b (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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
(* *********************************************************************)
(*                                                                     *)
(*              The Compcert verified compiler                         *)
(*                                                                     *)
(*          Xavier Leroy, INRIA Paris-Rocquencourt                     *)
(*          Bernhard Schommer, AbsInt Angewandte Informatik GmbH       *)
(*                                                                     *)
(*  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.     *)
(*                                                                     *)
(* *********************************************************************)

(* Util functions used for the expansion of built-ins and some 
   pseudo-instructions *)

open Asm
open AST
open Camlcoq
       
(* Buffering the expanded code *)

let current_code = ref ([]: instruction list)

let emit i = current_code := i :: !current_code

(* Generation of fresh labels *)
							  
let dummy_function = { fn_code = []; fn_sig = signature_main }
let current_function = ref dummy_function
let next_label = ref (None: label option)

let new_label () =
  let lbl =
    match !next_label with
    | Some l -> l
    | None ->
        (* on-demand computation of the next available label *)
        List.fold_left
          (fun next instr ->
            match instr with
            | Plabel l -> if P.lt l next then next else P.succ l
            | _ -> next)
          P.one (!current_function).fn_code
  in
    next_label := Some (P.succ lbl);
    lbl

		     
let set_current_function f =
  current_function := f; next_label := None; current_code := []

let get_current_function () =
  let c = List.rev !current_code in
  let fn = !current_function in
  set_current_function dummy_function;
  {fn with fn_code = c}

(* Expand function for debug information *)

let expand_scope id lbl oldscopes newscopes =
  let opening = List.filter (fun a -> not (List.mem a oldscopes)) newscopes
  and closing = List.filter (fun a -> not (List.mem a newscopes)) oldscopes in
  List.iter (fun i -> Debug.open_scope id i lbl) opening;
  List.iter (fun i -> Debug.close_scope id i lbl) closing
    

let expand_debug id annot simple l =
  let get_lbl = function
    | None -> 
        let lbl = new_label () in
        emit (Plabel lbl);
        lbl
    | Some lbl -> lbl in
  let rec  aux lbl scopes = function
    | [] -> let lbl = get_lbl lbl in
      Debug.function_end id lbl
    | (Pbuiltin(EF_debug (kind,txt,_x),args,_) as i)::rest ->
        let kind = (P.to_int kind) in
        begin
          match kind with
          | 1-> 
              emit i;aux lbl scopes rest
          | 2 ->
              aux  lbl scopes rest
          | 3 ->
             begin 
               match annot args with
               | Some a ->
                   let lbl = get_lbl lbl in
                   Debug.start_live_range (id,txt) lbl a;
                   aux (Some lbl) scopes rest
               | None ->  aux lbl scopes rest
             end
          | 4 ->
              let lbl = get_lbl lbl in
              Debug.end_live_range (id,txt) lbl;
              aux (Some lbl) scopes rest
          | 5 ->
              begin
                match annot args with
                | Some a->
                    Debug.stack_variable (id,txt) a;
                    aux lbl scopes rest
                | _ ->  aux lbl scopes rest
              end
          | 6  ->
              let lbl = get_lbl lbl in
              let scopes' = List.map (function BA_int x -> Int32.to_int (camlint_of_coqint x) | _ -> assert false) args in
              expand_scope id lbl scopes scopes';
              aux (Some lbl) scopes' rest
          | _ ->
              aux None scopes rest
        end
    | i::rest -> simple i; aux None scopes rest in
  (* We need to move all closing debug annotations before the last real statement *)
  let rec move_debug acc bcc = function
    | (Pbuiltin(EF_debug (kind,_,_),_,_) as i)::rest ->
        let kind = (P.to_int kind) in
        if kind = 1 then
          move_debug acc (i::bcc) rest (* Do not move debug line *)
        else
          move_debug (i::acc) bcc rest (* Move the debug annotations forward *)
    | b::rest -> List.rev ((List.rev (b::bcc)@List.rev acc)@rest) (* We found the first non debug location *)
    | [] -> List.rev acc (* This actually can never happen *) in
  aux None [] (move_debug [] [] (List.rev l))