perf annotate: Add support to identify memory instructions of opcode 31 in powerpc
authorAthira Rajeev <atrajeev@linux.vnet.ibm.com>
Thu, 18 Jul 2024 08:43:51 +0000 (14:13 +0530)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 31 Jul 2024 19:12:59 +0000 (16:12 -0300)
There are memory instructions in powerpc with opcode as 31.
Example: "ldx RT,RA,RB" , Its X form is as below:

  ______________________________________
  | 31 |  RT  |  RA |  RB |   21     |/|
  --------------------------------------
  0    6     11    16    21         30 31

The opcode for "ldx" is 31. There are other instructions also with
opcode 31 which are memory insn like ldux, stbx, lwzx, lhaux
But all instructions with opcode 31 are not memory. Example is add
instruction: "add RT,RA,RB"

The value in bit 21-30 [ 21 for ldx ] is different for these
instructions. Patch uses this value to assign instruction ops for these
cases. The naming convention and value to identify these are picked from
defines in "arch/powerpc/include/asm/ppc-opcode.h"

Reviewed-by: Kajol Jain <kjain@linux.ibm.com>
Reviewed-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
Tested-by: Kajol Jain <kjain@linux.ibm.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Akanksha J N <akanksha@linux.ibm.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Disha Goel <disgoel@linux.vnet.ibm.com>
Cc: Hari Bathini <hbathini@linux.ibm.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Segher Boessenkool <segher@kernel.crashing.org>
Link: https://lore.kernel.org/lkml/20240718084358.72242-9-atrajeev@linux.vnet.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/arch/powerpc/annotate/instructions.c
tools/perf/util/disasm.c

index b084423..1ffb64c 100644 (file)
@@ -49,18 +49,121 @@ static struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, con
        return ops;
 }
 
-#define PPC_OP(op)      (((op) >> 26) & 0x3F)
+#define PPC_OP(op)     (((op) >> 26) & 0x3F)
+#define PPC_21_30(R)   (((R) >> 1) & 0x3ff)
+
+struct insn_offset {
+       const char      *name;
+       int             value;
+};
+
+/*
+ * There are memory instructions with opcode 31 which are
+ * of X Form, Example:
+ * ldx RT,RA,RB
+ * ______________________________________
+ * | 31 |  RT  |  RA |  RB |   21     |/|
+ * --------------------------------------
+ * 0    6     11    16    21         30 31
+ *
+ * But all instructions with opcode 31 are not memory.
+ * Example: add RT,RA,RB
+ *
+ * Use bits 21 to 30 to check memory insns with 31 as opcode.
+ * In ins_array below, for ldx instruction:
+ * name => OP_31_XOP_LDX
+ * value => 21
+ */
+
+static struct insn_offset ins_array[] = {
+       { .name = "OP_31_XOP_LXSIWZX",  .value = 12, },
+       { .name = "OP_31_XOP_LWARX",    .value = 20, },
+       { .name = "OP_31_XOP_LDX",      .value = 21, },
+       { .name = "OP_31_XOP_LWZX",     .value = 23, },
+       { .name = "OP_31_XOP_LDUX",     .value = 53, },
+       { .name = "OP_31_XOP_LWZUX",    .value = 55, },
+       { .name = "OP_31_XOP_LXSIWAX",  .value = 76, },
+       { .name = "OP_31_XOP_LDARX",    .value = 84, },
+       { .name = "OP_31_XOP_LBZX",     .value = 87, },
+       { .name = "OP_31_XOP_LVX",      .value = 103, },
+       { .name = "OP_31_XOP_LBZUX",    .value = 119, },
+       { .name = "OP_31_XOP_STXSIWX",  .value = 140, },
+       { .name = "OP_31_XOP_STDX",     .value = 149, },
+       { .name = "OP_31_XOP_STWX",     .value = 151, },
+       { .name = "OP_31_XOP_STDUX",    .value = 181, },
+       { .name = "OP_31_XOP_STWUX",    .value = 183, },
+       { .name = "OP_31_XOP_STBX",     .value = 215, },
+       { .name = "OP_31_XOP_STVX",     .value = 231, },
+       { .name = "OP_31_XOP_STBUX",    .value = 247, },
+       { .name = "OP_31_XOP_LHZX",     .value = 279, },
+       { .name = "OP_31_XOP_LHZUX",    .value = 311, },
+       { .name = "OP_31_XOP_LXVDSX",   .value = 332, },
+       { .name = "OP_31_XOP_LWAX",     .value = 341, },
+       { .name = "OP_31_XOP_LHAX",     .value = 343, },
+       { .name = "OP_31_XOP_LWAUX",    .value = 373, },
+       { .name = "OP_31_XOP_LHAUX",    .value = 375, },
+       { .name = "OP_31_XOP_STHX",     .value = 407, },
+       { .name = "OP_31_XOP_STHUX",    .value = 439, },
+       { .name = "OP_31_XOP_LXSSPX",   .value = 524, },
+       { .name = "OP_31_XOP_LDBRX",    .value = 532, },
+       { .name = "OP_31_XOP_LSWX",     .value = 533, },
+       { .name = "OP_31_XOP_LWBRX",    .value = 534, },
+       { .name = "OP_31_XOP_LFSUX",    .value = 567, },
+       { .name = "OP_31_XOP_LXSDX",    .value = 588, },
+       { .name = "OP_31_XOP_LSWI",     .value = 597, },
+       { .name = "OP_31_XOP_LFDX",     .value = 599, },
+       { .name = "OP_31_XOP_LFDUX",    .value = 631, },
+       { .name = "OP_31_XOP_STXSSPX",  .value = 652, },
+       { .name = "OP_31_XOP_STDBRX",   .value = 660, },
+       { .name = "OP_31_XOP_STXWX",    .value = 661, },
+       { .name = "OP_31_XOP_STWBRX",   .value = 662, },
+       { .name = "OP_31_XOP_STFSX",    .value = 663, },
+       { .name = "OP_31_XOP_STFSUX",   .value = 695, },
+       { .name = "OP_31_XOP_STXSDX",   .value = 716, },
+       { .name = "OP_31_XOP_STSWI",    .value = 725, },
+       { .name = "OP_31_XOP_STFDX",    .value = 727, },
+       { .name = "OP_31_XOP_STFDUX",   .value = 759, },
+       { .name = "OP_31_XOP_LXVW4X",   .value = 780, },
+       { .name = "OP_31_XOP_LHBRX",    .value = 790, },
+       { .name = "OP_31_XOP_LXVD2X",   .value = 844, },
+       { .name = "OP_31_XOP_LFIWAX",   .value = 855, },
+       { .name = "OP_31_XOP_LFIWZX",   .value = 887, },
+       { .name = "OP_31_XOP_STXVW4X",  .value = 908, },
+       { .name = "OP_31_XOP_STHBRX",   .value = 918, },
+       { .name = "OP_31_XOP_STXVD2X",  .value = 972, },
+       { .name = "OP_31_XOP_STFIWX",   .value = 983, },
+};
+
+static int cmp_offset(const void *a, const void *b)
+{
+       const struct insn_offset *val1 = a;
+       const struct insn_offset *val2 = b;
+
+       return (val1->value - val2->value);
+}
 
 static struct ins_ops *check_ppc_insn(u32 raw_insn)
 {
        int opcode = PPC_OP(raw_insn);
+       int mem_insn_31 = PPC_21_30(raw_insn);
+       struct insn_offset *ret;
+       struct insn_offset mem_insns_31_opcode = {
+               "OP_31_INSN",
+               mem_insn_31
+       };
 
        /*
         * Instructions with opcode 32 to 63 are memory
         * instructions in powerpc
         */
-       if ((opcode & 0x20))
+       if ((opcode & 0x20)) {
                return &load_store_ops;
+       } else if (opcode == 31) {
+               /* Check for memory instructions with opcode 31 */
+               ret = bsearch(&mem_insns_31_opcode, ins_array, ARRAY_SIZE(ins_array), sizeof(ins_array[0]), cmp_offset);
+               if (ret != NULL)
+                       return &load_store_ops;
+       }
 
        return NULL;
 }
index 0afa184..e36be7b 100644 (file)
@@ -697,6 +697,9 @@ static int load_store__parse(struct arch *arch __maybe_unused, struct ins_operan
 {
        ops->source.mem_ref = true;
        ops->source.multi_regs = false;
+       /* opcode 31 is of X form */
+       if (PPC_OP(dl->raw.raw_insn) == 31)
+               ops->source.multi_regs = true;
 
        ops->target.mem_ref = false;
        ops->target.multi_regs = false;