2 Generate x86 code from an MIR atom expression tree.
3 Copyright (C) 2002,2001 Justin David Smith, Caltech
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
40 (* Declare the types of some common variable names used in the
41 OCaml code below. In theory, these declarations can be over-
42 ridden by dcl statements when necessary. *)
59 (* Begin MIR transform code *)
63 module Pos = MakePos (struct let name = "X86_mir_atom" end)
69 let three32 = Int32.of_int 3
70 let minus_one32 = Int32.of_int (-1)
74 let reg64_lookup { cg_reg64 = reg64 } = reg64_lookup reg64
75 let fvals_lookup { cg_fvals = fvals } = fvals_lookup fvals
78 let atom_warning msg =
79 eprintf "x86_mir_atom warning: %s\n" msg
86 Checks to see if this integer atomclass is int32-manipulation
87 friendly. Bytes and words are generally represented by 32-bit
88 ints while in registers, therefore most operations that work
89 on int32 can be used unmodified for the int8, int16 cases. *)
90 let int32_ok = function
91 Rawint.Int8 | Rawint.Int16 | Rawint.Int32 -> true
92 | Rawint.Int64 -> false
96 Checks to see if the atomclass given is a valid pointer class.
97 This function will not consider ACPointerInfix to be a valid
98 pointer; such pointers must be converted to real base or offset
99 pointers before use. *)
100 let ptr_ok = function
108 | ACPointerInfix _ ->
113 If the first atom is a constant, then this reorders the atoms
114 so that appears as the second atom. Usually instructions can
115 be more easily optimized if constant terms appear as the second
116 operand, instead of the first. *)
117 let reorder_atoms a1 a2 =
121 | AtomFloat _ -> a2, a1
126 Constructs a block with instructions given, that jumps to the
127 next block as determined by running cont on operand v. This
128 is mostly just a shorthand notation for something that will
129 be /frequently/ computed... *)
130 let build_atom_block debug name insts v cont =
131 let blocks, label = cont v in
132 let block, label = code_build_dst_block debug name insts label in
133 block :: blocks, label
137 Add the instruction to the listbuf. *)
138 let add_binop_inst cons insts op1 op2 =
140 add_inst `{ cons op1 op2 `};`
146 (* build_int_of_int32
147 Build the int31 representation. *)
148 let build_int_of_int32 insts op =
154 (* build_int32_of_int
155 Build an int32 from the int31 representation. *)
156 let build_int32_of_int insts op =
162 No transformation applied to the operand indicated. *)
163 let build_nop insts _ = insts
166 (* code_int32_of_float_op
167 Coerces a floating-point value to an int32 value. This accomplishes
168 the task by loading the value onto the stack, then popping it off as
169 a signed integer. Warning: we only played the signed int game here.
170 Op has already been decoded; this constructs a new block. *)
171 let code_int32_of_float_op debug coerce op cont =
175 comm_string "Coercing a float to an int32";
178 modify_listbuf `{ coerce insts (Register float_reg_1) `};
179 movl v, float_reg_1;`
181 build_atom_block debug "coerce_int32_of_float" insts v cont
184 (* code_float_of_int32_op
185 Coerces a signed int32 to a floating-point value. This accomplishes
186 the task by loading the value onto the stack as a signed int, then
187 popping it off as a float. *)
188 let code_float_of_int32_op debug coerce op cont =
192 comm_string "Coercing an int32 to a float";
193 movl float_reg_1, op;
194 modify_listbuf `{ coerce insts (Register float_reg_1) `};
198 build_atom_block debug "coerce_float_of_int32" insts v cont
201 (* code_int32_of_rawint_op
202 Coerces a rawint of any 32-bit precision into a rawint which has
203 at most 32-bits of precision. 64-bit values are not permitted
204 here. The operand is already converted when this is called. *)
205 let code_int32_of_rawint_op pos debug pre signed op cont =
206 let pos = string_pos "code_int32_of_rawint_op" pos in
207 let mov_extend pre op =
213 let v = Register (new_symbol_string "coerce") in
217 (* Note that for 8-bit source, we must somehow ensure that
218 the register used supports 8-bit referencing; the only
219 way to do that with the current allocator is pick a
220 specific register that is safe for this purpose; I will
221 use ECX since that is always getting clobbered... *)
226 (* For other cases, we can use any hardware register. *)
227 new_symbol_string "coerce_tmp"
230 match pre, signed with
231 Rawint.Int8, true -> "int8"
232 | Rawint.Int16, true -> "int16"
233 | Rawint.Int32, true -> "int32"
234 | Rawint.Int64, true -> "int64"
235 | Rawint.Int8, false -> "uint8"
236 | Rawint.Int16, false -> "uint16"
237 | Rawint.Int32, false -> "uint32"
238 | Rawint.Int64, false -> "uint64"
240 let insts = Listbuf.of_list
241 [CommentString ("Rawint " ^ source_string ^ " to Int32 coercion");
242 code_load_int32 r op]
247 Listbuf.add insts (mov_extend IB (Register r))
249 Listbuf.add insts (mov_extend IW (Register r))
253 raise (MirException (pos, InternalError "Int64 cannot be used as a destination here"))
255 let insts = Listbuf.add insts (code_store_int32 v r) in
256 build_atom_block debug "coerce_int32_of_rawint" insts v cont
259 (* code_int64_of_float
260 Coerces a floating-point value to an int64 value. This accomplishes
261 the task by loading the value onto the stack, then popping it off as
262 a signed integer. Warning: we only played the signed int game here. *)
263 let rec code_int64_of_float cg pos debug a cont =
264 let pos = string_pos "code_int64_of_float" pos in
265 code_atom_float cg pos debug a (fun op ->
266 let insts, vhi, vlo =
269 comm_string "Coercing a float to an int64";
272 movl vlo, float_reg_1;
273 movl vhi, float_reg_2;`
275 let blocks, label = cont vhi vlo in
276 let block, label = code_build_dst_block debug "coerce_int64_of_float" insts label in
277 block :: blocks, label)
280 (* code_float_of_int64
281 Coerces a signed int64 to a floating-point value. This accomplishes
282 the task by loading the value onto the stack as a signed int, then
283 popping it off as a float. *)
284 and code_float_of_int64 cg pos debug a cont =
285 let pos = string_pos "code_float_of_int64" pos in
286 code_atom_int64 cg pos debug a (fun ohi olo ->
290 comm_string "Coercing an int64 to a float";
291 movl float_reg_1, olo;
292 movl float_reg_2, ohi;
296 build_atom_block debug "coerce_float_of_int64" insts v cont)
299 (* code_int32_of_float
303 Toplevel functions for coercing integers to floats and vice versa. *)
304 and code_int32_of_float cg pos debug a cont =
305 let pos = string_pos "code_int32_of_float" pos in
306 code_atom_float cg pos debug a (fun op ->
307 code_int32_of_float_op debug build_nop op cont)
309 and code_float_of_int32 cg pos debug a cont =
310 let pos = string_pos "code_float_of_int32" pos in
311 code_atom_int32 cg pos debug a (fun op ->
312 code_float_of_int32_op debug build_nop op cont)
314 and code_int_of_float cg pos debug a cont =
315 let pos = string_pos "code_int_of_float" pos in
316 code_atom_float cg pos debug a (fun op ->
317 code_int32_of_float_op debug build_int_of_int32 op cont)
319 and code_float_of_int cg pos debug a cont =
320 let pos = string_pos "code_float_of_int" pos in
321 code_atom_int cg pos debug a (fun op ->
322 code_float_of_int32_op debug build_int32_of_int op cont)
326 Coerces a signed int to a rawint value. *)
327 and code_int32_of_int cg pos debug a cont =
328 let pos = string_pos "code_int32_of_int" pos in
329 code_atom_int cg pos debug a (fun op ->
333 comm_string "Coercing an int to an int32";
336 let insts = build_int32_of_int insts v in
337 build_atom_block debug "coerce_int32_of_int" insts v cont)
341 Coerces a rawint value into a signed ML int. *)
342 and code_int_of_int32 cg pos debug a cont =
343 let pos = string_pos "code_int_of_int32" pos in
344 code_atom_int32 cg pos debug a (fun op ->
348 comm_string "Coercing an int32 to an int";
351 let insts = build_int_of_int32 insts v in
352 build_atom_block debug "coerce_int_of_int32" insts v cont)
355 (* code_int32_of_rawint
356 Coerces a rawint of any precision into a rawint which has
357 at most 32-bits of precision. 64-bit result values are
358 not permitted here. NOTE: the resulting type is always
359 a 32-bit value which is sign-extended or zero-extended
361 and code_int32_of_rawint cg pos debug pre signed a cont =
362 let pos = string_pos "code_int32_of_rawint" pos in
365 Assuming spre was already a 32-bit value, coerce to whatever...
366 Operand has already been converted to an int32-compatible value
367 by this point (if coercion from an int64 was necessary to begin
369 let coerce_small op =
370 code_int32_of_rawint_op pos debug pre signed op cont
374 Assuming spre was a 64-bit value, coerce to a general
375 32-bit value before applying the specific coerction to
377 let coerce_large ohi olo =
381 comm_string "Int64 to Int32 coercion";
385 build_atom_block debug "coerce_int32_of_int64" insts v cont
388 (* Determine whether we need to chop down a 64-bit value into
389 a 32-bit value... If the latter, we need to cut down the
390 64-bit value before continuing... *)
392 code_atom_int32 cg pos debug a coerce_small
394 code_atom_int64 cg pos debug a coerce_large
397 (* code_int64_of_rawint
398 Coerce a rawint value of any precision into a 64-bit value. *)
399 and code_int64_of_rawint cg pos debug spre signed a cont =
400 if int32_ok spre then
401 (* A 32-bit value must be coerced to 64-bits. *)
402 code_atom_int32 cg pos debug a (fun op ->
403 let insts, vhi, vlo =
407 comm_string "Rawint signed coercion to int64 (sign-extend)";
415 comm_string "Rawint unsigned coercion to int64 (zero-extend)";
420 let blocks, label = cont vhi vlo in
421 let block, label = code_build_dst_block debug "coerce_int64_of_int32" insts label in
422 block :: blocks, label)
424 (* No change in internal representation; ignore *)
425 code_atom_int64 cg pos debug a cont
428 (*** Relative Operations ***)
432 See below; this is a more generic form that allows you to
433 specify arbitrary operands for the TRUE and FALSE values. *)
434 and code_cond_int_op debug op cont v op1 op2 tval fval =
435 (* Construct success and failure blocks *)
436 let blocks, label = cont v in
437 let isucc = Listbuf.of_elt (MOV (IL, v, tval)) in
438 let ifail = Listbuf.of_elt (MOV (IL, v, fval)) in
439 let bsucc, lsucc = code_build_dst_block debug "relop_succ" isucc label in
440 let bfail, lfail = code_build_dst_block debug "relop_fail" ifail label in
442 (* Construct the comparison operation itself *)
443 let build_cmp op1 op2 = CMP (IL, op1, op2) in
444 let insts = build_relop_int32 build_cmp Listbuf.empty op op1 op2 lsucc in
446 (* Assemble all the blocks together *)
447 let block, label = code_build_dst_block debug "relop" insts lfail in
448 block :: bfail :: bsucc :: blocks, label
452 See code_relop_int32; this auxiliary function handles the
453 actual conditional code for comparison, but does not do the
454 coercions that the higher-level functions require. *)
455 and code_relop_int_op debug op cont v op1 op2 =
456 let one = ImmediateNumber (OffNumber Int32.one) in
457 let zero = ImmediateNumber (OffNumber Int32.zero) in
458 code_cond_int_op debug op cont v op1 op2 one zero
462 Relations work transparently on ML ints, however we should use
463 the special encoder for ML ints to code the atoms themselves. *)
464 and code_relop_int cg pos debug op a1 a2 cont =
465 let pos = string_pos "code_relop_int" pos in
466 code_basic_binop_int cg pos debug a1 a2 (code_relop_int_op debug op cont)
470 Relations work transparently on poly values, however we should use
471 the special encoder for poly values to code the atoms themselves. *)
472 and code_relop_poly cg pos debug op a1 a2 cont =
473 let pos = string_pos "code_relop_poly" pos in
474 code_basic_binop_poly cg pos debug a1 a2 (code_relop_int_op debug op cont)
478 Wrapper for the various integer relative operations that you can use. *)
479 and code_relop_int32 cg pos debug pre signed op a1 a2 cont =
480 let pos = string_pos "code_relop_int32" pos in
481 code_basic_binop_int32 cg pos debug a1 a2 (fun v op1 op2 ->
482 code_int32_of_rawint_op pos debug pre signed op1 (fun op1 ->
483 code_int32_of_rawint_op pos debug pre signed op2 (fun op2 ->
484 code_relop_int_op debug op cont v op1 op2)))
488 Wrapper for operations that compare pointers... *)
489 and code_relop_ptr cg pos debug pre signed op a1 a2 cont =
490 let pos = string_pos "code_relop_ptr" pos in
491 code_atom_ptr_off cg pos debug a1 (fun op1 ->
492 code_atom_ptr_off cg pos debug a2 (fun op2 ->
493 let v = Register (new_symbol_string "relop_res") in
494 code_relop_int_op debug op cont v op1 op2))
498 See code_relop_int32; this does pretty much the same damn thing
499 except for 64-bit integers. A distinguishing feature here is
500 the need for a slightly different function structure due to the
501 way 64-bit ints are handled. *)
502 and code_relop_int64 cg pos debug op a1 a2 cont =
503 let pos = string_pos "code_relop_int64" pos in
504 code_atom_int64 cg pos debug a1 (fun ohi1 olo1 ->
505 code_atom_int64 cg pos debug a2 (fun ohi2 olo2 ->
506 (* Construct success and failure blocks *)
507 let v = Register (new_symbol_string "relop_res") in
508 let blocks, label = cont v in
509 let isucc = Listbuf.of_elt (MOV (IL, v, ImmediateNumber (OffNumber Int32.one))) in
510 let ifail = Listbuf.of_elt (MOV (IL, v, ImmediateNumber (OffNumber Int32.zero))) in
511 let bsucc, lsucc = code_build_dst_block debug "relop_succ" isucc label in
512 let bfail, lfail = code_build_dst_block debug "relop_fail" ifail label in
514 (* Construct the comparison operation itself *)
515 let build_cmp op1 op2 = CMP (IL, op1, op2) in
516 let insts = build_relop_int64 build_cmp Listbuf.empty op ohi1 olo1 ohi2 olo2 lsucc lfail in
518 (* Assemble all the blocks together *)
519 let block, label = code_build_dst_block debug "relop" insts lfail in
520 block :: bfail :: bsucc :: blocks, label))
524 Handles any type of rawint expression. *)
525 and code_relop_rawint cg pos debug pre signed op a1 a2 cont =
527 code_relop_int32 cg pos debug pre signed op a1 a2 cont
529 code_relop_int64 cg pos debug op a1 a2 cont
532 (* code_cond_float_op
533 See below; this is a more generic form that allows you to
534 specify arbitrary operands for the TRUE and FALSE values. *)
535 and code_cond_float_op debug op cont v op1 op2 tval fval =
536 (* Construct success and failure blocks *)
537 let blocks, label = cont v in
538 let isucc = Listbuf.of_elt (MOV (IL, v, tval)) in
539 let ifail = Listbuf.of_elt (MOV (IL, v, fval)) in
540 let bsucc, lsucc = code_build_dst_block debug "relop_float_succ" isucc label in
541 let bfail, lfail = code_build_dst_block debug "relop_float_fail" ifail label in
543 (* Construct the comparison code *)
544 let insts = build_relop_float Listbuf.empty op op1 op2 lsucc in
545 let block, label = code_build_dst_block debug "relop_float" insts lfail in
546 block :: bfail :: bsucc :: blocks, label
549 (* code_relop_float_op
550 Similar to above, but provides default values for T and F. *)
551 and code_relop_float_op debug op cont v op1 op2 =
552 code_cond_float_op debug op cont v op1 op2 (ImmediateNumber (OffNumber Int32.one)) (ImmediateNumber (OffNumber Int32.zero))
556 Similar to the above relops, but this one works for floats. We cannot
557 directly use JCC on floating-point comparisons because they set flags
558 in the FP status word, not the main flags. Furthermore, we're forced
559 to load the status word into AX (it's either that or memory) to check
560 the flags. This sucks. *)
561 and code_relop_float cg pos debug op a1 a2 cont =
562 let pos = string_pos "code_relop_float" pos in
563 code_basic_binop_float cg pos debug a1 a2 (fun _ op1 op2 ->
564 (* The variable generated is a float var; we need an int *)
565 let v = Register (new_symbol_string "float_relop_res") in
566 code_relop_float_op debug op cont v op1 op2)
569 (*** Int/Int32 Operations ***)
573 Writes a general-purpose unary operation for 32-bit values.
574 cons contains code to build a list of instructions which are
575 added to the inst buffer given to it. Note that cont is
576 expected to convert the result into int31 representation! *)
577 and code_unop_int cg pos debug a cont cons =
578 let pos = string_pos "code_unop_int" pos in
579 code_atom_int cg pos debug a (fun op ->
584 modify_listbuf `{ cons insts (Register r) `};
587 build_atom_block debug "unop" insts v cont)
591 Writes a general-purpose unary operation for 32-bit values.
592 cons contains code to build the actual inst (single-form). *)
593 and code_unop_int32 cg pos debug a cont cons =
594 let pos = string_pos "code_unop_int32" pos in
595 code_atom_int32 cg pos debug a (fun op ->
600 add_inst `{ cons (Register r) `};
603 build_atom_block debug "unop" insts v cont)
607 Writes code to access a dword in a header (the
608 word that contains the index and the tag). cons contains
609 code to build an inst that will return either the index or
610 the tag (depending on which you want), it takes the value
611 of that header dword as an input. *)
612 and code_mem_header_int word cg pos debug a cont cons =
613 let pos = string_pos "code_mem_header1" pos in
614 code_atom_ptr_base cg pos debug a (fun op ->
620 movl r2, *(r1, word);
621 modify_listbuf `{ cons insts (Register r2) `};
624 build_atom_block debug "mem_header1" insts v cont)
628 Writes code to access the closure index of a function pointed
629 to by the given atom. The atom MUST point to the beginning of
630 an escape version of a function in the program; otherwise, well
631 you'll get interesting results for sure. The index will be
632 packaged up into the operand passed to cont. *)
633 and code_mem_funindex_int cg pos debug a cont cons =
634 let pos = string_pos "code_mem_funindex" pos in
635 code_mem_header_int index_word32 cg pos debug a cont cons
637 and code_mem_funindex_int32 cg pos debug a cont =
638 code_mem_funindex_int cg pos debug a cont (fun insts _ -> insts)
642 Writes code to load the address of the _escape_ version
643 of the function indicated by the label v. An operand to
644 the resulting pointer will be passed to cont. *)
645 and code_fun_pointer_int32 cg pos debug v cont =
646 let pos = string_pos "code_fun_pointer_int32" pos in
647 let { cg_esc_funs = esc_funs } = cg in
648 let v', _, _ = try SymbolTable.find esc_funs v with
649 Not_found -> raise (MirException (pos, UnboundVar v))
656 comm_string `{ Printf.sprintf "Function %s escapes to %s" (string_of_symbol v) (string_of_symbol v') `};
660 build_atom_block debug "fun_pointer" insts v'' cont
663 (* code_basic_binop_int32
664 Writes the infrastructure used by most binary operations. *)
665 and code_basic_binop_int32 cg pos debug a1 a2 cont =
666 let pos = string_pos "code_basic_binop_int32" pos in
667 let v = Register (new_symbol_string "binop_res") in
668 code_atom_int32 cg pos debug a1 (fun op1 ->
669 code_atom_int32 cg pos debug a2 (fun op2 ->
673 (* code_basic_binop_int
674 Writes the infrastructure used by most binary operations. *)
675 and code_basic_binop_int cg pos debug a1 a2 cont =
676 let pos = string_pos "code_basic_binop_int" pos in
677 let v = Register (new_symbol_string "binop_res") in
678 code_atom_int cg pos debug a1 (fun op1 ->
679 code_atom_int cg pos debug a2 (fun op2 ->
683 (* code_basic_binop_poly
684 Writes the infrastructure used by most binary operations. *)
685 and code_basic_binop_poly cg pos debug a1 a2 cont =
686 let pos = string_pos "code_basic_binop_poly" pos in
687 let v = Register (new_symbol_string "binop_res") in
688 code_atom_poly cg pos debug a1 (fun op1 ->
689 code_atom_poly cg pos debug a2 (fun op2 ->
694 Writes a general-purpose binary operation for 32-bit values.
695 cons contains code to build the actual inst, it takes two
696 arguments which will be operands. Note: the first form is
697 some common code which we'll see in a lot of binops, might
698 as well list it here. *)
699 and code_binop_int_aux cg pos debug a1 a2 cont basic cons =
700 let pos = string_pos "code_binop_int_aux" pos in
701 basic cg pos debug a1 a2 (fun v op1 op2 ->
707 modify_listbuf `{ cons insts (Register r) op2 `};
710 build_atom_block debug "binop" insts v cont)
712 and code_binop_int32 cg pos debug a1 a2 cont cons =
713 code_binop_int_aux cg pos debug a1 a2 cont code_basic_binop_int32 (add_binop_inst cons)
715 and code_binop_int_nowrap cg pos debug a1 a2 cont cons =
716 code_binop_int_aux cg pos debug a1 a2 cont code_basic_binop_int (add_binop_inst cons)
719 (* code_binop_wrap_int
720 Convert the int31 to int32, perform the op, then convert back. *)
721 and code_binop_int_wrap cg pos debug a1 a2 cont cons =
722 code_binop_int_aux cg pos debug a1 a2 cont code_basic_binop_int (fun insts op1 op2 ->
729 add_inst `{ cons (Register v1) (Register v2) `};
735 (* code_binop_int32_cl
736 This is a special form of the above usually used for shl,
737 shr instructions. It indicates that one of the arguments
738 must either be ecx (which is the case for shifting), or an
740 and code_binop_int_cl_aux cg pos debug a1 a2 cont shift cons =
741 let pos = string_pos "code_binop_int32_cl" pos in
746 code_basic_binop_int32
748 basic cg pos debug a1 a2 (fun v op1 op2 ->
749 let r = new_symbol_string "binop_tmp" in
750 let insts = Listbuf.of_elt (code_load_int32 r op1) in
753 ImmediateNumber (OffNumber i) ->
755 cons insts (Register r) (ImmediateNumber (OffNumber (Int32.shift_right i 1)))
757 cons insts (Register r) op2
759 let insts = Listbuf.add insts (code_load_int32 ecx op2) in
762 Listbuf.add insts (SAR (IL, Register ecx, ImmediateNumber (OffNumber Int32.one)))
766 cons insts (Register r) (Register ecx)
768 let insts = Listbuf.add insts (code_store_int32 v r) in
769 build_atom_block debug "binop" insts v cont)
771 and code_binop_int32_cl cg pos debug a1 a2 cont cons =
772 code_binop_int_cl_aux cg pos debug a1 a2 cont false (fun insts op1 op2 ->
774 add_inst `{ cons op1 op2 `};`)
776 and code_binop_int_cl cg pos debug a1 a2 cont cons =
777 code_binop_int_cl_aux cg pos debug a1 a2 cont true (fun insts op1 op2 ->
779 (* op2 has already been shifted appropriately here *)
781 add_inst `{ cons op1 op2 `};
787 MUL has the same funny semantics as the div instructions have.
788 This operation only applies to unsigned MUL; signed multiplication
789 uses IMUL which accepts two operands (for no apparent reason). *)
790 and code_mulop_int32 cg pos debug a1 a2 cont =
791 let pos = string_pos "code_mulop_int32" pos in
792 code_basic_binop_int32 cg pos debug a1 a2 (fun v op1 op2 ->
793 (* MUL cannot have an immediate arg *)
803 build_atom_block debug "mulop" insts v cont)
807 Just like code_mulop_int32, except this form handles both signed
808 and unsigned division (based on the inst the cons function builds),
809 and it also handles remainders (pass result == eax for division,
810 or result == edx for remainder). I hate the funky div semantics --justins *)
811 and code_divop_int_aux cg pos debug a1 a2 cont result clop basic cons =
812 (* TEMP: The DIVOP code could be seriously improved with Kupo now
813 The current structure of the code is very messy though... *)
814 let pos = string_pos "code_divop_int_aux" pos in
815 basic cg pos debug a1 a2 (fun v op1 op2 ->
821 (* DIV, IDIV cannot have immediate args *)
825 (* We have to clear the high-order bits of the numerator *)
827 modify_listbuf `{ cons insts (Register eax) (Register r) `};
830 build_atom_block debug "divop" insts v cont)
832 and code_divop_int32 cg pos debug pre signed a1 a2 cont result =
835 CLTD, (fun op -> IDIV (IL, op))
837 MOV (IL, Register edx, ImmediateNumber (OffNumber Int32.zero)), (fun op -> DIV (IL, op))
839 let code_basic_binop_int32 cg pos debug a1 a2 cont =
840 code_basic_binop_int32 cg pos debug a1 a2 (fun v op1 op2 ->
841 code_int32_of_rawint_op pos debug pre signed op1 (fun op1 ->
842 code_int32_of_rawint_op pos debug pre signed op2 (fun op2 ->
845 code_divop_int_aux cg pos debug a1 a2 cont result clop code_basic_binop_int32 (fun insts _ op ->
846 Listbuf.add insts (cons op))
848 and code_divop_int cg pos debug a1 a2 cont result clop cons =
849 code_divop_int_aux cg pos debug a1 a2 cont result clop code_basic_binop_int (fun insts op1 op2 ->
857 add_inst `{ cons (Register v2) `};
863 References some random garbage in memory. We need to know the
864 exact precision here, so we know how many bytes we are reading
865 out of memory. Note: the first function given is an internal
866 form which may be of use to other atom classes as well. *)
867 and code_let_mem_aux cg pos debug a1 a2 cons =
868 let pos = string_pos "code_let_mem_aux" pos in
869 let insts = Listbuf.empty in
870 code_atom_ptr_off cg pos debug a1 (fun opptr ->
871 let rptr = new_symbol_string "let_mem_aux" in
872 let load_insts insts operand =
873 let insts = Listbuf.add insts (code_load_int32 rptr opptr) in
878 (* Offset is constant *)
879 let operand = MemRegOff(rptr, OffNumber (Rawint.to_int32 i)) in
880 load_insts insts operand
882 (* Offset in a register; it must be a byte-offset *)
883 let rofs = new_symbol_string "let_mem_off" in
884 code_atom_int32 cg pos debug a2 (fun oofs ->
885 let insts = Listbuf.add insts (code_load_int32 rofs oofs) in
886 let operand = MemRegRegOffMul (rptr, rofs, OffNumber Int32.zero, Int32.one) in
887 load_insts insts operand))
889 (* JDS: Killed JYH's revert, let's try this again.
890 JDS: This code can be removed once the next function down is verified. -2002.08.17
892 and code_let_mem_int cg pos debug a1 a2 cont =
893 let pos = string_pos "code_let_mem_int" pos in
894 let v = Register (new_symbol_string "let_mem") in
895 let load_insts_int operand insts =
896 let rval = new_symbol_string "let_mem_tmp" in
897 let insts = Listbuf.add_list insts
898 [CommentString "Loading an int from memory";
899 code_load_int32 rval operand;
900 code_store_int32 v rval]
902 let blocks, label = cont v in
903 let block, label = code_build_dst_block debug "code_let_mem_int" insts label in
904 block :: blocks, label
906 code_let_mem_aux cg pos debug a1 a2 load_insts_int
909 and code_let_mem_int cg pos debug a1 a2 cont =
910 let pos = string_pos "code_let_mem_int" pos in
911 let v = Register (new_symbol_string "let_mem") in
912 let load_insts_int op insts =
916 comm_string "Loading an int from memory";
920 let blocks, label = cont v in
921 let block, label = code_build_dst_block debug "code_let_mem_int" insts label in
922 block :: blocks, label
924 code_let_mem_aux cg pos debug a1 a2 load_insts_int
926 and code_let_mem_int32 cg pos debug int_class a1 a2 cont =
927 let pos = string_pos "code_let_mem_int32" pos in
928 let load_insts_int32 operand insts =
929 let v = Register (new_symbol_string "let_mem") in
930 let rval = new_symbol_string "let_mem_tmp" in
931 let name, code_load_mem =
933 Rawint.Int8, false -> "uint8", code_load_uint8
934 | Rawint.Int8, true -> "int8", code_load_int8
935 | Rawint.Int16, false -> "uint16", code_load_uint16
936 | Rawint.Int16, true -> "int16", code_load_int16
937 | Rawint.Int32, false -> "uint32", code_load_uint32
938 | Rawint.Int32, true -> "int32", code_load_int32
939 | _ -> raise (MirException (pos, InternalError "code_let_mem_int32"))
941 let insts = Listbuf.add_list insts
942 [CommentString ("Loading a " ^ name ^ " from memory");
943 code_load_mem rval operand;
944 code_store_int32 v rval]
946 let blocks, label = cont v in
947 let block, label = code_build_dst_block debug "code_let_mem_int32" insts label in
948 block :: blocks, label
950 code_let_mem_aux cg pos debug a1 a2 load_insts_int32
954 When a polymorphic value is loaded, we don't know if
955 it is an int or a pointer. check the LSB to test whether it
957 and code_let_mem_poly cg pos debug a1 a2 cont =
958 let pos = string_pos "code_let_mem_poly" pos in
959 let load_insts_poly operand insts =
960 let v = Register (new_symbol_string "let_mem_poly") in
961 let rval = new_symbol_string "let_mem_poly_tmp" in
963 (* Construct the continuation *)
964 let blocks, label1 = cont v in
966 (* What we do just before the continuation *)
967 let insts2 = Listbuf.of_elt (code_store_int32 v rval) in
968 let block2, label2 = code_build_dst_block debug "code_let_mem_poly" insts2 label1 in
970 (* IF LSB is zero, lookup from the pointer table *)
971 let insts3 = Listbuf.of_elt (MOV (IL, Register rval, MemRegRegOffMul (pointer_base, rval, OffNumber Int32.zero, Int32.one))) in
972 let block3, label3 = code_build_dst_block debug "code_let_mem_poly" insts3 label2 in
974 (* Preprocessing: check the LSB *)
975 let insts = Listbuf.add_list insts
976 [CommentString "Loading a <poly> from memory";
977 code_load_uint32 rval operand;
978 TEST (IL, Register rval, ImmediateNumber (OffNumber Int32.one));
979 JCC (NEQ, ImmediateLabel label2)]
981 let block4, label4 = code_build_dst_block debug "code_let_mem_poly" insts label3 in
982 block4 :: block3 :: block2 :: blocks, label4
984 code_let_mem_aux cg pos debug a1 a2 load_insts_poly
987 (* code_binop_int_max
991 Computes max- and min-code for integer values. This is more
992 optimized than doing the computation in FIR, since we can do
993 the branch optimization here. *)
994 and code_binop_int_max cg pos debug a1 a2 cont =
995 let pos = string_pos "code_binop_int_max" pos in
996 code_basic_binop_int cg pos debug a1 a2 (fun v op1 op2 ->
997 code_cond_int_op debug GT cont v op1 op2 op1 op2)
999 and code_binop_int_min cg pos debug a1 a2 cont =
1000 let pos = string_pos "code_binop_int_min" pos in
1001 code_basic_binop_int cg pos debug a1 a2 (fun v op1 op2 ->
1002 code_cond_int_op debug LT cont v op1 op2 op1 op2)
1004 and code_binop_int32_max cg pos debug a1 a2 cont =
1005 let pos = string_pos "code_binop_int32_max" pos in
1006 code_basic_binop_int32 cg pos debug a1 a2 (fun v op1 op2 ->
1007 code_cond_int_op debug GT cont v op1 op2 op1 op2)
1009 and code_binop_int32_min cg pos debug a1 a2 cont =
1010 let pos = string_pos "code_binop_int32_min" pos in
1011 code_basic_binop_int32 cg pos debug a1 a2 (fun v op1 op2 ->
1012 code_cond_int_op debug LT cont v op1 op2 op1 op2)
1016 Builds blocks to compute the atom expression given. *)
1017 and code_atom_int cg pos debug a cont =
1018 let pos = string_pos "code_atom_int" pos in
1020 (* Constants and variables *)
1022 cont (code_operand_of_int i)
1023 | AtomVar (ACInt, v) ->
1026 (* Illegal operands *)
1030 raise (MirException (pos, ImplicitCoercion a))
1032 (* Escaping functions *)
1033 | AtomFunVar (ac, _) ->
1034 raise (MirException (pos, ImplicitCoercion2 (ACInt, ac)))
1036 (* Unary arithmetic & bitwise operations *)
1037 | AtomUnop (IntOfRawIntOp (pre, _), a) when int32_ok pre ->
1038 code_int_of_int32 cg pos debug a cont
1039 | AtomUnop (IntOfFloatOp _, a) ->
1040 code_int_of_float cg pos debug a cont
1041 | AtomUnop (IntOfPolyOp, a) ->
1042 (* Poly values are currently transformed directly to int *)
1043 (* TEMP: should probably set LSB explicitly here, or have
1044 SOME sort of safety check?? *)
1045 code_atom_poly cg pos debug a cont
1046 | AtomUnop (UMinusOp ACInt, a) ->
1047 code_unop_int cg pos debug a cont (fun insts op ->
1051 | AtomUnop (NotOp ACInt, a) ->
1052 code_unop_int cg pos debug a cont (fun insts op ->
1056 | AtomUnop (AbsOp ACInt, a) ->
1057 (* BUG: this, of course, is wrong, but I don't know how to do a conditional here --jyh *)
1058 code_unop_int cg pos debug a cont (fun insts op ->
1063 (* Unary memory operations *)
1064 | AtomUnop (MemIndexOp (_, ACInt), a)
1065 | AtomUnop (MemFunIndexOp (_, ACInt), a) ->
1066 code_mem_header_int index_word32 cg pos debug a cont (fun insts op ->
1068 add_inst `{ build_shrop_int op (pred index_shift) `};
1069 andl op, index_pred_mask32;
1071 | AtomUnop (MemFunArityTagOp (_, ACInt), a) ->
1072 code_mem_header_int arity_tag_word32 cg pos debug a cont (fun insts op ->
1074 add_inst `{ build_shrop_int op (pred arity_tag_shift) `};
1075 andl op, arity_tag_pred_mask32;
1077 | AtomUnop (MemTagOp (PtrBlock, ACInt), a) ->
1078 code_mem_header_int tag_word32 cg pos debug a cont (fun insts op ->
1080 add_inst `{ build_shrop_int op (pred tag_shift) `};
1081 andl op, tag_pred_mask32;
1083 | AtomUnop (MemSizeOp (PtrAggr, ACInt), a) ->
1084 code_mem_header_int size_word32 cg pos debug a cont (fun insts op ->
1086 add_inst `{ build_shrop_int op (pred size_shift) `};
1087 andl op, size_pred_aggr_mask32;
1089 | AtomUnop (MemSizeOp (PtrBlock, ACInt), a) ->
1090 code_mem_header_int size_word32 cg pos debug a cont (fun insts op ->
1092 add_inst `{ build_shrop_int op (pred size_shift) `};
1093 andl op, size_pred_block_mask32;
1097 | AtomUnop (_, _) ->
1098 raise (MirException (pos, NotImplemented "code_atom_int: AtomUnop"))
1100 (* Binary arithmetic operations *)
1101 | AtomBinop (PlusOp ACInt, a1, a2) ->
1102 let a1, a2 = reorder_atoms a1 a2 in
1103 code_binop_int_aux cg pos debug a1 a2 cont code_basic_binop_int (fun insts op1 op2 ->
1107 | AtomBinop (MinusOp ACInt, a1, a2) ->
1108 code_binop_int_aux cg pos debug a1 a2 cont code_basic_binop_int (fun insts op1 op2 ->
1113 (* Multiply and divide *)
1114 | AtomBinop (MulOp ACInt, a1, a2) ->
1116 let a1, a2 = reorder_atoms a1 a2 in
1117 code_binop_int_wrap cg pos debug a1 a2 cont (fun op1 op2 -> IMUL (IL, op1, op2))
1119 | AtomBinop (DivOp ACInt, a1, a2) ->
1121 code_divop_int cg pos debug a1 a2 cont eax CLTD (fun op -> IDIV (IL, op))
1122 | AtomBinop (RemOp ACInt, a1, a2) ->
1124 code_divop_int cg pos debug a1 a2 cont edx CLTD (fun op -> IDIV (IL, op))
1126 (* Binary bitwise operations *)
1127 | AtomBinop (SlOp ACInt, a1, a2) ->
1129 code_binop_int_cl cg pos debug a1 a2 cont (fun op1 op2 -> SAL (IL, op1, op2))
1130 | AtomBinop (ASrOp ACInt, a1, a2) ->
1132 code_binop_int_cl cg pos debug a1 a2 cont (fun op1 op2 -> SAR (IL, op1, op2))
1133 | AtomBinop (LSrOp ACInt, a1, a2) ->
1135 code_binop_int_cl cg pos debug a1 a2 cont (fun op1 op2 -> SHR (IL, op1, op2))
1136 | AtomBinop (AndOp ACInt, a1, a2) ->
1137 let a1, a2 = reorder_atoms a1 a2 in
1138 code_binop_int_nowrap cg pos debug a1 a2 cont (fun op1 op2 -> AND (IL, op1, op2))
1139 | AtomBinop (OrOp ACInt, a1, a2) ->
1140 let a1, a2 = reorder_atoms a1 a2 in
1141 code_binop_int_nowrap cg pos debug a1 a2 cont (fun op1 op2 -> OR (IL, op1, op2))
1142 | AtomBinop (XorOp ACInt, a1, a2) ->
1143 let a1, a2 = reorder_atoms a1 a2 in
1144 code_binop_int_aux cg pos debug a1 a2 cont code_basic_binop_int (fun insts op1 op2 ->
1150 | AtomBinop (MaxOp ACInt, a1, a2) ->
1151 let a1, a2 = reorder_atoms a1 a2 in
1152 code_binop_int_max cg pos debug a1 a2 cont
1153 | AtomBinop (MinOp ACInt, a1, a2) ->
1154 let a1, a2 = reorder_atoms a1 a2 in
1155 code_binop_int_min cg pos debug a1 a2 cont
1157 (* Binary memory operations *)
1158 | AtomBinop (MemOp (ACInt, _), a1, a2) ->
1159 code_let_mem_int cg pos debug a1 a2 cont
1161 (* Comparative operators *)
1162 | AtomBinop (CmpOp ACInt, a1, a2) ->
1163 let gt = AtomBinop (GtOp ACInt, a1, a2) in
1164 let lt = AtomBinop (LtOp ACInt, a1, a2) in
1165 let a = AtomBinop (MinusOp (ACRawInt (Rawint.Int32, true)), gt, lt) in
1166 let a = AtomUnop (IntOfRawIntOp (Rawint.Int32, true), a) in
1167 let pos = string_pos "code_atom_int_CmpOp" pos in
1168 code_atom_int cg pos debug a cont
1170 (* Unknown binary *)
1171 | AtomBinop (_, _, _) ->
1172 raise (MirException (pos, NotImplemented "code_atom_int: AtomBinop"))
1176 Builds blocks to compute the atom expression given. *)
1177 and code_atom_int8 cg pos debug signed a cont =
1178 let pos = string_pos "code_atom_int8" pos in
1179 code_atom_int32 cg pos debug a (fun op ->
1180 code_int32_of_rawint_op pos debug Rawint.Int8 signed op cont)
1184 Builds blocks to compute the atom expression given. *)
1185 and code_atom_int16 cg pos debug signed a cont =
1186 let pos = string_pos "code_atom_int8" pos in
1187 code_atom_int32 cg pos debug a (fun op ->
1188 code_int32_of_rawint_op pos debug Rawint.Int16 signed op cont)
1192 Builds blocks to compute the atom expression given. *)
1193 and code_atom_int32 cg pos debug a cont =
1194 let pos = string_pos "code_atom_int32" pos in
1196 (* Constants and variables *)
1197 AtomRawInt i when int32_ok (Rawint.precision i) ->
1198 cont (ImmediateNumber (OffNumber (Rawint.to_int32 i)))
1199 | AtomVar (ACRawInt (pre, _), v) when int32_ok pre ->
1202 (* Illegal operands *)
1208 raise (MirException (pos, ImplicitCoercion a))
1210 (* Unary coercion operators *)
1211 | AtomUnop (RawIntOfIntOp (pre, _), a) when int32_ok pre ->
1212 code_int32_of_int cg pos debug a cont
1213 | AtomUnop (RawIntOfFloatOp (pre, true, _), a) when int32_ok pre ->
1214 code_int32_of_float cg pos debug a cont
1215 | AtomUnop (RawIntOfFloatOp (pre, false, _), a) when int32_ok pre ->
1216 atom_warning "coercion from float to unsigned will be treated as coercion from float to signed, expect range errors";
1217 code_int32_of_float cg pos debug a cont
1218 | AtomUnop (RawIntOfRawIntOp (dpre, dsigned, spre, ssigned), a) when int32_ok dpre && dsigned = ssigned ->
1219 code_int32_of_rawint cg pos debug spre ssigned a cont
1220 | AtomUnop (RawIntOfRawIntOp (dpre, dsigned, spre, ssigned), a) when int32_ok dpre && dpre = spre ->
1221 (* sign change with same precision *)
1222 code_int32_of_rawint cg pos debug spre ssigned a cont
1223 | AtomUnop (RawIntOfRawIntOp (dpre, dsigned, spre, ssigned), a) when int32_ok dpre && dsigned <> ssigned ->
1224 atom_warning "in coercions that change signedness, source sign wins in any bit extensions";
1225 code_int32_of_rawint cg pos debug spre ssigned a cont
1226 | AtomUnop (Int32OfPointerOp _, a) ->
1227 (* Reading the raw numerical value of a pointer; this is identity *)
1228 code_atom_ptr_off cg pos debug a cont
1230 (* Unary arithmetic & bitwise operations *)
1231 | AtomUnop (UMinusOp (ACRawInt (pre, _)), a) when int32_ok pre ->
1232 code_unop_int32 cg pos debug a cont (fun op -> NEG (IL, op))
1233 | AtomUnop (NotOp (ACRawInt (pre, _)), a) when int32_ok pre ->
1234 code_unop_int32 cg pos debug a cont (fun op -> NOT (IL, op))
1236 (* Read bitfields *)
1237 | AtomUnop (BitFieldOp (pre, true, ofs, len), a) when int32_ok pre ->
1238 code_atom_int32 cg pos debug a (fun op ->
1245 sall r, $32 - (ofs + len);
1249 build_atom_block debug "bitfield" insts v cont)
1250 | AtomUnop (BitFieldOp (pre, false, ofs, len), a) when int32_ok pre ->
1251 code_atom_int32 cg pos debug a (fun op ->
1259 andl r, $(pow2 len) - 1;
1262 build_atom_block debug "bitfield" insts v cont)
1264 (* Unary memory operations *)
1265 | AtomUnop (MemIndexOp (_, ACRawInt (pre, _)), a)
1266 | AtomUnop (MemFunIndexOp (_, ACRawInt (pre, _)), a)
1267 when int32_ok pre ->
1268 code_mem_header_int index_word32 cg pos debug a cont (fun insts op ->
1270 shrl op, $index_shift32;
1271 andl op, $index_mask32;`)
1272 | AtomUnop (MemFunArityTagOp (_, ACRawInt (pre, _)), a)
1273 when int32_ok pre ->
1274 code_mem_header_int arity_tag_word32 cg pos debug a cont (fun insts op ->
1276 shrl op, $arity_tag_shift32;
1277 andl op, $arity_tag_mask32;`)
1278 | AtomUnop (MemTagOp (PtrBlock, ACRawInt (pre, _)), a)
1279 when int32_ok pre ->
1280 code_mem_header_int tag_word32 cg pos debug a cont (fun insts op ->
1282 shrl op, $tag_shift32;
1283 andl op, $tag_mask32;`)
1284 | AtomUnop (MemSizeOp (PtrAggr, ACRawInt (pre, _)), a)
1285 when int32_ok pre ->
1286 code_mem_header_int size_word32 cg pos debug a cont (fun insts op ->
1288 shrl op, $size_shift32;
1289 andl op, $size_aggr_mask32;`)
1290 | AtomUnop (MemSizeOp (PtrBlock, ACRawInt (pre, _)), a)
1291 when int32_ok pre ->
1292 code_mem_header_int size_word32 cg pos debug a cont (fun insts op ->
1294 shrl op, $size_shift32;
1295 andl op, $size_block_mask32;`)
1297 (* Unary operations on infix pointers *)
1298 | AtomUnop (OffsetOfInfixPointerOp _, a) ->
1299 code_atom_ptr_infix cg pos debug a (fun base offset ->
1308 build_atom_block debug "base" insts v cont)
1312 raise (MirException (pos, NotImplemented "code_atom_int32: AtomUnop"))
1314 (* Binary arithmetic operations *)
1315 | AtomBinop (PlusOp (ACRawInt (pre, _)), a1, a2) when int32_ok pre ->
1316 let a1, a2 = reorder_atoms a1 a2 in
1317 code_binop_int32 cg pos debug a1 a2 cont (fun op1 op2 -> ADD (IL, op1, op2))
1318 | AtomBinop (MinusOp (ACRawInt (pre, _)), a1, a2) when int32_ok pre ->
1319 code_binop_int32 cg pos debug a1 a2 cont (fun op1 op2 -> SUB (IL, op1, op2))
1321 (* Multiply and divide *)
1322 | AtomBinop (MulOp (ACRawInt (pre, true)), a1, a2) when int32_ok pre ->
1324 let a1, a2 = reorder_atoms a1 a2 in
1325 code_binop_int32 cg pos debug a1 a2 cont (fun op1 op2 -> IMUL (IL, op1, op2))
1326 | AtomBinop (MulOp (ACRawInt (pre, false)), a1, a2) when int32_ok pre ->
1328 let a1, a2 = reorder_atoms a1 a2 in
1329 code_mulop_int32 cg pos debug a1 a2 cont
1330 | AtomBinop (DivOp (ACRawInt (pre, signed)), a1, a2) when int32_ok pre ->
1331 code_divop_int32 cg pos debug pre signed a1 a2 cont eax
1332 | AtomBinop (RemOp (ACRawInt (pre, signed)), a1, a2) when int32_ok pre ->
1333 code_divop_int32 cg pos debug pre signed a1 a2 cont edx
1335 (* Binary bitwise operations *)
1336 | AtomBinop (SlOp (ACRawInt (pre, true)), a1, a2) when int32_ok pre ->
1338 code_binop_int32_cl cg pos debug a1 a2 cont (fun op1 op2 -> SAL (IL, op1, op2))
1339 | AtomBinop (SlOp (ACRawInt (pre, false)), a1, a2) when int32_ok pre ->
1341 code_binop_int32_cl cg pos debug a1 a2 cont (fun op1 op2 -> SHL (IL, op1, op2))
1342 | AtomBinop (ASrOp (ACRawInt (pre, _)), a1, a2) when int32_ok pre ->
1344 code_binop_int32_cl cg pos debug a1 a2 cont (fun op1 op2 -> SAR (IL, op1, op2))
1345 | AtomBinop (LSrOp (ACRawInt (pre, _)), a1, a2) when int32_ok pre ->
1347 code_binop_int32_cl cg pos debug a1 a2 cont (fun op1 op2 -> SHR (IL, op1, op2))
1348 | AtomBinop (AndOp (ACRawInt (pre, _)), a1, a2) when int32_ok pre ->
1349 let a1, a2 = reorder_atoms a1 a2 in
1350 code_binop_int32 cg pos debug a1 a2 cont (fun op1 op2 -> AND (IL, op1, op2))
1351 | AtomBinop (OrOp (ACRawInt (pre, _)), a1, a2) when int32_ok pre ->
1352 let a1, a2 = reorder_atoms a1 a2 in
1353 code_binop_int32 cg pos debug a1 a2 cont (fun op1 op2 -> OR (IL, op1, op2))
1354 | AtomBinop (XorOp (ACRawInt (pre, _)), a1, a2) when int32_ok pre ->
1355 let a1, a2 = reorder_atoms a1 a2 in
1356 code_binop_int32 cg pos debug a1 a2 cont (fun op1 op2 -> XOR (IL, op1, op2))
1359 | AtomBinop (MaxOp (ACRawInt (pre, _)), a1, a2) when int32_ok pre ->
1360 let a1, a2 = reorder_atoms a1 a2 in
1361 code_binop_int32_max cg pos debug a1 a2 cont
1362 | AtomBinop (MinOp (ACRawInt (pre, _)), a1, a2) when int32_ok pre ->
1363 let a1, a2 = reorder_atoms a1 a2 in
1364 code_binop_int32_min cg pos debug a1 a2 cont
1367 | AtomBinop (SetBitFieldOp (pre, _, ofs, len), a1, a2) when int32_ok pre ->
1368 code_basic_binop_int32 cg pos debug a1 a2 (fun v op1 op2 ->
1373 def mask = (pow2 len) - 1;
1379 andl r1, $~(mask << ofs);
1383 build_atom_block debug "bitfield" insts v cont)
1385 (* Binary relational operations on poly data.
1386 Currently you can only check for equivalence. *)
1387 | AtomBinop (EqOp ACPoly, a1, a2) ->
1388 code_relop_poly cg pos debug EQ a1 a2 cont
1389 | AtomBinop (NeqOp ACPoly, a1, a2) ->
1390 code_relop_poly cg pos debug NEQ a1 a2 cont
1392 (* Binary relational operations on int *)
1393 | AtomBinop (EqOp ACInt, a1, a2) ->
1394 code_relop_int cg pos debug EQ a1 a2 cont
1395 | AtomBinop (NeqOp ACInt, a1, a2) ->
1396 code_relop_int cg pos debug NEQ a1 a2 cont
1397 | AtomBinop (LtOp ACInt, a1, a2) ->
1398 code_relop_int cg pos debug LT a1 a2 cont
1399 | AtomBinop (LeOp ACInt, a1, a2) ->
1400 code_relop_int cg pos debug LE a1 a2 cont
1401 | AtomBinop (GtOp ACInt, a1, a2) ->
1402 code_relop_int cg pos debug GT a1 a2 cont
1403 | AtomBinop (GeOp ACInt, a1, a2) ->
1404 code_relop_int cg pos debug GE a1 a2 cont
1406 (* Binary relational operations on floats *)
1407 | AtomBinop (EqOp (ACFloat _), a1, a2) ->
1408 code_relop_float cg pos debug EQ a1 a2 cont
1409 | AtomBinop (NeqOp (ACFloat _), a1, a2) ->
1410 code_relop_float cg pos debug NEQ a1 a2 cont
1411 | AtomBinop (LtOp (ACFloat _), a1, a2) ->
1412 code_relop_float cg pos debug LT a1 a2 cont
1413 | AtomBinop (LeOp (ACFloat _), a1, a2) ->
1414 code_relop_float cg pos debug LE a1 a2 cont
1415 | AtomBinop (GtOp (ACFloat _), a1, a2) ->
1416 code_relop_float cg pos debug GT a1 a2 cont
1417 | AtomBinop (GeOp (ACFloat _), a1, a2) ->
1418 code_relop_float cg pos debug GE a1 a2 cont
1420 (* Binary relational operations on rawint *)
1421 | AtomBinop (EqOp (ACRawInt (pre, signed)), a1, a2) ->
1422 code_relop_rawint cg pos debug pre signed EQ a1 a2 cont
1423 | AtomBinop (NeqOp (ACRawInt (pre, signed)), a1, a2) ->
1424 code_relop_rawint cg pos debug pre signed NEQ a1 a2 cont
1425 | AtomBinop (LtOp (ACRawInt (pre, true)), a1, a2) ->
1426 code_relop_rawint cg pos debug pre true LT a1 a2 cont
1427 | AtomBinop (LtOp (ACRawInt (pre, false)), a1, a2) ->
1428 code_relop_rawint cg pos debug pre false ULT a1 a2 cont
1429 | AtomBinop (LeOp (ACRawInt (pre, true)), a1, a2) ->
1430 code_relop_rawint cg pos debug pre true LE a1 a2 cont
1431 | AtomBinop (LeOp (ACRawInt (pre, false)), a1, a2) ->
1432 code_relop_rawint cg pos debug pre false ULE a1 a2 cont
1433 | AtomBinop (GtOp (ACRawInt (pre, true)), a1, a2) ->
1434 code_relop_rawint cg pos debug pre true GT a1 a2 cont
1435 | AtomBinop (GtOp (ACRawInt (pre, false)), a1, a2) ->
1436 code_relop_rawint cg pos debug pre false UGT a1 a2 cont
1437 | AtomBinop (GeOp (ACRawInt (pre, true)), a1, a2) ->
1438 code_relop_rawint cg pos debug pre true GE a1 a2 cont
1439 | AtomBinop (GeOp (ACRawInt (pre, false)), a1, a2) ->
1440 code_relop_rawint cg pos debug pre false UGE a1 a2 cont
1442 (* Binary relational operations on pointers *)
1443 | AtomBinop (EqOp (ACPointer _), a1, a2) ->
1444 code_relop_ptr cg pos debug Rawint.Int32 false EQ a1 a2 cont
1445 | AtomBinop (NeqOp (ACPointer _), a1, a2) ->
1446 code_relop_ptr cg pos debug Rawint.Int32 false NEQ a1 a2 cont
1448 (* Binary memory operations *)
1449 | AtomBinop (MemOp (ACRawInt (pre, signed), _), a1, a2) when int32_ok pre ->
1450 code_let_mem_int32 cg pos debug (pre, signed) a1 a2 cont
1452 (* Unknown binary *)
1454 raise (MirException (pos, NotImplemented "code_atom_int32: AtomBinop"))
1458 Builds blocks to compute the atom expression given. Polymorphic
1459 values are HEAVILY restricted in what operations they can participate
1460 in; this is a drastic change from earlier policies which let Poly and
1461 Int32 be used interchangably. *)
1462 and code_atom_poly cg pos debug a cont =
1463 let pos = string_pos "code_atom_poly" pos in
1465 (* Constants and variables *)
1466 | AtomVar (ACPoly, v) ->
1469 (* Illegal operands *)
1475 raise (MirException (pos, ImplicitCoercion a))
1477 (* Unary coercion operators *)
1478 | AtomUnop (PolyOfIntOp, a) ->
1479 (* Coerce ML Int to Int32, but do NOT do the bit-shift *)
1480 code_atom_int cg pos debug a cont
1481 | AtomUnop (PolyOfPointerOp _, a)
1482 | AtomUnop (PolyOfFunctionOp _, a) ->
1483 (* Coerce a real pointer to Int32; identity operation. *)
1484 code_atom_ptr_off cg pos debug a cont
1488 raise (MirException (pos, NotImplemented "code_atom_int32: AtomUnop"))
1490 (* Binary memory operations *)
1491 | AtomBinop (MemOp (ACPoly, _), a1, a2) ->
1492 code_let_mem_poly cg pos debug a1 a2 cont
1494 (* Unknown binary *)
1496 raise (MirException (pos, NotImplemented "code_atom_int32: AtomBinop"))
1499 (*** Pointer Operations ***)
1502 (* code_atom_ptr_base
1503 Builds blocks to compute the atom expression given. Here the result of
1504 the atom expression must be a pointer type; furthermore it must point to
1505 the base of a block in memory. *)
1506 and code_atom_ptr_base cg pos debug a cont =
1507 let pos = string_pos "code_atom_ptr_base" pos in
1509 AtomVar (ACPointerInfix _, v) ->
1510 let v, _ = reg64_lookup cg pos v in
1512 | AtomVar (ac, v) when ptr_ok ac ->
1515 (* Escaping functions *)
1516 | AtomFunVar (_, v) ->
1517 code_fun_pointer_int32 cg pos debug v cont
1519 (* Coercions to pointer base *)
1520 | AtomUnop (PointerOfPolyOp _, a)
1521 | AtomUnop (FunctionOfPolyOp _, a) ->
1522 code_atom_poly cg pos debug a cont
1524 (* Infix pointer addition *)
1525 | AtomUnop (BaseOfInfixPointerOp _, a)
1526 | AtomBinop (InfixOfBaseOffsetOp _, a, _)
1527 | AtomBinop (PlusPointerOp _, a, _) ->
1528 code_atom_ptr_base cg pos debug a cont
1530 (* Binary memory operations *)
1531 | AtomBinop (MemOp (ac, _), a1, a2) when ptr_ok ac ->
1532 code_let_mem_int32 cg pos debug (Rawint.Int32, false) a1 a2 cont
1534 (* Unknown expression *)
1541 raise (MirException (pos, StringFormatError ("code_atom_ptr_base: expression not implemented",
1542 (fun buf -> pp_print_atom buf a))))
1545 (* code_atom_ptr_off
1546 Builds blocks to compute the atom expression given. Here the result of
1547 the atom expression must be a pointer type, and it may be an infix int32
1548 pointer. WARNING: do NOT use this when getting header fields. This will
1549 return a real pointer. *)
1550 and code_atom_ptr_off cg pos debug a cont =
1551 let pos = string_pos "code_atom_ptr_off" pos in
1553 AtomVar (ACPointerInfix _, v) ->
1554 let _, v = reg64_lookup cg pos v in
1556 | AtomVar (ac, v) when ptr_ok ac ->
1559 (* Escaping functions *)
1560 | AtomFunVar (_, v) ->
1561 code_fun_pointer_int32 cg pos debug v cont
1563 (* Coercions to pointer offset. Note: if the value is polymorphic
1564 then it is assumed to be a base pointer, not an infix pointer. *)
1565 | AtomUnop (PointerOfPolyOp _, a)
1566 | AtomUnop (FunctionOfPolyOp _, a) ->
1567 code_atom_poly cg pos debug a cont
1569 (* Infix pointers; note that pointer arithmetic and the infix
1570 constructor really use the same mechanism since in this case,
1571 we are only interested in the final offset pointer... *)
1572 | AtomBinop (InfixOfBaseOffsetOp _, a1, a2)
1573 | AtomBinop (PlusPointerOp _, a1, a2) ->
1574 code_atom_ptr_off cg pos debug a1 (fun op1 ->
1575 code_atom_int32 cg pos debug a2 (fun op2 ->
1583 let blocks, label = cont vlo in
1584 let block, label = code_build_dst_block debug "ptr" insts label in
1585 block :: blocks, label))
1587 (* Binary memory operations *)
1588 | AtomBinop (MemOp (ac, _), a1, a2) when ptr_ok ac ->
1589 code_let_mem_int32 cg pos debug (Rawint.Int32, false) a1 a2 cont
1591 (* Unknown expression *)
1598 raise (MirException (pos, StringFormatError ("code_atom_ptr_off: expression not implemented", (fun buf -> pp_print_atom buf a))))
1601 (* code_atom_ptr_infix
1602 Builds blocks to compute the atom expression given. Here the result of
1603 the atom expression must be a pointer offset type, and the continuation
1604 is given both parts. *)
1605 and code_atom_ptr_infix cg pos debug a cont =
1606 let pos = string_pos "code_atom_ptr_infix" pos in
1608 (* Load from a variable *)
1609 AtomVar (ACPointerInfix _, v) ->
1610 let vhi, vlo = reg64_lookup cg pos v in
1611 cont (Register vhi) (Register vlo)
1613 (* Infix pointer construction. Note here that we build the
1614 real pointer offset by using the code_atom_ptr_off mechanism,
1615 which will take the base/offset we already have and perform
1616 the pointer arithmetic to make the offset pointer. *)
1617 | AtomBinop (InfixOfBaseOffsetOp _, a1, a2) ->
1618 code_atom_ptr_base cg pos debug a1 (fun a1 ->
1619 code_atom_ptr_off cg pos debug a (fun a2 ->
1622 (* Pointer addition. In this case, we do the same thing as
1623 in code_atom_ptr_off, but we have to keep around an already-
1624 existing base pointer. *)
1625 | AtomBinop (PlusPointerOp _, a1, a2) ->
1626 code_atom_ptr_infix cg pos debug a1 (fun ohi olo ->
1627 code_atom_int32 cg pos debug a2 (fun op ->
1636 let blocks, label = cont ohi vlo in
1637 let block, label = code_build_dst_block debug "ptr_off" insts label in
1638 block :: blocks, label))
1640 (* Other operations are unknown *)
1648 raise (MirException (pos, StringFormatError ("code_atom_ptr_infix: expression not implemented", (fun buf -> pp_print_atom buf a))))
1651 (*** Int64 Operations ***)
1654 (* code_basic_unop_int64
1655 Writes wrapper code for a unary 64-bit operation. *)
1656 and code_basic_unop_int64 cg pos debug a cont cons =
1657 let pos = string_pos "code_basic_unop_int64" pos in
1658 code_atom_int64 cg pos debug a (fun ohi olo ->
1659 (* TEMP: Vars MUST be interned first, unfortunately! *)
1660 let vhi = Register (new_symbol_string "unop_int64_hi") in
1661 let vlo = Register (new_symbol_string "unop_int64_lo") in
1662 let blocks, label = cont vhi vlo in
1670 modify_listbuf `{ cons insts label (Register rhi) (Register rlo) `};
1674 let block, label = code_build_dst_block debug "unop_int64" insts label in
1675 block :: blocks, label)
1679 Writes a unary 64-bit operation. *)
1680 and code_unop_int64 cg pos debug a cont conshi conslo =
1681 let pos = string_pos "code_unop_int64" pos in
1682 code_basic_unop_int64 cg pos debug a cont (fun insts label ohi olo ->
1684 add_inst `{ conslo olo `};
1685 add_inst `{ conshi ohi `};`)
1688 (* code_basic_binop_int64
1689 Writes the infrastructure used by several int64 binary operations. *)
1690 and code_basic_binop_int64 cg pos debug a1 a2 cont cons =
1691 let pos = string_pos "code_basic_binop_int64" pos in
1692 code_atom_int64 cg pos debug a1 (fun ohi1 olo1 ->
1693 code_atom_int64 cg pos debug a2 (fun ohi2 olo2 ->
1694 (* TEMP: Cannot eliminate explicit var declarations *)
1695 let vhi = Register (new_symbol_string "binop_int64_hi") in
1696 let vlo = Register (new_symbol_string "binop_int64_lo") in
1697 let blocks, label = cont vhi vlo in
1705 modify_listbuf `{ cons insts label (Register rhi) (Register rlo) ohi2 olo2 `};
1709 let block, label = code_build_dst_block debug "binop_int64" insts label in
1710 block :: blocks, label))
1713 (* code_shift_binop_int64
1714 Writes the infrastructure required for a 64-bit shift. *)
1715 and code_shift_binop_int64 cg pos debug a1 a2 cont cons =
1716 let pos = string_pos "code_basic_binop_int64" pos in
1717 code_atom_int64 cg pos debug a1 (fun ohi1 olo1 ->
1718 code_atom_int64 cg pos debug a2 (fun ohi2 olo2 ->
1719 (* TEMP: Cannot remove explicit var decls here *)
1720 let vhi = Register (new_symbol_string "binop_int64_hi") in
1721 let vlo = Register (new_symbol_string "binop_int64_lo") in
1722 let blocks, label = cont vhi vlo in
1724 (* Build the code that will patch in/store result *)
1725 let insts, rhi, rlo =
1732 let block, label = code_build_dst_block debug "binop_int64" insts label in
1733 let blocks = block :: blocks in
1735 (* Build the code to load and shift *)
1741 modify_listbuf `{ cons insts label rhi rlo ohi2 olo2 `};`
1743 let block, label = code_build_dst_block debug "binop_int64" insts label in
1744 block :: blocks, label))
1748 Codes a typical binary operator, where conshi and conslo build the
1749 opcodes for building the high and low 32-bits, respectively. The
1750 low-order bits will be built first so the high-order constructor may
1751 take advantage of such things as the flags set by the low constructor
1752 (carry, borrow, etc). *)
1753 and code_binop_int64 cg pos debug a1 a2 cont conshi conslo =
1754 let pos = string_pos "code_binop_int64" pos in
1755 code_basic_binop_int64 cg pos debug a1 a2 cont (fun insts label ohi1 olo1 ohi2 olo2 ->
1759 add_inst `{ conslo olo1 (Register rlo2) `};
1761 add_inst `{ conshi ohi1 (Register rhi2) `};`)
1764 (* code_let_mem_int64
1765 Reads an int64 value from memory. This simply looks like two int32
1766 memory read operations, so lets build it up to look that way. *)
1767 and code_let_mem_int64 cg pos debug aptr aofs cont =
1768 let pos = string_pos "code_let_mem_int64" pos in
1769 let int_class = Rawint.Int32, true in
1770 let offset = Rawint.of_int Rawint.Int32 true sizeof_int32 in
1771 let alo, ahi = aofs, AtomBinop (PlusOp (ACRawInt (Rawint.Int32, true)), aofs, AtomRawInt offset) in
1772 code_let_mem_int32 cg pos debug int_class aptr alo (fun vlo ->
1773 code_let_mem_int32 cg pos debug int_class aptr ahi (fun vhi ->
1778 Builds blocks to compute the atom expression given. *)
1779 and code_atom_int64 cg pos debug a cont =
1780 let pos = string_pos "code_atom_int64" pos in
1782 (* Constants and variables *)
1786 raise (MirException (pos, ImplicitCoercion a))
1787 | AtomRawInt i when int32_ok (Rawint.precision i) ->
1788 raise (MirException (pos, ImplicitCoercion a))
1790 let i = Rawint.to_int64 i in
1791 let mask = Int64.pred (Int64.shift_left Int64.one 32) in
1792 let ihi = Int64.to_int32 (Int64.shift_right_logical i 32) in
1793 let ilo = Int64.to_int32 (Int64.logand i mask) in
1794 cont (ImmediateNumber (OffNumber ihi)) (ImmediateNumber (OffNumber ilo))
1795 | AtomVar (ACRawInt (Rawint.Int64, _), v) ->
1796 let vhi, vlo = reg64_lookup cg pos v in
1797 cont (Register vhi) (Register vlo)
1799 raise (MirException (pos, ImplicitCoercion a))
1801 (* Unary arithmetic *)
1802 | AtomUnop (UMinusOp (ACRawInt (Rawint.Int64, signed)), a) ->
1803 code_basic_unop_int64 cg pos debug a cont (fun insts label ohi olo ->
1808 | AtomUnop (NotOp (ACRawInt (Rawint.Int64, signed)), a) ->
1809 let cons op = NOT (IL, op) in
1810 code_unop_int64 cg pos debug a cont cons cons
1813 | AtomUnop (RawIntOfFloatOp (Rawint.Int64, true, _), a) ->
1814 code_int64_of_float cg pos debug a cont
1815 | AtomUnop (RawIntOfFloatOp (Rawint.Int64, false, _), a) ->
1816 atom_warning "coercion from float to unsigned will be treated as coercion from float to signed, expect range errors";
1817 code_int64_of_float cg pos debug a cont
1818 | AtomUnop (RawIntOfRawIntOp (Rawint.Int64, dsigned, spre, ssigned), a) when dsigned = ssigned ->
1819 code_int64_of_rawint cg pos debug spre ssigned a cont
1820 | AtomUnop (RawIntOfRawIntOp (Rawint.Int64, dsigned, Rawint.Int64, ssigned), a) ->
1821 (* sign change on same precision *)
1822 code_int64_of_rawint cg pos debug Rawint.Int64 ssigned a cont
1823 | AtomUnop (RawIntOfRawIntOp (Rawint.Int64, dsigned, spre, ssigned), a) when dsigned <> ssigned ->
1824 atom_warning "in coercions that change signedness, source sign wins in any bit extensions";
1825 code_int64_of_rawint cg pos debug spre ssigned a cont
1828 | AtomUnop (_, _) ->
1829 raise (MirException (pos, NotImplemented "code_atom_int64: AtomUnop"))
1831 (* Binary arithmetic operations *)
1832 | AtomBinop (PlusOp (ACRawInt (Rawint.Int64, _)), a1, a2) ->
1833 code_binop_int64 cg pos debug a1 a2 cont (fun op1 op2 -> ADC (IL, op1, op2)) (fun op1 op2 -> ADD (IL, op1, op2))
1834 | AtomBinop (MinusOp (ACRawInt (Rawint.Int64, _)), a1, a2) ->
1835 code_binop_int64 cg pos debug a1 a2 cont (fun op1 op2 -> SBB (IL, op1, op2)) (fun op1 op2 -> SUB (IL, op1, op2))
1836 | AtomBinop (MulOp (ACRawInt (Rawint.Int64, false)), a1, a2) ->
1837 (* Unsigned multiplication is easier *)
1838 code_basic_binop_int64 cg pos debug a1 a2 cont (fun insts label ohi1 olo1 ohi2 olo2 ->
1842 (* Multiply the high-order bits -- here it gets murky *)
1850 (* Multiply the low-order bits, add carry to rhi *)
1856 | AtomBinop (MulOp (ACRawInt (Rawint.Int64, true)), a1, a2) ->
1857 (* Signed multiplication will use the FP stack -- for now *)
1858 let a1 = AtomUnop (FloatOfRawIntOp (Rawfloat.LongDouble, Rawint.Int64, true), a1) in
1859 let a2 = AtomUnop (FloatOfRawIntOp (Rawfloat.LongDouble, Rawint.Int64, true), a2) in
1860 let a = AtomBinop (MulOp (ACFloat Rawfloat.LongDouble), a1, a2) in
1861 let a = AtomUnop (RawIntOfFloatOp (Rawint.Int64, true, Rawfloat.LongDouble), a) in
1862 code_atom_int64 cg pos debug a cont
1863 | AtomBinop (DivOp (ACRawInt (Rawint.Int64, true)), a1, a2) ->
1864 (* Signed division will use the FP stack -- for now *)
1865 let a1 = AtomUnop (FloatOfRawIntOp (Rawfloat.LongDouble, Rawint.Int64, true), a1) in
1866 let a2 = AtomUnop (FloatOfRawIntOp (Rawfloat.LongDouble, Rawint.Int64, true), a2) in
1867 let a = AtomBinop (DivOp (ACFloat Rawfloat.LongDouble), a1, a2) in
1868 let a = AtomUnop (RawIntOfFloatOp (Rawint.Int64, true, Rawfloat.LongDouble), a) in
1869 code_atom_int64 cg pos debug a cont
1870 | AtomBinop (AndOp (ACRawInt (Rawint.Int64, _)), a1, a2) ->
1871 let logop op1 op2 = AND (IL, op1, op2) in
1872 code_binop_int64 cg pos debug a1 a2 cont logop logop
1873 | AtomBinop (OrOp (ACRawInt (Rawint.Int64, _)), a1, a2) ->
1874 let logop op1 op2 = OR (IL, op1, op2) in
1875 code_binop_int64 cg pos debug a1 a2 cont logop logop
1876 | AtomBinop (XorOp (ACRawInt (Rawint.Int64, _)), a1, a2) ->
1877 let logop op1 op2 = XOR (IL, op1, op2) in
1878 code_binop_int64 cg pos debug a1 a2 cont logop logop
1879 | AtomBinop (SlOp (ACRawInt (Rawint.Int64, signed)), a1, a2) ->
1880 code_shift_binop_int64 cg pos debug a1 a2 cont (fun insts label ohi1 olo1 ohi2 olo2 ->
1883 shldl ohi1, olo1, ecx;
1889 | AtomBinop (ASrOp (ACRawInt (Rawint.Int64, signed)), a1, a2) ->
1890 code_shift_binop_int64 cg pos debug a1 a2 cont (fun insts label ohi1 olo1 ohi2 olo2 ->
1893 shrdl olo1, ohi1, ecx;
1899 | AtomBinop (LSrOp (ACRawInt (Rawint.Int64, signed)), a1, a2) ->
1900 code_shift_binop_int64 cg pos debug a1 a2 cont (fun insts label ohi1 olo1 ohi2 olo2 ->
1903 shrdl olo1, ohi1, ecx;
1910 (* Binary memory operations *)
1911 | AtomBinop (MemOp (ACRawInt (Rawint.Int64, _), _), a1, a2) ->
1912 code_let_mem_int64 cg pos debug a1 a2 cont
1914 (* Unknown binary *)
1915 | AtomBinop (_, _, _) ->
1916 raise (MirException (pos, NotImplemented "code_atom_int64: AtomBinop"))
1919 (*** Floating-point Operations ***)
1923 Writes the code necessary to load a constant into a floating-point
1924 register. This just looks up the label that the constant is stored
1925 at and substitutes it in the continuation. *)
1926 and code_float_const cg pos debug f cont =
1927 let pos = string_pos "code_float_const" pos in
1928 let f = Rawfloat.to_float80 f in
1929 let v = fvals_lookup cg pos f in
1934 Writes code for a unary floating-point operation that reads its
1935 sole input from %st(0) and writes the result to same register. *)
1936 and code_unop_float cg pos debug a cont cons =
1937 let pos = string_pos "code_unop_float" pos in
1938 code_atom_float cg pos debug a (fun op ->
1943 add_inst `{ cons `};
1946 build_atom_block debug "unop" insts v cont)
1949 (* code_basic_binop_float
1950 Writes the infrastructure used by most binary operations. *)
1951 and code_basic_binop_float cg pos debug a1 a2 cont =
1952 let pos = string_pos "code_basic_binop_float" pos in
1953 let v = FloatRegister (new_symbol_string "binop_res") in
1954 code_atom_float cg pos debug a1 (fun op1 ->
1955 code_atom_float cg pos debug a2 (fun op2 ->
1960 Writes a binary operator of two floats, where the binary operation
1961 in question is a no-operand that reads both values from the stack,
1962 pops the stack and stores the result in the new top-of-stack. There
1963 may be other forms of this function for instructions which must take
1964 an argument, or require the arguments to be put on stack in reverse
1966 and code_binop_float cg pos debug a1 a2 cont cons =
1967 let pos = string_pos "code_binop_float" pos in
1968 code_basic_binop_float cg pos debug a1 a2 (fun v op1 op2 ->
1972 fldt op2; (* This will be %st(1) *)
1973 fldt op1; (* This will be %st(0) *)
1974 add_inst `{ cons `};
1977 build_atom_block debug "binop" insts v cont)
1980 (* code_binop_pop_float
1981 Same as above, but cons doesn't pop the stack, so we do it ourselves. *)
1982 and code_binop_pop_float cg pos debug a1 a2 cont cons =
1983 let pos = string_pos "code_binop_pop_float" pos in
1984 code_basic_binop_float cg pos debug a1 a2 (fun v op1 op2 ->
1988 fldt op2; (* This will be %st(1) *)
1989 fldt op1; (* This will be %st(0) *)
1990 add_inst `{ cons `};
1994 build_atom_block debug "binop" insts v cont)
1997 (* code_let_mem_float
1998 Reads a floating-point value from memory. We can mostly reuse
1999 code that is constructed earlier, only varying the final load
2000 (which we use the FP stack as an intermediary for, in convenience). *)
2001 and code_let_mem_float cg pos debug float_class a1 a2 cont =
2002 let pos = string_pos "code_let_mem_float" pos in
2003 let v = FloatRegister (new_symbol_string "let_mem") in
2004 let float_class = float_prec float_class in
2005 let load_insts_float operand insts =
2006 let insts = Listbuf.add_list insts
2007 [CommentString "Loading a float from memory";
2008 FMOVP (FT, v, float_class, operand)]
2010 let blocks, label = cont v in
2011 let block, label = code_build_dst_block debug "code_let_mem_float" insts label in
2012 block :: blocks, label
2014 code_let_mem_aux cg pos debug a1 a2 load_insts_float
2017 (* code_binop_float_max
2018 code_binop_float_min
2019 Computes max- and min-code for floating-point values. This is
2020 more optimized than doing the computation in FIR, since we can
2021 do the branch optimization here. *)
2022 and code_binop_float_max cg pos debug a1 a2 cont =
2023 let pos = string_pos "code_binop_float_max" pos in
2024 code_basic_binop_float cg pos debug a1 a2 (fun v op1 op2 ->
2025 code_cond_float_op debug GT cont v op1 op2 op1 op2)
2027 and code_binop_float_min cg pos debug a1 a2 cont =
2028 let pos = string_pos "code_binop_float_min" pos in
2029 code_basic_binop_float cg pos debug a1 a2 (fun v op1 op2 ->
2030 code_cond_float_op debug LT cont v op1 op2 op1 op2)
2034 Builds blocks to compute the atom expression given. *)
2035 and code_atom_float cg pos debug a cont =
2036 let pos = string_pos "code_atom_float" pos in
2038 (* Constants and variables *)
2042 raise (MirException (pos, ImplicitCoercion a))
2043 | AtomVar (ACFloat _, v) ->
2044 cont (FloatRegister v)
2046 raise (MirException (pos, ImplicitCoercion a))
2048 code_float_const cg pos debug x cont
2050 (* Unary arithmetic & bitwise operations *)
2051 | AtomUnop (UMinusOp (ACFloat _), a) ->
2052 code_unop_float cg pos debug a cont FCHS
2053 | AtomUnop (FloatOfRawIntOp (_, pre, true), a) when int32_ok pre ->
2054 code_float_of_int32 cg pos debug a cont
2055 | AtomUnop (FloatOfRawIntOp (_, Rawint.Int64, true), a) ->
2056 code_float_of_int64 cg pos debug a cont
2058 (* Unary FloatOfFloat is an identity *)
2059 | AtomUnop (FloatOfFloatOp _, a) ->
2060 code_atom_float cg pos debug a cont
2062 (* Unary triginometric and roots *)
2063 | AtomUnop (SinOp _, a) ->
2064 code_unop_float cg pos debug a cont FSIN
2065 | AtomUnop (CosOp _, a) ->
2066 code_unop_float cg pos debug a cont FCOS
2067 | AtomUnop (SqrtOp _, a) ->
2068 code_unop_float cg pos debug a cont FSQRT
2071 | AtomUnop (_, _) ->
2072 raise (MirException (pos, NotImplemented "code_atom_float: AtomUnop"))
2074 (* Addition and subtraction *)
2075 | AtomBinop (PlusOp (ACFloat _), a1, a2) ->
2076 code_binop_float cg pos debug a2 a1 cont FADDP
2077 | AtomBinop (MinusOp (ACFloat _), a1, a2) ->
2078 code_binop_float cg pos debug a1 a2 cont FSUBP
2079 | AtomBinop (MulOp (ACFloat _), a1, a2) ->
2080 code_binop_float cg pos debug a2 a1 cont FMULP
2081 | AtomBinop (DivOp (ACFloat _), a1, a2) ->
2082 code_binop_float cg pos debug a1 a2 cont FDIVP
2083 | AtomBinop (RemOp (ACFloat _), a1, a2) ->
2084 code_binop_pop_float cg pos debug a1 a2 cont FPREM
2086 (* Bounds operations *)
2087 | AtomBinop (MaxOp (ACFloat _), a1, a2) ->
2088 code_binop_float_max cg pos debug a1 a2 cont
2089 | AtomBinop (MinOp (ACFloat _), a1, a2) ->
2090 code_binop_float_min cg pos debug a1 a2 cont
2092 (* Triginometric operations *)
2093 | AtomBinop (ATan2Op _, a1, a2) ->
2094 code_binop_pop_float cg pos debug a1 a2 cont FPATAN
2096 (* Binary memory operations *)
2097 | AtomBinop (MemOp (ACFloat fprec, _), a1, a2) ->
2098 code_let_mem_float cg pos debug fprec a1 a2 cont
2100 (* Unknown binary *)
2101 | AtomBinop (_, _, _) ->
2102 raise (MirException (pos, NotImplemented "code_atom_float: AtomBinop"))