From bdb169a04f3c42716bf98bdab661a509e287065d Mon Sep 17 00:00:00 2001 From: Xavier Leroy Date: Nov 01 2013 18:10:18 +0000 Subject: Follow-up to commit r14254: optimization of immediate division and modulus for ARM64. Completely untested. git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@14257 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02 --- diff --git a/asmcomp/arm64/emit.mlp b/asmcomp/arm64/emit.mlp index fc9649c..ac8216c 100644 --- a/asmcomp/arm64/emit.mlp +++ b/asmcomp/arm64/emit.mlp @@ -454,17 +454,41 @@ let emit_instr i = | Lop(Iintop Imod) -> ` sdiv {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; ` msub {emit_reg i.res.(0)}, {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n` - | Lop(Iintop_imm(Idiv, n)) -> (* n is a power of 2 *) + | Lop(Iintop_imm(Idiv, n)) -> let l = Misc.log2 n in - ` asr {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, #63\n`; - ` add {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg reg_tmp1}, lsr {emit_int (64-l)}\n`; - ` asr {emit_reg i.res.(0)}, {emit_reg reg_tmp1}, {emit_int l}\n` - | Lop(Iintop_imm(Imod, n)) -> (* n is a power of 2 *) + if n = 1 lsl l then begin + ` asr {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, #63\n`; + ` add {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg reg_tmp1}, lsr {emit_int (64-l)}\n`; + ` asr {emit_reg i.res.(0)}, {emit_reg reg_tmp1}, {emit_int l}\n` + end else begin + let (m, p) = Selectgen.divimm_parameters (Nativeint.of_int n) in + emit_intconst reg_tmp1 m; + ` smulh {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg reg_tmp1}\n`; + if m < 0n then + ` add {emit_reg reg_tmp1}, {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}\n`; + if p > 0 then + ` asr {emit_reg reg_tmp1}, #{emit_int p}\n`; + ` add {emit_reg i.res.(0)}, {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, lsr 63\n` + end + | Lop(Iintop_imm(Imod, n)) -> let l = Misc.log2 n in - ` asr {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, #63\n`; - ` add {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg reg_tmp1}, lsr {emit_int (64-l)}\n`; - ` asr {emit_reg reg_tmp1}, {emit_reg reg_tmp1}, {emit_int l}\n`; - ` sub {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg reg_tmp1}, lsl {emit_int l}\n` + if n = 1 lsl l then begin + ` asr {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, #63\n`; + ` add {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg reg_tmp1}, lsr {emit_int (64-l)}\n`; + ` asr {emit_reg reg_tmp1}, {emit_reg reg_tmp1}, {emit_int l}\n`; + ` sub {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg reg_tmp1}, lsl {emit_int l}\n` + end else begin + let (m, p) = Selectgen.divimm_parameters (Nativeint.of_int n) in + emit_intconst reg_tmp1 m; + ` smulh {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg reg_tmp1}\n`; + if m < 0n then + ` add {emit_reg reg_tmp1}, {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}\n`; + if p > 0 then + ` asr {emit_reg reg_tmp1}, #{emit_int p}\n`; + ` add {emit_reg reg_tmp1}, {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, lsr 63\n`; + emit_intconst reg_tmp2 (Nativeint.of_int n); + ` msub {emit_reg i.res.(0)}, {emit_reg reg_tmp1}, {emit_reg reg_tmp2}, {emit_reg i.arg.(0)}\n` + end | Lop(Iintop op) -> let instr = name_for_int_operation op in ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` diff --git a/asmcomp/arm64/selection.ml b/asmcomp/arm64/selection.ml index c74b282..6af158f 100644 --- a/asmcomp/arm64/selection.ml +++ b/asmcomp/arm64/selection.ml @@ -194,17 +194,17 @@ method! select_operation op args = (Iintop Imul, args) end (* Division and modulus *) - (* Recognize (x / cst) and (x % cst) only if cst is a power of 2. *) + (* Recognize (x / cst) and (x % cst) only if cst is > 0. *) | Cdivi -> begin match args with - | [arg; Cconst_int n] when n = 1 lsl Misc.log2 n -> + | [arg; Cconst_int n] when n > 0 -> ((if n = 1 then Imove else Iintop_imm(Idiv, n)), [arg]) | _ -> (Iintop Idiv, args) end | Cmodi -> begin match args with - | [arg; Cconst_int n] when n = 1 lsl Misc.log2 n -> + | [arg; Cconst_int n] when n > 0 -> ((if n = 1 then Iconst_int 0n else Iintop_imm(Imod, n)), [arg]) | _ -> (Iintop Imod, args)