1 (***********************************************************************)
5 (* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
7 (* Copyright 1996 Institut National de Recherche en Informatique et *)
8 (* en Automatique. All rights reserved. This file is distributed *)
9 (* under the terms of the Q Public License version 1.0. *)
11 (***********************************************************************)
13 (* $Id: emit.mlp 9475 2009-12-16 10:04:38Z xleroy $ *)
15 (* Emission of PowerPC assembly code *)
17 module StringSet = Set.Make(struct type t = string let compare = compare end)
29 (* Layout of the stack. The stack is kept 16-aligned. *)
31 let stack_offset = ref 0
35 !stack_offset + (* Trap frame, outgoing parameters *)
36 size_int * num_stack_slots.(0) + (* Local int variables *)
37 size_float * num_stack_slots.(1) + (* Local float variables *)
38 (if !contains_calls then size_int else 0) in (* The return address *)
41 let slot_offset loc cls =
45 then !stack_offset + num_stack_slots.(1) * size_float + n * size_int
46 else !stack_offset + n * size_float
47 | Incoming n -> frame_size() + n
50 (* Whether stack backtraces are supported *)
52 let supports_backtraces =
53 match Config.system with
60 match Config.system with
61 | "elf" | "bsd" -> (fun s -> Emitaux.emit_symbol '.' s)
62 | "rhapsody" -> (fun s -> emit_char '_'; Emitaux.emit_symbol '$' s)
68 match Config.system with
69 | "elf" | "bsd" -> ".L"
74 emit_string label_prefix; emit_int lbl
76 (* Section switching *)
79 match Config.system with
80 | "elf" | "bsd" -> " .section \".data\"\n"
81 | "rhapsody" -> " .data\n"
85 match Config.system with
86 | "elf" | "bsd" -> " .section \".text\"\n"
87 | "rhapsody" -> " .text\n"
91 match Config.system with
92 | "elf" | "bsd" -> " .section \".rodata\"\n"
93 | "rhapsody" -> " .const\n"
96 (* Names of instructions that differ in 32 and 64-bit modes *)
98 let lg = if ppc64 then "ld" else "lwz"
99 let stg = if ppc64 then "std" else "stw"
100 let lwa = if ppc64 then "lwa" else "lwz"
101 let cmpg = if ppc64 then "cmpd" else "cmpw"
102 let cmplg = if ppc64 then "cmpld" else "cmplw"
103 let datag = if ppc64 then ".quad" else ".long"
104 let aligng = if ppc64 then 3 else 2
105 let mullg = if ppc64 then "mulld" else "mullw"
106 let divg = if ppc64 then "divd" else "divw"
107 let tglle = if ppc64 then "tdlle" else "twlle"
108 let sragi = if ppc64 then "sradi" else "srawi"
109 let slgi = if ppc64 then "sldi" else "slwi"
110 let fctigz = if ppc64 then "fctidz" else "fctiwz"
112 (* Output a pseudo-register *)
116 Reg r -> emit_string (register_name r)
117 | _ -> fatal_error "Emit.emit_reg"
119 let use_full_regnames =
120 Config.system = "rhapsody"
123 if use_full_regnames then emit_char 'r';
127 if use_full_regnames then emit_char 'f';
131 if use_full_regnames then emit_string "cr";
134 (* Output a stack reference *)
139 let ofs = slot_offset s (register_class r) in `{emit_int ofs}({emit_gpr 1})`
140 | _ -> fatal_error "Emit.emit_stack"
142 (* Split a 32-bit integer constants in two 16-bit halves *)
144 let low n = n land 0xFFFF
145 let high n = n asr 16
147 let nativelow n = Nativeint.to_int n land 0xFFFF
148 let nativehigh n = Nativeint.to_int (Nativeint.shift_right n 16)
151 n <= 32767 && n >= -32768
153 let is_native_immediate n =
154 n <= 32767n && n >= -32768n
156 (* Output a "upper 16 bits" or "lower 16 bits" operator. *)
158 let emit_upper emit_fun arg =
159 match Config.system with
161 emit_fun arg; emit_string "@ha"
163 emit_string "ha16("; emit_fun arg; emit_string ")"
166 let emit_lower emit_fun arg =
167 match Config.system with
169 emit_fun arg; emit_string "@l"
171 emit_string "lo16("; emit_fun arg; emit_string ")"
174 (* Output a load or store operation *)
176 let emit_symbol_offset (s, d) =
179 if d <> 0 then emit_int d
181 let valid_offset instr ofs =
182 ofs land 3 = 0 || (instr <> "ld" && instr <> "std")
184 let emit_load_store instr addressing_mode addr n arg =
185 match addressing_mode with
187 ` addis {emit_gpr 11}, 0, {emit_upper emit_symbol_offset (s,d)}\n`;
188 ` {emit_string instr} {emit_reg arg}, {emit_lower emit_symbol_offset (s,d)}({emit_gpr 11})\n`
190 if is_immediate ofs && valid_offset instr ofs then
191 ` {emit_string instr} {emit_reg arg}, {emit_int ofs}({emit_reg addr.(n)})\n`
193 ` lis {emit_gpr 0}, {emit_int(high ofs)}\n`;
195 ` ori {emit_gpr 0}, {emit_gpr 0}, {emit_int(low ofs)}\n`;
196 ` {emit_string instr}x {emit_reg arg}, {emit_reg addr.(n)}, {emit_gpr 0}\n`
199 ` {emit_string instr}x {emit_reg arg}, {emit_reg addr.(n)}, {emit_reg addr.(n+1)}\n`
201 (* After a comparison, extract the result as 0 or 1 *)
203 let emit_set_comp cmp res =
204 ` mfcr {emit_gpr 0}\n`;
210 ` rlwinm {emit_reg res}, {emit_gpr 0}, {emit_int(bitnum+1)}, 31, 31\n`;
212 Cne | Cle | Cge -> ` xori {emit_reg res}, {emit_reg res}, 1\n`
216 (* Record live pointers at call points *)
218 let record_frame live dbg =
219 let lbl = new_label() in
220 let live_offset = ref [] in
223 {typ = Addr; loc = Reg r} ->
224 live_offset := (r lsl 1) + 1 :: !live_offset
225 | {typ = Addr; loc = Stack s} as reg ->
226 live_offset := slot_offset s (register_class reg) :: !live_offset
231 fd_frame_size = frame_size();
232 fd_live_offset = !live_offset;
233 fd_debuginfo = dbg } :: !frame_descriptors;
234 `{emit_label lbl}:\n`
236 (* Record floating-point and large integer literals *)
238 let float_literals = ref ([] : (string * int) list)
239 let int_literals = ref ([] : (nativeint * int) list)
241 (* Record external C functions to be called in a position-independent way
244 let pic_externals = (Config.system = "rhapsody")
246 let external_functions = ref StringSet.empty
248 let emit_external s =
249 ` .non_lazy_symbol_pointer\n`;
250 `L{emit_symbol s}$non_lazy_ptr:\n`;
251 ` .indirect_symbol {emit_symbol s}\n`;
252 ` {emit_string datag} 0\n`
254 (* Names for conditional branches after comparisons *)
256 let branch_for_comparison = function
257 Ceq -> "beq" | Cne -> "bne"
258 | Cle -> "ble" | Cgt -> "bgt"
259 | Cge -> "bge" | Clt -> "blt"
261 let name_for_int_comparison = function
262 Isigned cmp -> (cmpg, branch_for_comparison cmp)
263 | Iunsigned cmp -> (cmplg, branch_for_comparison cmp)
265 (* Names for various instructions *)
267 let name_for_intop = function
269 | Imul -> if ppc64 then "mulld" else "mullw"
270 | Idiv -> if ppc64 then "divd" else "divw"
274 | Ilsl -> if ppc64 then "sld" else "slw"
275 | Ilsr -> if ppc64 then "srd" else "srw"
276 | Iasr -> if ppc64 then "srad" else "sraw"
277 | _ -> Misc.fatal_error "Emit.Intop"
279 let name_for_intop_imm = function
285 | Ilsl -> if ppc64 then "sldi" else "slwi"
286 | Ilsr -> if ppc64 then "srdi" else "srwi"
287 | Iasr -> if ppc64 then "sradi" else "srawi"
288 | _ -> Misc.fatal_error "Emit.Intop_imm"
290 let name_for_floatop1 = function
293 | _ -> Misc.fatal_error "Emit.Iopf1"
295 let name_for_floatop2 = function
300 | _ -> Misc.fatal_error "Emit.Iopf2"
302 let name_for_specific = function
304 | Imultsubf -> "fmsub"
305 | _ -> Misc.fatal_error "Emit.Ispecific"
307 (* Name of current function *)
308 let function_name = ref ""
309 (* Entry point for tail recursive calls *)
310 let tailrec_entry_point = ref 0
311 (* Names of functions defined in the current file *)
312 let defined_functions = ref StringSet.empty
313 (* Label of glue code for calling the GC *)
314 let call_gc_label = ref 0
316 (* Fixup conditional branches that exceed hardware allowed range *)
318 let load_store_size = function
320 | Iindexed ofs -> if is_immediate ofs then 1 else 3
323 let instr_size = function
325 | Lop(Imove | Ispill | Ireload) -> 1
326 | Lop(Iconst_int n) -> if is_native_immediate n then 1 else 2
327 | Lop(Iconst_float s) -> 2
328 | Lop(Iconst_symbol s) -> 2
329 | Lop(Icall_ind) -> 2
330 | Lop(Icall_imm s) -> 1
331 | Lop(Itailcall_ind) -> 5
332 | Lop(Itailcall_imm s) -> if s = !function_name then 1 else 4
333 | Lop(Iextcall(s, true)) -> 3
334 | Lop(Iextcall(s, false)) -> if pic_externals then 4 else 1
335 | Lop(Istackoffset n) -> 1
336 | Lop(Iload(chunk, addr)) ->
337 if chunk = Byte_signed
338 then load_store_size addr + 1
339 else load_store_size addr
340 | Lop(Istore(chunk, addr)) -> load_store_size addr
342 | Lop(Ispecific(Ialloc_far n)) -> 5
343 | Lop(Iintop Imod) -> 3
344 | Lop(Iintop(Icomp cmp)) -> 4
345 | Lop(Iintop op) -> 1
346 | Lop(Iintop_imm(Idiv, n)) -> 2
347 | Lop(Iintop_imm(Imod, n)) -> 4
348 | Lop(Iintop_imm(Icomp cmp, n)) -> 4
349 | Lop(Iintop_imm(op, n)) -> 1
350 | Lop(Inegf | Iabsf | Iaddf | Isubf | Imulf | Idivf) -> 1
351 | Lop(Ifloatofint) -> 9
352 | Lop(Iintoffloat) -> 4
353 | Lop(Ispecific sop) -> 1
354 | Lreloadretaddr -> 2
358 | Lcondbranch(tst, lbl) -> 2
359 | Lcondbranch3(lbl0, lbl1, lbl2) ->
360 1 + (if lbl0 = None then 0 else 1)
361 + (if lbl1 = None then 0 else 1)
362 + (if lbl2 = None then 0 else 1)
363 | Lswitch jumptbl -> 8
364 | Lsetuptrap lbl -> 1
370 let map = Hashtbl.create 37 in
371 let rec fill_map pc instr =
372 match instr.desc with
374 | Llabel lbl -> Hashtbl.add map lbl pc; fill_map pc instr.next
375 | op -> fill_map (pc + instr_size op) instr.next
378 let max_branch_offset = 8180
379 (* 14-bit signed offset in words. Remember to cut some slack
380 for multi-word instructions where the branch can be anywhere in
381 the middle. 12 words of slack is plenty. *)
383 let branch_overflows map pc_branch lbl_dest =
384 let pc_dest = Hashtbl.find map lbl_dest in
385 let delta = pc_dest - (pc_branch + 1) in
386 delta <= -max_branch_offset || delta >= max_branch_offset
388 let opt_branch_overflows map pc_branch opt_lbl_dest =
389 match opt_lbl_dest with
391 | Some lbl_dest -> branch_overflows map pc_branch lbl_dest
393 let fixup_branches codesize map code =
394 let expand_optbranch lbl n arg next =
398 instr_cons (Lcondbranch(Iinttest_imm(Isigned Ceq, n), l))
400 let rec fixup did_fix pc instr =
401 match instr.desc with
403 | Lcondbranch(test, lbl) when branch_overflows map pc lbl ->
404 let lbl2 = new_label() in
406 instr_cons (Lbranch lbl) [||] [||]
407 (instr_cons (Llabel lbl2) [||] [||] instr.next) in
408 instr.desc <- Lcondbranch(invert_test test, lbl2);
410 fixup true (pc + 2) instr.next
411 | Lcondbranch3(lbl0, lbl1, lbl2)
412 when opt_branch_overflows map pc lbl0
413 || opt_branch_overflows map pc lbl1
414 || opt_branch_overflows map pc lbl2 ->
416 expand_optbranch lbl0 0 instr.arg
417 (expand_optbranch lbl1 1 instr.arg
418 (expand_optbranch lbl2 2 instr.arg instr.next)) in
419 instr.desc <- cont.desc;
420 instr.next <- cont.next;
422 | Lop(Ialloc n) when codesize - pc >= max_branch_offset ->
423 instr.desc <- Lop(Ispecific(Ialloc_far n));
424 fixup true (pc + 4) instr.next
426 fixup did_fix (pc + instr_size op) instr.next
427 in fixup false 0 code
429 (* Iterate branch expansion till all conditional branches are OK *)
431 let rec branch_normalization code =
432 let (codesize, map) = label_map code in
433 if codesize >= max_branch_offset && fixup_branches codesize map code
434 then branch_normalization code
438 (* Output the assembly code for an instruction *)
440 let rec emit_instr i dslot =
443 | Lop(Imove | Ispill | Ireload) ->
444 let src = i.arg.(0) and dst = i.res.(0) in
445 if src.loc <> dst.loc then begin
446 match (src, dst) with
447 {loc = Reg rs; typ = (Int | Addr)}, {loc = Reg rd} ->
448 ` mr {emit_reg dst}, {emit_reg src}\n`
449 | {loc = Reg rs; typ = Float}, {loc = Reg rd; typ = Float} ->
450 ` fmr {emit_reg dst}, {emit_reg src}\n`
451 | {loc = Reg rs; typ = (Int | Addr)}, {loc = Stack sd} ->
452 ` {emit_string stg} {emit_reg src}, {emit_stack dst}\n`
453 | {loc = Reg rs; typ = Float}, {loc = Stack sd} ->
454 ` stfd {emit_reg src}, {emit_stack dst}\n`
455 | {loc = Stack ss; typ = (Int | Addr)}, {loc = Reg rd} ->
456 ` {emit_string lg} {emit_reg dst}, {emit_stack src}\n`
457 | {loc = Stack ss; typ = Float}, {loc = Reg rd} ->
458 ` lfd {emit_reg dst}, {emit_stack src}\n`
460 fatal_error "Emit: Imove"
462 | Lop(Iconst_int n) ->
463 if is_native_immediate n then
464 ` li {emit_reg i.res.(0)}, {emit_nativeint n}\n`
465 else if n >= -0x8000_0000n && n <= 0x7FFF_FFFFn then begin
466 ` lis {emit_reg i.res.(0)}, {emit_int(nativehigh n)}\n`;
467 if nativelow n <> 0 then
468 ` ori {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, {emit_int(nativelow n)}\n`
470 let lbl = new_label() in
471 int_literals := (n, lbl) :: !int_literals;
472 ` addis {emit_gpr 11}, 0, {emit_upper emit_label lbl}\n`;
473 ` {emit_string lg} {emit_reg i.res.(0)}, {emit_lower emit_label lbl}({emit_gpr 11})\n`
475 | Lop(Iconst_float s) ->
476 let lbl = new_label() in
477 float_literals := (s, lbl) :: !float_literals;
478 ` addis {emit_gpr 11}, 0, {emit_upper emit_label lbl}\n`;
479 ` lfd {emit_reg i.res.(0)}, {emit_lower emit_label lbl}({emit_gpr 11})\n`
480 | Lop(Iconst_symbol s) ->
481 ` addis {emit_reg i.res.(0)}, 0, {emit_upper emit_symbol s}\n`;
482 ` addi {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, {emit_lower emit_symbol s}\n`
484 ` mtctr {emit_reg i.arg.(0)}\n`;
486 record_frame i.live i.dbg
487 | Lop(Icall_imm s) ->
488 ` bl {emit_symbol s}\n`;
489 record_frame i.live i.dbg
490 | Lop(Itailcall_ind) ->
491 let n = frame_size() in
492 ` mtctr {emit_reg i.arg.(0)}\n`;
493 if !contains_calls then begin
494 ` {emit_string lg} {emit_gpr 11}, {emit_int(n - size_addr)}({emit_gpr 1})\n`;
495 ` addi {emit_gpr 1}, {emit_gpr 1}, {emit_int n}\n`;
496 ` mtlr {emit_gpr 11}\n`
499 ` addi {emit_gpr 1}, {emit_gpr 1}, {emit_int n}\n`
502 | Lop(Itailcall_imm s) ->
503 if s = !function_name then
504 ` b {emit_label !tailrec_entry_point}\n`
506 let n = frame_size() in
507 if !contains_calls then begin
508 ` {emit_string lg} {emit_gpr 11}, {emit_int(n - size_addr)}({emit_gpr 1})\n`;
509 ` addi {emit_gpr 1}, {emit_gpr 1}, {emit_int n}\n`;
510 ` mtlr {emit_gpr 11}\n`
513 ` addi {emit_gpr 1}, {emit_gpr 1}, {emit_int n}\n`
515 ` b {emit_symbol s}\n`
517 | Lop(Iextcall(s, alloc)) ->
519 if pic_externals then begin
520 external_functions := StringSet.add s !external_functions;
521 ` addis {emit_gpr 11}, 0, ha16(L{emit_symbol s}$non_lazy_ptr)\n`;
522 ` {emit_string lg} {emit_gpr 11}, lo16(L{emit_symbol s}$non_lazy_ptr)({emit_gpr 11})\n`
524 ` addis {emit_gpr 11}, 0, {emit_upper emit_symbol s}\n`;
525 ` addi {emit_gpr 11}, {emit_gpr 11}, {emit_lower emit_symbol s}\n`
527 ` bl {emit_symbol "caml_c_call"}\n`;
528 record_frame i.live i.dbg
530 if pic_externals then begin
531 external_functions := StringSet.add s !external_functions;
532 ` addis {emit_gpr 11}, 0, ha16(L{emit_symbol s}$non_lazy_ptr)\n`;
533 ` {emit_string lg} {emit_gpr 11}, lo16(L{emit_symbol s}$non_lazy_ptr)({emit_gpr 11})\n`;
534 ` mtctr {emit_gpr 11}\n`;
537 ` bl {emit_symbol s}\n`
539 | Lop(Istackoffset n) ->
540 ` addi {emit_gpr 1}, {emit_gpr 1}, {emit_int (-n)}\n`;
541 stack_offset := !stack_offset + n
542 | Lop(Iload(chunk, addr)) ->
545 Byte_unsigned -> "lbz"
546 | Byte_signed -> "lbz"
547 | Sixteen_unsigned -> "lhz"
548 | Sixteen_signed -> "lha"
549 | Thirtytwo_unsigned -> "lwz"
550 | Thirtytwo_signed -> if ppc64 then "lwa" else "lwz"
553 | Double | Double_u -> "lfd" in
554 emit_load_store loadinstr addr i.arg 0 i.res.(0);
555 if chunk = Byte_signed then
556 ` extsb {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n`
557 | Lop(Istore(chunk, addr)) ->
560 Byte_unsigned | Byte_signed -> "stb"
561 | Sixteen_unsigned | Sixteen_signed -> "sth"
562 | Thirtytwo_unsigned | Thirtytwo_signed -> "stw"
565 | Double | Double_u -> "stfd" in
566 emit_load_store storeinstr addr i.arg 1 i.arg.(0)
568 if !call_gc_label = 0 then call_gc_label := new_label();
569 ` addi {emit_gpr 31}, {emit_gpr 31}, {emit_int(-n)}\n`;
570 ` {emit_string cmplg} {emit_gpr 31}, {emit_gpr 30}\n`;
571 ` addi {emit_reg i.res.(0)}, {emit_gpr 31}, {emit_int size_addr}\n`;
572 ` bltl {emit_label !call_gc_label}\n`;
573 record_frame i.live Debuginfo.none
574 | Lop(Ispecific(Ialloc_far n)) ->
575 if !call_gc_label = 0 then call_gc_label := new_label();
576 let lbl = new_label() in
577 ` addi {emit_gpr 31}, {emit_gpr 31}, {emit_int(-n)}\n`;
578 ` {emit_string cmplg} {emit_gpr 31}, {emit_gpr 30}\n`;
579 ` bge {emit_label lbl}\n`;
580 ` bl {emit_label !call_gc_label}\n`;
581 record_frame i.live Debuginfo.none;
582 `{emit_label lbl}: addi {emit_reg i.res.(0)}, {emit_gpr 31}, {emit_int size_addr}\n`
583 | Lop(Iintop Isub) -> (* subfc has swapped arguments *)
584 ` subfc {emit_reg i.res.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`
585 | Lop(Iintop Imod) ->
586 ` {emit_string divg} {emit_gpr 0}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
587 ` {emit_string mullg} {emit_gpr 0}, {emit_gpr 0}, {emit_reg i.arg.(1)}\n`;
588 ` subfc {emit_reg i.res.(0)}, {emit_gpr 0}, {emit_reg i.arg.(0)}\n`
589 | Lop(Iintop(Icomp cmp)) ->
592 ` {emit_string cmpg} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
593 emit_set_comp c i.res.(0)
595 ` {emit_string cmplg} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
596 emit_set_comp c i.res.(0)
598 | Lop(Iintop Icheckbound) ->
599 if !Clflags.debug && supports_backtraces then
600 record_frame Reg.Set.empty i.dbg;
601 ` {emit_string tglle} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`
603 let instr = name_for_intop op in
604 ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`
605 | Lop(Iintop_imm(Isub, n)) ->
606 ` addi {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int(-n)}\n`
607 | Lop(Iintop_imm(Idiv, n)) -> (* n is guaranteed to be a power of 2 *)
608 let l = Misc.log2 n in
609 ` {emit_string sragi} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int l}\n`;
610 ` addze {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n`
611 | Lop(Iintop_imm(Imod, n)) -> (* n is guaranteed to be a power of 2 *)
612 let l = Misc.log2 n in
613 ` {emit_string sragi} {emit_gpr 0}, {emit_reg i.arg.(0)}, {emit_int l}\n`;
614 ` addze {emit_gpr 0}, {emit_gpr 0}\n`;
615 ` {emit_string slgi} {emit_gpr 0}, {emit_gpr 0}, {emit_int l}\n`;
616 ` subfc {emit_reg i.res.(0)}, {emit_gpr 0}, {emit_reg i.arg.(0)}\n`
617 | Lop(Iintop_imm(Icomp cmp, n)) ->
620 ` {emit_string cmpg}i {emit_reg i.arg.(0)}, {emit_int n}\n`;
621 emit_set_comp c i.res.(0)
623 ` {emit_string cmplg}i {emit_reg i.arg.(0)}, {emit_int n}\n`;
624 emit_set_comp c i.res.(0)
626 | Lop(Iintop_imm(Icheckbound, n)) ->
627 if !Clflags.debug && supports_backtraces then
628 record_frame Reg.Set.empty i.dbg;
629 ` {emit_string tglle}i {emit_reg i.arg.(0)}, {emit_int n}\n`
630 | Lop(Iintop_imm(op, n)) ->
631 let instr = name_for_intop_imm op in
632 ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int n}\n`
633 | Lop(Inegf | Iabsf as op) ->
634 let instr = name_for_floatop1 op in
635 ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}\n`
636 | Lop(Iaddf | Isubf | Imulf | Idivf as op) ->
637 let instr = name_for_floatop2 op in
638 ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`
639 | Lop(Ifloatofint) ->
641 ` stdu {emit_reg i.arg.(0)}, -16({emit_gpr 1})\n`;
642 ` lfd {emit_reg i.res.(0)}, 0({emit_gpr 1})\n`;
643 ` addi {emit_gpr 1}, {emit_gpr 1}, 16\n`;
644 ` fcfid {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n`
646 let lbl = new_label() in
647 float_literals := ("4.503601774854144e15", lbl) :: !float_literals;
648 (* That float above represents 0x4330000080000000 *)
649 ` addis {emit_gpr 11}, 0, {emit_upper emit_label lbl}\n`;
650 ` lfd {emit_fpr 0}, {emit_lower emit_label lbl}({emit_gpr 11})\n`;
651 ` lis {emit_gpr 0}, 0x4330\n`;
652 ` stwu {emit_gpr 0}, -16({emit_gpr 1})\n`;
653 ` xoris {emit_gpr 0}, {emit_reg i.arg.(0)}, 0x8000\n`;
654 ` stw {emit_gpr 0}, 4({emit_gpr 1})\n`;
655 ` lfd {emit_reg i.res.(0)}, 0({emit_gpr 1})\n`;
656 ` addi {emit_gpr 1}, {emit_gpr 1}, 16\n`;
657 ` fsub {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, {emit_fpr 0}\n`
659 | Lop(Iintoffloat) ->
660 let ofs = if ppc64 then 0 else 4 in
661 ` {emit_string fctigz} {emit_fpr 0}, {emit_reg i.arg.(0)}\n`;
662 ` stfdu {emit_fpr 0}, -16({emit_gpr 1})\n`;
663 ` {emit_string lg} {emit_reg i.res.(0)}, {emit_int ofs}({emit_gpr 1})\n`;
664 ` addi {emit_gpr 1}, {emit_gpr 1}, 16\n`
665 | Lop(Ispecific sop) ->
666 let instr = name_for_specific sop in
667 ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(2)}\n`
669 let n = frame_size() in
670 ` {emit_string lg} {emit_gpr 11}, {emit_int(n - size_addr)}({emit_gpr 1})\n`;
671 ` mtlr {emit_gpr 11}\n`
673 let n = frame_size() in
675 ` addi {emit_gpr 1}, {emit_gpr 1}, {emit_int n}\n`;
678 `{emit_label lbl}:\n`
680 ` b {emit_label lbl}\n`
681 | Lcondbranch(tst, lbl) ->
684 ` {emit_string cmpg}i {emit_reg i.arg.(0)}, 0\n`;
686 ` bne {emit_label lbl}\n`
688 ` {emit_string cmpg}i {emit_reg i.arg.(0)}, 0\n`;
690 ` beq {emit_label lbl}\n`
692 let (comp, branch) = name_for_int_comparison cmp in
693 ` {emit_string comp} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
695 ` {emit_string branch} {emit_label lbl}\n`
696 | Iinttest_imm(cmp, n) ->
697 let (comp, branch) = name_for_int_comparison cmp in
698 ` {emit_string comp}i {emit_reg i.arg.(0)}, {emit_int n}\n`;
700 ` {emit_string branch} {emit_label lbl}\n`
701 | Ifloattest(cmp, neg) ->
702 ` fcmpu {emit_ccr 0}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
703 (* bit 0 = lt, bit 1 = gt, bit 2 = eq *)
704 let (bitnum, negtst) =
707 | Cne -> (2, not neg)
708 | Cle -> ` cror 3, 0, 2\n`; (* lt or eq *)
711 | Cge -> ` cror 3, 1, 2\n`; (* gt or eq *)
716 then ` bf {emit_int bitnum}, {emit_label lbl}\n`
717 else ` bt {emit_int bitnum}, {emit_label lbl}\n`
719 ` andi. {emit_gpr 0}, {emit_reg i.arg.(0)}, 1\n`;
721 ` bne {emit_label lbl}\n`
723 ` andi. {emit_gpr 0}, {emit_reg i.arg.(0)}, 1\n`;
725 ` beq {emit_label lbl}\n`
727 | Lcondbranch3(lbl0, lbl1, lbl2) ->
728 ` {emit_string cmpg}i {emit_reg i.arg.(0)}, 1\n`;
730 begin match lbl0 with
732 | Some lbl -> ` blt {emit_label lbl}\n`
734 begin match lbl1 with
736 | Some lbl -> ` beq {emit_label lbl}\n`
738 begin match lbl2 with
740 | Some lbl -> ` bgt {emit_label lbl}\n`
743 let lbl = new_label() in
744 ` addis {emit_gpr 11}, 0, {emit_upper emit_label lbl}\n`;
745 ` addi {emit_gpr 11}, {emit_gpr 11}, {emit_lower emit_label lbl}\n`;
746 ` {emit_string slgi} {emit_gpr 0}, {emit_reg i.arg.(0)}, 2\n`;
747 ` {emit_string lwa}x {emit_gpr 0}, {emit_gpr 11}, {emit_gpr 0}\n`;
748 ` add {emit_gpr 0}, {emit_gpr 11}, {emit_gpr 0}\n`;
749 ` mtctr {emit_gpr 0}\n`;
751 emit_string rodata_space;
753 for i = 0 to Array.length jumptbl - 1 do
754 ` .long {emit_label jumptbl.(i)} - {emit_label lbl}\n`
756 emit_string code_space
758 ` bl {emit_label lbl}\n`
760 stack_offset := !stack_offset + 16;
761 ` mflr {emit_gpr 0}\n`;
762 ` {emit_string stg}u {emit_gpr 0}, -16({emit_gpr 1})\n`;
763 ` {emit_string stg} {emit_gpr 29}, {emit_int size_addr}({emit_gpr 1})\n`;
764 ` mr {emit_gpr 29}, {emit_gpr 1}\n`
766 ` {emit_string lg} {emit_gpr 29}, {emit_int size_addr}({emit_gpr 1})\n`;
767 ` addi {emit_gpr 1}, {emit_gpr 1}, 16\n`;
768 stack_offset := !stack_offset - 16
770 if !Clflags.debug && supports_backtraces then begin
771 ` bl {emit_symbol "caml_raise_exn"}\n`;
772 record_frame Reg.Set.empty i.dbg
774 ` {emit_string lg} {emit_gpr 0}, 0({emit_gpr 29})\n`;
775 ` mr {emit_gpr 1}, {emit_gpr 29}\n`;
776 ` mtlr {emit_gpr 0}\n`;
777 ` {emit_string lg} {emit_gpr 29}, {emit_int size_addr}({emit_gpr 1})\n`;
778 ` addi {emit_gpr 1}, {emit_gpr 1}, 16\n`;
782 and emit_delay = function
784 | Some i -> emit_instr i None
786 (* Checks if a pseudo-instruction expands to instructions
787 that do not branch and do not affect CR0 nor R12. *)
789 let is_simple_instr i =
793 Icall_imm _ | Icall_ind | Itailcall_imm _ | Itailcall_ind |
794 Iextcall(_, _) -> false
796 | Iintop(Icomp _) -> false
797 | Iintop_imm(Iand, _) -> false
798 | Iintop_imm(Icomp _, _) -> false
801 | Lreloadretaddr -> true
804 let no_interference res arg =
806 for i = 0 to Array.length arg - 1 do
807 for j = 0 to Array.length res - 1 do
808 if arg.(i).loc = res.(j).loc then raise Exit
815 (* Emit a sequence of instructions, trying to fill delay slots for branches *)
820 | {next = {desc = (Lcondbranch(_, _) | Lcondbranch3(_, _, _))}}
821 when is_simple_instr i & no_interference i.res i.next.arg ->
822 emit_instr i.next (Some i);
828 (* Emission of a function declaration *)
830 let fundecl fundecl =
831 function_name := fundecl.fun_name;
832 defined_functions := StringSet.add fundecl.fun_name !defined_functions;
833 tailrec_entry_point := new_label();
836 float_literals := [];
838 if Config.system = "rhapsody"
839 && not !Clflags.output_c_object
840 && is_generic_function fundecl.fun_name
842 ` .private_extern {emit_symbol fundecl.fun_name}\n`
844 ` .globl {emit_symbol fundecl.fun_name}\n`;
845 begin match Config.system with
847 ` .type {emit_symbol fundecl.fun_name}, @function\n`
850 emit_string code_space;
852 `{emit_symbol fundecl.fun_name}:\n`;
853 let n = frame_size() in
854 if !contains_calls then begin
855 ` mflr {emit_gpr 0}\n`;
856 ` addi {emit_gpr 1}, {emit_gpr 1}, {emit_int(-n)}\n`;
857 ` {emit_string stg} {emit_gpr 0}, {emit_int(n - size_addr)}({emit_gpr 1})\n`
860 ` addi {emit_gpr 1}, {emit_gpr 1}, {emit_int(-n)}\n`
862 `{emit_label !tailrec_entry_point}:\n`;
863 branch_normalization fundecl.fun_body;
864 emit_all fundecl.fun_body;
865 (* Emit the glue code to call the GC *)
866 if !call_gc_label > 0 then begin
867 `{emit_label !call_gc_label}:\n`;
868 ` b {emit_symbol "caml_call_gc"}\n`
870 (* Emit the numeric literals *)
871 if !float_literals <> [] || !int_literals <> [] then begin
872 emit_string rodata_space;
878 then emit_float64_directive ".quad" f
879 else emit_float64_split_directive ".long" f)
883 `{emit_label lbl}: {emit_string datag} {emit_nativeint n}\n`)
887 (* Emission of data *)
889 let declare_global_data s =
890 ` .globl {emit_symbol s}\n`;
891 if Config.system = "elf" || Config.system = "bsd" then
892 ` .type {emit_symbol s}, @object\n`
894 let emit_item = function
896 declare_global_data s
897 | Cdefine_symbol s ->
898 `{emit_symbol s}:\n`;
899 | Cdefine_label lbl ->
900 `{emit_label (lbl + 100000)}:\n`
902 ` .byte {emit_int n}\n`
904 ` .short {emit_int n}\n`
906 ` .long {emit_nativeint n}\n`
908 ` {emit_string datag} {emit_nativeint n}\n`
910 emit_float32_directive ".long" f
913 then emit_float64_directive ".quad" f
914 else emit_float64_split_directive ".long" f
915 | Csymbol_address s ->
916 ` {emit_string datag} {emit_symbol s}\n`
917 | Clabel_address lbl ->
918 ` {emit_string datag} {emit_label (lbl + 100000)}\n`
920 emit_bytes_directive " .byte " s
922 if n > 0 then ` .space {emit_int n}\n`
924 ` .align {emit_int (Misc.log2 n)}\n`
927 emit_string data_space;
928 List.iter emit_item l
930 (* Beginning / end of an assembly file *)
932 let begin_assembly() =
933 defined_functions := StringSet.empty;
934 external_functions := StringSet.empty;
935 (* Emit the beginning of the segments *)
936 let lbl_begin = Compilenv.make_symbol (Some "data_begin") in
937 emit_string data_space;
938 declare_global_data lbl_begin;
939 `{emit_symbol lbl_begin}:\n`;
940 let lbl_begin = Compilenv.make_symbol (Some "code_begin") in
941 emit_string code_space;
942 declare_global_data lbl_begin;
943 `{emit_symbol lbl_begin}:\n`
946 if pic_externals then
947 (* Emit the pointers to external functions *)
948 StringSet.iter emit_external !external_functions;
949 (* Emit the end of the segments *)
950 emit_string code_space;
951 let lbl_end = Compilenv.make_symbol (Some "code_end") in
952 declare_global_data lbl_end;
953 `{emit_symbol lbl_end}:\n`;
955 emit_string data_space;
956 let lbl_end = Compilenv.make_symbol (Some "data_end") in
957 declare_global_data lbl_end;
958 `{emit_symbol lbl_end}:\n`;
959 ` {emit_string datag} 0\n`;
960 (* Emit the frame descriptors *)
961 emit_string rodata_space;
962 let lbl = Compilenv.make_symbol (Some "frametable") in
963 declare_global_data lbl;
964 `{emit_symbol lbl}:\n`;
966 { efa_label = (fun l -> ` {emit_string datag} {emit_label l}\n`);
967 efa_16 = (fun n -> ` .short {emit_int n}\n`);
968 efa_32 = (fun n -> ` .long {emit_int32 n}\n`);
969 efa_word = (fun n -> ` {emit_string datag} {emit_int n}\n`);
970 efa_align = (fun n -> ` .align {emit_int (Misc.log2 n)}\n`);
971 efa_label_rel = (fun lbl ofs ->
972 ` .long ({emit_label lbl} - .) + {emit_int32 ofs}\n`);
973 efa_def_label = (fun l -> `{emit_label l}:\n`);
974 efa_string = (fun s -> emit_bytes_directive " .byte " (s ^ "\000"))