diff options
| author | Ian Rogers <irogers@google.com> | 2026-01-22 13:35:12 -0800 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2026-01-23 16:58:38 -0300 |
| commit | 07b972ff09f45cfb7acd20cd9b3769c6975bc434 (patch) | |
| tree | f8cecf6a6a63113dd96b4305a42ef5af5eecef2b /tools/perf/arch/powerpc | |
| parent | 9273085273103e5994952dc2725f1f0109af97d1 (diff) | |
| download | lwn-07b972ff09f45cfb7acd20cd9b3769c6975bc434.tar.gz lwn-07b972ff09f45cfb7acd20cd9b3769c6975bc434.zip | |
perf disasm: Don't include C files from the arch directory
Move the arch instructions.c files into appropriately named files in
annotate-arch in the util directory.
Don't #include to compile the code, switch to building the files and fix
up the #includes accordingly.
Move powerpc specific disasm code out of disasm.c and into
annotate-powerpc.c.
Declarations and static removed as appropriate for the code to compile
as separate compilation units.
The e_machine and e_flags set up is moved to the disasm.c architectures
array so that later patches can sort by them.
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Aditya Bodkhe <aditya.b1@linux.ibm.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Albert Ou <aou@eecs.berkeley.edu>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Ghiti <alex@ghiti.fr>
Cc: Athira Rajeev <atrajeev@linux.ibm.com>
Cc: Bill Wendling <morbo@google.com>
Cc: Dr. David Alan Gilbert <linux@treblig.org>
Cc: Guo Ren <guoren@kernel.org>
Cc: Howard Chu <howardchu95@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Julia Lawall <Julia.Lawall@inria.fr>
Cc: Justin Stitt <justinstitt@google.com>
Cc: Krzysztof Łopatowski <krzysztof.m.lopatowski@gmail.com>
Cc: Leo Yan <leo.yan@linux.dev>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nick Desaulniers <nick.desaulniers+lkml@gmail.com>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Paul Walmsley <pjw@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sergei Trofimovich <slyich@gmail.com>
Cc: Shimin Guo <shimin.guo@skydio.com>
Cc: Suchit Karunakaran <suchitkarunakaran@gmail.com>
Cc: Thomas Falcon <thomas.falcon@intel.com>
Cc: Tianyou Li <tianyou.li@intel.com>
Cc: Will Deacon <will@kernel.org>
Cc: Zecheng Li <zecheng@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/arch/powerpc')
| -rw-r--r-- | tools/perf/arch/powerpc/annotate/instructions.c | 317 |
1 files changed, 0 insertions, 317 deletions
diff --git a/tools/perf/arch/powerpc/annotate/instructions.c b/tools/perf/arch/powerpc/annotate/instructions.c deleted file mode 100644 index d1be55425e35..000000000000 --- a/tools/perf/arch/powerpc/annotate/instructions.c +++ /dev/null @@ -1,317 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/compiler.h> - -static const struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, const char *name) -{ - int i; - const struct ins_ops *ops; - - /* - * - Interested only if instruction starts with 'b'. - * - Few start with 'b', but aren't branch instructions. - */ - if (name[0] != 'b' || - !strncmp(name, "bcd", 3) || - !strncmp(name, "brinc", 5) || - !strncmp(name, "bper", 4)) - return NULL; - - ops = &jump_ops; - - i = strlen(name) - 1; - if (i < 0) - return NULL; - - /* ignore optional hints at the end of the instructions */ - if (name[i] == '+' || name[i] == '-') - i--; - - if (name[i] == 'l' || (name[i] == 'a' && name[i-1] == 'l')) { - /* - * if the instruction ends up with 'l' or 'la', then - * those are considered 'calls' since they update LR. - * ... except for 'bnl' which is branch if not less than - * and the absolute form of the same. - */ - if (strcmp(name, "bnl") && strcmp(name, "bnl+") && - strcmp(name, "bnl-") && strcmp(name, "bnla") && - strcmp(name, "bnla+") && strcmp(name, "bnla-")) - ops = &call_ops; - } - if (name[i] == 'r' && name[i-1] == 'l') - /* - * instructions ending with 'lr' are considered to be - * return instructions - */ - ops = &ret_ops; - - arch__associate_ins_ops(arch, name, ops); - return ops; -} - -#define PPC_OP(op) (((op) >> 26) & 0x3F) -#define PPC_21_30(R) (((R) >> 1) & 0x3ff) -#define PPC_22_30(R) (((R) >> 1) & 0x1ff) - -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, }, -}; - -/* - * Arithmetic instructions which are having opcode as 31. - * These instructions are tracked to save the register state - * changes. Example: - * - * lwz r10,264(r3) - * add r31, r3, r3 - * lwz r9, 0(r31) - * - * Here instruction tracking needs to identify the "add" - * instruction and save data type of r3 to r31. If a sample - * is hit at next "lwz r9, 0(r31)", by this instruction tracking, - * data type of r31 can be resolved. - */ -static struct insn_offset arithmetic_ins_op_31[] = { - { .name = "SUB_CARRY_XO_FORM", .value = 8, }, - { .name = "MUL_HDW_XO_FORM1", .value = 9, }, - { .name = "ADD_CARRY_XO_FORM", .value = 10, }, - { .name = "MUL_HW_XO_FORM1", .value = 11, }, - { .name = "SUB_XO_FORM", .value = 40, }, - { .name = "MUL_HDW_XO_FORM", .value = 73, }, - { .name = "MUL_HW_XO_FORM", .value = 75, }, - { .name = "SUB_EXT_XO_FORM", .value = 136, }, - { .name = "ADD_EXT_XO_FORM", .value = 138, }, - { .name = "SUB_ZERO_EXT_XO_FORM", .value = 200, }, - { .name = "ADD_ZERO_EXT_XO_FORM", .value = 202, }, - { .name = "SUB_EXT_XO_FORM2", .value = 232, }, - { .name = "MUL_DW_XO_FORM", .value = 233, }, - { .name = "ADD_EXT_XO_FORM2", .value = 234, }, - { .name = "MUL_W_XO_FORM", .value = 235, }, - { .name = "ADD_XO_FORM", .value = 266, }, - { .name = "DIV_DW_XO_FORM1", .value = 457, }, - { .name = "DIV_W_XO_FORM1", .value = 459, }, - { .name = "DIV_DW_XO_FORM", .value = 489, }, - { .name = "DIV_W_XO_FORM", .value = 491, }, -}; - -static struct insn_offset arithmetic_two_ops[] = { - { .name = "mulli", .value = 7, }, - { .name = "subfic", .value = 8, }, - { .name = "addic", .value = 12, }, - { .name = "addic.", .value = 13, }, - { .name = "addi", .value = 14, }, - { .name = "addis", .value = 15, }, -}; - -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 const struct ins_ops *check_ppc_insn(struct disasm_line *dl) -{ - int raw_insn = dl->raw.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 - }; - char name_insn[32]; - - /* - * Instructions with opcode 32 to 63 are memory - * instructions in powerpc - */ - if ((opcode & 0x20)) { - /* - * Set name in case of raw instruction to - * opcode to be used in insn-stat - */ - if (!strlen(dl->ins.name)) { - sprintf(name_insn, "%d", opcode); - dl->ins.name = strdup(name_insn); - } - 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) { - if (!strlen(dl->ins.name)) - dl->ins.name = strdup(ret->name); - return &load_store_ops; - } else { - mem_insns_31_opcode.value = PPC_22_30(raw_insn); - ret = bsearch(&mem_insns_31_opcode, arithmetic_ins_op_31, ARRAY_SIZE(arithmetic_ins_op_31), - sizeof(arithmetic_ins_op_31[0]), cmp_offset); - if (ret != NULL) - return &arithmetic_ops; - /* Bits 21 to 30 has value 444 for "mr" insn ie, OR X form */ - if (PPC_21_30(raw_insn) == 444) - return &arithmetic_ops; - } - } else { - mem_insns_31_opcode.value = opcode; - ret = bsearch(&mem_insns_31_opcode, arithmetic_two_ops, ARRAY_SIZE(arithmetic_two_ops), - sizeof(arithmetic_two_ops[0]), cmp_offset); - if (ret != NULL) - return &arithmetic_ops; - } - - return NULL; -} - -/* - * Instruction tracking function to track register state moves. - * Example sequence: - * ld r10,264(r3) - * mr r31,r3 - * <<after some sequence> - * ld r9,312(r31) - * - * Previous instruction sequence shows that register state of r3 - * is moved to r31. update_insn_state_powerpc tracks these state - * changes - */ -#ifdef HAVE_LIBDW_SUPPORT -static void update_insn_state_powerpc(struct type_state *state, - struct data_loc_info *dloc, Dwarf_Die * cu_die __maybe_unused, - struct disasm_line *dl) -{ - struct annotated_insn_loc loc; - struct annotated_op_loc *src = &loc.ops[INSN_OP_SOURCE]; - struct annotated_op_loc *dst = &loc.ops[INSN_OP_TARGET]; - struct type_state_reg *tsr; - u32 insn_offset = dl->al.offset; - - if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0) - return; - - /* - * Value 444 for bits 21:30 is for "mr" - * instruction. "mr" is extended OR. So set the - * source and destination reg correctly - */ - if (PPC_21_30(dl->raw.raw_insn) == 444) { - int src_reg = src->reg1; - - src->reg1 = dst->reg1; - dst->reg1 = src_reg; - } - - if (!has_reg_type(state, dst->reg1)) - return; - - tsr = &state->regs[dst->reg1]; - - if (!has_reg_type(state, src->reg1) || - !state->regs[src->reg1].ok) { - tsr->ok = false; - return; - } - - tsr->type = state->regs[src->reg1].type; - tsr->kind = state->regs[src->reg1].kind; - tsr->ok = true; - - pr_debug_dtp("mov [%x] reg%d -> reg%d", - insn_offset, src->reg1, dst->reg1); - pr_debug_type_name(&tsr->type, tsr->kind); -} -#endif /* HAVE_LIBDW_SUPPORT */ - -static int powerpc__annotate_init(struct arch *arch, char *cpuid __maybe_unused) -{ - if (!arch->initialized) { - arch->initialized = true; - arch->associate_instruction_ops = powerpc__associate_instruction_ops; - arch->objdump.comment_char = '#'; - annotate_opts.show_asm_raw = true; - arch->e_machine = EM_PPC; - arch->e_flags = 0; - } - - return 0; -} |
