1 (***********************************************************************)
5 (* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
7 (* Copyright 1996 Institut National de Recherche en Informatique et *)
8 (* en Automatique. All rights reserved. This file is distributed *)
9 (* under the terms of the Q Public License version 1.0. *)
11 (***********************************************************************)
13 (* $Id: emitaux.ml 9314 2009-07-15 12:14:39Z xleroy $ *)
15 (* Common functions for emitting assembly code *)
22 let output_channel = ref stdout
24 let emit_string s = output_string !output_channel s
26 let emit_int n = output_string !output_channel (string_of_int n)
28 let emit_char c = output_char !output_channel c
30 let emit_nativeint n = output_string !output_channel (Nativeint.to_string n)
33 Printf.fprintf !output_channel fmt
35 let emit_int32 n = emit_printf "0x%lx" n
37 let emit_symbol esc s =
38 for i = 0 to String.length s - 1 do
41 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' ->
42 output_char !output_channel c
44 Printf.fprintf !output_channel "%c%02x" esc (Char.code c)
47 let emit_string_literal s =
48 let last_was_escape = ref false in
50 for i = 0 to String.length s - 1 do
52 if c >= '0' && c <= '9' then
54 then Printf.fprintf !output_channel "\\%o" (Char.code c)
55 else output_char !output_channel c
56 else if c >= ' ' && c <= '~' && c <> '"' (* '"' *) && c <> '\\' then begin
57 output_char !output_channel c;
58 last_was_escape := false
60 Printf.fprintf !output_channel "\\%o" (Char.code c);
61 last_was_escape := true
66 let emit_string_directive directive s =
67 let l = String.length s in
69 else if l < 80 then begin
70 emit_string directive;
71 emit_string_literal s;
76 let n = min (l - !i) 80 in
77 emit_string directive;
78 emit_string_literal (String.sub s !i n);
84 let emit_bytes_directive directive s =
86 for i = 0 to String.length s - 1 do
88 then emit_string directive
90 emit_int(Char.code s.[i]);
92 if !pos >= 16 then begin emit_char '\n'; pos := 0 end
94 if !pos > 0 then emit_char '\n'
96 (* PR#4813: assemblers do strange things with float literals indeed,
97 so we convert to IEEE representation ourselves and emit float
98 literals as 32- or 64-bit integers. *)
100 let emit_float64_directive directive f =
101 let x = Int64.bits_of_float (float_of_string f) in
102 emit_printf "\t%s\t0x%Lx\n" directive x
104 let emit_float64_split_directive directive f =
105 let x = Int64.bits_of_float (float_of_string f) in
106 let lo = Int64.logand x 0xFFFF_FFFFL
107 and hi = Int64.shift_right_logical x 32 in
108 emit_printf "\t%s\t0x%Lx, 0x%Lx\n"
110 (if Arch.big_endian then hi else lo)
111 (if Arch.big_endian then lo else hi)
113 let emit_float32_directive directive f =
114 let x = Int32.bits_of_float (float_of_string f) in
115 emit_printf "\t%s\t0x%lx\n" directive x
117 (* Record live pointers at call points *)
120 { fd_lbl: int; (* Return address *)
121 fd_frame_size: int; (* Size of stack frame *)
122 fd_live_offset: int list; (* Offsets/regs of live addresses *)
123 fd_debuginfo: Debuginfo.t } (* Location, if any *)
125 let frame_descriptors = ref([] : frame_descr list)
127 type emit_frame_actions =
128 { efa_label: int -> unit;
130 efa_32: int32 -> unit;
131 efa_word: int -> unit;
132 efa_align: int -> unit;
133 efa_label_rel: int -> int32 -> unit;
134 efa_def_label: int -> unit;
135 efa_string: string -> unit }
138 let filenames = Hashtbl.create 7 in
139 let lbl_filenames = ref 200000 in
140 let label_filename name =
142 Hashtbl.find filenames name
144 let lbl = !lbl_filenames in
145 Hashtbl.add filenames name lbl;
149 a.efa_label fd.fd_lbl;
150 a.efa_16 (if fd.fd_debuginfo == Debuginfo.none
151 then fd.fd_frame_size
152 else fd.fd_frame_size + 1);
153 a.efa_16 (List.length fd.fd_live_offset);
154 List.iter a.efa_16 fd.fd_live_offset;
155 a.efa_align Arch.size_addr;
156 if fd.fd_debuginfo != Debuginfo.none then begin
157 let d = fd.fd_debuginfo in
158 let line = min 0xFFFFF d.dinfo_line
159 and char_start = min 0xFF d.dinfo_char_start
160 and char_end = min 0x3FF d.dinfo_char_end
161 and kind = match d.dinfo_kind with Dinfo_call -> 0 | Dinfo_raise -> 1 in
163 Int64.add (Int64.shift_left (Int64.of_int line) 44) (
164 Int64.add (Int64.shift_left (Int64.of_int char_start) 36) (
165 Int64.add (Int64.shift_left (Int64.of_int char_end) 26)
166 (Int64.of_int kind))) in
168 (label_filename d.dinfo_file)
169 (Int64.to_int32 info);
170 a.efa_32 (Int64.to_int32 (Int64.shift_right info 32))
172 let emit_filename name lbl =
175 a.efa_align Arch.size_addr in
176 a.efa_word (List.length !frame_descriptors);
177 List.iter emit_frame !frame_descriptors;
178 Hashtbl.iter emit_filename filenames;
179 frame_descriptors := []
181 (* Detection of functions that can be duplicated between a DLL and
182 the main program (PR#4690) *)
185 String.length s1 <= String.length s2
186 && String.sub s2 0 (String.length s1) = s1
188 let is_generic_function name =
190 (fun p -> isprefix p name)
191 ["caml_apply"; "caml_curry"; "caml_send"; "caml_tuplify"]