1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
|
# 2 "asmcomp/arm64/selection.ml"
(**************************************************************************)
(* *)
(* OCaml *)
(* *)
(* Xavier Leroy, projet Gallium, INRIA Rocquencourt *)
(* Benedikt Meurer, University of Siegen *)
(* *)
(* Copyright 2013 Institut National de Recherche en Informatique et *)
(* en Automatique. *)
(* Copyright 2012 Benedikt Meurer. *)
(* *)
(* All rights reserved. This file is distributed under the terms of *)
(* the GNU Lesser General Public License version 2.1, with the *)
(* special exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)
(* Instruction selection for the ARM processor *)
open Arch
open Cmm
open Mach
let is_offset chunk n =
(n >= -256 && n <= 255) (* 9 bits signed unscaled *)
|| (n >= 0 &&
match chunk with (* 12 bits unsigned, scaled by chunk size *)
| Byte_unsigned | Byte_signed ->
n < 0x1000
| Sixteen_unsigned | Sixteen_signed ->
n land 1 = 0 && n lsr 1 < 0x1000
| Thirtytwo_unsigned | Thirtytwo_signed | Single ->
n land 3 = 0 && n lsr 2 < 0x1000
| Sixtyfour | Word_int | Word_val | Double ->
n land 7 = 0 && n lsr 3 < 0x1000)
let is_logical_immediate n =
Arch.is_logical_immediate (Nativeint.of_int n)
(* Signed immediates are simpler *)
let is_immediate n =
let mn = -n in
n land 0xFFF = n || n land 0xFFF_000 = n
|| mn land 0xFFF = mn || mn land 0xFFF_000 = mn
(* If you update [inline_ops], you may need to update [is_simple_expr] and/or
[effects_of], below. *)
let inline_ops =
[ "sqrt"; "caml_bswap16_direct"; "caml_int32_direct_bswap";
"caml_int64_direct_bswap"; "caml_nativeint_direct_bswap" ]
let use_direct_addressing _symb =
(not !Clflags.dlcode) && (not Arch.macosx)
let is_stack_slot rv =
Reg.(match rv with
| [| { loc = Stack _ } |] -> true
| _ -> false)
(* Instruction selection *)
class selector = object(self)
inherit Selectgen.selector_generic as super
method is_immediate_test _cmp n =
is_immediate n
method! is_immediate op n =
match op with
| Iadd | Isub -> n <= 0xFFF_FFF && n >= -0xFFF_FFF
| Iand | Ior | Ixor -> is_logical_immediate n
| Icomp _ | Icheckbound -> is_immediate n
| _ -> super#is_immediate op n
method! is_simple_expr = function
(* inlined floating-point ops are simple if their arguments are *)
| Cop(Cextcall (fn, _, _, _), args, _) when List.mem fn inline_ops ->
List.for_all self#is_simple_expr args
| e -> super#is_simple_expr e
method! effects_of e =
match e with
| Cop(Cextcall (fn, _, _, _), args, _) when List.mem fn inline_ops ->
Selectgen.Effect_and_coeffect.join_list_map args self#effects_of
| e -> super#effects_of e
method select_addressing chunk = function
| Cop((Caddv | Cadda), [Cconst_symbol (s, _); Cconst_int (n, _)], _)
when use_direct_addressing s ->
(Ibased(s, n), Ctuple [])
| Cop((Caddv | Cadda), [arg; Cconst_int (n, _)], _)
when is_offset chunk n ->
(Iindexed n, arg)
| Cop((Caddv | Cadda as op),
[arg1; Cop(Caddi, [arg2; Cconst_int (n, _)], _)], dbg)
when is_offset chunk n ->
(Iindexed n, Cop(op, [arg1; arg2], dbg))
| Cconst_symbol (s, _)
when use_direct_addressing s ->
(Ibased(s, 0), Ctuple [])
| arg ->
(Iindexed 0, arg)
method! select_operation op args dbg =
match op with
(* Integer addition *)
| Caddi | Caddv | Cadda ->
begin match args with
(* Shift-add *)
| [arg1; Cop(Clsl, [arg2; Cconst_int (n, _)], _)] when n > 0 && n < 64 ->
(Ispecific(Ishiftarith(Ishiftadd, n)), [arg1; arg2])
| [arg1; Cop(Casr, [arg2; Cconst_int (n, _)], _)] when n > 0 && n < 64 ->
(Ispecific(Ishiftarith(Ishiftadd, -n)), [arg1; arg2])
| [Cop(Clsl, [arg1; Cconst_int (n, _)], _); arg2] when n > 0 && n < 64 ->
(Ispecific(Ishiftarith(Ishiftadd, n)), [arg2; arg1])
| [Cop(Casr, [arg1; Cconst_int (n, _)], _); arg2] when n > 0 && n < 64 ->
(Ispecific(Ishiftarith(Ishiftadd, -n)), [arg2; arg1])
(* Multiply-add *)
| [arg1; Cop(Cmuli, args2, dbg)] | [Cop(Cmuli, args2, dbg); arg1] ->
begin match self#select_operation Cmuli args2 dbg with
| (Iintop_imm(Ilsl, l), [arg3]) ->
(Ispecific(Ishiftarith(Ishiftadd, l)), [arg1; arg3])
| (Iintop Imul, [arg3; arg4]) ->
(Ispecific Imuladd, [arg3; arg4; arg1])
| _ ->
super#select_operation op args dbg
end
| _ ->
super#select_operation op args dbg
end
(* Integer subtraction *)
| Csubi ->
begin match args with
(* Shift-sub *)
| [arg1; Cop(Clsl, [arg2; Cconst_int (n, _)], _)] when n > 0 && n < 64 ->
(Ispecific(Ishiftarith(Ishiftsub, n)), [arg1; arg2])
| [arg1; Cop(Casr, [arg2; Cconst_int (n, _)], _)] when n > 0 && n < 64 ->
(Ispecific(Ishiftarith(Ishiftsub, -n)), [arg1; arg2])
(* Multiply-sub *)
| [arg1; Cop(Cmuli, args2, dbg)] ->
begin match self#select_operation Cmuli args2 dbg with
| (Iintop_imm(Ilsl, l), [arg3]) ->
(Ispecific(Ishiftarith(Ishiftsub, l)), [arg1; arg3])
| (Iintop Imul, [arg3; arg4]) ->
(Ispecific Imulsub, [arg3; arg4; arg1])
| _ ->
super#select_operation op args dbg
end
| _ ->
super#select_operation op args dbg
end
(* Checkbounds *)
| Ccheckbound ->
begin match args with
| [Cop(Clsr, [arg1; Cconst_int (n, _)], _); arg2] when n > 0 && n < 64 ->
(Ispecific(Ishiftcheckbound { shift = n; }),
[arg1; arg2])
| _ ->
super#select_operation op args dbg
end
(* Recognize sign extension *)
| Casr ->
begin match args with
[Cop(Clsl, [k; Cconst_int (n, _)], _); Cconst_int (n', _)]
when n' = n && 0 < n && n < 64 ->
(Ispecific (Isignext (64 - n)), [k])
| _ -> super#select_operation op args dbg
end
(* Use trivial addressing mode for atomic loads *)
| Cload {memory_chunk; mutability; is_atomic = true} ->
(Iload {memory_chunk; addressing_mode = Iindexed 0;
mutability; is_atomic = true},
args)
(* Recognize floating-point negate and multiply *)
| Cnegf ->
begin match args with
| [Cop(Cmulf, args, _)] -> (Ispecific Inegmulf, args)
| _ -> super#select_operation op args dbg
end
(* Recognize floating-point multiply and add/sub *)
| Caddf ->
begin match args with
| [arg; Cop(Cmulf, args, _)] | [Cop(Cmulf, args, _); arg] ->
(Ispecific Imuladdf, arg :: args)
| _ ->
super#select_operation op args dbg
end
| Csubf ->
begin match args with
| [arg; Cop(Cmulf, args, _)] ->
(Ispecific Imulsubf, arg :: args)
| [Cop(Cmulf, args, _); arg] ->
(Ispecific Inegmulsubf, arg :: args)
| _ ->
super#select_operation op args dbg
end
(* Recognize floating-point square root *)
| Cextcall("sqrt", _, _, _) ->
(Ispecific Isqrtf, args)
(* Recognize bswap instructions *)
| Cextcall("caml_bswap16_direct", _, _, _) ->
(Ispecific(Ibswap 16), args)
| Cextcall("caml_int32_direct_bswap", _, _, _) ->
(Ispecific(Ibswap 32), args)
| Cextcall(("caml_int64_direct_bswap"|"caml_nativeint_direct_bswap"),
_, _, _) ->
(Ispecific (Ibswap 64), args)
(* Other operations are regular *)
| _ ->
super#select_operation op args dbg
method! insert_move_extcall_arg env ty_arg src dst =
if macosx && ty_arg = XInt32 && is_stack_slot dst
then self#insert env (Iop (Ispecific Imove32)) src dst
else self#insert_moves env src dst
end
let fundecl ~future_funcnames f = (new selector)#emit_fundecl
~future_funcnames f
|