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 Intel 386 assembly code *)
17 module StringSet = Set.Make(struct type t = string let compare = compare end)
29 (* Tradeoff between code size and code speed *)
31 let fastcode_flag = ref true
33 let stack_offset = ref 0
35 (* Layout of the stack frame *)
37 let frame_size () = (* includes return address *)
39 !stack_offset + 4 * num_stack_slots.(0) + 8 * num_stack_slots.(1) + 4
40 in Misc.align sz stack_alignment
42 let slot_offset loc cl =
49 then !stack_offset + n * 4
50 else !stack_offset + num_stack_slots.(0) * 4 + n * 8
55 let trap_frame_size = Misc.align 8 stack_alignment
57 (* Prefixing of symbols with "_" *)
60 match Config.system with
69 emit_string symbol_prefix; Emitaux.emit_symbol '$' s
74 match Config.system with
83 emit_string label_prefix; emit_int lbl
86 (* Some data directives have different names under Solaris *)
89 match Config.system with
93 match Config.system with
97 match Config.system with
101 (* MacOSX has its own way to reference symbols potentially defined in
105 match Config.system with
109 (* Output a .align directive.
110 The numerical argument to .align is log2 of alignment size, except
111 under ELF, where it is the alignment size... *)
114 match Config.system with
115 "linux_elf" | "bsd_elf" | "solaris" | "beos" | "cygwin" | "mingw" | "gnu" ->
116 (fun n -> ` .align {emit_int n}\n`)
118 (fun n -> ` .align {emit_int(Misc.log2 n)}\n`)
120 let emit_Llabel fallthrough lbl =
121 if not fallthrough && !fastcode_flag then
125 (* Output a pseudo-register *)
127 let emit_reg = function
129 emit_string (register_name r)
130 | { loc = Stack(Incoming n | Outgoing n) } when n < 0 ->
131 `{emit_symbol "caml_extra_params"} + {emit_int (n + 64)}`
132 | { loc = Stack s } as r ->
133 let ofs = slot_offset s (register_class r) in
134 `{emit_int ofs}(%esp)`
135 | { loc = Unknown } ->
136 fatal_error "Emit_i386.emit_reg"
138 (* Output a reference to the lower 8 bits or lower 16 bits of a register *)
140 let reg_low_byte_name = [| "%al"; "%bl"; "%cl"; "%dl" |]
141 let reg_low_half_name = [| "%ax"; "%bx"; "%cx"; "%dx"; "%si"; "%di"; "%bp" |]
145 Reg r when r < 4 -> emit_string (reg_low_byte_name.(r))
146 | _ -> fatal_error "Emit_i386.emit_reg8"
150 Reg r when r < 7 -> emit_string (reg_low_half_name.(r))
151 | _ -> fatal_error "Emit_i386.emit_reg16"
153 (* Output an addressing mode *)
155 let emit_addressing addr r n =
159 if d <> 0 then ` + {emit_int d}`
161 if d <> 0 then emit_int d;
164 if d <> 0 then emit_int d;
165 `({emit_reg r.(n)}, {emit_reg r.(n+1)})`
167 if d <> 0 then emit_int d;
168 `({emit_reg r.(n)}, {emit_reg r.(n)})`
169 | Iscaled(scale, d) ->
170 if d <> 0 then emit_int d;
171 `(, {emit_reg r.(n)}, {emit_int scale})`
172 | Iindexed2scaled(scale, d) ->
173 if d <> 0 then emit_int d;
174 `({emit_reg r.(n)}, {emit_reg r.(n+1)}, {emit_int scale})`
176 (* Record live pointers at call points *)
178 let record_frame_label live dbg =
179 let lbl = new_label() in
180 let live_offset = ref [] in
183 {typ = Addr; loc = Reg r} ->
184 live_offset := ((r lsl 1) + 1) :: !live_offset
185 | {typ = Addr; loc = Stack s} as reg ->
186 live_offset := slot_offset s (register_class reg) :: !live_offset
191 fd_frame_size = frame_size();
192 fd_live_offset = !live_offset;
193 fd_debuginfo = dbg } :: !frame_descriptors;
196 let record_frame live dbg =
197 let lbl = record_frame_label live dbg in `{emit_label lbl}:\n`
199 (* Record calls to the GC -- we've moved them out of the way *)
202 { gc_lbl: label; (* Entry label *)
203 gc_return_lbl: label; (* Where to branch after GC *)
204 gc_frame: label } (* Label of frame descriptor *)
206 let call_gc_sites = ref ([] : gc_call list)
208 let emit_call_gc gc =
209 `{emit_label gc.gc_lbl}: call {emit_symbol "caml_call_gc"}\n`;
210 `{emit_label gc.gc_frame}: jmp {emit_label gc.gc_return_lbl}\n`
212 (* Record calls to caml_ml_array_bound_error.
213 In -g mode, we maintain one call to caml_ml_array_bound_error
214 per bound check site. Without -g, we can share a single call. *)
216 type bound_error_call =
217 { bd_lbl: label; (* Entry label *)
218 bd_frame: label } (* Label of frame descriptor *)
220 let bound_error_sites = ref ([] : bound_error_call list)
221 let bound_error_call = ref 0
223 let bound_error_label dbg =
224 if !Clflags.debug then begin
225 let lbl_bound_error = new_label() in
226 let lbl_frame = record_frame_label Reg.Set.empty dbg in
228 { bd_lbl = lbl_bound_error; bd_frame = lbl_frame } :: !bound_error_sites;
231 if !bound_error_call = 0 then bound_error_call := new_label();
235 let emit_call_bound_error bd =
236 `{emit_label bd.bd_lbl}: call {emit_symbol "caml_ml_array_bound_error"}\n`;
237 `{emit_label bd.bd_frame}:\n`
239 let emit_call_bound_errors () =
240 List.iter emit_call_bound_error !bound_error_sites;
241 if !bound_error_call > 0 then
242 `{emit_label !bound_error_call}: call {emit_symbol "caml_ml_array_bound_error"}\n`
244 (* Names for instructions *)
246 let instr_for_intop = function
256 | _ -> fatal_error "Emit_i386: instr_for_intop"
258 let instr_for_floatop = function
265 | Ispecific Isubfrev -> "fsubrl"
266 | Ispecific Idivfrev -> "fdivrl"
267 | _ -> fatal_error "Emit_i386: instr_for_floatop"
269 let instr_for_floatop_reversed = function
274 | Ispecific Isubfrev -> "fsubl"
275 | Ispecific Idivfrev -> "fdivl"
276 | _ -> fatal_error "Emit_i386: instr_for_floatop_reversed"
278 let instr_for_floatop_pop = function
283 | Ispecific Isubfrev -> "fsubrp"
284 | Ispecific Idivfrev -> "fdivrp"
285 | _ -> fatal_error "Emit_i386: instr_for_floatop_pop"
287 let instr_for_floatarithmem double = function
288 Ifloatadd -> if double then "faddl" else "fadds"
289 | Ifloatsub -> if double then "fsubl" else "fsubs"
290 | Ifloatsubrev -> if double then "fsubrl" else "fsubrs"
291 | Ifloatmul -> if double then "fmull" else "fmuls"
292 | Ifloatdiv -> if double then "fdivl" else "fdivs"
293 | Ifloatdivrev -> if double then "fdivrl" else "fdivrs"
295 let name_for_cond_branch = function
296 Isigned Ceq -> "e" | Isigned Cne -> "ne"
297 | Isigned Cle -> "le" | Isigned Cgt -> "g"
298 | Isigned Clt -> "l" | Isigned Cge -> "ge"
299 | Iunsigned Ceq -> "e" | Iunsigned Cne -> "ne"
300 | Iunsigned Cle -> "be" | Iunsigned Cgt -> "a"
301 | Iunsigned Clt -> "b" | Iunsigned Cge -> "ae"
303 (* Output an = 0 or <> 0 test. *)
305 let output_test_zero arg =
307 Reg r -> ` testl {emit_reg arg}, {emit_reg arg}\n`
308 | _ -> ` cmpl $0, {emit_reg arg}\n`
310 (* Deallocate the stack frame before a return or tail call *)
312 let output_epilogue () =
313 let n = frame_size() - 4 in
314 if n > 0 then ` addl ${emit_int n}, %esp\n`
316 (* Determine if the given register is the top of the floating-point stack *)
318 let is_tos = function { loc = Reg _; typ = Float } -> true | _ -> false
320 (* Emit the code for a floating-point comparison *)
322 let emit_float_test cmp neg arg lbl =
324 match (is_tos arg.(0), is_tos arg.(1)) with
326 (* both args on top of FP stack *)
330 (* first arg on top of FP stack *)
331 ` fcompl {emit_reg arg.(1)}\n`;
334 (* second arg on top of FP stack *)
335 ` fcompl {emit_reg arg.(0)}\n`;
336 Cmm.swap_comparison cmp
338 ` fldl {emit_reg arg.(0)}\n`;
339 ` fcompl {emit_reg arg.(1)}\n`;
343 begin match actual_cmp with
390 (* Emit a Ifloatspecial instruction *)
392 let emit_floatspecial = function
393 "atan" -> ` fld1; fpatan\n`
394 | "atan2" -> ` fpatan\n`
396 | "log" -> ` fldln2; fxch; fyl2x\n`
397 | "log10" -> ` fldlg2; fxch; fyl2x\n`
399 | "sqrt" -> ` fsqrt\n`
400 | "tan" -> ` fptan; fstp %st(0)\n`
403 (* Output the assembly code for an instruction *)
405 (* Name of current function *)
406 let function_name = ref ""
407 (* Entry point for tail recursive calls *)
408 let tailrec_entry_point = ref 0
409 (* Label of trap for out-of-range accesses *)
410 let range_check_trap = ref 0
411 (* Record float literals to be emitted later *)
412 let float_constants = ref ([] : (int * string) list)
413 (* Record references to external C functions (for MacOSX) *)
414 let external_symbols_direct = ref StringSet.empty
415 let external_symbols_indirect = ref StringSet.empty
417 let emit_instr fallthrough i =
420 | Lop(Imove | Ispill | Ireload) ->
421 let src = i.arg.(0) and dst = i.res.(0) in
422 if src.loc <> dst.loc then begin
423 if src.typ = Float then
425 ` fstpl {emit_reg dst}\n`
426 else if is_tos dst then
427 ` fldl {emit_reg src}\n`
429 ` fldl {emit_reg src}\n`;
430 ` fstpl {emit_reg dst}\n`
433 ` movl {emit_reg src}, {emit_reg dst}\n`
435 | Lop(Iconst_int n) ->
437 match i.res.(0).loc with
438 Reg n -> ` xorl {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n`
439 | _ -> ` movl $0, {emit_reg i.res.(0)}\n`
441 ` movl ${emit_nativeint n}, {emit_reg i.res.(0)}\n`
442 | Lop(Iconst_float s) ->
443 begin match Int64.bits_of_float (float_of_string s) with
444 | 0x0000_0000_0000_0000L -> (* +0.0 *)
446 | 0x8000_0000_0000_0000L -> (* -0.0 *)
448 | 0x3FF0_0000_0000_0000L -> (* 1.0 *)
450 | 0xBFF0_0000_0000_0000L -> (* -1.0 *)
453 let lbl = new_label() in
454 float_constants := (lbl, s) :: !float_constants;
455 ` fldl {emit_label lbl}\n`
457 | Lop(Iconst_symbol s) ->
458 ` movl ${emit_symbol s}, {emit_reg i.res.(0)}\n`
460 ` call *{emit_reg i.arg.(0)}\n`;
461 record_frame i.live i.dbg
462 | Lop(Icall_imm s) ->
463 ` call {emit_symbol s}\n`;
464 record_frame i.live i.dbg
465 | Lop(Itailcall_ind) ->
467 ` jmp *{emit_reg i.arg.(0)}\n`
468 | Lop(Itailcall_imm s) ->
469 if s = !function_name then
470 ` jmp {emit_label !tailrec_entry_point}\n`
473 ` jmp {emit_symbol s}\n`
475 | Lop(Iextcall(s, alloc)) ->
478 ` movl ${emit_symbol s}, %eax\n`
480 external_symbols_indirect :=
481 StringSet.add s !external_symbols_indirect;
482 ` movl L{emit_symbol s}$non_lazy_ptr, %eax\n`
484 ` call {emit_symbol "caml_c_call"}\n`;
485 record_frame i.live i.dbg
488 ` call {emit_symbol s}\n`
490 external_symbols_direct :=
491 StringSet.add s !external_symbols_direct;
492 ` call L{emit_symbol s}$stub\n`
495 | Lop(Istackoffset n) ->
497 then ` addl ${emit_int(-n)}, %esp\n`
498 else ` subl ${emit_int(n)}, %esp\n`;
499 stack_offset := !stack_offset + n
500 | Lop(Iload(chunk, addr)) ->
501 let dest = i.res.(0) in
502 begin match chunk with
503 | Word | Thirtytwo_signed | Thirtytwo_unsigned ->
504 ` movl {emit_addressing addr i.arg 0}, {emit_reg dest}\n`
506 ` movzbl {emit_addressing addr i.arg 0}, {emit_reg dest}\n`
508 ` movsbl {emit_addressing addr i.arg 0}, {emit_reg dest}\n`
509 | Sixteen_unsigned ->
510 ` movzwl {emit_addressing addr i.arg 0}, {emit_reg dest}\n`
512 ` movswl {emit_addressing addr i.arg 0}, {emit_reg dest}\n`
514 ` flds {emit_addressing addr i.arg 0}\n`
515 | Double | Double_u ->
516 ` fldl {emit_addressing addr i.arg 0}\n`
518 | Lop(Istore(chunk, addr)) ->
519 begin match chunk with
520 | Word | Thirtytwo_signed | Thirtytwo_unsigned ->
521 ` movl {emit_reg i.arg.(0)}, {emit_addressing addr i.arg 1}\n`
522 | Byte_unsigned | Byte_signed ->
523 ` movb {emit_reg8 i.arg.(0)}, {emit_addressing addr i.arg 1}\n`
524 | Sixteen_unsigned | Sixteen_signed ->
525 ` movw {emit_reg16 i.arg.(0)}, {emit_addressing addr i.arg 1}\n`
527 if is_tos i.arg.(0) then
528 ` fstps {emit_addressing addr i.arg 1}\n`
530 ` fldl {emit_reg i.arg.(0)}\n`;
531 ` fstps {emit_addressing addr i.arg 1}\n`
533 | Double | Double_u ->
534 if is_tos i.arg.(0) then
535 ` fstpl {emit_addressing addr i.arg 1}\n`
537 ` fldl {emit_reg i.arg.(0)}\n`;
538 ` fstpl {emit_addressing addr i.arg 1}\n`
542 if !fastcode_flag then begin
543 let lbl_redo = new_label() in
544 `{emit_label lbl_redo}: movl {emit_symbol "caml_young_ptr"}, %eax\n`;
545 ` subl ${emit_int n}, %eax\n`;
546 ` movl %eax, {emit_symbol "caml_young_ptr"}\n`;
547 ` cmpl {emit_symbol "caml_young_limit"}, %eax\n`;
548 let lbl_call_gc = new_label() in
549 let lbl_frame = record_frame_label i.live Debuginfo.none in
550 ` jb {emit_label lbl_call_gc}\n`;
551 ` leal 4(%eax), {emit_reg i.res.(0)}\n`;
553 { gc_lbl = lbl_call_gc;
554 gc_return_lbl = lbl_redo;
555 gc_frame = lbl_frame } :: !call_gc_sites
558 8 -> ` call {emit_symbol "caml_alloc1"}\n`
559 | 12 -> ` call {emit_symbol "caml_alloc2"}\n`
560 | 16 -> ` call {emit_symbol "caml_alloc3"}\n`
561 | _ -> ` movl ${emit_int n}, %eax\n`;
562 ` call {emit_symbol "caml_allocN"}\n`
564 `{record_frame i.live Debuginfo.none} leal 4(%eax), {emit_reg i.res.(0)}\n`
566 | Lop(Iintop(Icomp cmp)) ->
567 ` cmpl {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`;
568 let b = name_for_cond_branch cmp in
569 ` set{emit_string b} %al\n`;
570 ` movzbl %al, {emit_reg i.res.(0)}\n`
571 | Lop(Iintop_imm(Icomp cmp, n)) ->
572 ` cmpl ${emit_int n}, {emit_reg i.arg.(0)}\n`;
573 let b = name_for_cond_branch cmp in
574 ` set{emit_string b} %al\n`;
575 ` movzbl %al, {emit_reg i.res.(0)}\n`
576 | Lop(Iintop Icheckbound) ->
577 let lbl = bound_error_label i.dbg in
578 ` cmpl {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`;
579 ` jbe {emit_label lbl}\n`
580 | Lop(Iintop_imm(Icheckbound, n)) ->
581 let lbl = bound_error_label i.dbg in
582 ` cmpl ${emit_int n}, {emit_reg i.arg.(0)}\n`;
583 ` jbe {emit_label lbl}\n`
584 | Lop(Iintop(Idiv | Imod)) ->
586 ` idivl {emit_reg i.arg.(1)}\n`
587 | Lop(Iintop(Ilsl | Ilsr | Iasr as op)) ->
588 (* We have i.arg.(0) = i.res.(0) and i.arg.(1) = %ecx *)
589 ` {emit_string(instr_for_intop op)} %cl, {emit_reg i.res.(0)}\n`
591 (* We have i.arg.(0) = i.res.(0) *)
592 ` {emit_string(instr_for_intop op)} {emit_reg i.arg.(1)}, {emit_reg i.res.(0)}\n`
593 | Lop(Iintop_imm(Iadd, n)) when i.arg.(0).loc <> i.res.(0).loc ->
594 ` leal {emit_int n}({emit_reg i.arg.(0)}), {emit_reg i.res.(0)}\n`
595 | Lop(Iintop_imm(Iadd, 1) | Iintop_imm(Isub, -1)) ->
596 ` incl {emit_reg i.res.(0)}\n`
597 | Lop(Iintop_imm(Iadd, -1) | Iintop_imm(Isub, 1)) ->
598 ` decl {emit_reg i.res.(0)}\n`
599 | Lop(Iintop_imm(Idiv, n)) ->
600 let l = Misc.log2 n in
601 let lbl = new_label() in
602 output_test_zero i.arg.(0);
603 ` jge {emit_label lbl}\n`;
604 ` addl ${emit_int(n-1)}, {emit_reg i.arg.(0)}\n`;
605 `{emit_label lbl}: sarl ${emit_int l}, {emit_reg i.arg.(0)}\n`
606 | Lop(Iintop_imm(Imod, n)) ->
607 let lbl = new_label() in
608 ` movl {emit_reg i.arg.(0)}, %eax\n`;
609 ` testl %eax, %eax\n`;
610 ` jge {emit_label lbl}\n`;
611 ` addl ${emit_int(n-1)}, %eax\n`;
612 `{emit_label lbl}: andl ${emit_int(-n)}, %eax\n`;
613 ` subl %eax, {emit_reg i.arg.(0)}\n`
614 | Lop(Iintop_imm(op, n)) ->
615 (* We have i.arg.(0) = i.res.(0) *)
616 ` {emit_string(instr_for_intop op)} ${emit_int n}, {emit_reg i.res.(0)}\n`
617 | Lop(Inegf | Iabsf as floatop) ->
618 if not (is_tos i.arg.(0)) then
619 ` fldl {emit_reg i.arg.(0)}\n`;
620 ` {emit_string(instr_for_floatop floatop)}\n`
621 | Lop(Iaddf | Isubf | Imulf | Idivf | Ispecific(Isubfrev | Idivfrev)
623 begin match (is_tos i.arg.(0), is_tos i.arg.(1)) with
625 (* both operands on top of FP stack *)
626 ` {emit_string(instr_for_floatop_pop floatop)} %st, %st(1)\n`
628 (* first operand on stack *)
629 ` {emit_string(instr_for_floatop floatop)} {emit_reg i.arg.(1)}\n`
631 (* second operand on stack *)
632 ` {emit_string(instr_for_floatop_reversed floatop)} {emit_reg i.arg.(0)}\n`
634 (* both operands in memory *)
635 ` fldl {emit_reg i.arg.(0)}\n`;
636 ` {emit_string(instr_for_floatop floatop)} {emit_reg i.arg.(1)}\n`
638 | Lop(Ifloatofint) ->
639 begin match i.arg.(0).loc with
641 ` fildl {emit_reg i.arg.(0)}\n`
643 ` pushl {emit_reg i.arg.(0)}\n`;
647 | Lop(Iintoffloat) ->
648 if not (is_tos i.arg.(0)) then
649 ` fldl {emit_reg i.arg.(0)}\n`;
650 stack_offset := !stack_offset - 8;
653 ` movw 4(%esp), %ax\n`;
655 ` movw %ax, 0(%esp)\n`;
657 begin match i.res.(0).loc with
659 ` fistpl {emit_reg i.res.(0)}\n`
662 ` movl (%esp), {emit_reg i.res.(0)}\n`
666 stack_offset := !stack_offset + 8
667 | Lop(Ispecific(Ilea addr)) ->
668 ` lea {emit_addressing addr i.arg 0}, {emit_reg i.res.(0)}\n`
669 | Lop(Ispecific(Istore_int(n, addr))) ->
670 ` movl ${emit_nativeint n}, {emit_addressing addr i.arg 0}\n`
671 | Lop(Ispecific(Istore_symbol(s, addr))) ->
672 ` movl ${emit_symbol s}, {emit_addressing addr i.arg 0}\n`
673 | Lop(Ispecific(Ioffset_loc(n, addr))) ->
674 ` addl ${emit_int n}, {emit_addressing addr i.arg 0}\n`
675 | Lop(Ispecific(Ipush)) ->
676 (* Push arguments in reverse order *)
677 for n = Array.length i.arg - 1 downto 0 do
680 {loc = Reg _; typ = Float} ->
683 stack_offset := !stack_offset + 8
684 | {loc = Stack sl; typ = Float} ->
685 let ofs = slot_offset sl 1 in
686 ` pushl {emit_int(ofs + 4)}(%esp)\n`;
687 ` pushl {emit_int(ofs + 4)}(%esp)\n`;
688 stack_offset := !stack_offset + 8
690 ` pushl {emit_reg r}\n`;
691 stack_offset := !stack_offset + 4
693 | Lop(Ispecific(Ipush_int n)) ->
694 ` pushl ${emit_nativeint n}\n`;
695 stack_offset := !stack_offset + 4
696 | Lop(Ispecific(Ipush_symbol s)) ->
697 ` pushl ${emit_symbol s}\n`;
698 stack_offset := !stack_offset + 4
699 | Lop(Ispecific(Ipush_load addr)) ->
700 ` pushl {emit_addressing addr i.arg 0}\n`;
701 stack_offset := !stack_offset + 4
702 | Lop(Ispecific(Ipush_load_float addr)) ->
703 ` pushl {emit_addressing (offset_addressing addr 4) i.arg 0}\n`;
704 ` pushl {emit_addressing addr i.arg 0}\n`;
705 stack_offset := !stack_offset + 8
706 | Lop(Ispecific(Ifloatarithmem(double, op, addr))) ->
707 if not (is_tos i.arg.(0)) then
708 ` fldl {emit_reg i.arg.(0)}\n`;
709 ` {emit_string(instr_for_floatarithmem double op)} {emit_addressing addr i.arg 1}\n`
710 | Lop(Ispecific(Ifloatspecial s)) ->
711 (* Push args on float stack if necessary *)
712 for k = 0 to Array.length i.arg - 1 do
713 if not (is_tos i.arg.(k)) then ` fldl {emit_reg i.arg.(k)}\n`
715 (* Fix-up for binary instrs whose args were swapped *)
716 if Array.length i.arg = 2 && is_tos i.arg.(1) then
725 `{emit_Llabel fallthrough lbl}:\n`
727 ` jmp {emit_label lbl}\n`
728 | Lcondbranch(tst, lbl) ->
731 output_test_zero i.arg.(0);
732 ` jne {emit_label lbl}\n`
734 output_test_zero i.arg.(0);
735 ` je {emit_label lbl}\n`
737 ` cmpl {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`;
738 let b = name_for_cond_branch cmp in
739 ` j{emit_string b} {emit_label lbl}\n`
740 | Iinttest_imm((Isigned Ceq | Isigned Cne |
741 Iunsigned Ceq | Iunsigned Cne) as cmp, 0) ->
742 output_test_zero i.arg.(0);
743 let b = name_for_cond_branch cmp in
744 ` j{emit_string b} {emit_label lbl}\n`
745 | Iinttest_imm(cmp, n) ->
746 ` cmpl ${emit_int n}, {emit_reg i.arg.(0)}\n`;
747 let b = name_for_cond_branch cmp in
748 ` j{emit_string b} {emit_label lbl}\n`
749 | Ifloattest(cmp, neg) ->
750 emit_float_test cmp neg i.arg lbl
752 ` testl $1, {emit_reg i.arg.(0)}\n`;
753 ` jne {emit_label lbl}\n`
755 ` testl $1, {emit_reg i.arg.(0)}\n`;
756 ` je {emit_label lbl}\n`
758 | Lcondbranch3(lbl0, lbl1, lbl2) ->
759 ` cmpl $1, {emit_reg i.arg.(0)}\n`;
760 begin match lbl0 with
762 | Some lbl -> ` jb {emit_label lbl}\n`
764 begin match lbl1 with
766 | Some lbl -> ` je {emit_label lbl}\n`
768 begin match lbl2 with
770 | Some lbl -> ` jg {emit_label lbl}\n`
773 let lbl = new_label() in
774 ` jmp *{emit_label lbl}(, {emit_reg i.arg.(0)}, 4)\n`;
777 for i = 0 to Array.length jumptbl - 1 do
778 ` .long {emit_label jumptbl.(i)}\n`
782 ` call {emit_label lbl}\n`
784 if trap_frame_size > 8 then
785 ` subl ${emit_int (trap_frame_size - 8)}, %esp\n`;
786 ` pushl {emit_symbol "caml_exception_pointer"}\n`;
787 ` movl %esp, {emit_symbol "caml_exception_pointer"}\n`;
788 stack_offset := !stack_offset + trap_frame_size
790 ` popl {emit_symbol "caml_exception_pointer"}\n`;
791 ` addl ${emit_int (trap_frame_size - 4)}, %esp\n`;
792 stack_offset := !stack_offset - trap_frame_size
794 if !Clflags.debug then begin
795 ` call {emit_symbol "caml_raise_exn"}\n`;
796 record_frame Reg.Set.empty i.dbg
798 ` movl {emit_symbol "caml_exception_pointer"}, %esp\n`;
799 ` popl {emit_symbol "caml_exception_pointer"}\n`;
800 if trap_frame_size > 8 then
801 ` addl ${emit_int (trap_frame_size - 8)}, %esp\n`;
805 let rec emit_all fallthrough i =
809 emit_instr fallthrough i;
811 (Linearize.has_fallthrough i.desc)
814 (* Emission of the floating-point constants *)
816 let emit_float_constant (lbl, cst) =
819 emit_float64_split_directive ".long" cst
821 (* Emission of external symbol references (for MacOSX) *)
823 let emit_external_symbol_direct s =
824 `L{emit_symbol s}$stub:\n`;
825 ` .indirect_symbol {emit_symbol s}\n`;
826 ` hlt ; hlt ; hlt ; hlt ; hlt\n`
828 let emit_external_symbol_indirect s =
829 `L{emit_symbol s}$non_lazy_ptr:\n`;
830 ` .indirect_symbol {emit_symbol s}\n`;
833 let emit_external_symbols () =
834 ` .section __IMPORT,__pointers,non_lazy_symbol_pointers\n`;
835 StringSet.iter emit_external_symbol_indirect !external_symbols_indirect;
836 external_symbols_indirect := StringSet.empty;
837 ` .section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5\n`;
838 StringSet.iter emit_external_symbol_direct !external_symbols_direct;
839 external_symbols_direct := StringSet.empty;
840 if !Clflags.gprofile then begin
842 ` .indirect_symbol mcount\n`;
843 ` hlt ; hlt ; hlt ; hlt ; hlt\n`
846 (* Emission of the profiling prelude *)
848 let emit_profile () =
849 match Config.system with
850 "linux_elf" | "gnu" ->
852 ` movl %esp, %ebp\n`;
855 ` call {emit_symbol "mcount"}\n`;
861 ` movl %esp, %ebp\n`;
870 ` movl %esp, %ebp\n`;
873 ` call Lmcount$stub\n`;
877 | _ -> () (*unsupported yet*)
879 (* Emission of a function declaration *)
881 let fundecl fundecl =
882 function_name := fundecl.fun_name;
883 fastcode_flag := fundecl.fun_fast;
884 tailrec_entry_point := new_label();
886 float_constants := [];
888 bound_error_sites := [];
889 bound_error_call := 0;
893 && not !Clflags.output_c_object
894 && is_generic_function fundecl.fun_name
896 ` .private_extern {emit_symbol fundecl.fun_name}\n`
898 ` .globl {emit_symbol fundecl.fun_name}\n`;
899 `{emit_symbol fundecl.fun_name}:\n`;
900 if !Clflags.gprofile then emit_profile();
901 let n = frame_size() - 4 in
903 ` subl ${emit_int n}, %esp\n`;
904 `{emit_label !tailrec_entry_point}:\n`;
905 emit_all true fundecl.fun_body;
906 List.iter emit_call_gc !call_gc_sites;
907 emit_call_bound_errors ();
908 List.iter emit_float_constant !float_constants;
909 match Config.system with
910 "linux_elf" | "bsd_elf" | "gnu" ->
911 ` .type {emit_symbol fundecl.fun_name},@function\n`;
912 ` .size {emit_symbol fundecl.fun_name},.-{emit_symbol fundecl.fun_name}\n`
916 (* Emission of data *)
918 let emit_item = function
920 ` .globl {emit_symbol s}\n`;
921 | Cdefine_symbol s ->
923 | Cdefine_label lbl ->
924 `{emit_label (100000 + lbl)}:\n`
926 ` .byte {emit_int n}\n`
928 ` {emit_string word_dir} {emit_int n}\n`
930 ` .long {emit_nativeint n}\n`
932 ` .long {emit_nativeint n}\n`
934 emit_float32_directive ".long" f
936 emit_float64_split_directive ".long" f
937 | Csymbol_address s ->
938 ` .long {emit_symbol s}\n`
939 | Clabel_address lbl ->
940 ` .long {emit_label (100000 + lbl)}\n`
943 then emit_string_directive " .ascii " s
944 else emit_bytes_directive " .byte " s
946 if n > 0 then ` {emit_string skip_dir} {emit_int n}\n`
952 List.iter emit_item l
954 (* Beginning / end of an assembly file *)
956 let begin_assembly() =
957 let lbl_begin = Compilenv.make_symbol (Some "data_begin") in
959 ` .globl {emit_symbol lbl_begin}\n`;
960 `{emit_symbol lbl_begin}:\n`;
961 let lbl_begin = Compilenv.make_symbol (Some "code_begin") in
963 ` .globl {emit_symbol lbl_begin}\n`;
964 `{emit_symbol lbl_begin}:\n`;
965 if macosx then ` nop\n` (* PR#4690 *)
968 let lbl_end = Compilenv.make_symbol (Some "code_end") in
970 if macosx then ` nop\n`; (* suppress "ld warning: atom sorting error" *)
971 ` .globl {emit_symbol lbl_end}\n`;
972 `{emit_symbol lbl_end}:\n`;
974 let lbl_end = Compilenv.make_symbol (Some "data_end") in
975 ` .globl {emit_symbol lbl_end}\n`;
976 `{emit_symbol lbl_end}:\n`;
978 let lbl = Compilenv.make_symbol (Some "frametable") in
979 ` .globl {emit_symbol lbl}\n`;
980 `{emit_symbol lbl}:\n`;
982 { efa_label = (fun l -> ` .long {emit_label l}\n`);
983 efa_16 = (fun n -> ` {emit_string word_dir} {emit_int n}\n`);
984 efa_32 = (fun n -> ` .long {emit_int32 n}\n`);
985 efa_word = (fun n -> ` .long {emit_int n}\n`);
986 efa_align = emit_align;
987 efa_label_rel = (fun lbl ofs ->
988 ` .long {emit_label lbl} - . + {emit_int32 ofs}\n`);
989 efa_def_label = (fun l -> `{emit_label l}:\n`);
990 efa_string = (fun s ->
991 let s = s ^ "\000" in
993 then emit_string_directive " .ascii " s
994 else emit_bytes_directive " .byte " s) };
995 if macosx then emit_external_symbols ();
996 if Config.system = "linux_elf" then
997 (* Mark stack as non-executable, PR#4564 *)
998 `\n .section .note.GNU-stack,\"\",%progbits\n`