Skip to content

Commit

Permalink
From patchwork series 413207
Browse files Browse the repository at this point in the history
  • Loading branch information
Fox Snowpatch committed Jul 1, 2024
1 parent 18bc7f1 commit 995f195
Show file tree
Hide file tree
Showing 21 changed files with 1,399 additions and 505 deletions.
2 changes: 2 additions & 0 deletions tools/include/linux/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,7 @@ extern char * __must_check skip_spaces(const char *);

extern char *strim(char *);

extern void remove_spaces(char *s);

extern void *memchr_inv(const void *start, int c, size_t bytes);
#endif /* _TOOLS_LINUX_STRING_H_ */
13 changes: 13 additions & 0 deletions tools/lib/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,19 @@ char *strim(char *s)
return skip_spaces(s);
}

/*
* remove_spaces - Removes whitespaces from @s
*/
void remove_spaces(char *s)
{
char *d = s;

do {
while (*d == ' ')
++d;
} while ((*s++ = *d++));
}

/**
* strreplace - Replace all occurrences of character in string.
* @s: The string to operate on.
Expand Down
3 changes: 2 additions & 1 deletion tools/perf/arch/arm64/annotate/instructions.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ struct arm64_annotate {

static int arm64_mov__parse(struct arch *arch __maybe_unused,
struct ins_operands *ops,
struct map_symbol *ms __maybe_unused)
struct map_symbol *ms __maybe_unused,
struct disasm_line *dl __maybe_unused)
{
char *s = strchr(ops->raw, ','), *target, *endptr;

Expand Down
6 changes: 4 additions & 2 deletions tools/perf/arch/loongarch/annotate/instructions.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
* Copyright (C) 2020-2023 Loongson Technology Corporation Limited
*/

static int loongarch_call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
static int loongarch_call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms,
struct disasm_line *dl __maybe_unused)
{
char *c, *endptr, *tok, *name;
struct map *map = ms->map;
Expand Down Expand Up @@ -51,7 +52,8 @@ static struct ins_ops loongarch_call_ops = {
.scnprintf = call__scnprintf,
};

static int loongarch_jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
static int loongarch_jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms,
struct disasm_line *dl __maybe_unused)
{
struct map *map = ms->map;
struct symbol *sym = ms->sym;
Expand Down
254 changes: 254 additions & 0 deletions tools/perf/arch/powerpc/annotate/instructions.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,266 @@ static struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, con
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 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_DWARF_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, dloc->arch))
return;

tsr = &state->regs[dst->reg1];

if (!has_reg_type(state, src->reg1, dloc->arch) ||
!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_DWARF_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;
}

return 0;
Expand Down
53 changes: 53 additions & 0 deletions tools/perf/arch/powerpc/util/dwarf-regs.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,56 @@ int regs_query_register_offset(const char *name)
return roff->ptregs_offset;
return -EINVAL;
}

#define PPC_OP(op) (((op) >> 26) & 0x3F)
#define PPC_RA(a) (((a) >> 16) & 0x1f)
#define PPC_RT(t) (((t) >> 21) & 0x1f)
#define PPC_RB(b) (((b) >> 11) & 0x1f)
#define PPC_D(D) ((D) & 0xfffe)
#define PPC_DS(DS) ((DS) & 0xfffc)
#define OP_LD 58
#define OP_STD 62

static int get_source_reg(u32 raw_insn)
{
return PPC_RA(raw_insn);
}

static int get_target_reg(u32 raw_insn)
{
return PPC_RT(raw_insn);
}

static int get_offset_opcode(u32 raw_insn)
{
int opcode = PPC_OP(raw_insn);

/* DS- form */
if ((opcode == OP_LD) || (opcode == OP_STD))
return PPC_DS(raw_insn);
else
return PPC_D(raw_insn);
}

/*
* Fills the required fields for op_loc depending on if it
* is a source or target.
* D form: ins RT,D(RA) -> src_reg1 = RA, offset = D, dst_reg1 = RT
* DS form: ins RT,DS(RA) -> src_reg1 = RA, offset = DS, dst_reg1 = RT
* X form: ins RT,RA,RB -> src_reg1 = RA, src_reg2 = RB, dst_reg1 = RT
*/
void get_powerpc_regs(u32 raw_insn, int is_source,
struct annotated_op_loc *op_loc)
{
if (is_source)
op_loc->reg1 = get_source_reg(raw_insn);
else
op_loc->reg1 = get_target_reg(raw_insn);

if (op_loc->multi_regs)
op_loc->reg2 = PPC_RB(raw_insn);

/* TODO: Implement offset handling for X Form */
if ((op_loc->mem_ref) && (PPC_OP(raw_insn) != 31))
op_loc->offset = get_offset_opcode(raw_insn);
}
Loading

0 comments on commit 995f195

Please sign in to comment.