qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/22] plugins: Rewrite plugin code generation
@ 2024-03-16  1:56 Richard Henderson
  2024-03-16  1:56 ` [PATCH 01/22] tcg: Add TCGContext.emit_before_op Richard Henderson
                   ` (22 more replies)
  0 siblings, 23 replies; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

As I mooted with Pierrick earlier this week:

(1) Add a (trivial) mechanism for emitting code into
the middle of the opcode sequence: tcg_ctx->emit_before_op.

(2) Rip out all of the "empty" generation and "copy"
to modify those sequences.  Replace with regular code
generation once we know what values to place.

There's probably still more cleanup that could be done:

There seems to be a lot of artificial separation between
plugins and the rest of the code base, even between
plugins/api.c and plugins/core.c.

I suspect that all of plugins could be moved into the
build-once buckets.


r~


Richard Henderson (22):
  tcg: Add TCGContext.emit_before_op
  tcg: Make tcg/helper-info.h self-contained
  tcg: Pass function pointer to tcg_gen_call*
  plugins: Zero new qemu_plugin_dyn_cb entries
  plugins: Move function pointer in qemu_plugin_dyn_cb
  plugins: Create TCGHelperInfo for all out-of-line callbacks
  plugins: Use emit_before_op for PLUGIN_GEN_AFTER_INSN
  plugins: Use emit_before_op for PLUGIN_GEN_FROM_TB
  plugins: Add PLUGIN_GEN_AFTER_TB
  plugins: Use emit_before_op for PLUGIN_GEN_FROM_INSN
  plugins: Use emit_before_op for PLUGIN_GEN_FROM_MEM
  plugins: Remove plugin helpers
  tcg: Remove TCG_CALL_PLUGIN
  tcg: Remove INDEX_op_plugin_cb_{start,end}
  plugins: Simplify callback queues
  plugins: Introduce PLUGIN_CB_MEM_REGULAR
  plugins: Replace pr_ops with a proper debug dump flag
  plugins: Split out common cb expanders
  plugins: Merge qemu_plugin_tb_insn_get to plugin-gen.c
  plugins: Move qemu_plugin_insn_cleanup_fn to tcg.c
  plugins: Inline plugin_gen_empty_callback
  plugins: Update the documentation block for plugin-gen.c

 accel/tcg/plugin-helpers.h         |    5 -
 include/exec/helper-gen-common.h   |    4 -
 include/exec/helper-proto-common.h |    4 -
 include/exec/plugin-gen.h          |    4 -
 include/qemu/log.h                 |    1 +
 include/qemu/plugin.h              |   79 +--
 include/tcg/helper-info.h          |    3 +
 include/tcg/tcg-op-common.h        |    4 +-
 include/tcg/tcg-opc.h              |    4 +-
 include/tcg/tcg.h                  |   27 +-
 include/exec/helper-gen.h.inc      |   24 +-
 accel/tcg/plugin-gen.c             | 1008 +++++++---------------------
 plugins/api.c                      |   26 +-
 plugins/core.c                     |   61 +-
 tcg/tcg-op-ldst.c                  |    6 +-
 tcg/tcg-op.c                       |    8 +-
 tcg/tcg.c                          |  104 ++-
 util/log.c                         |    4 +
 18 files changed, 424 insertions(+), 952 deletions(-)
 delete mode 100644 accel/tcg/plugin-helpers.h

-- 
2.34.1



^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH 01/22] tcg: Add TCGContext.emit_before_op
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
@ 2024-03-16  1:56 ` Richard Henderson
  2024-03-19 10:55   ` Pierrick Bouvier
  2024-03-19 14:04   ` Alex Bennée
  2024-03-16  1:57 ` [PATCH 02/22] tcg: Make tcg/helper-info.h self-contained Richard Henderson
                   ` (21 subsequent siblings)
  22 siblings, 2 replies; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

Allow operations to be emitted via normal expanders
into the middle of the opcode stream.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/tcg/tcg.h |  1 +
 tcg/tcg.c         | 14 ++++++++++++--
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index 451f3fec41..e9d05f40b0 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -552,6 +552,7 @@ struct TCGContext {
 
     QTAILQ_HEAD(, TCGOp) ops, free_ops;
     QSIMPLEQ_HEAD(, TCGLabel) labels;
+    TCGOp *emit_before_op;
 
     /* Tells which temporary holds a given register.
        It does not take into account fixed registers */
diff --git a/tcg/tcg.c b/tcg/tcg.c
index d6670237fb..0c0bb9d169 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -1521,6 +1521,7 @@ void tcg_func_start(TCGContext *s)
 
     QTAILQ_INIT(&s->ops);
     QTAILQ_INIT(&s->free_ops);
+    s->emit_before_op = NULL;
     QSIMPLEQ_INIT(&s->labels);
 
     tcg_debug_assert(s->addr_type == TCG_TYPE_I32 ||
@@ -2332,7 +2333,11 @@ static void tcg_gen_callN(TCGHelperInfo *info, TCGTemp *ret, TCGTemp **args)
     op->args[pi++] = (uintptr_t)info;
     tcg_debug_assert(pi == total_args);
 
-    QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
+    if (tcg_ctx->emit_before_op) {
+        QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
+    } else {
+        QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
+    }
 
     tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
     for (i = 0; i < n_extend; ++i) {
@@ -3215,7 +3220,12 @@ static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
 TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
 {
     TCGOp *op = tcg_op_alloc(opc, nargs);
-    QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
+
+    if (tcg_ctx->emit_before_op) {
+        QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
+    } else {
+        QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
+    }
     return op;
 }
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 02/22] tcg: Make tcg/helper-info.h self-contained
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
  2024-03-16  1:56 ` [PATCH 01/22] tcg: Add TCGContext.emit_before_op Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-18 10:01   ` Alex Bennée
  2024-03-18 10:03   ` Alex Bennée
  2024-03-16  1:57 ` [PATCH 03/22] tcg: Pass function pointer to tcg_gen_call* Richard Henderson
                   ` (20 subsequent siblings)
  22 siblings, 2 replies; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

Move MAX_CALL_IARGS from tcg.h and include for
the define of TCG_TARGET_REG_BITS.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/tcg/helper-info.h | 3 +++
 include/tcg/tcg.h         | 2 --
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/include/tcg/helper-info.h b/include/tcg/helper-info.h
index 7c27d6164a..909fe73afa 100644
--- a/include/tcg/helper-info.h
+++ b/include/tcg/helper-info.h
@@ -12,6 +12,9 @@
 #ifdef CONFIG_TCG_INTERPRETER
 #include <ffi.h>
 #endif
+#include "tcg-target-reg-bits.h"
+
+#define MAX_CALL_IARGS  7
 
 /*
  * Describe the calling convention of a given argument type.
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index e9d05f40b0..a6e7df146a 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -39,8 +39,6 @@
 /* XXX: make safe guess about sizes */
 #define MAX_OP_PER_INSTR 266
 
-#define MAX_CALL_IARGS  7
-
 #define CPU_TEMP_BUF_NLONGS 128
 #define TCG_STATIC_FRAME_SIZE  (CPU_TEMP_BUF_NLONGS * sizeof(long))
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 03/22] tcg: Pass function pointer to tcg_gen_call*
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
  2024-03-16  1:56 ` [PATCH 01/22] tcg: Add TCGContext.emit_before_op Richard Henderson
  2024-03-16  1:57 ` [PATCH 02/22] tcg: Make tcg/helper-info.h self-contained Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-18 10:02   ` Alex Bennée
  2024-03-16  1:57 ` [PATCH 04/22] plugins: Zero new qemu_plugin_dyn_cb entries Richard Henderson
                   ` (19 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

For normal helpers, read the function pointer from the
structure earlier.  For plugins, this will allow the
function pointer to come from elsewhere.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/tcg/tcg.h             | 21 +++++++++-------
 include/exec/helper-gen.h.inc | 24 ++++++++++++-------
 tcg/tcg.c                     | 45 +++++++++++++++++++----------------
 3 files changed, 52 insertions(+), 38 deletions(-)

diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index a6e7df146a..95a7f4d010 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -847,19 +847,22 @@ typedef struct TCGTargetOpDef {
 
 bool tcg_op_supported(TCGOpcode op);
 
-void tcg_gen_call0(TCGHelperInfo *, TCGTemp *ret);
-void tcg_gen_call1(TCGHelperInfo *, TCGTemp *ret, TCGTemp *);
-void tcg_gen_call2(TCGHelperInfo *, TCGTemp *ret, TCGTemp *, TCGTemp *);
-void tcg_gen_call3(TCGHelperInfo *, TCGTemp *ret, TCGTemp *,
+void tcg_gen_call0(void *func, TCGHelperInfo *, TCGTemp *ret);
+void tcg_gen_call1(void *func, TCGHelperInfo *, TCGTemp *ret, TCGTemp *);
+void tcg_gen_call2(void *func, TCGHelperInfo *, TCGTemp *ret,
                    TCGTemp *, TCGTemp *);
-void tcg_gen_call4(TCGHelperInfo *, TCGTemp *ret, TCGTemp *, TCGTemp *,
-                   TCGTemp *, TCGTemp *);
-void tcg_gen_call5(TCGHelperInfo *, TCGTemp *ret, TCGTemp *, TCGTemp *,
+void tcg_gen_call3(void *func, TCGHelperInfo *, TCGTemp *ret,
                    TCGTemp *, TCGTemp *, TCGTemp *);
-void tcg_gen_call6(TCGHelperInfo *, TCGTemp *ret, TCGTemp *, TCGTemp *,
+void tcg_gen_call4(void *func, TCGHelperInfo *, TCGTemp *ret,
                    TCGTemp *, TCGTemp *, TCGTemp *, TCGTemp *);
-void tcg_gen_call7(TCGHelperInfo *, TCGTemp *ret, TCGTemp *, TCGTemp *,
+void tcg_gen_call5(void *func, TCGHelperInfo *, TCGTemp *ret,
                    TCGTemp *, TCGTemp *, TCGTemp *, TCGTemp *, TCGTemp *);
+void tcg_gen_call6(void *func, TCGHelperInfo *, TCGTemp *ret,
+                   TCGTemp *, TCGTemp *, TCGTemp *, TCGTemp *,
+                   TCGTemp *, TCGTemp *);
+void tcg_gen_call7(void *func, TCGHelperInfo *, TCGTemp *ret,
+                   TCGTemp *, TCGTemp *, TCGTemp *, TCGTemp *,
+                   TCGTemp *, TCGTemp *, TCGTemp *);
 
 TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs);
 void tcg_op_remove(TCGContext *s, TCGOp *op);
diff --git a/include/exec/helper-gen.h.inc b/include/exec/helper-gen.h.inc
index c009641517..f7eb59b6c1 100644
--- a/include/exec/helper-gen.h.inc
+++ b/include/exec/helper-gen.h.inc
@@ -14,7 +14,8 @@
 extern TCGHelperInfo glue(helper_info_, name);                          \
 static inline void glue(gen_helper_, name)(dh_retvar_decl0(ret))        \
 {                                                                       \
-    tcg_gen_call0(&glue(helper_info_, name), dh_retvar(ret));           \
+    tcg_gen_call0(glue(helper_info_,name).func,                         \
+                  &glue(helper_info_,name), dh_retvar(ret));            \
 }
 
 #define DEF_HELPER_FLAGS_1(name, flags, ret, t1)                        \
@@ -22,7 +23,8 @@ extern TCGHelperInfo glue(helper_info_, name);                          \
 static inline void glue(gen_helper_, name)(dh_retvar_decl(ret)          \
     dh_arg_decl(t1, 1))                                                 \
 {                                                                       \
-    tcg_gen_call1(&glue(helper_info_, name), dh_retvar(ret),            \
+    tcg_gen_call1(glue(helper_info_,name).func,                         \
+                  &glue(helper_info_,name), dh_retvar(ret),             \
                   dh_arg(t1, 1));                                       \
 }
 
@@ -31,7 +33,8 @@ extern TCGHelperInfo glue(helper_info_, name);                          \
 static inline void glue(gen_helper_, name)(dh_retvar_decl(ret)          \
     dh_arg_decl(t1, 1), dh_arg_decl(t2, 2))                             \
 {                                                                       \
-    tcg_gen_call2(&glue(helper_info_, name), dh_retvar(ret),            \
+    tcg_gen_call2(glue(helper_info_,name).func,                         \
+                  &glue(helper_info_,name), dh_retvar(ret),             \
                   dh_arg(t1, 1), dh_arg(t2, 2));                        \
 }
 
@@ -40,7 +43,8 @@ extern TCGHelperInfo glue(helper_info_, name);                          \
 static inline void glue(gen_helper_, name)(dh_retvar_decl(ret)          \
     dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3))         \
 {                                                                       \
-    tcg_gen_call3(&glue(helper_info_, name), dh_retvar(ret),            \
+    tcg_gen_call3(glue(helper_info_,name).func,                         \
+                  &glue(helper_info_,name), dh_retvar(ret),             \
                   dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3));         \
 }
 
@@ -50,7 +54,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret)          \
     dh_arg_decl(t1, 1), dh_arg_decl(t2, 2),                             \
     dh_arg_decl(t3, 3), dh_arg_decl(t4, 4))                             \
 {                                                                       \
-    tcg_gen_call4(&glue(helper_info_, name), dh_retvar(ret),            \
+    tcg_gen_call4(glue(helper_info_,name).func,                         \
+                  &glue(helper_info_,name), dh_retvar(ret),             \
                   dh_arg(t1, 1), dh_arg(t2, 2),                         \
                   dh_arg(t3, 3), dh_arg(t4, 4));                        \
 }
@@ -61,7 +66,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret)          \
     dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3),         \
     dh_arg_decl(t4, 4), dh_arg_decl(t5, 5))                             \
 {                                                                       \
-    tcg_gen_call5(&glue(helper_info_, name), dh_retvar(ret),            \
+    tcg_gen_call5(glue(helper_info_,name).func,                         \
+                  &glue(helper_info_,name), dh_retvar(ret),             \
                   dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3),          \
                   dh_arg(t4, 4), dh_arg(t5, 5));                        \
 }
@@ -72,7 +78,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret)          \
     dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3),         \
     dh_arg_decl(t4, 4), dh_arg_decl(t5, 5), dh_arg_decl(t6, 6))         \
 {                                                                       \
-    tcg_gen_call6(&glue(helper_info_, name), dh_retvar(ret),            \
+    tcg_gen_call6(glue(helper_info_,name).func,                         \
+                  &glue(helper_info_,name), dh_retvar(ret),             \
                   dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3),          \
                   dh_arg(t4, 4), dh_arg(t5, 5), dh_arg(t6, 6));         \
 }
@@ -84,7 +91,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret)          \
     dh_arg_decl(t4, 4), dh_arg_decl(t5, 5), dh_arg_decl(t6, 6),         \
     dh_arg_decl(t7, 7))                                                 \
 {                                                                       \
-    tcg_gen_call7(&glue(helper_info_, name), dh_retvar(ret),            \
+    tcg_gen_call7(glue(helper_info_,name).func,                         \
+                  &glue(helper_info_,name), dh_retvar(ret),             \
                   dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3),          \
                   dh_arg(t4, 4), dh_arg(t5, 5), dh_arg(t6, 6),          \
                   dh_arg(t7, 7));                                       \
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 0c0bb9d169..0bf218314b 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -2251,7 +2251,8 @@ bool tcg_op_supported(TCGOpcode op)
 
 static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);
 
-static void tcg_gen_callN(TCGHelperInfo *info, TCGTemp *ret, TCGTemp **args)
+static void tcg_gen_callN(void *func, TCGHelperInfo *info,
+                          TCGTemp *ret, TCGTemp **args)
 {
     TCGv_i64 extend_free[MAX_CALL_IARGS];
     int n_extend = 0;
@@ -2329,7 +2330,7 @@ static void tcg_gen_callN(TCGHelperInfo *info, TCGTemp *ret, TCGTemp **args)
             g_assert_not_reached();
         }
     }
-    op->args[pi++] = (uintptr_t)info->func;
+    op->args[pi++] = (uintptr_t)func;
     op->args[pi++] = (uintptr_t)info;
     tcg_debug_assert(pi == total_args);
 
@@ -2345,56 +2346,58 @@ static void tcg_gen_callN(TCGHelperInfo *info, TCGTemp *ret, TCGTemp **args)
     }
 }
 
-void tcg_gen_call0(TCGHelperInfo *info, TCGTemp *ret)
+void tcg_gen_call0(void *func, TCGHelperInfo *info, TCGTemp *ret)
 {
-    tcg_gen_callN(info, ret, NULL);
+    tcg_gen_callN(func, info, ret, NULL);
 }
 
-void tcg_gen_call1(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1)
+void tcg_gen_call1(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1)
 {
-    tcg_gen_callN(info, ret, &t1);
+    tcg_gen_callN(func, info, ret, &t1);
 }
 
-void tcg_gen_call2(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, TCGTemp *t2)
+void tcg_gen_call2(void *func, TCGHelperInfo *info, TCGTemp *ret,
+                   TCGTemp *t1, TCGTemp *t2)
 {
     TCGTemp *args[2] = { t1, t2 };
-    tcg_gen_callN(info, ret, args);
+    tcg_gen_callN(func, info, ret, args);
 }
 
-void tcg_gen_call3(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
-                   TCGTemp *t2, TCGTemp *t3)
+void tcg_gen_call3(void *func, TCGHelperInfo *info, TCGTemp *ret,
+                   TCGTemp *t1, TCGTemp *t2, TCGTemp *t3)
 {
     TCGTemp *args[3] = { t1, t2, t3 };
-    tcg_gen_callN(info, ret, args);
+    tcg_gen_callN(func, info, ret, args);
 }
 
-void tcg_gen_call4(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
-                   TCGTemp *t2, TCGTemp *t3, TCGTemp *t4)
+void tcg_gen_call4(void *func, TCGHelperInfo *info, TCGTemp *ret,
+                   TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, TCGTemp *t4)
 {
     TCGTemp *args[4] = { t1, t2, t3, t4 };
-    tcg_gen_callN(info, ret, args);
+    tcg_gen_callN(func, info, ret, args);
 }
 
-void tcg_gen_call5(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
+void tcg_gen_call5(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
                    TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, TCGTemp *t5)
 {
     TCGTemp *args[5] = { t1, t2, t3, t4, t5 };
-    tcg_gen_callN(info, ret, args);
+    tcg_gen_callN(func, info, ret, args);
 }
 
-void tcg_gen_call6(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, TCGTemp *t2,
-                   TCGTemp *t3, TCGTemp *t4, TCGTemp *t5, TCGTemp *t6)
+void tcg_gen_call6(void *func, TCGHelperInfo *info, TCGTemp *ret,
+                   TCGTemp *t1, TCGTemp *t2, TCGTemp *t3,
+                   TCGTemp *t4, TCGTemp *t5, TCGTemp *t6)
 {
     TCGTemp *args[6] = { t1, t2, t3, t4, t5, t6 };
-    tcg_gen_callN(info, ret, args);
+    tcg_gen_callN(func, info, ret, args);
 }
 
-void tcg_gen_call7(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
+void tcg_gen_call7(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
                    TCGTemp *t2, TCGTemp *t3, TCGTemp *t4,
                    TCGTemp *t5, TCGTemp *t6, TCGTemp *t7)
 {
     TCGTemp *args[7] = { t1, t2, t3, t4, t5, t6, t7 };
-    tcg_gen_callN(info, ret, args);
+    tcg_gen_callN(func, info, ret, args);
 }
 
 static void tcg_reg_alloc_start(TCGContext *s)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 04/22] plugins: Zero new qemu_plugin_dyn_cb entries
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (2 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 03/22] tcg: Pass function pointer to tcg_gen_call* Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-18 10:03   ` Alex Bennée
  2024-03-16  1:57 ` [PATCH 05/22] plugins: Move function pointer in qemu_plugin_dyn_cb Richard Henderson
                   ` (18 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 plugins/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/plugins/core.c b/plugins/core.c
index 11ca20e626..4487cb7c48 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -307,7 +307,7 @@ static struct qemu_plugin_dyn_cb *plugin_get_dyn_cb(GArray **arr)
     GArray *cbs = *arr;
 
     if (!cbs) {
-        cbs = g_array_sized_new(false, false,
+        cbs = g_array_sized_new(false, true,
                                 sizeof(struct qemu_plugin_dyn_cb), 1);
         *arr = cbs;
     }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 05/22] plugins: Move function pointer in qemu_plugin_dyn_cb
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (3 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 04/22] plugins: Zero new qemu_plugin_dyn_cb entries Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-18 10:04   ` Alex Bennée
  2024-03-19 13:18   ` Pierrick Bouvier
  2024-03-16  1:57 ` [PATCH 06/22] plugins: Create TCGHelperInfo for all out-of-line callbacks Richard Henderson
                   ` (17 subsequent siblings)
  22 siblings, 2 replies; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

The out-of-line function pointer is mutually exclusive
with inline expansion, so move it into the union.
Wrap the pointer in a structure named 'regular' to match
PLUGIN_CB_REGULAR.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/qemu/plugin.h  | 4 +++-
 accel/tcg/plugin-gen.c | 4 ++--
 plugins/core.c         | 8 ++++----
 3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index 12a96cea2a..143262dca8 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -84,13 +84,15 @@ enum plugin_dyn_cb_subtype {
  * instance of a callback to be called upon the execution of a particular TB.
  */
 struct qemu_plugin_dyn_cb {
-    union qemu_plugin_cb_sig f;
     void *userp;
     enum plugin_dyn_cb_subtype type;
     /* @rw applies to mem callbacks only (both regular and inline) */
     enum qemu_plugin_mem_rw rw;
     /* fields specific to each dyn_cb type go here */
     union {
+        struct {
+            union qemu_plugin_cb_sig f;
+        } regular;
         struct {
             qemu_plugin_u64 entry;
             enum qemu_plugin_op op;
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index 8028786c7b..c56f104aee 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -431,7 +431,7 @@ static TCGOp *append_udata_cb(const struct qemu_plugin_dyn_cb *cb,
     }
 
     /* call */
-    op = copy_call(&begin_op, op, cb->f.vcpu_udata, cb_idx);
+    op = copy_call(&begin_op, op, cb->regular.f.vcpu_udata, cb_idx);
 
     return op;
 }
@@ -479,7 +479,7 @@ static TCGOp *append_mem_cb(const struct qemu_plugin_dyn_cb *cb,
 
     if (type == PLUGIN_GEN_CB_MEM) {
         /* call */
-        op = copy_call(&begin_op, op, cb->f.vcpu_udata, cb_idx);
+        op = copy_call(&begin_op, op, cb->regular.f.vcpu_udata, cb_idx);
     }
 
     return op;
diff --git a/plugins/core.c b/plugins/core.c
index 4487cb7c48..837c373690 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -342,7 +342,7 @@ void plugin_register_dyn_cb__udata(GArray **arr,
 
     dyn_cb->userp = udata;
     /* Note flags are discarded as unused. */
-    dyn_cb->f.vcpu_udata = cb;
+    dyn_cb->regular.f.vcpu_udata = cb;
     dyn_cb->type = PLUGIN_CB_REGULAR;
 }
 
@@ -359,7 +359,7 @@ void plugin_register_vcpu_mem_cb(GArray **arr,
     /* Note flags are discarded as unused. */
     dyn_cb->type = PLUGIN_CB_REGULAR;
     dyn_cb->rw = rw;
-    dyn_cb->f.generic = cb;
+    dyn_cb->regular.f.vcpu_mem = cb;
 }
 
 /*
@@ -511,8 +511,8 @@ void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
         }
         switch (cb->type) {
         case PLUGIN_CB_REGULAR:
-            cb->f.vcpu_mem(cpu->cpu_index, make_plugin_meminfo(oi, rw),
-                           vaddr, cb->userp);
+            cb->regular.f.vcpu_mem(cpu->cpu_index, make_plugin_meminfo(oi, rw),
+                                   vaddr, cb->userp);
             break;
         case PLUGIN_CB_INLINE:
             exec_inline_op(cb, cpu->cpu_index);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 06/22] plugins: Create TCGHelperInfo for all out-of-line callbacks
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (4 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 05/22] plugins: Move function pointer in qemu_plugin_dyn_cb Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-19 13:12   ` Pierrick Bouvier
  2024-03-16  1:57 ` [PATCH 07/22] plugins: Use emit_before_op for PLUGIN_GEN_AFTER_INSN Richard Henderson
                   ` (16 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

TCGHelperInfo includes the ABI for every function call.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/qemu/plugin.h |  1 +
 plugins/core.c        | 51 ++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 46 insertions(+), 6 deletions(-)

diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index 143262dca8..793c44f1f2 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -92,6 +92,7 @@ struct qemu_plugin_dyn_cb {
     union {
         struct {
             union qemu_plugin_cb_sig f;
+            TCGHelperInfo *info;
         } regular;
         struct {
             qemu_plugin_u64 entry;
diff --git a/plugins/core.c b/plugins/core.c
index 837c373690..b0a2e80874 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -338,12 +338,26 @@ void plugin_register_dyn_cb__udata(GArray **arr,
                                    enum qemu_plugin_cb_flags flags,
                                    void *udata)
 {
-    struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
+    static TCGHelperInfo info[3] = {
+        [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG | TCG_CALL_PLUGIN,
+        [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG | TCG_CALL_PLUGIN,
+        [QEMU_PLUGIN_CB_RW_REGS].flags = TCG_CALL_PLUGIN,
+        /*
+         * Match qemu_plugin_vcpu_udata_cb_t:
+         *   void (*)(uint32_t, void *)
+         */
+        [0 ... 2].typemask = (dh_typemask(void, 0) |
+                              dh_typemask(i32, 1) |
+                              dh_typemask(ptr, 2))
+    };
 
+    struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
     dyn_cb->userp = udata;
-    /* Note flags are discarded as unused. */
-    dyn_cb->regular.f.vcpu_udata = cb;
     dyn_cb->type = PLUGIN_CB_REGULAR;
+    dyn_cb->regular.f.vcpu_udata = cb;
+
+    assert((unsigned)flags < ARRAY_SIZE(info));
+    dyn_cb->regular.info = &info[flags];
 }
 
 void plugin_register_vcpu_mem_cb(GArray **arr,
@@ -352,14 +366,39 @@ void plugin_register_vcpu_mem_cb(GArray **arr,
                                  enum qemu_plugin_mem_rw rw,
                                  void *udata)
 {
-    struct qemu_plugin_dyn_cb *dyn_cb;
+    /*
+     * Expect that the underlying type for enum qemu_plugin_meminfo_t
+     * is either int32_t or uint32_t, aka int or unsigned int.
+     */
+    QEMU_BUILD_BUG_ON(
+        !__builtin_types_compatible_p(qemu_plugin_meminfo_t, uint32_t) &&
+        !__builtin_types_compatible_p(qemu_plugin_meminfo_t, int32_t));
 
-    dyn_cb = plugin_get_dyn_cb(arr);
+    static TCGHelperInfo info[3] = {
+        [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG | TCG_CALL_PLUGIN,
+        [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG | TCG_CALL_PLUGIN,
+        [QEMU_PLUGIN_CB_RW_REGS].flags = TCG_CALL_PLUGIN,
+        /*
+         * Match qemu_plugin_vcpu_mem_cb_t:
+         *   void (*)(uint32_t, qemu_plugin_meminfo_t, uint64_t, void *)
+         */
+        [0 ... 2].typemask =
+            (dh_typemask(void, 0) |
+             dh_typemask(i32, 1) |
+             (__builtin_types_compatible_p(qemu_plugin_meminfo_t, uint32_t)
+              ? dh_typemask(i32, 2) : dh_typemask(s32, 2)) |
+             dh_typemask(i64, 3) |
+             dh_typemask(ptr, 4))
+    };
+
+    struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
     dyn_cb->userp = udata;
-    /* Note flags are discarded as unused. */
     dyn_cb->type = PLUGIN_CB_REGULAR;
     dyn_cb->rw = rw;
     dyn_cb->regular.f.vcpu_mem = cb;
+
+    assert((unsigned)flags < ARRAY_SIZE(info));
+    dyn_cb->regular.info = &info[flags];
 }
 
 /*
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 07/22] plugins: Use emit_before_op for PLUGIN_GEN_AFTER_INSN
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (5 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 06/22] plugins: Create TCGHelperInfo for all out-of-line callbacks Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-19 13:32   ` Pierrick Bouvier
  2024-03-16  1:57 ` [PATCH 08/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_TB Richard Henderson
                   ` (15 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

Introduce a new plugin_cb op and migrate one operation.
By using emit_before_op, we do not need to emit opcodes
early and modify them later -- we can simply emit the
final set of opcodes once.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/tcg/tcg-op-common.h |  1 +
 include/tcg/tcg-opc.h       |  1 +
 accel/tcg/plugin-gen.c      | 74 +++++++++++++++++++++----------------
 tcg/tcg-op.c                |  5 +++
 4 files changed, 50 insertions(+), 31 deletions(-)

diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h
index 2d932a515e..9de5a7f280 100644
--- a/include/tcg/tcg-op-common.h
+++ b/include/tcg/tcg-op-common.h
@@ -74,6 +74,7 @@ void tcg_gen_goto_tb(unsigned idx);
  */
 void tcg_gen_lookup_and_goto_ptr(void);
 
+void tcg_gen_plugin_cb(unsigned from);
 void tcg_gen_plugin_cb_start(unsigned from, unsigned type, unsigned wr);
 void tcg_gen_plugin_cb_end(void);
 
diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h
index b80227fa1c..3b7cb2bce1 100644
--- a/include/tcg/tcg-opc.h
+++ b/include/tcg/tcg-opc.h
@@ -197,6 +197,7 @@ DEF(exit_tb, 0, 0, 1, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
 DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
 DEF(goto_ptr, 0, 1, 0, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
 
+DEF(plugin_cb, 0, 0, 1, TCG_OPF_NOT_PRESENT)
 DEF(plugin_cb_start, 0, 0, 3, TCG_OPF_NOT_PRESENT)
 DEF(plugin_cb_end, 0, 0, 0, TCG_OPF_NOT_PRESENT)
 
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index c56f104aee..8fa342b425 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -207,8 +207,7 @@ static void plugin_gen_empty_callback(enum plugin_gen_from from)
 {
     switch (from) {
     case PLUGIN_GEN_AFTER_INSN:
-        gen_wrapped(from, PLUGIN_GEN_DISABLE_MEM_HELPER,
-                    gen_empty_mem_helper);
+        tcg_gen_plugin_cb(from);
         break;
     case PLUGIN_GEN_FROM_INSN:
         /*
@@ -614,16 +613,6 @@ static void inject_mem_enable_helper(struct qemu_plugin_tb *ptb,
     inject_mem_helper(begin_op, arr);
 }
 
-static void inject_mem_disable_helper(struct qemu_plugin_insn *plugin_insn,
-                                      TCGOp *begin_op)
-{
-    if (likely(!plugin_insn->mem_helper)) {
-        rm_ops(begin_op);
-        return;
-    }
-    inject_mem_helper(begin_op, NULL);
-}
-
 /* called before finishing a TB with exit_tb, goto_tb or goto_ptr */
 void plugin_gen_disable_mem_helpers(void)
 {
@@ -709,11 +698,14 @@ static void plugin_gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
     inject_mem_enable_helper(ptb, insn, begin_op);
 }
 
-static void plugin_gen_disable_mem_helper(struct qemu_plugin_tb *ptb,
-                                          TCGOp *begin_op, int insn_idx)
+static void gen_disable_mem_helper(struct qemu_plugin_tb *ptb,
+                                   struct qemu_plugin_insn *insn)
 {
-    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
-    inject_mem_disable_helper(insn, begin_op);
+    if (insn->mem_helper) {
+        tcg_gen_st_ptr(tcg_constant_ptr(0), tcg_env,
+                       offsetof(CPUState, plugin_mem_cbs) -
+                       offsetof(ArchCPU, env));
+    }
 }
 
 /* #define DEBUG_PLUGIN_GEN_OPS */
@@ -772,16 +764,49 @@ static void pr_ops(void)
 
 static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
 {
-    TCGOp *op;
+    TCGOp *op, *next;
     int insn_idx = -1;
 
     pr_ops();
 
-    QTAILQ_FOREACH(op, &tcg_ctx->ops, link) {
+    /*
+     * While injecting code, we cannot afford to reuse any ebb temps
+     * that might be live within the existing opcode stream.
+     * The simplest solution is to release them all and create new.
+     */
+    memset(tcg_ctx->free_temps, 0, sizeof(tcg_ctx->free_temps));
+
+    QTAILQ_FOREACH_SAFE(op, &tcg_ctx->ops, link, next) {
         switch (op->opc) {
         case INDEX_op_insn_start:
             insn_idx++;
             break;
+
+        case INDEX_op_plugin_cb:
+        {
+            enum plugin_gen_from from = op->args[0];
+            struct qemu_plugin_insn *insn = NULL;
+
+            if (insn_idx >= 0) {
+                insn = g_ptr_array_index(plugin_tb->insns, insn_idx);
+            }
+
+            tcg_ctx->emit_before_op = op;
+
+            switch (from) {
+            case PLUGIN_GEN_AFTER_INSN:
+                assert(insn != NULL);
+                gen_disable_mem_helper(plugin_tb, insn);
+                break;
+            default:
+                g_assert_not_reached();
+            }
+
+            tcg_ctx->emit_before_op = NULL;
+            tcg_op_remove(tcg_ctx, op);
+            break;
+        }
+
         case INDEX_op_plugin_cb_start:
         {
             enum plugin_gen_from from = op->args[0];
@@ -846,19 +871,6 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
 
                 break;
             }
-            case PLUGIN_GEN_AFTER_INSN:
-            {
-                g_assert(insn_idx >= 0);
-
-                switch (type) {
-                case PLUGIN_GEN_DISABLE_MEM_HELPER:
-                    plugin_gen_disable_mem_helper(plugin_tb, op, insn_idx);
-                    break;
-                default:
-                    g_assert_not_reached();
-                }
-                break;
-            }
             default:
                 g_assert_not_reached();
             }
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index aa6bc6f57d..0f2026c91c 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -312,6 +312,11 @@ void tcg_gen_mb(TCGBar mb_type)
     }
 }
 
+void tcg_gen_plugin_cb(unsigned from)
+{
+    tcg_gen_op1(INDEX_op_plugin_cb, from);
+}
+
 void tcg_gen_plugin_cb_start(unsigned from, unsigned type, unsigned wr)
 {
     tcg_gen_op3(INDEX_op_plugin_cb_start, from, type, wr);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 08/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_TB
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (6 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 07/22] plugins: Use emit_before_op for PLUGIN_GEN_AFTER_INSN Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-19 13:22   ` Pierrick Bouvier
  2024-03-16  1:57 ` [PATCH 09/22] plugins: Add PLUGIN_GEN_AFTER_TB Richard Henderson
                   ` (14 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

By having the qemu_plugin_cb_flags be recorded in the TCGHelperInfo,
we no longer need to distinguish PLUGIN_CB_REGULAR from
PLUGIN_CB_REGULAR_R, so place all TB callbacks in the same queue.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 accel/tcg/plugin-gen.c | 96 +++++++++++++++++++++++++-----------------
 plugins/api.c          |  6 +--
 2 files changed, 58 insertions(+), 44 deletions(-)

diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index 8fa342b425..f92aa80510 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -207,6 +207,7 @@ static void plugin_gen_empty_callback(enum plugin_gen_from from)
 {
     switch (from) {
     case PLUGIN_GEN_AFTER_INSN:
+    case PLUGIN_GEN_FROM_TB:
         tcg_gen_plugin_cb(from);
         break;
     case PLUGIN_GEN_FROM_INSN:
@@ -216,8 +217,6 @@ static void plugin_gen_empty_callback(enum plugin_gen_from from)
          */
         gen_wrapped(from, PLUGIN_GEN_ENABLE_MEM_HELPER,
                     gen_empty_mem_helper);
-        /* fall through */
-    case PLUGIN_GEN_FROM_TB:
         gen_wrapped(from, PLUGIN_GEN_CB_UDATA, gen_empty_udata_cb_no_rwg);
         gen_wrapped(from, PLUGIN_GEN_CB_UDATA_R, gen_empty_udata_cb_no_wg);
         gen_wrapped(from, PLUGIN_GEN_CB_INLINE, gen_empty_inline_cb);
@@ -632,24 +631,6 @@ void plugin_gen_disable_mem_helpers(void)
                    offsetof(CPUState, plugin_mem_cbs) - offsetof(ArchCPU, env));
 }
 
-static void plugin_gen_tb_udata(const struct qemu_plugin_tb *ptb,
-                                TCGOp *begin_op)
-{
-    inject_udata_cb(ptb->cbs[PLUGIN_CB_REGULAR], begin_op);
-}
-
-static void plugin_gen_tb_udata_r(const struct qemu_plugin_tb *ptb,
-                                  TCGOp *begin_op)
-{
-    inject_udata_cb(ptb->cbs[PLUGIN_CB_REGULAR_R], begin_op);
-}
-
-static void plugin_gen_tb_inline(const struct qemu_plugin_tb *ptb,
-                                 TCGOp *begin_op)
-{
-    inject_inline_cb(ptb->cbs[PLUGIN_CB_INLINE], begin_op, op_ok);
-}
-
 static void plugin_gen_insn_udata(const struct qemu_plugin_tb *ptb,
                                   TCGOp *begin_op, int insn_idx)
 {
@@ -708,6 +689,41 @@ static void gen_disable_mem_helper(struct qemu_plugin_tb *ptb,
     }
 }
 
+static void gen_udata_cb(struct qemu_plugin_dyn_cb *cb)
+{
+    TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
+
+    tcg_gen_ld_i32(cpu_index, tcg_env,
+                   -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
+    tcg_gen_call2(cb->regular.f.vcpu_udata, cb->regular.info, NULL,
+                  tcgv_i32_temp(cpu_index),
+                  tcgv_ptr_temp(tcg_constant_ptr(cb->userp)));
+    tcg_temp_free_i32(cpu_index);
+}
+
+static void gen_inline_cb(struct qemu_plugin_dyn_cb *cb)
+{
+    GArray *arr = cb->inline_insn.entry.score->data;
+    size_t offset = cb->inline_insn.entry.offset;
+    TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
+    TCGv_i64 val = tcg_temp_ebb_new_i64();
+    TCGv_ptr ptr = tcg_temp_ebb_new_ptr();
+
+    tcg_gen_ld_i32(cpu_index, tcg_env,
+                   -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
+    tcg_gen_muli_i32(cpu_index, cpu_index, g_array_get_element_size(arr));
+    tcg_gen_ext_i32_ptr(ptr, cpu_index);
+    tcg_temp_free_i32(cpu_index);
+
+    tcg_gen_addi_ptr(ptr, ptr, (intptr_t)arr->data);
+    tcg_gen_ld_i64(val, ptr, offset);
+    tcg_gen_addi_i64(val, val, cb->inline_insn.imm);
+    tcg_gen_st_i64(val, ptr, offset);
+
+    tcg_temp_free_i64(val);
+    tcg_temp_free_ptr(ptr);
+}
+
 /* #define DEBUG_PLUGIN_GEN_OPS */
 static void pr_ops(void)
 {
@@ -786,6 +802,8 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
         {
             enum plugin_gen_from from = op->args[0];
             struct qemu_plugin_insn *insn = NULL;
+            const GArray *cbs;
+            int i, n;
 
             if (insn_idx >= 0) {
                 insn = g_ptr_array_index(plugin_tb->insns, insn_idx);
@@ -798,6 +816,25 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
                 assert(insn != NULL);
                 gen_disable_mem_helper(plugin_tb, insn);
                 break;
+
+            case PLUGIN_GEN_FROM_TB:
+                assert(insn == NULL);
+
+                cbs = plugin_tb->cbs[PLUGIN_CB_REGULAR];
+                for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
+                    struct qemu_plugin_dyn_cb *cb =
+                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
+                    gen_udata_cb(cb);
+                }
+
+                cbs = plugin_tb->cbs[PLUGIN_CB_INLINE];
+                for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
+                    struct qemu_plugin_dyn_cb *cb =
+                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
+                    gen_inline_cb(cb);
+                }
+                break;
+
             default:
                 g_assert_not_reached();
             }
@@ -813,25 +850,6 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
             enum plugin_gen_cb type = op->args[1];
 
             switch (from) {
-            case PLUGIN_GEN_FROM_TB:
-            {
-                g_assert(insn_idx == -1);
-
-                switch (type) {
-                case PLUGIN_GEN_CB_UDATA:
-                    plugin_gen_tb_udata(plugin_tb, op);
-                    break;
-                case PLUGIN_GEN_CB_UDATA_R:
-                    plugin_gen_tb_udata_r(plugin_tb, op);
-                    break;
-                case PLUGIN_GEN_CB_INLINE:
-                    plugin_gen_tb_inline(plugin_tb, op);
-                    break;
-                default:
-                    g_assert_not_reached();
-                }
-                break;
-            }
             case PLUGIN_GEN_FROM_INSN:
             {
                 g_assert(insn_idx >= 0);
diff --git a/plugins/api.c b/plugins/api.c
index 8fa5a600ac..5d119e8049 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -92,11 +92,7 @@ void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
                                           void *udata)
 {
     if (!tb->mem_only) {
-        int index = flags == QEMU_PLUGIN_CB_R_REGS ||
-                    flags == QEMU_PLUGIN_CB_RW_REGS ?
-                    PLUGIN_CB_REGULAR_R : PLUGIN_CB_REGULAR;
-
-        plugin_register_dyn_cb__udata(&tb->cbs[index],
+        plugin_register_dyn_cb__udata(&tb->cbs[PLUGIN_CB_REGULAR],
                                       cb, flags, udata);
     }
 }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 09/22] plugins: Add PLUGIN_GEN_AFTER_TB
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (7 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 08/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_TB Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-19 13:33   ` Pierrick Bouvier
  2024-03-16  1:57 ` [PATCH 10/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_INSN Richard Henderson
                   ` (13 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

Delay test of plugin_tb->mem_helper until the inject pass.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 accel/tcg/plugin-gen.c | 37 ++++++++++++++++---------------------
 1 file changed, 16 insertions(+), 21 deletions(-)

diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index f92aa80510..aa74e580bd 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -75,6 +75,7 @@ enum plugin_gen_from {
     PLUGIN_GEN_FROM_INSN,
     PLUGIN_GEN_FROM_MEM,
     PLUGIN_GEN_AFTER_INSN,
+    PLUGIN_GEN_AFTER_TB,
     PLUGIN_GEN_N_FROMS,
 };
 
@@ -615,20 +616,9 @@ static void inject_mem_enable_helper(struct qemu_plugin_tb *ptb,
 /* called before finishing a TB with exit_tb, goto_tb or goto_ptr */
 void plugin_gen_disable_mem_helpers(void)
 {
-    /*
-     * We could emit the clearing unconditionally and be done. However, this can
-     * be wasteful if for instance plugins don't track memory accesses, or if
-     * most TBs don't use helpers. Instead, emit the clearing iff the TB calls
-     * helpers that might access guest memory.
-     *
-     * Note: we do not reset plugin_tb->mem_helper here; a TB might have several
-     * exit points, and we want to emit the clearing from all of them.
-     */
-    if (!tcg_ctx->plugin_tb->mem_helper) {
-        return;
+    if (tcg_ctx->plugin_insn) {
+        tcg_gen_plugin_cb(PLUGIN_GEN_AFTER_TB);
     }
-    tcg_gen_st_ptr(tcg_constant_ptr(NULL), tcg_env,
-                   offsetof(CPUState, plugin_mem_cbs) - offsetof(ArchCPU, env));
 }
 
 static void plugin_gen_insn_udata(const struct qemu_plugin_tb *ptb,
@@ -679,14 +669,11 @@ static void plugin_gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
     inject_mem_enable_helper(ptb, insn, begin_op);
 }
 
-static void gen_disable_mem_helper(struct qemu_plugin_tb *ptb,
-                                   struct qemu_plugin_insn *insn)
+static void gen_disable_mem_helper(void)
 {
-    if (insn->mem_helper) {
-        tcg_gen_st_ptr(tcg_constant_ptr(0), tcg_env,
-                       offsetof(CPUState, plugin_mem_cbs) -
-                       offsetof(ArchCPU, env));
-    }
+    tcg_gen_st_ptr(tcg_constant_ptr(0), tcg_env,
+                   offsetof(CPUState, plugin_mem_cbs) -
+                   offsetof(ArchCPU, env));
 }
 
 static void gen_udata_cb(struct qemu_plugin_dyn_cb *cb)
@@ -812,9 +799,17 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
             tcg_ctx->emit_before_op = op;
 
             switch (from) {
+            case PLUGIN_GEN_AFTER_TB:
+                if (plugin_tb->mem_helper) {
+                    gen_disable_mem_helper();
+                }
+                break;
+
             case PLUGIN_GEN_AFTER_INSN:
                 assert(insn != NULL);
-                gen_disable_mem_helper(plugin_tb, insn);
+                if (insn->mem_helper) {
+                    gen_disable_mem_helper();
+                }
                 break;
 
             case PLUGIN_GEN_FROM_TB:
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 10/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_INSN
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (8 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 09/22] plugins: Add PLUGIN_GEN_AFTER_TB Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-19 13:34   ` Pierrick Bouvier
  2024-03-16  1:57 ` [PATCH 11/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_MEM Richard Henderson
                   ` (12 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/qemu/plugin.h  |   1 -
 accel/tcg/plugin-gen.c | 286 ++++++++++-------------------------------
 plugins/api.c          |   8 +-
 3 files changed, 67 insertions(+), 228 deletions(-)

diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index 793c44f1f2..ee1c1b174a 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -73,7 +73,6 @@ enum plugin_dyn_cb_type {
 
 enum plugin_dyn_cb_subtype {
     PLUGIN_CB_REGULAR,
-    PLUGIN_CB_REGULAR_R,
     PLUGIN_CB_INLINE,
     PLUGIN_N_CB_SUBTYPES,
 };
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index aa74e580bd..4785838eca 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -104,30 +104,6 @@ void HELPER(plugin_vcpu_mem_cb)(unsigned int vcpu_index,
                                 void *userdata)
 { }
 
-static void gen_empty_udata_cb(void (*gen_helper)(TCGv_i32, TCGv_ptr))
-{
-    TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
-    TCGv_ptr udata = tcg_temp_ebb_new_ptr();
-
-    tcg_gen_movi_ptr(udata, 0);
-    tcg_gen_ld_i32(cpu_index, tcg_env,
-                   -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
-    gen_helper(cpu_index, udata);
-
-    tcg_temp_free_ptr(udata);
-    tcg_temp_free_i32(cpu_index);
-}
-
-static void gen_empty_udata_cb_no_wg(void)
-{
-    gen_empty_udata_cb(gen_helper_plugin_vcpu_udata_cb_no_wg);
-}
-
-static void gen_empty_udata_cb_no_rwg(void)
-{
-    gen_empty_udata_cb(gen_helper_plugin_vcpu_udata_cb_no_rwg);
-}
-
 /*
  * For now we only support addi_i64.
  * When we support more ops, we can generate one empty inline cb for each.
@@ -176,51 +152,19 @@ static void gen_empty_mem_cb(TCGv_i64 addr, uint32_t info)
     tcg_temp_free_i32(cpu_index);
 }
 
-/*
- * Share the same function for enable/disable. When enabling, the NULL
- * pointer will be overwritten later.
- */
-static void gen_empty_mem_helper(void)
-{
-    TCGv_ptr ptr = tcg_temp_ebb_new_ptr();
-
-    tcg_gen_movi_ptr(ptr, 0);
-    tcg_gen_st_ptr(ptr, tcg_env, offsetof(CPUState, plugin_mem_cbs) -
-                                 offsetof(ArchCPU, env));
-    tcg_temp_free_ptr(ptr);
-}
-
 static void gen_plugin_cb_start(enum plugin_gen_from from,
                                 enum plugin_gen_cb type, unsigned wr)
 {
     tcg_gen_plugin_cb_start(from, type, wr);
 }
 
-static void gen_wrapped(enum plugin_gen_from from,
-                        enum plugin_gen_cb type, void (*func)(void))
-{
-    gen_plugin_cb_start(from, type, 0);
-    func();
-    tcg_gen_plugin_cb_end();
-}
-
 static void plugin_gen_empty_callback(enum plugin_gen_from from)
 {
     switch (from) {
     case PLUGIN_GEN_AFTER_INSN:
     case PLUGIN_GEN_FROM_TB:
-        tcg_gen_plugin_cb(from);
-        break;
     case PLUGIN_GEN_FROM_INSN:
-        /*
-         * Note: plugin_gen_inject() relies on ENABLE_MEM_HELPER being
-         * the first callback of an instruction
-         */
-        gen_wrapped(from, PLUGIN_GEN_ENABLE_MEM_HELPER,
-                    gen_empty_mem_helper);
-        gen_wrapped(from, PLUGIN_GEN_CB_UDATA, gen_empty_udata_cb_no_rwg);
-        gen_wrapped(from, PLUGIN_GEN_CB_UDATA_R, gen_empty_udata_cb_no_wg);
-        gen_wrapped(from, PLUGIN_GEN_CB_INLINE, gen_empty_inline_cb);
+        tcg_gen_plugin_cb(from);
         break;
     default:
         g_assert_not_reached();
@@ -374,18 +318,6 @@ static TCGOp *copy_mul_i32(TCGOp **begin_op, TCGOp *op, uint32_t v)
     return op;
 }
 
-static TCGOp *copy_st_ptr(TCGOp **begin_op, TCGOp *op)
-{
-    if (UINTPTR_MAX == UINT32_MAX) {
-        /* st_i32 */
-        op = copy_op(begin_op, op, INDEX_op_st_i32);
-    } else {
-        /* st_i64 */
-        op = copy_st_i64(begin_op, op);
-    }
-    return op;
-}
-
 static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *func, int *cb_idx)
 {
     TCGOp *old_op;
@@ -409,32 +341,6 @@ static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *func, int *cb_idx)
     return op;
 }
 
-/*
- * When we append/replace ops here we are sensitive to changing patterns of
- * TCGOps generated by the tcg_gen_FOO calls when we generated the
- * empty callbacks. This will assert very quickly in a debug build as
- * we assert the ops we are replacing are the correct ones.
- */
-static TCGOp *append_udata_cb(const struct qemu_plugin_dyn_cb *cb,
-                              TCGOp *begin_op, TCGOp *op, int *cb_idx)
-{
-    /* const_ptr */
-    op = copy_const_ptr(&begin_op, op, cb->userp);
-
-    /* copy the ld_i32, but note that we only have to copy it once */
-    if (*cb_idx == -1) {
-        op = copy_op(&begin_op, op, INDEX_op_ld_i32);
-    } else {
-        begin_op = QTAILQ_NEXT(begin_op, link);
-        tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32);
-    }
-
-    /* call */
-    op = copy_call(&begin_op, op, cb->regular.f.vcpu_udata, cb_idx);
-
-    return op;
-}
-
 static TCGOp *append_inline_cb(const struct qemu_plugin_dyn_cb *cb,
                                TCGOp *begin_op, TCGOp *op,
                                int *unused)
@@ -488,11 +394,6 @@ typedef TCGOp *(*inject_fn)(const struct qemu_plugin_dyn_cb *cb,
                             TCGOp *begin_op, TCGOp *op, int *intp);
 typedef bool (*op_ok_fn)(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb);
 
-static bool op_ok(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb)
-{
-    return true;
-}
-
 static bool op_rw(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb)
 {
     int w;
@@ -530,12 +431,6 @@ static void inject_cb_type(const GArray *cbs, TCGOp *begin_op,
     rm_ops_range(begin_op, end_op);
 }
 
-static void
-inject_udata_cb(const GArray *cbs, TCGOp *begin_op)
-{
-    inject_cb_type(cbs, begin_op, append_udata_cb, op_ok);
-}
-
 static void
 inject_inline_cb(const GArray *cbs, TCGOp *begin_op, op_ok_fn ok)
 {
@@ -548,71 +443,6 @@ inject_mem_cb(const GArray *cbs, TCGOp *begin_op)
     inject_cb_type(cbs, begin_op, append_mem_cb, op_rw);
 }
 
-/* we could change the ops in place, but we can reuse more code by copying */
-static void inject_mem_helper(TCGOp *begin_op, GArray *arr)
-{
-    TCGOp *orig_op = begin_op;
-    TCGOp *end_op;
-    TCGOp *op;
-
-    end_op = find_op(begin_op, INDEX_op_plugin_cb_end);
-    tcg_debug_assert(end_op);
-
-    /* const ptr */
-    op = copy_const_ptr(&begin_op, end_op, arr);
-
-    /* st_ptr */
-    op = copy_st_ptr(&begin_op, op);
-
-    rm_ops_range(orig_op, end_op);
-}
-
-/*
- * Tracking memory accesses performed from helpers requires extra work.
- * If an instruction is emulated with helpers, we do two things:
- * (1) copy the CB descriptors, and keep track of it so that they can be
- * freed later on, and (2) point CPUState.plugin_mem_cbs to the descriptors, so
- * that we can read them at run-time (i.e. when the helper executes).
- * This run-time access is performed from qemu_plugin_vcpu_mem_cb.
- *
- * Note that plugin_gen_disable_mem_helpers undoes (2). Since it
- * is possible that the code we generate after the instruction is
- * dead, we also add checks before generating tb_exit etc.
- */
-static void inject_mem_enable_helper(struct qemu_plugin_tb *ptb,
-                                     struct qemu_plugin_insn *plugin_insn,
-                                     TCGOp *begin_op)
-{
-    GArray *cbs[2];
-    GArray *arr;
-    size_t n_cbs, i;
-
-    cbs[0] = plugin_insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR];
-    cbs[1] = plugin_insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
-
-    n_cbs = 0;
-    for (i = 0; i < ARRAY_SIZE(cbs); i++) {
-        n_cbs += cbs[i]->len;
-    }
-
-    plugin_insn->mem_helper = plugin_insn->calls_helpers && n_cbs;
-    if (likely(!plugin_insn->mem_helper)) {
-        rm_ops(begin_op);
-        return;
-    }
-    ptb->mem_helper = true;
-
-    arr = g_array_sized_new(false, false,
-                            sizeof(struct qemu_plugin_dyn_cb), n_cbs);
-
-    for (i = 0; i < ARRAY_SIZE(cbs); i++) {
-        g_array_append_vals(arr, cbs[i]->data, cbs[i]->len);
-    }
-
-    qemu_plugin_add_dyn_cb_arr(arr);
-    inject_mem_helper(begin_op, arr);
-}
-
 /* called before finishing a TB with exit_tb, goto_tb or goto_ptr */
 void plugin_gen_disable_mem_helpers(void)
 {
@@ -621,30 +451,6 @@ void plugin_gen_disable_mem_helpers(void)
     }
 }
 
-static void plugin_gen_insn_udata(const struct qemu_plugin_tb *ptb,
-                                  TCGOp *begin_op, int insn_idx)
-{
-    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
-
-    inject_udata_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR], begin_op);
-}
-
-static void plugin_gen_insn_udata_r(const struct qemu_plugin_tb *ptb,
-                                    TCGOp *begin_op, int insn_idx)
-{
-    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
-
-    inject_udata_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR_R], begin_op);
-}
-
-static void plugin_gen_insn_inline(const struct qemu_plugin_tb *ptb,
-                                   TCGOp *begin_op, int insn_idx)
-{
-    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
-    inject_inline_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE],
-                     begin_op, op_ok);
-}
-
 static void plugin_gen_mem_regular(const struct qemu_plugin_tb *ptb,
                                    TCGOp *begin_op, int insn_idx)
 {
@@ -662,11 +468,51 @@ static void plugin_gen_mem_inline(const struct qemu_plugin_tb *ptb,
     inject_inline_cb(cbs, begin_op, op_rw);
 }
 
-static void plugin_gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
-                                         TCGOp *begin_op, int insn_idx)
+static void gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
+                                  struct qemu_plugin_insn *insn)
 {
-    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
-    inject_mem_enable_helper(ptb, insn, begin_op);
+    GArray *cbs[2];
+    GArray *arr;
+    size_t n_cbs;
+
+    /*
+     * Tracking memory accesses performed from helpers requires extra work.
+     * If an instruction is emulated with helpers, we do two things:
+     * (1) copy the CB descriptors, and keep track of it so that they can be
+     * freed later on, and (2) point CPUState.plugin_mem_cbs to the
+     * descriptors, so that we can read them at run-time
+     * (i.e. when the helper executes).
+     * This run-time access is performed from qemu_plugin_vcpu_mem_cb.
+     *
+     * Note that plugin_gen_disable_mem_helpers undoes (2). Since it
+     * is possible that the code we generate after the instruction is
+     * dead, we also add checks before generating tb_exit etc.
+     */
+    if (!insn->calls_helpers) {
+        return;
+    }
+
+    cbs[0] = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR];
+    cbs[1] = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
+    n_cbs = cbs[0]->len + cbs[1]->len;
+
+    if (n_cbs == 0) {
+        insn->mem_helper = false;
+        return;
+    }
+    insn->mem_helper = true;
+    ptb->mem_helper = true;
+
+    arr = g_array_sized_new(false, false,
+                            sizeof(struct qemu_plugin_dyn_cb), n_cbs);
+    g_array_append_vals(arr, cbs[0]->data, cbs[0]->len);
+    g_array_append_vals(arr, cbs[1]->data, cbs[1]->len);
+
+    qemu_plugin_add_dyn_cb_arr(arr);
+
+    tcg_gen_st_ptr(tcg_constant_ptr((intptr_t)arr), tcg_env,
+                   offsetof(CPUState, plugin_mem_cbs) -
+                   offsetof(ArchCPU, env));
 }
 
 static void gen_disable_mem_helper(void)
@@ -830,6 +676,26 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
                 }
                 break;
 
+            case PLUGIN_GEN_FROM_INSN:
+                assert(insn != NULL);
+
+                gen_enable_mem_helper(plugin_tb, insn);
+
+                cbs = insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR];
+                for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
+                    struct qemu_plugin_dyn_cb *cb =
+                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
+                    gen_udata_cb(cb);
+                }
+
+                cbs = insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE];
+                for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
+                    struct qemu_plugin_dyn_cb *cb =
+                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
+                    gen_inline_cb(cb);
+                }
+                break;
+
             default:
                 g_assert_not_reached();
             }
@@ -845,28 +711,6 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
             enum plugin_gen_cb type = op->args[1];
 
             switch (from) {
-            case PLUGIN_GEN_FROM_INSN:
-            {
-                g_assert(insn_idx >= 0);
-
-                switch (type) {
-                case PLUGIN_GEN_CB_UDATA:
-                    plugin_gen_insn_udata(plugin_tb, op, insn_idx);
-                    break;
-                case PLUGIN_GEN_CB_UDATA_R:
-                    plugin_gen_insn_udata_r(plugin_tb, op, insn_idx);
-                    break;
-                case PLUGIN_GEN_CB_INLINE:
-                    plugin_gen_insn_inline(plugin_tb, op, insn_idx);
-                    break;
-                case PLUGIN_GEN_ENABLE_MEM_HELPER:
-                    plugin_gen_enable_mem_helper(plugin_tb, op, insn_idx);
-                    break;
-                default:
-                    g_assert_not_reached();
-                }
-                break;
-            }
             case PLUGIN_GEN_FROM_MEM:
             {
                 g_assert(insn_idx >= 0);
diff --git a/plugins/api.c b/plugins/api.c
index 5d119e8049..29cce2d97c 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -115,12 +115,8 @@ void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
                                             void *udata)
 {
     if (!insn->mem_only) {
-        int index = flags == QEMU_PLUGIN_CB_R_REGS ||
-                    flags == QEMU_PLUGIN_CB_RW_REGS ?
-                    PLUGIN_CB_REGULAR_R : PLUGIN_CB_REGULAR;
-
-        plugin_register_dyn_cb__udata(&insn->cbs[PLUGIN_CB_INSN][index],
-                                      cb, flags, udata);
+        plugin_register_dyn_cb__udata(
+            &insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR], cb, flags, udata);
     }
 }
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 11/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_MEM
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (9 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 10/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_INSN Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-19 13:35   ` Pierrick Bouvier
  2024-03-16  1:57 ` [PATCH 12/22] plugins: Remove plugin helpers Richard Henderson
                   ` (11 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

Introduce a new plugin_mem_cb op to hold the address temp
and meminfo computed by tcg-op-ldst.c.  Because this now
has its own opcode, we no longer need PLUGIN_GEN_FROM_MEM.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/exec/plugin-gen.h   |   4 -
 include/tcg/tcg-op-common.h |   1 +
 include/tcg/tcg-opc.h       |   1 +
 accel/tcg/plugin-gen.c      | 408 ++++--------------------------------
 tcg/tcg-op-ldst.c           |   6 +-
 tcg/tcg-op.c                |   5 +
 6 files changed, 54 insertions(+), 371 deletions(-)

diff --git a/include/exec/plugin-gen.h b/include/exec/plugin-gen.h
index c4552b5061..f333f33198 100644
--- a/include/exec/plugin-gen.h
+++ b/include/exec/plugin-gen.h
@@ -25,7 +25,6 @@ void plugin_gen_insn_start(CPUState *cpu, const struct DisasContextBase *db);
 void plugin_gen_insn_end(void);
 
 void plugin_gen_disable_mem_helpers(void);
-void plugin_gen_empty_mem_callback(TCGv_i64 addr, uint32_t info);
 
 #else /* !CONFIG_PLUGIN */
 
@@ -48,9 +47,6 @@ static inline void plugin_gen_tb_end(CPUState *cpu, size_t num_insns)
 static inline void plugin_gen_disable_mem_helpers(void)
 { }
 
-static inline void plugin_gen_empty_mem_callback(TCGv_i64 addr, uint32_t info)
-{ }
-
 #endif /* CONFIG_PLUGIN */
 
 #endif /* QEMU_PLUGIN_GEN_H */
diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h
index 9de5a7f280..72b80b20d0 100644
--- a/include/tcg/tcg-op-common.h
+++ b/include/tcg/tcg-op-common.h
@@ -75,6 +75,7 @@ void tcg_gen_goto_tb(unsigned idx);
 void tcg_gen_lookup_and_goto_ptr(void);
 
 void tcg_gen_plugin_cb(unsigned from);
+void tcg_gen_plugin_mem_cb(TCGv_i64 addr, unsigned meminfo);
 void tcg_gen_plugin_cb_start(unsigned from, unsigned type, unsigned wr);
 void tcg_gen_plugin_cb_end(void);
 
diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h
index 3b7cb2bce1..be9e36e386 100644
--- a/include/tcg/tcg-opc.h
+++ b/include/tcg/tcg-opc.h
@@ -198,6 +198,7 @@ DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
 DEF(goto_ptr, 0, 1, 0, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
 
 DEF(plugin_cb, 0, 0, 1, TCG_OPF_NOT_PRESENT)
+DEF(plugin_mem_cb, 0, 1, 1, TCG_OPF_NOT_PRESENT)
 DEF(plugin_cb_start, 0, 0, 3, TCG_OPF_NOT_PRESENT)
 DEF(plugin_cb_end, 0, 0, 0, TCG_OPF_NOT_PRESENT)
 
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index 4785838eca..be7fd548cc 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -73,7 +73,6 @@
 enum plugin_gen_from {
     PLUGIN_GEN_FROM_TB,
     PLUGIN_GEN_FROM_INSN,
-    PLUGIN_GEN_FROM_MEM,
     PLUGIN_GEN_AFTER_INSN,
     PLUGIN_GEN_AFTER_TB,
     PLUGIN_GEN_N_FROMS,
@@ -104,60 +103,6 @@ void HELPER(plugin_vcpu_mem_cb)(unsigned int vcpu_index,
                                 void *userdata)
 { }
 
-/*
- * For now we only support addi_i64.
- * When we support more ops, we can generate one empty inline cb for each.
- */
-static void gen_empty_inline_cb(void)
-{
-    TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
-    TCGv_ptr cpu_index_as_ptr = tcg_temp_ebb_new_ptr();
-    TCGv_i64 val = tcg_temp_ebb_new_i64();
-    TCGv_ptr ptr = tcg_temp_ebb_new_ptr();
-
-    tcg_gen_ld_i32(cpu_index, tcg_env,
-                   -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
-    /* second operand will be replaced by immediate value */
-    tcg_gen_mul_i32(cpu_index, cpu_index, cpu_index);
-    tcg_gen_ext_i32_ptr(cpu_index_as_ptr, cpu_index);
-
-    tcg_gen_movi_ptr(ptr, 0);
-    tcg_gen_add_ptr(ptr, ptr, cpu_index_as_ptr);
-    tcg_gen_ld_i64(val, ptr, 0);
-    /* second operand will be replaced by immediate value */
-    tcg_gen_add_i64(val, val, val);
-
-    tcg_gen_st_i64(val, ptr, 0);
-    tcg_temp_free_ptr(ptr);
-    tcg_temp_free_i64(val);
-    tcg_temp_free_ptr(cpu_index_as_ptr);
-    tcg_temp_free_i32(cpu_index);
-}
-
-static void gen_empty_mem_cb(TCGv_i64 addr, uint32_t info)
-{
-    TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
-    TCGv_i32 meminfo = tcg_temp_ebb_new_i32();
-    TCGv_ptr udata = tcg_temp_ebb_new_ptr();
-
-    tcg_gen_movi_i32(meminfo, info);
-    tcg_gen_movi_ptr(udata, 0);
-    tcg_gen_ld_i32(cpu_index, tcg_env,
-                   -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
-
-    gen_helper_plugin_vcpu_mem_cb(cpu_index, meminfo, addr, udata);
-
-    tcg_temp_free_ptr(udata);
-    tcg_temp_free_i32(meminfo);
-    tcg_temp_free_i32(cpu_index);
-}
-
-static void gen_plugin_cb_start(enum plugin_gen_from from,
-                                enum plugin_gen_cb type, unsigned wr)
-{
-    tcg_gen_plugin_cb_start(from, type, wr);
-}
-
 static void plugin_gen_empty_callback(enum plugin_gen_from from)
 {
     switch (from) {
@@ -171,278 +116,6 @@ static void plugin_gen_empty_callback(enum plugin_gen_from from)
     }
 }
 
-void plugin_gen_empty_mem_callback(TCGv_i64 addr, uint32_t info)
-{
-    enum qemu_plugin_mem_rw rw = get_plugin_meminfo_rw(info);
-
-    gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, PLUGIN_GEN_CB_MEM, rw);
-    gen_empty_mem_cb(addr, info);
-    tcg_gen_plugin_cb_end();
-
-    gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, PLUGIN_GEN_CB_INLINE, rw);
-    gen_empty_inline_cb();
-    tcg_gen_plugin_cb_end();
-}
-
-static TCGOp *find_op(TCGOp *op, TCGOpcode opc)
-{
-    while (op) {
-        if (op->opc == opc) {
-            return op;
-        }
-        op = QTAILQ_NEXT(op, link);
-    }
-    return NULL;
-}
-
-static TCGOp *rm_ops_range(TCGOp *begin, TCGOp *end)
-{
-    TCGOp *ret = QTAILQ_NEXT(end, link);
-
-    QTAILQ_REMOVE_SEVERAL(&tcg_ctx->ops, begin, end, link);
-    return ret;
-}
-
-/* remove all ops until (and including) plugin_cb_end */
-static TCGOp *rm_ops(TCGOp *op)
-{
-    TCGOp *end_op = find_op(op, INDEX_op_plugin_cb_end);
-
-    tcg_debug_assert(end_op);
-    return rm_ops_range(op, end_op);
-}
-
-static TCGOp *copy_op_nocheck(TCGOp **begin_op, TCGOp *op)
-{
-    TCGOp *old_op = QTAILQ_NEXT(*begin_op, link);
-    unsigned nargs = old_op->nargs;
-
-    *begin_op = old_op;
-    op = tcg_op_insert_after(tcg_ctx, op, old_op->opc, nargs);
-    memcpy(op->args, old_op->args, sizeof(op->args[0]) * nargs);
-
-    return op;
-}
-
-static TCGOp *copy_op(TCGOp **begin_op, TCGOp *op, TCGOpcode opc)
-{
-    op = copy_op_nocheck(begin_op, op);
-    tcg_debug_assert((*begin_op)->opc == opc);
-    return op;
-}
-
-static TCGOp *copy_const_ptr(TCGOp **begin_op, TCGOp *op, void *ptr)
-{
-    if (UINTPTR_MAX == UINT32_MAX) {
-        /* mov_i32 */
-        op = copy_op(begin_op, op, INDEX_op_mov_i32);
-        op->args[1] = tcgv_i32_arg(tcg_constant_i32((uintptr_t)ptr));
-    } else {
-        /* mov_i64 */
-        op = copy_op(begin_op, op, INDEX_op_mov_i64);
-        op->args[1] = tcgv_i64_arg(tcg_constant_i64((uintptr_t)ptr));
-    }
-    return op;
-}
-
-static TCGOp *copy_ld_i32(TCGOp **begin_op, TCGOp *op)
-{
-    return copy_op(begin_op, op, INDEX_op_ld_i32);
-}
-
-static TCGOp *copy_ext_i32_ptr(TCGOp **begin_op, TCGOp *op)
-{
-    if (UINTPTR_MAX == UINT32_MAX) {
-        op = copy_op(begin_op, op, INDEX_op_mov_i32);
-    } else {
-        op = copy_op(begin_op, op, INDEX_op_ext_i32_i64);
-    }
-    return op;
-}
-
-static TCGOp *copy_add_ptr(TCGOp **begin_op, TCGOp *op)
-{
-    if (UINTPTR_MAX == UINT32_MAX) {
-        op = copy_op(begin_op, op, INDEX_op_add_i32);
-    } else {
-        op = copy_op(begin_op, op, INDEX_op_add_i64);
-    }
-    return op;
-}
-
-static TCGOp *copy_ld_i64(TCGOp **begin_op, TCGOp *op)
-{
-    if (TCG_TARGET_REG_BITS == 32) {
-        /* 2x ld_i32 */
-        op = copy_ld_i32(begin_op, op);
-        op = copy_ld_i32(begin_op, op);
-    } else {
-        /* ld_i64 */
-        op = copy_op(begin_op, op, INDEX_op_ld_i64);
-    }
-    return op;
-}
-
-static TCGOp *copy_st_i64(TCGOp **begin_op, TCGOp *op)
-{
-    if (TCG_TARGET_REG_BITS == 32) {
-        /* 2x st_i32 */
-        op = copy_op(begin_op, op, INDEX_op_st_i32);
-        op = copy_op(begin_op, op, INDEX_op_st_i32);
-    } else {
-        /* st_i64 */
-        op = copy_op(begin_op, op, INDEX_op_st_i64);
-    }
-    return op;
-}
-
-static TCGOp *copy_add_i64(TCGOp **begin_op, TCGOp *op, uint64_t v)
-{
-    if (TCG_TARGET_REG_BITS == 32) {
-        /* all 32-bit backends must implement add2_i32 */
-        g_assert(TCG_TARGET_HAS_add2_i32);
-        op = copy_op(begin_op, op, INDEX_op_add2_i32);
-        op->args[4] = tcgv_i32_arg(tcg_constant_i32(v));
-        op->args[5] = tcgv_i32_arg(tcg_constant_i32(v >> 32));
-    } else {
-        op = copy_op(begin_op, op, INDEX_op_add_i64);
-        op->args[2] = tcgv_i64_arg(tcg_constant_i64(v));
-    }
-    return op;
-}
-
-static TCGOp *copy_mul_i32(TCGOp **begin_op, TCGOp *op, uint32_t v)
-{
-    op = copy_op(begin_op, op, INDEX_op_mul_i32);
-    op->args[2] = tcgv_i32_arg(tcg_constant_i32(v));
-    return op;
-}
-
-static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *func, int *cb_idx)
-{
-    TCGOp *old_op;
-    int func_idx;
-
-    /* copy all ops until the call */
-    do {
-        op = copy_op_nocheck(begin_op, op);
-    } while (op->opc != INDEX_op_call);
-
-    /* fill in the op call */
-    old_op = *begin_op;
-    TCGOP_CALLI(op) = TCGOP_CALLI(old_op);
-    TCGOP_CALLO(op) = TCGOP_CALLO(old_op);
-    tcg_debug_assert(op->life == 0);
-
-    func_idx = TCGOP_CALLO(op) + TCGOP_CALLI(op);
-    *cb_idx = func_idx;
-    op->args[func_idx] = (uintptr_t)func;
-
-    return op;
-}
-
-static TCGOp *append_inline_cb(const struct qemu_plugin_dyn_cb *cb,
-                               TCGOp *begin_op, TCGOp *op,
-                               int *unused)
-{
-    char *ptr = cb->inline_insn.entry.score->data->data;
-    size_t elem_size = g_array_get_element_size(
-        cb->inline_insn.entry.score->data);
-    size_t offset = cb->inline_insn.entry.offset;
-
-    op = copy_ld_i32(&begin_op, op);
-    op = copy_mul_i32(&begin_op, op, elem_size);
-    op = copy_ext_i32_ptr(&begin_op, op);
-    op = copy_const_ptr(&begin_op, op, ptr + offset);
-    op = copy_add_ptr(&begin_op, op);
-    op = copy_ld_i64(&begin_op, op);
-    op = copy_add_i64(&begin_op, op, cb->inline_insn.imm);
-    op = copy_st_i64(&begin_op, op);
-    return op;
-}
-
-static TCGOp *append_mem_cb(const struct qemu_plugin_dyn_cb *cb,
-                            TCGOp *begin_op, TCGOp *op, int *cb_idx)
-{
-    enum plugin_gen_cb type = begin_op->args[1];
-
-    tcg_debug_assert(type == PLUGIN_GEN_CB_MEM);
-
-    /* const_i32 == mov_i32 ("info", so it remains as is) */
-    op = copy_op(&begin_op, op, INDEX_op_mov_i32);
-
-    /* const_ptr */
-    op = copy_const_ptr(&begin_op, op, cb->userp);
-
-    /* copy the ld_i32, but note that we only have to copy it once */
-    if (*cb_idx == -1) {
-        op = copy_op(&begin_op, op, INDEX_op_ld_i32);
-    } else {
-        begin_op = QTAILQ_NEXT(begin_op, link);
-        tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32);
-    }
-
-    if (type == PLUGIN_GEN_CB_MEM) {
-        /* call */
-        op = copy_call(&begin_op, op, cb->regular.f.vcpu_udata, cb_idx);
-    }
-
-    return op;
-}
-
-typedef TCGOp *(*inject_fn)(const struct qemu_plugin_dyn_cb *cb,
-                            TCGOp *begin_op, TCGOp *op, int *intp);
-typedef bool (*op_ok_fn)(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb);
-
-static bool op_rw(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb)
-{
-    int w;
-
-    w = op->args[2];
-    return !!(cb->rw & (w + 1));
-}
-
-static void inject_cb_type(const GArray *cbs, TCGOp *begin_op,
-                           inject_fn inject, op_ok_fn ok)
-{
-    TCGOp *end_op;
-    TCGOp *op;
-    int cb_idx = -1;
-    int i;
-
-    if (!cbs || cbs->len == 0) {
-        rm_ops(begin_op);
-        return;
-    }
-
-    end_op = find_op(begin_op, INDEX_op_plugin_cb_end);
-    tcg_debug_assert(end_op);
-
-    op = end_op;
-    for (i = 0; i < cbs->len; i++) {
-        struct qemu_plugin_dyn_cb *cb =
-            &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
-
-        if (!ok(begin_op, cb)) {
-            continue;
-        }
-        op = inject(cb, begin_op, op, &cb_idx);
-    }
-    rm_ops_range(begin_op, end_op);
-}
-
-static void
-inject_inline_cb(const GArray *cbs, TCGOp *begin_op, op_ok_fn ok)
-{
-    inject_cb_type(cbs, begin_op, append_inline_cb, ok);
-}
-
-static void
-inject_mem_cb(const GArray *cbs, TCGOp *begin_op)
-{
-    inject_cb_type(cbs, begin_op, append_mem_cb, op_rw);
-}
-
 /* called before finishing a TB with exit_tb, goto_tb or goto_ptr */
 void plugin_gen_disable_mem_helpers(void)
 {
@@ -451,23 +124,6 @@ void plugin_gen_disable_mem_helpers(void)
     }
 }
 
-static void plugin_gen_mem_regular(const struct qemu_plugin_tb *ptb,
-                                   TCGOp *begin_op, int insn_idx)
-{
-    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
-    inject_mem_cb(insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR], begin_op);
-}
-
-static void plugin_gen_mem_inline(const struct qemu_plugin_tb *ptb,
-                                  TCGOp *begin_op, int insn_idx)
-{
-    const GArray *cbs;
-    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
-
-    cbs = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
-    inject_inline_cb(cbs, begin_op, op_rw);
-}
-
 static void gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
                                   struct qemu_plugin_insn *insn)
 {
@@ -557,6 +213,21 @@ static void gen_inline_cb(struct qemu_plugin_dyn_cb *cb)
     tcg_temp_free_ptr(ptr);
 }
 
+static void gen_mem_cb(struct qemu_plugin_dyn_cb *cb,
+                       qemu_plugin_meminfo_t meminfo, TCGv_i64 addr)
+{
+    TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
+
+    tcg_gen_ld_i32(cpu_index, tcg_env,
+                   -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
+    tcg_gen_call4(cb->regular.f.vcpu_mem, cb->regular.info, NULL,
+                  tcgv_i32_temp(cpu_index),
+                  tcgv_i32_temp(tcg_constant_i32(meminfo)),
+                  tcgv_i64_temp(addr),
+                  tcgv_ptr_temp(tcg_constant_ptr(cb->userp)));
+    tcg_temp_free_i32(cpu_index);
+}
+
 /* #define DEBUG_PLUGIN_GEN_OPS */
 static void pr_ops(void)
 {
@@ -705,34 +376,43 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
             break;
         }
 
-        case INDEX_op_plugin_cb_start:
+        case INDEX_op_plugin_mem_cb:
         {
-            enum plugin_gen_from from = op->args[0];
-            enum plugin_gen_cb type = op->args[1];
+            TCGv_i64 addr = temp_tcgv_i64(arg_temp(op->args[0]));
+            qemu_plugin_meminfo_t meminfo = op->args[1];
+            struct qemu_plugin_insn *insn;
+            const GArray *cbs;
+            int i, n, rw;
 
-            switch (from) {
-            case PLUGIN_GEN_FROM_MEM:
-            {
-                g_assert(insn_idx >= 0);
+            assert(insn_idx >= 0);
+            insn = g_ptr_array_index(plugin_tb->insns, insn_idx);
+            rw = qemu_plugin_mem_is_store(meminfo) ? 2 : 1;
 
-                switch (type) {
-                case PLUGIN_GEN_CB_MEM:
-                    plugin_gen_mem_regular(plugin_tb, op, insn_idx);
-                    break;
-                case PLUGIN_GEN_CB_INLINE:
-                    plugin_gen_mem_inline(plugin_tb, op, insn_idx);
-                    break;
-                default:
-                    g_assert_not_reached();
+            tcg_ctx->emit_before_op = op;
+
+            cbs = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR];
+            for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
+                struct qemu_plugin_dyn_cb *cb =
+                    &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
+                if (cb->rw & rw) {
+                    gen_mem_cb(cb, meminfo, addr);
                 }
+            }
 
-                break;
-            }
-            default:
-                g_assert_not_reached();
+            cbs = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
+            for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
+                struct qemu_plugin_dyn_cb *cb =
+                    &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
+                if (cb->rw & rw) {
+                    gen_inline_cb(cb);
+                }
             }
+
+            tcg_ctx->emit_before_op = NULL;
+            tcg_op_remove(tcg_ctx, op);
             break;
         }
+
         default:
             /* plugins don't care about any other ops */
             break;
diff --git a/tcg/tcg-op-ldst.c b/tcg/tcg-op-ldst.c
index f11043b449..8510160258 100644
--- a/tcg/tcg-op-ldst.c
+++ b/tcg/tcg-op-ldst.c
@@ -161,14 +161,14 @@ plugin_gen_mem_callbacks(TCGv_i64 copy_addr, TCGTemp *orig_addr, MemOpIdx oi,
                 copy_addr = tcg_temp_ebb_new_i64();
                 tcg_gen_extu_i32_i64(copy_addr, temp_tcgv_i32(orig_addr));
             }
-            plugin_gen_empty_mem_callback(copy_addr, info);
+            tcg_gen_plugin_mem_cb(copy_addr, info);
             tcg_temp_free_i64(copy_addr);
         } else {
             if (copy_addr) {
-                plugin_gen_empty_mem_callback(copy_addr, info);
+                tcg_gen_plugin_mem_cb(copy_addr, info);
                 tcg_temp_free_i64(copy_addr);
             } else {
-                plugin_gen_empty_mem_callback(temp_tcgv_i64(orig_addr), info);
+                tcg_gen_plugin_mem_cb(temp_tcgv_i64(orig_addr), info);
             }
         }
     }
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index 0f2026c91c..0ae12fa49d 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -317,6 +317,11 @@ void tcg_gen_plugin_cb(unsigned from)
     tcg_gen_op1(INDEX_op_plugin_cb, from);
 }
 
+void tcg_gen_plugin_mem_cb(TCGv_i64 addr, unsigned meminfo)
+{
+    tcg_gen_op2(INDEX_op_plugin_mem_cb, tcgv_i64_arg(addr), meminfo);
+}
+
 void tcg_gen_plugin_cb_start(unsigned from, unsigned type, unsigned wr)
 {
     tcg_gen_op3(INDEX_op_plugin_cb_start, from, type, wr);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 12/22] plugins: Remove plugin helpers
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (10 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 11/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_MEM Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-18 16:38   ` Alex Bennée
  2024-03-16  1:57 ` [PATCH 13/22] tcg: Remove TCG_CALL_PLUGIN Richard Henderson
                   ` (10 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

These placeholder helpers are no longer required.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 accel/tcg/plugin-helpers.h         |  5 -----
 include/exec/helper-gen-common.h   |  4 ----
 include/exec/helper-proto-common.h |  4 ----
 accel/tcg/plugin-gen.c             | 20 --------------------
 4 files changed, 33 deletions(-)
 delete mode 100644 accel/tcg/plugin-helpers.h

diff --git a/accel/tcg/plugin-helpers.h b/accel/tcg/plugin-helpers.h
deleted file mode 100644
index 11796436f3..0000000000
--- a/accel/tcg/plugin-helpers.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef CONFIG_PLUGIN
-DEF_HELPER_FLAGS_2(plugin_vcpu_udata_cb_no_wg, TCG_CALL_NO_WG | TCG_CALL_PLUGIN, void, i32, ptr)
-DEF_HELPER_FLAGS_2(plugin_vcpu_udata_cb_no_rwg, TCG_CALL_NO_RWG | TCG_CALL_PLUGIN, void, i32, ptr)
-DEF_HELPER_FLAGS_4(plugin_vcpu_mem_cb, TCG_CALL_NO_RWG | TCG_CALL_PLUGIN, void, i32, i32, i64, ptr)
-#endif
diff --git a/include/exec/helper-gen-common.h b/include/exec/helper-gen-common.h
index 5d6d78a625..834590dc4e 100644
--- a/include/exec/helper-gen-common.h
+++ b/include/exec/helper-gen-common.h
@@ -11,8 +11,4 @@
 #include "exec/helper-gen.h.inc"
 #undef  HELPER_H
 
-#define HELPER_H "accel/tcg/plugin-helpers.h"
-#include "exec/helper-gen.h.inc"
-#undef  HELPER_H
-
 #endif /* HELPER_GEN_COMMON_H */
diff --git a/include/exec/helper-proto-common.h b/include/exec/helper-proto-common.h
index 8b67170a22..16782ef46c 100644
--- a/include/exec/helper-proto-common.h
+++ b/include/exec/helper-proto-common.h
@@ -13,8 +13,4 @@
 #include "exec/helper-proto.h.inc"
 #undef  HELPER_H
 
-#define HELPER_H "accel/tcg/plugin-helpers.h"
-#include "exec/helper-proto.h.inc"
-#undef  HELPER_H
-
 #endif /* HELPER_PROTO_COMMON_H */
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index be7fd548cc..b5261edc38 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -51,11 +51,6 @@
 #include "exec/exec-all.h"
 #include "exec/plugin-gen.h"
 #include "exec/translator.h"
-#include "exec/helper-proto-common.h"
-
-#define HELPER_H  "accel/tcg/plugin-helpers.h"
-#include "exec/helper-info.c.inc"
-#undef  HELPER_H
 
 #ifdef CONFIG_SOFTMMU
 # define CONFIG_SOFTMMU_GATE 1
@@ -88,21 +83,6 @@ enum plugin_gen_cb {
     PLUGIN_GEN_N_CBS,
 };
 
-/*
- * These helpers are stubs that get dynamically switched out for calls
- * direct to the plugin if they are subscribed to.
- */
-void HELPER(plugin_vcpu_udata_cb_no_wg)(uint32_t cpu_index, void *udata)
-{ }
-
-void HELPER(plugin_vcpu_udata_cb_no_rwg)(uint32_t cpu_index, void *udata)
-{ }
-
-void HELPER(plugin_vcpu_mem_cb)(unsigned int vcpu_index,
-                                qemu_plugin_meminfo_t info, uint64_t vaddr,
-                                void *userdata)
-{ }
-
 static void plugin_gen_empty_callback(enum plugin_gen_from from)
 {
     switch (from) {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 13/22] tcg: Remove TCG_CALL_PLUGIN
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (11 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 12/22] plugins: Remove plugin helpers Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-19 13:06   ` Pierrick Bouvier
  2024-03-16  1:57 ` [PATCH 14/22] tcg: Remove INDEX_op_plugin_cb_{start,end} Richard Henderson
                   ` (9 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

Since we no longer emit plugin helpers during the initial code
translation phase, we don't need to specially mark plugin helpers.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/tcg/tcg.h |  2 --
 plugins/core.c    | 10 ++++------
 tcg/tcg.c         |  4 +---
 3 files changed, 5 insertions(+), 11 deletions(-)

diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index 95a7f4d010..df66e8f012 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -353,8 +353,6 @@ typedef TCGv_ptr TCGv_env;
 #define TCG_CALL_NO_SIDE_EFFECTS    0x0004
 /* Helper is G_NORETURN.  */
 #define TCG_CALL_NO_RETURN          0x0008
-/* Helper is part of Plugins.  */
-#define TCG_CALL_PLUGIN             0x0010
 
 /* convenience version of most used call flags */
 #define TCG_CALL_NO_RWG         TCG_CALL_NO_READ_GLOBALS
diff --git a/plugins/core.c b/plugins/core.c
index b0a2e80874..b0615f1e7f 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -339,9 +339,8 @@ void plugin_register_dyn_cb__udata(GArray **arr,
                                    void *udata)
 {
     static TCGHelperInfo info[3] = {
-        [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG | TCG_CALL_PLUGIN,
-        [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG | TCG_CALL_PLUGIN,
-        [QEMU_PLUGIN_CB_RW_REGS].flags = TCG_CALL_PLUGIN,
+        [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
+        [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
         /*
          * Match qemu_plugin_vcpu_udata_cb_t:
          *   void (*)(uint32_t, void *)
@@ -375,9 +374,8 @@ void plugin_register_vcpu_mem_cb(GArray **arr,
         !__builtin_types_compatible_p(qemu_plugin_meminfo_t, int32_t));
 
     static TCGHelperInfo info[3] = {
-        [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG | TCG_CALL_PLUGIN,
-        [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG | TCG_CALL_PLUGIN,
-        [QEMU_PLUGIN_CB_RW_REGS].flags = TCG_CALL_PLUGIN,
+        [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
+        [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
         /*
          * Match qemu_plugin_vcpu_mem_cb_t:
          *   void (*)(uint32_t, qemu_plugin_meminfo_t, uint64_t, void *)
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 0bf218314b..363a065e28 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -2269,9 +2269,7 @@ static void tcg_gen_callN(void *func, TCGHelperInfo *info,
 
 #ifdef CONFIG_PLUGIN
     /* Flag helpers that may affect guest state */
-    if (tcg_ctx->plugin_insn &&
-        !(info->flags & TCG_CALL_PLUGIN) &&
-        !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
+    if (tcg_ctx->plugin_insn && !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
         tcg_ctx->plugin_insn->calls_helpers = true;
     }
 #endif
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 14/22] tcg: Remove INDEX_op_plugin_cb_{start,end}
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (12 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 13/22] tcg: Remove TCG_CALL_PLUGIN Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-19 13:04   ` Pierrick Bouvier
  2024-03-16  1:57 ` [PATCH 15/22] plugins: Simplify callback queues Richard Henderson
                   ` (8 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

These opcodes are no longer used.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/tcg/tcg-op-common.h |  2 --
 include/tcg/tcg-opc.h       |  2 --
 accel/tcg/plugin-gen.c      | 18 ------------------
 tcg/tcg-op.c                | 10 ----------
 4 files changed, 32 deletions(-)

diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h
index 72b80b20d0..009e2778c5 100644
--- a/include/tcg/tcg-op-common.h
+++ b/include/tcg/tcg-op-common.h
@@ -76,8 +76,6 @@ void tcg_gen_lookup_and_goto_ptr(void);
 
 void tcg_gen_plugin_cb(unsigned from);
 void tcg_gen_plugin_mem_cb(TCGv_i64 addr, unsigned meminfo);
-void tcg_gen_plugin_cb_start(unsigned from, unsigned type, unsigned wr);
-void tcg_gen_plugin_cb_end(void);
 
 /* 32 bit ops */
 
diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h
index be9e36e386..546eb49c11 100644
--- a/include/tcg/tcg-opc.h
+++ b/include/tcg/tcg-opc.h
@@ -199,8 +199,6 @@ DEF(goto_ptr, 0, 1, 0, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
 
 DEF(plugin_cb, 0, 0, 1, TCG_OPF_NOT_PRESENT)
 DEF(plugin_mem_cb, 0, 1, 1, TCG_OPF_NOT_PRESENT)
-DEF(plugin_cb_start, 0, 0, 3, TCG_OPF_NOT_PRESENT)
-DEF(plugin_cb_end, 0, 0, 0, TCG_OPF_NOT_PRESENT)
 
 /* Replicate ld/st ops for 32 and 64-bit guest addresses. */
 DEF(qemu_ld_a32_i32, 1, 1, 1,
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index b5261edc38..c8f0e0ecaa 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -58,29 +58,11 @@
 # define CONFIG_SOFTMMU_GATE 0
 #endif
 
-/*
- * plugin_cb_start TCG op args[]:
- * 0: enum plugin_gen_from
- * 1: enum plugin_gen_cb
- * 2: set to 1 for mem callback that is a write, 0 otherwise.
- */
-
 enum plugin_gen_from {
     PLUGIN_GEN_FROM_TB,
     PLUGIN_GEN_FROM_INSN,
     PLUGIN_GEN_AFTER_INSN,
     PLUGIN_GEN_AFTER_TB,
-    PLUGIN_GEN_N_FROMS,
-};
-
-enum plugin_gen_cb {
-    PLUGIN_GEN_CB_UDATA,
-    PLUGIN_GEN_CB_UDATA_R,
-    PLUGIN_GEN_CB_INLINE,
-    PLUGIN_GEN_CB_MEM,
-    PLUGIN_GEN_ENABLE_MEM_HELPER,
-    PLUGIN_GEN_DISABLE_MEM_HELPER,
-    PLUGIN_GEN_N_CBS,
 };
 
 static void plugin_gen_empty_callback(enum plugin_gen_from from)
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index 0ae12fa49d..eff3728622 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -322,16 +322,6 @@ void tcg_gen_plugin_mem_cb(TCGv_i64 addr, unsigned meminfo)
     tcg_gen_op2(INDEX_op_plugin_mem_cb, tcgv_i64_arg(addr), meminfo);
 }
 
-void tcg_gen_plugin_cb_start(unsigned from, unsigned type, unsigned wr)
-{
-    tcg_gen_op3(INDEX_op_plugin_cb_start, from, type, wr);
-}
-
-void tcg_gen_plugin_cb_end(void)
-{
-    tcg_emit_op(INDEX_op_plugin_cb_end, 0);
-}
-
 /* 32 bit ops */
 
 void tcg_gen_discard_i32(TCGv_i32 arg)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 15/22] plugins: Simplify callback queues
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (13 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 14/22] tcg: Remove INDEX_op_plugin_cb_{start,end} Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-19 13:28   ` Pierrick Bouvier
  2024-03-16  1:57 ` [PATCH 16/22] plugins: Introduce PLUGIN_CB_MEM_REGULAR Richard Henderson
                   ` (7 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

We have qemu_plugin_dyn_cb.type to differentiate the various
callback types, so we do not need to keep them in separate queues.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/qemu/plugin.h  | 35 ++++++----------
 accel/tcg/plugin-gen.c | 90 ++++++++++++++++++++++--------------------
 plugins/api.c          | 18 +++------
 3 files changed, 65 insertions(+), 78 deletions(-)

diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index ee1c1b174a..cf9758be55 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -66,15 +66,8 @@ union qemu_plugin_cb_sig {
 };
 
 enum plugin_dyn_cb_type {
-    PLUGIN_CB_INSN,
-    PLUGIN_CB_MEM,
-    PLUGIN_N_CB_TYPES,
-};
-
-enum plugin_dyn_cb_subtype {
     PLUGIN_CB_REGULAR,
     PLUGIN_CB_INLINE,
-    PLUGIN_N_CB_SUBTYPES,
 };
 
 /*
@@ -84,7 +77,7 @@ enum plugin_dyn_cb_subtype {
  */
 struct qemu_plugin_dyn_cb {
     void *userp;
-    enum plugin_dyn_cb_subtype type;
+    enum plugin_dyn_cb_type type;
     /* @rw applies to mem callbacks only (both regular and inline) */
     enum qemu_plugin_mem_rw rw;
     /* fields specific to each dyn_cb type go here */
@@ -106,7 +99,8 @@ struct qemu_plugin_insn {
     GByteArray *data;
     uint64_t vaddr;
     void *haddr;
-    GArray *cbs[PLUGIN_N_CB_TYPES][PLUGIN_N_CB_SUBTYPES];
+    GArray *insn_cbs;
+    GArray *mem_cbs;
     bool calls_helpers;
 
     /* if set, the instruction calls helpers that might access guest memory */
@@ -135,16 +129,9 @@ static inline void qemu_plugin_insn_cleanup_fn(gpointer data)
 
 static inline struct qemu_plugin_insn *qemu_plugin_insn_alloc(void)
 {
-    int i, j;
     struct qemu_plugin_insn *insn = g_new0(struct qemu_plugin_insn, 1);
-    insn->data = g_byte_array_sized_new(4);
 
-    for (i = 0; i < PLUGIN_N_CB_TYPES; i++) {
-        for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) {
-            insn->cbs[i][j] = g_array_new(false, false,
-                                          sizeof(struct qemu_plugin_dyn_cb));
-        }
-    }
+    insn->data = g_byte_array_sized_new(4);
     return insn;
 }
 
@@ -161,7 +148,7 @@ struct qemu_plugin_tb {
     /* if set, the TB calls helpers that might access guest memory */
     bool mem_helper;
 
-    GArray *cbs[PLUGIN_N_CB_SUBTYPES];
+    GArray *cbs;
 };
 
 /**
@@ -174,22 +161,22 @@ struct qemu_plugin_insn *qemu_plugin_tb_insn_get(struct qemu_plugin_tb *tb,
                                                  uint64_t pc)
 {
     struct qemu_plugin_insn *insn;
-    int i, j;
 
     if (unlikely(tb->n == tb->insns->len)) {
         struct qemu_plugin_insn *new_insn = qemu_plugin_insn_alloc();
         g_ptr_array_add(tb->insns, new_insn);
     }
+
     insn = g_ptr_array_index(tb->insns, tb->n++);
     g_byte_array_set_size(insn->data, 0);
     insn->calls_helpers = false;
     insn->mem_helper = false;
     insn->vaddr = pc;
-
-    for (i = 0; i < PLUGIN_N_CB_TYPES; i++) {
-        for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) {
-            g_array_set_size(insn->cbs[i][j], 0);
-        }
+    if (insn->insn_cbs) {
+        g_array_set_size(insn->insn_cbs, 0);
+    }
+    if (insn->mem_cbs) {
+        g_array_set_size(insn->mem_cbs, 0);
     }
 
     return insn;
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index c8f0e0ecaa..669e343cfb 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -89,9 +89,8 @@ void plugin_gen_disable_mem_helpers(void)
 static void gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
                                   struct qemu_plugin_insn *insn)
 {
-    GArray *cbs[2];
     GArray *arr;
-    size_t n_cbs;
+    size_t len;
 
     /*
      * Tracking memory accesses performed from helpers requires extra work.
@@ -110,22 +109,25 @@ static void gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
         return;
     }
 
-    cbs[0] = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR];
-    cbs[1] = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
-    n_cbs = cbs[0]->len + cbs[1]->len;
-
-    if (n_cbs == 0) {
+    if (!insn->mem_cbs || !insn->mem_cbs->len) {
         insn->mem_helper = false;
         return;
     }
     insn->mem_helper = true;
     ptb->mem_helper = true;
 
+    /*
+     * TODO: It seems like we should be able to use ref/unref
+     * to avoid needing to actually copy this array.
+     * Alternately, perhaps we could allocate new memory adjacent
+     * to the TranslationBlock itself, so that we do not have to
+     * actively manage the lifetime after this.
+     */
+    len = insn->mem_cbs->len;
     arr = g_array_sized_new(false, false,
-                            sizeof(struct qemu_plugin_dyn_cb), n_cbs);
-    g_array_append_vals(arr, cbs[0]->data, cbs[0]->len);
-    g_array_append_vals(arr, cbs[1]->data, cbs[1]->len);
-
+                            sizeof(struct qemu_plugin_dyn_cb), len);
+    memcpy(arr->data, insn->mem_cbs->data,
+           len * sizeof(struct qemu_plugin_dyn_cb));
     qemu_plugin_add_dyn_cb_arr(arr);
 
     tcg_gen_st_ptr(tcg_constant_ptr((intptr_t)arr), tcg_env,
@@ -294,18 +296,21 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
             case PLUGIN_GEN_FROM_TB:
                 assert(insn == NULL);
 
-                cbs = plugin_tb->cbs[PLUGIN_CB_REGULAR];
+                cbs = plugin_tb->cbs;
                 for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
                     struct qemu_plugin_dyn_cb *cb =
                         &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
-                    gen_udata_cb(cb);
-                }
 
-                cbs = plugin_tb->cbs[PLUGIN_CB_INLINE];
-                for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
-                    struct qemu_plugin_dyn_cb *cb =
-                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
-                    gen_inline_cb(cb);
+                    switch (cb->type) {
+                    case PLUGIN_CB_REGULAR:
+                        gen_udata_cb(cb);
+                        break;
+                    case PLUGIN_CB_INLINE:
+                        gen_inline_cb(cb);
+                        break;
+                    default:
+                        g_assert_not_reached();
+                    }
                 }
                 break;
 
@@ -314,18 +319,21 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
 
                 gen_enable_mem_helper(plugin_tb, insn);
 
-                cbs = insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR];
+                cbs = insn->insn_cbs;
                 for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
                     struct qemu_plugin_dyn_cb *cb =
                         &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
-                    gen_udata_cb(cb);
-                }
 
-                cbs = insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE];
-                for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
-                    struct qemu_plugin_dyn_cb *cb =
-                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
-                    gen_inline_cb(cb);
+                    switch (cb->type) {
+                    case PLUGIN_CB_REGULAR:
+                        gen_udata_cb(cb);
+                        break;
+                    case PLUGIN_CB_INLINE:
+                        gen_inline_cb(cb);
+                        break;
+                    default:
+                        g_assert_not_reached();
+                    }
                 }
                 break;
 
@@ -352,21 +360,22 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
 
             tcg_ctx->emit_before_op = op;
 
-            cbs = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR];
+            cbs = insn->mem_cbs;
             for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
                 struct qemu_plugin_dyn_cb *cb =
                     &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
-                if (cb->rw & rw) {
-                    gen_mem_cb(cb, meminfo, addr);
-                }
-            }
 
-            cbs = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
-            for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
-                struct qemu_plugin_dyn_cb *cb =
-                    &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
                 if (cb->rw & rw) {
-                    gen_inline_cb(cb);
+                    switch (cb->type) {
+                    case PLUGIN_CB_REGULAR:
+                        gen_mem_cb(cb, meminfo, addr);
+                        break;
+                    case PLUGIN_CB_INLINE:
+                        gen_inline_cb(cb);
+                        break;
+                    default:
+                        g_assert_not_reached();
+                    }
                 }
             }
 
@@ -390,13 +399,10 @@ bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
 
     if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_state->event_mask)) {
         struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
-        int i;
 
         /* reset callbacks */
-        for (i = 0; i < PLUGIN_N_CB_SUBTYPES; i++) {
-            if (ptb->cbs[i]) {
-                g_array_set_size(ptb->cbs[i], 0);
-            }
+        if (ptb->cbs) {
+            g_array_set_size(ptb->cbs, 0);
         }
         ptb->n = 0;
 
diff --git a/plugins/api.c b/plugins/api.c
index 29cce2d97c..3912c9cc8f 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -92,8 +92,7 @@ void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
                                           void *udata)
 {
     if (!tb->mem_only) {
-        plugin_register_dyn_cb__udata(&tb->cbs[PLUGIN_CB_REGULAR],
-                                      cb, flags, udata);
+        plugin_register_dyn_cb__udata(&tb->cbs, cb, flags, udata);
     }
 }
 
@@ -104,8 +103,7 @@ void qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
     uint64_t imm)
 {
     if (!tb->mem_only) {
-        plugin_register_inline_op_on_entry(
-            &tb->cbs[PLUGIN_CB_INLINE], 0, op, entry, imm);
+        plugin_register_inline_op_on_entry(&tb->cbs, 0, op, entry, imm);
     }
 }
 
@@ -115,8 +113,7 @@ void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
                                             void *udata)
 {
     if (!insn->mem_only) {
-        plugin_register_dyn_cb__udata(
-            &insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR], cb, flags, udata);
+        plugin_register_dyn_cb__udata(&insn->insn_cbs, cb, flags, udata);
     }
 }
 
@@ -127,8 +124,7 @@ void qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
     uint64_t imm)
 {
     if (!insn->mem_only) {
-        plugin_register_inline_op_on_entry(
-            &insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE], 0, op, entry, imm);
+        plugin_register_inline_op_on_entry(&insn->insn_cbs, 0, op, entry, imm);
     }
 }
 
@@ -143,8 +139,7 @@ void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
                                       enum qemu_plugin_mem_rw rw,
                                       void *udata)
 {
-    plugin_register_vcpu_mem_cb(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR],
-                                cb, flags, rw, udata);
+    plugin_register_vcpu_mem_cb(&insn->mem_cbs, cb, flags, rw, udata);
 }
 
 void qemu_plugin_register_vcpu_mem_inline_per_vcpu(
@@ -154,8 +149,7 @@ void qemu_plugin_register_vcpu_mem_inline_per_vcpu(
     qemu_plugin_u64 entry,
     uint64_t imm)
 {
-    plugin_register_inline_op_on_entry(
-        &insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE], rw, op, entry, imm);
+    plugin_register_inline_op_on_entry(&insn->mem_cbs, rw, op, entry, imm);
 }
 
 void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 16/22] plugins: Introduce PLUGIN_CB_MEM_REGULAR
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (14 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 15/22] plugins: Simplify callback queues Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-19 13:28   ` Pierrick Bouvier
  2024-03-16  1:57 ` [PATCH 17/22] plugins: Replace pr_ops with a proper debug dump flag Richard Henderson
                   ` (6 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

Use different enumerators for vcpu_udata and vcpu_mem callbacks.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/qemu/plugin.h  | 1 +
 accel/tcg/plugin-gen.c | 2 +-
 plugins/core.c         | 4 ++--
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index cf9758be55..34498da717 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -67,6 +67,7 @@ union qemu_plugin_cb_sig {
 
 enum plugin_dyn_cb_type {
     PLUGIN_CB_REGULAR,
+    PLUGIN_CB_MEM_REGULAR,
     PLUGIN_CB_INLINE,
 };
 
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index 669e343cfb..6f0731b479 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -367,7 +367,7 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
 
                 if (cb->rw & rw) {
                     switch (cb->type) {
-                    case PLUGIN_CB_REGULAR:
+                    case PLUGIN_CB_MEM_REGULAR:
                         gen_mem_cb(cb, meminfo, addr);
                         break;
                     case PLUGIN_CB_INLINE:
diff --git a/plugins/core.c b/plugins/core.c
index b0615f1e7f..0213513ec6 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -391,7 +391,7 @@ void plugin_register_vcpu_mem_cb(GArray **arr,
 
     struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
     dyn_cb->userp = udata;
-    dyn_cb->type = PLUGIN_CB_REGULAR;
+    dyn_cb->type = PLUGIN_CB_MEM_REGULAR;
     dyn_cb->rw = rw;
     dyn_cb->regular.f.vcpu_mem = cb;
 
@@ -547,7 +547,7 @@ void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
                 break;
         }
         switch (cb->type) {
-        case PLUGIN_CB_REGULAR:
+        case PLUGIN_CB_MEM_REGULAR:
             cb->regular.f.vcpu_mem(cpu->cpu_index, make_plugin_meminfo(oi, rw),
                                    vaddr, cb->userp);
             break;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 17/22] plugins: Replace pr_ops with a proper debug dump flag
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (15 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 16/22] plugins: Introduce PLUGIN_CB_MEM_REGULAR Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-19 12:59   ` Pierrick Bouvier
  2024-03-16  1:57 ` [PATCH 18/22] plugins: Split out common cb expanders Richard Henderson
                   ` (5 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

The DEBUG_PLUGIN_GEN_OPS ifdef is replaced with "-d op_plugin".
The second pr_ops call can be obtained with "-d op".

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/qemu/log.h     |  1 +
 include/tcg/tcg.h      |  1 +
 accel/tcg/plugin-gen.c | 68 ++++++++----------------------------------
 tcg/tcg.c              | 29 +++++++++++++++++-
 util/log.c             |  4 +++
 5 files changed, 46 insertions(+), 57 deletions(-)

diff --git a/include/qemu/log.h b/include/qemu/log.h
index df59bfabcd..e10e24cd4f 100644
--- a/include/qemu/log.h
+++ b/include/qemu/log.h
@@ -36,6 +36,7 @@ bool qemu_log_separate(void);
 #define LOG_STRACE         (1 << 19)
 #define LOG_PER_THREAD     (1 << 20)
 #define CPU_LOG_TB_VPU     (1 << 21)
+#define LOG_TB_OP_PLUGIN   (1 << 22)
 
 /* Lock/unlock output. */
 
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index df66e8f012..753d7ca3e0 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -1065,5 +1065,6 @@ static inline const TCGOpcode *tcg_swap_vecop_list(const TCGOpcode *n)
 }
 
 bool tcg_can_emit_vecop_list(const TCGOpcode *, TCGType, unsigned);
+void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs);
 
 #endif /* TCG_H */
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index 6f0731b479..10d917abd3 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -44,6 +44,7 @@
  */
 #include "qemu/osdep.h"
 #include "qemu/plugin.h"
+#include "qemu/log.h"
 #include "cpu.h"
 #include "tcg/tcg.h"
 #include "tcg/tcg-temp-internal.h"
@@ -58,6 +59,7 @@
 # define CONFIG_SOFTMMU_GATE 0
 #endif
 
+/* Update plugin_from_name in tcg.c. */
 enum plugin_gen_from {
     PLUGIN_GEN_FROM_TB,
     PLUGIN_GEN_FROM_INSN,
@@ -192,66 +194,21 @@ static void gen_mem_cb(struct qemu_plugin_dyn_cb *cb,
     tcg_temp_free_i32(cpu_index);
 }
 
-/* #define DEBUG_PLUGIN_GEN_OPS */
-static void pr_ops(void)
-{
-#ifdef DEBUG_PLUGIN_GEN_OPS
-    TCGOp *op;
-    int i = 0;
-
-    QTAILQ_FOREACH(op, &tcg_ctx->ops, link) {
-        const char *name = "";
-        const char *type = "";
-
-        if (op->opc == INDEX_op_plugin_cb_start) {
-            switch (op->args[0]) {
-            case PLUGIN_GEN_FROM_TB:
-                name = "tb";
-                break;
-            case PLUGIN_GEN_FROM_INSN:
-                name = "insn";
-                break;
-            case PLUGIN_GEN_FROM_MEM:
-                name = "mem";
-                break;
-            case PLUGIN_GEN_AFTER_INSN:
-                name = "after insn";
-                break;
-            default:
-                break;
-            }
-            switch (op->args[1]) {
-            case PLUGIN_GEN_CB_UDATA:
-                type = "udata";
-                break;
-            case PLUGIN_GEN_CB_INLINE:
-                type = "inline";
-                break;
-            case PLUGIN_GEN_CB_MEM:
-                type = "mem";
-                break;
-            case PLUGIN_GEN_ENABLE_MEM_HELPER:
-                type = "enable mem helper";
-                break;
-            case PLUGIN_GEN_DISABLE_MEM_HELPER:
-                type = "disable mem helper";
-                break;
-            default:
-                break;
-            }
-        }
-        printf("op[%2i]: %s %s %s\n", i, tcg_op_defs[op->opc].name, name, type);
-        i++;
-    }
-#endif
-}
-
 static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
 {
     TCGOp *op, *next;
     int insn_idx = -1;
 
-    pr_ops();
+    if (unlikely(qemu_loglevel_mask(LOG_TB_OP_PLUGIN)
+                 && qemu_log_in_addr_range(plugin_tb->vaddr))) {
+        FILE *logfile = qemu_log_trylock();
+        if (logfile) {
+            fprintf(logfile, "OP before plugin injection:\n");
+            tcg_dump_ops(tcg_ctx, logfile, false);
+            fprintf(logfile, "\n");
+            qemu_log_unlock(logfile);
+        }
+    }
 
     /*
      * While injecting code, we cannot afford to reuse any ebb temps
@@ -389,7 +346,6 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
             break;
         }
     }
-    pr_ops();
 }
 
 bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 363a065e28..d248c52e96 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -2540,6 +2540,15 @@ static const char bswap_flag_name[][6] = {
     [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
 };
 
+#ifdef CONFIG_PLUGIN
+static const char * const plugin_from_name[] = {
+    "from-tb",
+    "from-insn",
+    "after-insn",
+    "after-tb",
+};
+#endif
+
 static inline bool tcg_regset_single(TCGRegSet d)
 {
     return (d & (d - 1)) == 0;
@@ -2558,7 +2567,7 @@ static inline TCGReg tcg_regset_first(TCGRegSet d)
 #define ne_fprintf(...) \
     ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
 
-static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
+void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
 {
     char buf[128];
     TCGOp *op;
@@ -2714,6 +2723,24 @@ static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
                     i = k = 1;
                 }
                 break;
+#ifdef CONFIG_PLUGIN
+            case INDEX_op_plugin_cb:
+                {
+                    TCGArg from = op->args[k++];
+                    const char *name = NULL;
+
+                    if (from < ARRAY_SIZE(plugin_from_name)) {
+                        name = plugin_from_name[from];
+                    }
+                    if (name) {
+                        col += ne_fprintf(f, "%s", name);
+                    } else {
+                        col += ne_fprintf(f, "$0x%" TCG_PRIlx, from);
+                    }
+                    i = 1;
+                }
+                break;
+#endif
             default:
                 i = 0;
                 break;
diff --git a/util/log.c b/util/log.c
index d36c98da0b..6219819855 100644
--- a/util/log.c
+++ b/util/log.c
@@ -466,6 +466,10 @@ const QEMULogItem qemu_log_items[] = {
       "show micro ops after optimization" },
     { CPU_LOG_TB_OP_IND, "op_ind",
       "show micro ops before indirect lowering" },
+#ifdef CONFIG_PLUGIN
+    { LOG_TB_OP_PLUGIN, "op_plugin",
+      "show micro ops before plugin injection" },
+#endif
     { CPU_LOG_INT, "int",
       "show interrupts/exceptions in short format" },
     { CPU_LOG_EXEC, "exec",
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 18/22] plugins: Split out common cb expanders
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (16 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 17/22] plugins: Replace pr_ops with a proper debug dump flag Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-19 13:29   ` Pierrick Bouvier
  2024-03-16  1:57 ` [PATCH 19/22] plugins: Merge qemu_plugin_tb_insn_get to plugin-gen.c Richard Henderson
                   ` (4 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 accel/tcg/plugin-gen.c | 84 +++++++++++++++++++++---------------------
 1 file changed, 41 insertions(+), 43 deletions(-)

diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index 10d917abd3..28414c4ff1 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -194,6 +194,37 @@ static void gen_mem_cb(struct qemu_plugin_dyn_cb *cb,
     tcg_temp_free_i32(cpu_index);
 }
 
+static void inject_cb(struct qemu_plugin_dyn_cb *cb)
+
+{
+    switch (cb->type) {
+    case PLUGIN_CB_REGULAR:
+        gen_udata_cb(cb);
+        break;
+    case PLUGIN_CB_INLINE:
+        gen_inline_cb(cb);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void inject_mem_cb(struct qemu_plugin_dyn_cb *cb,
+                          enum qemu_plugin_mem_rw rw,
+                          qemu_plugin_meminfo_t meminfo, TCGv_i64 addr)
+{
+    if (cb->rw & rw) {
+        switch (cb->type) {
+        case PLUGIN_CB_MEM_REGULAR:
+            gen_mem_cb(cb, meminfo, addr);
+            break;
+        default:
+            inject_cb(cb);
+            break;
+        }
+    }
+}
+
 static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
 {
     TCGOp *op, *next;
@@ -255,19 +286,8 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
 
                 cbs = plugin_tb->cbs;
                 for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
-                    struct qemu_plugin_dyn_cb *cb =
-                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
-
-                    switch (cb->type) {
-                    case PLUGIN_CB_REGULAR:
-                        gen_udata_cb(cb);
-                        break;
-                    case PLUGIN_CB_INLINE:
-                        gen_inline_cb(cb);
-                        break;
-                    default:
-                        g_assert_not_reached();
-                    }
+                    inject_cb(
+                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i));
                 }
                 break;
 
@@ -278,19 +298,8 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
 
                 cbs = insn->insn_cbs;
                 for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
-                    struct qemu_plugin_dyn_cb *cb =
-                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
-
-                    switch (cb->type) {
-                    case PLUGIN_CB_REGULAR:
-                        gen_udata_cb(cb);
-                        break;
-                    case PLUGIN_CB_INLINE:
-                        gen_inline_cb(cb);
-                        break;
-                    default:
-                        g_assert_not_reached();
-                    }
+                    inject_cb(
+                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i));
                 }
                 break;
 
@@ -307,33 +316,22 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
         {
             TCGv_i64 addr = temp_tcgv_i64(arg_temp(op->args[0]));
             qemu_plugin_meminfo_t meminfo = op->args[1];
+            enum qemu_plugin_mem_rw rw =
+                (qemu_plugin_mem_is_store(meminfo)
+                 ? QEMU_PLUGIN_MEM_W : QEMU_PLUGIN_MEM_R);
             struct qemu_plugin_insn *insn;
             const GArray *cbs;
-            int i, n, rw;
+            int i, n;
 
             assert(insn_idx >= 0);
             insn = g_ptr_array_index(plugin_tb->insns, insn_idx);
-            rw = qemu_plugin_mem_is_store(meminfo) ? 2 : 1;
 
             tcg_ctx->emit_before_op = op;
 
             cbs = insn->mem_cbs;
             for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
-                struct qemu_plugin_dyn_cb *cb =
-                    &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
-
-                if (cb->rw & rw) {
-                    switch (cb->type) {
-                    case PLUGIN_CB_MEM_REGULAR:
-                        gen_mem_cb(cb, meminfo, addr);
-                        break;
-                    case PLUGIN_CB_INLINE:
-                        gen_inline_cb(cb);
-                        break;
-                    default:
-                        g_assert_not_reached();
-                    }
-                }
+                inject_mem_cb(&g_array_index(cbs, struct qemu_plugin_dyn_cb, i),
+                              rw, meminfo, addr);
             }
 
             tcg_ctx->emit_before_op = NULL;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 19/22] plugins: Merge qemu_plugin_tb_insn_get to plugin-gen.c
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (17 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 18/22] plugins: Split out common cb expanders Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-19 13:30   ` Pierrick Bouvier
  2024-03-16  1:57 ` [PATCH 20/22] plugins: Move qemu_plugin_insn_cleanup_fn to tcg.c Richard Henderson
                   ` (3 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

Merge qemu_plugin_insn_alloc and qemu_plugin_tb_insn_get into
plugin_gen_insn_start, since it is used nowhere else.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/qemu/plugin.h  | 39 ---------------------------------------
 accel/tcg/plugin-gen.c | 39 ++++++++++++++++++++++++++++++++-------
 2 files changed, 32 insertions(+), 46 deletions(-)

diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index 34498da717..07b1755990 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -128,14 +128,6 @@ static inline void qemu_plugin_insn_cleanup_fn(gpointer data)
     g_byte_array_free(insn->data, true);
 }
 
-static inline struct qemu_plugin_insn *qemu_plugin_insn_alloc(void)
-{
-    struct qemu_plugin_insn *insn = g_new0(struct qemu_plugin_insn, 1);
-
-    insn->data = g_byte_array_sized_new(4);
-    return insn;
-}
-
 /* Internal context for this TranslationBlock */
 struct qemu_plugin_tb {
     GPtrArray *insns;
@@ -152,37 +144,6 @@ struct qemu_plugin_tb {
     GArray *cbs;
 };
 
-/**
- * qemu_plugin_tb_insn_get(): get next plugin record for translation.
- * @tb: the internal tb context
- * @pc: address of instruction
- */
-static inline
-struct qemu_plugin_insn *qemu_plugin_tb_insn_get(struct qemu_plugin_tb *tb,
-                                                 uint64_t pc)
-{
-    struct qemu_plugin_insn *insn;
-
-    if (unlikely(tb->n == tb->insns->len)) {
-        struct qemu_plugin_insn *new_insn = qemu_plugin_insn_alloc();
-        g_ptr_array_add(tb->insns, new_insn);
-    }
-
-    insn = g_ptr_array_index(tb->insns, tb->n++);
-    g_byte_array_set_size(insn->data, 0);
-    insn->calls_helpers = false;
-    insn->mem_helper = false;
-    insn->vaddr = pc;
-    if (insn->insn_cbs) {
-        g_array_set_size(insn->insn_cbs, 0);
-    }
-    if (insn->mem_cbs) {
-        g_array_set_size(insn->mem_cbs, 0);
-    }
-
-    return insn;
-}
-
 /**
  * struct CPUPluginState - per-CPU state for plugins
  * @event_mask: plugin event bitmap. Modified only via async work.
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index 28414c4ff1..70914c3bf8 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -380,11 +380,34 @@ bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
 void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
 {
     struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
-    struct qemu_plugin_insn *pinsn;
+    struct qemu_plugin_insn *insn;
+    size_t n = db->num_insns;
+    vaddr pc;
 
-    pinsn = qemu_plugin_tb_insn_get(ptb, db->pc_next);
-    tcg_ctx->plugin_insn = pinsn;
-    plugin_gen_empty_callback(PLUGIN_GEN_FROM_INSN);
+    assert(n >= 1);
+    ptb->n = n;
+    if (n <= ptb->insns->len) {
+        insn = g_ptr_array_index(ptb->insns, n - 1);
+        g_byte_array_set_size(insn->data, 0);
+    } else {
+        assert(n - 1 == ptb->insns->len);
+        insn = g_new0(struct qemu_plugin_insn, 1);
+        insn->data = g_byte_array_sized_new(4);
+        g_ptr_array_add(ptb->insns, insn);
+    }
+
+    tcg_ctx->plugin_insn = insn;
+    insn->calls_helpers = false;
+    insn->mem_helper = false;
+    if (insn->insn_cbs) {
+        g_array_set_size(insn->insn_cbs, 0);
+    }
+    if (insn->mem_cbs) {
+        g_array_set_size(insn->mem_cbs, 0);
+    }
+
+    pc = db->pc_next;
+    insn->vaddr = pc;
 
     /*
      * Detect page crossing to get the new host address.
@@ -392,16 +415,18 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
      * fetching instructions from a region not backed by RAM.
      */
     if (ptb->haddr1 == NULL) {
-        pinsn->haddr = NULL;
+        insn->haddr = NULL;
     } else if (is_same_page(db, db->pc_next)) {
-        pinsn->haddr = ptb->haddr1 + pinsn->vaddr - ptb->vaddr;
+        insn->haddr = ptb->haddr1 + pc - ptb->vaddr;
     } else {
         if (ptb->vaddr2 == -1) {
             ptb->vaddr2 = TARGET_PAGE_ALIGN(db->pc_first);
             get_page_addr_code_hostp(cpu_env(cpu), ptb->vaddr2, &ptb->haddr2);
         }
-        pinsn->haddr = ptb->haddr2 + pinsn->vaddr - ptb->vaddr2;
+        insn->haddr = ptb->haddr2 + pc - ptb->vaddr2;
     }
+
+    plugin_gen_empty_callback(PLUGIN_GEN_FROM_INSN);
 }
 
 void plugin_gen_insn_end(void)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 20/22] plugins: Move qemu_plugin_insn_cleanup_fn to tcg.c
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (18 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 19/22] plugins: Merge qemu_plugin_tb_insn_get to plugin-gen.c Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-18 17:44   ` Alex Bennée
  2024-03-16  1:57 ` [PATCH 21/22] plugins: Inline plugin_gen_empty_callback Richard Henderson
                   ` (2 subsequent siblings)
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

This is only used in one place, and usage requires an
out-of-line function.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/qemu/plugin.h | 12 ------------
 tcg/tcg.c             | 12 ++++++++++++
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index 07b1755990..201889cbee 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -116,18 +116,6 @@ struct qemu_plugin_scoreboard {
     QLIST_ENTRY(qemu_plugin_scoreboard) entry;
 };
 
-/*
- * qemu_plugin_insn allocate and cleanup functions. We don't expect to
- * cleanup many of these structures. They are reused for each fresh
- * translation.
- */
-
-static inline void qemu_plugin_insn_cleanup_fn(gpointer data)
-{
-    struct qemu_plugin_insn *insn = (struct qemu_plugin_insn *) data;
-    g_byte_array_free(insn->data, true);
-}
-
 /* Internal context for this TranslationBlock */
 struct qemu_plugin_tb {
     GPtrArray *insns;
diff --git a/tcg/tcg.c b/tcg/tcg.c
index d248c52e96..d7abc514c4 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -761,6 +761,18 @@ QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) -
                   < MIN_TLB_MASK_TABLE_OFS);
 #endif
 
+#ifdef CONFIG_PLUGIN
+/*
+ * We don't expect to cleanup many of these structures.
+ * They are reused for each fresh translation.
+ */
+static void qemu_plugin_insn_cleanup_fn(gpointer data)
+{
+    struct qemu_plugin_insn *insn = (struct qemu_plugin_insn *) data;
+    g_byte_array_free(insn->data, true);
+}
+#endif
+
 static void alloc_tcg_plugin_context(TCGContext *s)
 {
 #ifdef CONFIG_PLUGIN
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 21/22] plugins: Inline plugin_gen_empty_callback
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (19 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 20/22] plugins: Move qemu_plugin_insn_cleanup_fn to tcg.c Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-18 19:09   ` Alex Bennée
  2024-03-16  1:57 ` [PATCH 22/22] plugins: Update the documentation block for plugin-gen.c Richard Henderson
  2024-03-19 13:38 ` [PATCH 00/22] plugins: Rewrite plugin code generation Pierrick Bouvier
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

Each caller can use tcg_gen_plugin_cb directly.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 accel/tcg/plugin-gen.c | 19 +++----------------
 1 file changed, 3 insertions(+), 16 deletions(-)

diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index 70914c3bf8..fd52ea3987 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -67,19 +67,6 @@ enum plugin_gen_from {
     PLUGIN_GEN_AFTER_TB,
 };
 
-static void plugin_gen_empty_callback(enum plugin_gen_from from)
-{
-    switch (from) {
-    case PLUGIN_GEN_AFTER_INSN:
-    case PLUGIN_GEN_FROM_TB:
-    case PLUGIN_GEN_FROM_INSN:
-        tcg_gen_plugin_cb(from);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-}
-
 /* called before finishing a TB with exit_tb, goto_tb or goto_ptr */
 void plugin_gen_disable_mem_helpers(void)
 {
@@ -369,7 +356,7 @@ bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
         ptb->mem_only = mem_only;
         ptb->mem_helper = false;
 
-        plugin_gen_empty_callback(PLUGIN_GEN_FROM_TB);
+        tcg_gen_plugin_cb(PLUGIN_GEN_FROM_TB);
     }
 
     tcg_ctx->plugin_insn = NULL;
@@ -426,12 +413,12 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
         insn->haddr = ptb->haddr2 + pc - ptb->vaddr2;
     }
 
-    plugin_gen_empty_callback(PLUGIN_GEN_FROM_INSN);
+    tcg_gen_plugin_cb(PLUGIN_GEN_FROM_INSN);
 }
 
 void plugin_gen_insn_end(void)
 {
-    plugin_gen_empty_callback(PLUGIN_GEN_AFTER_INSN);
+    tcg_gen_plugin_cb(PLUGIN_GEN_AFTER_INSN);
 }
 
 /*
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 22/22] plugins: Update the documentation block for plugin-gen.c
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (20 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 21/22] plugins: Inline plugin_gen_empty_callback Richard Henderson
@ 2024-03-16  1:57 ` Richard Henderson
  2024-03-19 12:56   ` Pierrick Bouvier
  2024-03-19 13:38 ` [PATCH 00/22] plugins: Rewrite plugin code generation Pierrick Bouvier
  22 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-16  1:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: pierrick.bouvier, alex.bennee

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 accel/tcg/plugin-gen.c | 31 ++++---------------------------
 1 file changed, 4 insertions(+), 27 deletions(-)

diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index fd52ea3987..c354825779 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -14,33 +14,10 @@
  * Injecting the desired instrumentation could be done with a second
  * translation pass that combined the instrumentation requests, but that
  * would be ugly and inefficient since we would decode the guest code twice.
- * Instead, during TB translation we add "empty" instrumentation calls for all
- * possible instrumentation events, and then once we collect the instrumentation
- * requests from plugins, we either "fill in" those empty events or remove them
- * if they have no requests.
- *
- * When "filling in" an event we first copy the empty callback's TCG ops. This
- * might seem unnecessary, but it is done to support an arbitrary number
- * of callbacks per event. Take for example a regular instruction callback.
- * We first generate a callback to an empty helper function. Then, if two
- * plugins register one callback each for this instruction, we make two copies
- * of the TCG ops generated for the empty callback, substituting the function
- * pointer that points to the empty helper function with the plugins' desired
- * callback functions. After that we remove the empty callback's ops.
- *
- * Note that the location in TCGOp.args[] of the pointer to a helper function
- * varies across different guest and host architectures. Instead of duplicating
- * the logic that figures this out, we rely on the fact that the empty
- * callbacks point to empty functions that are unique pointers in the program.
- * Thus, to find the right location we just have to look for a match in
- * TCGOp.args[]. This is the main reason why we first copy an empty callback's
- * TCG ops and then fill them in; regardless of whether we have one or many
- * callbacks for that event, the logic to add all of them is the same.
- *
- * When generating more than one callback per event, we make a small
- * optimization to avoid generating redundant operations. For instance, for the
- * second and all subsequent callbacks of an event, we do not need to reload the
- * CPU's index into a TCG temp, since the first callback did it already.
+ * Instead, during TB translation we add "plugin_cb" marker opcodes
+ * for all possible instrumentation events, and then once we collect the
+ * instrumentation requests from plugins, we generate code for those markers
+ * or remove them if they have no requests.
  */
 #include "qemu/osdep.h"
 #include "qemu/plugin.h"
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH 02/22] tcg: Make tcg/helper-info.h self-contained
  2024-03-16  1:57 ` [PATCH 02/22] tcg: Make tcg/helper-info.h self-contained Richard Henderson
@ 2024-03-18 10:01   ` Alex Bennée
  2024-03-18 10:03   ` Alex Bennée
  1 sibling, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2024-03-18 10:01 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel, pierrick.bouvier

Richard Henderson <richard.henderson@linaro.org> writes:

> Move MAX_CALL_IARGS from tcg.h and include for
> the define of TCG_TARGET_REG_BITS.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 03/22] tcg: Pass function pointer to tcg_gen_call*
  2024-03-16  1:57 ` [PATCH 03/22] tcg: Pass function pointer to tcg_gen_call* Richard Henderson
@ 2024-03-18 10:02   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2024-03-18 10:02 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel, pierrick.bouvier

Richard Henderson <richard.henderson@linaro.org> writes:

> For normal helpers, read the function pointer from the
> structure earlier.  For plugins, this will allow the
> function pointer to come from elsewhere.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 02/22] tcg: Make tcg/helper-info.h self-contained
  2024-03-16  1:57 ` [PATCH 02/22] tcg: Make tcg/helper-info.h self-contained Richard Henderson
  2024-03-18 10:01   ` Alex Bennée
@ 2024-03-18 10:03   ` Alex Bennée
  1 sibling, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2024-03-18 10:03 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel, pierrick.bouvier

Richard Henderson <richard.henderson@linaro.org> writes:

> Move MAX_CALL_IARGS from tcg.h and include for
> the define of TCG_TARGET_REG_BITS.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

This may have broken TCI:

../tcg/tci.c: In function 'tcg_qemu_tb_exec':
../tcg/tci.c:391:34: error: 'MAX_CALL_IARGS' undeclared (first use in this function)
  391 |                 void *call_slots[MAX_CALL_IARGS];
      |                                  ^~~~~~~~~~~~~~
../tcg/tci.c:391:34: note: each undeclared identifier is reported only once for each function it appears in
../tcg/tci.c:391:23: error: unused variable 'call_slots' [-Werror=unused-variable]
  391 |                 void *call_slots[MAX_CALL_IARGS];
      |                       ^~~~~~~~~~
cc1: all warnings being treated as errors

the gift that keeps on giving ;-)

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 04/22] plugins: Zero new qemu_plugin_dyn_cb entries
  2024-03-16  1:57 ` [PATCH 04/22] plugins: Zero new qemu_plugin_dyn_cb entries Richard Henderson
@ 2024-03-18 10:03   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2024-03-18 10:03 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel, pierrick.bouvier

Richard Henderson <richard.henderson@linaro.org> writes:

> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 05/22] plugins: Move function pointer in qemu_plugin_dyn_cb
  2024-03-16  1:57 ` [PATCH 05/22] plugins: Move function pointer in qemu_plugin_dyn_cb Richard Henderson
@ 2024-03-18 10:04   ` Alex Bennée
  2024-03-19 13:18   ` Pierrick Bouvier
  1 sibling, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2024-03-18 10:04 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel, pierrick.bouvier

Richard Henderson <richard.henderson@linaro.org> writes:

> The out-of-line function pointer is mutually exclusive
> with inline expansion, so move it into the union.
> Wrap the pointer in a structure named 'regular' to match
> PLUGIN_CB_REGULAR.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 12/22] plugins: Remove plugin helpers
  2024-03-16  1:57 ` [PATCH 12/22] plugins: Remove plugin helpers Richard Henderson
@ 2024-03-18 16:38   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2024-03-18 16:38 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel, pierrick.bouvier

Richard Henderson <richard.henderson@linaro.org> writes:

> These placeholder helpers are no longer required.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 20/22] plugins: Move qemu_plugin_insn_cleanup_fn to tcg.c
  2024-03-16  1:57 ` [PATCH 20/22] plugins: Move qemu_plugin_insn_cleanup_fn to tcg.c Richard Henderson
@ 2024-03-18 17:44   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2024-03-18 17:44 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel, pierrick.bouvier

Richard Henderson <richard.henderson@linaro.org> writes:

> This is only used in one place, and usage requires an
> out-of-line function.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  include/qemu/plugin.h | 12 ------------
>  tcg/tcg.c             | 12 ++++++++++++
>  2 files changed, 12 insertions(+), 12 deletions(-)
>
> diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
> index 07b1755990..201889cbee 100644
> --- a/include/qemu/plugin.h
> +++ b/include/qemu/plugin.h
> @@ -116,18 +116,6 @@ struct qemu_plugin_scoreboard {
>      QLIST_ENTRY(qemu_plugin_scoreboard) entry;
>  };
>  
> -/*
> - * qemu_plugin_insn allocate and cleanup functions. We don't expect to
> - * cleanup many of these structures. They are reused for each fresh
> - * translation.
> - */
> -
> -static inline void qemu_plugin_insn_cleanup_fn(gpointer data)
> -{
> -    struct qemu_plugin_insn *insn = (struct qemu_plugin_insn *) data;
> -    g_byte_array_free(insn->data, true);
> -}
> -
>  /* Internal context for this TranslationBlock */
>  struct qemu_plugin_tb {
>      GPtrArray *insns;
> diff --git a/tcg/tcg.c b/tcg/tcg.c
> index d248c52e96..d7abc514c4 100644
> --- a/tcg/tcg.c
> +++ b/tcg/tcg.c
> @@ -761,6 +761,18 @@ QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) -
>                    < MIN_TLB_MASK_TABLE_OFS);
>  #endif
>  
> +#ifdef CONFIG_PLUGIN
> +/*
> + * We don't expect to cleanup many of these structures.
> + * They are reused for each fresh translation.
> + */
> +static void qemu_plugin_insn_cleanup_fn(gpointer data)
> +{
> +    struct qemu_plugin_insn *insn = (struct qemu_plugin_insn *) data;
> +    g_byte_array_free(insn->data, true);
> +}
> +#endif
> +

You could expand the ifdef to the next function and make an alternate
empty alloc_tcg_plugin_context. Alternatively maybe we should consider
dropping the CONFIG_PLUGIN gymnastics and make it a first class TCG
feature?

Is the null case still visible on the code generation benchmarks? Does
anyone using TCG actually --disable-plugins?

Anyway:

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>


>  static void alloc_tcg_plugin_context(TCGContext *s)
>  {
>  #ifdef CONFIG_PLUGIN

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 21/22] plugins: Inline plugin_gen_empty_callback
  2024-03-16  1:57 ` [PATCH 21/22] plugins: Inline plugin_gen_empty_callback Richard Henderson
@ 2024-03-18 19:09   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2024-03-18 19:09 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel, pierrick.bouvier

Richard Henderson <richard.henderson@linaro.org> writes:

> Each caller can use tcg_gen_plugin_cb directly.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 01/22] tcg: Add TCGContext.emit_before_op
  2024-03-16  1:56 ` [PATCH 01/22] tcg: Add TCGContext.emit_before_op Richard Henderson
@ 2024-03-19 10:55   ` Pierrick Bouvier
  2024-03-19 14:04   ` Alex Bennée
  1 sibling, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 10:55 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:56, Richard Henderson wrote:
> Allow operations to be emitted via normal expanders
> into the middle of the opcode stream.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/tcg/tcg.h |  1 +
>   tcg/tcg.c         | 14 ++++++++++++--
>   2 files changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
> index 451f3fec41..e9d05f40b0 100644
> --- a/include/tcg/tcg.h
> +++ b/include/tcg/tcg.h
> @@ -552,6 +552,7 @@ struct TCGContext {
>   
>       QTAILQ_HEAD(, TCGOp) ops, free_ops;
>       QSIMPLEQ_HEAD(, TCGLabel) labels;
> +    TCGOp *emit_before_op;
>   
>       /* Tells which temporary holds a given register.
>          It does not take into account fixed registers */
> diff --git a/tcg/tcg.c b/tcg/tcg.c
> index d6670237fb..0c0bb9d169 100644
> --- a/tcg/tcg.c
> +++ b/tcg/tcg.c
> @@ -1521,6 +1521,7 @@ void tcg_func_start(TCGContext *s)
>   
>       QTAILQ_INIT(&s->ops);
>       QTAILQ_INIT(&s->free_ops);
> +    s->emit_before_op = NULL;
>       QSIMPLEQ_INIT(&s->labels);
>   
>       tcg_debug_assert(s->addr_type == TCG_TYPE_I32 ||
> @@ -2332,7 +2333,11 @@ static void tcg_gen_callN(TCGHelperInfo *info, TCGTemp *ret, TCGTemp **args)
>       op->args[pi++] = (uintptr_t)info;
>       tcg_debug_assert(pi == total_args);
>   
> -    QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
> +    if (tcg_ctx->emit_before_op) {
> +        QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
> +    } else {
> +        QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
> +    }
>   
>       tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
>       for (i = 0; i < n_extend; ++i) {
> @@ -3215,7 +3220,12 @@ static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
>   TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
>   {
>       TCGOp *op = tcg_op_alloc(opc, nargs);
> -    QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
> +
> +    if (tcg_ctx->emit_before_op) {
> +        QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
> +    } else {
> +        QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
> +    }
>       return op;
>   }
>   

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 22/22] plugins: Update the documentation block for plugin-gen.c
  2024-03-16  1:57 ` [PATCH 22/22] plugins: Update the documentation block for plugin-gen.c Richard Henderson
@ 2024-03-19 12:56   ` Pierrick Bouvier
  0 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 12:56 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:57, Richard Henderson wrote:
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   accel/tcg/plugin-gen.c | 31 ++++---------------------------
>   1 file changed, 4 insertions(+), 27 deletions(-)
> 
> diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
> index fd52ea3987..c354825779 100644
> --- a/accel/tcg/plugin-gen.c
> +++ b/accel/tcg/plugin-gen.c
> @@ -14,33 +14,10 @@
>    * Injecting the desired instrumentation could be done with a second
>    * translation pass that combined the instrumentation requests, but that
>    * would be ugly and inefficient since we would decode the guest code twice.
> - * Instead, during TB translation we add "empty" instrumentation calls for all
> - * possible instrumentation events, and then once we collect the instrumentation
> - * requests from plugins, we either "fill in" those empty events or remove them
> - * if they have no requests.
> - *
> - * When "filling in" an event we first copy the empty callback's TCG ops. This
> - * might seem unnecessary, but it is done to support an arbitrary number
> - * of callbacks per event. Take for example a regular instruction callback.
> - * We first generate a callback to an empty helper function. Then, if two
> - * plugins register one callback each for this instruction, we make two copies
> - * of the TCG ops generated for the empty callback, substituting the function
> - * pointer that points to the empty helper function with the plugins' desired
> - * callback functions. After that we remove the empty callback's ops.
> - *
> - * Note that the location in TCGOp.args[] of the pointer to a helper function
> - * varies across different guest and host architectures. Instead of duplicating
> - * the logic that figures this out, we rely on the fact that the empty
> - * callbacks point to empty functions that are unique pointers in the program.
> - * Thus, to find the right location we just have to look for a match in
> - * TCGOp.args[]. This is the main reason why we first copy an empty callback's
> - * TCG ops and then fill them in; regardless of whether we have one or many
> - * callbacks for that event, the logic to add all of them is the same.
> - *
> - * When generating more than one callback per event, we make a small
> - * optimization to avoid generating redundant operations. For instance, for the
> - * second and all subsequent callbacks of an event, we do not need to reload the
> - * CPU's index into a TCG temp, since the first callback did it already.
> + * Instead, during TB translation we add "plugin_cb" marker opcodes
> + * for all possible instrumentation events, and then once we collect the
> + * instrumentation requests from plugins, we generate code for those markers
> + * or remove them if they have no requests.
>    */
>   #include "qemu/osdep.h"
>   #include "qemu/plugin.h"

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 17/22] plugins: Replace pr_ops with a proper debug dump flag
  2024-03-16  1:57 ` [PATCH 17/22] plugins: Replace pr_ops with a proper debug dump flag Richard Henderson
@ 2024-03-19 12:59   ` Pierrick Bouvier
  0 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 12:59 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:57, Richard Henderson wrote:
> The DEBUG_PLUGIN_GEN_OPS ifdef is replaced with "-d op_plugin".
> The second pr_ops call can be obtained with "-d op".
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/qemu/log.h     |  1 +
>   include/tcg/tcg.h      |  1 +
>   accel/tcg/plugin-gen.c | 68 ++++++++----------------------------------
>   tcg/tcg.c              | 29 +++++++++++++++++-
>   util/log.c             |  4 +++
>   5 files changed, 46 insertions(+), 57 deletions(-)
> 
> diff --git a/include/qemu/log.h b/include/qemu/log.h
> index df59bfabcd..e10e24cd4f 100644
> --- a/include/qemu/log.h
> +++ b/include/qemu/log.h
> @@ -36,6 +36,7 @@ bool qemu_log_separate(void);
>   #define LOG_STRACE         (1 << 19)
>   #define LOG_PER_THREAD     (1 << 20)
>   #define CPU_LOG_TB_VPU     (1 << 21)
> +#define LOG_TB_OP_PLUGIN   (1 << 22)
>   
>   /* Lock/unlock output. */
>   
> diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
> index df66e8f012..753d7ca3e0 100644
> --- a/include/tcg/tcg.h
> +++ b/include/tcg/tcg.h
> @@ -1065,5 +1065,6 @@ static inline const TCGOpcode *tcg_swap_vecop_list(const TCGOpcode *n)
>   }
>   
>   bool tcg_can_emit_vecop_list(const TCGOpcode *, TCGType, unsigned);
> +void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs);
>   
>   #endif /* TCG_H */
> diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
> index 6f0731b479..10d917abd3 100644
> --- a/accel/tcg/plugin-gen.c
> +++ b/accel/tcg/plugin-gen.c
> @@ -44,6 +44,7 @@
>    */
>   #include "qemu/osdep.h"
>   #include "qemu/plugin.h"
> +#include "qemu/log.h"
>   #include "cpu.h"
>   #include "tcg/tcg.h"
>   #include "tcg/tcg-temp-internal.h"
> @@ -58,6 +59,7 @@
>   # define CONFIG_SOFTMMU_GATE 0
>   #endif
>   
> +/* Update plugin_from_name in tcg.c. */
>   enum plugin_gen_from {
>       PLUGIN_GEN_FROM_TB,
>       PLUGIN_GEN_FROM_INSN,
> @@ -192,66 +194,21 @@ static void gen_mem_cb(struct qemu_plugin_dyn_cb *cb,
>       tcg_temp_free_i32(cpu_index);
>   }
>   
> -/* #define DEBUG_PLUGIN_GEN_OPS */
> -static void pr_ops(void)
> -{
> -#ifdef DEBUG_PLUGIN_GEN_OPS
> -    TCGOp *op;
> -    int i = 0;
> -
> -    QTAILQ_FOREACH(op, &tcg_ctx->ops, link) {
> -        const char *name = "";
> -        const char *type = "";
> -
> -        if (op->opc == INDEX_op_plugin_cb_start) {
> -            switch (op->args[0]) {
> -            case PLUGIN_GEN_FROM_TB:
> -                name = "tb";
> -                break;
> -            case PLUGIN_GEN_FROM_INSN:
> -                name = "insn";
> -                break;
> -            case PLUGIN_GEN_FROM_MEM:
> -                name = "mem";
> -                break;
> -            case PLUGIN_GEN_AFTER_INSN:
> -                name = "after insn";
> -                break;
> -            default:
> -                break;
> -            }
> -            switch (op->args[1]) {
> -            case PLUGIN_GEN_CB_UDATA:
> -                type = "udata";
> -                break;
> -            case PLUGIN_GEN_CB_INLINE:
> -                type = "inline";
> -                break;
> -            case PLUGIN_GEN_CB_MEM:
> -                type = "mem";
> -                break;
> -            case PLUGIN_GEN_ENABLE_MEM_HELPER:
> -                type = "enable mem helper";
> -                break;
> -            case PLUGIN_GEN_DISABLE_MEM_HELPER:
> -                type = "disable mem helper";
> -                break;
> -            default:
> -                break;
> -            }
> -        }
> -        printf("op[%2i]: %s %s %s\n", i, tcg_op_defs[op->opc].name, name, type);
> -        i++;
> -    }
> -#endif
> -}
> -
>   static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>   {
>       TCGOp *op, *next;
>       int insn_idx = -1;
>   
> -    pr_ops();
> +    if (unlikely(qemu_loglevel_mask(LOG_TB_OP_PLUGIN)
> +                 && qemu_log_in_addr_range(plugin_tb->vaddr))) {
> +        FILE *logfile = qemu_log_trylock();
> +        if (logfile) {
> +            fprintf(logfile, "OP before plugin injection:\n");
> +            tcg_dump_ops(tcg_ctx, logfile, false);
> +            fprintf(logfile, "\n");
> +            qemu_log_unlock(logfile);
> +        }
> +    }
>   
>       /*
>        * While injecting code, we cannot afford to reuse any ebb temps
> @@ -389,7 +346,6 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>               break;
>           }
>       }
> -    pr_ops();
>   }
>   
>   bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
> diff --git a/tcg/tcg.c b/tcg/tcg.c
> index 363a065e28..d248c52e96 100644
> --- a/tcg/tcg.c
> +++ b/tcg/tcg.c
> @@ -2540,6 +2540,15 @@ static const char bswap_flag_name[][6] = {
>       [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
>   };
>   
> +#ifdef CONFIG_PLUGIN
> +static const char * const plugin_from_name[] = {
> +    "from-tb",
> +    "from-insn",
> +    "after-insn",
> +    "after-tb",
> +};
> +#endif
> +
>   static inline bool tcg_regset_single(TCGRegSet d)
>   {
>       return (d & (d - 1)) == 0;
> @@ -2558,7 +2567,7 @@ static inline TCGReg tcg_regset_first(TCGRegSet d)
>   #define ne_fprintf(...) \
>       ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
>   
> -static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
> +void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
>   {
>       char buf[128];
>       TCGOp *op;
> @@ -2714,6 +2723,24 @@ static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
>                       i = k = 1;
>                   }
>                   break;
> +#ifdef CONFIG_PLUGIN
> +            case INDEX_op_plugin_cb:
> +                {
> +                    TCGArg from = op->args[k++];
> +                    const char *name = NULL;
> +
> +                    if (from < ARRAY_SIZE(plugin_from_name)) {
> +                        name = plugin_from_name[from];
> +                    }
> +                    if (name) {
> +                        col += ne_fprintf(f, "%s", name);
> +                    } else {
> +                        col += ne_fprintf(f, "$0x%" TCG_PRIlx, from);
> +                    }
> +                    i = 1;
> +                }
> +                break;
> +#endif
>               default:
>                   i = 0;
>                   break;
> diff --git a/util/log.c b/util/log.c
> index d36c98da0b..6219819855 100644
> --- a/util/log.c
> +++ b/util/log.c
> @@ -466,6 +466,10 @@ const QEMULogItem qemu_log_items[] = {
>         "show micro ops after optimization" },
>       { CPU_LOG_TB_OP_IND, "op_ind",
>         "show micro ops before indirect lowering" },
> +#ifdef CONFIG_PLUGIN
> +    { LOG_TB_OP_PLUGIN, "op_plugin",
> +      "show micro ops before plugin injection" },
> +#endif
>       { CPU_LOG_INT, "int",
>         "show interrupts/exceptions in short format" },
>       { CPU_LOG_EXEC, "exec",

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 14/22] tcg: Remove INDEX_op_plugin_cb_{start,end}
  2024-03-16  1:57 ` [PATCH 14/22] tcg: Remove INDEX_op_plugin_cb_{start,end} Richard Henderson
@ 2024-03-19 13:04   ` Pierrick Bouvier
  0 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 13:04 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:57, Richard Henderson wrote:
> These opcodes are no longer used.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/tcg/tcg-op-common.h |  2 --
>   include/tcg/tcg-opc.h       |  2 --
>   accel/tcg/plugin-gen.c      | 18 ------------------
>   tcg/tcg-op.c                | 10 ----------
>   4 files changed, 32 deletions(-)
> 
> diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h
> index 72b80b20d0..009e2778c5 100644
> --- a/include/tcg/tcg-op-common.h
> +++ b/include/tcg/tcg-op-common.h
> @@ -76,8 +76,6 @@ void tcg_gen_lookup_and_goto_ptr(void);
>   
>   void tcg_gen_plugin_cb(unsigned from);
>   void tcg_gen_plugin_mem_cb(TCGv_i64 addr, unsigned meminfo);
> -void tcg_gen_plugin_cb_start(unsigned from, unsigned type, unsigned wr);
> -void tcg_gen_plugin_cb_end(void);
>   
>   /* 32 bit ops */
>   
> diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h
> index be9e36e386..546eb49c11 100644
> --- a/include/tcg/tcg-opc.h
> +++ b/include/tcg/tcg-opc.h
> @@ -199,8 +199,6 @@ DEF(goto_ptr, 0, 1, 0, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
>   
>   DEF(plugin_cb, 0, 0, 1, TCG_OPF_NOT_PRESENT)
>   DEF(plugin_mem_cb, 0, 1, 1, TCG_OPF_NOT_PRESENT)
> -DEF(plugin_cb_start, 0, 0, 3, TCG_OPF_NOT_PRESENT)
> -DEF(plugin_cb_end, 0, 0, 0, TCG_OPF_NOT_PRESENT)
>   
>   /* Replicate ld/st ops for 32 and 64-bit guest addresses. */
>   DEF(qemu_ld_a32_i32, 1, 1, 1,
> diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
> index b5261edc38..c8f0e0ecaa 100644
> --- a/accel/tcg/plugin-gen.c
> +++ b/accel/tcg/plugin-gen.c
> @@ -58,29 +58,11 @@
>   # define CONFIG_SOFTMMU_GATE 0
>   #endif
>   
> -/*
> - * plugin_cb_start TCG op args[]:
> - * 0: enum plugin_gen_from
> - * 1: enum plugin_gen_cb
> - * 2: set to 1 for mem callback that is a write, 0 otherwise.
> - */
> -
>   enum plugin_gen_from {
>       PLUGIN_GEN_FROM_TB,
>       PLUGIN_GEN_FROM_INSN,
>       PLUGIN_GEN_AFTER_INSN,
>       PLUGIN_GEN_AFTER_TB,
> -    PLUGIN_GEN_N_FROMS,
> -};
> -
> -enum plugin_gen_cb {
> -    PLUGIN_GEN_CB_UDATA,
> -    PLUGIN_GEN_CB_UDATA_R,
> -    PLUGIN_GEN_CB_INLINE,
> -    PLUGIN_GEN_CB_MEM,
> -    PLUGIN_GEN_ENABLE_MEM_HELPER,
> -    PLUGIN_GEN_DISABLE_MEM_HELPER,
> -    PLUGIN_GEN_N_CBS,
>   };
>   

Nice that you could remove this enum sounded duplicated from the similar 
one when registering ops/cbs.

>   static void plugin_gen_empty_callback(enum plugin_gen_from from)
> diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
> index 0ae12fa49d..eff3728622 100644
> --- a/tcg/tcg-op.c
> +++ b/tcg/tcg-op.c
> @@ -322,16 +322,6 @@ void tcg_gen_plugin_mem_cb(TCGv_i64 addr, unsigned meminfo)
>       tcg_gen_op2(INDEX_op_plugin_mem_cb, tcgv_i64_arg(addr), meminfo);
>   }
>   
> -void tcg_gen_plugin_cb_start(unsigned from, unsigned type, unsigned wr)
> -{
> -    tcg_gen_op3(INDEX_op_plugin_cb_start, from, type, wr);
> -}
> -
> -void tcg_gen_plugin_cb_end(void)
> -{
> -    tcg_emit_op(INDEX_op_plugin_cb_end, 0);
> -}
> -
>   /* 32 bit ops */
>   
>   void tcg_gen_discard_i32(TCGv_i32 arg)

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 13/22] tcg: Remove TCG_CALL_PLUGIN
  2024-03-16  1:57 ` [PATCH 13/22] tcg: Remove TCG_CALL_PLUGIN Richard Henderson
@ 2024-03-19 13:06   ` Pierrick Bouvier
  0 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 13:06 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:57, Richard Henderson wrote:
> Since we no longer emit plugin helpers during the initial code
> translation phase, we don't need to specially mark plugin helpers.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/tcg/tcg.h |  2 --
>   plugins/core.c    | 10 ++++------
>   tcg/tcg.c         |  4 +---
>   3 files changed, 5 insertions(+), 11 deletions(-)
> 
> diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
> index 95a7f4d010..df66e8f012 100644
> --- a/include/tcg/tcg.h
> +++ b/include/tcg/tcg.h
> @@ -353,8 +353,6 @@ typedef TCGv_ptr TCGv_env;
>   #define TCG_CALL_NO_SIDE_EFFECTS    0x0004
>   /* Helper is G_NORETURN.  */
>   #define TCG_CALL_NO_RETURN          0x0008
> -/* Helper is part of Plugins.  */
> -#define TCG_CALL_PLUGIN             0x0010
>   
>   /* convenience version of most used call flags */
>   #define TCG_CALL_NO_RWG         TCG_CALL_NO_READ_GLOBALS
> diff --git a/plugins/core.c b/plugins/core.c
> index b0a2e80874..b0615f1e7f 100644
> --- a/plugins/core.c
> +++ b/plugins/core.c
> @@ -339,9 +339,8 @@ void plugin_register_dyn_cb__udata(GArray **arr,
>                                      void *udata)
>   {
>       static TCGHelperInfo info[3] = {
> -        [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG | TCG_CALL_PLUGIN,
> -        [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG | TCG_CALL_PLUGIN,
> -        [QEMU_PLUGIN_CB_RW_REGS].flags = TCG_CALL_PLUGIN,
> +        [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
> +        [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
>           /*
>            * Match qemu_plugin_vcpu_udata_cb_t:
>            *   void (*)(uint32_t, void *)
> @@ -375,9 +374,8 @@ void plugin_register_vcpu_mem_cb(GArray **arr,
>           !__builtin_types_compatible_p(qemu_plugin_meminfo_t, int32_t));
>   
>       static TCGHelperInfo info[3] = {
> -        [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG | TCG_CALL_PLUGIN,
> -        [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG | TCG_CALL_PLUGIN,
> -        [QEMU_PLUGIN_CB_RW_REGS].flags = TCG_CALL_PLUGIN,
> +        [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
> +        [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
>           /*
>            * Match qemu_plugin_vcpu_mem_cb_t:
>            *   void (*)(uint32_t, qemu_plugin_meminfo_t, uint64_t, void *)
> diff --git a/tcg/tcg.c b/tcg/tcg.c
> index 0bf218314b..363a065e28 100644
> --- a/tcg/tcg.c
> +++ b/tcg/tcg.c
> @@ -2269,9 +2269,7 @@ static void tcg_gen_callN(void *func, TCGHelperInfo *info,
>   
>   #ifdef CONFIG_PLUGIN
>       /* Flag helpers that may affect guest state */
> -    if (tcg_ctx->plugin_insn &&
> -        !(info->flags & TCG_CALL_PLUGIN) &&
> -        !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
> +    if (tcg_ctx->plugin_insn && !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
>           tcg_ctx->plugin_insn->calls_helpers = true;
>       }
>   #endif

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 06/22] plugins: Create TCGHelperInfo for all out-of-line callbacks
  2024-03-16  1:57 ` [PATCH 06/22] plugins: Create TCGHelperInfo for all out-of-line callbacks Richard Henderson
@ 2024-03-19 13:12   ` Pierrick Bouvier
  2024-03-19 19:51     ` Richard Henderson
  0 siblings, 1 reply; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 13:12 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:57, Richard Henderson wrote:
> TCGHelperInfo includes the ABI for every function call.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/qemu/plugin.h |  1 +
>   plugins/core.c        | 51 ++++++++++++++++++++++++++++++++++++++-----
>   2 files changed, 46 insertions(+), 6 deletions(-)
> 
> diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
> index 143262dca8..793c44f1f2 100644
> --- a/include/qemu/plugin.h
> +++ b/include/qemu/plugin.h
> @@ -92,6 +92,7 @@ struct qemu_plugin_dyn_cb {
>       union {
>           struct {
>               union qemu_plugin_cb_sig f;
> +            TCGHelperInfo *info;
>           } regular;
>           struct {
>               qemu_plugin_u64 entry;
> diff --git a/plugins/core.c b/plugins/core.c
> index 837c373690..b0a2e80874 100644
> --- a/plugins/core.c
> +++ b/plugins/core.c
> @@ -338,12 +338,26 @@ void plugin_register_dyn_cb__udata(GArray **arr,
>                                      enum qemu_plugin_cb_flags flags,
>                                      void *udata)
>   {
> -    struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
> +    static TCGHelperInfo info[3] = {
> +        [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG | TCG_CALL_PLUGIN,
> +        [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG | TCG_CALL_PLUGIN,
> +        [QEMU_PLUGIN_CB_RW_REGS].flags = TCG_CALL_PLUGIN,
> +        /*
> +         * Match qemu_plugin_vcpu_udata_cb_t:
> +         *   void (*)(uint32_t, void *)
> +

Any chance we could have a static assert ensuring this?
I know it's possible in C11, but I don't know if glib offers something 
for this.

          */
> +        [0 ... 2].typemask = (dh_typemask(void, 0) |
> +                              dh_typemask(i32, 1) |
> +                              dh_typemask(ptr, 2))
> +    };
>   
> +    struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
>       dyn_cb->userp = udata;
> -    /* Note flags are discarded as unused. */
> -    dyn_cb->regular.f.vcpu_udata = cb;
>       dyn_cb->type = PLUGIN_CB_REGULAR;
> +    dyn_cb->regular.f.vcpu_udata = cb;
> +
> +    assert((unsigned)flags < ARRAY_SIZE(info));
> +    dyn_cb->regular.info = &info[flags];
>   }
>   
>   void plugin_register_vcpu_mem_cb(GArray **arr,
> @@ -352,14 +366,39 @@ void plugin_register_vcpu_mem_cb(GArray **arr,
>                                    enum qemu_plugin_mem_rw rw,
>                                    void *udata)
>   {
> -    struct qemu_plugin_dyn_cb *dyn_cb;
> +    /*
> +     * Expect that the underlying type for enum qemu_plugin_meminfo_t
> +     * is either int32_t or uint32_t, aka int or unsigned int.
> +     */
> +    QEMU_BUILD_BUG_ON(
> +        !__builtin_types_compatible_p(qemu_plugin_meminfo_t, uint32_t) &&
> +        !__builtin_types_compatible_p(qemu_plugin_meminfo_t, int32_t));
>   
> -    dyn_cb = plugin_get_dyn_cb(arr);
> +    static TCGHelperInfo info[3] = {
> +        [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG | TCG_CALL_PLUGIN,
> +        [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG | TCG_CALL_PLUGIN,
> +        [QEMU_PLUGIN_CB_RW_REGS].flags = TCG_CALL_PLUGIN,
> +        /*
> +         * Match qemu_plugin_vcpu_mem_cb_t:
> +         *   void (*)(uint32_t, qemu_plugin_meminfo_t, uint64_t, void *)
> +         */
> +        [0 ... 2].typemask =
> +            (dh_typemask(void, 0) |
> +             dh_typemask(i32, 1) |
> +             (__builtin_types_compatible_p(qemu_plugin_meminfo_t, uint32_t)
> +              ? dh_typemask(i32, 2) : dh_typemask(s32, 2)) |
> +             dh_typemask(i64, 3) |
> +             dh_typemask(ptr, 4))
> +    };
> +
> +    struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
>       dyn_cb->userp = udata;
> -    /* Note flags are discarded as unused. */
>       dyn_cb->type = PLUGIN_CB_REGULAR;
>       dyn_cb->rw = rw;
>       dyn_cb->regular.f.vcpu_mem = cb;
> +
> +    assert((unsigned)flags < ARRAY_SIZE(info));
> +    dyn_cb->regular.info = &info[flags];
>   }
>   
>   /*

else,
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 05/22] plugins: Move function pointer in qemu_plugin_dyn_cb
  2024-03-16  1:57 ` [PATCH 05/22] plugins: Move function pointer in qemu_plugin_dyn_cb Richard Henderson
  2024-03-18 10:04   ` Alex Bennée
@ 2024-03-19 13:18   ` Pierrick Bouvier
  2024-03-19 21:30     ` Richard Henderson
  1 sibling, 1 reply; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 13:18 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:57, Richard Henderson wrote:
> The out-of-line function pointer is mutually exclusive
> with inline expansion, so move it into the union.
> Wrap the pointer in a structure named 'regular' to match
> PLUGIN_CB_REGULAR.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/qemu/plugin.h  | 4 +++-
>   accel/tcg/plugin-gen.c | 4 ++--
>   plugins/core.c         | 8 ++++----
>   3 files changed, 9 insertions(+), 7 deletions(-)
> 
> diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
> index 12a96cea2a..143262dca8 100644
> --- a/include/qemu/plugin.h
> +++ b/include/qemu/plugin.h
> @@ -84,13 +84,15 @@ enum plugin_dyn_cb_subtype {
>    * instance of a callback to be called upon the execution of a particular TB.
>    */
>   struct qemu_plugin_dyn_cb {
> -    union qemu_plugin_cb_sig f;
>       void *userp;
>       enum plugin_dyn_cb_subtype type;
>       /* @rw applies to mem callbacks only (both regular and inline) */
>       enum qemu_plugin_mem_rw rw;
>       /* fields specific to each dyn_cb type go here */
>       union {
> +        struct {
> +            union qemu_plugin_cb_sig f;
> +        } regular;
>           struct {
>               qemu_plugin_u64 entry;
>               enum qemu_plugin_op op;

While we are cleaning this, maybe this could be only a union (moving rw 
and userp to fields), and only type + union would be used.
Even if we duplicate userp in regular, and mem_cb, it would be much more 
readable.
For instance, userp is never used by inline operations.

> diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
> index 8028786c7b..c56f104aee 100644
> --- a/accel/tcg/plugin-gen.c
> +++ b/accel/tcg/plugin-gen.c
> @@ -431,7 +431,7 @@ static TCGOp *append_udata_cb(const struct qemu_plugin_dyn_cb *cb,
>       }
>   
>       /* call */
> -    op = copy_call(&begin_op, op, cb->f.vcpu_udata, cb_idx);
> +    op = copy_call(&begin_op, op, cb->regular.f.vcpu_udata, cb_idx);
>   
>       return op;
>   }
> @@ -479,7 +479,7 @@ static TCGOp *append_mem_cb(const struct qemu_plugin_dyn_cb *cb,
>   
>       if (type == PLUGIN_GEN_CB_MEM) {
>           /* call */
> -        op = copy_call(&begin_op, op, cb->f.vcpu_udata, cb_idx);
> +        op = copy_call(&begin_op, op, cb->regular.f.vcpu_udata, cb_idx);
>       }
>   
>       return op;
> diff --git a/plugins/core.c b/plugins/core.c
> index 4487cb7c48..837c373690 100644
> --- a/plugins/core.c
> +++ b/plugins/core.c
> @@ -342,7 +342,7 @@ void plugin_register_dyn_cb__udata(GArray **arr,
>   
>       dyn_cb->userp = udata;
>       /* Note flags are discarded as unused. */
> -    dyn_cb->f.vcpu_udata = cb;
> +    dyn_cb->regular.f.vcpu_udata = cb;
>       dyn_cb->type = PLUGIN_CB_REGULAR;
>   }
>   
> @@ -359,7 +359,7 @@ void plugin_register_vcpu_mem_cb(GArray **arr,
>       /* Note flags are discarded as unused. */
>       dyn_cb->type = PLUGIN_CB_REGULAR;
>       dyn_cb->rw = rw;
> -    dyn_cb->f.generic = cb;
> +    dyn_cb->regular.f.vcpu_mem = cb;
>   }
>   
>   /*
> @@ -511,8 +511,8 @@ void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
>           }
>           switch (cb->type) {
>           case PLUGIN_CB_REGULAR:
> -            cb->f.vcpu_mem(cpu->cpu_index, make_plugin_meminfo(oi, rw),
> -                           vaddr, cb->userp);
> +            cb->regular.f.vcpu_mem(cpu->cpu_index, make_plugin_meminfo(oi, rw),
> +                                   vaddr, cb->userp);
>               break;
>           case PLUGIN_CB_INLINE:
>               exec_inline_op(cb, cpu->cpu_index);


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 08/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_TB
  2024-03-16  1:57 ` [PATCH 08/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_TB Richard Henderson
@ 2024-03-19 13:22   ` Pierrick Bouvier
  2024-03-19 19:57     ` Richard Henderson
  0 siblings, 1 reply; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 13:22 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:57, Richard Henderson wrote:
> By having the qemu_plugin_cb_flags be recorded in the TCGHelperInfo,
> we no longer need to distinguish PLUGIN_CB_REGULAR from
> PLUGIN_CB_REGULAR_R, so place all TB callbacks in the same queue.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   accel/tcg/plugin-gen.c | 96 +++++++++++++++++++++++++-----------------
>   plugins/api.c          |  6 +--
>   2 files changed, 58 insertions(+), 44 deletions(-)
> 
> diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
> index 8fa342b425..f92aa80510 100644
> --- a/accel/tcg/plugin-gen.c
> +++ b/accel/tcg/plugin-gen.c
> @@ -207,6 +207,7 @@ static void plugin_gen_empty_callback(enum plugin_gen_from from)
>   {
>       switch (from) {
>       case PLUGIN_GEN_AFTER_INSN:
> +    case PLUGIN_GEN_FROM_TB:
>           tcg_gen_plugin_cb(from);
>           break;
>       case PLUGIN_GEN_FROM_INSN:
> @@ -216,8 +217,6 @@ static void plugin_gen_empty_callback(enum plugin_gen_from from)
>            */
>           gen_wrapped(from, PLUGIN_GEN_ENABLE_MEM_HELPER,
>                       gen_empty_mem_helper);
> -        /* fall through */
> -    case PLUGIN_GEN_FROM_TB:
>           gen_wrapped(from, PLUGIN_GEN_CB_UDATA, gen_empty_udata_cb_no_rwg);
>           gen_wrapped(from, PLUGIN_GEN_CB_UDATA_R, gen_empty_udata_cb_no_wg);
>           gen_wrapped(from, PLUGIN_GEN_CB_INLINE, gen_empty_inline_cb);
> @@ -632,24 +631,6 @@ void plugin_gen_disable_mem_helpers(void)
>                      offsetof(CPUState, plugin_mem_cbs) - offsetof(ArchCPU, env));
>   }
>   
> -static void plugin_gen_tb_udata(const struct qemu_plugin_tb *ptb,
> -                                TCGOp *begin_op)
> -{
> -    inject_udata_cb(ptb->cbs[PLUGIN_CB_REGULAR], begin_op);
> -}
> -
> -static void plugin_gen_tb_udata_r(const struct qemu_plugin_tb *ptb,
> -                                  TCGOp *begin_op)
> -{
> -    inject_udata_cb(ptb->cbs[PLUGIN_CB_REGULAR_R], begin_op);
> -}
> -
> -static void plugin_gen_tb_inline(const struct qemu_plugin_tb *ptb,
> -                                 TCGOp *begin_op)
> -{
> -    inject_inline_cb(ptb->cbs[PLUGIN_CB_INLINE], begin_op, op_ok);
> -}
> -
>   static void plugin_gen_insn_udata(const struct qemu_plugin_tb *ptb,
>                                     TCGOp *begin_op, int insn_idx)
>   {
> @@ -708,6 +689,41 @@ static void gen_disable_mem_helper(struct qemu_plugin_tb *ptb,
>       }
>   }
>   
> +static void gen_udata_cb(struct qemu_plugin_dyn_cb *cb)
> +{
> +    TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
> +
> +    tcg_gen_ld_i32(cpu_index, tcg_env,
> +                   -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
> +    tcg_gen_call2(cb->regular.f.vcpu_udata, cb->regular.info, NULL,
> +                  tcgv_i32_temp(cpu_index),
> +                  tcgv_ptr_temp(tcg_constant_ptr(cb->userp)));
> +    tcg_temp_free_i32(cpu_index);
> +}
> +
> +static void gen_inline_cb(struct qemu_plugin_dyn_cb *cb)
> +{
> +    GArray *arr = cb->inline_insn.entry.score->data;
> +    size_t offset = cb->inline_insn.entry.offset;
> +    TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
> +    TCGv_i64 val = tcg_temp_ebb_new_i64();
> +    TCGv_ptr ptr = tcg_temp_ebb_new_ptr();
> +
> +    tcg_gen_ld_i32(cpu_index, tcg_env,
> +                   -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
> +    tcg_gen_muli_i32(cpu_index, cpu_index, g_array_get_element_size(arr));
> +    tcg_gen_ext_i32_ptr(ptr, cpu_index);
> +    tcg_temp_free_i32(cpu_index);
> +
> +    tcg_gen_addi_ptr(ptr, ptr, (intptr_t)arr->data);
> +    tcg_gen_ld_i64(val, ptr, offset);
> +    tcg_gen_addi_i64(val, val, cb->inline_insn.imm);
> +    tcg_gen_st_i64(val, ptr, offset);
> +
> +    tcg_temp_free_i64(val);
> +    tcg_temp_free_ptr(ptr);
> +}
> +
>   /* #define DEBUG_PLUGIN_GEN_OPS */
>   static void pr_ops(void)
>   {
> @@ -786,6 +802,8 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>           {
>               enum plugin_gen_from from = op->args[0];
>               struct qemu_plugin_insn *insn = NULL;
> +            const GArray *cbs;
> +            int i, n;
>   
>               if (insn_idx >= 0) {
>                   insn = g_ptr_array_index(plugin_tb->insns, insn_idx);
> @@ -798,6 +816,25 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>                   assert(insn != NULL);
>                   gen_disable_mem_helper(plugin_tb, insn);
>                   break;
> +
> +            case PLUGIN_GEN_FROM_TB:
> +                assert(insn == NULL);
> +
> +                cbs = plugin_tb->cbs[PLUGIN_CB_REGULAR];
> +                for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
> +                    struct qemu_plugin_dyn_cb *cb =
> +                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> +                    gen_udata_cb(cb);
> +                }
> +
> +                cbs = plugin_tb->cbs[PLUGIN_CB_INLINE];
> +                for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
> +                    struct qemu_plugin_dyn_cb *cb =
> +                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> +                    gen_inline_cb(cb);
> +                }
> +                break;
> +

Maybe I am missing something, but couldn't we simply mix all cbs 
possible. This way, the order mentioned by user when registering is the 
only one that matters, and he can select to mix callbacks and inline ops 
freely.
Just checking the type of callback would be needed to know which gen_* 
fn should be used.

>               default:
>                   g_assert_not_reached();
>               }
> @@ -813,25 +850,6 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>               enum plugin_gen_cb type = op->args[1];
>   
>               switch (from) {
> -            case PLUGIN_GEN_FROM_TB:
> -            {
> -                g_assert(insn_idx == -1);
> -
> -                switch (type) {
> -                case PLUGIN_GEN_CB_UDATA:
> -                    plugin_gen_tb_udata(plugin_tb, op);
> -                    break;
> -                case PLUGIN_GEN_CB_UDATA_R:
> -                    plugin_gen_tb_udata_r(plugin_tb, op);
> -                    break;
> -                case PLUGIN_GEN_CB_INLINE:
> -                    plugin_gen_tb_inline(plugin_tb, op);
> -                    break;
> -                default:
> -                    g_assert_not_reached();
> -                }
> -                break;
> -            }
>               case PLUGIN_GEN_FROM_INSN:
>               {
>                   g_assert(insn_idx >= 0);
> diff --git a/plugins/api.c b/plugins/api.c
> index 8fa5a600ac..5d119e8049 100644
> --- a/plugins/api.c
> +++ b/plugins/api.c
> @@ -92,11 +92,7 @@ void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
>                                             void *udata)
>   {
>       if (!tb->mem_only) {
> -        int index = flags == QEMU_PLUGIN_CB_R_REGS ||
> -                    flags == QEMU_PLUGIN_CB_RW_REGS ?
> -                    PLUGIN_CB_REGULAR_R : PLUGIN_CB_REGULAR;
> -
> -        plugin_register_dyn_cb__udata(&tb->cbs[index],
> +        plugin_register_dyn_cb__udata(&tb->cbs[PLUGIN_CB_REGULAR],
>                                         cb, flags, udata);
>       }
>   }


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 15/22] plugins: Simplify callback queues
  2024-03-16  1:57 ` [PATCH 15/22] plugins: Simplify callback queues Richard Henderson
@ 2024-03-19 13:28   ` Pierrick Bouvier
  0 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 13:28 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:57, Richard Henderson wrote:
> We have qemu_plugin_dyn_cb.type to differentiate the various
> callback types, so we do not need to keep them in separate queues.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/qemu/plugin.h  | 35 ++++++----------
>   accel/tcg/plugin-gen.c | 90 ++++++++++++++++++++++--------------------
>   plugins/api.c          | 18 +++------
>   3 files changed, 65 insertions(+), 78 deletions(-)
> 
> diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
> index ee1c1b174a..cf9758be55 100644
> --- a/include/qemu/plugin.h
> +++ b/include/qemu/plugin.h
> @@ -66,15 +66,8 @@ union qemu_plugin_cb_sig {
>   };
>   
>   enum plugin_dyn_cb_type {
> -    PLUGIN_CB_INSN,
> -    PLUGIN_CB_MEM,
> -    PLUGIN_N_CB_TYPES,
> -};
> -
> -enum plugin_dyn_cb_subtype {
>       PLUGIN_CB_REGULAR,
>       PLUGIN_CB_INLINE,
> -    PLUGIN_N_CB_SUBTYPES,
>   };
>   
>   /*
> @@ -84,7 +77,7 @@ enum plugin_dyn_cb_subtype {
>    */
>   struct qemu_plugin_dyn_cb {
>       void *userp;
> -    enum plugin_dyn_cb_subtype type;
> +    enum plugin_dyn_cb_type type;
>       /* @rw applies to mem callbacks only (both regular and inline) */
>       enum qemu_plugin_mem_rw rw;
>       /* fields specific to each dyn_cb type go here */
> @@ -106,7 +99,8 @@ struct qemu_plugin_insn {
>       GByteArray *data;
>       uint64_t vaddr;
>       void *haddr;
> -    GArray *cbs[PLUGIN_N_CB_TYPES][PLUGIN_N_CB_SUBTYPES];
> +    GArray *insn_cbs;
> +    GArray *mem_cbs;
>       bool calls_helpers;
>   
>       /* if set, the instruction calls helpers that might access guest memory */
> @@ -135,16 +129,9 @@ static inline void qemu_plugin_insn_cleanup_fn(gpointer data)
>   
>   static inline struct qemu_plugin_insn *qemu_plugin_insn_alloc(void)
>   {
> -    int i, j;
>       struct qemu_plugin_insn *insn = g_new0(struct qemu_plugin_insn, 1);
> -    insn->data = g_byte_array_sized_new(4);
>   
> -    for (i = 0; i < PLUGIN_N_CB_TYPES; i++) {
> -        for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) {
> -            insn->cbs[i][j] = g_array_new(false, false,
> -                                          sizeof(struct qemu_plugin_dyn_cb));
> -        }
> -    }
> +    insn->data = g_byte_array_sized_new(4);
>       return insn;
>   }
>   
> @@ -161,7 +148,7 @@ struct qemu_plugin_tb {
>       /* if set, the TB calls helpers that might access guest memory */
>       bool mem_helper;
>   
> -    GArray *cbs[PLUGIN_N_CB_SUBTYPES];
> +    GArray *cbs;
>   };
>   
>   /**
> @@ -174,22 +161,22 @@ struct qemu_plugin_insn *qemu_plugin_tb_insn_get(struct qemu_plugin_tb *tb,
>                                                    uint64_t pc)
>   {
>       struct qemu_plugin_insn *insn;
> -    int i, j;
>   
>       if (unlikely(tb->n == tb->insns->len)) {
>           struct qemu_plugin_insn *new_insn = qemu_plugin_insn_alloc();
>           g_ptr_array_add(tb->insns, new_insn);
>       }
> +
>       insn = g_ptr_array_index(tb->insns, tb->n++);
>       g_byte_array_set_size(insn->data, 0);
>       insn->calls_helpers = false;
>       insn->mem_helper = false;
>       insn->vaddr = pc;
> -
> -    for (i = 0; i < PLUGIN_N_CB_TYPES; i++) {
> -        for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) {
> -            g_array_set_size(insn->cbs[i][j], 0);
> -        }
> +    if (insn->insn_cbs) {
> +        g_array_set_size(insn->insn_cbs, 0);
> +    }
> +    if (insn->mem_cbs) {
> +        g_array_set_size(insn->mem_cbs, 0);
>       }
>   
>       return insn;
> diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
> index c8f0e0ecaa..669e343cfb 100644
> --- a/accel/tcg/plugin-gen.c
> +++ b/accel/tcg/plugin-gen.c
> @@ -89,9 +89,8 @@ void plugin_gen_disable_mem_helpers(void)
>   static void gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
>                                     struct qemu_plugin_insn *insn)
>   {
> -    GArray *cbs[2];
>       GArray *arr;
> -    size_t n_cbs;
> +    size_t len;
>   
>       /*
>        * Tracking memory accesses performed from helpers requires extra work.
> @@ -110,22 +109,25 @@ static void gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
>           return;
>       }
>   
> -    cbs[0] = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR];
> -    cbs[1] = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
> -    n_cbs = cbs[0]->len + cbs[1]->len;
> -
> -    if (n_cbs == 0) {
> +    if (!insn->mem_cbs || !insn->mem_cbs->len) {
>           insn->mem_helper = false;
>           return;
>       }
>       insn->mem_helper = true;
>       ptb->mem_helper = true;
>   
> +    /*
> +     * TODO: It seems like we should be able to use ref/unref
> +     * to avoid needing to actually copy this array.
> +     * Alternately, perhaps we could allocate new memory adjacent
> +     * to the TranslationBlock itself, so that we do not have to
> +     * actively manage the lifetime after this.
> +     */
> +    len = insn->mem_cbs->len;
>       arr = g_array_sized_new(false, false,
> -                            sizeof(struct qemu_plugin_dyn_cb), n_cbs);
> -    g_array_append_vals(arr, cbs[0]->data, cbs[0]->len);
> -    g_array_append_vals(arr, cbs[1]->data, cbs[1]->len);
> -
> +                            sizeof(struct qemu_plugin_dyn_cb), len);
> +    memcpy(arr->data, insn->mem_cbs->data,
> +           len * sizeof(struct qemu_plugin_dyn_cb));
>       qemu_plugin_add_dyn_cb_arr(arr);
>   
>       tcg_gen_st_ptr(tcg_constant_ptr((intptr_t)arr), tcg_env,
> @@ -294,18 +296,21 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>               case PLUGIN_GEN_FROM_TB:
>                   assert(insn == NULL);
>   
> -                cbs = plugin_tb->cbs[PLUGIN_CB_REGULAR];
> +                cbs = plugin_tb->cbs;
>                   for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
>                       struct qemu_plugin_dyn_cb *cb =
>                           &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> -                    gen_udata_cb(cb);
> -                }
>   
> -                cbs = plugin_tb->cbs[PLUGIN_CB_INLINE];
> -                for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
> -                    struct qemu_plugin_dyn_cb *cb =
> -                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> -                    gen_inline_cb(cb);
> +                    switch (cb->type) {
> +                    case PLUGIN_CB_REGULAR:
> +                        gen_udata_cb(cb);
> +                        break;
> +                    case PLUGIN_CB_INLINE:
> +                        gen_inline_cb(cb);
> +                        break;
> +                    default:
> +                        g_assert_not_reached();
> +                    }
>                   }
>                   break;
>   
> @@ -314,18 +319,21 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>   
>                   gen_enable_mem_helper(plugin_tb, insn);
>   
> -                cbs = insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR];
> +                cbs = insn->insn_cbs;
>                   for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
>                       struct qemu_plugin_dyn_cb *cb =
>                           &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> -                    gen_udata_cb(cb);
> -                }
>   
> -                cbs = insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE];
> -                for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
> -                    struct qemu_plugin_dyn_cb *cb =
> -                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> -                    gen_inline_cb(cb);
> +                    switch (cb->type) {
> +                    case PLUGIN_CB_REGULAR:
> +                        gen_udata_cb(cb);
> +                        break;
> +                    case PLUGIN_CB_INLINE:
> +                        gen_inline_cb(cb);
> +                        break;
> +                    default:
> +                        g_assert_not_reached();
> +                    }
>                   }
>                   break;
>   
> @@ -352,21 +360,22 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>   
>               tcg_ctx->emit_before_op = op;
>   
> -            cbs = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR];
> +            cbs = insn->mem_cbs;
>               for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
>                   struct qemu_plugin_dyn_cb *cb =
>                       &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> -                if (cb->rw & rw) {
> -                    gen_mem_cb(cb, meminfo, addr);
> -                }
> -            }
>   
> -            cbs = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
> -            for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
> -                struct qemu_plugin_dyn_cb *cb =
> -                    &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
>                   if (cb->rw & rw) {
> -                    gen_inline_cb(cb);
> +                    switch (cb->type) {
> +                    case PLUGIN_CB_REGULAR:
> +                        gen_mem_cb(cb, meminfo, addr);
> +                        break;
> +                    case PLUGIN_CB_INLINE:
> +                        gen_inline_cb(cb);
> +                        break;
> +                    default:
> +                        g_assert_not_reached();
> +                    }
>                   }
>               }
>   
> @@ -390,13 +399,10 @@ bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
>   
>       if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_state->event_mask)) {
>           struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
> -        int i;
>   
>           /* reset callbacks */
> -        for (i = 0; i < PLUGIN_N_CB_SUBTYPES; i++) {
> -            if (ptb->cbs[i]) {
> -                g_array_set_size(ptb->cbs[i], 0);
> -            }
> +        if (ptb->cbs) {
> +            g_array_set_size(ptb->cbs, 0);
>           }
>           ptb->n = 0;
>   
> diff --git a/plugins/api.c b/plugins/api.c
> index 29cce2d97c..3912c9cc8f 100644
> --- a/plugins/api.c
> +++ b/plugins/api.c
> @@ -92,8 +92,7 @@ void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
>                                             void *udata)
>   {
>       if (!tb->mem_only) {
> -        plugin_register_dyn_cb__udata(&tb->cbs[PLUGIN_CB_REGULAR],
> -                                      cb, flags, udata);
> +        plugin_register_dyn_cb__udata(&tb->cbs, cb, flags, udata);
>       }
>   }
>   
> @@ -104,8 +103,7 @@ void qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
>       uint64_t imm)
>   {
>       if (!tb->mem_only) {
> -        plugin_register_inline_op_on_entry(
> -            &tb->cbs[PLUGIN_CB_INLINE], 0, op, entry, imm);
> +        plugin_register_inline_op_on_entry(&tb->cbs, 0, op, entry, imm);
>       }
>   }
>   
> @@ -115,8 +113,7 @@ void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
>                                               void *udata)
>   {
>       if (!insn->mem_only) {
> -        plugin_register_dyn_cb__udata(
> -            &insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR], cb, flags, udata);
> +        plugin_register_dyn_cb__udata(&insn->insn_cbs, cb, flags, udata);
>       }
>   }
>   
> @@ -127,8 +124,7 @@ void qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
>       uint64_t imm)
>   {
>       if (!insn->mem_only) {
> -        plugin_register_inline_op_on_entry(
> -            &insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE], 0, op, entry, imm);
> +        plugin_register_inline_op_on_entry(&insn->insn_cbs, 0, op, entry, imm);
>       }
>   }
>   
> @@ -143,8 +139,7 @@ void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
>                                         enum qemu_plugin_mem_rw rw,
>                                         void *udata)
>   {
> -    plugin_register_vcpu_mem_cb(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR],
> -                                cb, flags, rw, udata);
> +    plugin_register_vcpu_mem_cb(&insn->mem_cbs, cb, flags, rw, udata);
>   }
>   
>   void qemu_plugin_register_vcpu_mem_inline_per_vcpu(
> @@ -154,8 +149,7 @@ void qemu_plugin_register_vcpu_mem_inline_per_vcpu(
>       qemu_plugin_u64 entry,
>       uint64_t imm)
>   {
> -    plugin_register_inline_op_on_entry(
> -        &insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE], rw, op, entry, imm);
> +    plugin_register_inline_op_on_entry(&insn->mem_cbs, rw, op, entry, imm);
>   }
>   
>   void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,

Great, that makes sense.
I expressed in another patch why we didn't mix all cbs together, so good 
to see this here.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 16/22] plugins: Introduce PLUGIN_CB_MEM_REGULAR
  2024-03-16  1:57 ` [PATCH 16/22] plugins: Introduce PLUGIN_CB_MEM_REGULAR Richard Henderson
@ 2024-03-19 13:28   ` Pierrick Bouvier
  0 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 13:28 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:57, Richard Henderson wrote:
> Use different enumerators for vcpu_udata and vcpu_mem callbacks.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/qemu/plugin.h  | 1 +
>   accel/tcg/plugin-gen.c | 2 +-
>   plugins/core.c         | 4 ++--
>   3 files changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
> index cf9758be55..34498da717 100644
> --- a/include/qemu/plugin.h
> +++ b/include/qemu/plugin.h
> @@ -67,6 +67,7 @@ union qemu_plugin_cb_sig {
>   
>   enum plugin_dyn_cb_type {
>       PLUGIN_CB_REGULAR,
> +    PLUGIN_CB_MEM_REGULAR,
>       PLUGIN_CB_INLINE,
>   };
>   
> diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
> index 669e343cfb..6f0731b479 100644
> --- a/accel/tcg/plugin-gen.c
> +++ b/accel/tcg/plugin-gen.c
> @@ -367,7 +367,7 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>   
>                   if (cb->rw & rw) {
>                       switch (cb->type) {
> -                    case PLUGIN_CB_REGULAR:
> +                    case PLUGIN_CB_MEM_REGULAR:
>                           gen_mem_cb(cb, meminfo, addr);
>                           break;
>                       case PLUGIN_CB_INLINE:
> diff --git a/plugins/core.c b/plugins/core.c
> index b0615f1e7f..0213513ec6 100644
> --- a/plugins/core.c
> +++ b/plugins/core.c
> @@ -391,7 +391,7 @@ void plugin_register_vcpu_mem_cb(GArray **arr,
>   
>       struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
>       dyn_cb->userp = udata;
> -    dyn_cb->type = PLUGIN_CB_REGULAR;
> +    dyn_cb->type = PLUGIN_CB_MEM_REGULAR;
>       dyn_cb->rw = rw;
>       dyn_cb->regular.f.vcpu_mem = cb;
>   
> @@ -547,7 +547,7 @@ void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
>                   break;
>           }
>           switch (cb->type) {
> -        case PLUGIN_CB_REGULAR:
> +        case PLUGIN_CB_MEM_REGULAR:
>               cb->regular.f.vcpu_mem(cpu->cpu_index, make_plugin_meminfo(oi, rw),
>                                      vaddr, cb->userp);
>               break;

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 18/22] plugins: Split out common cb expanders
  2024-03-16  1:57 ` [PATCH 18/22] plugins: Split out common cb expanders Richard Henderson
@ 2024-03-19 13:29   ` Pierrick Bouvier
  0 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 13:29 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:57, Richard Henderson wrote:
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   accel/tcg/plugin-gen.c | 84 +++++++++++++++++++++---------------------
>   1 file changed, 41 insertions(+), 43 deletions(-)
> 
> diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
> index 10d917abd3..28414c4ff1 100644
> --- a/accel/tcg/plugin-gen.c
> +++ b/accel/tcg/plugin-gen.c
> @@ -194,6 +194,37 @@ static void gen_mem_cb(struct qemu_plugin_dyn_cb *cb,
>       tcg_temp_free_i32(cpu_index);
>   }
>   
> +static void inject_cb(struct qemu_plugin_dyn_cb *cb)
> +
> +{
> +    switch (cb->type) {
> +    case PLUGIN_CB_REGULAR:
> +        gen_udata_cb(cb);
> +        break;
> +    case PLUGIN_CB_INLINE:
> +        gen_inline_cb(cb);
> +        break;
> +    default:
> +        g_assert_not_reached();
> +    }
> +}
> +
> +static void inject_mem_cb(struct qemu_plugin_dyn_cb *cb,
> +                          enum qemu_plugin_mem_rw rw,
> +                          qemu_plugin_meminfo_t meminfo, TCGv_i64 addr)
> +{
> +    if (cb->rw & rw) {
> +        switch (cb->type) {
> +        case PLUGIN_CB_MEM_REGULAR:
> +            gen_mem_cb(cb, meminfo, addr);
> +            break;
> +        default:
> +            inject_cb(cb);
> +            break;
> +        }
> +    }
> +}
> +
>   static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>   {
>       TCGOp *op, *next;
> @@ -255,19 +286,8 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>   
>                   cbs = plugin_tb->cbs;
>                   for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
> -                    struct qemu_plugin_dyn_cb *cb =
> -                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> -
> -                    switch (cb->type) {
> -                    case PLUGIN_CB_REGULAR:
> -                        gen_udata_cb(cb);
> -                        break;
> -                    case PLUGIN_CB_INLINE:
> -                        gen_inline_cb(cb);
> -                        break;
> -                    default:
> -                        g_assert_not_reached();
> -                    }
> +                    inject_cb(
> +                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i));
>                   }
>                   break;
>   
> @@ -278,19 +298,8 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>   
>                   cbs = insn->insn_cbs;
>                   for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
> -                    struct qemu_plugin_dyn_cb *cb =
> -                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> -
> -                    switch (cb->type) {
> -                    case PLUGIN_CB_REGULAR:
> -                        gen_udata_cb(cb);
> -                        break;
> -                    case PLUGIN_CB_INLINE:
> -                        gen_inline_cb(cb);
> -                        break;
> -                    default:
> -                        g_assert_not_reached();
> -                    }
> +                    inject_cb(
> +                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i));
>                   }
>                   break;
>   
> @@ -307,33 +316,22 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>           {
>               TCGv_i64 addr = temp_tcgv_i64(arg_temp(op->args[0]));
>               qemu_plugin_meminfo_t meminfo = op->args[1];
> +            enum qemu_plugin_mem_rw rw =
> +                (qemu_plugin_mem_is_store(meminfo)
> +                 ? QEMU_PLUGIN_MEM_W : QEMU_PLUGIN_MEM_R);
>               struct qemu_plugin_insn *insn;
>               const GArray *cbs;
> -            int i, n, rw;
> +            int i, n;
>   
>               assert(insn_idx >= 0);
>               insn = g_ptr_array_index(plugin_tb->insns, insn_idx);
> -            rw = qemu_plugin_mem_is_store(meminfo) ? 2 : 1;
>   
>               tcg_ctx->emit_before_op = op;
>   
>               cbs = insn->mem_cbs;
>               for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
> -                struct qemu_plugin_dyn_cb *cb =
> -                    &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> -
> -                if (cb->rw & rw) {
> -                    switch (cb->type) {
> -                    case PLUGIN_CB_MEM_REGULAR:
> -                        gen_mem_cb(cb, meminfo, addr);
> -                        break;
> -                    case PLUGIN_CB_INLINE:
> -                        gen_inline_cb(cb);
> -                        break;
> -                    default:
> -                        g_assert_not_reached();
> -                    }
> -                }
> +                inject_mem_cb(&g_array_index(cbs, struct qemu_plugin_dyn_cb, i),
> +                              rw, meminfo, addr);
>               }
>   
>               tcg_ctx->emit_before_op = NULL;

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 19/22] plugins: Merge qemu_plugin_tb_insn_get to plugin-gen.c
  2024-03-16  1:57 ` [PATCH 19/22] plugins: Merge qemu_plugin_tb_insn_get to plugin-gen.c Richard Henderson
@ 2024-03-19 13:30   ` Pierrick Bouvier
  0 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 13:30 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:57, Richard Henderson wrote:
> Merge qemu_plugin_insn_alloc and qemu_plugin_tb_insn_get into
> plugin_gen_insn_start, since it is used nowhere else.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/qemu/plugin.h  | 39 ---------------------------------------
>   accel/tcg/plugin-gen.c | 39 ++++++++++++++++++++++++++++++++-------
>   2 files changed, 32 insertions(+), 46 deletions(-)
> 
> diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
> index 34498da717..07b1755990 100644
> --- a/include/qemu/plugin.h
> +++ b/include/qemu/plugin.h
> @@ -128,14 +128,6 @@ static inline void qemu_plugin_insn_cleanup_fn(gpointer data)
>       g_byte_array_free(insn->data, true);
>   }
>   
> -static inline struct qemu_plugin_insn *qemu_plugin_insn_alloc(void)
> -{
> -    struct qemu_plugin_insn *insn = g_new0(struct qemu_plugin_insn, 1);
> -
> -    insn->data = g_byte_array_sized_new(4);
> -    return insn;
> -}
> -
>   /* Internal context for this TranslationBlock */
>   struct qemu_plugin_tb {
>       GPtrArray *insns;
> @@ -152,37 +144,6 @@ struct qemu_plugin_tb {
>       GArray *cbs;
>   };
>   
> -/**
> - * qemu_plugin_tb_insn_get(): get next plugin record for translation.
> - * @tb: the internal tb context
> - * @pc: address of instruction
> - */
> -static inline
> -struct qemu_plugin_insn *qemu_plugin_tb_insn_get(struct qemu_plugin_tb *tb,
> -                                                 uint64_t pc)
> -{
> -    struct qemu_plugin_insn *insn;
> -
> -    if (unlikely(tb->n == tb->insns->len)) {
> -        struct qemu_plugin_insn *new_insn = qemu_plugin_insn_alloc();
> -        g_ptr_array_add(tb->insns, new_insn);
> -    }
> -
> -    insn = g_ptr_array_index(tb->insns, tb->n++);
> -    g_byte_array_set_size(insn->data, 0);
> -    insn->calls_helpers = false;
> -    insn->mem_helper = false;
> -    insn->vaddr = pc;
> -    if (insn->insn_cbs) {
> -        g_array_set_size(insn->insn_cbs, 0);
> -    }
> -    if (insn->mem_cbs) {
> -        g_array_set_size(insn->mem_cbs, 0);
> -    }
> -
> -    return insn;
> -}
> -
>   /**
>    * struct CPUPluginState - per-CPU state for plugins
>    * @event_mask: plugin event bitmap. Modified only via async work.
> diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
> index 28414c4ff1..70914c3bf8 100644
> --- a/accel/tcg/plugin-gen.c
> +++ b/accel/tcg/plugin-gen.c
> @@ -380,11 +380,34 @@ bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
>   void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
>   {
>       struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
> -    struct qemu_plugin_insn *pinsn;
> +    struct qemu_plugin_insn *insn;
> +    size_t n = db->num_insns;
> +    vaddr pc;
>   
> -    pinsn = qemu_plugin_tb_insn_get(ptb, db->pc_next);
> -    tcg_ctx->plugin_insn = pinsn;
> -    plugin_gen_empty_callback(PLUGIN_GEN_FROM_INSN);
> +    assert(n >= 1);
> +    ptb->n = n;
> +    if (n <= ptb->insns->len) {
> +        insn = g_ptr_array_index(ptb->insns, n - 1);
> +        g_byte_array_set_size(insn->data, 0);
> +    } else {
> +        assert(n - 1 == ptb->insns->len);
> +        insn = g_new0(struct qemu_plugin_insn, 1);
> +        insn->data = g_byte_array_sized_new(4);
> +        g_ptr_array_add(ptb->insns, insn);
> +    }
> +
> +    tcg_ctx->plugin_insn = insn;
> +    insn->calls_helpers = false;
> +    insn->mem_helper = false;
> +    if (insn->insn_cbs) {
> +        g_array_set_size(insn->insn_cbs, 0);
> +    }
> +    if (insn->mem_cbs) {
> +        g_array_set_size(insn->mem_cbs, 0);
> +    }
> +
> +    pc = db->pc_next;
> +    insn->vaddr = pc;
>   
>       /*
>        * Detect page crossing to get the new host address.
> @@ -392,16 +415,18 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
>        * fetching instructions from a region not backed by RAM.
>        */
>       if (ptb->haddr1 == NULL) {
> -        pinsn->haddr = NULL;
> +        insn->haddr = NULL;
>       } else if (is_same_page(db, db->pc_next)) {
> -        pinsn->haddr = ptb->haddr1 + pinsn->vaddr - ptb->vaddr;
> +        insn->haddr = ptb->haddr1 + pc - ptb->vaddr;
>       } else {
>           if (ptb->vaddr2 == -1) {
>               ptb->vaddr2 = TARGET_PAGE_ALIGN(db->pc_first);
>               get_page_addr_code_hostp(cpu_env(cpu), ptb->vaddr2, &ptb->haddr2);
>           }
> -        pinsn->haddr = ptb->haddr2 + pinsn->vaddr - ptb->vaddr2;
> +        insn->haddr = ptb->haddr2 + pc - ptb->vaddr2;
>       }
> +
> +    plugin_gen_empty_callback(PLUGIN_GEN_FROM_INSN);
>   }
>   
>   void plugin_gen_insn_end(void)

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 07/22] plugins: Use emit_before_op for PLUGIN_GEN_AFTER_INSN
  2024-03-16  1:57 ` [PATCH 07/22] plugins: Use emit_before_op for PLUGIN_GEN_AFTER_INSN Richard Henderson
@ 2024-03-19 13:32   ` Pierrick Bouvier
  2024-03-19 19:56     ` Richard Henderson
  0 siblings, 1 reply; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 13:32 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:57, Richard Henderson wrote:
> Introduce a new plugin_cb op and migrate one operation.
> By using emit_before_op, we do not need to emit opcodes
> early and modify them later -- we can simply emit the
> final set of opcodes once.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/tcg/tcg-op-common.h |  1 +
>   include/tcg/tcg-opc.h       |  1 +
>   accel/tcg/plugin-gen.c      | 74 +++++++++++++++++++++----------------
>   tcg/tcg-op.c                |  5 +++
>   4 files changed, 50 insertions(+), 31 deletions(-)
> 
> diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h
> index 2d932a515e..9de5a7f280 100644
> --- a/include/tcg/tcg-op-common.h
> +++ b/include/tcg/tcg-op-common.h
> @@ -74,6 +74,7 @@ void tcg_gen_goto_tb(unsigned idx);
>    */
>   void tcg_gen_lookup_and_goto_ptr(void);
>   
> +void tcg_gen_plugin_cb(unsigned from);
>   void tcg_gen_plugin_cb_start(unsigned from, unsigned type, unsigned wr);
>   void tcg_gen_plugin_cb_end(void);
>   
> diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h
> index b80227fa1c..3b7cb2bce1 100644
> --- a/include/tcg/tcg-opc.h
> +++ b/include/tcg/tcg-opc.h
> @@ -197,6 +197,7 @@ DEF(exit_tb, 0, 0, 1, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
>   DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
>   DEF(goto_ptr, 0, 1, 0, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
>   
> +DEF(plugin_cb, 0, 0, 1, TCG_OPF_NOT_PRESENT)
>   DEF(plugin_cb_start, 0, 0, 3, TCG_OPF_NOT_PRESENT)
>   DEF(plugin_cb_end, 0, 0, 0, TCG_OPF_NOT_PRESENT)
>   
> diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
> index c56f104aee..8fa342b425 100644
> --- a/accel/tcg/plugin-gen.c
> +++ b/accel/tcg/plugin-gen.c
> @@ -207,8 +207,7 @@ static void plugin_gen_empty_callback(enum plugin_gen_from from)
>   {
>       switch (from) {
>       case PLUGIN_GEN_AFTER_INSN:
> -        gen_wrapped(from, PLUGIN_GEN_DISABLE_MEM_HELPER,
> -                    gen_empty_mem_helper);
> +        tcg_gen_plugin_cb(from);
>           break;
>       case PLUGIN_GEN_FROM_INSN:
>           /*
> @@ -614,16 +613,6 @@ static void inject_mem_enable_helper(struct qemu_plugin_tb *ptb,
>       inject_mem_helper(begin_op, arr);
>   }
>   
> -static void inject_mem_disable_helper(struct qemu_plugin_insn *plugin_insn,
> -                                      TCGOp *begin_op)
> -{
> -    if (likely(!plugin_insn->mem_helper)) {
> -        rm_ops(begin_op);
> -        return;
> -    }
> -    inject_mem_helper(begin_op, NULL);
> -}
> -
>   /* called before finishing a TB with exit_tb, goto_tb or goto_ptr */
>   void plugin_gen_disable_mem_helpers(void)
>   {
> @@ -709,11 +698,14 @@ static void plugin_gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
>       inject_mem_enable_helper(ptb, insn, begin_op);
>   }
>   
> -static void plugin_gen_disable_mem_helper(struct qemu_plugin_tb *ptb,
> -                                          TCGOp *begin_op, int insn_idx)
> +static void gen_disable_mem_helper(struct qemu_plugin_tb *ptb,
> +                                   struct qemu_plugin_insn *insn)
>   {
> -    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
> -    inject_mem_disable_helper(insn, begin_op);
> +    if (insn->mem_helper) {
> +        tcg_gen_st_ptr(tcg_constant_ptr(0), tcg_env,
> +                       offsetof(CPUState, plugin_mem_cbs) -
> +                       offsetof(ArchCPU, env));
> +    }
>   }
>   
>   /* #define DEBUG_PLUGIN_GEN_OPS */
> @@ -772,16 +764,49 @@ static void pr_ops(void)
>   
>   static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>   {
> -    TCGOp *op;
> +    TCGOp *op, *next;
>       int insn_idx = -1;
>   
>       pr_ops();
>   
> -    QTAILQ_FOREACH(op, &tcg_ctx->ops, link) {
> +    /*
> +     * While injecting code, we cannot afford to reuse any ebb temps
> +     * that might be live within the existing opcode stream.
> +     * The simplest solution is to release them all and create new.
> +     */
> +    memset(tcg_ctx->free_temps, 0, sizeof(tcg_ctx->free_temps));
> +

Not an expert at this, but wouldn't that break an existing TB that 
already has some ops on those temps?

> +    QTAILQ_FOREACH_SAFE(op, &tcg_ctx->ops, link, next) {
>           switch (op->opc) {
>           case INDEX_op_insn_start:
>               insn_idx++;
>               break;
> +
> +        case INDEX_op_plugin_cb:
> +        {
> +            enum plugin_gen_from from = op->args[0];
> +            struct qemu_plugin_insn *insn = NULL;
> +
> +            if (insn_idx >= 0) {
> +                insn = g_ptr_array_index(plugin_tb->insns, insn_idx);
> +            }
> +
> +            tcg_ctx->emit_before_op = op;
> +
> +            switch (from) {
> +            case PLUGIN_GEN_AFTER_INSN:
> +                assert(insn != NULL);
> +                gen_disable_mem_helper(plugin_tb, insn);
> +                break;
> +            default:
> +                g_assert_not_reached();
> +            }
> +
> +            tcg_ctx->emit_before_op = NULL;
> +            tcg_op_remove(tcg_ctx, op);
> +            break;
> +        }
> +
>           case INDEX_op_plugin_cb_start:
>           {
>               enum plugin_gen_from from = op->args[0];
> @@ -846,19 +871,6 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>   
>                   break;
>               }
> -            case PLUGIN_GEN_AFTER_INSN:
> -            {
> -                g_assert(insn_idx >= 0);
> -
> -                switch (type) {
> -                case PLUGIN_GEN_DISABLE_MEM_HELPER:
> -                    plugin_gen_disable_mem_helper(plugin_tb, op, insn_idx);
> -                    break;
> -                default:
> -                    g_assert_not_reached();
> -                }
> -                break;
> -            }
>               default:
>                   g_assert_not_reached();
>               }
> diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
> index aa6bc6f57d..0f2026c91c 100644
> --- a/tcg/tcg-op.c
> +++ b/tcg/tcg-op.c
> @@ -312,6 +312,11 @@ void tcg_gen_mb(TCGBar mb_type)
>       }
>   }
>   
> +void tcg_gen_plugin_cb(unsigned from)
> +{
> +    tcg_gen_op1(INDEX_op_plugin_cb, from);
> +}
> +
>   void tcg_gen_plugin_cb_start(unsigned from, unsigned type, unsigned wr)
>   {
>       tcg_gen_op3(INDEX_op_plugin_cb_start, from, type, wr);


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 09/22] plugins: Add PLUGIN_GEN_AFTER_TB
  2024-03-16  1:57 ` [PATCH 09/22] plugins: Add PLUGIN_GEN_AFTER_TB Richard Henderson
@ 2024-03-19 13:33   ` Pierrick Bouvier
  0 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 13:33 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:57, Richard Henderson wrote:
> Delay test of plugin_tb->mem_helper until the inject pass.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   accel/tcg/plugin-gen.c | 37 ++++++++++++++++---------------------
>   1 file changed, 16 insertions(+), 21 deletions(-)
> 
> diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
> index f92aa80510..aa74e580bd 100644
> --- a/accel/tcg/plugin-gen.c
> +++ b/accel/tcg/plugin-gen.c
> @@ -75,6 +75,7 @@ enum plugin_gen_from {
>       PLUGIN_GEN_FROM_INSN,
>       PLUGIN_GEN_FROM_MEM,
>       PLUGIN_GEN_AFTER_INSN,
> +    PLUGIN_GEN_AFTER_TB,
>       PLUGIN_GEN_N_FROMS,
>   };
>   
> @@ -615,20 +616,9 @@ static void inject_mem_enable_helper(struct qemu_plugin_tb *ptb,
>   /* called before finishing a TB with exit_tb, goto_tb or goto_ptr */
>   void plugin_gen_disable_mem_helpers(void)
>   {
> -    /*
> -     * We could emit the clearing unconditionally and be done. However, this can
> -     * be wasteful if for instance plugins don't track memory accesses, or if
> -     * most TBs don't use helpers. Instead, emit the clearing iff the TB calls
> -     * helpers that might access guest memory.
> -     *
> -     * Note: we do not reset plugin_tb->mem_helper here; a TB might have several
> -     * exit points, and we want to emit the clearing from all of them.
> -     */
> -    if (!tcg_ctx->plugin_tb->mem_helper) {
> -        return;
> +    if (tcg_ctx->plugin_insn) {
> +        tcg_gen_plugin_cb(PLUGIN_GEN_AFTER_TB);
>       }
> -    tcg_gen_st_ptr(tcg_constant_ptr(NULL), tcg_env,
> -                   offsetof(CPUState, plugin_mem_cbs) - offsetof(ArchCPU, env));
>   }
>   
>   static void plugin_gen_insn_udata(const struct qemu_plugin_tb *ptb,
> @@ -679,14 +669,11 @@ static void plugin_gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
>       inject_mem_enable_helper(ptb, insn, begin_op);
>   }
>   
> -static void gen_disable_mem_helper(struct qemu_plugin_tb *ptb,
> -                                   struct qemu_plugin_insn *insn)
> +static void gen_disable_mem_helper(void)
>   {
> -    if (insn->mem_helper) {
> -        tcg_gen_st_ptr(tcg_constant_ptr(0), tcg_env,
> -                       offsetof(CPUState, plugin_mem_cbs) -
> -                       offsetof(ArchCPU, env));
> -    }
> +    tcg_gen_st_ptr(tcg_constant_ptr(0), tcg_env,
> +                   offsetof(CPUState, plugin_mem_cbs) -
> +                   offsetof(ArchCPU, env));
>   }
>   
>   static void gen_udata_cb(struct qemu_plugin_dyn_cb *cb)
> @@ -812,9 +799,17 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>               tcg_ctx->emit_before_op = op;
>   
>               switch (from) {
> +            case PLUGIN_GEN_AFTER_TB:
> +                if (plugin_tb->mem_helper) {
> +                    gen_disable_mem_helper();
> +                }
> +                break;
> +
>               case PLUGIN_GEN_AFTER_INSN:
>                   assert(insn != NULL);
> -                gen_disable_mem_helper(plugin_tb, insn);
> +                if (insn->mem_helper) {
> +                    gen_disable_mem_helper();
> +                }
>                   break;
>   
>               case PLUGIN_GEN_FROM_TB:

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 10/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_INSN
  2024-03-16  1:57 ` [PATCH 10/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_INSN Richard Henderson
@ 2024-03-19 13:34   ` Pierrick Bouvier
  0 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 13:34 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee



On 3/16/24 05:57, Richard Henderson wrote:
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/qemu/plugin.h  |   1 -
>   accel/tcg/plugin-gen.c | 286 ++++++++++-------------------------------
>   plugins/api.c          |   8 +-
>   3 files changed, 67 insertions(+), 228 deletions(-)
> 
> diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
> index 793c44f1f2..ee1c1b174a 100644
> --- a/include/qemu/plugin.h
> +++ b/include/qemu/plugin.h
> @@ -73,7 +73,6 @@ enum plugin_dyn_cb_type {
>   
>   enum plugin_dyn_cb_subtype {
>       PLUGIN_CB_REGULAR,
> -    PLUGIN_CB_REGULAR_R,
>       PLUGIN_CB_INLINE,
>       PLUGIN_N_CB_SUBTYPES,
>   };
> diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
> index aa74e580bd..4785838eca 100644
> --- a/accel/tcg/plugin-gen.c
> +++ b/accel/tcg/plugin-gen.c
> @@ -104,30 +104,6 @@ void HELPER(plugin_vcpu_mem_cb)(unsigned int vcpu_index,
>                                   void *userdata)
>   { }
>   
> -static void gen_empty_udata_cb(void (*gen_helper)(TCGv_i32, TCGv_ptr))
> -{
> -    TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
> -    TCGv_ptr udata = tcg_temp_ebb_new_ptr();
> -
> -    tcg_gen_movi_ptr(udata, 0);
> -    tcg_gen_ld_i32(cpu_index, tcg_env,
> -                   -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
> -    gen_helper(cpu_index, udata);
> -
> -    tcg_temp_free_ptr(udata);
> -    tcg_temp_free_i32(cpu_index);
> -}
> -
> -static void gen_empty_udata_cb_no_wg(void)
> -{
> -    gen_empty_udata_cb(gen_helper_plugin_vcpu_udata_cb_no_wg);
> -}
> -
> -static void gen_empty_udata_cb_no_rwg(void)
> -{
> -    gen_empty_udata_cb(gen_helper_plugin_vcpu_udata_cb_no_rwg);
> -}
> -
>   /*
>    * For now we only support addi_i64.
>    * When we support more ops, we can generate one empty inline cb for each.
> @@ -176,51 +152,19 @@ static void gen_empty_mem_cb(TCGv_i64 addr, uint32_t info)
>       tcg_temp_free_i32(cpu_index);
>   }
>   
> -/*
> - * Share the same function for enable/disable. When enabling, the NULL
> - * pointer will be overwritten later.
> - */
> -static void gen_empty_mem_helper(void)
> -{
> -    TCGv_ptr ptr = tcg_temp_ebb_new_ptr();
> -
> -    tcg_gen_movi_ptr(ptr, 0);
> -    tcg_gen_st_ptr(ptr, tcg_env, offsetof(CPUState, plugin_mem_cbs) -
> -                                 offsetof(ArchCPU, env));
> -    tcg_temp_free_ptr(ptr);
> -}
> -
>   static void gen_plugin_cb_start(enum plugin_gen_from from,
>                                   enum plugin_gen_cb type, unsigned wr)
>   {
>       tcg_gen_plugin_cb_start(from, type, wr);
>   }
>   
> -static void gen_wrapped(enum plugin_gen_from from,
> -                        enum plugin_gen_cb type, void (*func)(void))
> -{
> -    gen_plugin_cb_start(from, type, 0);
> -    func();
> -    tcg_gen_plugin_cb_end();
> -}
> -
>   static void plugin_gen_empty_callback(enum plugin_gen_from from)
>   {
>       switch (from) {
>       case PLUGIN_GEN_AFTER_INSN:
>       case PLUGIN_GEN_FROM_TB:
> -        tcg_gen_plugin_cb(from);
> -        break;
>       case PLUGIN_GEN_FROM_INSN:
> -        /*
> -         * Note: plugin_gen_inject() relies on ENABLE_MEM_HELPER being
> -         * the first callback of an instruction
> -         */
> -        gen_wrapped(from, PLUGIN_GEN_ENABLE_MEM_HELPER,
> -                    gen_empty_mem_helper);
> -        gen_wrapped(from, PLUGIN_GEN_CB_UDATA, gen_empty_udata_cb_no_rwg);
> -        gen_wrapped(from, PLUGIN_GEN_CB_UDATA_R, gen_empty_udata_cb_no_wg);
> -        gen_wrapped(from, PLUGIN_GEN_CB_INLINE, gen_empty_inline_cb);
> +        tcg_gen_plugin_cb(from);
>           break;
>       default:
>           g_assert_not_reached();
> @@ -374,18 +318,6 @@ static TCGOp *copy_mul_i32(TCGOp **begin_op, TCGOp *op, uint32_t v)
>       return op;
>   }
>   
> -static TCGOp *copy_st_ptr(TCGOp **begin_op, TCGOp *op)
> -{
> -    if (UINTPTR_MAX == UINT32_MAX) {
> -        /* st_i32 */
> -        op = copy_op(begin_op, op, INDEX_op_st_i32);
> -    } else {
> -        /* st_i64 */
> -        op = copy_st_i64(begin_op, op);
> -    }
> -    return op;
> -}
> -
>   static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *func, int *cb_idx)
>   {
>       TCGOp *old_op;
> @@ -409,32 +341,6 @@ static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *func, int *cb_idx)
>       return op;
>   }
>   
> -/*
> - * When we append/replace ops here we are sensitive to changing patterns of
> - * TCGOps generated by the tcg_gen_FOO calls when we generated the
> - * empty callbacks. This will assert very quickly in a debug build as
> - * we assert the ops we are replacing are the correct ones.
> - */
> -static TCGOp *append_udata_cb(const struct qemu_plugin_dyn_cb *cb,
> -                              TCGOp *begin_op, TCGOp *op, int *cb_idx)
> -{
> -    /* const_ptr */
> -    op = copy_const_ptr(&begin_op, op, cb->userp);
> -
> -    /* copy the ld_i32, but note that we only have to copy it once */
> -    if (*cb_idx == -1) {
> -        op = copy_op(&begin_op, op, INDEX_op_ld_i32);
> -    } else {
> -        begin_op = QTAILQ_NEXT(begin_op, link);
> -        tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32);
> -    }
> -
> -    /* call */
> -    op = copy_call(&begin_op, op, cb->regular.f.vcpu_udata, cb_idx);
> -
> -    return op;
> -}
> -
>   static TCGOp *append_inline_cb(const struct qemu_plugin_dyn_cb *cb,
>                                  TCGOp *begin_op, TCGOp *op,
>                                  int *unused)
> @@ -488,11 +394,6 @@ typedef TCGOp *(*inject_fn)(const struct qemu_plugin_dyn_cb *cb,
>                               TCGOp *begin_op, TCGOp *op, int *intp);
>   typedef bool (*op_ok_fn)(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb);
>   
> -static bool op_ok(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb)
> -{
> -    return true;
> -}
> -
>   static bool op_rw(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb)
>   {
>       int w;
> @@ -530,12 +431,6 @@ static void inject_cb_type(const GArray *cbs, TCGOp *begin_op,
>       rm_ops_range(begin_op, end_op);
>   }
>   
> -static void
> -inject_udata_cb(const GArray *cbs, TCGOp *begin_op)
> -{
> -    inject_cb_type(cbs, begin_op, append_udata_cb, op_ok);
> -}
> -
>   static void
>   inject_inline_cb(const GArray *cbs, TCGOp *begin_op, op_ok_fn ok)
>   {
> @@ -548,71 +443,6 @@ inject_mem_cb(const GArray *cbs, TCGOp *begin_op)
>       inject_cb_type(cbs, begin_op, append_mem_cb, op_rw);
>   }
>   
> -/* we could change the ops in place, but we can reuse more code by copying */
> -static void inject_mem_helper(TCGOp *begin_op, GArray *arr)
> -{
> -    TCGOp *orig_op = begin_op;
> -    TCGOp *end_op;
> -    TCGOp *op;
> -
> -    end_op = find_op(begin_op, INDEX_op_plugin_cb_end);
> -    tcg_debug_assert(end_op);
> -
> -    /* const ptr */
> -    op = copy_const_ptr(&begin_op, end_op, arr);
> -
> -    /* st_ptr */
> -    op = copy_st_ptr(&begin_op, op);
> -
> -    rm_ops_range(orig_op, end_op);
> -}
> -
> -/*
> - * Tracking memory accesses performed from helpers requires extra work.
> - * If an instruction is emulated with helpers, we do two things:
> - * (1) copy the CB descriptors, and keep track of it so that they can be
> - * freed later on, and (2) point CPUState.plugin_mem_cbs to the descriptors, so
> - * that we can read them at run-time (i.e. when the helper executes).
> - * This run-time access is performed from qemu_plugin_vcpu_mem_cb.
> - *
> - * Note that plugin_gen_disable_mem_helpers undoes (2). Since it
> - * is possible that the code we generate after the instruction is
> - * dead, we also add checks before generating tb_exit etc.
> - */
> -static void inject_mem_enable_helper(struct qemu_plugin_tb *ptb,
> -                                     struct qemu_plugin_insn *plugin_insn,
> -                                     TCGOp *begin_op)
> -{
> -    GArray *cbs[2];
> -    GArray *arr;
> -    size_t n_cbs, i;
> -
> -    cbs[0] = plugin_insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR];
> -    cbs[1] = plugin_insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
> -
> -    n_cbs = 0;
> -    for (i = 0; i < ARRAY_SIZE(cbs); i++) {
> -        n_cbs += cbs[i]->len;
> -    }
> -
> -    plugin_insn->mem_helper = plugin_insn->calls_helpers && n_cbs;
> -    if (likely(!plugin_insn->mem_helper)) {
> -        rm_ops(begin_op);
> -        return;
> -    }
> -    ptb->mem_helper = true;
> -
> -    arr = g_array_sized_new(false, false,
> -                            sizeof(struct qemu_plugin_dyn_cb), n_cbs);
> -
> -    for (i = 0; i < ARRAY_SIZE(cbs); i++) {
> -        g_array_append_vals(arr, cbs[i]->data, cbs[i]->len);
> -    }
> -
> -    qemu_plugin_add_dyn_cb_arr(arr);
> -    inject_mem_helper(begin_op, arr);
> -}
> -
>   /* called before finishing a TB with exit_tb, goto_tb or goto_ptr */
>   void plugin_gen_disable_mem_helpers(void)
>   {
> @@ -621,30 +451,6 @@ void plugin_gen_disable_mem_helpers(void)
>       }
>   }
>   
> -static void plugin_gen_insn_udata(const struct qemu_plugin_tb *ptb,
> -                                  TCGOp *begin_op, int insn_idx)
> -{
> -    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
> -
> -    inject_udata_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR], begin_op);
> -}
> -
> -static void plugin_gen_insn_udata_r(const struct qemu_plugin_tb *ptb,
> -                                    TCGOp *begin_op, int insn_idx)
> -{
> -    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
> -
> -    inject_udata_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR_R], begin_op);
> -}
> -
> -static void plugin_gen_insn_inline(const struct qemu_plugin_tb *ptb,
> -                                   TCGOp *begin_op, int insn_idx)
> -{
> -    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
> -    inject_inline_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE],
> -                     begin_op, op_ok);
> -}
> -
>   static void plugin_gen_mem_regular(const struct qemu_plugin_tb *ptb,
>                                      TCGOp *begin_op, int insn_idx)
>   {
> @@ -662,11 +468,51 @@ static void plugin_gen_mem_inline(const struct qemu_plugin_tb *ptb,
>       inject_inline_cb(cbs, begin_op, op_rw);
>   }
>   
> -static void plugin_gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
> -                                         TCGOp *begin_op, int insn_idx)
> +static void gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
> +                                  struct qemu_plugin_insn *insn)
>   {
> -    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
> -    inject_mem_enable_helper(ptb, insn, begin_op);
> +    GArray *cbs[2];
> +    GArray *arr;
> +    size_t n_cbs;
> +
> +    /*
> +     * Tracking memory accesses performed from helpers requires extra work.
> +     * If an instruction is emulated with helpers, we do two things:
> +     * (1) copy the CB descriptors, and keep track of it so that they can be
> +     * freed later on, and (2) point CPUState.plugin_mem_cbs to the
> +     * descriptors, so that we can read them at run-time
> +     * (i.e. when the helper executes).
> +     * This run-time access is performed from qemu_plugin_vcpu_mem_cb.
> +     *
> +     * Note that plugin_gen_disable_mem_helpers undoes (2). Since it
> +     * is possible that the code we generate after the instruction is
> +     * dead, we also add checks before generating tb_exit etc.
> +     */
> +    if (!insn->calls_helpers) {
> +        return;
> +    }
> +
> +    cbs[0] = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR];
> +    cbs[1] = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
> +    n_cbs = cbs[0]->len + cbs[1]->len;
> +
> +    if (n_cbs == 0) {
> +        insn->mem_helper = false;
> +        return;
> +    }
> +    insn->mem_helper = true;
> +    ptb->mem_helper = true;
> +
> +    arr = g_array_sized_new(false, false,
> +                            sizeof(struct qemu_plugin_dyn_cb), n_cbs);
> +    g_array_append_vals(arr, cbs[0]->data, cbs[0]->len);
> +    g_array_append_vals(arr, cbs[1]->data, cbs[1]->len);
> +
> +    qemu_plugin_add_dyn_cb_arr(arr);
> +
> +    tcg_gen_st_ptr(tcg_constant_ptr((intptr_t)arr), tcg_env,
> +                   offsetof(CPUState, plugin_mem_cbs) -
> +                   offsetof(ArchCPU, env));
>   }
>   
>   static void gen_disable_mem_helper(void)
> @@ -830,6 +676,26 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>                   }
>                   break;
>   
> +            case PLUGIN_GEN_FROM_INSN:
> +                assert(insn != NULL);
> +
> +                gen_enable_mem_helper(plugin_tb, insn);
> +
> +                cbs = insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR];
> +                for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
> +                    struct qemu_plugin_dyn_cb *cb =
> +                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> +                    gen_udata_cb(cb);
> +                }
> +
> +                cbs = insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE];
> +                for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
> +                    struct qemu_plugin_dyn_cb *cb =
> +                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> +                    gen_inline_cb(cb);
> +                }
> +                break;
> +
>               default:
>                   g_assert_not_reached();
>               }
> @@ -845,28 +711,6 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>               enum plugin_gen_cb type = op->args[1];
>   
>               switch (from) {
> -            case PLUGIN_GEN_FROM_INSN:
> -            {
> -                g_assert(insn_idx >= 0);
> -
> -                switch (type) {
> -                case PLUGIN_GEN_CB_UDATA:
> -                    plugin_gen_insn_udata(plugin_tb, op, insn_idx);
> -                    break;
> -                case PLUGIN_GEN_CB_UDATA_R:
> -                    plugin_gen_insn_udata_r(plugin_tb, op, insn_idx);
> -                    break;
> -                case PLUGIN_GEN_CB_INLINE:
> -                    plugin_gen_insn_inline(plugin_tb, op, insn_idx);
> -                    break;
> -                case PLUGIN_GEN_ENABLE_MEM_HELPER:
> -                    plugin_gen_enable_mem_helper(plugin_tb, op, insn_idx);
> -                    break;
> -                default:
> -                    g_assert_not_reached();
> -                }
> -                break;
> -            }
>               case PLUGIN_GEN_FROM_MEM:
>               {
>                   g_assert(insn_idx >= 0);
> diff --git a/plugins/api.c b/plugins/api.c
> index 5d119e8049..29cce2d97c 100644
> --- a/plugins/api.c
> +++ b/plugins/api.c
> @@ -115,12 +115,8 @@ void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
>                                               void *udata)
>   {
>       if (!insn->mem_only) {
> -        int index = flags == QEMU_PLUGIN_CB_R_REGS ||
> -                    flags == QEMU_PLUGIN_CB_RW_REGS ?
> -                    PLUGIN_CB_REGULAR_R : PLUGIN_CB_REGULAR;
> -
> -        plugin_register_dyn_cb__udata(&insn->cbs[PLUGIN_CB_INSN][index],
> -                                      cb, flags, udata);
> +        plugin_register_dyn_cb__udata(
> +            &insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR], cb, flags, udata);
>       }
>   }
>   

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 11/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_MEM
  2024-03-16  1:57 ` [PATCH 11/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_MEM Richard Henderson
@ 2024-03-19 13:35   ` Pierrick Bouvier
  0 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 13:35 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:57, Richard Henderson wrote:
> Introduce a new plugin_mem_cb op to hold the address temp
> and meminfo computed by tcg-op-ldst.c.  Because this now
> has its own opcode, we no longer need PLUGIN_GEN_FROM_MEM.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/exec/plugin-gen.h   |   4 -
>   include/tcg/tcg-op-common.h |   1 +
>   include/tcg/tcg-opc.h       |   1 +
>   accel/tcg/plugin-gen.c      | 408 ++++--------------------------------
>   tcg/tcg-op-ldst.c           |   6 +-
>   tcg/tcg-op.c                |   5 +
>   6 files changed, 54 insertions(+), 371 deletions(-)
> 
> diff --git a/include/exec/plugin-gen.h b/include/exec/plugin-gen.h
> index c4552b5061..f333f33198 100644
> --- a/include/exec/plugin-gen.h
> +++ b/include/exec/plugin-gen.h
> @@ -25,7 +25,6 @@ void plugin_gen_insn_start(CPUState *cpu, const struct DisasContextBase *db);
>   void plugin_gen_insn_end(void);
>   
>   void plugin_gen_disable_mem_helpers(void);
> -void plugin_gen_empty_mem_callback(TCGv_i64 addr, uint32_t info);
>   
>   #else /* !CONFIG_PLUGIN */
>   
> @@ -48,9 +47,6 @@ static inline void plugin_gen_tb_end(CPUState *cpu, size_t num_insns)
>   static inline void plugin_gen_disable_mem_helpers(void)
>   { }
>   
> -static inline void plugin_gen_empty_mem_callback(TCGv_i64 addr, uint32_t info)
> -{ }
> -
>   #endif /* CONFIG_PLUGIN */
>   
>   #endif /* QEMU_PLUGIN_GEN_H */
> diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h
> index 9de5a7f280..72b80b20d0 100644
> --- a/include/tcg/tcg-op-common.h
> +++ b/include/tcg/tcg-op-common.h
> @@ -75,6 +75,7 @@ void tcg_gen_goto_tb(unsigned idx);
>   void tcg_gen_lookup_and_goto_ptr(void);
>   
>   void tcg_gen_plugin_cb(unsigned from);
> +void tcg_gen_plugin_mem_cb(TCGv_i64 addr, unsigned meminfo);
>   void tcg_gen_plugin_cb_start(unsigned from, unsigned type, unsigned wr);
>   void tcg_gen_plugin_cb_end(void);
>   
> diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h
> index 3b7cb2bce1..be9e36e386 100644
> --- a/include/tcg/tcg-opc.h
> +++ b/include/tcg/tcg-opc.h
> @@ -198,6 +198,7 @@ DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
>   DEF(goto_ptr, 0, 1, 0, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
>   
>   DEF(plugin_cb, 0, 0, 1, TCG_OPF_NOT_PRESENT)
> +DEF(plugin_mem_cb, 0, 1, 1, TCG_OPF_NOT_PRESENT)
>   DEF(plugin_cb_start, 0, 0, 3, TCG_OPF_NOT_PRESENT)
>   DEF(plugin_cb_end, 0, 0, 0, TCG_OPF_NOT_PRESENT)
>   
> diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
> index 4785838eca..be7fd548cc 100644
> --- a/accel/tcg/plugin-gen.c
> +++ b/accel/tcg/plugin-gen.c
> @@ -73,7 +73,6 @@
>   enum plugin_gen_from {
>       PLUGIN_GEN_FROM_TB,
>       PLUGIN_GEN_FROM_INSN,
> -    PLUGIN_GEN_FROM_MEM,
>       PLUGIN_GEN_AFTER_INSN,
>       PLUGIN_GEN_AFTER_TB,
>       PLUGIN_GEN_N_FROMS,
> @@ -104,60 +103,6 @@ void HELPER(plugin_vcpu_mem_cb)(unsigned int vcpu_index,
>                                   void *userdata)
>   { }
>   
> -/*
> - * For now we only support addi_i64.
> - * When we support more ops, we can generate one empty inline cb for each.
> - */
> -static void gen_empty_inline_cb(void)
> -{
> -    TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
> -    TCGv_ptr cpu_index_as_ptr = tcg_temp_ebb_new_ptr();
> -    TCGv_i64 val = tcg_temp_ebb_new_i64();
> -    TCGv_ptr ptr = tcg_temp_ebb_new_ptr();
> -
> -    tcg_gen_ld_i32(cpu_index, tcg_env,
> -                   -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
> -    /* second operand will be replaced by immediate value */
> -    tcg_gen_mul_i32(cpu_index, cpu_index, cpu_index);
> -    tcg_gen_ext_i32_ptr(cpu_index_as_ptr, cpu_index);
> -
> -    tcg_gen_movi_ptr(ptr, 0);
> -    tcg_gen_add_ptr(ptr, ptr, cpu_index_as_ptr);
> -    tcg_gen_ld_i64(val, ptr, 0);
> -    /* second operand will be replaced by immediate value */
> -    tcg_gen_add_i64(val, val, val);
> -
> -    tcg_gen_st_i64(val, ptr, 0);
> -    tcg_temp_free_ptr(ptr);
> -    tcg_temp_free_i64(val);
> -    tcg_temp_free_ptr(cpu_index_as_ptr);
> -    tcg_temp_free_i32(cpu_index);
> -}
> -
> -static void gen_empty_mem_cb(TCGv_i64 addr, uint32_t info)
> -{
> -    TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
> -    TCGv_i32 meminfo = tcg_temp_ebb_new_i32();
> -    TCGv_ptr udata = tcg_temp_ebb_new_ptr();
> -
> -    tcg_gen_movi_i32(meminfo, info);
> -    tcg_gen_movi_ptr(udata, 0);
> -    tcg_gen_ld_i32(cpu_index, tcg_env,
> -                   -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
> -
> -    gen_helper_plugin_vcpu_mem_cb(cpu_index, meminfo, addr, udata);
> -
> -    tcg_temp_free_ptr(udata);
> -    tcg_temp_free_i32(meminfo);
> -    tcg_temp_free_i32(cpu_index);
> -}
> -
> -static void gen_plugin_cb_start(enum plugin_gen_from from,
> -                                enum plugin_gen_cb type, unsigned wr)
> -{
> -    tcg_gen_plugin_cb_start(from, type, wr);
> -}
> -
>   static void plugin_gen_empty_callback(enum plugin_gen_from from)
>   {
>       switch (from) {
> @@ -171,278 +116,6 @@ static void plugin_gen_empty_callback(enum plugin_gen_from from)
>       }
>   }
>   
> -void plugin_gen_empty_mem_callback(TCGv_i64 addr, uint32_t info)
> -{
> -    enum qemu_plugin_mem_rw rw = get_plugin_meminfo_rw(info);
> -
> -    gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, PLUGIN_GEN_CB_MEM, rw);
> -    gen_empty_mem_cb(addr, info);
> -    tcg_gen_plugin_cb_end();
> -
> -    gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, PLUGIN_GEN_CB_INLINE, rw);
> -    gen_empty_inline_cb();
> -    tcg_gen_plugin_cb_end();
> -}
> -
> -static TCGOp *find_op(TCGOp *op, TCGOpcode opc)
> -{
> -    while (op) {
> -        if (op->opc == opc) {
> -            return op;
> -        }
> -        op = QTAILQ_NEXT(op, link);
> -    }
> -    return NULL;
> -}
> -
> -static TCGOp *rm_ops_range(TCGOp *begin, TCGOp *end)
> -{
> -    TCGOp *ret = QTAILQ_NEXT(end, link);
> -
> -    QTAILQ_REMOVE_SEVERAL(&tcg_ctx->ops, begin, end, link);
> -    return ret;
> -}
> -
> -/* remove all ops until (and including) plugin_cb_end */
> -static TCGOp *rm_ops(TCGOp *op)
> -{
> -    TCGOp *end_op = find_op(op, INDEX_op_plugin_cb_end);
> -
> -    tcg_debug_assert(end_op);
> -    return rm_ops_range(op, end_op);
> -}
> -
> -static TCGOp *copy_op_nocheck(TCGOp **begin_op, TCGOp *op)
> -{
> -    TCGOp *old_op = QTAILQ_NEXT(*begin_op, link);
> -    unsigned nargs = old_op->nargs;
> -
> -    *begin_op = old_op;
> -    op = tcg_op_insert_after(tcg_ctx, op, old_op->opc, nargs);
> -    memcpy(op->args, old_op->args, sizeof(op->args[0]) * nargs);
> -
> -    return op;
> -}
> -
> -static TCGOp *copy_op(TCGOp **begin_op, TCGOp *op, TCGOpcode opc)
> -{
> -    op = copy_op_nocheck(begin_op, op);
> -    tcg_debug_assert((*begin_op)->opc == opc);
> -    return op;
> -}
> -
> -static TCGOp *copy_const_ptr(TCGOp **begin_op, TCGOp *op, void *ptr)
> -{
> -    if (UINTPTR_MAX == UINT32_MAX) {
> -        /* mov_i32 */
> -        op = copy_op(begin_op, op, INDEX_op_mov_i32);
> -        op->args[1] = tcgv_i32_arg(tcg_constant_i32((uintptr_t)ptr));
> -    } else {
> -        /* mov_i64 */
> -        op = copy_op(begin_op, op, INDEX_op_mov_i64);
> -        op->args[1] = tcgv_i64_arg(tcg_constant_i64((uintptr_t)ptr));
> -    }
> -    return op;
> -}
> -
> -static TCGOp *copy_ld_i32(TCGOp **begin_op, TCGOp *op)
> -{
> -    return copy_op(begin_op, op, INDEX_op_ld_i32);
> -}
> -
> -static TCGOp *copy_ext_i32_ptr(TCGOp **begin_op, TCGOp *op)
> -{
> -    if (UINTPTR_MAX == UINT32_MAX) {
> -        op = copy_op(begin_op, op, INDEX_op_mov_i32);
> -    } else {
> -        op = copy_op(begin_op, op, INDEX_op_ext_i32_i64);
> -    }
> -    return op;
> -}
> -
> -static TCGOp *copy_add_ptr(TCGOp **begin_op, TCGOp *op)
> -{
> -    if (UINTPTR_MAX == UINT32_MAX) {
> -        op = copy_op(begin_op, op, INDEX_op_add_i32);
> -    } else {
> -        op = copy_op(begin_op, op, INDEX_op_add_i64);
> -    }
> -    return op;
> -}
> -
> -static TCGOp *copy_ld_i64(TCGOp **begin_op, TCGOp *op)
> -{
> -    if (TCG_TARGET_REG_BITS == 32) {
> -        /* 2x ld_i32 */
> -        op = copy_ld_i32(begin_op, op);
> -        op = copy_ld_i32(begin_op, op);
> -    } else {
> -        /* ld_i64 */
> -        op = copy_op(begin_op, op, INDEX_op_ld_i64);
> -    }
> -    return op;
> -}
> -
> -static TCGOp *copy_st_i64(TCGOp **begin_op, TCGOp *op)
> -{
> -    if (TCG_TARGET_REG_BITS == 32) {
> -        /* 2x st_i32 */
> -        op = copy_op(begin_op, op, INDEX_op_st_i32);
> -        op = copy_op(begin_op, op, INDEX_op_st_i32);
> -    } else {
> -        /* st_i64 */
> -        op = copy_op(begin_op, op, INDEX_op_st_i64);
> -    }
> -    return op;
> -}
> -
> -static TCGOp *copy_add_i64(TCGOp **begin_op, TCGOp *op, uint64_t v)
> -{
> -    if (TCG_TARGET_REG_BITS == 32) {
> -        /* all 32-bit backends must implement add2_i32 */
> -        g_assert(TCG_TARGET_HAS_add2_i32);
> -        op = copy_op(begin_op, op, INDEX_op_add2_i32);
> -        op->args[4] = tcgv_i32_arg(tcg_constant_i32(v));
> -        op->args[5] = tcgv_i32_arg(tcg_constant_i32(v >> 32));
> -    } else {
> -        op = copy_op(begin_op, op, INDEX_op_add_i64);
> -        op->args[2] = tcgv_i64_arg(tcg_constant_i64(v));
> -    }
> -    return op;
> -}
> -
> -static TCGOp *copy_mul_i32(TCGOp **begin_op, TCGOp *op, uint32_t v)
> -{
> -    op = copy_op(begin_op, op, INDEX_op_mul_i32);
> -    op->args[2] = tcgv_i32_arg(tcg_constant_i32(v));
> -    return op;
> -}
> -
> -static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *func, int *cb_idx)
> -{
> -    TCGOp *old_op;
> -    int func_idx;
> -
> -    /* copy all ops until the call */
> -    do {
> -        op = copy_op_nocheck(begin_op, op);
> -    } while (op->opc != INDEX_op_call);
> -
> -    /* fill in the op call */
> -    old_op = *begin_op;
> -    TCGOP_CALLI(op) = TCGOP_CALLI(old_op);
> -    TCGOP_CALLO(op) = TCGOP_CALLO(old_op);
> -    tcg_debug_assert(op->life == 0);
> -
> -    func_idx = TCGOP_CALLO(op) + TCGOP_CALLI(op);
> -    *cb_idx = func_idx;
> -    op->args[func_idx] = (uintptr_t)func;
> -
> -    return op;
> -}
> -
> -static TCGOp *append_inline_cb(const struct qemu_plugin_dyn_cb *cb,
> -                               TCGOp *begin_op, TCGOp *op,
> -                               int *unused)
> -{
> -    char *ptr = cb->inline_insn.entry.score->data->data;
> -    size_t elem_size = g_array_get_element_size(
> -        cb->inline_insn.entry.score->data);
> -    size_t offset = cb->inline_insn.entry.offset;
> -
> -    op = copy_ld_i32(&begin_op, op);
> -    op = copy_mul_i32(&begin_op, op, elem_size);
> -    op = copy_ext_i32_ptr(&begin_op, op);
> -    op = copy_const_ptr(&begin_op, op, ptr + offset);
> -    op = copy_add_ptr(&begin_op, op);
> -    op = copy_ld_i64(&begin_op, op);
> -    op = copy_add_i64(&begin_op, op, cb->inline_insn.imm);
> -    op = copy_st_i64(&begin_op, op);
> -    return op;
> -}
> -
> -static TCGOp *append_mem_cb(const struct qemu_plugin_dyn_cb *cb,
> -                            TCGOp *begin_op, TCGOp *op, int *cb_idx)
> -{
> -    enum plugin_gen_cb type = begin_op->args[1];
> -
> -    tcg_debug_assert(type == PLUGIN_GEN_CB_MEM);
> -
> -    /* const_i32 == mov_i32 ("info", so it remains as is) */
> -    op = copy_op(&begin_op, op, INDEX_op_mov_i32);
> -
> -    /* const_ptr */
> -    op = copy_const_ptr(&begin_op, op, cb->userp);
> -
> -    /* copy the ld_i32, but note that we only have to copy it once */
> -    if (*cb_idx == -1) {
> -        op = copy_op(&begin_op, op, INDEX_op_ld_i32);
> -    } else {
> -        begin_op = QTAILQ_NEXT(begin_op, link);
> -        tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32);
> -    }
> -
> -    if (type == PLUGIN_GEN_CB_MEM) {
> -        /* call */
> -        op = copy_call(&begin_op, op, cb->regular.f.vcpu_udata, cb_idx);
> -    }
> -
> -    return op;
> -}
> -
> -typedef TCGOp *(*inject_fn)(const struct qemu_plugin_dyn_cb *cb,
> -                            TCGOp *begin_op, TCGOp *op, int *intp);
> -typedef bool (*op_ok_fn)(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb);
> -
> -static bool op_rw(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb)
> -{
> -    int w;
> -
> -    w = op->args[2];
> -    return !!(cb->rw & (w + 1));
> -}
> -
> -static void inject_cb_type(const GArray *cbs, TCGOp *begin_op,
> -                           inject_fn inject, op_ok_fn ok)
> -{
> -    TCGOp *end_op;
> -    TCGOp *op;
> -    int cb_idx = -1;
> -    int i;
> -
> -    if (!cbs || cbs->len == 0) {
> -        rm_ops(begin_op);
> -        return;
> -    }
> -
> -    end_op = find_op(begin_op, INDEX_op_plugin_cb_end);
> -    tcg_debug_assert(end_op);
> -
> -    op = end_op;
> -    for (i = 0; i < cbs->len; i++) {
> -        struct qemu_plugin_dyn_cb *cb =
> -            &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> -
> -        if (!ok(begin_op, cb)) {
> -            continue;
> -        }
> -        op = inject(cb, begin_op, op, &cb_idx);
> -    }
> -    rm_ops_range(begin_op, end_op);
> -}
> -
> -static void
> -inject_inline_cb(const GArray *cbs, TCGOp *begin_op, op_ok_fn ok)
> -{
> -    inject_cb_type(cbs, begin_op, append_inline_cb, ok);
> -}
> -
> -static void
> -inject_mem_cb(const GArray *cbs, TCGOp *begin_op)
> -{
> -    inject_cb_type(cbs, begin_op, append_mem_cb, op_rw);
> -}
> -
>   /* called before finishing a TB with exit_tb, goto_tb or goto_ptr */
>   void plugin_gen_disable_mem_helpers(void)
>   {
> @@ -451,23 +124,6 @@ void plugin_gen_disable_mem_helpers(void)
>       }
>   }
>   
> -static void plugin_gen_mem_regular(const struct qemu_plugin_tb *ptb,
> -                                   TCGOp *begin_op, int insn_idx)
> -{
> -    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
> -    inject_mem_cb(insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR], begin_op);
> -}
> -
> -static void plugin_gen_mem_inline(const struct qemu_plugin_tb *ptb,
> -                                  TCGOp *begin_op, int insn_idx)
> -{
> -    const GArray *cbs;
> -    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
> -
> -    cbs = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
> -    inject_inline_cb(cbs, begin_op, op_rw);
> -}
> -
>   static void gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
>                                     struct qemu_plugin_insn *insn)
>   {
> @@ -557,6 +213,21 @@ static void gen_inline_cb(struct qemu_plugin_dyn_cb *cb)
>       tcg_temp_free_ptr(ptr);
>   }
>   
> +static void gen_mem_cb(struct qemu_plugin_dyn_cb *cb,
> +                       qemu_plugin_meminfo_t meminfo, TCGv_i64 addr)
> +{
> +    TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
> +
> +    tcg_gen_ld_i32(cpu_index, tcg_env,
> +                   -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
> +    tcg_gen_call4(cb->regular.f.vcpu_mem, cb->regular.info, NULL,
> +                  tcgv_i32_temp(cpu_index),
> +                  tcgv_i32_temp(tcg_constant_i32(meminfo)),
> +                  tcgv_i64_temp(addr),
> +                  tcgv_ptr_temp(tcg_constant_ptr(cb->userp)));
> +    tcg_temp_free_i32(cpu_index);
> +}
> +
>   /* #define DEBUG_PLUGIN_GEN_OPS */
>   static void pr_ops(void)
>   {
> @@ -705,34 +376,43 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>               break;
>           }
>   
> -        case INDEX_op_plugin_cb_start:
> +        case INDEX_op_plugin_mem_cb:
>           {
> -            enum plugin_gen_from from = op->args[0];
> -            enum plugin_gen_cb type = op->args[1];
> +            TCGv_i64 addr = temp_tcgv_i64(arg_temp(op->args[0]));
> +            qemu_plugin_meminfo_t meminfo = op->args[1];
> +            struct qemu_plugin_insn *insn;
> +            const GArray *cbs;
> +            int i, n, rw;
>   
> -            switch (from) {
> -            case PLUGIN_GEN_FROM_MEM:
> -            {
> -                g_assert(insn_idx >= 0);
> +            assert(insn_idx >= 0);
> +            insn = g_ptr_array_index(plugin_tb->insns, insn_idx);
> +            rw = qemu_plugin_mem_is_store(meminfo) ? 2 : 1;
>   
> -                switch (type) {
> -                case PLUGIN_GEN_CB_MEM:
> -                    plugin_gen_mem_regular(plugin_tb, op, insn_idx);
> -                    break;
> -                case PLUGIN_GEN_CB_INLINE:
> -                    plugin_gen_mem_inline(plugin_tb, op, insn_idx);
> -                    break;
> -                default:
> -                    g_assert_not_reached();
> +            tcg_ctx->emit_before_op = op;
> +
> +            cbs = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR];
> +            for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
> +                struct qemu_plugin_dyn_cb *cb =
> +                    &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> +                if (cb->rw & rw) {
> +                    gen_mem_cb(cb, meminfo, addr);
>                   }
> +            }
>   
> -                break;
> -            }
> -            default:
> -                g_assert_not_reached();
> +            cbs = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
> +            for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
> +                struct qemu_plugin_dyn_cb *cb =
> +                    &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
> +                if (cb->rw & rw) {
> +                    gen_inline_cb(cb);
> +                }
>               }
> +
> +            tcg_ctx->emit_before_op = NULL;
> +            tcg_op_remove(tcg_ctx, op);
>               break;
>           }
> +
>           default:
>               /* plugins don't care about any other ops */
>               break;
> diff --git a/tcg/tcg-op-ldst.c b/tcg/tcg-op-ldst.c
> index f11043b449..8510160258 100644
> --- a/tcg/tcg-op-ldst.c
> +++ b/tcg/tcg-op-ldst.c
> @@ -161,14 +161,14 @@ plugin_gen_mem_callbacks(TCGv_i64 copy_addr, TCGTemp *orig_addr, MemOpIdx oi,
>                   copy_addr = tcg_temp_ebb_new_i64();
>                   tcg_gen_extu_i32_i64(copy_addr, temp_tcgv_i32(orig_addr));
>               }
> -            plugin_gen_empty_mem_callback(copy_addr, info);
> +            tcg_gen_plugin_mem_cb(copy_addr, info);
>               tcg_temp_free_i64(copy_addr);
>           } else {
>               if (copy_addr) {
> -                plugin_gen_empty_mem_callback(copy_addr, info);
> +                tcg_gen_plugin_mem_cb(copy_addr, info);
>                   tcg_temp_free_i64(copy_addr);
>               } else {
> -                plugin_gen_empty_mem_callback(temp_tcgv_i64(orig_addr), info);
> +                tcg_gen_plugin_mem_cb(temp_tcgv_i64(orig_addr), info);
>               }
>           }
>       }
> diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
> index 0f2026c91c..0ae12fa49d 100644
> --- a/tcg/tcg-op.c
> +++ b/tcg/tcg-op.c
> @@ -317,6 +317,11 @@ void tcg_gen_plugin_cb(unsigned from)
>       tcg_gen_op1(INDEX_op_plugin_cb, from);
>   }
>   
> +void tcg_gen_plugin_mem_cb(TCGv_i64 addr, unsigned meminfo)
> +{
> +    tcg_gen_op2(INDEX_op_plugin_mem_cb, tcgv_i64_arg(addr), meminfo);
> +}
> +
>   void tcg_gen_plugin_cb_start(unsigned from, unsigned type, unsigned wr)
>   {
>       tcg_gen_op3(INDEX_op_plugin_cb_start, from, type, wr);

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 00/22] plugins: Rewrite plugin code generation
  2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
                   ` (21 preceding siblings ...)
  2024-03-16  1:57 ` [PATCH 22/22] plugins: Update the documentation block for plugin-gen.c Richard Henderson
@ 2024-03-19 13:38 ` Pierrick Bouvier
  22 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-19 13:38 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/16/24 05:56, Richard Henderson wrote:
> As I mooted with Pierrick earlier this week:
> 
> (1) Add a (trivial) mechanism for emitting code into
> the middle of the opcode sequence: tcg_ctx->emit_before_op.
> 
> (2) Rip out all of the "empty" generation and "copy"
> to modify those sequences.  Replace with regular code
> generation once we know what values to place.
> 
> There's probably still more cleanup that could be done:
> 
> There seems to be a lot of artificial separation between
> plugins and the rest of the code base, even between
> plugins/api.c and plugins/core.c.
> 
> I suspect that all of plugins could be moved into the
> build-once buckets.
> 
> 
> r~
> 
> 
> Richard Henderson (22):
>    tcg: Add TCGContext.emit_before_op
>    tcg: Make tcg/helper-info.h self-contained
>    tcg: Pass function pointer to tcg_gen_call*
>    plugins: Zero new qemu_plugin_dyn_cb entries
>    plugins: Move function pointer in qemu_plugin_dyn_cb
>    plugins: Create TCGHelperInfo for all out-of-line callbacks
>    plugins: Use emit_before_op for PLUGIN_GEN_AFTER_INSN
>    plugins: Use emit_before_op for PLUGIN_GEN_FROM_TB
>    plugins: Add PLUGIN_GEN_AFTER_TB
>    plugins: Use emit_before_op for PLUGIN_GEN_FROM_INSN
>    plugins: Use emit_before_op for PLUGIN_GEN_FROM_MEM
>    plugins: Remove plugin helpers
>    tcg: Remove TCG_CALL_PLUGIN
>    tcg: Remove INDEX_op_plugin_cb_{start,end}
>    plugins: Simplify callback queues
>    plugins: Introduce PLUGIN_CB_MEM_REGULAR
>    plugins: Replace pr_ops with a proper debug dump flag
>    plugins: Split out common cb expanders
>    plugins: Merge qemu_plugin_tb_insn_get to plugin-gen.c
>    plugins: Move qemu_plugin_insn_cleanup_fn to tcg.c
>    plugins: Inline plugin_gen_empty_callback
>    plugins: Update the documentation block for plugin-gen.c
> 
>   accel/tcg/plugin-helpers.h         |    5 -
>   include/exec/helper-gen-common.h   |    4 -
>   include/exec/helper-proto-common.h |    4 -
>   include/exec/plugin-gen.h          |    4 -
>   include/qemu/log.h                 |    1 +
>   include/qemu/plugin.h              |   79 +--
>   include/tcg/helper-info.h          |    3 +
>   include/tcg/tcg-op-common.h        |    4 +-
>   include/tcg/tcg-opc.h              |    4 +-
>   include/tcg/tcg.h                  |   27 +-
>   include/exec/helper-gen.h.inc      |   24 +-
>   accel/tcg/plugin-gen.c             | 1008 +++++++---------------------
>   plugins/api.c                      |   26 +-
>   plugins/core.c                     |   61 +-
>   tcg/tcg-op-ldst.c                  |    6 +-
>   tcg/tcg-op.c                       |    8 +-
>   tcg/tcg.c                          |  104 ++-
>   util/log.c                         |    4 +
>   18 files changed, 424 insertions(+), 952 deletions(-)
>   delete mode 100644 accel/tcg/plugin-helpers.h
> 

Really great series. Not only the final code is much simpler, but it's 
faster as well (from the few tests I ran).


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 01/22] tcg: Add TCGContext.emit_before_op
  2024-03-16  1:56 ` [PATCH 01/22] tcg: Add TCGContext.emit_before_op Richard Henderson
  2024-03-19 10:55   ` Pierrick Bouvier
@ 2024-03-19 14:04   ` Alex Bennée
  2024-03-19 21:23     ` Richard Henderson
  1 sibling, 1 reply; 57+ messages in thread
From: Alex Bennée @ 2024-03-19 14:04 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel, pierrick.bouvier

Richard Henderson <richard.henderson@linaro.org> writes:

> Allow operations to be emitted via normal expanders
> into the middle of the opcode stream.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  include/tcg/tcg.h |  1 +
>  tcg/tcg.c         | 14 ++++++++++++--
>  2 files changed, 13 insertions(+), 2 deletions(-)
>
> diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
> index 451f3fec41..e9d05f40b0 100644
> --- a/include/tcg/tcg.h
> +++ b/include/tcg/tcg.h
> @@ -552,6 +552,7 @@ struct TCGContext {
>  
>      QTAILQ_HEAD(, TCGOp) ops, free_ops;
>      QSIMPLEQ_HEAD(, TCGLabel) labels;
> +    TCGOp *emit_before_op;

Could we add some kdoc comments to the TCGContext describing what each
variables is for. Is this just a list of ops to emit before the current
instruction emulation? Is it cleared between instruction boundaries?

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 06/22] plugins: Create TCGHelperInfo for all out-of-line callbacks
  2024-03-19 13:12   ` Pierrick Bouvier
@ 2024-03-19 19:51     ` Richard Henderson
  2024-03-20  5:22       ` Pierrick Bouvier
  0 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-19 19:51 UTC (permalink / raw)
  To: Pierrick Bouvier, qemu-devel; +Cc: alex.bennee

On 3/19/24 03:12, Pierrick Bouvier wrote:
> On 3/16/24 05:57, Richard Henderson wrote:
>> TCGHelperInfo includes the ABI for every function call.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
>>   include/qemu/plugin.h |  1 +
>>   plugins/core.c        | 51 ++++++++++++++++++++++++++++++++++++++-----
>>   2 files changed, 46 insertions(+), 6 deletions(-)
>>
>> diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
>> index 143262dca8..793c44f1f2 100644
>> --- a/include/qemu/plugin.h
>> +++ b/include/qemu/plugin.h
>> @@ -92,6 +92,7 @@ struct qemu_plugin_dyn_cb {
>>       union {
>>           struct {
>>               union qemu_plugin_cb_sig f;
>> +            TCGHelperInfo *info;
>>           } regular;
>>           struct {
>>               qemu_plugin_u64 entry;
>> diff --git a/plugins/core.c b/plugins/core.c
>> index 837c373690..b0a2e80874 100644
>> --- a/plugins/core.c
>> +++ b/plugins/core.c
>> @@ -338,12 +338,26 @@ void plugin_register_dyn_cb__udata(GArray **arr,
>>                                      enum qemu_plugin_cb_flags flags,
>>                                      void *udata)
>>   {
>> -    struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
>> +    static TCGHelperInfo info[3] = {
>> +        [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG | TCG_CALL_PLUGIN,
>> +        [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG | TCG_CALL_PLUGIN,
>> +        [QEMU_PLUGIN_CB_RW_REGS].flags = TCG_CALL_PLUGIN,
>> +        /*
>> +         * Match qemu_plugin_vcpu_udata_cb_t:
>> +         *   void (*)(uint32_t, void *)
>> +
> 
> Any chance we could have a static assert ensuring this?
> I know it's possible in C11, but I don't know if glib offers something for this.

I don't see how.  While you could ask questions about the pointer type 
qemu_plugin_vcpu_udata_cb_t, you can't ask questions about the function arguments.


r~


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 07/22] plugins: Use emit_before_op for PLUGIN_GEN_AFTER_INSN
  2024-03-19 13:32   ` Pierrick Bouvier
@ 2024-03-19 19:56     ` Richard Henderson
  2024-03-20  5:36       ` Pierrick Bouvier
  0 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-19 19:56 UTC (permalink / raw)
  To: Pierrick Bouvier, qemu-devel; +Cc: alex.bennee

On 3/19/24 03:32, Pierrick Bouvier wrote:
>>   static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>>   {
>> -    TCGOp *op;
>> +    TCGOp *op, *next;
>>       int insn_idx = -1;
>>       pr_ops();
>> -    QTAILQ_FOREACH(op, &tcg_ctx->ops, link) {
>> +    /*
>> +     * While injecting code, we cannot afford to reuse any ebb temps
>> +     * that might be live within the existing opcode stream.
>> +     * The simplest solution is to release them all and create new.
>> +     */
>> +    memset(tcg_ctx->free_temps, 0, sizeof(tcg_ctx->free_temps));
>> +
> 
> Not an expert at this, but wouldn't that break an existing TB that already has some ops on 
> those temps?

No, this only affects allocation of new temps -- if free_temps is empty, a new temp will 
be allocated from tcg_ctx->nb_temps++.

Zeroing free_temps here ensures that we *do not* reuse a temp that might already be live 
across any plugin insertion point.  Between insertion points, we will free plugin temps 
and only reuse those.


r~


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 08/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_TB
  2024-03-19 13:22   ` Pierrick Bouvier
@ 2024-03-19 19:57     ` Richard Henderson
  0 siblings, 0 replies; 57+ messages in thread
From: Richard Henderson @ 2024-03-19 19:57 UTC (permalink / raw)
  To: Pierrick Bouvier, qemu-devel; +Cc: alex.bennee

On 3/19/24 03:22, Pierrick Bouvier wrote:
>> @@ -798,6 +816,25 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>>                   assert(insn != NULL);
>>                   gen_disable_mem_helper(plugin_tb, insn);
>>                   break;
>> +
>> +            case PLUGIN_GEN_FROM_TB:
>> +                assert(insn == NULL);
>> +
>> +                cbs = plugin_tb->cbs[PLUGIN_CB_REGULAR];
>> +                for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
>> +                    struct qemu_plugin_dyn_cb *cb =
>> +                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
>> +                    gen_udata_cb(cb);
>> +                }
>> +
>> +                cbs = plugin_tb->cbs[PLUGIN_CB_INLINE];
>> +                for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
>> +                    struct qemu_plugin_dyn_cb *cb =
>> +                        &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
>> +                    gen_inline_cb(cb);
>> +                }
>> +                break;
>> +
> 
> Maybe I am missing something, but couldn't we simply mix all cbs possible. This way, the 
> order mentioned by user when registering is the only one that matters, and he can select 
> to mix callbacks and inline ops freely.
> Just checking the type of callback would be needed to know which gen_* fn should be used.

See patch 15.  :-)


r~


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 01/22] tcg: Add TCGContext.emit_before_op
  2024-03-19 14:04   ` Alex Bennée
@ 2024-03-19 21:23     ` Richard Henderson
  0 siblings, 0 replies; 57+ messages in thread
From: Richard Henderson @ 2024-03-19 21:23 UTC (permalink / raw)
  To: Alex Bennée; +Cc: qemu-devel, pierrick.bouvier

On 3/19/24 04:04, Alex Bennée wrote:
> Richard Henderson <richard.henderson@linaro.org> writes:
> 
>> Allow operations to be emitted via normal expanders
>> into the middle of the opcode stream.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
>>   include/tcg/tcg.h |  1 +
>>   tcg/tcg.c         | 14 ++++++++++++--
>>   2 files changed, 13 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
>> index 451f3fec41..e9d05f40b0 100644
>> --- a/include/tcg/tcg.h
>> +++ b/include/tcg/tcg.h
>> @@ -552,6 +552,7 @@ struct TCGContext {
>>   
>>       QTAILQ_HEAD(, TCGOp) ops, free_ops;
>>       QSIMPLEQ_HEAD(, TCGLabel) labels;
>> +    TCGOp *emit_before_op;
> 
> Could we add some kdoc comments to the TCGContext describing what each
> variables is for. Is this just a list of ops to emit before the current
> instruction emulation? Is it cleared between instruction boundaries?

It's not a list, it's an insertion point.
Nothing automatic about it; manually controlled by plugin-gen.c.
(I believe it will be useful for cleanup in tcg/optimize.c as well.)


r~



^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 05/22] plugins: Move function pointer in qemu_plugin_dyn_cb
  2024-03-19 13:18   ` Pierrick Bouvier
@ 2024-03-19 21:30     ` Richard Henderson
  2024-03-20  5:31       ` Pierrick Bouvier
  0 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2024-03-19 21:30 UTC (permalink / raw)
  To: Pierrick Bouvier, qemu-devel; +Cc: alex.bennee

On 3/19/24 03:18, Pierrick Bouvier wrote:
> On 3/16/24 05:57, Richard Henderson wrote:
>> The out-of-line function pointer is mutually exclusive
>> with inline expansion, so move it into the union.
>> Wrap the pointer in a structure named 'regular' to match
>> PLUGIN_CB_REGULAR.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
>>   include/qemu/plugin.h  | 4 +++-
>>   accel/tcg/plugin-gen.c | 4 ++--
>>   plugins/core.c         | 8 ++++----
>>   3 files changed, 9 insertions(+), 7 deletions(-)
>>
>> diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
>> index 12a96cea2a..143262dca8 100644
>> --- a/include/qemu/plugin.h
>> +++ b/include/qemu/plugin.h
>> @@ -84,13 +84,15 @@ enum plugin_dyn_cb_subtype {
>>    * instance of a callback to be called upon the execution of a particular TB.
>>    */
>>   struct qemu_plugin_dyn_cb {
>> -    union qemu_plugin_cb_sig f;
>>       void *userp;
>>       enum plugin_dyn_cb_subtype type;
>>       /* @rw applies to mem callbacks only (both regular and inline) */
>>       enum qemu_plugin_mem_rw rw;
>>       /* fields specific to each dyn_cb type go here */
>>       union {
>> +        struct {
>> +            union qemu_plugin_cb_sig f;
>> +        } regular;
>>           struct {
>>               qemu_plugin_u64 entry;
>>               enum qemu_plugin_op op;
> 
> While we are cleaning this, maybe this could be only a union (moving rw and userp to 
> fields), and only type + union would be used.
> Even if we duplicate userp in regular, and mem_cb, it would be much more readable.
> For instance, userp is never used by inline operations.

I was wondering about this.  But I was also thinking about your follow-on patch set to add 
conditional calls: do we want a multiplicity of union members, or will we want separate 
bits and pieces that can be strung together?

E.g.

     TCGCond cond;  /* ALWAYS, or compare entry vs imm. */

     /* PLUGIN_CB_REGULAR_COND or PLUGIN_CB_INLINE_* */
     qemu_plugin_u64 entry;
     uint64_t imm;

     /* PLUGIN_CB_REGULAR_* */
     union qemu_plugin_cb_sig f;
     void *userp;


r~


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 06/22] plugins: Create TCGHelperInfo for all out-of-line callbacks
  2024-03-19 19:51     ` Richard Henderson
@ 2024-03-20  5:22       ` Pierrick Bouvier
  0 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-20  5:22 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/19/24 23:51, Richard Henderson wrote:
> On 3/19/24 03:12, Pierrick Bouvier wrote:
>> On 3/16/24 05:57, Richard Henderson wrote:
>>> TCGHelperInfo includes the ABI for every function call.
>>>
>>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>>> ---
>>>    include/qemu/plugin.h |  1 +
>>>    plugins/core.c        | 51 ++++++++++++++++++++++++++++++++++++++-----
>>>    2 files changed, 46 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
>>> index 143262dca8..793c44f1f2 100644
>>> --- a/include/qemu/plugin.h
>>> +++ b/include/qemu/plugin.h
>>> @@ -92,6 +92,7 @@ struct qemu_plugin_dyn_cb {
>>>        union {
>>>            struct {
>>>                union qemu_plugin_cb_sig f;
>>> +            TCGHelperInfo *info;
>>>            } regular;
>>>            struct {
>>>                qemu_plugin_u64 entry;
>>> diff --git a/plugins/core.c b/plugins/core.c
>>> index 837c373690..b0a2e80874 100644
>>> --- a/plugins/core.c
>>> +++ b/plugins/core.c
>>> @@ -338,12 +338,26 @@ void plugin_register_dyn_cb__udata(GArray **arr,
>>>                                       enum qemu_plugin_cb_flags flags,
>>>                                       void *udata)
>>>    {
>>> -    struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
>>> +    static TCGHelperInfo info[3] = {
>>> +        [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG | TCG_CALL_PLUGIN,
>>> +        [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG | TCG_CALL_PLUGIN,
>>> +        [QEMU_PLUGIN_CB_RW_REGS].flags = TCG_CALL_PLUGIN,
>>> +        /*
>>> +         * Match qemu_plugin_vcpu_udata_cb_t:
>>> +         *   void (*)(uint32_t, void *)
>>> +
>>
>> Any chance we could have a static assert ensuring this?
>> I know it's possible in C11, but I don't know if glib offers something for this.
> 
> I don't see how.  While you could ask questions about the pointer type
> qemu_plugin_vcpu_udata_cb_t, you can't ask questions about the function arguments.
> 

I was thinking about something similar to:
static_assert(typeof(qemu_plugin_vcpu_udata_cb_t) == void (*)(uint32_t, 
void *));

But I don't think it's possible to express this in C standard before 11.

> 
> r~

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 05/22] plugins: Move function pointer in qemu_plugin_dyn_cb
  2024-03-19 21:30     ` Richard Henderson
@ 2024-03-20  5:31       ` Pierrick Bouvier
  0 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-20  5:31 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/20/24 01:30, Richard Henderson wrote:
> On 3/19/24 03:18, Pierrick Bouvier wrote:
>> On 3/16/24 05:57, Richard Henderson wrote:
>>> The out-of-line function pointer is mutually exclusive
>>> with inline expansion, so move it into the union.
>>> Wrap the pointer in a structure named 'regular' to match
>>> PLUGIN_CB_REGULAR.
>>>
>>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>>> ---
>>>    include/qemu/plugin.h  | 4 +++-
>>>    accel/tcg/plugin-gen.c | 4 ++--
>>>    plugins/core.c         | 8 ++++----
>>>    3 files changed, 9 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
>>> index 12a96cea2a..143262dca8 100644
>>> --- a/include/qemu/plugin.h
>>> +++ b/include/qemu/plugin.h
>>> @@ -84,13 +84,15 @@ enum plugin_dyn_cb_subtype {
>>>     * instance of a callback to be called upon the execution of a particular TB.
>>>     */
>>>    struct qemu_plugin_dyn_cb {
>>> -    union qemu_plugin_cb_sig f;
>>>        void *userp;
>>>        enum plugin_dyn_cb_subtype type;
>>>        /* @rw applies to mem callbacks only (both regular and inline) */
>>>        enum qemu_plugin_mem_rw rw;
>>>        /* fields specific to each dyn_cb type go here */
>>>        union {
>>> +        struct {
>>> +            union qemu_plugin_cb_sig f;
>>> +        } regular;
>>>            struct {
>>>                qemu_plugin_u64 entry;
>>>                enum qemu_plugin_op op;
>>
>> While we are cleaning this, maybe this could be only a union (moving rw and userp to
>> fields), and only type + union would be used.
>> Even if we duplicate userp in regular, and mem_cb, it would be much more readable.
>> For instance, userp is never used by inline operations.
> 
> I was wondering about this.  But I was also thinking about your follow-on patch set to add
> conditional calls: do we want a multiplicity of union members, or will we want separate
> bits and pieces that can be strung together?
> 
> E.g.
> 
>       TCGCond cond;  /* ALWAYS, or compare entry vs imm. */
> 
>       /* PLUGIN_CB_REGULAR_COND or PLUGIN_CB_INLINE_* */
>       qemu_plugin_u64 entry;
>       uint64_t imm;
> 
>       /* PLUGIN_CB_REGULAR_* */
>       union qemu_plugin_cb_sig f;
>       void *userp;
> 
> 

In an ideal world:

struct regular_cb {
    // full data for regular cb
};

struct conditional_cb {
    // full data for cond cb
};

struct inline_op {
    // full data for inline op
};

...

and

struct qemu_plugin_dyn_cb {
    enum plugin_dyn_cb_subtype type;
    union {
        struct regular_cb regular;
        struct conditional_cb conditional;
        struct inline_op inline;
    };
};

It's the same as describing the structs directly inside union, but at 
least you can duplicate fields without thinking too much. In terms of 
memory layout it does not change anything, the upper bound is still the 
largest struct, whether you share fields or not.

In short, an algebraic data type. Hope it's not a bad word around here :)

> r~

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 07/22] plugins: Use emit_before_op for PLUGIN_GEN_AFTER_INSN
  2024-03-19 19:56     ` Richard Henderson
@ 2024-03-20  5:36       ` Pierrick Bouvier
  0 siblings, 0 replies; 57+ messages in thread
From: Pierrick Bouvier @ 2024-03-20  5:36 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: alex.bennee

On 3/19/24 23:56, Richard Henderson wrote:
> On 3/19/24 03:32, Pierrick Bouvier wrote:
>>>    static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
>>>    {
>>> -    TCGOp *op;
>>> +    TCGOp *op, *next;
>>>        int insn_idx = -1;
>>>        pr_ops();
>>> -    QTAILQ_FOREACH(op, &tcg_ctx->ops, link) {
>>> +    /*
>>> +     * While injecting code, we cannot afford to reuse any ebb temps
>>> +     * that might be live within the existing opcode stream.
>>> +     * The simplest solution is to release them all and create new.
>>> +     */
>>> +    memset(tcg_ctx->free_temps, 0, sizeof(tcg_ctx->free_temps));
>>> +
>>
>> Not an expert at this, but wouldn't that break an existing TB that already has some ops on
>> those temps?
> 
> No, this only affects allocation of new temps -- if free_temps is empty, a new temp will
> be allocated from tcg_ctx->nb_temps++.
> 
> Zeroing free_temps here ensures that we *do not* reuse a temp that might already be live
> across any plugin insertion point.  Between insertion points, we will free plugin temps
> and only reuse those.
> 

Thanks, by looking at tcg_temp_new_internal fn, and with your 
explaination, it makes more sense.

> 
> r~

^ permalink raw reply	[flat|nested] 57+ messages in thread

end of thread, other threads:[~2024-03-20  5:37 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-03-16  1:56 [PATCH 00/22] plugins: Rewrite plugin code generation Richard Henderson
2024-03-16  1:56 ` [PATCH 01/22] tcg: Add TCGContext.emit_before_op Richard Henderson
2024-03-19 10:55   ` Pierrick Bouvier
2024-03-19 14:04   ` Alex Bennée
2024-03-19 21:23     ` Richard Henderson
2024-03-16  1:57 ` [PATCH 02/22] tcg: Make tcg/helper-info.h self-contained Richard Henderson
2024-03-18 10:01   ` Alex Bennée
2024-03-18 10:03   ` Alex Bennée
2024-03-16  1:57 ` [PATCH 03/22] tcg: Pass function pointer to tcg_gen_call* Richard Henderson
2024-03-18 10:02   ` Alex Bennée
2024-03-16  1:57 ` [PATCH 04/22] plugins: Zero new qemu_plugin_dyn_cb entries Richard Henderson
2024-03-18 10:03   ` Alex Bennée
2024-03-16  1:57 ` [PATCH 05/22] plugins: Move function pointer in qemu_plugin_dyn_cb Richard Henderson
2024-03-18 10:04   ` Alex Bennée
2024-03-19 13:18   ` Pierrick Bouvier
2024-03-19 21:30     ` Richard Henderson
2024-03-20  5:31       ` Pierrick Bouvier
2024-03-16  1:57 ` [PATCH 06/22] plugins: Create TCGHelperInfo for all out-of-line callbacks Richard Henderson
2024-03-19 13:12   ` Pierrick Bouvier
2024-03-19 19:51     ` Richard Henderson
2024-03-20  5:22       ` Pierrick Bouvier
2024-03-16  1:57 ` [PATCH 07/22] plugins: Use emit_before_op for PLUGIN_GEN_AFTER_INSN Richard Henderson
2024-03-19 13:32   ` Pierrick Bouvier
2024-03-19 19:56     ` Richard Henderson
2024-03-20  5:36       ` Pierrick Bouvier
2024-03-16  1:57 ` [PATCH 08/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_TB Richard Henderson
2024-03-19 13:22   ` Pierrick Bouvier
2024-03-19 19:57     ` Richard Henderson
2024-03-16  1:57 ` [PATCH 09/22] plugins: Add PLUGIN_GEN_AFTER_TB Richard Henderson
2024-03-19 13:33   ` Pierrick Bouvier
2024-03-16  1:57 ` [PATCH 10/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_INSN Richard Henderson
2024-03-19 13:34   ` Pierrick Bouvier
2024-03-16  1:57 ` [PATCH 11/22] plugins: Use emit_before_op for PLUGIN_GEN_FROM_MEM Richard Henderson
2024-03-19 13:35   ` Pierrick Bouvier
2024-03-16  1:57 ` [PATCH 12/22] plugins: Remove plugin helpers Richard Henderson
2024-03-18 16:38   ` Alex Bennée
2024-03-16  1:57 ` [PATCH 13/22] tcg: Remove TCG_CALL_PLUGIN Richard Henderson
2024-03-19 13:06   ` Pierrick Bouvier
2024-03-16  1:57 ` [PATCH 14/22] tcg: Remove INDEX_op_plugin_cb_{start,end} Richard Henderson
2024-03-19 13:04   ` Pierrick Bouvier
2024-03-16  1:57 ` [PATCH 15/22] plugins: Simplify callback queues Richard Henderson
2024-03-19 13:28   ` Pierrick Bouvier
2024-03-16  1:57 ` [PATCH 16/22] plugins: Introduce PLUGIN_CB_MEM_REGULAR Richard Henderson
2024-03-19 13:28   ` Pierrick Bouvier
2024-03-16  1:57 ` [PATCH 17/22] plugins: Replace pr_ops with a proper debug dump flag Richard Henderson
2024-03-19 12:59   ` Pierrick Bouvier
2024-03-16  1:57 ` [PATCH 18/22] plugins: Split out common cb expanders Richard Henderson
2024-03-19 13:29   ` Pierrick Bouvier
2024-03-16  1:57 ` [PATCH 19/22] plugins: Merge qemu_plugin_tb_insn_get to plugin-gen.c Richard Henderson
2024-03-19 13:30   ` Pierrick Bouvier
2024-03-16  1:57 ` [PATCH 20/22] plugins: Move qemu_plugin_insn_cleanup_fn to tcg.c Richard Henderson
2024-03-18 17:44   ` Alex Bennée
2024-03-16  1:57 ` [PATCH 21/22] plugins: Inline plugin_gen_empty_callback Richard Henderson
2024-03-18 19:09   ` Alex Bennée
2024-03-16  1:57 ` [PATCH 22/22] plugins: Update the documentation block for plugin-gen.c Richard Henderson
2024-03-19 12:56   ` Pierrick Bouvier
2024-03-19 13:38 ` [PATCH 00/22] plugins: Rewrite plugin code generation Pierrick Bouvier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).