diff options
Diffstat (limited to 'ocaml-binary-annot/asmcomp/arm/selection.ml')
| -rw-r--r-- | ocaml-binary-annot/asmcomp/arm/selection.ml | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/ocaml-binary-annot/asmcomp/arm/selection.ml b/ocaml-binary-annot/asmcomp/arm/selection.ml new file mode 100644 index 0000000000..1574bf01e7 --- /dev/null +++ b/ocaml-binary-annot/asmcomp/arm/selection.ml @@ -0,0 +1,200 @@ +(***********************************************************************) +(* *) +(* Objective Caml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1998 Institut National de Recherche en Informatique et *) +(* en Automatique. All rights reserved. This file is distributed *) +(* under the terms of the Q Public License version 1.0. *) +(* *) +(***********************************************************************) + +(* $Id$ *) + +(* Instruction selection for the ARM processor *) + +open Misc +open Cmm +open Reg +open Arch +open Proc +open Mach + +(* Immediate operands are 8-bit immediate values, zero-extended, and rotated + right by 0, 2, 4, ... 30 bits. + To avoid problems with Caml's 31-bit arithmetic, + we check only with 8-bit values shifted left 0 to 22 bits. *) + +let rec is_immed n shift = + if shift > 22 then false + else if n land (0xFF lsl shift) = n then true + else is_immed n (shift + 2) + +(* We have 12-bit + sign byte offsets for word accesses, + 8-bit + sign word offsets for float accesses, + and 8-bit + sign byte offsets for bytes and shorts. + Use lowest common denominator. *) + +let is_offset n = n < 256 && n > -256 + +let is_intconst = function Cconst_int n -> true | _ -> false + +(* Soft emulation of float comparisons *) + +let float_comparison_function = function + | Ceq -> "__eqdf2" + | Cne -> "__nedf2" + | Clt -> "__ltdf2" + | Cle -> "__ledf2" + | Cgt -> "__gtdf2" + | Cge -> "__gedf2" + +(* Instruction selection *) +class selector = object(self) + +inherit Selectgen.selector_generic as super + +method! regs_for tyv = + (* Expand floats into pairs of integer registers *) + let nty = Array.length tyv in + let rec expand i = + if i >= nty then [] else begin + match tyv.(i) with + | Float -> Int :: Int :: expand (i+1) + | ty -> ty :: expand (i+1) + end in + Reg.createv (Array.of_list (expand 0)) + +method is_immediate n = + n land 0xFF = n || is_immed n 2 + +method select_addressing = function + Cop(Cadda, [arg; Cconst_int n]) when is_offset n -> + (Iindexed n, arg) + | Cop(Cadda, [arg1; Cop(Caddi, [arg2; Cconst_int n])]) when is_offset n -> + (Iindexed n, Cop(Cadda, [arg1; arg2])) + | arg -> + (Iindexed 0, arg) + +method select_shift_arith op shiftop shiftrevop args = + match args with + [arg1; Cop(Clsl, [arg2; Cconst_int n])] + when n > 0 && n < 32 && not(is_intconst arg2) -> + (Ispecific(Ishiftarith(shiftop, n)), [arg1; arg2]) + | [arg1; Cop(Casr, [arg2; Cconst_int n])] + when n > 0 && n < 32 && not(is_intconst arg2) -> + (Ispecific(Ishiftarith(shiftop, -n)), [arg1; arg2]) + | [Cop(Clsl, [arg1; Cconst_int n]); arg2] + when n > 0 && n < 32 && not(is_intconst arg1) -> + (Ispecific(Ishiftarith(shiftrevop, n)), [arg2; arg1]) + | [Cop(Casr, [arg1; Cconst_int n]); arg2] + when n > 0 && n < 32 && not(is_intconst arg1) -> + (Ispecific(Ishiftarith(shiftrevop, -n)), [arg2; arg1]) + | _ -> + super#select_operation op args + +method! select_operation op args = + match op with + Cadda | Caddi -> + begin match args with + [arg1; Cconst_int n] when n < 0 && self#is_immediate (-n) -> + (Iintop_imm(Isub, -n), [arg1]) + | _ -> + self#select_shift_arith op Ishiftadd Ishiftadd args + end + | Csuba | Csubi -> + begin match args with + [arg1; Cconst_int n] when n < 0 && self#is_immediate (-n) -> + (Iintop_imm(Iadd, -n), [arg1]) + | [Cconst_int n; arg2] when self#is_immediate n -> + (Ispecific(Irevsubimm n), [arg2]) + | _ -> + self#select_shift_arith op Ishiftsub Ishiftsubrev args + end + | Cmuli -> (* no multiply immediate *) + (Iintop Imul, args) + | Cdivi -> + begin match args with + [arg1; Cconst_int n] when n = 1 lsl (Misc.log2 n) -> + (Iintop_imm(Idiv, n), [arg1]) + | _ -> + (Iextcall("__divsi3", false), args) + end + | Cmodi -> + begin match args with + [arg1; Cconst_int n] when n = 1 lsl (Misc.log2 n) -> + (Iintop_imm(Imod, n), [arg1]) + | _ -> + (Iextcall("__modsi3", false), args) + end + | Ccheckbound _ -> + begin match args with + [Cop(Clsr, [arg1; Cconst_int n]); arg2] + when n > 0 && n < 32 && not(is_intconst arg2) -> + (Ispecific(Ishiftcheckbound n), [arg1; arg2]) + | _ -> + super#select_operation op args + end + (* Turn floating-point operations into library function calls *) + | Caddf -> (Iextcall("__adddf3", false), args) + | Csubf -> (Iextcall("__subdf3", false), args) + | Cmulf -> (Iextcall("__muldf3", false), args) + | Cdivf -> (Iextcall("__divdf3", false), args) + | Cfloatofint -> (Iextcall("__floatsidf", false), args) + | Cintoffloat -> (Iextcall("__fixdfsi", false), args) + | Ccmpf comp -> + (Iintop_imm(Icomp(Isigned comp), 0), + [Cop(Cextcall(float_comparison_function comp, + typ_int, false, Debuginfo.none), + args)]) + (* Add coercions around loads and stores of 32-bit floats *) + | Cload Single -> + (Iextcall("__extendsfdf2", false), [Cop(Cload Word, args)]) + | Cstore Single -> + begin match args with + | [arg1; arg2] -> + let arg2' = + Cop(Cextcall("__truncdfsf2", typ_int, false, Debuginfo.none), + [arg2]) in + self#select_operation (Cstore Word) [arg1; arg2'] + | _ -> assert false + end + (* Other operations are regular *) + | _ -> super#select_operation op args + +method! select_condition = function + | Cop(Ccmpf cmp, args) -> + (Iinttest_imm(Isigned cmp, 0), + Cop(Cextcall(float_comparison_function cmp, + typ_int, false, Debuginfo.none), + args)) + | expr -> + super#select_condition expr + +(* Deal with some register irregularities: + +1- In mul rd, rm, rs, the registers rm and rd must be different. + We deal with this by pretending that rm is also a result of the mul + operation. + +2- For Inegf and Iabsf, force arguments and results in (r0, r1); + this simplifies code generation later. +*) + +method! insert_op_debug op dbg rs rd = + match op with + | Iintop(Imul) -> + self#insert_debug (Iop op) dbg rs [| rd.(0); rs.(0) |]; rd + | Iabsf | Inegf -> + let r = [| phys_reg 0; phys_reg 1 |] in + self#insert_moves rs r; + self#insert_debug (Iop op) dbg r r; + self#insert_moves r rd; + rd + | _ -> + super#insert_op_debug op dbg rs rd + +end + +let fundecl f = (new selector)#emit_fundecl f |
