https://github.com/charguer/ocaml
Tip revision: 4d8a058815162a784551a65edb4bb91397a373f6 authored by Jacques Garrigue on 12 October 2010, 09:37:49 UTC
be principal
be principal
Tip revision: 4d8a058
emitaux.ml
(***********************************************************************)
(* *)
(* Objective Caml *)
(* *)
(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 1996 Institut National de Recherche en Informatique et *)
(* en Automatique. All rights reserved. This file is distributed *)
(* under the terms of the Q Public License version 1.0. *)
(* *)
(***********************************************************************)
(* $Id$ *)
(* Common functions for emitting assembly code *)
open Debuginfo
open Cmm
open Reg
open Linearize
let output_channel = ref stdout
let emit_string s = output_string !output_channel s
let emit_int n = output_string !output_channel (string_of_int n)
let emit_char c = output_char !output_channel c
let emit_nativeint n = output_string !output_channel (Nativeint.to_string n)
let emit_printf fmt =
Printf.fprintf !output_channel fmt
let emit_int32 n = emit_printf "0x%lx" n
let emit_symbol esc s =
for i = 0 to String.length s - 1 do
let c = s.[i] in
match c with
'A'..'Z' | 'a'..'z' | '0'..'9' | '_' ->
output_char !output_channel c
| _ ->
Printf.fprintf !output_channel "%c%02x" esc (Char.code c)
done
let emit_string_literal s =
let last_was_escape = ref false in
emit_string "\"";
for i = 0 to String.length s - 1 do
let c = s.[i] in
if c >= '0' && c <= '9' then
if !last_was_escape
then Printf.fprintf !output_channel "\\%o" (Char.code c)
else output_char !output_channel c
else if c >= ' ' && c <= '~' && c <> '"' (* '"' *) && c <> '\\' then begin
output_char !output_channel c;
last_was_escape := false
end else begin
Printf.fprintf !output_channel "\\%o" (Char.code c);
last_was_escape := true
end
done;
emit_string "\""
let emit_string_directive directive s =
let l = String.length s in
if l = 0 then ()
else if l < 80 then begin
emit_string directive;
emit_string_literal s;
emit_char '\n'
end else begin
let i = ref 0 in
while !i < l do
let n = min (l - !i) 80 in
emit_string directive;
emit_string_literal (String.sub s !i n);
emit_char '\n';
i := !i + n
done
end
let emit_bytes_directive directive s =
let pos = ref 0 in
for i = 0 to String.length s - 1 do
if !pos = 0
then emit_string directive
else emit_char ',';
emit_int(Char.code s.[i]);
incr pos;
if !pos >= 16 then begin emit_char '\n'; pos := 0 end
done;
if !pos > 0 then emit_char '\n'
(* PR#4813: assemblers do strange things with float literals indeed,
so we convert to IEEE representation ourselves and emit float
literals as 32- or 64-bit integers. *)
let emit_float64_directive directive f =
let x = Int64.bits_of_float (float_of_string f) in
emit_printf "\t%s\t0x%Lx\n" directive x
let emit_float64_split_directive directive f =
let x = Int64.bits_of_float (float_of_string f) in
let lo = Int64.logand x 0xFFFF_FFFFL
and hi = Int64.shift_right_logical x 32 in
emit_printf "\t%s\t0x%Lx, 0x%Lx\n"
directive
(if Arch.big_endian then hi else lo)
(if Arch.big_endian then lo else hi)
let emit_float32_directive directive f =
let x = Int32.bits_of_float (float_of_string f) in
emit_printf "\t%s\t0x%lx\n" directive x
(* Record live pointers at call points *)
type frame_descr =
{ fd_lbl: int; (* Return address *)
fd_frame_size: int; (* Size of stack frame *)
fd_live_offset: int list; (* Offsets/regs of live addresses *)
fd_debuginfo: Debuginfo.t } (* Location, if any *)
let frame_descriptors = ref([] : frame_descr list)
type emit_frame_actions =
{ efa_label: int -> unit;
efa_16: int -> unit;
efa_32: int32 -> unit;
efa_word: int -> unit;
efa_align: int -> unit;
efa_label_rel: int -> int32 -> unit;
efa_def_label: int -> unit;
efa_string: string -> unit }
let emit_frames a =
let filenames = Hashtbl.create 7 in
let lbl_filenames = ref 200000 in
let label_filename name =
try
Hashtbl.find filenames name
with Not_found ->
let lbl = !lbl_filenames in
Hashtbl.add filenames name lbl;
incr lbl_filenames;
lbl in
let emit_frame fd =
a.efa_label fd.fd_lbl;
a.efa_16 (if fd.fd_debuginfo == Debuginfo.none
then fd.fd_frame_size
else fd.fd_frame_size + 1);
a.efa_16 (List.length fd.fd_live_offset);
List.iter a.efa_16 fd.fd_live_offset;
a.efa_align Arch.size_addr;
if fd.fd_debuginfo != Debuginfo.none then begin
let d = fd.fd_debuginfo in
let line = min 0xFFFFF d.dinfo_line
and char_start = min 0xFF d.dinfo_char_start
and char_end = min 0x3FF d.dinfo_char_end
and kind = match d.dinfo_kind with Dinfo_call -> 0 | Dinfo_raise -> 1 in
let info =
Int64.add (Int64.shift_left (Int64.of_int line) 44) (
Int64.add (Int64.shift_left (Int64.of_int char_start) 36) (
Int64.add (Int64.shift_left (Int64.of_int char_end) 26)
(Int64.of_int kind))) in
a.efa_label_rel
(label_filename d.dinfo_file)
(Int64.to_int32 info);
a.efa_32 (Int64.to_int32 (Int64.shift_right info 32))
end in
let emit_filename name lbl =
a.efa_def_label lbl;
a.efa_string name;
a.efa_align Arch.size_addr in
a.efa_word (List.length !frame_descriptors);
List.iter emit_frame !frame_descriptors;
Hashtbl.iter emit_filename filenames;
frame_descriptors := []
(* Detection of functions that can be duplicated between a DLL and
the main program (PR#4690) *)
let isprefix s1 s2 =
String.length s1 <= String.length s2
&& String.sub s2 0 (String.length s1) = s1
let is_generic_function name =
List.exists
(fun p -> isprefix p name)
["caml_apply"; "caml_curry"; "caml_send"; "caml_tuplify"]