File 2164-Optimize-testing-for-small-operands.patch of Package erlang
From 512fc927093064e8a75c0a818b11d4ba06f8753d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Thu, 8 Sep 2022 05:53:39 +0200
Subject: [PATCH 4/7] Optimize testing for small operands
---
erts/emulator/beam/jit/x86/instr_arith.cpp | 52 ++++++++++++++--------
1 file changed, 33 insertions(+), 19 deletions(-)
diff --git a/erts/emulator/beam/jit/x86/instr_arith.cpp b/erts/emulator/beam/jit/x86/instr_arith.cpp
index fc29ff844f..bc8c8ea3bb 100644
--- a/erts/emulator/beam/jit/x86/instr_arith.cpp
+++ b/erts/emulator/beam/jit/x86/instr_arith.cpp
@@ -31,6 +31,9 @@ extern "C"
#include "erl_bif_table.h"
}
+/*
+ * Clobbers ARG1.
+ */
void BeamModuleAssembler::emit_is_small(Label fail,
const ArgSource &Arg,
x86::Gp Reg) {
@@ -40,7 +43,7 @@ void BeamModuleAssembler::emit_is_small(Label fail,
comment("skipped test for small operand since it is always small");
} else if (always_one_of(Arg, BEAM_TYPE_FLOAT | BEAM_TYPE_INTEGER)) {
comment("simplified test for small operand since it is a number");
- a.test(Reg.r32(), imm(TAG_PRIMARY_LIST));
+ a.test(Reg.r8(), imm(TAG_PRIMARY_LIST));
a.short_().je(fail);
} else {
comment("is the operand small?");
@@ -51,6 +54,9 @@ void BeamModuleAssembler::emit_is_small(Label fail,
}
}
+/*
+ * Clobbers RET, ARG1.
+ */
void BeamModuleAssembler::emit_are_both_small(Label fail,
const ArgSource &LHS,
x86::Gp A,
@@ -63,9 +69,9 @@ void BeamModuleAssembler::emit_are_both_small(Label fail,
always_one_of(RHS, BEAM_TYPE_FLOAT | BEAM_TYPE_INTEGER)) {
comment("simplified test for small operands since both are numbers");
if (always_small(RHS)) {
- a.test(A.r32(), imm(TAG_PRIMARY_LIST));
+ a.test(A.r8(), imm(TAG_PRIMARY_LIST));
} else if (always_small(LHS)) {
- a.test(B.r32(), imm(TAG_PRIMARY_LIST));
+ a.test(B.r8(), imm(TAG_PRIMARY_LIST));
} else if (A != RET && B != RET) {
a.mov(RETd, A.r32());
a.and_(RETd, B.r32());
@@ -73,9 +79,29 @@ void BeamModuleAssembler::emit_are_both_small(Label fail,
} else {
a.mov(ARG1d, A.r32());
a.and_(ARG1d, B.r32());
- a.test(ARG1d, imm(TAG_PRIMARY_LIST));
+ a.test(ARG1.r8(), imm(TAG_PRIMARY_LIST));
}
a.short_().je(fail);
+ } else if (always_small(LHS)) {
+ if (A == RET || B == RET) {
+ emit_is_small(fail, RHS, B);
+ } else {
+ comment("is the operand small?");
+ a.mov(RETd, B.r32());
+ a.and_(RETb, imm(_TAG_IMMED1_MASK));
+ a.cmp(RETb, imm(_TAG_IMMED1_SMALL));
+ a.short_().jne(fail);
+ }
+ } else if (always_small(RHS)) {
+ if (A == RET || B == RET) {
+ emit_is_small(fail, LHS, A);
+ } else {
+ comment("is the operand small?");
+ a.mov(RETd, A.r32());
+ a.and_(RETb, imm(_TAG_IMMED1_MASK));
+ a.cmp(RETb, imm(_TAG_IMMED1_SMALL));
+ a.short_().jne(fail);
+ }
} else {
comment("are both operands small?");
if (A != RET && B != RET) {
@@ -1064,11 +1090,7 @@ void BeamModuleAssembler::emit_i_band(const ArgSource &LHS,
Label generic = a.newLabel(), next = a.newLabel();
- if (always_small(RHS)) {
- emit_is_small(generic, LHS, ARG2);
- } else {
- emit_are_both_small(generic, LHS, ARG2, RHS, RET);
- }
+ emit_are_both_small(generic, LHS, ARG2, RHS, RET);
/* TAG & TAG = TAG, so we don't need to tag it again. */
a.and_(RET, ARG2);
@@ -1119,11 +1141,7 @@ void BeamModuleAssembler::emit_i_bor(const ArgLabel &Fail,
Label generic = a.newLabel(), next = a.newLabel();
- if (always_small(RHS)) {
- emit_is_small(generic, LHS, ARG2);
- } else {
- emit_are_both_small(generic, LHS, ARG2, RHS, RET);
- }
+ emit_are_both_small(generic, LHS, ARG2, RHS, RET);
/* TAG | TAG = TAG, so we don't need to tag it again. */
a.or_(RET, ARG2);
@@ -1176,11 +1194,7 @@ void BeamModuleAssembler::emit_i_bxor(const ArgLabel &Fail,
Label generic = a.newLabel(), next = a.newLabel();
- if (always_small(RHS)) {
- emit_is_small(generic, LHS, ARG2);
- } else {
- emit_are_both_small(generic, LHS, ARG2, RHS, RET);
- }
+ emit_are_both_small(generic, LHS, ARG2, RHS, RET);
/* TAG ^ TAG = 0, so we need to tag it again. */
a.xor_(RET, ARG2);
--
2.35.3