File 1125-Simplify-updating-a-single-element-of-a-map.patch of Package erlang

From 2b227d7149ab81f90a482853a7842ae8f1cde7ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Mon, 4 Sep 2023 06:14:03 +0200
Subject: [PATCH 05/25] Simplify updating a single element of a map

---
 erts/emulator/beam/jit/arm/beam_asm.hpp       |  30 +++++
 .../beam/jit/arm/beam_asm_global.hpp.pl       |   6 +-
 erts/emulator/beam/jit/arm/instr_map.cpp      | 101 +++++++++++++----
 .../beam/jit/x86/beam_asm_global.hpp.pl       |   2 +
 erts/emulator/beam/jit/x86/instr_map.cpp      | 104 ++++++++++++++----
 5 files changed, 201 insertions(+), 42 deletions(-)

diff --git a/erts/emulator/beam/jit/arm/beam_asm.hpp b/erts/emulator/beam/jit/arm/beam_asm.hpp
index 38f1c6875f..c51edb512f 100644
--- a/erts/emulator/beam/jit/arm/beam_asm.hpp
+++ b/erts/emulator/beam/jit/arm/beam_asm.hpp
@@ -1440,6 +1440,36 @@ protected:
         return Variable<arm::VecD>(tmp);
     }
 
+    void emit_load_args(const ArgSource &Src1,
+                        arm::Gp src1_default,
+                        const ArgSource &Src2,
+                        arm::Gp src2_default,
+                        const ArgSource &Src3,
+                        arm::Gp src3_default) {
+        if (isRegisterBacked(Src1) || !Src1.isRegister()) {
+            auto src1 = load_source(Src1, src1_default);
+            auto [src2, src3] =
+                    load_sources(Src2, src2_default, Src3, src3_default);
+            mov_var(src1_default, src1);
+            mov_var(src2_default, src2);
+            mov_var(src3_default, src3);
+        } else if (isRegisterBacked(Src2) || !Src2.isRegister()) {
+            auto [src1, src3] =
+                    load_sources(Src1, src1_default, Src3, src3_default);
+            auto src2 = load_source(Src2, src2_default);
+            mov_var(src1_default, src1);
+            mov_var(src2_default, src2);
+            mov_var(src3_default, src3);
+        } else {
+            auto [src1, src2] =
+                    load_sources(Src1, src1_default, Src2, src2_default);
+            auto src3 = load_source(Src3, src3_default);
+            mov_var(src1_default, src1);
+            mov_var(src2_default, src2);
+            mov_var(src3_default, src3);
+        }
+    }
+
     template<typename Reg>
     void mov_var(const Variable<Reg> &to, const Variable<Reg> &from) {
         mov_var(to.reg, from);
diff --git a/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl b/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl
index 93b239ddbd..0cb95c5ce3 100644
--- a/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl
+++ b/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl
@@ -103,17 +103,19 @@ my @beam_global_funcs = qw(
     mul_body_shared
     mul_guard_shared
     new_map_shared
-    update_map_assoc_shared
-    unloaded_fun
     plus_body_shared
     process_exit
     process_main
     raise_exception
     raise_exception_shared
     store_unaligned
+    unloaded_fun
     unary_minus_body_shared
+    update_map_assoc_shared
+    update_map_single_assoc_shared
     update_map_exact_guard_shared
     update_map_exact_body_shared
+    update_map_single_exact_body_shared
     );
 
 
diff --git a/erts/emulator/beam/jit/arm/instr_map.cpp b/erts/emulator/beam/jit/arm/instr_map.cpp
index daecdb80ef..129c29d5b2 100644
--- a/erts/emulator/beam/jit/arm/instr_map.cpp
+++ b/erts/emulator/beam/jit/arm/instr_map.cpp
@@ -545,23 +545,44 @@ void BeamGlobalAssembler::emit_update_map_assoc_shared() {
     a.ret(a64::x30);
 }
 
+/* ARG2 = key
+ * ARG3 = value
+ * ARG4 = map
+ */
+void BeamGlobalAssembler::emit_update_map_single_assoc_shared() {
+    emit_enter_runtime_frame();
+    emit_enter_runtime<Update::eHeapAlloc>();
+
+    a.mov(ARG1, c_p);
+    runtime_call<4>(erts_maps_put);
+
+    emit_leave_runtime<Update::eHeapAlloc>();
+    emit_leave_runtime_frame();
+
+    a.ret(a64::x30);
+}
+
 void BeamModuleAssembler::emit_update_map_assoc(const ArgSource &Src,
                                                 const ArgRegister &Dst,
                                                 const ArgWord &Live,
                                                 const ArgWord &Size,
                                                 const Span<ArgVal> &args) {
-    auto src_reg = load_source(Src, TMP1);
-
     ASSERT(Size.get() == args.size());
 
-    embed_vararg_rodata(args, ARG5);
+    if (args.size() == 2) {
+        emit_load_args(args[0], ARG2, args[1], ARG3, Src, ARG4);
+        fragment_call(ga->get_update_map_single_assoc_shared());
+    } else {
+        auto src = load_source(Src, TMP1);
 
-    mov_arg(ArgXRegister(Live.get()), src_reg.reg);
-    mov_arg(ARG3, Live);
-    mov_imm(ARG4, args.size());
+        embed_vararg_rodata(args, ARG5);
 
-    fragment_call(ga->get_update_map_assoc_shared());
+        mov_arg(ArgXRegister(Live.get()), src.reg);
+        mov_arg(ARG3, Live);
+        mov_imm(ARG4, args.size());
 
+        fragment_call(ga->get_update_map_assoc_shared());
+    }
     mov_arg(Dst, ARG1);
 }
 
@@ -612,29 +633,67 @@ void BeamGlobalAssembler::emit_update_map_exact_body_shared() {
     }
 }
 
+/* ARG2 = key
+ * ARG3 = value
+ * ARG4 = map
+ *
+ * Does not return on error. */
+void BeamGlobalAssembler::emit_update_map_single_exact_body_shared() {
+    Label error = a.newLabel();
+
+    a.str(ARG2, TMP_MEM2q);
+
+    emit_enter_runtime_frame();
+    emit_enter_runtime<Update::eHeapAlloc>();
+
+    a.mov(ARG1, c_p);
+    lea(ARG5, TMP_MEM1q);
+    runtime_call<5>(erts_maps_update);
+
+    emit_leave_runtime<Update::eHeapAlloc>();
+    emit_leave_runtime_frame();
+
+    a.cbz(ARG1.w(), error);
+
+    a.ldr(ARG1, TMP_MEM1q);
+    a.ret(a64::x30);
+
+    a.bind(error);
+    {
+        a.ldr(TMP2, TMP_MEM2q);
+        mov_imm(TMP1, BADKEY);
+        ERTS_CT_ASSERT_FIELD_PAIR(Process, freason, fvalue);
+        a.stp(TMP1, TMP2, arm::Mem(c_p, offsetof(Process, freason)));
+        mov_imm(ARG4, 0);
+        a.b(labels[raise_exception]);
+    }
+}
+
 void BeamModuleAssembler::emit_update_map_exact(const ArgSource &Src,
                                                 const ArgLabel &Fail,
                                                 const ArgRegister &Dst,
                                                 const ArgWord &Live,
                                                 const ArgWord &Size,
                                                 const Span<ArgVal> &args) {
-    auto src_reg = load_source(Src, TMP1);
-
     ASSERT(Size.get() == args.size());
 
-    embed_vararg_rodata(args, ARG5);
-
-    /* We _KNOW_ Src is a map */
-
-    mov_arg(ArgXRegister(Live.get()), src_reg.reg);
-    mov_arg(ARG3, Live);
-    mov_imm(ARG4, args.size());
-
-    if (Fail.get() != 0) {
-        fragment_call(ga->get_update_map_exact_guard_shared());
-        emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown));
+    if (args.size() == 2 && Fail.get() == 0) {
+        emit_load_args(args[0], ARG2, args[1], ARG3, Src, ARG4);
+        fragment_call(ga->get_update_map_single_exact_body_shared());
     } else {
-        fragment_call(ga->get_update_map_exact_body_shared());
+        auto src = load_source(Src, ARG4);
+        embed_vararg_rodata(args, ARG5);
+        mov_arg(ArgXRegister(Live.get()), src.reg);
+        mov_arg(ARG3, Live);
+        mov_imm(ARG4, args.size());
+
+        if (Fail.get() != 0) {
+            fragment_call(ga->get_update_map_exact_guard_shared());
+            emit_branch_if_not_value(ARG1,
+                                     resolve_beam_label(Fail, dispUnknown));
+        } else {
+            fragment_call(ga->get_update_map_exact_body_shared());
+        }
     }
 
     mov_arg(Dst, ARG1);
diff --git a/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl b/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl
index 9782bbb226..e6f8a53219 100755
--- a/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl
+++ b/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl
@@ -108,6 +108,8 @@ my @beam_global_funcs = qw(
     update_map_assoc_shared
     update_map_exact_guard_shared
     update_map_exact_body_shared
+    update_map_single_assoc_shared
+    update_map_single_exact_body_shared
     );
 
 # Labels exported from within process_main
diff --git a/erts/emulator/beam/jit/x86/instr_map.cpp b/erts/emulator/beam/jit/x86/instr_map.cpp
index 18eb9eb50a..c386208b63 100644
--- a/erts/emulator/beam/jit/x86/instr_map.cpp
+++ b/erts/emulator/beam/jit/x86/instr_map.cpp
@@ -574,21 +574,45 @@ void BeamGlobalAssembler::emit_update_map_assoc_shared() {
     a.ret();
 }
 
+/* ARG2 = key
+ * ARG3 = value
+ * ARG4 = map
+ */
+void BeamGlobalAssembler::emit_update_map_single_assoc_shared() {
+    emit_enter_frame();
+    emit_enter_runtime<Update::eHeapAlloc>();
+
+    a.mov(ARG1, c_p);
+    runtime_call<4>(erts_maps_put);
+
+    emit_leave_runtime<Update::eHeapAlloc>();
+    emit_leave_frame();
+
+    a.ret();
+}
+
 void BeamModuleAssembler::emit_update_map_assoc(const ArgSource &Src,
                                                 const ArgRegister &Dst,
                                                 const ArgWord &Live,
                                                 const ArgWord &Size,
                                                 const Span<ArgVal> &args) {
-    Label data = embed_vararg_rodata(args, CP_SIZE);
-
     ASSERT(Size.get() == args.size());
 
-    mov_arg(getXRef(Live.get()), Src);
+    if (args.size() == 2) {
+        mov_arg(ARG2, args[0]);
+        mov_arg(ARG3, args[1]);
+        mov_arg(ARG4, Src);
+        safe_fragment_call(ga->get_update_map_single_assoc_shared());
+    } else {
+        Label data = embed_vararg_rodata(args, CP_SIZE);
 
-    mov_imm(ARG3, Live.get());
-    mov_imm(ARG4, args.size());
-    a.lea(ARG5, x86::qword_ptr(data));
-    fragment_call(ga->get_update_map_assoc_shared());
+        mov_arg(getXRef(Live.get()), Src);
+
+        mov_imm(ARG3, Live.get());
+        mov_imm(ARG4, args.size());
+        a.lea(ARG5, x86::qword_ptr(data));
+        fragment_call(ga->get_update_map_assoc_shared());
+    }
 
     mov_arg(Dst, RET);
 }
@@ -639,28 +663,70 @@ void BeamGlobalAssembler::emit_update_map_exact_body_shared() {
     }
 }
 
+/* ARG2 = key
+ * ARG3 = value
+ * ARG4 = map
+ *
+ * Does not return on error. */
+void BeamGlobalAssembler::emit_update_map_single_exact_body_shared() {
+    Label error = a.newLabel();
+
+    a.mov(TMP_MEM2q, ARG2);
+
+    emit_enter_frame();
+    emit_enter_runtime<Update::eHeapAlloc>();
+
+    a.mov(ARG1, c_p);
+    a.lea(ARG5, TMP_MEM1q);
+    runtime_call<5>(erts_maps_update);
+
+    emit_leave_runtime<Update::eHeapAlloc>();
+    emit_leave_frame();
+
+    a.test(RETd, RETd);
+    a.short_().je(error);
+
+    a.mov(RET, TMP_MEM1q);
+    a.ret();
+
+    a.bind(error);
+    {
+        a.mov(RET, TMP_MEM2q);
+        a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), imm(BADKEY));
+        a.mov(x86::qword_ptr(c_p, offsetof(Process, fvalue)), RET);
+        mov_imm(ARG4, 0);
+        a.jmp(labels[raise_exception]);
+    }
+}
+
 void BeamModuleAssembler::emit_update_map_exact(const ArgSource &Src,
                                                 const ArgLabel &Fail,
                                                 const ArgRegister &Dst,
                                                 const ArgWord &Live,
                                                 const ArgWord &Size,
                                                 const Span<ArgVal> &args) {
-    Label data = embed_vararg_rodata(args, CP_SIZE);
-
     ASSERT(Size.get() == args.size());
 
-    /* We _KNOW_ Src is a map */
-    mov_arg(getXRef(Live.get()), Src);
+    if (args.size() == 2 && Fail.get() == 0) {
+        mov_arg(ARG2, args[0]);
+        mov_arg(ARG3, args[1]);
+        mov_arg(ARG4, Src);
+        fragment_call(ga->get_update_map_single_exact_body_shared());
+    } else {
+        Label data = embed_vararg_rodata(args, CP_SIZE);
 
-    mov_imm(ARG3, Live.get());
-    mov_imm(ARG4, args.size());
-    a.lea(ARG5, x86::qword_ptr(data));
+        mov_arg(getXRef(Live.get()), Src);
 
-    if (Fail.get() != 0) {
-        fragment_call(ga->get_update_map_exact_guard_shared());
-        a.je(resolve_beam_label(Fail));
-    } else {
-        fragment_call(ga->get_update_map_exact_body_shared());
+        mov_imm(ARG3, Live.get());
+        mov_imm(ARG4, args.size());
+        a.lea(ARG5, x86::qword_ptr(data));
+
+        if (Fail.get() != 0) {
+            fragment_call(ga->get_update_map_exact_guard_shared());
+            a.je(resolve_beam_label(Fail));
+        } else {
+            fragment_call(ga->get_update_map_exact_body_shared());
+        }
     }
 
     mov_arg(Dst, RET);
-- 
2.35.3

openSUSE Build Service is sponsored by