--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/components/ocaml/patches/ocaml-3.11.0-ppc64.patch Wed Aug 21 14:33:32 2013 -0700
@@ -0,0 +1,2089 @@
+
+Patch from Fedora spec-file to add powerpc support. This patch was rejected by
+upstream. This may not be needed on Solaris, but keeping it for consistency
+with the RHEL package.
+https://sympa.inria.fr/sympa/arc/caml-list/2007-10/msg00502.html
+
+diff -uNr ocaml-3.10.1/asmcomp/power64/arch.ml ocaml-3.10.1.ppc64/asmcomp/power64/arch.ml
+--- ocaml-3.10.1/asmcomp/power64/arch.ml 1969-12-31 19:00:00.000000000 -0500
++++ ocaml-3.10.1.ppc64/asmcomp/power64/arch.ml 2008-02-29 08:37:45.000000000 -0500
+@@ -0,0 +1,84 @@
++(***********************************************************************)
++(* *)
++(* 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: arch.ml,v 1.11 2004/06/19 16:13:32 xleroy Exp $ *)
++
++(* Specific operations for the PowerPC processor *)
++
++open Misc
++open Format
++
++(* Machine-specific command-line options *)
++
++let command_line_options = []
++
++(* Specific operations *)
++
++type specific_operation =
++ Imultaddf (* multiply and add *)
++ | Imultsubf (* multiply and subtract *)
++ | Ialloc_far of int (* allocation in large functions *)
++
++(* Addressing modes *)
++
++type addressing_mode =
++ Ibased of string * int (* symbol + displ *)
++ | Iindexed of int (* reg + displ *)
++ | Iindexed2 (* reg + reg *)
++
++(* Sizes, endianness *)
++
++let big_endian = true
++
++let size_addr = 8
++let size_int = 8
++let size_float = 8
++
++(* Operations on addressing modes *)
++
++let identity_addressing = Iindexed 0
++
++let offset_addressing addr delta =
++ match addr with
++ Ibased(s, n) -> Ibased(s, n + delta)
++ | Iindexed n -> Iindexed(n + delta)
++ | Iindexed2 -> assert false
++
++let num_args_addressing = function
++ Ibased(s, n) -> 0
++ | Iindexed n -> 1
++ | Iindexed2 -> 2
++
++(* Printing operations and addressing modes *)
++
++let print_addressing printreg addr ppf arg =
++ match addr with
++ | Ibased(s, n) ->
++ let idx = if n <> 0 then Printf.sprintf " + %i" n else "" in
++ fprintf ppf "\"%s\"%s" s idx
++ | Iindexed n ->
++ let idx = if n <> 0 then Printf.sprintf " + %i" n else "" in
++ fprintf ppf "%a%s" printreg arg.(0) idx
++ | Iindexed2 ->
++ fprintf ppf "%a + %a" printreg arg.(0) printreg arg.(1)
++
++let print_specific_operation printreg op ppf arg =
++ match op with
++ | Imultaddf ->
++ fprintf ppf "%a *f %a +f %a"
++ printreg arg.(0) printreg arg.(1) printreg arg.(2)
++ | Imultsubf ->
++ fprintf ppf "%a *f %a -f %a"
++ printreg arg.(0) printreg arg.(1) printreg arg.(2)
++ | Ialloc_far n ->
++ fprintf ppf "alloc_far %d" n
++
+diff -uNr ocaml-3.10.1/asmcomp/power64/emit.mlp ocaml-3.10.1.ppc64/asmcomp/power64/emit.mlp
+--- ocaml-3.10.1/asmcomp/power64/emit.mlp 1969-12-31 19:00:00.000000000 -0500
++++ ocaml-3.10.1.ppc64/asmcomp/power64/emit.mlp 2008-02-29 08:37:45.000000000 -0500
+@@ -0,0 +1,989 @@
++(***********************************************************************)
++(* *)
++(* 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: emit.mlp,v 1.21 2004/06/19 17:39:34 xleroy Exp $ *)
++
++(* Emission of PowerPC assembly code *)
++
++module StringSet = Set.Make(struct type t = string let compare = compare end)
++
++open Location
++open Misc
++open Cmm
++open Arch
++open Proc
++open Reg
++open Mach
++open Linearize
++open Emitaux
++
++(* Layout of the stack. The stack is kept 16-aligned. *)
++
++let stack_size_lbl = ref 0
++let stack_slot_lbl = ref 0
++let stack_args_size = ref 0
++let stack_traps_size = ref 0
++
++(* We have a stack frame of our own if we call other functions (including
++ use of exceptions, or if we need more than the red zone *)
++let has_stack_frame () =
++ if !contains_calls or (num_stack_slots.(0) + num_stack_slots.(1)) > (288-16)/8 then
++ true
++ else
++ false
++
++let frame_size_sans_args () =
++ let size = 8 * num_stack_slots.(0) + 8 * num_stack_slots.(1) + 48 in
++ Misc.align size 16
++
++let slot_offset loc cls =
++ match loc with
++ Local n ->
++ if cls = 0
++ then (!stack_slot_lbl, num_stack_slots.(1) * 8 + n * 8)
++ else (!stack_slot_lbl, n * 8)
++ | Incoming n -> ((if has_stack_frame() then !stack_size_lbl else 0), 48 + n)
++ | Outgoing n -> (0, n)
++
++(* Output a symbol *)
++
++let emit_symbol =
++ match Config.system with
++ | "elf" | "bsd" -> (fun s -> Emitaux.emit_symbol '.' s)
++ | "rhapsody" -> (fun s -> emit_char '_'; Emitaux.emit_symbol '$' s)
++ | _ -> assert false
++
++(* Output a label *)
++
++let label_prefix =
++ match Config.system with
++ | "elf" | "bsd" -> ".L"
++ | "rhapsody" -> "L"
++ | _ -> assert false
++
++let emit_label lbl =
++ emit_string label_prefix; emit_int lbl
++
++(* Section switching *)
++
++let toc_space =
++ match Config.system with
++ | "elf" | "bsd" -> " .section \".toc\",\"aw\"\n"
++ | "rhapsody" -> " .toc\n"
++ | _ -> assert false
++
++let data_space =
++ match Config.system with
++ | "elf" | "bsd" -> " .section \".data\"\n"
++ | "rhapsody" -> " .data\n"
++ | _ -> assert false
++
++let code_space =
++ match Config.system with
++ | "elf" | "bsd" -> " .section \".text\"\n"
++ | "rhapsody" -> " .text\n"
++ | _ -> assert false
++
++let rodata_space =
++ match Config.system with
++ | "elf" | "bsd" -> " .section \".rodata\"\n"
++ | "rhapsody" -> " .const\n"
++ | _ -> assert false
++
++(* Output a pseudo-register *)
++
++let emit_reg r =
++ match r.loc with
++ Reg r -> emit_string (register_name r)
++ | _ -> fatal_error "Emit.emit_reg"
++
++let use_full_regnames =
++ Config.system = "rhapsody"
++
++let emit_gpr r =
++ if use_full_regnames then emit_char 'r';
++ emit_int r
++
++let emit_fpr r =
++ if use_full_regnames then emit_char 'f';
++ emit_int r
++
++let emit_ccr r =
++ if use_full_regnames then emit_string "cr";
++ emit_int r
++
++(* Output a stack reference *)
++
++let emit_stack r =
++ match r.loc with
++ Stack s ->
++ let lbl, ofs = slot_offset s (register_class r) in
++ if lbl > 0 then
++ `{emit_label lbl}+`;
++ `{emit_int ofs}({emit_gpr 1})`
++ | _ -> fatal_error "Emit.emit_stack"
++
++(* Split a 32-bit integer constants in two 16-bit halves *)
++
++let low n = n land 0xFFFF
++let high n = n asr 16
++
++let nativelow n = Nativeint.to_int n land 0xFFFF
++let nativehigh n = Nativeint.to_int (Nativeint.shift_right n 16)
++
++let is_immediate n =
++ n <= 32767 && n >= -32768
++
++let is_native_immediate n =
++ n <= 32767n && n >= -32768n
++
++
++type tocentry =
++ TocSymOfs of (string * int)
++ | TocLabel of int
++ | TocInt of nativeint
++ | TocFloat of string
++
++(* List of all labels in tocref (reverse order) *)
++let tocref_entries = ref []
++
++(* Output a TOC reference *)
++
++let emit_symbol_offset (s, d) =
++ emit_symbol s;
++ if d > 0 then `+`;
++ if d <> 0 then emit_int d
++
++let emit_tocentry entry =
++ match entry with
++ TocSymOfs(s,d) -> emit_symbol_offset(s,d)
++ | TocInt i -> emit_nativeint i
++ | TocFloat f -> emit_string f
++ | TocLabel lbl -> emit_label lbl
++
++ let rec tocref_label = function
++ ( [] , content ) ->
++ let lbl = new_label() in
++ tocref_entries := (lbl, content) :: !tocref_entries;
++ lbl
++ | ( (lbl, o_content) :: lst, content) ->
++ if content = o_content then
++ lbl
++ else
++ tocref_label (lst, content)
++
++let emit_tocref entry =
++ let lbl = tocref_label (!tocref_entries,entry) in
++ emit_label lbl; emit_string "@toc(2) #"; emit_tocentry entry
++
++
++(* Output a load or store operation *)
++
++let valid_offset instr ofs =
++ ofs land 3 = 0 || (instr <> "ld" && instr <> "std")
++
++let emit_load_store instr addressing_mode addr n arg =
++ match addressing_mode with
++ Ibased(s, d) ->
++ let dd = (d + 0x8000) in (* We can only offset by -0x8000 .. +0x7fff *)
++ let a = (dd land -0x10000) in
++ let b = (dd land 0xffff) - 0x8000 in
++ ` ld {emit_gpr 11}, {emit_tocref (TocSymOfs (s,a))}\n`;
++ ` {emit_string instr} {emit_reg arg}, {emit_int b}({emit_gpr 11})\n`
++ | Iindexed ofs ->
++ if is_immediate ofs && valid_offset instr ofs then
++ ` {emit_string instr} {emit_reg arg}, {emit_int ofs}({emit_reg addr.(n)})\n`
++ else begin
++ ` lis {emit_gpr 0}, {emit_int(high ofs)}\n`;
++ if low ofs <> 0 then
++ ` ori {emit_gpr 0}, {emit_gpr 0}, {emit_int(low ofs)}\n`;
++ ` {emit_string instr}x {emit_reg arg}, {emit_reg addr.(n)}, {emit_gpr 0}\n`
++ end
++ | Iindexed2 ->
++ ` {emit_string instr}x {emit_reg arg}, {emit_reg addr.(n)}, {emit_reg addr.(n+1)}\n`
++
++(* After a comparison, extract the result as 0 or 1 *)
++
++let emit_set_comp cmp res =
++ ` mfcr {emit_gpr 0}\n`;
++ let bitnum =
++ match cmp with
++ Ceq | Cne -> 2
++ | Cgt | Cle -> 1
++ | Clt | Cge -> 0 in
++` rlwinm {emit_reg res}, {emit_gpr 0}, {emit_int(bitnum+1)}, 31, 31\n`;
++ begin match cmp with
++ Cne | Cle | Cge -> ` xori {emit_reg res}, {emit_reg res}, 1\n`
++ | _ -> ()
++ end
++
++(* Record live pointers at call points *)
++
++type frame_descr =
++ { fd_lbl: int; (* Return address *)
++ fd_frame_size_lbl: int; (* Size of stack frame *)
++ fd_live_offset: (int * int) list } (* Offsets/regs of live addresses *)
++
++let frame_descriptors = ref([] : frame_descr list)
++
++let record_frame live =
++ let lbl = new_label() in
++ let live_offset = ref [] in
++ Reg.Set.iter
++ (function
++ {typ = Addr; loc = Reg r} ->
++ live_offset := (0, (r lsl 1) + 1) :: !live_offset
++ | {typ = Addr; loc = Stack s} as reg ->
++ live_offset := slot_offset s (register_class reg) :: !live_offset
++ | _ -> ())
++ live;
++ frame_descriptors :=
++ { fd_lbl = lbl;
++ fd_frame_size_lbl = !stack_size_lbl; (* frame_size *)
++ fd_live_offset = !live_offset } :: !frame_descriptors;
++ `{emit_label lbl}:\n`
++
++let emit_frame fd =
++ ` .quad {emit_label fd.fd_lbl} + 4\n`;
++ ` .short {emit_label fd.fd_frame_size_lbl}\n`;
++ ` .short {emit_int (List.length fd.fd_live_offset)}\n`;
++ List.iter
++ (fun (lbl,n) ->
++ ` .short `;
++ if lbl > 0 then `{emit_label lbl}+`;
++ `{emit_int n}\n`)
++ fd.fd_live_offset;
++ ` .align 3\n`
++
++(* Record external C functions to be called in a position-independent way
++ (for MacOSX) *)
++
++let pic_externals = (Config.system = "rhapsody")
++
++let external_functions = ref StringSet.empty
++
++let emit_external s =
++ ` .non_lazy_symbol_pointer\n`;
++ `L{emit_symbol s}$non_lazy_ptr:\n`;
++ ` .indirect_symbol {emit_symbol s}\n`;
++ ` .quad 0\n`
++
++(* Names for conditional branches after comparisons *)
++
++let branch_for_comparison = function
++ Ceq -> "beq" | Cne -> "bne"
++ | Cle -> "ble" | Cgt -> "bgt"
++ | Cge -> "bge" | Clt -> "blt"
++
++let name_for_int_comparison = function
++ Isigned cmp -> ("cmpd", branch_for_comparison cmp)
++ | Iunsigned cmp -> ("cmpld", branch_for_comparison cmp)
++
++(* Names for various instructions *)
++
++let name_for_intop = function
++ Iadd -> "add"
++ | Imul -> "mulld"
++ | Idiv -> "divd"
++ | Iand -> "and"
++ | Ior -> "or"
++ | Ixor -> "xor"
++ | Ilsl -> "sld"
++ | Ilsr -> "srd"
++ | Iasr -> "srad"
++ | _ -> Misc.fatal_error "Emit.Intop"
++
++let name_for_intop_imm = function
++ Iadd -> "addi"
++ | Imul -> "mulli"
++ | Iand -> "andi."
++ | Ior -> "ori"
++ | Ixor -> "xori"
++ | Ilsl -> "sldi"
++ | Ilsr -> "srdi"
++ | Iasr -> "sradi"
++ | _ -> Misc.fatal_error "Emit.Intop_imm"
++
++let name_for_floatop1 = function
++ Inegf -> "fneg"
++ | Iabsf -> "fabs"
++ | _ -> Misc.fatal_error "Emit.Iopf1"
++
++let name_for_floatop2 = function
++ Iaddf -> "fadd"
++ | Isubf -> "fsub"
++ | Imulf -> "fmul"
++ | Idivf -> "fdiv"
++ | _ -> Misc.fatal_error "Emit.Iopf2"
++
++let name_for_specific = function
++ Imultaddf -> "fmadd"
++ | Imultsubf -> "fmsub"
++ | _ -> Misc.fatal_error "Emit.Ispecific"
++
++(* Name of current function *)
++let function_name = ref ""
++(* Entry point for tail recursive calls *)
++let tailrec_entry_point = ref 0
++(* Names of functions defined in the current file *)
++let defined_functions = ref StringSet.empty
++(* Label of glue code for calling the GC *)
++let call_gc_label = ref 0
++(* Label of jump table *)
++let lbl_jumptbl = ref 0
++(* List of all labels in jumptable (reverse order) *)
++let jumptbl_entries = ref []
++(* Number of jumptable entries *)
++let num_jumptbl_entries = ref 0
++
++(* Fixup conditional branches that exceed hardware allowed range *)
++
++let load_store_size = function
++ Ibased(s, d) -> 2
++ | Iindexed ofs -> if is_immediate ofs then 1 else 3
++ | Iindexed2 -> 1
++
++let instr_size = function
++ Lend -> 0
++ | Lop(Imove | Ispill | Ireload) -> 1
++ | Lop(Iconst_int n) -> if is_native_immediate n then 1 else 2
++ | Lop(Iconst_float s) -> 2
++ | Lop(Iconst_symbol s) -> 2
++ | Lop(Icall_ind) -> 6
++ | Lop(Icall_imm s) -> 7
++ | Lop(Itailcall_ind) -> if !contains_calls then 7 else if has_stack_frame() then 5 else 4
++ | Lop(Itailcall_imm s) -> if s = !function_name then 1 else
++ if !contains_calls then 8 else
++ if has_stack_frame() then 6 else 5
++ | Lop(Iextcall(s, true)) -> 8
++ | Lop(Iextcall(s, false)) -> 7
++ | Lop(Istackoffset n) -> 0
++ | Lop(Iload(chunk, addr)) ->
++ if chunk = Byte_signed
++ then load_store_size addr + 1
++ else load_store_size addr
++ | Lop(Istore(chunk, addr)) -> load_store_size addr
++ | Lop(Ialloc n) -> 4
++ | Lop(Ispecific(Ialloc_far n)) -> 5
++ | Lop(Iintop Imod) -> 3
++ | Lop(Iintop(Icomp cmp)) -> 4
++ | Lop(Iintop op) -> 1
++ | Lop(Iintop_imm(Idiv, n)) -> 2
++ | Lop(Iintop_imm(Imod, n)) -> 4
++ | Lop(Iintop_imm(Icomp cmp, n)) -> 4
++ | Lop(Iintop_imm(op, n)) -> 1
++ | Lop(Inegf | Iabsf | Iaddf | Isubf | Imulf | Idivf) -> 1
++ | Lop(Ifloatofint) -> 3
++ | Lop(Iintoffloat) -> 3
++ | Lop(Ispecific sop) -> 1
++ | Lreloadretaddr -> 2
++ | Lreturn -> if has_stack_frame() then 2 else 1
++ | Llabel lbl -> 0
++ | Lbranch lbl -> 1
++ | Lcondbranch(tst, lbl) -> 2
++ | Lcondbranch3(lbl0, lbl1, lbl2) ->
++ 1 + (if lbl0 = None then 0 else 1)
++ + (if lbl1 = None then 0 else 1)
++ + (if lbl2 = None then 0 else 1)
++ | Lswitch jumptbl -> 7
++ | Lsetuptrap lbl -> 1
++ | Lpushtrap -> 7
++ | Lpoptrap -> 1
++ | Lraise -> 6
++
++let label_map code =
++ let map = Hashtbl.create 37 in
++ let rec fill_map pc instr =
++ match instr.desc with
++ Lend -> (pc, map)
++ | Llabel lbl -> Hashtbl.add map lbl pc; fill_map pc instr.next
++ | op -> fill_map (pc + instr_size op) instr.next
++ in fill_map 0 code
++
++let max_branch_offset = 8180
++(* 14-bit signed offset in words. Remember to cut some slack
++ for multi-word instructions where the branch can be anywhere in
++ the middle. 12 words of slack is plenty. *)
++
++let branch_overflows map pc_branch lbl_dest =
++ let pc_dest = Hashtbl.find map lbl_dest in
++ let delta = pc_dest - (pc_branch + 1) in
++ delta <= -max_branch_offset || delta >= max_branch_offset
++
++let opt_branch_overflows map pc_branch opt_lbl_dest =
++ match opt_lbl_dest with
++ None -> false
++ | Some lbl_dest -> branch_overflows map pc_branch lbl_dest
++
++let fixup_branches codesize map code =
++ let expand_optbranch lbl n arg next =
++ match lbl with
++ None -> next
++ | Some l ->
++ instr_cons (Lcondbranch(Iinttest_imm(Isigned Ceq, n), l))
++ arg [||] next in
++ let rec fixup did_fix pc instr =
++ match instr.desc with
++ Lend -> did_fix
++ | Lcondbranch(test, lbl) when branch_overflows map pc lbl ->
++ let lbl2 = new_label() in
++ let cont =
++ instr_cons (Lbranch lbl) [||] [||]
++ (instr_cons (Llabel lbl2) [||] [||] instr.next) in
++ instr.desc <- Lcondbranch(invert_test test, lbl2);
++ instr.next <- cont;
++ fixup true (pc + 2) instr.next
++ | Lcondbranch3(lbl0, lbl1, lbl2)
++ when opt_branch_overflows map pc lbl0
++ || opt_branch_overflows map pc lbl1
++ || opt_branch_overflows map pc lbl2 ->
++ let cont =
++ expand_optbranch lbl0 0 instr.arg
++ (expand_optbranch lbl1 1 instr.arg
++ (expand_optbranch lbl2 2 instr.arg instr.next)) in
++ instr.desc <- cont.desc;
++ instr.next <- cont.next;
++ fixup true pc instr
++ | Lop(Ialloc n) when codesize - pc >= max_branch_offset ->
++ instr.desc <- Lop(Ispecific(Ialloc_far n));
++ fixup true (pc + 4) instr.next
++ | op ->
++ fixup did_fix (pc + instr_size op) instr.next
++ in fixup false 0 code
++
++(* Iterate branch expansion till all conditional branches are OK *)
++
++let rec branch_normalization code =
++ let (codesize, map) = label_map code in
++ if codesize >= max_branch_offset && fixup_branches codesize map code
++ then branch_normalization code
++ else ()
++
++
++(* Output the assembly code for an instruction *)
++
++let rec emit_instr i dslot =
++ match i.desc with
++ Lend -> ()
++ | Lop(Imove | Ispill | Ireload) ->
++ let src = i.arg.(0) and dst = i.res.(0) in
++ if src.loc <> dst.loc then begin
++ match (src, dst) with
++ {loc = Reg rs; typ = (Int | Addr)}, {loc = Reg rd} ->
++ ` mr {emit_reg dst}, {emit_reg src}\n`
++ | {loc = Reg rs; typ = Float}, {loc = Reg rd; typ = Float} ->
++ ` fmr {emit_reg dst}, {emit_reg src}\n`
++ | {loc = Reg rs; typ = (Int | Addr)}, {loc = Stack sd} ->
++ ` std {emit_reg src}, {emit_stack dst}\n`
++ | {loc = Reg rs; typ = Float}, {loc = Stack sd} ->
++ ` stfd {emit_reg src}, {emit_stack dst}\n`
++ | {loc = Stack ss; typ = (Int | Addr)}, {loc = Reg rd} ->
++ ` ld {emit_reg dst}, {emit_stack src}\n`
++ | {loc = Stack ss; typ = Float}, {loc = Reg rd} ->
++ ` lfd {emit_reg dst}, {emit_stack src}\n`
++ | (_, _) ->
++ fatal_error "Emit: Imove"
++ end
++ | Lop(Iconst_int n) ->
++ if is_native_immediate n then
++ ` li {emit_reg i.res.(0)}, {emit_nativeint n}\n`
++ else if n >= -0x8000_0000n && n <= 0x7FFF_FFFFn then begin
++ ` lis {emit_reg i.res.(0)}, {emit_int(nativehigh n)}\n`;
++ if nativelow n <> 0 then
++ ` ori {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, {emit_int(nativelow n)}\n`
++ end else begin
++ ` ld {emit_reg i.res.(0)}, {emit_tocref (TocInt n)}\n`
++ end
++ | Lop(Iconst_float s) ->
++ ` lfd {emit_reg i.res.(0)}, {emit_tocref (TocFloat s)}\n`
++ | Lop(Iconst_symbol s) ->
++ ` ld {emit_reg i.res.(0)}, {emit_tocref (TocSymOfs (s,0))}\n`
++ | Lop(Icall_ind) ->
++ ` std {emit_gpr 2},40({emit_gpr 1})\n`;
++ ` ld {emit_gpr 2}, 8({emit_reg i.arg.(0)})\n`;
++ ` ld {emit_reg i.arg.(0)}, 0({emit_reg i.arg.(0)})\n`;
++ ` mtctr {emit_reg i.arg.(0)}\n`;
++ record_frame i.live;
++ ` bctrl\n`;
++ ` ld {emit_gpr 2},40({emit_gpr 1})\n`
++ | Lop(Icall_imm s) ->
++ ` ld {emit_gpr 11}, {emit_tocref (TocSymOfs (s,0))}\n`;
++ ` std {emit_gpr 2},40({emit_gpr 1})\n`;
++ ` ld {emit_gpr 2}, 8({emit_gpr 11})\n`;
++ ` ld {emit_gpr 11}, 0({emit_gpr 11})\n`;
++ ` mtctr {emit_gpr 11}\n`;
++ record_frame i.live;
++ ` bctrl\n`;
++ ` ld {emit_gpr 2},40({emit_gpr 1})\n`
++ | Lop(Itailcall_ind) ->
++ ` ld {emit_gpr 2}, 8({emit_reg i.arg.(0)})\n`;
++ ` ld {emit_reg i.arg.(0)}, 0({emit_reg i.arg.(0)})\n`;
++ ` mtctr {emit_reg i.arg.(0)}\n`;
++ if has_stack_frame() then
++ ` ld {emit_gpr 1}, 0({emit_gpr 1})\n`;
++ if !contains_calls then begin
++ ` ld {emit_gpr 11}, 16({emit_gpr 1})\n`;
++ ` mtlr {emit_gpr 11}\n`
++ end;
++ ` bctr\n`
++ | Lop(Itailcall_imm s) ->
++ if s = !function_name then
++ ` b {emit_label !tailrec_entry_point}\n`
++ else begin
++ if has_stack_frame() then
++ ` ld {emit_gpr 1}, 0({emit_gpr 1})\n`;
++ if !contains_calls then begin
++ ` ld {emit_gpr 11}, 16({emit_gpr 1})\n`;
++ ` mtlr {emit_gpr 11}\n`
++ end;
++ ` ld {emit_gpr 11}, {emit_tocref (TocSymOfs (s,0))}\n`;
++ ` ld {emit_gpr 2}, 8({emit_gpr 11})\n`;
++ ` ld {emit_gpr 11}, 0({emit_gpr 11})\n`;
++ ` mtctr {emit_gpr 11}\n`;
++ ` bctr\n`
++ end
++ | Lop(Iextcall(s, alloc)) ->
++ if alloc then begin
++ ` ld {emit_gpr 11}, {emit_tocref (TocSymOfs (s,0))}\n`;
++ ` ld {emit_gpr 12}, {emit_tocref (TocSymOfs ("caml_c_call",0))}\n`;
++ end else
++ ` ld {emit_gpr 12}, {emit_tocref (TocSymOfs (s,0))}\n`;
++ ` std {emit_gpr 2}, 40({emit_gpr 1})\n`;
++ ` ld {emit_gpr 2}, 8({emit_gpr 12})\n`;
++ ` ld {emit_gpr 12}, 0({emit_gpr 12})\n`;
++ ` mtctr {emit_gpr 12}\n`;
++ if alloc then record_frame i.live;
++ ` bctrl\n`;
++ ` ld {emit_gpr 2}, 40({emit_gpr 1})\n`
++ | Lop(Istackoffset n) ->
++ if n > !stack_args_size then
++ stack_args_size := n
++ | Lop(Iload(chunk, addr)) ->
++ let loadinstr =
++ match chunk with
++ Byte_unsigned -> "lbz"
++ | Byte_signed -> "lbz"
++ | Sixteen_unsigned -> "lhz"
++ | Sixteen_signed -> "lha"
++ | Thirtytwo_unsigned -> "lwz"
++ | Thirtytwo_signed -> "lwa"
++ | Word -> "ld"
++ | Single -> "lfs"
++ | Double | Double_u -> "lfd" in
++ emit_load_store loadinstr addr i.arg 0 i.res.(0);
++ if chunk = Byte_signed then
++ ` extsb {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n`
++ | Lop(Istore(chunk, addr)) ->
++ let storeinstr =
++ match chunk with
++ Byte_unsigned | Byte_signed -> "stb"
++ | Sixteen_unsigned | Sixteen_signed -> "sth"
++ | Thirtytwo_unsigned | Thirtytwo_signed -> "stw"
++ | Word -> "std"
++ | Single -> "stfs"
++ | Double | Double_u -> "stfd" in
++ emit_load_store storeinstr addr i.arg 1 i.arg.(0)
++ | Lop(Ialloc n) ->
++ if !call_gc_label = 0 then call_gc_label := new_label();
++ ` addi {emit_gpr 31}, {emit_gpr 31}, {emit_int(-n)}\n`;
++ ` cmpld {emit_gpr 31}, {emit_gpr 30}\n`;
++ ` addi {emit_reg i.res.(0)}, {emit_gpr 31}, 8\n`;
++ record_frame i.live;
++ ` bltl {emit_label !call_gc_label}\n` (* Must be 4 insns to restart *)
++ | Lop(Ispecific(Ialloc_far n)) ->
++ if !call_gc_label = 0 then call_gc_label := new_label();
++ let lbl = new_label() in
++ ` addi {emit_gpr 31}, {emit_gpr 31}, {emit_int(-n)}\n`;
++ ` cmpld {emit_gpr 31}, {emit_gpr 30}\n`;
++ ` bge {emit_label lbl}\n`;
++ record_frame i.live;
++ ` bl {emit_label !call_gc_label}\n`; (* Must be 4 insns to restart *)
++ `{emit_label lbl}: addi {emit_reg i.res.(0)}, {emit_gpr 31}, 4\n`
++ | Lop(Iintop Isub) -> (* subfc has swapped arguments *)
++ ` subfc {emit_reg i.res.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`
++ | Lop(Iintop Imod) ->
++ ` divd {emit_gpr 0}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
++ ` mulld {emit_gpr 0}, {emit_gpr 0}, {emit_reg i.arg.(1)}\n`;
++ ` subfc {emit_reg i.res.(0)}, {emit_gpr 0}, {emit_reg i.arg.(0)}\n`
++ | Lop(Iintop(Icomp cmp)) ->
++ begin match cmp with
++ Isigned c ->
++ ` cmpd {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
++ emit_set_comp c i.res.(0)
++ | Iunsigned c ->
++ ` cmpld {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
++ emit_set_comp c i.res.(0)
++ end
++ | Lop(Iintop Icheckbound) ->
++ ` tdlle {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`
++ | Lop(Iintop op) ->
++ let instr = name_for_intop op in
++ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`
++ | Lop(Iintop_imm(Isub, n)) ->
++ ` addi {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int(-n)}\n`
++ | Lop(Iintop_imm(Idiv, n)) -> (* n is guaranteed to be a power of 2 *)
++ let l = Misc.log2 n in
++ ` sradi {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int l}\n`;
++ ` addze {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n`
++ | Lop(Iintop_imm(Imod, n)) -> (* n is guaranteed to be a power of 2 *)
++ let l = Misc.log2 n in
++ ` sradi {emit_gpr 0}, {emit_reg i.arg.(0)}, {emit_int l}\n`;
++ ` addze {emit_gpr 0}, {emit_gpr 0}\n`;
++ ` sldi {emit_gpr 0}, {emit_gpr 0}, {emit_int l}\n`;
++ ` subfc {emit_reg i.res.(0)}, {emit_gpr 0}, {emit_reg i.arg.(0)}\n`
++ | Lop(Iintop_imm(Icomp cmp, n)) ->
++ begin match cmp with
++ Isigned c ->
++ ` cmpdi {emit_reg i.arg.(0)}, {emit_int n}\n`;
++ emit_set_comp c i.res.(0)
++ | Iunsigned c ->
++ ` cmpldi {emit_reg i.arg.(0)}, {emit_int n}\n`;
++ emit_set_comp c i.res.(0)
++ end
++ | Lop(Iintop_imm(Icheckbound, n)) ->
++ ` tdllei {emit_reg i.arg.(0)}, {emit_int n}\n`
++ | Lop(Iintop_imm(op, n)) ->
++ let instr = name_for_intop_imm op in
++ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int n}\n`
++ | Lop(Inegf | Iabsf as op) ->
++ let instr = name_for_floatop1 op in
++ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}\n`
++ | Lop(Iaddf | Isubf | Imulf | Idivf as op) ->
++ let instr = name_for_floatop2 op in
++ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`
++ | Lop(Ifloatofint) ->
++ let ofs = if has_stack_frame() then 16 else 8 * (2 + num_stack_slots.(0) + num_stack_slots.(1)) in
++ ` std {emit_reg i.arg.(0)}, -{emit_int ofs}({emit_gpr 1})\n`;
++ ` lfd {emit_reg i.res.(0)}, -{emit_int ofs}({emit_gpr 1})\n`;
++ ` fcfid {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n`
++ | Lop(Iintoffloat) ->
++ let ofs = if has_stack_frame() then 16 else 8 * (2 + num_stack_slots.(0) + num_stack_slots.(1)) in
++ ` fctidz {emit_fpr 0}, {emit_reg i.arg.(0)}\n`;
++ ` stfd {emit_fpr 0}, -{emit_int ofs}({emit_gpr 1})\n`;
++ ` ld {emit_reg i.res.(0)}, -{emit_int ofs}({emit_gpr 1})\n`
++ | Lop(Ispecific sop) ->
++ let instr = name_for_specific sop in
++ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(2)}\n`
++ | Lreloadretaddr ->
++ if has_stack_frame() then begin
++ ` ld {emit_gpr 11}, {emit_label !stack_size_lbl}+16({emit_gpr 1})\n`;
++ ` mtlr {emit_gpr 11}\n`
++ end
++ | Lreturn ->
++ if has_stack_frame() then
++ ` ld {emit_gpr 1}, 0({emit_gpr 1})\n`;
++ ` blr\n`
++ | Llabel lbl ->
++ `{emit_label lbl}:\n`
++ | Lbranch lbl ->
++ ` b {emit_label lbl}\n`
++ | Lcondbranch(tst, lbl) ->
++ begin match tst with
++ Itruetest ->
++ ` cmpdi {emit_reg i.arg.(0)}, 0\n`;
++ emit_delay dslot;
++ ` bne {emit_label lbl}\n`
++ | Ifalsetest ->
++ ` cmpdi {emit_reg i.arg.(0)}, 0\n`;
++ emit_delay dslot;
++ ` beq {emit_label lbl}\n`
++ | Iinttest cmp ->
++ let (comp, branch) = name_for_int_comparison cmp in
++ ` {emit_string comp} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
++ emit_delay dslot;
++ ` {emit_string branch} {emit_label lbl}\n`
++ | Iinttest_imm(cmp, n) ->
++ let (comp, branch) = name_for_int_comparison cmp in
++ ` {emit_string comp}i {emit_reg i.arg.(0)}, {emit_int n}\n`;
++ emit_delay dslot;
++ ` {emit_string branch} {emit_label lbl}\n`
++ | Ifloattest(cmp, neg) ->
++ ` fcmpu {emit_ccr 0}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
++ (* bit 0 = lt, bit 1 = gt, bit 2 = eq *)
++ let (bitnum, negtst) =
++ match cmp with
++ Ceq -> (2, neg)
++ | Cne -> (2, not neg)
++ | Cle -> ` cror 3, 0, 2\n`; (* lt or eq *)
++ (3, neg)
++ | Cgt -> (1, neg)
++ | Cge -> ` cror 3, 1, 2\n`; (* gt or eq *)
++ (3, neg)
++ | Clt -> (0, neg) in
++ emit_delay dslot;
++ if negtst
++ then ` bf {emit_int bitnum}, {emit_label lbl}\n`
++ else ` bt {emit_int bitnum}, {emit_label lbl}\n`
++ | Ioddtest ->
++ ` andi. {emit_gpr 0}, {emit_reg i.arg.(0)}, 1\n`;
++ emit_delay dslot;
++ ` bne {emit_label lbl}\n`
++ | Ieventest ->
++ ` andi. {emit_gpr 0}, {emit_reg i.arg.(0)}, 1\n`;
++ emit_delay dslot;
++ ` beq {emit_label lbl}\n`
++ end
++ | Lcondbranch3(lbl0, lbl1, lbl2) ->
++ ` cmpdi {emit_reg i.arg.(0)}, 1\n`;
++ emit_delay dslot;
++ begin match lbl0 with
++ None -> ()
++ | Some lbl -> ` blt {emit_label lbl}\n`
++ end;
++ begin match lbl1 with
++ None -> ()
++ | Some lbl -> ` beq {emit_label lbl}\n`
++ end;
++ begin match lbl2 with
++ None -> ()
++ | Some lbl -> ` bgt {emit_label lbl}\n`
++ end
++ | Lswitch jumptbl ->
++ if !lbl_jumptbl = 0 then lbl_jumptbl := new_label();
++ ` ld {emit_gpr 11}, {emit_tocref (TocLabel !lbl_jumptbl)}\n`;
++ ` addi {emit_gpr 0}, {emit_reg i.arg.(0)}, {emit_int !num_jumptbl_entries}\n`;
++ ` sldi {emit_gpr 0}, {emit_gpr 0}, 2\n`;
++ ` lwax {emit_gpr 0}, {emit_gpr 11}, {emit_gpr 0}\n`;
++ ` add {emit_gpr 0}, {emit_gpr 11}, {emit_gpr 0}\n`;
++ ` mtctr {emit_gpr 0}\n`;
++ ` bctr\n`;
++ for i = 0 to Array.length jumptbl - 1 do
++ jumptbl_entries := jumptbl.(i) :: !jumptbl_entries;
++ incr num_jumptbl_entries
++ done
++ | Lsetuptrap lbl ->
++ ` bl {emit_label lbl}\n`;
++ | Lpushtrap ->
++ stack_traps_size := !stack_traps_size + 32;
++ ` addi {emit_gpr 11}, {emit_gpr 1}, {emit_label !stack_size_lbl}-{emit_int !stack_traps_size}\n`;
++ ` mflr {emit_gpr 0}\n`;
++ ` std {emit_gpr 29}, 0({emit_gpr 11})\n`;
++ ` std {emit_gpr 0}, 8({emit_gpr 11})\n`;
++ ` std {emit_gpr 1}, 16({emit_gpr 11})\n`;
++ ` std {emit_gpr 2}, 24({emit_gpr 11})\n`;
++ ` mr {emit_gpr 29}, {emit_gpr 11}\n`
++ | Lpoptrap ->
++ ` ld {emit_gpr 29}, 0({emit_gpr 29})\n`
++ | Lraise ->
++ ` ld {emit_gpr 0}, 8({emit_gpr 29})\n`;
++ ` ld {emit_gpr 1}, 16({emit_gpr 29})\n`;
++ ` ld {emit_gpr 2}, 24({emit_gpr 29})\n`;
++ ` mtlr {emit_gpr 0}\n`;
++ ` ld {emit_gpr 29}, 0({emit_gpr 29})\n`;
++ ` blr\n`
++
++and emit_delay = function
++ None -> ()
++ | Some i -> emit_instr i None
++
++(* Checks if a pseudo-instruction expands to instructions
++ that do not branch and do not affect CR0 nor R12. *)
++
++let is_simple_instr i =
++ match i.desc with
++ Lop op ->
++ begin match op with
++ Icall_imm _ | Icall_ind | Itailcall_imm _ | Itailcall_ind |
++ Iextcall(_, _) -> false
++ | Ialloc(_) -> false
++ | Iintop(Icomp _) -> false
++ | Iintop_imm(Iand, _) -> false
++ | Iintop_imm(Icomp _, _) -> false
++ | _ -> true
++ end
++ | Lreloadretaddr -> true
++ | _ -> false
++
++let no_interference res arg =
++ try
++ for i = 0 to Array.length arg - 1 do
++ for j = 0 to Array.length res - 1 do
++ if arg.(i).loc = res.(j).loc then raise Exit
++ done
++ done;
++ true
++ with Exit ->
++ false
++
++(* Emit a sequence of instructions, trying to fill delay slots for branches *)
++
++let rec emit_all i =
++ match i with
++ {desc = Lend} -> ()
++ | {next = {desc = (Lcondbranch(_, _) | Lcondbranch3(_, _, _))}}
++ when is_simple_instr i & no_interference i.res i.next.arg ->
++ emit_instr i.next (Some i);
++ emit_all i.next.next
++ | _ ->
++ emit_instr i None;
++ emit_all i.next
++
++(* Emission of a function declaration *)
++
++let fundecl fundecl =
++ function_name := fundecl.fun_name;
++ defined_functions := StringSet.add fundecl.fun_name !defined_functions;
++ tailrec_entry_point := new_label();
++ if has_stack_frame() then
++ stack_size_lbl := new_label();
++ stack_slot_lbl := new_label();
++ stack_args_size := 0;
++ stack_traps_size := 0;
++ call_gc_label := 0;
++ ` .globl {emit_symbol fundecl.fun_name}\n`;
++ begin match Config.system with
++ | "elf" | "bsd" ->
++ ` .section \".opd\",\"aw\"\n`;
++ ` .align 3\n`;
++ ` .type {emit_symbol fundecl.fun_name}, @function\n`;
++ `{emit_symbol fundecl.fun_name}:\n`;
++ ` .quad .L.{emit_symbol fundecl.fun_name},.TOC.@tocbase\n`;
++ ` .previous\n`;
++ ` .align 2\n`;
++ emit_string code_space;
++ `.L.{emit_symbol fundecl.fun_name}:\n`
++ | _ ->
++ ` .align 2\n`;
++ emit_string code_space;
++ `{emit_symbol fundecl.fun_name}:\n`
++ end;
++ if !contains_calls then begin
++ ` mflr {emit_gpr 0}\n`;
++ ` std {emit_gpr 0}, 16({emit_gpr 1})\n`
++ end;
++ if has_stack_frame() then
++ ` stdu {emit_gpr 1}, -{emit_label !stack_size_lbl}({emit_gpr 1})\n`;
++ `{emit_label !tailrec_entry_point}:\n`;
++ branch_normalization fundecl.fun_body;
++ emit_all fundecl.fun_body;
++ ` .size .L.{emit_symbol fundecl.fun_name}, . - .L.{emit_symbol fundecl.fun_name}\n`;
++ if has_stack_frame() then begin
++ ` .set {emit_label !stack_size_lbl},{emit_int (frame_size_sans_args() + !stack_args_size + !stack_traps_size)} # stack size including traps\n`;
++ ` .set {emit_label !stack_slot_lbl},{emit_int (48 + !stack_args_size)} # stack slot offset\n`
++ end else (* leave 8 bytes for float <-> conversions *)
++ ` .set {emit_label !stack_slot_lbl},{emit_int (40-frame_size_sans_args())} # stack slot offset (negative)\n`;
++
++ (* Emit the glue code to call the GC *)
++ if !call_gc_label > 0 then begin
++ `{emit_label !call_gc_label}:\n`;
++ ` ld {emit_gpr 12}, {emit_tocref (TocSymOfs ("caml_call_gc",0))}\n`;
++ ` ld {emit_gpr 12}, 0({emit_gpr 12})\n`;
++ ` mtctr {emit_gpr 12}\n`;
++ ` bctr\n`;
++ end
++
++(* Emission of data *)
++
++let declare_global_data s =
++ ` .globl {emit_symbol s}\n`;
++ if Config.system = "elf" || Config.system = "bsd" then
++ ` .type {emit_symbol s}, @object\n`
++
++let emit_item = function
++ Cglobal_symbol s ->
++ declare_global_data s
++ | Cdefine_symbol s ->
++ `{emit_symbol s}:\n`;
++ | Cdefine_label lbl ->
++ `{emit_label (lbl + 100000)}:\n`
++ | Cint8 n ->
++ ` .byte {emit_int n}\n`
++ | Cint16 n ->
++ ` .short {emit_int n}\n`
++ | Cint32 n ->
++ ` .long {emit_nativeint n}\n`
++ | Cint n ->
++ ` .quad {emit_nativeint n}\n`
++ | Csingle f ->
++ ` .float 0d{emit_string f}\n`
++ | Cdouble f ->
++ ` .double 0d{emit_string f}\n`
++ | Csymbol_address s ->
++ ` .quad {emit_symbol s}\n`
++ | Clabel_address lbl ->
++ ` .quad {emit_label (lbl + 100000)}\n`
++ | Cstring s ->
++ emit_bytes_directive " .byte " s
++ | Cskip n ->
++ if n > 0 then ` .space {emit_int n}\n`
++ | Calign n ->
++ ` .align {emit_int (Misc.log2 n)}\n`
++
++let data l =
++ emit_string data_space;
++ List.iter emit_item l
++
++(* Beginning / end of an assembly file *)
++
++let begin_assembly() =
++ defined_functions := StringSet.empty;
++ external_functions := StringSet.empty;
++ tocref_entries := [];
++ num_jumptbl_entries := 0;
++ jumptbl_entries := [];
++ lbl_jumptbl := 0;
++ (* Emit the beginning of the segments *)
++ let lbl_begin = Compilenv.make_symbol (Some "data_begin") in
++ emit_string data_space;
++ declare_global_data lbl_begin;
++ `{emit_symbol lbl_begin}:\n`;
++ let lbl_begin = Compilenv.make_symbol (Some "code_begin") in
++ emit_string code_space;
++ declare_global_data lbl_begin;
++ `{emit_symbol lbl_begin}:\n`
++
++let end_assembly() =
++ (* Emit the jump table *)
++ if !num_jumptbl_entries > 0 then begin
++ emit_string code_space;
++ `{emit_label !lbl_jumptbl}:\n`;
++ List.iter
++ (fun lbl -> ` .long {emit_label lbl} - {emit_label !lbl_jumptbl}\n`)
++ (List.rev !jumptbl_entries);
++ jumptbl_entries := []
++ end;
++ if !tocref_entries <> [] then begin
++ emit_string toc_space;
++ List.iter
++ (fun (lbl, entry) ->
++ `{emit_label lbl}:\n`;
++ match entry with
++ TocFloat f ->
++ ` .double {emit_tocentry entry}\n`
++ | _ ->
++ ` .tc {emit_label lbl}[TC],{emit_tocentry entry}\n`
++ )
++ !tocref_entries;
++ tocref_entries := []
++ end;
++ if pic_externals then
++ (* Emit the pointers to external functions *)
++ StringSet.iter emit_external !external_functions;
++ (* Emit the end of the segments *)
++ emit_string code_space;
++ let lbl_end = Compilenv.make_symbol (Some "code_end") in
++ declare_global_data lbl_end;
++ `{emit_symbol lbl_end}:\n`;
++ ` .long 0\n`;
++ emit_string data_space;
++ let lbl_end = Compilenv.make_symbol (Some "data_end") in
++ declare_global_data lbl_end;
++ `{emit_symbol lbl_end}:\n`;
++ ` .quad 0\n`;
++ (* Emit the frame descriptors *)
++ emit_string rodata_space;
++ let lbl = Compilenv.make_symbol (Some "frametable") in
++ declare_global_data lbl;
++ `{emit_symbol lbl}:\n`;
++ ` .quad {emit_int (List.length !frame_descriptors)}\n`;
++ List.iter emit_frame !frame_descriptors;
++ frame_descriptors := []
+diff -uNr ocaml-3.10.1/asmcomp/power64/proc.ml ocaml-3.10.1.ppc64/asmcomp/power64/proc.ml
+--- ocaml-3.10.1/asmcomp/power64/proc.ml 1969-12-31 19:00:00.000000000 -0500
++++ ocaml-3.10.1.ppc64/asmcomp/power64/proc.ml 2008-02-29 08:37:45.000000000 -0500
+@@ -0,0 +1,245 @@
++(***********************************************************************)
++(* *)
++(* 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: proc.ml,v 1.12 2004/06/19 17:39:35 xleroy Exp $ *)
++
++(* Description of the Power PC *)
++
++open Misc
++open Cmm
++open Reg
++open Arch
++open Mach
++
++(* Instruction selection *)
++
++let word_addressed = false
++
++(* Registers available for register allocation *)
++
++(* Integer register map:
++ 0 temporary, null register for some operations
++ 1 stack pointer
++ 2 pointer to table of contents
++ 3 - 10 function arguments and results
++ 11 - 12 temporaries
++ 13 pointer to small data area
++ 14 - 28 general purpose, preserved by C
++ 29 trap pointer
++ 30 allocation limit
++ 31 allocation pointer
++ Floating-point register map:
++ 0 temporary
++ 1 - 13 function arguments and results
++ 14 - 31 general purpose, preserved by C
++*)
++
++let int_reg_name =
++ if Config.system = "rhapsody" then
++ [| "r3"; "r4"; "r5"; "r6"; "r7"; "r8"; "r9"; "r10";
++ "r14"; "r15"; "r16"; "r17"; "r18"; "r19"; "r20"; "r21";
++ "r22"; "r23"; "r24"; "r25"; "r26"; "r27"; "r28" |]
++ else
++ [| "3"; "4"; "5"; "6"; "7"; "8"; "9"; "10";
++ "14"; "15"; "16"; "17"; "18"; "19"; "20"; "21";
++ "22"; "23"; "24"; "25"; "26"; "27"; "28" |]
++
++let float_reg_name =
++ if Config.system = "rhapsody" then
++ [| "f1"; "f2"; "f3"; "f4"; "f5"; "f6"; "f7"; "f8";
++ "f9"; "f10"; "f11"; "f12"; "f13"; "f14"; "f15"; "f16";
++ "f17"; "f18"; "f19"; "f20"; "f21"; "f22"; "f23"; "f24";
++ "f25"; "f26"; "f27"; "f28"; "f29"; "f30"; "f31" |]
++ else
++ [| "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" |]
++
++let num_register_classes = 2
++
++let register_class r =
++ match r.typ with
++ Int -> 0
++ | Addr -> 0
++ | Float -> 1
++
++let num_available_registers = [| 23; 31 |]
++
++let first_available_register = [| 0; 100 |]
++
++let register_name r =
++ if r < 100 then int_reg_name.(r) else float_reg_name.(r - 100)
++
++let rotate_registers = true
++
++(* Representation of hard registers by pseudo-registers *)
++
++let hard_int_reg =
++ let v = Array.create 23 Reg.dummy in
++ for i = 0 to 22 do v.(i) <- Reg.at_location Int (Reg i) done; v
++
++let hard_float_reg =
++ let v = Array.create 31 Reg.dummy in
++ for i = 0 to 30 do v.(i) <- Reg.at_location Float (Reg(100 + i)) done; v
++
++let all_phys_regs =
++ Array.append hard_int_reg hard_float_reg
++
++let phys_reg n =
++ if n < 100 then hard_int_reg.(n) else hard_float_reg.(n - 100)
++
++let stack_slot slot ty =
++ Reg.at_location ty (Stack slot)
++
++(* Calling conventions *)
++
++let calling_conventions
++ first_int last_int first_float last_float make_stack stack_ofs arg =
++ let loc = Array.create (Array.length arg) Reg.dummy in
++ let int = ref first_int in
++ let float = ref first_float in
++ let ofs = ref stack_ofs in
++ for i = 0 to Array.length arg - 1 do
++ match arg.(i).typ with
++ Int | Addr as ty ->
++ if !int <= last_int then begin
++ loc.(i) <- phys_reg !int;
++ incr int
++ end else begin
++ loc.(i) <- stack_slot (make_stack !ofs) ty;
++ end;
++ ofs := !ofs + 8
++ | Float ->
++ if !float <= last_float then begin
++ loc.(i) <- phys_reg !float;
++ incr float
++ end else begin
++ loc.(i) <- stack_slot (make_stack !ofs) Float;
++ end;
++ ofs := !ofs + 8
++ done;
++ (loc, Misc.align !ofs 16)
++ (* Keep stack 16-aligned. *)
++
++let incoming ofs = Incoming ofs
++let outgoing ofs = Outgoing ofs
++let not_supported ofs = fatal_error "Proc.loc_results: cannot call"
++
++let loc_arguments arg =
++ calling_conventions 0 7 100 112 outgoing 48 arg
++let loc_parameters arg =
++ let (loc, ofs) = calling_conventions 0 7 100 112 incoming 0 arg in loc
++let loc_results res =
++ let (loc, ofs) = calling_conventions 0 7 100 112 not_supported 0 res in loc
++
++(* C calling conventions under PowerOpen:
++ use GPR 3-10 and FPR 1-13 just like ML calling
++ conventions, but always reserve stack space for all arguments.
++ Also, using a float register automatically reserves two int registers
++ (in 32-bit mode) or one int register (in 64-bit mode).
++ (If we were to call a non-prototyped C function, each float argument
++ would have to go both in a float reg and in the matching pair
++ of integer regs.)
++
++ C calling conventions under SVR4:
++ use GPR 3-10 and FPR 1-8 just like ML calling conventions.
++ Using a float register does not affect the int registers.
++ Always reserve 8 bytes at bottom of stack, plus whatever is needed
++ to hold the overflow arguments. *)
++
++let poweropen_external_conventions first_int last_int
++ first_float last_float arg =
++ let loc = Array.create (Array.length arg) Reg.dummy in
++ let int = ref first_int in
++ let float = ref first_float in
++ let ofs = ref 112 in
++ for i = 0 to Array.length arg - 1 do
++ match arg.(i).typ with
++ Int | Addr as ty ->
++ if !int <= last_int then begin
++ loc.(i) <- phys_reg !int;
++ incr int
++ end else begin
++ loc.(i) <- stack_slot (Outgoing !ofs) ty;
++ ofs := !ofs + size_int
++ end
++ | Float ->
++ if !float <= last_float then begin
++ loc.(i) <- phys_reg !float;
++ incr float
++ end else begin
++ loc.(i) <- stack_slot (Outgoing !ofs) Float;
++ ofs := !ofs + size_float
++ end;
++ int := !int + 1
++ done;
++ (loc, Misc.align !ofs 16) (* Keep stack 16-aligned *)
++
++let loc_external_arguments =
++ match Config.system with
++ | "rhapsody" -> poweropen_external_conventions 0 7 100 112
++ | "elf" | "bsd" -> calling_conventions 0 7 100 107 outgoing 8
++ | _ -> assert false
++
++let extcall_use_push = false
++
++(* Results are in GPR 3 and FPR 1 *)
++
++let loc_external_results res =
++ let (loc, ofs) = calling_conventions 0 0 100 100 not_supported 0 res in loc
++
++(* Exceptions are in GPR 3 *)
++
++let loc_exn_bucket = phys_reg 0
++
++(* Registers destroyed by operations *)
++
++let destroyed_at_c_call =
++ Array.of_list(List.map phys_reg
++ [0; 1; 2; 3; 4; 5; 6; 7;
++ 100; 101; 102; 103; 104; 105; 106; 107; 108; 109; 110; 111; 112])
++
++let destroyed_at_oper = function
++ Iop(Icall_ind | Icall_imm _ | Iextcall(_, true)) -> all_phys_regs
++ | Iop(Iextcall(_, false)) -> destroyed_at_c_call
++ | _ -> [||]
++
++let destroyed_at_raise = all_phys_regs
++
++(* Maximal register pressure *)
++
++let safe_register_pressure = function
++ Iextcall(_, _) -> 15
++ | _ -> 23
++
++let max_register_pressure = function
++ Iextcall(_, _) -> [| 15; 18 |]
++ | _ -> [| 23; 30 |]
++
++(* Layout of the stack *)
++
++let num_stack_slots = [| 0; 0 |]
++let contains_calls = ref false
++
++(* Calling the assembler *)
++
++let assemble_file infile outfile =
++ let infile = Filename.quote infile
++ and outfile = Filename.quote outfile in
++ match Config.system with
++ | "elf" ->
++ Ccomp.command ("as -u -m ppc64 -o " ^ outfile ^ " " ^ infile)
++ | _ -> assert false
++
++open Clflags;;
++open Config;;
+diff -uNr ocaml-3.10.1/asmcomp/power64/reload.ml ocaml-3.10.1.ppc64/asmcomp/power64/reload.ml
+--- ocaml-3.10.1/asmcomp/power64/reload.ml 1969-12-31 19:00:00.000000000 -0500
++++ ocaml-3.10.1.ppc64/asmcomp/power64/reload.ml 2008-02-29 08:37:45.000000000 -0500
+@@ -0,0 +1,18 @@
++(***********************************************************************)
++(* *)
++(* 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: reload.ml,v 1.3 1999/11/17 18:56:46 xleroy Exp $ *)
++
++(* Reloading for the PowerPC *)
++
++let fundecl f =
++ (new Reloadgen.reload_generic)#fundecl f
+diff -uNr ocaml-3.10.1/asmcomp/power64/scheduling.ml ocaml-3.10.1.ppc64/asmcomp/power64/scheduling.ml
+--- ocaml-3.10.1/asmcomp/power64/scheduling.ml 1969-12-31 19:00:00.000000000 -0500
++++ ocaml-3.10.1.ppc64/asmcomp/power64/scheduling.ml 2008-02-29 08:37:45.000000000 -0500
+@@ -0,0 +1,66 @@
++(***********************************************************************)
++(* *)
++(* 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: scheduling.ml,v 1.6 2004/06/19 16:13:33 xleroy Exp $ *)
++
++(* Instruction scheduling for the Power PC *)
++
++open Arch
++open Mach
++
++class scheduler = object
++
++inherit Schedgen.scheduler_generic
++
++(* Latencies (in cycles). Based roughly on the "common model". *)
++
++method oper_latency = function
++ Ireload -> 2
++ | Iload(_, _) -> 2
++ | Iconst_float _ -> 2 (* turned into a load *)
++ | Iconst_symbol _ -> 1
++ | Iintop Imul -> 9
++ | Iintop_imm(Imul, _) -> 5
++ | Iintop(Idiv | Imod) -> 36
++ | Iaddf | Isubf -> 4
++ | Imulf -> 5
++ | Idivf -> 33
++ | Ispecific(Imultaddf | Imultsubf) -> 5
++ | _ -> 1
++
++method reload_retaddr_latency = 12
++ (* If we can have that many cycles between the reloadretaddr and the
++ return, we can expect that the blr branch will be completely folded. *)
++
++(* Issue cycles. Rough approximations. *)
++
++method oper_issue_cycles = function
++ Iconst_float _ | Iconst_symbol _ -> 2
++ | Iload(_, Ibased(_, _)) -> 2
++ | Istore(_, Ibased(_, _)) -> 2
++ | Ialloc _ -> 4
++ | Iintop(Imod) -> 40 (* assuming full stall *)
++ | Iintop(Icomp _) -> 4
++ | Iintop_imm(Idiv, _) -> 2
++ | Iintop_imm(Imod, _) -> 4
++ | Iintop_imm(Icomp _, _) -> 4
++ | Ifloatofint -> 9
++ | Iintoffloat -> 4
++ | _ -> 1
++
++method reload_retaddr_issue_cycles = 3
++ (* load then stalling mtlr *)
++
++end
++
++let fundecl f = (new scheduler)#schedule_fundecl f
++
+diff -uNr ocaml-3.10.1/asmcomp/power64/selection.ml ocaml-3.10.1.ppc64/asmcomp/power64/selection.ml
+--- ocaml-3.10.1/asmcomp/power64/selection.ml 1969-12-31 19:00:00.000000000 -0500
++++ ocaml-3.10.1.ppc64/asmcomp/power64/selection.ml 2008-02-29 08:37:45.000000000 -0500
+@@ -0,0 +1,103 @@
++(***********************************************************************)
++(* *)
++(* Objective Caml *)
++(* *)
++(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
++(* *)
++(* Copyright 1997 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: selection.ml,v 1.6 2004/06/19 16:13:33 xleroy Exp $ *)
++
++(* Instruction selection for the Power PC processor *)
++
++open Misc
++open Cmm
++open Reg
++open Arch
++open Mach
++
++(* Recognition of addressing modes *)
++
++type addressing_expr =
++ Asymbol of string
++ | Alinear of expression
++ | Aadd of expression * expression
++
++let rec select_addr = function
++ Cconst_symbol s ->
++ (Asymbol s, 0)
++ | Cop((Caddi | Cadda), [arg; Cconst_int m]) ->
++ let (a, n) = select_addr arg in (a, n + m)
++ | Cop((Caddi | Cadda), [Cconst_int m; arg]) ->
++ let (a, n) = select_addr arg in (a, n + m)
++ | Cop((Caddi | Cadda), [arg1; arg2]) ->
++ begin match (select_addr arg1, select_addr arg2) with
++ ((Alinear e1, n1), (Alinear e2, n2)) ->
++ (Aadd(e1, e2), n1 + n2)
++ | _ ->
++ (Aadd(arg1, arg2), 0)
++ end
++ | exp ->
++ (Alinear exp, 0)
++
++(* Instruction selection *)
++
++class selector = object (self)
++
++inherit Selectgen.selector_generic as super
++
++method is_immediate n = (n <= 32767) && (n >= -32768)
++
++method select_addressing exp =
++ match select_addr exp with
++ (Asymbol s, d) ->
++ (Ibased(s, d), Ctuple [])
++ | (Alinear e, d) ->
++ (Iindexed d, e)
++ | (Aadd(e1, e2), d) ->
++ if d = 0
++ then (Iindexed2, Ctuple[e1; e2])
++ else (Iindexed d, Cop(Cadda, [e1; e2]))
++
++method select_operation op args =
++ match (op, args) with
++ (* Prevent the recognition of (x / cst) and (x % cst) when cst is not
++ a power of 2, which do not correspond to an instruction. *)
++ (Cdivi, [arg; Cconst_int n]) when n = 1 lsl (Misc.log2 n) ->
++ (Iintop_imm(Idiv, n), [arg])
++ | (Cdivi, _) ->
++ (Iintop Idiv, args)
++ | (Cmodi, [arg; Cconst_int n]) when n = 1 lsl (Misc.log2 n) ->
++ (Iintop_imm(Imod, n), [arg])
++ | (Cmodi, _) ->
++ (Iintop Imod, args)
++ (* The and, or and xor instructions have a different range of immediate
++ operands than the other instructions *)
++ | (Cand, _) -> self#select_logical Iand args
++ | (Cor, _) -> self#select_logical Ior args
++ | (Cxor, _) -> self#select_logical Ixor args
++ (* Recognize mult-add and mult-sub instructions *)
++ | (Caddf, [Cop(Cmulf, [arg1; arg2]); arg3]) ->
++ (Ispecific Imultaddf, [arg1; arg2; arg3])
++ | (Caddf, [arg3; Cop(Cmulf, [arg1; arg2])]) ->
++ (Ispecific Imultaddf, [arg1; arg2; arg3])
++ | (Csubf, [Cop(Cmulf, [arg1; arg2]); arg3]) ->
++ (Ispecific Imultsubf, [arg1; arg2; arg3])
++ | _ ->
++ super#select_operation op args
++
++method select_logical op = function
++ [arg; Cconst_int n] when n >= 0 && n <= 0xFFFF ->
++ (Iintop_imm(op, n), [arg])
++ | [Cconst_int n; arg] when n >= 0 && n <= 0xFFFF ->
++ (Iintop_imm(op, n), [arg])
++ | args ->
++ (Iintop op, args)
++
++end
++
++let fundecl f = (new selector)#emit_fundecl f
+diff -uNr ocaml-3.10.1/asmrun/Makefile ocaml-3.10.1.ppc64/asmrun/Makefile
+--- ocaml-3.10.1/asmrun/Makefile 2007-02-23 04:29:45.000000000 -0500
++++ ocaml-3.10.1.ppc64/asmrun/Makefile 2008-02-29 08:37:45.000000000 -0500
+@@ -74,6 +74,12 @@
+ power.p.o: power-$(SYSTEM).o
+ cp power-$(SYSTEM).o power.p.o
+
++power64.o: power64-$(SYSTEM).o
++ cp power64-$(SYSTEM).o power64.o
++
++power64.p.o: power64-$(SYSTEM).o
++ cp power64-$(SYSTEM).o power64.p.o
++
+ main.c: ../byterun/main.c
+ ln -s ../byterun/main.c main.c
+ misc.c: ../byterun/misc.c
+diff -uNr ocaml-3.10.1/asmrun/power64-elf.S ocaml-3.10.1.ppc64/asmrun/power64-elf.S
+--- ocaml-3.10.1/asmrun/power64-elf.S 1969-12-31 19:00:00.000000000 -0500
++++ ocaml-3.10.1.ppc64/asmrun/power64-elf.S 2008-02-29 08:37:45.000000000 -0500
+@@ -0,0 +1,486 @@
++/*********************************************************************/
++/* */
++/* 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 GNU Library General Public License, with */
++/* the special exception on linking described in file ../LICENSE. */
++/* */
++/*********************************************************************/
++
++/* $Id: power-elf.S,v 1.18 2004/01/03 12:51:19 doligez Exp $ */
++
++#define Addrglobal(reg,glob) \
++ addis reg, 0, glob@ha; \
++ addi reg, reg, glob@l
++#define Loadglobal(reg,glob,tmp) \
++ addis tmp, 0, glob@ha; \
++ ld reg, glob@l(tmp)
++#define Storeglobal(reg,glob,tmp) \
++ addis tmp, 0, glob@ha; \
++ std reg, glob@l(tmp)
++
++ .section ".text"
++
++/* Invoke the garbage collector. */
++
++ .globl caml_call_gc
++ .type caml_call_gc, @function
++ .section ".opd","aw"
++ .align 3
++caml_call_gc:
++ .quad .L.caml_call_gc,.TOC.@tocbase
++ .previous
++ .align 2
++.L.caml_call_gc:
++ /* Set up stack frame */
++ mflr 0
++ std 0, 16(1)
++ /* Record return address into Caml code */
++ Storeglobal(0, caml_last_return_address, 11)
++ /* Record lowest stack address */
++ Storeglobal(1, caml_bottom_of_stack, 11)
++ /* 0x220 = 8*32 (int regs) + 8*32 (float regs) + 48 (stack frame) */
++ stdu 1, -0x230(1)
++ /* Record pointer to register array */
++ addi 0, 1, 8*32 + 48
++ Storeglobal(0, caml_gc_regs, 11)
++ /* Save current allocation pointer for debugging purposes */
++ Storeglobal(31, caml_young_ptr, 11)
++ /* Save exception pointer (if e.g. a sighandler raises) */
++ Storeglobal(29, caml_exception_pointer, 11)
++ /* Save all registers used by the code generator */
++ addi 11, 1, 8*32 + 48 - 8
++ stdu 3, 8(11)
++ stdu 4, 8(11)
++ stdu 5, 8(11)
++ stdu 6, 8(11)
++ stdu 7, 8(11)
++ stdu 8, 8(11)
++ stdu 9, 8(11)
++ stdu 10, 8(11)
++ stdu 14, 8(11)
++ stdu 15, 8(11)
++ stdu 16, 8(11)
++ stdu 17, 8(11)
++ stdu 18, 8(11)
++ stdu 19, 8(11)
++ stdu 20, 8(11)
++ stdu 21, 8(11)
++ stdu 22, 8(11)
++ stdu 23, 8(11)
++ stdu 24, 8(11)
++ stdu 25, 8(11)
++ stdu 26, 8(11)
++ stdu 27, 8(11)
++ stdu 28, 8(11)
++ addi 11, 1, 48 - 8
++ stfdu 1, 8(11)
++ stfdu 2, 8(11)
++ stfdu 3, 8(11)
++ stfdu 4, 8(11)
++ stfdu 5, 8(11)
++ stfdu 6, 8(11)
++ stfdu 7, 8(11)
++ stfdu 8, 8(11)
++ stfdu 9, 8(11)
++ stfdu 10, 8(11)
++ stfdu 11, 8(11)
++ stfdu 12, 8(11)
++ stfdu 13, 8(11)
++ stfdu 14, 8(11)
++ stfdu 15, 8(11)
++ stfdu 16, 8(11)
++ stfdu 17, 8(11)
++ stfdu 18, 8(11)
++ stfdu 19, 8(11)
++ stfdu 20, 8(11)
++ stfdu 21, 8(11)
++ stfdu 22, 8(11)
++ stfdu 23, 8(11)
++ stfdu 24, 8(11)
++ stfdu 25, 8(11)
++ stfdu 26, 8(11)
++ stfdu 27, 8(11)
++ stfdu 28, 8(11)
++ stfdu 29, 8(11)
++ stfdu 30, 8(11)
++ stfdu 31, 8(11)
++ /* Call the GC */
++ std 2,40(1)
++ Addrglobal(11, caml_garbage_collection)
++ ld 2,8(11)
++ ld 11,0(11)
++ mtlr 11
++ blrl
++ ld 2,40(1)
++ /* Reload new allocation pointer and allocation limit */
++ Loadglobal(31, caml_young_ptr, 11)
++ Loadglobal(30, caml_young_limit, 11)
++ /* Restore all regs used by the code generator */
++ addi 11, 1, 8*32 + 48 - 8
++ ldu 3, 8(11)
++ ldu 4, 8(11)
++ ldu 5, 8(11)
++ ldu 6, 8(11)
++ ldu 7, 8(11)
++ ldu 8, 8(11)
++ ldu 9, 8(11)
++ ldu 10, 8(11)
++ ldu 14, 8(11)
++ ldu 15, 8(11)
++ ldu 16, 8(11)
++ ldu 17, 8(11)
++ ldu 18, 8(11)
++ ldu 19, 8(11)
++ ldu 20, 8(11)
++ ldu 21, 8(11)
++ ldu 22, 8(11)
++ ldu 23, 8(11)
++ ldu 24, 8(11)
++ ldu 25, 8(11)
++ ldu 26, 8(11)
++ ldu 27, 8(11)
++ ldu 28, 8(11)
++ addi 11, 1, 48 - 8
++ lfdu 1, 8(11)
++ lfdu 2, 8(11)
++ lfdu 3, 8(11)
++ lfdu 4, 8(11)
++ lfdu 5, 8(11)
++ lfdu 6, 8(11)
++ lfdu 7, 8(11)
++ lfdu 8, 8(11)
++ lfdu 9, 8(11)
++ lfdu 10, 8(11)
++ lfdu 11, 8(11)
++ lfdu 12, 8(11)
++ lfdu 13, 8(11)
++ lfdu 14, 8(11)
++ lfdu 15, 8(11)
++ lfdu 16, 8(11)
++ lfdu 17, 8(11)
++ lfdu 18, 8(11)
++ lfdu 19, 8(11)
++ lfdu 20, 8(11)
++ lfdu 21, 8(11)
++ lfdu 22, 8(11)
++ lfdu 23, 8(11)
++ lfdu 24, 8(11)
++ lfdu 25, 8(11)
++ lfdu 26, 8(11)
++ lfdu 27, 8(11)
++ lfdu 28, 8(11)
++ lfdu 29, 8(11)
++ lfdu 30, 8(11)
++ lfdu 31, 8(11)
++ /* Return to caller, restarting the allocation */
++ Loadglobal(0, caml_last_return_address, 11)
++ addic 0, 0, -16 /* Restart the allocation (4 instructions) */
++ mtlr 0
++ /* Say we are back into Caml code */
++ li 12, 0
++ Storeglobal(12, caml_last_return_address, 11)
++ /* Deallocate stack frame */
++ ld 1, 0(1)
++ /* Return */
++ blr
++ .size .L.caml_call_gc,.-.L.caml_call_gc
++
++/* Call a C function from Caml */
++
++ .globl caml_c_call
++ .type caml_c_call, @function
++ .section ".opd","aw"
++ .align 3
++caml_c_call:
++ .quad .L.caml_c_call,.TOC.@tocbase
++ .previous
++ .align 2
++.L.caml_c_call:
++ .cfi_startproc
++ /* Save return address */
++ mflr 25
++ .cfi_register lr,25
++ /* Get ready to call C function (address in 11) */
++ ld 2, 8(11)
++ ld 11,0(11)
++ mtlr 11
++ /* Record lowest stack address and return address */
++ Storeglobal(1, caml_bottom_of_stack, 12)
++ Storeglobal(25, caml_last_return_address, 12)
++ /* Make the exception handler and alloc ptr available to the C code */
++ Storeglobal(31, caml_young_ptr, 11)
++ Storeglobal(29, caml_exception_pointer, 11)
++ /* Call the function (address in link register) */
++ blrl
++ /* Restore return address (in 25, preserved by the C function) */
++ mtlr 25
++ /* Reload allocation pointer and allocation limit*/
++ Loadglobal(31, caml_young_ptr, 11)
++ Loadglobal(30, caml_young_limit, 11)
++ /* Say we are back into Caml code */
++ li 12, 0
++ Storeglobal(12, caml_last_return_address, 11)
++ /* Return to caller */
++ blr
++ .cfi_endproc
++ .size .L.caml_c_call,.-.L.caml_c_call
++
++/* Raise an exception from C */
++
++ .globl caml_raise_exception
++ .type caml_raise_exception, @function
++ .section ".opd","aw"
++ .align 3
++caml_raise_exception:
++ .quad .L.caml_raise_exception,.TOC.@tocbase
++ .previous
++ .align 2
++.L.caml_raise_exception:
++ /* Reload Caml global registers */
++ Loadglobal(29, caml_exception_pointer, 11)
++ Loadglobal(31, caml_young_ptr, 11)
++ Loadglobal(30, caml_young_limit, 11)
++ /* Say we are back into Caml code */
++ li 0, 0
++ Storeglobal(0, caml_last_return_address, 11)
++ /* Pop trap frame */
++ ld 0, 8(29)
++ ld 1, 16(29)
++ mtlr 0
++ ld 2, 24(29)
++ ld 29, 0(29)
++ /* Branch to handler */
++ blr
++ .size .L.caml_raise_exception,.-.L.caml_raise_exception
++
++/* Start the Caml program */
++
++ .globl caml_start_program
++ .type caml_start_program, @function
++ .section ".opd","aw"
++ .align 3
++caml_start_program:
++ .quad .L.caml_start_program,.TOC.@tocbase
++ .previous
++ .align 2
++.L.caml_start_program:
++ Addrglobal(12, caml_program)
++
++/* Code shared between caml_start_program and caml_callback */
++.L102:
++ /* Allocate and link stack frame */
++ mflr 0
++ std 0, 16(1)
++ stdu 1, -0x190(1) /* 48 + 8*36(regs) + 32(callback) + 32(exc) */
++ /* Save return address */
++ /* Save all callee-save registers */
++ /* GPR 14 ... GPR 31 then FPR 14 ... FPR 31 starting at sp+16 */
++ addi 11, 1, 48-8
++ stdu 14, 8(11)
++ stdu 15, 8(11)
++ stdu 16, 8(11)
++ stdu 17, 8(11)
++ stdu 18, 8(11)
++ stdu 19, 8(11)
++ stdu 20, 8(11)
++ stdu 21, 8(11)
++ stdu 22, 8(11)
++ stdu 23, 8(11)
++ stdu 24, 8(11)
++ stdu 25, 8(11)
++ stdu 26, 8(11)
++ stdu 27, 8(11)
++ stdu 28, 8(11)
++ stdu 29, 8(11)
++ stdu 30, 8(11)
++ stdu 31, 8(11)
++ stfdu 14, 8(11)
++ stfdu 15, 8(11)
++ stfdu 16, 8(11)
++ stfdu 17, 8(11)
++ stfdu 18, 8(11)
++ stfdu 19, 8(11)
++ stfdu 20, 8(11)
++ stfdu 21, 8(11)
++ stfdu 22, 8(11)
++ stfdu 23, 8(11)
++ stfdu 24, 8(11)
++ stfdu 25, 8(11)
++ stfdu 26, 8(11)
++ stfdu 27, 8(11)
++ stfdu 28, 8(11)
++ stfdu 29, 8(11)
++ stfdu 30, 8(11)
++ stfdu 31, 8(11)
++ /* Set up a callback link */
++ Loadglobal(9, caml_bottom_of_stack, 11)
++ Loadglobal(10, caml_last_return_address, 11)
++ Loadglobal(11, caml_gc_regs, 11)
++ std 9, 0x150(1)
++ std 10, 0x158(1)
++ std 11, 0x160(1)
++ /* Build an exception handler to catch exceptions escaping out of Caml */
++ bl .L103
++ b .L104
++.L103:
++ mflr 0
++ addi 29, 1, 0x170 /* Alignment */
++ std 0, 8(29)
++ std 1, 16(29)
++ std 2, 24(29)
++ Loadglobal(11, caml_exception_pointer, 11)
++ std 11, 0(29)
++ /* Reload allocation pointers */
++ Loadglobal(31, caml_young_ptr, 11)
++ Loadglobal(30, caml_young_limit, 11)
++ /* Say we are back into Caml code */
++ li 0, 0
++ Storeglobal(0, caml_last_return_address, 11)
++ /* Call the Caml code */
++ std 2,40(1)
++ ld 2,8(12)
++ ld 12,0(12)
++ mtlr 12
++.L105:
++ blrl
++ ld 2,40(1)
++ /* Pop the trap frame, restoring caml_exception_pointer */
++ ld 9, 0x170(1)
++ Storeglobal(9, caml_exception_pointer, 11)
++ /* Pop the callback link, restoring the global variables */
++.L106:
++ ld 9, 0x150(1)
++ ld 10, 0x158(1)
++ ld 11, 0x160(1)
++ Storeglobal(9, caml_bottom_of_stack, 12)
++ Storeglobal(10, caml_last_return_address, 12)
++ Storeglobal(11, caml_gc_regs, 12)
++ /* Update allocation pointer */
++ Storeglobal(31, caml_young_ptr, 11)
++ /* Restore callee-save registers */
++ addi 11, 1, 48-8
++ ldu 14, 8(11)
++ ldu 15, 8(11)
++ ldu 16, 8(11)
++ ldu 17, 8(11)
++ ldu 18, 8(11)
++ ldu 19, 8(11)
++ ldu 20, 8(11)
++ ldu 21, 8(11)
++ ldu 22, 8(11)
++ ldu 23, 8(11)
++ ldu 24, 8(11)
++ ldu 25, 8(11)
++ ldu 26, 8(11)
++ ldu 27, 8(11)
++ ldu 28, 8(11)
++ ldu 29, 8(11)
++ ldu 30, 8(11)
++ ldu 31, 8(11)
++ lfdu 14, 8(11)
++ lfdu 15, 8(11)
++ lfdu 16, 8(11)
++ lfdu 17, 8(11)
++ lfdu 18, 8(11)
++ lfdu 19, 8(11)
++ lfdu 20, 8(11)
++ lfdu 21, 8(11)
++ lfdu 22, 8(11)
++ lfdu 23, 8(11)
++ lfdu 24, 8(11)
++ lfdu 25, 8(11)
++ lfdu 26, 8(11)
++ lfdu 27, 8(11)
++ lfdu 28, 8(11)
++ lfdu 29, 8(11)
++ lfdu 30, 8(11)
++ lfdu 31, 8(11)
++ /* Return */
++ ld 1,0(1)
++ /* Reload return address */
++ ld 0, 16(1)
++ mtlr 0
++ blr
++
++ /* The trap handler: */
++.L104:
++ /* Update caml_exception_pointer */
++ Storeglobal(29, caml_exception_pointer, 11)
++ /* Encode exception bucket as an exception result and return it */
++ ori 3, 3, 2
++ b .L106
++ .size .L.caml_start_program,.-.L.caml_start_program
++
++/* Callback from C to Caml */
++
++ .globl caml_callback_exn
++ .type caml_callback_exn, @function
++ .section ".opd","aw"
++ .align 3
++caml_callback_exn:
++ .quad .L.caml_callback_exn,.TOC.@tocbase
++ .previous
++ .align 2
++.L.caml_callback_exn:
++ /* Initial shuffling of arguments */
++ mr 0, 3 /* Closure */
++ mr 3, 4 /* Argument */
++ mr 4, 0
++ ld 12, 0(4) /* Code pointer */
++ b .L102
++ .size .L.caml_callback_exn,.-.L.caml_callback_exn
++
++
++ .globl caml_callback2_exn
++ .type caml_callback2_exn, @function
++ .section ".opd","aw"
++ .align 3
++caml_callback2_exn:
++ .quad .L.caml_callback2_exn,.TOC.@tocbase
++ .previous
++ .align 2
++.L.caml_callback2_exn:
++ mr 0, 3 /* Closure */
++ mr 3, 4 /* First argument */
++ mr 4, 5 /* Second argument */
++ mr 5, 0
++ Addrglobal(12, caml_apply2)
++ b .L102
++ .size .L.caml_callback2_exn,.-.L.caml_callback2_exn
++
++
++ .globl caml_callback3_exn
++ .type caml_callback3_exn, @function
++ .section ".opd","aw"
++ .align 3
++caml_callback3_exn:
++ .quad .L.caml_callback3_exn,.TOC.@tocbase
++ .previous
++ .align 2
++.L.caml_callback3_exn:
++ mr 0, 3 /* Closure */
++ mr 3, 4 /* First argument */
++ mr 4, 5 /* Second argument */
++ mr 5, 6 /* Third argument */
++ mr 6, 0
++ Addrglobal(12, caml_apply3)
++ b .L102
++ .size .L.caml_callback3_exn,.-.L.caml_callback3_exn
++
++/* Frame table */
++
++ .section ".data"
++ .globl caml_system__frametable
++ .type caml_system__frametable, @object
++caml_system__frametable:
++ .quad 1 /* one descriptor */
++ .quad .L105 + 4 /* return address into callback */
++ .short -1 /* negative size count => use callback link */
++ .short 0 /* no roots here */
++ .align 3
++
+diff -uNr ocaml-3.10.1/asmrun/stack.h ocaml-3.10.1.ppc64/asmrun/stack.h
+--- ocaml-3.10.1/asmrun/stack.h 2007-02-15 13:35:20.000000000 -0500
++++ ocaml-3.10.1.ppc64/asmrun/stack.h 2008-02-29 08:37:45.000000000 -0500
+@@ -65,6 +65,15 @@
+ #define Callback_link(sp) ((struct caml_context *)((sp) + Trap_frame_size))
+ #endif
+
++#ifdef TARGET_power64
++#define Saved_return_address(sp) *((intnat *)((sp) +16))
++#define Already_scanned(sp, retaddr) ((retaddr) & 1)
++#define Mark_scanned(sp, retaddr) (Saved_return_address(sp) = (retaddr) | 1)
++#define Mask_already_scanned(retaddr) ((retaddr) & ~1)
++#define Trap_frame_size 0x150
++#define Callback_link(sp) ((struct caml_context *)((sp) + Trap_frame_size))
++#endif
++
+ #ifdef TARGET_m68k
+ #define Saved_return_address(sp) *((intnat *)((sp) - 4))
+ #define Callback_link(sp) ((struct caml_context *)((sp) + 8))
+diff -uNr ocaml-3.11.0+beta1/configure ocaml-3.11.0+beta1.ppc64/configure
+--- ocaml-3.11.0+beta1/configure.ppc64 2008-11-18 15:46:57.000000000 +0000
++++ ocaml-3.11.0+beta1/configure 2008-11-18 15:49:19.000000000 +0000
+@@ -632,6 +632,7 @@
+ hppa2.0*-*-hpux*) arch=hppa; system=hpux;;
+ hppa*-*-linux*) arch=hppa; system=linux;;
+ hppa*-*-gnu*) arch=hppa; system=gnu;;
++ powerpc64-*-linux*) arch=power64; model=ppc64; system=elf;;
+ powerpc*-*-linux*) arch=power; model=ppc; system=elf;;
+ powerpc-*-netbsd*) arch=power; model=ppc; system=elf;;
+ powerpc-*-rhapsody*) arch=power; model=ppc; system=rhapsody;;
+@@ -655,7 +656,7 @@
+
+ if $arch64; then
+ case "$arch,$model" in
+- sparc,default|mips,default|hppa,default|power,ppc)
++ sparc,default|mips,default|hppa,default)
+ arch=none; model=default; system=unknown;;
+ esac
+ fi
+@@ -712,6 +713,8 @@
+ aspp='as -n32 -O2';;
+ power,*,elf) as='as -u -m ppc'
+ aspp='gcc -c';;
++ power64,*,elf) as='as -u -m ppc64'
++ aspp='gcc -c';;
+ power,*,bsd) as='as'
+ aspp='gcc -c';;
+ power,*,rhapsody) as="as -arch $model"