Commit 1b4406d2 authored by Athira Rajeev's avatar Athira Rajeev Committed by Arnaldo Carvalho de Melo
Browse files

perf annotate: Update parameters for reg extract functions to use raw instruction on powerpc



Use the raw instruction code and macros to identify memory instructions,
extract register fields and also offset.

The implementation addresses the D-form, X-form, DS-form instructions.

Adds "mem_ref" field to check whether source/target has memory
reference.

Add function "get_powerpc_regs" which will set these fields: reg1, reg2,
offset depending of where it is source or target ops.

Update "parse" callback for "struct ins_ops" to also pass "struct
disasm_line" as argument. This is needed in parse functions where opcode
is used to determine whether to set multi_regs and other fields

Reviewed-by: default avatarKajol Jain <kjain@linux.ibm.com>
Reviewed-by: default avatarNamhyung Kim <namhyung@kernel.org>
Signed-off-by: default avatarAthira Rajeev <atrajeev@linux.vnet.ibm.com>
Tested-by: default avatarKajol 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-7-atrajeev@linux.vnet.ibm.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 0b971e6b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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;

+4 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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;
+44 −0
Original line number Diff line number Diff line
@@ -107,3 +107,47 @@ int regs_query_register_offset(const char *name)
#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);
}
+3 −2
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
#include <linux/compiler.h>

static int s390_call__parse(struct arch *arch, struct ins_operands *ops,
			    struct map_symbol *ms)
			    struct map_symbol *ms, struct disasm_line *dl __maybe_unused)
{
	char *endptr, *tok, *name;
	struct map *map = ms->map;
@@ -52,7 +52,8 @@ static struct ins_ops s390_call_ops = {

static int s390_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;

+16 −3
Original line number Diff line number Diff line
@@ -2123,20 +2123,33 @@ int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl,
	for_each_insn_op_loc(loc, i, op_loc) {
		const char *insn_str = ops->source.raw;
		bool multi_regs = ops->source.multi_regs;
		bool mem_ref = ops->source.mem_ref;

		if (i == INSN_OP_TARGET) {
			insn_str = ops->target.raw;
			multi_regs = ops->target.multi_regs;
			mem_ref = ops->target.mem_ref;
		}

		/* Invalidate the register by default */
		op_loc->reg1 = -1;
		op_loc->reg2 = -1;

		if (insn_str == NULL)
		if (insn_str == NULL) {
			if (!arch__is(arch, "powerpc"))
				continue;
		}

		if (strchr(insn_str, arch->objdump.memory_ref_char)) {
		/*
		 * For powerpc, call get_powerpc_regs function which extracts the
		 * required fields for op_loc, ie reg1, reg2, offset from the
		 * raw instruction.
		 */
		if (arch__is(arch, "powerpc")) {
			op_loc->mem_ref = mem_ref;
			op_loc->multi_regs = multi_regs;
			get_powerpc_regs(dl->raw.raw_insn, !i, op_loc);
		} else if (strchr(insn_str, arch->objdump.memory_ref_char)) {
			op_loc->mem_ref = true;
			op_loc->multi_regs = multi_regs;
			extract_reg_offset(arch, insn_str, op_loc);
Loading