1964N/APatch from Fedora spec-file to add powerpc support. This patch was rejected by
1964N/Aupstream. This may not be needed on Solaris, but keeping it for consistency
1964N/A+(***********************************************************************)
1964N/A+(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
1964N/A+(* Copyright 1996 Institut National de Recherche en Informatique et *)
1964N/A+(* en Automatique. All rights reserved. This file is distributed *)
1964N/A+(* under the terms of the Q Public License version 1.0. *)
1964N/A+(***********************************************************************)
1964N/A+(* Specific operations for the PowerPC processor *)
1964N/A+(* Machine-specific command-line options *)
1964N/A+let command_line_options = []
1964N/A+ Imultaddf (* multiply and add *)
1964N/A+ | Imultsubf (* multiply and subtract *)
1964N/A+ | Ialloc_far of int (* allocation in large functions *)
1964N/A+ Ibased of string * int (* symbol + displ *)
1964N/A+ | Iindexed of int (* reg + displ *)
1964N/A+ | Iindexed2 (* reg + reg *)
1964N/A+(* Operations on addressing modes *)
1964N/A+let identity_addressing = Iindexed 0
1964N/A+let offset_addressing addr delta =
1964N/A+ Ibased(s, n) -> Ibased(s, n + delta)
1964N/A+ | Iindexed n -> Iindexed(n + delta)
1964N/A+ | Iindexed2 -> assert false
1964N/A+let num_args_addressing = function
1964N/A+(* Printing operations and addressing modes *)
1964N/A+let print_addressing printreg addr ppf arg =
1964N/A+ fprintf ppf "\"%s\"%s" s idx
1964N/A+ fprintf ppf "%a%s" printreg arg.(0) idx
1964N/A+ fprintf ppf "%a + %a" printreg arg.(0) printreg arg.(1)
1964N/A+let print_specific_operation printreg op ppf arg =
1964N/A+ fprintf ppf "%a *f %a +f %a"
1964N/A+ printreg arg.(0) printreg arg.(1) printreg arg.(2)
1964N/A+ fprintf ppf "%a *f %a -f %a"
1964N/A+ printreg arg.(0) printreg arg.(1) printreg arg.(2)
1964N/A+ fprintf ppf "alloc_far %d" n
1964N/A+(***********************************************************************)
1964N/A+(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
1964N/A+(* Copyright 1996 Institut National de Recherche en Informatique et *)
1964N/A+(* en Automatique. All rights reserved. This file is distributed *)
1964N/A+(* under the terms of the Q Public License version 1.0. *)
1964N/A+(***********************************************************************)
1964N/A+(* Emission of PowerPC assembly code *)
1964N/A+module StringSet =
Set.Make(struct type t = string let compare = compare end)
1964N/A+(* Layout of the stack. The stack is kept 16-aligned. *)
1964N/A+let stack_args_size = ref 0
1964N/A+let stack_traps_size = ref 0
1964N/A+(* We have a stack frame of our own if we call other functions (including
1964N/A+ use of exceptions, or if we need more than the red zone *)
1964N/A+ if !contains_calls or (num_stack_slots.(0) + num_stack_slots.(1)) > (288-16)/8 then
1964N/A+let frame_size_sans_args () =
1964N/A+ let size = 8 * num_stack_slots.(0) + 8 * num_stack_slots.(1) + 48 in
1964N/A+ then (!stack_slot_lbl, num_stack_slots.(1) * 8 + n * 8)
1964N/A+ else (!stack_slot_lbl, n * 8)
1964N/A+ | Incoming n -> ((if has_stack_frame() then !stack_size_lbl else 0), 48 + n)
1964N/A+ emit_string label_prefix; emit_int lbl
1964N/A+ | "elf" | "bsd" -> " .section \".toc\",\"aw\"\n"
1964N/A+ | "elf" | "bsd" -> " .section \".data\"\n"
1964N/A+ | "rhapsody" -> " .data\n"
1964N/A+ | "elf" | "bsd" -> " .section \".text\"\n"
1964N/A+ | "rhapsody" -> " .text\n"
1964N/A+ | "elf" | "bsd" -> " .section \".rodata\"\n"
1964N/A+ | "rhapsody" -> " .const\n"
1964N/A+(* Output a pseudo-register *)
1964N/A+ Reg r -> emit_string (register_name r)
1964N/A+ if use_full_regnames then emit_char 'r';
1964N/A+ if use_full_regnames then emit_char 'f';
1964N/A+ if use_full_regnames then emit_string "cr";
1964N/A+(* Output a stack reference *)
1964N/A+ let lbl, ofs = slot_offset s (register_class r) in
1964N/A+ `{emit_int ofs}({emit_gpr 1})`
1964N/A+(* Split a 32-bit integer constants in two 16-bit halves *)
1964N/A+let is_native_immediate n =
1964N/A+ n <= 32767n && n >= -32768n
1964N/A+ TocSymOfs of (string * int)
1964N/A+(* List of all labels in tocref (reverse order) *)
1964N/A+let tocref_entries = ref []
1964N/A+(* Output a TOC reference *)
1964N/A+let emit_symbol_offset (s, d) =
1964N/A+ TocSymOfs(s,d) -> emit_symbol_offset(s,d)
1964N/A+ | TocInt i -> emit_nativeint i
1964N/A+ | TocFloat f -> emit_string f
1964N/A+ | TocLabel lbl -> emit_label lbl
1964N/A+ let rec tocref_label = function
1964N/A+ tocref_entries := (lbl, content) :: !tocref_entries;
1964N/A+ | ( (lbl, o_content) :: lst, content) ->
1964N/A+ if content = o_content then
1964N/A+ tocref_label (lst, content)
1964N/A+ let lbl = tocref_label (!tocref_entries,entry) in
1964N/A+ emit_label lbl; emit_string "@toc(2) #"; emit_tocentry entry
1964N/A+(* Output a load or store operation *)
1964N/A+let valid_offset instr ofs =
1964N/A+ ofs land 3 = 0 || (instr <> "ld" && instr <> "std")
1964N/A+let emit_load_store instr addressing_mode addr n arg =
1964N/A+ match addressing_mode with
1964N/A+ let dd = (d + 0x8000) in (* We can only offset by -0x8000 .. +0x7fff *)
1964N/A+ let a = (dd land -0x10000) in
1964N/A+ let b = (dd land 0xffff) - 0x8000 in
1964N/A+ ` ld {emit_gpr 11}, {emit_tocref (TocSymOfs (s,a))}\n`;
1964N/A+ ` {emit_string instr} {emit_reg arg}, {emit_int b}({emit_gpr 11})\n`
1964N/A+ if is_immediate ofs && valid_offset instr ofs then
1964N/A+ ` {emit_string instr} {emit_reg arg}, {emit_int ofs}({emit_reg addr.(n)})\n`
1964N/A+ ` lis {emit_gpr 0}, {emit_int(high ofs)}\n`;
1964N/A+ ` ori {emit_gpr 0}, {emit_gpr 0}, {emit_int(low ofs)}\n`;
1964N/A+ ` {emit_string instr}x {emit_reg arg}, {emit_reg addr.(n)}, {emit_gpr 0}\n`
1964N/A+ ` {emit_string instr}x {emit_reg arg}, {emit_reg addr.(n)}, {emit_reg addr.(n+1)}\n`
1964N/A+(* After a comparison, extract the result as 0 or 1 *)
1964N/A+let emit_set_comp cmp res =
1964N/A+` rlwinm {emit_reg res}, {emit_gpr 0}, {emit_int(bitnum+1)}, 31, 31\n`;
1964N/A+ Cne | Cle | Cge -> ` xori {emit_reg res}, {emit_reg res}, 1\n`
1964N/A+(* Record live pointers at call points *)
1964N/A+ { fd_lbl: int; (* Return address *)
1964N/A+ fd_frame_size_lbl: int; (* Size of stack frame *)
1964N/A+let frame_descriptors = ref([] : frame_descr list)
1964N/A+ let live_offset = ref [] in
1964N/A+ {typ = Addr; loc = Reg r} ->
1964N/A+ live_offset := (0, (r lsl 1) + 1) :: !live_offset
1964N/A+ | {typ = Addr; loc = Stack s} as reg ->
1964N/A+ live_offset := slot_offset s (register_class reg) :: !live_offset
1964N/A+ fd_frame_size_lbl = !stack_size_lbl; (* frame_size *)
1964N/A+ fd_live_offset = !live_offset } :: !frame_descriptors;
1964N/A+ if lbl > 0 then `{emit_label lbl}+`;
1964N/A+(* Record external C functions to be called in a position-independent way
1964N/A+ ` .non_lazy_symbol_pointer\n`;
1964N/A+ `L{emit_symbol s}$non_lazy_ptr:\n`;
1964N/A+ ` .indirect_symbol {emit_symbol s}\n`;
1964N/A+(* Names for conditional branches after comparisons *)
1964N/A+let branch_for_comparison = function
1964N/A+ Ceq -> "beq" | Cne -> "bne"
1964N/A+ | Cle -> "ble" | Cgt -> "bgt"
1964N/A+ | Cge -> "bge" | Clt -> "blt"
1964N/A+let name_for_int_comparison = function
1964N/A+ Isigned cmp -> ("cmpd", branch_for_comparison cmp)
1964N/A+ | Iunsigned cmp -> ("cmpld", branch_for_comparison cmp)
1964N/A+(* Names for various instructions *)
1964N/A+let name_for_intop = function
1964N/A+let name_for_intop_imm = function
1964N/A+let name_for_floatop1 = function
1964N/A+let name_for_floatop2 = function
1964N/A+let name_for_specific = function
1964N/A+(* Name of current function *)
1964N/A+(* Entry point for tail recursive calls *)
1964N/A+let tailrec_entry_point = ref 0
1964N/A+(* Names of functions defined in the current file *)
1964N/A+(* Label of glue code for calling the GC *)
1964N/A+(* List of all labels in jumptable (reverse order) *)
1964N/A+let jumptbl_entries = ref []
1964N/A+(* Number of jumptable entries *)
1964N/A+let num_jumptbl_entries = ref 0
1964N/A+(* Fixup conditional branches that exceed hardware allowed range *)
1964N/A+let load_store_size = function
1964N/A+ | Iindexed ofs -> if is_immediate ofs then 1 else 3
1964N/A+ | Lop(Imove | Ispill | Ireload) -> 1
1964N/A+ | Lop(Iconst_int n) -> if is_native_immediate n then 1 else 2
1964N/A+ | Lop(Iconst_float s) -> 2
1964N/A+ | Lop(Iconst_symbol s) -> 2
1964N/A+ | Lop(Itailcall_ind) -> if !contains_calls then 7 else if has_stack_frame() then 5 else 4
1964N/A+ | Lop(Itailcall_imm s) -> if s = !function_name then 1 else
1964N/A+ if !contains_calls then 8 else
1964N/A+ if has_stack_frame() then 6 else 5
1964N/A+ | Lop(Iextcall(s, true)) -> 8
1964N/A+ | Lop(Iextcall(s, false)) -> 7
1964N/A+ | Lop(Istackoffset n) -> 0
1964N/A+ | Lop(Iload(chunk, addr)) ->
1964N/A+ then load_store_size addr + 1
1964N/A+ | Lop(Istore(chunk, addr)) -> load_store_size addr
1964N/A+ | Lop(Ispecific(Ialloc_far n)) -> 5
1964N/A+ | Lop(Iintop(Icomp cmp)) -> 4
1964N/A+ | Lop(Iintop_imm(Idiv, n)) -> 2
1964N/A+ | Lop(Iintop_imm(Imod, n)) -> 4
1964N/A+ | Lop(Iintop_imm(Icomp cmp, n)) -> 4
1964N/A+ | Lop(Iintop_imm(op, n)) -> 1
1964N/A+ | Lop(Inegf | Iabsf | Iaddf | Isubf | Imulf | Idivf) -> 1
1964N/A+ | Lreturn -> if has_stack_frame() then 2 else 1
1964N/A+ | Lcondbranch(tst, lbl) -> 2
1964N/A+ | Lcondbranch3(lbl0, lbl1, lbl2) ->
1964N/A+ 1 + (if lbl0 = None then 0 else 1)
1964N/A+ + (if lbl1 = None then 0 else 1)
1964N/A+ + (if lbl2 = None then 0 else 1)
1964N/A+ let rec fill_map pc instr =
1964N/A+let max_branch_offset = 8180
1964N/A+(* 14-bit signed offset in words. Remember to cut some slack
1964N/A+ for multi-word instructions where the branch can be anywhere in
1964N/A+ the middle. 12 words of slack is plenty. *)
1964N/A+let branch_overflows map pc_branch lbl_dest =
1964N/A+ let delta = pc_dest - (pc_branch + 1) in
1964N/A+ delta <= -max_branch_offset || delta >= max_branch_offset
1964N/A+let opt_branch_overflows map pc_branch opt_lbl_dest =
1964N/A+ | Some lbl_dest -> branch_overflows map pc_branch lbl_dest
1964N/A+let fixup_branches codesize map code =
1964N/A+ let expand_optbranch lbl n arg next =
1964N/A+ instr_cons (Lcondbranch(Iinttest_imm(Isigned Ceq, n), l))
1964N/A+ let rec fixup did_fix pc instr =
1964N/A+ | Lcondbranch(test, lbl) when branch_overflows map pc lbl ->
1964N/A+ instr_cons (Lbranch lbl) [||] [||]
1964N/A+ | Lcondbranch3(lbl0, lbl1, lbl2)
1964N/A+ when opt_branch_overflows map pc lbl0
1964N/A+ || opt_branch_overflows map pc lbl1
1964N/A+ || opt_branch_overflows map pc lbl2 ->
1964N/A+ | Lop(Ialloc n) when codesize - pc >= max_branch_offset ->
1964N/A+(* Iterate branch expansion till all conditional branches are OK *)
1964N/A+let rec branch_normalization code =
1964N/A+ let (codesize, map) = label_map code in
1964N/A+ if codesize >= max_branch_offset && fixup_branches codesize map code
1964N/A+ then branch_normalization code
1964N/A+(* Output the assembly code for an instruction *)
1964N/A+let rec emit_instr i dslot =
1964N/A+ | Lop(Imove | Ispill | Ireload) ->
1964N/A+ {loc = Reg rs; typ = (Int | Addr)}, {loc = Reg rd} ->
1964N/A+ ` mr {emit_reg dst}, {emit_reg src}\n`
1964N/A+ | {loc = Reg rs; typ = Float}, {loc = Reg rd; typ = Float} ->
1964N/A+ ` fmr {emit_reg dst}, {emit_reg src}\n`
1964N/A+ | {loc = Reg rs; typ = (Int | Addr)}, {loc = Stack sd} ->
1964N/A+ ` std {emit_reg src}, {emit_stack dst}\n`
1964N/A+ | {loc = Reg rs; typ = Float}, {loc = Stack sd} ->
1964N/A+ ` stfd {emit_reg src}, {emit_stack dst}\n`
1964N/A+ | {loc = Stack ss; typ = (Int | Addr)}, {loc = Reg rd} ->
1964N/A+ ` ld {emit_reg dst}, {emit_stack src}\n`
1964N/A+ | {loc = Stack ss; typ = Float}, {loc = Reg rd} ->
1964N/A+ ` lfd {emit_reg dst}, {emit_stack src}\n`
1964N/A+ if is_native_immediate n then
1964N/A+ else if n >= -0x8000_0000n && n <= 0x7FFF_FFFFn then begin
1964N/A+ ` lis {emit_reg
i.res.(0)}, {emit_int(nativehigh n)}\n`;
1964N/A+ ` lfd {emit_reg
i.res.(0)}, {emit_tocref (TocFloat s)}\n`
1964N/A+ ` ld {emit_reg
i.res.(0)}, {emit_tocref (TocSymOfs (s,0))}\n`
1964N/A+ ` std {emit_gpr 2},40({emit_gpr 1})\n`;
1964N/A+ ` ld {emit_gpr 2},40({emit_gpr 1})\n`
1964N/A+ ` ld {emit_gpr 11}, {emit_tocref (TocSymOfs (s,0))}\n`;
1964N/A+ ` std {emit_gpr 2},40({emit_gpr 1})\n`;
1964N/A+ ` ld {emit_gpr 2}, 8({emit_gpr 11})\n`;
1964N/A+ ` ld {emit_gpr 11}, 0({emit_gpr 11})\n`;
1964N/A+ ` ld {emit_gpr 2},40({emit_gpr 1})\n`
1964N/A+ ` ld {emit_gpr 1}, 0({emit_gpr 1})\n`;
1964N/A+ if !contains_calls then begin
1964N/A+ ` ld {emit_gpr 11}, 16({emit_gpr 1})\n`;
1964N/A+ if s = !function_name then
1964N/A+ ` b {emit_label !tailrec_entry_point}\n`
1964N/A+ ` ld {emit_gpr 1}, 0({emit_gpr 1})\n`;
1964N/A+ if !contains_calls then begin
1964N/A+ ` ld {emit_gpr 11}, 16({emit_gpr 1})\n`;
1964N/A+ ` ld {emit_gpr 11}, {emit_tocref (TocSymOfs (s,0))}\n`;
1964N/A+ ` ld {emit_gpr 2}, 8({emit_gpr 11})\n`;
1964N/A+ ` ld {emit_gpr 11}, 0({emit_gpr 11})\n`;
1964N/A+ | Lop(Iextcall(s, alloc)) ->
1964N/A+ ` ld {emit_gpr 11}, {emit_tocref (TocSymOfs (s,0))}\n`;
1964N/A+ ` ld {emit_gpr 12}, {emit_tocref (TocSymOfs ("caml_c_call",0))}\n`;
1964N/A+ ` ld {emit_gpr 12}, {emit_tocref (TocSymOfs (s,0))}\n`;
1964N/A+ ` std {emit_gpr 2}, 40({emit_gpr 1})\n`;
1964N/A+ ` ld {emit_gpr 2}, 8({emit_gpr 12})\n`;
1964N/A+ ` ld {emit_gpr 12}, 0({emit_gpr 12})\n`;
1964N/A+ ` ld {emit_gpr 2}, 40({emit_gpr 1})\n`
1964N/A+ if n > !stack_args_size then
1964N/A+ | Lop(Iload(chunk, addr)) ->
1964N/A+ | Sixteen_unsigned -> "lhz"
1964N/A+ | Thirtytwo_unsigned -> "lwz"
1964N/A+ | Thirtytwo_signed -> "lwa"
1964N/A+ | Double | Double_u -> "lfd" in
1964N/A+ if chunk = Byte_signed then
1964N/A+ | Lop(Istore(chunk, addr)) ->
1964N/A+ Byte_unsigned | Byte_signed -> "stb"
1964N/A+ | Sixteen_unsigned | Sixteen_signed -> "sth"
1964N/A+ | Thirtytwo_unsigned | Thirtytwo_signed -> "stw"
1964N/A+ | Double | Double_u -> "stfd" in
1964N/A+ if !call_gc_label = 0 then call_gc_label := new_label();
1964N/A+ ` addi {emit_gpr 31}, {emit_gpr 31}, {emit_int(-n)}\n`;
1964N/A+ ` cmpld {emit_gpr 31}, {emit_gpr 30}\n`;
1964N/A+ ` bltl {emit_label !call_gc_label}\n` (* Must be 4 insns to restart *)
1964N/A+ | Lop(Ispecific(Ialloc_far n)) ->
1964N/A+ if !call_gc_label = 0 then call_gc_label := new_label();
1964N/A+ ` addi {emit_gpr 31}, {emit_gpr 31}, {emit_int(-n)}\n`;
1964N/A+ ` cmpld {emit_gpr 31}, {emit_gpr 30}\n`;
1964N/A+ ` bge {emit_label lbl}\n`;
1964N/A+ ` bl {emit_label !call_gc_label}\n`; (* Must be 4 insns to restart *)
1964N/A+ `{emit_label lbl}: addi {emit_reg
i.res.(0)}, {emit_gpr 31}, 4\n`
1964N/A+ | Lop(Iintop Isub) -> (* subfc has swapped arguments *)
1964N/A+ ` mulld {emit_gpr 0}, {emit_gpr 0}, {emit_reg
i.arg.(1)}\n`;
1964N/A+ | Lop(Iintop(Icomp cmp)) ->
1964N/A+ | Lop(Iintop Icheckbound) ->
1964N/A+ let instr = name_for_intop op in
1964N/A+ | Lop(Iintop_imm(Isub, n)) ->
1964N/A+ | Lop(Iintop_imm(Idiv, n)) -> (* n is guaranteed to be a power of 2 *)
1964N/A+ | Lop(Iintop_imm(Imod, n)) -> (* n is guaranteed to be a power of 2 *)
1964N/A+ ` sradi {emit_gpr 0}, {emit_reg
i.arg.(0)}, {emit_int l}\n`;
1964N/A+ ` addze {emit_gpr 0}, {emit_gpr 0}\n`;
1964N/A+ ` sldi {emit_gpr 0}, {emit_gpr 0}, {emit_int l}\n`;
1964N/A+ | Lop(Iintop_imm(Icomp cmp, n)) ->
1964N/A+ | Lop(Iintop_imm(Icheckbound, n)) ->
1964N/A+ | Lop(Iintop_imm(op, n)) ->
1964N/A+ let instr = name_for_intop_imm op in
1964N/A+ | Lop(Inegf | Iabsf as op) ->
1964N/A+ let instr = name_for_floatop1 op in
1964N/A+ | Lop(Iaddf | Isubf | Imulf | Idivf as op) ->
1964N/A+ let instr = name_for_floatop2 op in
1964N/A+ let ofs = if has_stack_frame() then 16 else 8 * (2 + num_stack_slots.(0) + num_stack_slots.(1)) in
1964N/A+ ` std {emit_reg
i.arg.(0)}, -{emit_int ofs}({emit_gpr 1})\n`;
1964N/A+ ` lfd {emit_reg
i.res.(0)}, -{emit_int ofs}({emit_gpr 1})\n`;
1964N/A+ let ofs = if has_stack_frame() then 16 else 8 * (2 + num_stack_slots.(0) + num_stack_slots.(1)) in
1964N/A+ ` stfd {emit_fpr 0}, -{emit_int ofs}({emit_gpr 1})\n`;
1964N/A+ ` ld {emit_reg
i.res.(0)}, -{emit_int ofs}({emit_gpr 1})\n`
1964N/A+ let instr = name_for_specific sop in
1964N/A+ if has_stack_frame() then begin
1964N/A+ ` ld {emit_gpr 11}, {emit_label !stack_size_lbl}+16({emit_gpr 1})\n`;
1964N/A+ ` ld {emit_gpr 1}, 0({emit_gpr 1})\n`;
1964N/A+ | Lcondbranch(tst, lbl) ->
1964N/A+ let (comp, branch) = name_for_int_comparison cmp in
1964N/A+ ` {emit_string branch} {emit_label lbl}\n`
1964N/A+ let (comp, branch) = name_for_int_comparison cmp in
1964N/A+ ` {emit_string comp}i {emit_reg
i.arg.(0)}, {emit_int n}\n`;
1964N/A+ ` {emit_string branch} {emit_label lbl}\n`
1964N/A+ (* bit 0 = lt, bit 1 = gt, bit 2 = eq *)
1964N/A+ | Cle -> ` cror 3, 0, 2\n`; (* lt or eq *)
1964N/A+ | Cge -> ` cror 3, 1, 2\n`; (* gt or eq *)
1964N/A+ then ` bf {emit_int bitnum}, {emit_label lbl}\n`
1964N/A+ else ` bt {emit_int bitnum}, {emit_label lbl}\n`
1964N/A+ | Lcondbranch3(lbl0, lbl1, lbl2) ->
1964N/A+ | Some lbl -> ` blt {emit_label lbl}\n`
1964N/A+ | Some lbl -> ` beq {emit_label lbl}\n`
1964N/A+ | Some lbl -> ` bgt {emit_label lbl}\n`
1964N/A+ if !lbl_jumptbl = 0 then lbl_jumptbl := new_label();
1964N/A+ ` ld {emit_gpr 11}, {emit_tocref (TocLabel !lbl_jumptbl)}\n`;
1964N/A+ ` addi {emit_gpr 0}, {emit_reg
i.arg.(0)}, {emit_int !num_jumptbl_entries}\n`;
1964N/A+ ` sldi {emit_gpr 0}, {emit_gpr 0}, 2\n`;
1964N/A+ ` lwax {emit_gpr 0}, {emit_gpr 11}, {emit_gpr 0}\n`;
1964N/A+ ` add {emit_gpr 0}, {emit_gpr 11}, {emit_gpr 0}\n`;
1964N/A+ jumptbl_entries := jumptbl.(i) :: !jumptbl_entries;
1964N/A+ stack_traps_size := !stack_traps_size + 32;
1964N/A+ ` addi {emit_gpr 11}, {emit_gpr 1}, {emit_label !stack_size_lbl}-{emit_int !stack_traps_size}\n`;
1964N/A+ ` std {emit_gpr 29}, 0({emit_gpr 11})\n`;
1964N/A+ ` std {emit_gpr 0}, 8({emit_gpr 11})\n`;
1964N/A+ ` std {emit_gpr 1}, 16({emit_gpr 11})\n`;
1964N/A+ ` std {emit_gpr 2}, 24({emit_gpr 11})\n`;
1964N/A+ ` mr {emit_gpr 29}, {emit_gpr 11}\n`
1964N/A+ ` ld {emit_gpr 29}, 0({emit_gpr 29})\n`
1964N/A+ ` ld {emit_gpr 0}, 8({emit_gpr 29})\n`;
1964N/A+ ` ld {emit_gpr 1}, 16({emit_gpr 29})\n`;
1964N/A+ ` ld {emit_gpr 2}, 24({emit_gpr 29})\n`;
1964N/A+ ` ld {emit_gpr 29}, 0({emit_gpr 29})\n`;
1964N/A+ | Some i -> emit_instr i None
1964N/A+(* Checks if a pseudo-instruction expands to instructions
1964N/A+ that do not branch and do not affect CR0 nor R12. *)
1964N/A+ Icall_imm _ | Icall_ind | Itailcall_imm _ | Itailcall_ind |
1964N/A+ | Iintop(Icomp _) -> false
1964N/A+ | Iintop_imm(Iand, _) -> false
1964N/A+ | Iintop_imm(Icomp _, _) -> false
1964N/A+let no_interference res arg =
1964N/A+ if arg.(i).loc = res.(j).loc then raise Exit
1964N/A+(* Emit a sequence of instructions, trying to fill delay slots for branches *)
1964N/A+ | {next = {desc = (Lcondbranch(_, _) | Lcondbranch3(_, _, _))}}
1964N/A+(* Emission of a function declaration *)
1964N/A+ tailrec_entry_point := new_label();
1964N/A+ stack_size_lbl := new_label();
1964N/A+ stack_slot_lbl := new_label();
1964N/A+ ` .section \".opd\",\"aw\"\n`;
1964N/A+ if !contains_calls then begin
1964N/A+ ` std {emit_gpr 0}, 16({emit_gpr 1})\n`
1964N/A+ ` stdu {emit_gpr 1}, -{emit_label !stack_size_lbl}({emit_gpr 1})\n`;
1964N/A+ `{emit_label !tailrec_entry_point}:\n`;
1964N/A+ if has_stack_frame() then begin
1964N/A+ ` .set {emit_label !stack_size_lbl},{emit_int (frame_size_sans_args() + !stack_args_size + !stack_traps_size)} # stack size including traps\n`;
1964N/A+ ` .set {emit_label !stack_slot_lbl},{emit_int (48 + !stack_args_size)} # stack slot offset\n`
1964N/A+ end else (* leave 8 bytes for float <-> conversions *)
1964N/A+ ` .set {emit_label !stack_slot_lbl},{emit_int (40-frame_size_sans_args())} # stack slot offset (negative)\n`;
1964N/A+ (* Emit the glue code to call the GC *)
1964N/A+ if !call_gc_label > 0 then begin
1964N/A+ `{emit_label !call_gc_label}:\n`;
1964N/A+ ` ld {emit_gpr 12}, {emit_tocref (TocSymOfs ("caml_call_gc",0))}\n`;
1964N/A+ ` ld {emit_gpr 12}, 0({emit_gpr 12})\n`;
1964N/A+let declare_global_data s =
1964N/A+ ` .globl {emit_symbol s}\n`;
1964N/A+ ` .type {emit_symbol s}, @object\n`
1964N/A+ `{emit_label (lbl + 100000)}:\n`
1964N/A+ ` .long {emit_nativeint n}\n`
1964N/A+ ` .quad {emit_nativeint n}\n`
1964N/A+ ` .float 0d{emit_string f}\n`
1964N/A+ ` .double 0d{emit_string f}\n`
1964N/A+ ` .quad {emit_symbol s}\n`
1964N/A+ ` .quad {emit_label (lbl + 100000)}\n`
1964N/A+ emit_bytes_directive " .byte " s
1964N/A+ if n > 0 then ` .space {emit_int n}\n`
1964N/A+(* Beginning / end of an assembly file *)
1964N/A+ (* Emit the beginning of the segments *)
1964N/A+ declare_global_data lbl_begin;
1964N/A+ `{emit_symbol lbl_begin}:\n`;
1964N/A+ declare_global_data lbl_begin;
1964N/A+ `{emit_symbol lbl_begin}:\n`
1964N/A+ if !num_jumptbl_entries > 0 then begin
1964N/A+ `{emit_label !lbl_jumptbl}:\n`;
1964N/A+ (fun lbl -> ` .long {emit_label lbl} - {emit_label !lbl_jumptbl}\n`)
1964N/A+ if !tocref_entries <> [] then begin
1964N/A+ ` .double {emit_tocentry entry}\n`
1964N/A+ ` .tc {emit_label lbl}[TC],{emit_tocentry entry}\n`
1964N/A+ (* Emit the pointers to external functions *)
1964N/A+ (* Emit the end of the segments *)
1964N/A+ declare_global_data lbl_end;
1964N/A+ `{emit_symbol lbl_end}:\n`;
1964N/A+ declare_global_data lbl_end;
1964N/A+ `{emit_symbol lbl_end}:\n`;
1964N/A+ (* Emit the frame descriptors *)
1964N/A+(***********************************************************************)
1964N/A+(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
1964N/A+(* Copyright 1996 Institut National de Recherche en Informatique et *)
1964N/A+(* en Automatique. All rights reserved. This file is distributed *)
1964N/A+(* under the terms of the Q Public License version 1.0. *)
1964N/A+(***********************************************************************)
1964N/A+(* Description of the Power PC *)
1964N/A+(* Instruction selection *)
1964N/A+(* Registers available for register allocation *)
1964N/A+ 0 temporary, null register for some operations
1964N/A+ 2 pointer to table of contents
1964N/A+ 3 - 10 function arguments and results
1964N/A+ 13 pointer to small data area
1964N/A+ 14 - 28 general purpose, preserved by C
1964N/A+ Floating-point register map:
1964N/A+ 1 - 13 function arguments and results
1964N/A+ 14 - 31 general purpose, preserved by C
1964N/A+ [| "r3"; "r4"; "r5"; "r6"; "r7"; "r8"; "r9"; "r10";
1964N/A+ "r14"; "r15"; "r16"; "r17"; "r18"; "r19"; "r20"; "r21";
1964N/A+ "r22"; "r23"; "r24"; "r25"; "r26"; "r27"; "r28" |]
1964N/A+ [| "3"; "4"; "5"; "6"; "7"; "8"; "9"; "10";
1964N/A+ "14"; "15"; "16"; "17"; "18"; "19"; "20"; "21";
1964N/A+ "22"; "23"; "24"; "25"; "26"; "27"; "28" |]
1964N/A+ [| "f1"; "f2"; "f3"; "f4"; "f5"; "f6"; "f7"; "f8";
1964N/A+ "f9"; "f10"; "f11"; "f12"; "f13"; "f14"; "f15"; "f16";
1964N/A+ "f17"; "f18"; "f19"; "f20"; "f21"; "f22"; "f23"; "f24";
1964N/A+ "f25"; "f26"; "f27"; "f28"; "f29"; "f30"; "f31" |]
1964N/A+ [| "1"; "2"; "3"; "4"; "5"; "6"; "7"; "8";
1964N/A+ "9"; "10"; "11"; "12"; "13"; "14"; "15"; "16";
1964N/A+ "17"; "18"; "19"; "20"; "21"; "22"; "23"; "24";
1964N/A+ "25"; "26"; "27"; "28"; "29"; "30"; "31" |]
1964N/A+let num_register_classes = 2
1964N/A+let num_available_registers = [| 23; 31 |]
1964N/A+let first_available_register = [| 0; 100 |]
1964N/A+ if r < 100 then int_reg_name.(r) else float_reg_name.(r - 100)
1964N/A+let rotate_registers = true
1964N/A+(* Representation of hard registers by pseudo-registers *)
1964N/A+ if n < 100 then hard_int_reg.(n) else hard_float_reg.(n - 100)
1964N/A+ first_int last_int first_float last_float make_stack stack_ofs arg =
1964N/A+ let int = ref first_int in
1964N/A+ let float = ref first_float in
1964N/A+ let ofs = ref stack_ofs in
1964N/A+ if !int <= last_int then begin
1964N/A+ loc.(i) <- stack_slot (make_stack !ofs) ty;
1964N/A+ if !float <= last_float then begin
1964N/A+ loc.(i) <- phys_reg !float;
1964N/A+ loc.(i) <- stack_slot (make_stack !ofs) Float;
1964N/A+ (* Keep stack 16-aligned. *)
1964N/A+let incoming ofs = Incoming ofs
1964N/A+let outgoing ofs = Outgoing ofs
1964N/A+ calling_conventions 0 7 100 112 outgoing 48 arg
1964N/A+ let (loc, ofs) = calling_conventions 0 7 100 112 incoming 0 arg in loc
1964N/A+ let (loc, ofs) = calling_conventions 0 7 100 112 not_supported 0 res in loc
1964N/A+(* C calling conventions under PowerOpen:
1964N/A+ use GPR 3-10 and FPR 1-13 just like ML calling
1964N/A+ conventions, but always reserve stack space for all arguments.
1964N/A+ Also, using a float register automatically reserves two int registers
1964N/A+ (in 32-bit mode) or one int register (in 64-bit mode).
1964N/A+ (If we were to call a non-prototyped C function, each float argument
1964N/A+ would have to go both in a float reg and in the matching pair
1964N/A+ C calling conventions under SVR4:
1964N/A+ use GPR 3-10 and FPR 1-8 just like ML calling conventions.
1964N/A+ Using a float register does not affect the int registers.
1964N/A+ Always reserve 8 bytes at bottom of stack, plus whatever is needed
1964N/A+ to hold the overflow arguments. *)
1964N/A+let poweropen_external_conventions first_int last_int
1964N/A+ first_float last_float arg =
1964N/A+ let int = ref first_int in
1964N/A+ let float = ref first_float in
1964N/A+ if !int <= last_int then begin
1964N/A+ loc.(i) <- stack_slot (Outgoing !ofs) ty;
1964N/A+ if !float <= last_float then begin
1964N/A+ loc.(i) <- phys_reg !float;
1964N/A+ loc.(i) <- stack_slot (Outgoing !ofs) Float;
1964N/A+let loc_external_arguments =
1964N/A+ | "rhapsody" -> poweropen_external_conventions 0 7 100 112
1964N/A+ | "elf" | "bsd" -> calling_conventions 0 7 100 107 outgoing 8
1964N/A+let extcall_use_push = false
1964N/A+(* Results are in GPR 3 and FPR 1 *)
1964N/A+let loc_external_results res =
1964N/A+ let (loc, ofs) = calling_conventions 0 0 100 100 not_supported 0 res in loc
1964N/A+(* Exceptions are in GPR 3 *)
1964N/A+let loc_exn_bucket = phys_reg 0
1964N/A+(* Registers destroyed by operations *)
1964N/A+ 100; 101; 102; 103; 104; 105; 106; 107; 108; 109; 110; 111; 112])
1964N/A+let destroyed_at_oper = function
1964N/A+ Iop(Icall_ind | Icall_imm _ | Iextcall(_, true)) -> all_phys_regs
1964N/A+ | Iop(Iextcall(_, false)) -> destroyed_at_c_call
1964N/A+let destroyed_at_raise = all_phys_regs
1964N/A+(* Maximal register pressure *)
1964N/A+let safe_register_pressure = function
1964N/A+let max_register_pressure = function
1964N/A+ Iextcall(_, _) -> [| 15; 18 |]
1964N/A+let num_stack_slots = [| 0; 0 |]
1964N/A+let contains_calls = ref false
1964N/A+(* Calling the assembler *)
1964N/A+let assemble_file infile outfile =
1964N/A+(***********************************************************************)
1964N/A+(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
1964N/A+(* Copyright 1996 Institut National de Recherche en Informatique et *)
1964N/A+(* en Automatique. All rights reserved. This file is distributed *)
1964N/A+(* under the terms of the Q Public License version 1.0. *)
1964N/A+(***********************************************************************)
1964N/A+(* Reloading for the PowerPC *)
1964N/A+(***********************************************************************)
1964N/A+(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
1964N/A+(* Copyright 1996 Institut National de Recherche en Informatique et *)
1964N/A+(* en Automatique. All rights reserved. This file is distributed *)
1964N/A+(* under the terms of the Q Public License version 1.0. *)
1964N/A+(***********************************************************************)
1964N/A+(* Instruction scheduling for the Power PC *)
1964N/A+(* Latencies (in cycles). Based roughly on the "common model". *)
1964N/A+method oper_latency = function
1964N/A+ | Iconst_float _ -> 2 (* turned into a load *)
1964N/A+ | Iintop_imm(Imul, _) -> 5
1964N/A+ | Iintop(Idiv | Imod) -> 36
1964N/A+ | Ispecific(Imultaddf | Imultsubf) -> 5
1964N/A+method reload_retaddr_latency = 12
1964N/A+ (* If we can have that many cycles between the reloadretaddr and the
1964N/A+ return, we can expect that the blr branch will be completely folded. *)
1964N/A+(* Issue cycles. Rough approximations. *)
1964N/A+method oper_issue_cycles = function
1964N/A+ Iconst_float _ | Iconst_symbol _ -> 2
1964N/A+ | Iload(_, Ibased(_, _)) -> 2
1964N/A+ | Istore(_, Ibased(_, _)) -> 2
1964N/A+ | Iintop(Imod) -> 40 (* assuming full stall *)
1964N/A+ | Iintop_imm(Idiv, _) -> 2
1964N/A+ | Iintop_imm(Imod, _) -> 4
1964N/A+ | Iintop_imm(Icomp _, _) -> 4
1964N/A+method reload_retaddr_issue_cycles = 3
1964N/A+ (* load then stalling mtlr *)
1964N/A+let fundecl f = (new scheduler)#schedule_fundecl f
1964N/A+(***********************************************************************)
1964N/A+(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
1964N/A+(* Copyright 1997 Institut National de Recherche en Informatique et *)
1964N/A+(* en Automatique. All rights reserved. This file is distributed *)
1964N/A+(* under the terms of the Q Public License version 1.0. *)
1964N/A+(***********************************************************************)
1964N/A+(* Instruction selection for the Power PC processor *)
1964N/A+(* Recognition of addressing modes *)
1964N/A+ | Aadd of expression * expression
1964N/A+let rec select_addr = function
1964N/A+ | Cop((Caddi | Cadda), [arg; Cconst_int m]) ->
1964N/A+ let (a, n) = select_addr arg in (a, n + m)
1964N/A+ | Cop((Caddi | Cadda), [Cconst_int m; arg]) ->
1964N/A+ let (a, n) = select_addr arg in (a, n + m)
1964N/A+ | Cop((Caddi | Cadda), [arg1; arg2]) ->
1964N/A+ begin match (select_addr arg1, select_addr arg2) with
1964N/A+ ((Alinear e1, n1), (Alinear e2, n2)) ->
1964N/A+(* Instruction selection *)
1964N/A+class selector = object (self)
1964N/A+method is_immediate n = (n <= 32767) && (n >= -32768)
1964N/A+method select_addressing exp =
1964N/A+ match select_addr exp with
1964N/A+ then (Iindexed2, Ctuple[e1; e2])
1964N/A+ else (Iindexed d, Cop(Cadda, [e1; e2]))
1964N/A+method select_operation op args =
1964N/A+ (* Prevent the recognition of (x / cst) and (x % cst) when cst is not
1964N/A+ a power of 2, which do not correspond to an instruction. *)
1964N/A+ (Iintop_imm(Idiv, n), [arg])
1964N/A+ (Iintop_imm(Imod, n), [arg])
1964N/A+ (* The and, or and xor instructions have a different range of immediate
1964N/A+ operands than the other instructions *)
1964N/A+ | (Cand, _) -> self#select_logical Iand args
1964N/A+ | (Cor, _) -> self#select_logical Ior args
1964N/A+ | (Cxor, _) -> self#select_logical Ixor args
1964N/A+ (* Recognize mult-add and mult-sub instructions *)
1964N/A+ | (Caddf, [Cop(Cmulf, [arg1; arg2]); arg3]) ->
1964N/A+ (Ispecific Imultaddf, [arg1; arg2; arg3])
1964N/A+ | (Caddf, [arg3; Cop(Cmulf, [arg1; arg2])]) ->
1964N/A+ (Ispecific Imultaddf, [arg1; arg2; arg3])
1964N/A+ | (Csubf, [Cop(Cmulf, [arg1; arg2]); arg3]) ->
1964N/A+ (Ispecific Imultsubf, [arg1; arg2; arg3])
1964N/A+ super#select_operation op args
1964N/A+method select_logical op = function
1964N/A+ [arg; Cconst_int n] when n >= 0 && n <= 0xFFFF ->
1964N/A+ (Iintop_imm(op, n), [arg])
1964N/A+ | [Cconst_int n; arg] when n >= 0 && n <= 0xFFFF ->
1964N/A+ (Iintop_imm(op, n), [arg])
1964N/A+let fundecl f = (new selector)#emit_fundecl f
1964N/A+/*********************************************************************/
1964N/A+/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
1964N/A+/* Copyright 1996 Institut National de Recherche en Informatique et */
1964N/A+/* en Automatique. All rights reserved. This file is distributed */
1964N/A+/* under the terms of the GNU Library General Public License, with */
1964N/A+/* the special exception on linking described in file ../LICENSE. */
1964N/A+/*********************************************************************/
1964N/A+#define Addrglobal(reg,glob) \
1964N/A+#define Loadglobal(reg,glob,tmp) \
1964N/A+#define Storeglobal(reg,glob,tmp) \
1964N/A+/* Invoke the garbage collector. */
1964N/A+ .type caml_call_gc, @function
1964N/A+ /* Record return address into Caml code */
1964N/A+ Storeglobal(0, caml_last_return_address, 11)
1964N/A+ /* Record lowest stack address */
1964N/A+ Storeglobal(1, caml_bottom_of_stack, 11)
1964N/A+ /* 0x220 = 8*32 (int regs) + 8*32 (float regs) + 48 (stack frame) */
1964N/A+ /* Record pointer to register array */
1964N/A+ Storeglobal(0, caml_gc_regs, 11)
1964N/A+ /* Save current allocation pointer for debugging purposes */
1964N/A+ Storeglobal(31, caml_young_ptr, 11)
1964N/A+ /* Save exception pointer (if
e.g. a sighandler raises) */
1964N/A+ Storeglobal(29, caml_exception_pointer, 11)
1964N/A+ /* Save all registers used by the code generator */
1964N/A+ Addrglobal(11, caml_garbage_collection)
1964N/A+ /* Reload new allocation pointer and allocation limit */
1964N/A+ Loadglobal(31, caml_young_ptr, 11)
1964N/A+ Loadglobal(30, caml_young_limit, 11)
1964N/A+ /* Restore all regs used by the code generator */
1964N/A+ /* Return to caller, restarting the allocation */
1964N/A+ Loadglobal(0, caml_last_return_address, 11)
1964N/A+ addic 0, 0, -16 /* Restart the allocation (4 instructions) */
1964N/A+ /* Say we are back into Caml code */
1964N/A+ Storeglobal(12, caml_last_return_address, 11)
1964N/A+ /* Deallocate stack frame */
1964N/A+/* Call a C function from Caml */
1964N/A+ .type caml_c_call, @function
1964N/A+ /* Get ready to call C function (address in 11) */
1964N/A+ /* Record lowest stack address and return address */
1964N/A+ Storeglobal(1, caml_bottom_of_stack, 12)
1964N/A+ Storeglobal(25, caml_last_return_address, 12)
1964N/A+ /* Make the exception handler and alloc ptr available to the C code */
1964N/A+ Storeglobal(31, caml_young_ptr, 11)
1964N/A+ Storeglobal(29, caml_exception_pointer, 11)
1964N/A+ /* Call the function (address in link register) */
1964N/A+ /* Restore return address (in 25, preserved by the C function) */
1964N/A+ /* Reload allocation pointer and allocation limit*/
1964N/A+ Loadglobal(31, caml_young_ptr, 11)
1964N/A+ Loadglobal(30, caml_young_limit, 11)
1964N/A+ /* Say we are back into Caml code */
1964N/A+ Storeglobal(12, caml_last_return_address, 11)
1964N/A+/* Raise an exception from C */
1964N/A+ .globl caml_raise_exception
1964N/A+ .type caml_raise_exception, @function
1964N/A+ /* Reload Caml global registers */
1964N/A+ Loadglobal(29, caml_exception_pointer, 11)
1964N/A+ Loadglobal(31, caml_young_ptr, 11)
1964N/A+ Loadglobal(30, caml_young_limit, 11)
1964N/A+ /* Say we are back into Caml code */
1964N/A+ Storeglobal(0, caml_last_return_address, 11)
1964N/A+/* Start the Caml program */
1964N/A+ .type caml_start_program, @function
1964N/A+ Addrglobal(12, caml_program)
1964N/A+/* Code shared between caml_start_program and caml_callback */
1964N/A+ /* Allocate and link stack frame */
1964N/A+ stdu 1, -0x190(1) /* 48 + 8*36(regs) + 32(callback) + 32(exc) */
1964N/A+ /* Save all callee-save registers */
1964N/A+ /* GPR 14 ... GPR 31 then FPR 14 ... FPR 31 starting at sp+16 */
1964N/A+ /* Set up a callback link */
1964N/A+ Loadglobal(9, caml_bottom_of_stack, 11)
1964N/A+ Loadglobal(10, caml_last_return_address, 11)
1964N/A+ Loadglobal(11, caml_gc_regs, 11)
1964N/A+ /* Build an exception handler to catch exceptions escaping out of Caml */
1964N/A+ addi 29, 1, 0x170 /* Alignment */
1964N/A+ Loadglobal(11, caml_exception_pointer, 11)
1964N/A+ /* Reload allocation pointers */
1964N/A+ Loadglobal(31, caml_young_ptr, 11)
1964N/A+ Loadglobal(30, caml_young_limit, 11)
1964N/A+ /* Say we are back into Caml code */
1964N/A+ Storeglobal(0, caml_last_return_address, 11)
1964N/A+ /* Pop the trap frame, restoring caml_exception_pointer */
1964N/A+ Storeglobal(9, caml_exception_pointer, 11)
1964N/A+ /* Pop the callback link, restoring the global variables */
1964N/A+ Storeglobal(9, caml_bottom_of_stack, 12)
1964N/A+ Storeglobal(10, caml_last_return_address, 12)
1964N/A+ Storeglobal(11, caml_gc_regs, 12)
1964N/A+ /* Update allocation pointer */
1964N/A+ Storeglobal(31, caml_young_ptr, 11)
1964N/A+ /* Restore callee-save registers */
1964N/A+ /* Reload return address */
1964N/A+ /* Update caml_exception_pointer */
1964N/A+ Storeglobal(29, caml_exception_pointer, 11)
1964N/A+ /* Encode exception bucket as an exception result and return it */
1964N/A+/* Callback from C to Caml */
1964N/A+ .type caml_callback_exn, @function
1964N/A+ /* Initial shuffling of arguments */
1964N/A+ ld 12, 0(4) /* Code pointer */
1964N/A+ .type caml_callback2_exn, @function
1964N/A+ mr 3, 4 /* First argument */
1964N/A+ mr 4, 5 /* Second argument */
1964N/A+ Addrglobal(12, caml_apply2)
1964N/A+ .type caml_callback3_exn, @function
1964N/A+ mr 3, 4 /* First argument */
1964N/A+ mr 4, 5 /* Second argument */
1964N/A+ mr 5, 6 /* Third argument */
1964N/A+ Addrglobal(12, caml_apply3)
1964N/A+ .globl caml_system__frametable
1964N/A+ .type caml_system__frametable, @object
1964N/A+ .quad 1 /* one descriptor */
1964N/A+ .quad .L105 + 4 /* return address into callback */
1964N/A+ .short -1 /* negative size count => use callback link */
1964N/A+ .short 0 /* no roots here */
1964N/A #define Callback_link(sp) ((struct caml_context *)((sp) + Trap_frame_size))
1964N/A+#define Saved_return_address(sp) *((intnat *)((sp) +16))
1964N/A+#define Already_scanned(sp, retaddr) ((retaddr) & 1)
1964N/A+#define Mark_scanned(sp, retaddr) (Saved_return_address(sp) = (retaddr) | 1)
1964N/A+#define Mask_already_scanned(retaddr) ((retaddr) & ~1)
1964N/A+#define Trap_frame_size 0x150
1964N/A+#define Callback_link(sp) ((struct caml_context *)((sp) + Trap_frame_size))
1964N/A #define Saved_return_address(sp) *((intnat *)((sp) - 4))
1964N/A #define Callback_link(sp) ((struct caml_context *)((sp) + 8))
1964N/A hppa2.0*-*-hpux*) arch=hppa; system=hpux;;
1964N/A hppa*-*-linux*) arch=hppa; system=linux;;
1964N/A hppa*-*-gnu*) arch=hppa; system=gnu;;
1964N/A+ powerpc64-*-linux*) arch=power64; model=ppc64; system=elf;;
1964N/A powerpc*-*-linux*) arch=power; model=ppc; system=elf;;
1964N/A powerpc-*-netbsd*) arch=power; model=ppc; system=elf;;
1964N/A powerpc-*-rhapsody*) arch=power; model=ppc; system=rhapsody;;
1964N/A- sparc,default|mips,default|hppa,default|power,ppc)
1964N/A+ sparc,default|mips,default|hppa,default)
1964N/A arch=none; model=default; system=unknown;;
1964N/A power,*,elf) as='as -u -m ppc'
1964N/A+ power64,*,elf) as='as -u -m ppc64'
1964N/A power,*,rhapsody) as="as -arch $model"