summaryrefslogtreecommitdiff
path: root/powerpc/eabi/CPragmas.ml
blob: 3104cc886f96e9d52635c1493e49641dcc135105 (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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
(* *********************************************************************)
(*                                                                     *)
(*              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 GNU General Public License as published by  *)
(*  the Free Software Foundation, either version 2 of the License, or  *)
(*  (at your option) any later version.  This file is also distributed *)
(*  under the terms of the INRIA Non-Commercial License Agreement.     *)
(*                                                                     *)
(* *********************************************************************)

(* Platform-dependent handling of pragmas *)

open Printf
open Camlcoq
open Cparser

type section_info = {
  sec_name_init: string;
  sec_name_uninit: string;
  sec_acc_mode: string;
  sec_near_access: bool
}

let default_section_info = {
  sec_name_init = ".data";
  sec_name_uninit = ".data"; (* COMM? *)
  sec_acc_mode = "RW";
  sec_near_access = false
}

let section_table : (string, section_info) Hashtbl.t =
  Hashtbl.create 17

(* Built-in sections *)

let _ =
  let rodata =
    if Configuration.system = "linux" then ".rodata" else ".text" in
  List.iter (fun (n, si) -> Hashtbl.add section_table n si) [
     "CODE",  {sec_name_init = ".text";
               sec_name_uninit = ".text";
               sec_acc_mode = "RX";
               sec_near_access = false};
     "DATA",  {sec_name_init = ".data";
               sec_name_uninit = ".data"; (* COMM? *)
               sec_acc_mode = "RW";
               sec_near_access = false};
     "SDATA", {sec_name_init = ".sdata";
               sec_name_uninit = ".sbss";
               sec_acc_mode = "RW";
               sec_near_access = true};
     "CONST", {sec_name_init = rodata;
               sec_name_uninit = rodata;
               sec_acc_mode = "R";
               sec_near_access = false};
     "SCONST",{sec_name_init = ".sdata2";
               sec_name_uninit = ".sdata2";
               sec_acc_mode = "R";
               sec_near_access = true};
     "STRING",{sec_name_init = rodata;
               sec_name_uninit = rodata;
               sec_acc_mode = "R";
               sec_near_access = false}
  ]

(* #pragma section *)

let process_section_pragma classname istring ustring addrmode accmode =
  let old_si =
    try Hashtbl.find section_table classname
    with Not_found -> default_section_info in
  let si =
    { sec_name_init =
        if istring = "" then old_si.sec_name_init else istring;
      sec_name_uninit =
        if ustring = "" then old_si.sec_name_uninit else ustring;
      sec_acc_mode =
        if accmode = "" then old_si.sec_acc_mode else accmode;
      sec_near_access =
        if addrmode = ""
        then old_si.sec_near_access
        else (addrmode = "near-code") || (addrmode = "near-data") } in
  Hashtbl.add section_table classname si

(* #pragma use_section *)

let use_section_table : (AST.ident, section_info) Hashtbl.t =
  Hashtbl.create 51

let process_use_section_pragma classname id =
  try
    let info = Hashtbl.find section_table classname in
    Hashtbl.add use_section_table (intern_string id) info
  with Not_found ->
    C2Clight.error (sprintf "unknown section name `%s'" classname)

let default_use_section id classname =
  if not (Hashtbl.mem use_section_table id) then begin
    let info =
      try Hashtbl.find section_table classname
      with Not_found -> assert false in
    Hashtbl.add use_section_table id info
  end

let define_function id d =
  default_use_section id "CODE"

let define_stringlit id =
  default_use_section id "STRING"

let define_variable id d =
  let is_small limit =
    match C2Clight.atom_sizeof id with
    | None -> false
    | Some sz -> sz <= limit in
  let sect =
    if C2Clight.atom_is_readonly id then
      if is_small !Clflags.option_small_const then "SCONST" else "CONST"
    else
      if is_small !Clflags.option_small_data then "SDATA" else "DATA" in
  default_use_section id sect

(* #pragma reserve_register *)

let process_reserve_register_pragma name =
  match Machregsaux.register_by_name name with
  | None ->
      C2Clight.error "unknown register in `reserve_register' pragma"
  | Some r ->
      if Machregsaux.can_reserve_register r then
        Coloringaux.reserved_registers :=
          r :: !Coloringaux.reserved_registers
      else
        C2Clight.error "cannot reserve this register (not a callee-save)"

(* Parsing of pragmas using regexps *)

let re_start_pragma_section = Str.regexp "section\\b"

let re_pragma_section = Str.regexp(
  "section[ \t]+"
^ "\\([A-Za-z_][A-Za-z_0-9]*\\)[ \t]+"  (* class_name *)
^ "\\(\"[^\"]*\"\\)?[ \t]*"             (* istring *)
^ "\\(\"[^\"]*\"\\)?[ \t]*"             (* ustring *)
^ "\\(standard\\|near-absolute\\|far-absolute\\|near-data\\|far-data\\|near-code\\|far-code\\)?[ \t]*"                  (* addressing mode *)
^ "\\([RWXON]*\\)"                      (* access mode *)
)

let re_start_pragma_use_section = Str.regexp "use_section\\b"

let re_pragma_use_section = Str.regexp
  "use_section[ \t]+\
   \\([A-Za-z_][A-Za-z_0-9]*\\)[ \t]+\
   \\(.*\\)$"

let re_split_idents = Str.regexp "[ \t,]+"

let re_start_pragma_reserve_register = Str.regexp "reserve_register\\b"

let re_pragma_reserve_register = Str.regexp
  "reserve_register[ \t]+\\([A-Za-z0-9]+\\)"

let process_pragma name =
  if Str.string_match re_pragma_section name 0 then begin
    process_section_pragma
      (Str.matched_group 1 name) (* classname *)
      (Str.matched_group 2 name) (* istring *)
      (Str.matched_group 3 name) (* ustring *)
      (Str.matched_group 4 name) (* addrmode *)
      (Str.matched_group 5 name); (* accmode *)
    true
  end else if Str.string_match re_start_pragma_section name 0 then
    (C2Clight.error "ill-formed `section' pragma"; true)
 else if Str.string_match re_pragma_use_section name 0 then begin
    let classname = Str.matched_group 1 name
    and idents = Str.matched_group 2 name in
    let identlist = Str.split re_split_idents idents in
    if identlist = [] then C2Clight.warning "vacuous `use_section' pragma";
    List.iter (process_use_section_pragma classname) identlist;
    true
  end else if Str.string_match re_start_pragma_use_section name 0 then begin
    C2Clight.error "ill-formed `use_section' pragma"; true
  end else if Str.string_match re_pragma_reserve_register name 0 then begin
    process_reserve_register_pragma (Str.matched_group 1 name); true
  end else if Str.string_match re_start_pragma_reserve_register name 0 then begin
    C2Clight.error "ill-formed `reserve_register' pragma"; true
  end else
    false

let initialize () =
  C2Clight.process_pragma_hook := process_pragma;
  C2Clight.define_variable_hook := define_variable;
  C2Clight.define_function_hook := define_function;
  C2Clight.define_stringlit_hook := define_stringlit

(* PowerPC-specific: say if an atom is in a small data area *)

let atom_is_small_data a ofs =
  match C2Clight.atom_sizeof a with
  | None -> false
  | Some sz ->
      let ofs = camlint_of_coqint ofs in
      if ofs >= 0l && ofs < Int32.of_int sz then begin
        try
          (Hashtbl.find use_section_table a).sec_near_access
        with Not_found ->
          if C2Clight.atom_is_readonly a
          then sz <= !Clflags.option_small_const
          else sz <= !Clflags.option_small_data
      end else
        false

(* PowerPC-specific: determine section to use for a particular symbol *)

let section_for_atom a init =
  try
    let sinfo = Hashtbl.find use_section_table a in
    let sname =
      if init then sinfo.sec_name_init else sinfo.sec_name_uninit in
    if not (String.contains sname '\"') then
      Some sname
    else begin
      (* The following is Diab-specific... *)
      let accmode = sinfo.sec_acc_mode in
      let is_writable = String.contains accmode 'W'
      and is_executable = String.contains accmode 'X' in
      let stype =
        match is_writable, is_executable with
        | true, true -> 'm'                 (* text+data *)
        | true, false -> 'd'                (* data *)
        | false, true -> 'c'                (* text *)
        | false, false -> 'r'               (* const *)
      in Some(sprintf ".section\t%s,,%c" sname stype)
    end
  with Not_found -> None