From d009572893913b889320f2fa3435543ee4c63f82 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sun, 27 Dec 2020 10:36:31 +0100 Subject: Remove PUSHACC0, as it is strictly equivalent to PUSH. --- kernel/vmemitcodes.ml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'kernel/vmemitcodes.ml') diff --git a/kernel/vmemitcodes.ml b/kernel/vmemitcodes.ml index c1d8fcb855..e70285d9ab 100644 --- a/kernel/vmemitcodes.ml +++ b/kernel/vmemitcodes.ml @@ -375,7 +375,9 @@ let rec emit env insns remaining = match insns with | (first::rest) -> emit env first rest) (* Peephole optimizations *) | Kpush :: Kacc n :: c -> - if n < 8 then out env(opPUSHACC0 + n) else (out env opPUSHACC; out_int env n); + if n = 0 then out env opPUSH + else if n < 8 then out env (opPUSHACC1 + n - 1) + else (out env opPUSHACC; out_int env n); emit env c remaining | Kpush :: Kenvacc n :: c -> if n >= 0 && n <= 3 -- cgit v1.2.3 From ee5fa81585a67cc556b19e145f518b641c40ffb7 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sun, 27 Dec 2020 11:24:07 +0100 Subject: Add a peephole optimization for PUSHFIELDS(1). The PUSHFIELDS opcode is a costly one, yet lots of constructors have at most one usable argument (e.g., option, nat, positive, Z, Acc). For those constructors, PUSHFIELDS(1) is replaced by GETFIELD(0);PUSH, assuming the accu register is no longer used afterwards. Replacing one single opcode by two opcodes might seem like a pessimization, but it is not. Indeed, pattern-matching branches usually start by filling the accu register with a constructor argument or the value of a free variable or a constant. All of those offer peephole optimizations for PUSH, which means that the number of opcodes actually stay constant. Note that, for the same reason, the assumption above holds in practice: the accu register is no longer used after PUSHFIELDS. --- kernel/vmemitcodes.ml | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'kernel/vmemitcodes.ml') diff --git a/kernel/vmemitcodes.ml b/kernel/vmemitcodes.ml index e70285d9ab..5849641c20 100644 --- a/kernel/vmemitcodes.ml +++ b/kernel/vmemitcodes.ml @@ -135,6 +135,16 @@ let out env opcode = let is_immed i = Uint63.le (Uint63.of_int i) Uint63.maxuint31 +(* Detect whether the current value of the accu register is no longer + needed (i.e., the register is written before being read). If so, the + register can be used freely; no need to save and restore it. *) +let is_accu_dead = function + | [] -> false + | c :: _ -> + match c with + | Kacc _ | Kenvacc _ | Kconst _ | Koffsetclosure _ | Kgetglobal _ -> true + | _ -> false + let out_int env n = out_word env n (n asr 8) (n asr 16) (n asr 24) @@ -399,6 +409,9 @@ let rec emit env insns remaining = match insns with | Kpush :: Kconst const :: c -> out env opPUSHGETGLOBAL; slot_for_const env const; emit env c remaining + | Kpushfields 1 :: c when is_accu_dead c -> + out env opGETFIELD0; + emit env (Kpush :: c) remaining | Kpop n :: Kjump :: c -> out env opRETURN; out_int env n; emit env c remaining | Ksequence c1 :: c -> -- cgit v1.2.3 From d1215d47c3cda09f4df2f07ce9362b3e6fc5b164 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sun, 27 Dec 2020 11:29:51 +0100 Subject: Remove SETFIELD0 and SETFIELD1. The generated bytecode almost never needs to modify the field of an OCaml object. The only exception is the laziness mechanism of coinductive types. But it modifies field 2, and thus uses the generic opcode SETFIELD anyway. --- kernel/vmemitcodes.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'kernel/vmemitcodes.ml') diff --git a/kernel/vmemitcodes.ml b/kernel/vmemitcodes.ml index 5849641c20..85b5ca03e5 100644 --- a/kernel/vmemitcodes.ml +++ b/kernel/vmemitcodes.ml @@ -359,8 +359,7 @@ let emit_instr env = function if n <= 1 then out env (opGETFIELD0+n) else (out env opGETFIELD;out_int env n) | Ksetfield n -> - if n <= 1 then out env (opSETFIELD0+n) - else (out env opSETFIELD;out_int env n) + out env opSETFIELD; out_int env n | Ksequence _ -> invalid_arg "Vmemitcodes.emit_instr" | Kproj p -> out env opPROJ; out_int env (Projection.Repr.arg p); slot_for_proj_name env p | Kensurestackcapacity size -> out env opENSURESTACKCAPACITY; out_int env size -- cgit v1.2.3 From 5820a964a5b380d82923be7905cdacd6fa6bd6c3 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sun, 27 Dec 2020 14:55:17 +0100 Subject: Remove MAKEPROD. MAKEPROD is just MAKEBLOCK2(0), but one word shorter. Since this opcode is never encountered in the fast path, this optimization is not worth the extra complexity. --- kernel/vmemitcodes.ml | 2 -- 1 file changed, 2 deletions(-) (limited to 'kernel/vmemitcodes.ml') diff --git a/kernel/vmemitcodes.ml b/kernel/vmemitcodes.ml index 85b5ca03e5..d3af8bf09b 100644 --- a/kernel/vmemitcodes.ml +++ b/kernel/vmemitcodes.ml @@ -337,8 +337,6 @@ let emit_instr env = function if Int.equal n 0 then invalid_arg "emit_instr : block size = 0" else if n < 4 then (out env(opMAKEBLOCK1 + n - 1); out_int env t) else (out env opMAKEBLOCK; out_int env n; out_int env t) - | Kmakeprod -> - out env opMAKEPROD | Kmakeswitchblock(typlbl,swlbl,annot,sz) -> out env opMAKESWITCHBLOCK; out_label env typlbl; out_label env swlbl; -- cgit v1.2.3