In the perf annotate view for LoongArch, there is no arrowed line
pointing to the target from the branch instruction. This issue is
caused by incorrect instruction association and parsing.
$ perf record alloc-6276705c94ad1398 # rust benchmark
$ perf report
0.28 │ ori $a1, $zero, 0x63
│ move $a2, $zero
10.55 │ addi.d $a3, $a2, 1(0x1)
│ sltu $a4, $a3, $s7
9.53 │ masknez $a4, $s7, $a4
│ sub.d $a3, $a3, $a4
12.12 │ st.d $a1, $fp, 24(0x18)
│ st.d $a3, $fp, 16(0x10)
16.29 │ slli.d $a2, $a2, 0x2
│ ldx.w $a2, $s8, $a2
12.77 │ st.w $a2, $sp, 724(0x2d4)
│ st.w $s0, $sp, 720(0x2d0)
7.03 │ addi.d $a2, $sp, 720(0x2d0)
│ addi.d $a1, $a1, -1(0xfff)
12.03 │ move $a2, $a3
│ → bne $a1, $s3, -52(0x3ffcc) # 82ce8 <test::bench::Bencher::iter+0x3f4>
2.50 │ addi.d $a0, $a0, 1(0x1)
This patch fixes instruction association issues, such as associating
branch instructions with jump_ops instead of call_ops, and corrects
false instruction matches. It also implements branch instruction parsing
specifically for LoongArch. With this patch, we will be able to see the
arrowed line.
0.79 │3ec: ori $a1, $zero, 0x63
│ move $a2, $zero
10.32 │3f4:┌─→addi.d $a3, $a2, 1(0x1)
│ │ sltu $a4, $a3, $s7
10.44 │ │ masknez $a4, $s7, $a4
│ │ sub.d $a3, $a3, $a4
14.17 │ │ st.d $a1, $fp, 24(0x18)
│ │ st.d $a3, $fp, 16(0x10)
13.15 │ │ slli.d $a2, $a2, 0x2
│ │ ldx.w $a2, $s8, $a2
11.00 │ │ st.w $a2, $sp, 724(0x2d4)
│ │ st.w $s0, $sp, 720(0x2d0)
8.00 │ │ addi.d $a2, $sp, 720(0x2d0)
│ │ addi.d $a1, $a1, -1(0xfff)
11.99 │ │ move $a2, $a3
│ └──bne $a1, $s3, 3f4
3.17 │ addi.d $a0, $a0, 1(0x1)
Signed-off-by: WANG Rui <[email protected]>
---
.../arch/loongarch/annotate/instructions.c | 116 ++++++++++++++++--
tools/perf/arch/s390/annotate/instructions.c | 3 -
tools/perf/util/annotate.c | 8 +-
3 files changed, 109 insertions(+), 18 deletions(-)
diff --git a/tools/perf/arch/loongarch/annotate/instructions.c b/tools/perf/arch/loongarch/annotate/instructions.c
index ab21bf122135..98e19c5366ac 100644
--- a/tools/perf/arch/loongarch/annotate/instructions.c
+++ b/tools/perf/arch/loongarch/annotate/instructions.c
@@ -5,25 +5,115 @@
* Copyright (C) 2020-2023 Loongson Technology Corporation Limited
*/
+static int loongarch_call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
+{
+ char *c, *endptr, *tok, *name;
+ struct map *map = ms->map;
+ struct addr_map_symbol target = {
+ .ms = { .map = map, },
+ };
+
+ c = strchr(ops->raw, '#');
+ if (c++ == NULL)
+ return -1;
+
+ ops->target.addr = strtoull(c, &endptr, 16);
+
+ name = strchr(endptr, '<');
+ name++;
+
+ if (arch->objdump.skip_functions_char &&
+ strchr(name, arch->objdump.skip_functions_char))
+ return -1;
+
+ tok = strchr(name, '>');
+ if (tok == NULL)
+ return -1;
+
+ *tok = '\0';
+ ops->target.name = strdup(name);
+ *tok = '>';
+
+ if (ops->target.name == NULL)
+ return -1;
+
+ target.addr = map__objdump_2mem(map, ops->target.addr);
+
+ if (maps__find_ams(ms->maps, &target) == 0 &&
+ map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
+ ops->target.sym = target.ms.sym;
+
+ return 0;
+}
+
+static struct ins_ops loongarch_call_ops = {
+ .parse = loongarch_call__parse,
+ .scnprintf = call__scnprintf,
+};
+
+static int loongarch_jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
+{
+ struct map *map = ms->map;
+ struct symbol *sym = ms->sym;
+ struct addr_map_symbol target = {
+ .ms = { .map = map, },
+ };
+ const char *c = strchr(ops->raw, '#');
+ u64 start, end;
+
+ ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char);
+ ops->raw_func_start = strchr(ops->raw, '<');
+
+ if (ops->raw_func_start && c > ops->raw_func_start)
+ c = NULL;
+
+ if (c++ != NULL)
+ ops->target.addr = strtoull(c, NULL, 16);
+ else
+ ops->target.addr = strtoull(ops->raw, NULL, 16);
+
+ target.addr = map__objdump_2mem(map, ops->target.addr);
+ start = map__unmap_ip(map, sym->start);
+ end = map__unmap_ip(map, sym->end);
+
+ ops->target.outside = target.addr < start || target.addr > end;
+
+ if (maps__find_ams(ms->maps, &target) == 0 &&
+ map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
+ ops->target.sym = target.ms.sym;
+
+ if (!ops->target.outside) {
+ ops->target.offset = target.addr - start;
+ ops->target.offset_avail = true;
+ } else {
+ ops->target.offset_avail = false;
+ }
+
+ return 0;
+}
+
+static struct ins_ops loongarch_jump_ops = {
+ .parse = loongarch_jump__parse,
+ .scnprintf = jump__scnprintf,
+};
+
static
struct ins_ops *loongarch__associate_ins_ops(struct arch *arch, const char *name)
{
struct ins_ops *ops = NULL;
- if (!strncmp(name, "beqz", 4) ||
- !strncmp(name, "bnez", 4) ||
- !strncmp(name, "beq", 3) ||
- !strncmp(name, "bne", 3) ||
- !strncmp(name, "blt", 3) ||
- !strncmp(name, "bge", 3) ||
- !strncmp(name, "bltu", 4) ||
- !strncmp(name, "bgeu", 4) ||
- !strncmp(name, "bl", 2))
- ops = &call_ops;
- else if (!strncmp(name, "jirl", 4))
+ if (!strcmp(name, "bl"))
+ ops = &loongarch_call_ops;
+ else if (!strcmp(name, "jirl"))
ops = &ret_ops;
- else if (name[0] == 'b')
- ops = &jump_ops;
+ else if (!strcmp(name, "b") ||
+ !strncmp(name, "beq", 3) ||
+ !strncmp(name, "bne", 3) ||
+ !strncmp(name, "blt", 3) ||
+ !strncmp(name, "bge", 3) ||
+ !strncmp(name, "bltu", 4) ||
+ !strncmp(name, "bgeu", 4))
+ ops = &loongarch_jump_ops;
else
return NULL;
diff --git a/tools/perf/arch/s390/annotate/instructions.c b/tools/perf/arch/s390/annotate/instructions.c
index de925b0e35ce..da5aa3e1f04c 100644
--- a/tools/perf/arch/s390/annotate/instructions.c
+++ b/tools/perf/arch/s390/annotate/instructions.c
@@ -45,9 +45,6 @@ static int s390_call__parse(struct arch *arch, struct ins_operands *ops,
return 0;
}
-static int call__scnprintf(struct ins *ins, char *bf, size_t size,
- struct ins_operands *ops, int max_ins_name);
-
static struct ins_ops s390_call_ops = {
.parse = s390_call__parse,
.scnprintf = call__scnprintf,
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index cdd1924a4418..ad40adbd8895 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -61,6 +61,10 @@ static regex_t file_lineno;
static struct ins_ops *ins__find(struct arch *arch, const char *name);
static void ins__sort(struct arch *arch);
static int disasm_line__parse(char *line, const char **namep, char **rawp);
+static int call__scnprintf(struct ins *ins, char *bf, size_t size,
+ struct ins_operands *ops, int max_ins_name);
+static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
+ struct ins_operands *ops, int max_ins_name);
struct arch {
const char *name;
@@ -323,7 +327,7 @@ static struct ins_ops call_ops = {
bool ins__is_call(const struct ins *ins)
{
- return ins->ops == &call_ops || ins->ops == &s390_call_ops;
+ return ins->ops == &call_ops || ins->ops == &s390_call_ops || ins->ops == &loongarch_call_ops;
}
/*
@@ -464,7 +468,7 @@ static struct ins_ops jump_ops = {
bool ins__is_jump(const struct ins *ins)
{
- return ins->ops == &jump_ops;
+ return ins->ops == &jump_ops || ins->ops == &loongarch_jump_ops;
}
static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
--
2.41.0
Hello,
On Tue, Jun 20, 2023 at 6:21 AM WANG Rui <[email protected]> wrote:
>
> In the perf annotate view for LoongArch, there is no arrowed line
> pointing to the target from the branch instruction. This issue is
> caused by incorrect instruction association and parsing.
>
> $ perf record alloc-6276705c94ad1398 # rust benchmark
> $ perf report
>
> 0.28 │ ori $a1, $zero, 0x63
> │ move $a2, $zero
> 10.55 │ addi.d $a3, $a2, 1(0x1)
> │ sltu $a4, $a3, $s7
> 9.53 │ masknez $a4, $s7, $a4
> │ sub.d $a3, $a3, $a4
> 12.12 │ st.d $a1, $fp, 24(0x18)
> │ st.d $a3, $fp, 16(0x10)
> 16.29 │ slli.d $a2, $a2, 0x2
> │ ldx.w $a2, $s8, $a2
> 12.77 │ st.w $a2, $sp, 724(0x2d4)
> │ st.w $s0, $sp, 720(0x2d0)
> 7.03 │ addi.d $a2, $sp, 720(0x2d0)
> │ addi.d $a1, $a1, -1(0xfff)
> 12.03 │ move $a2, $a3
> │ → bne $a1, $s3, -52(0x3ffcc) # 82ce8 <test::bench::Bencher::iter+0x3f4>
> 2.50 │ addi.d $a0, $a0, 1(0x1)
>
> This patch fixes instruction association issues, such as associating
> branch instructions with jump_ops instead of call_ops, and corrects
> false instruction matches. It also implements branch instruction parsing
> specifically for LoongArch. With this patch, we will be able to see the
> arrowed line.
>
> 0.79 │3ec: ori $a1, $zero, 0x63
> │ move $a2, $zero
> 10.32 │3f4:┌─→addi.d $a3, $a2, 1(0x1)
> │ │ sltu $a4, $a3, $s7
> 10.44 │ │ masknez $a4, $s7, $a4
> │ │ sub.d $a3, $a3, $a4
> 14.17 │ │ st.d $a1, $fp, 24(0x18)
> │ │ st.d $a3, $fp, 16(0x10)
> 13.15 │ │ slli.d $a2, $a2, 0x2
> │ │ ldx.w $a2, $s8, $a2
> 11.00 │ │ st.w $a2, $sp, 724(0x2d4)
> │ │ st.w $s0, $sp, 720(0x2d0)
> 8.00 │ │ addi.d $a2, $sp, 720(0x2d0)
> │ │ addi.d $a1, $a1, -1(0xfff)
> 11.99 │ │ move $a2, $a3
> │ └──bne $a1, $s3, 3f4
> 3.17 │ addi.d $a0, $a0, 1(0x1)
>
> Signed-off-by: WANG Rui <[email protected]>
Just a nitpick. Otherwise looks good.
> ---
> .../arch/loongarch/annotate/instructions.c | 116 ++++++++++++++++--
> tools/perf/arch/s390/annotate/instructions.c | 3 -
> tools/perf/util/annotate.c | 8 +-
> 3 files changed, 109 insertions(+), 18 deletions(-)
>
> diff --git a/tools/perf/arch/loongarch/annotate/instructions.c b/tools/perf/arch/loongarch/annotate/instructions.c
> index ab21bf122135..98e19c5366ac 100644
> --- a/tools/perf/arch/loongarch/annotate/instructions.c
> +++ b/tools/perf/arch/loongarch/annotate/instructions.c
> @@ -5,25 +5,115 @@
> * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> */
>
> +static int loongarch_call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
> +{
> + char *c, *endptr, *tok, *name;
> + struct map *map = ms->map;
> + struct addr_map_symbol target = {
> + .ms = { .map = map, },
Looking here...
> + };
> +
> + c = strchr(ops->raw, '#');
> + if (c++ == NULL)
> + return -1;
> +
> + ops->target.addr = strtoull(c, &endptr, 16);
> +
> + name = strchr(endptr, '<');
> + name++;
> +
> + if (arch->objdump.skip_functions_char &&
> + strchr(name, arch->objdump.skip_functions_char))
> + return -1;
> +
> + tok = strchr(name, '>');
> + if (tok == NULL)
> + return -1;
> +
> + *tok = '\0';
> + ops->target.name = strdup(name);
> + *tok = '>';
> +
> + if (ops->target.name == NULL)
> + return -1;
> +
> + target.addr = map__objdump_2mem(map, ops->target.addr);
> +
> + if (maps__find_ams(ms->maps, &target) == 0 &&
> + map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
So the target.ms.map is 'map', right? Then we can reduce the line.
> + ops->target.sym = target.ms.sym;
> +
> + return 0;
> +}
> +
> +static struct ins_ops loongarch_call_ops = {
> + .parse = loongarch_call__parse,
> + .scnprintf = call__scnprintf,
> +};
> +
> +static int loongarch_jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
> +{
> + struct map *map = ms->map;
> + struct symbol *sym = ms->sym;
> + struct addr_map_symbol target = {
> + .ms = { .map = map, },
> + };
> + const char *c = strchr(ops->raw, '#');
> + u64 start, end;
> +
> + ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char);
> + ops->raw_func_start = strchr(ops->raw, '<');
> +
> + if (ops->raw_func_start && c > ops->raw_func_start)
> + c = NULL;
> +
> + if (c++ != NULL)
> + ops->target.addr = strtoull(c, NULL, 16);
> + else
> + ops->target.addr = strtoull(ops->raw, NULL, 16);
> +
> + target.addr = map__objdump_2mem(map, ops->target.addr);
> + start = map__unmap_ip(map, sym->start);
> + end = map__unmap_ip(map, sym->end);
> +
> + ops->target.outside = target.addr < start || target.addr > end;
> +
> + if (maps__find_ams(ms->maps, &target) == 0 &&
> + map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
Ditto.
Thanks,
Namhyung
> + ops->target.sym = target.ms.sym;
> +
> + if (!ops->target.outside) {
> + ops->target.offset = target.addr - start;
> + ops->target.offset_avail = true;
> + } else {
> + ops->target.offset_avail = false;
> + }
> +
> + return 0;
> +}
> +
> +static struct ins_ops loongarch_jump_ops = {
> + .parse = loongarch_jump__parse,
> + .scnprintf = jump__scnprintf,
> +};
> +
> static
> struct ins_ops *loongarch__associate_ins_ops(struct arch *arch, const char *name)
> {
> struct ins_ops *ops = NULL;
>
> - if (!strncmp(name, "beqz", 4) ||
> - !strncmp(name, "bnez", 4) ||
> - !strncmp(name, "beq", 3) ||
> - !strncmp(name, "bne", 3) ||
> - !strncmp(name, "blt", 3) ||
> - !strncmp(name, "bge", 3) ||
> - !strncmp(name, "bltu", 4) ||
> - !strncmp(name, "bgeu", 4) ||
> - !strncmp(name, "bl", 2))
> - ops = &call_ops;
> - else if (!strncmp(name, "jirl", 4))
> + if (!strcmp(name, "bl"))
> + ops = &loongarch_call_ops;
> + else if (!strcmp(name, "jirl"))
> ops = &ret_ops;
> - else if (name[0] == 'b')
> - ops = &jump_ops;
> + else if (!strcmp(name, "b") ||
> + !strncmp(name, "beq", 3) ||
> + !strncmp(name, "bne", 3) ||
> + !strncmp(name, "blt", 3) ||
> + !strncmp(name, "bge", 3) ||
> + !strncmp(name, "bltu", 4) ||
> + !strncmp(name, "bgeu", 4))
> + ops = &loongarch_jump_ops;
> else
> return NULL;
>
> diff --git a/tools/perf/arch/s390/annotate/instructions.c b/tools/perf/arch/s390/annotate/instructions.c
> index de925b0e35ce..da5aa3e1f04c 100644
> --- a/tools/perf/arch/s390/annotate/instructions.c
> +++ b/tools/perf/arch/s390/annotate/instructions.c
> @@ -45,9 +45,6 @@ static int s390_call__parse(struct arch *arch, struct ins_operands *ops,
> return 0;
> }
>
> -static int call__scnprintf(struct ins *ins, char *bf, size_t size,
> - struct ins_operands *ops, int max_ins_name);
> -
> static struct ins_ops s390_call_ops = {
> .parse = s390_call__parse,
> .scnprintf = call__scnprintf,
> diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
> index cdd1924a4418..ad40adbd8895 100644
> --- a/tools/perf/util/annotate.c
> +++ b/tools/perf/util/annotate.c
> @@ -61,6 +61,10 @@ static regex_t file_lineno;
> static struct ins_ops *ins__find(struct arch *arch, const char *name);
> static void ins__sort(struct arch *arch);
> static int disasm_line__parse(char *line, const char **namep, char **rawp);
> +static int call__scnprintf(struct ins *ins, char *bf, size_t size,
> + struct ins_operands *ops, int max_ins_name);
> +static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
> + struct ins_operands *ops, int max_ins_name);
>
> struct arch {
> const char *name;
> @@ -323,7 +327,7 @@ static struct ins_ops call_ops = {
>
> bool ins__is_call(const struct ins *ins)
> {
> - return ins->ops == &call_ops || ins->ops == &s390_call_ops;
> + return ins->ops == &call_ops || ins->ops == &s390_call_ops || ins->ops == &loongarch_call_ops;
> }
>
> /*
> @@ -464,7 +468,7 @@ static struct ins_ops jump_ops = {
>
> bool ins__is_jump(const struct ins *ins)
> {
> - return ins->ops == &jump_ops;
> + return ins->ops == &jump_ops || ins->ops == &loongarch_jump_ops;
> }
>
> static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
> --
> 2.41.0
>
Hello Namhyung,
On Wed, Jun 21, 2023 at 2:42 AM Namhyung Kim <[email protected]> wrote:
> > +static int loongarch_call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
> > +{
> > + char *c, *endptr, *tok, *name;
> > + struct map *map = ms->map;
> > + struct addr_map_symbol target = {
> > + .ms = { .map = map, },
>
> Looking here...
>
> > + };
> > +
> > + c = strchr(ops->raw, '#');
> > + if (c++ == NULL)
> > + return -1;
> > +
> > + ops->target.addr = strtoull(c, &endptr, 16);
> > +
> > + name = strchr(endptr, '<');
> > + name++;
> > +
> > + if (arch->objdump.skip_functions_char &&
> > + strchr(name, arch->objdump.skip_functions_char))
> > + return -1;
> > +
> > + tok = strchr(name, '>');
> > + if (tok == NULL)
> > + return -1;
> > +
> > + *tok = '\0';
> > + ops->target.name = strdup(name);
> > + *tok = '>';
> > +
> > + if (ops->target.name == NULL)
> > + return -1;
> > +
> > + target.addr = map__objdump_2mem(map, ops->target.addr);
> > +
> > + if (maps__find_ams(ms->maps, &target) == 0 &&
> > + map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
>
> So the target.ms.map is 'map', right? Then we can reduce the line.
toos/perf/util/maps.c:
> int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams)
> {
> if (ams->addr < map__start(ams->ms.map) || ams->addr >= map__end(ams->ms.map)) {
> if (maps == NULL)
> return -1;
> ams->ms.map = maps__find(maps, ams->addr);
Is it possible that `target.ms.map` might be reassigned within the
`maps_find_ams` function in this case?
> if (ams->ms.map == NULL)
> return -1;
> }
>
> ams->al_addr = map__map_ip(ams->ms.map, ams->addr);
> ams->ms.sym = map__find_symbol(ams->ms.map, ams->al_addr);
>
> return ams->ms.sym ? 0 : -1;
> }
Thanks!
--
WANG Rui
Loongson Technology Corporation Limited
On Tue, Jun 20, 2023 at 9:37 PM WANG Rui <[email protected]> wrote:
>
> Hello Namhyung,
>
> On Wed, Jun 21, 2023 at 2:42 AM Namhyung Kim <[email protected]> wrote:
> > > +static int loongarch_call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
> > > +{
> > > + char *c, *endptr, *tok, *name;
> > > + struct map *map = ms->map;
> > > + struct addr_map_symbol target = {
> > > + .ms = { .map = map, },
> >
> > Looking here...
> >
> > > + };
> > > +
> > > + c = strchr(ops->raw, '#');
> > > + if (c++ == NULL)
> > > + return -1;
> > > +
> > > + ops->target.addr = strtoull(c, &endptr, 16);
> > > +
> > > + name = strchr(endptr, '<');
> > > + name++;
> > > +
> > > + if (arch->objdump.skip_functions_char &&
> > > + strchr(name, arch->objdump.skip_functions_char))
> > > + return -1;
> > > +
> > > + tok = strchr(name, '>');
> > > + if (tok == NULL)
> > > + return -1;
> > > +
> > > + *tok = '\0';
> > > + ops->target.name = strdup(name);
> > > + *tok = '>';
> > > +
> > > + if (ops->target.name == NULL)
> > > + return -1;
> > > +
> > > + target.addr = map__objdump_2mem(map, ops->target.addr);
> > > +
> > > + if (maps__find_ams(ms->maps, &target) == 0 &&
> > > + map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
> >
> > So the target.ms.map is 'map', right? Then we can reduce the line.
>
> toos/perf/util/maps.c:
>
> > int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams)
> > {
> > if (ams->addr < map__start(ams->ms.map) || ams->addr >= map__end(ams->ms.map)) {
> > if (maps == NULL)
> > return -1;
> > ams->ms.map = maps__find(maps, ams->addr);
>
> Is it possible that `target.ms.map` might be reassigned within the
> `maps_find_ams` function in this case?
Ah, ok. Missed that part. It can change if the target is from a
different library.
Acked-by: Namhyung Kim <[email protected]>
Thanks,
Namhyung
>
> > if (ams->ms.map == NULL)
> > return -1;
> > }
> >
> > ams->al_addr = map__map_ip(ams->ms.map, ams->addr);
> > ams->ms.sym = map__find_symbol(ams->ms.map, ams->al_addr);
> >
> > return ams->ms.sym ? 0 : -1;
> > }
>
On Tue, Jun 20, 2023 at 6:21 AM WANG Rui <[email protected]> wrote:
>
> In the perf annotate view for LoongArch, there is no arrowed line
> pointing to the target from the branch instruction. This issue is
> caused by incorrect instruction association and parsing.
>
> $ perf record alloc-6276705c94ad1398 # rust benchmark
> $ perf report
>
> 0.28 │ ori $a1, $zero, 0x63
> │ move $a2, $zero
> 10.55 │ addi.d $a3, $a2, 1(0x1)
> │ sltu $a4, $a3, $s7
> 9.53 │ masknez $a4, $s7, $a4
> │ sub.d $a3, $a3, $a4
> 12.12 │ st.d $a1, $fp, 24(0x18)
> │ st.d $a3, $fp, 16(0x10)
> 16.29 │ slli.d $a2, $a2, 0x2
> │ ldx.w $a2, $s8, $a2
> 12.77 │ st.w $a2, $sp, 724(0x2d4)
> │ st.w $s0, $sp, 720(0x2d0)
> 7.03 │ addi.d $a2, $sp, 720(0x2d0)
> │ addi.d $a1, $a1, -1(0xfff)
> 12.03 │ move $a2, $a3
> │ → bne $a1, $s3, -52(0x3ffcc) # 82ce8 <test::bench::Bencher::iter+0x3f4>
> 2.50 │ addi.d $a0, $a0, 1(0x1)
>
> This patch fixes instruction association issues, such as associating
> branch instructions with jump_ops instead of call_ops, and corrects
> false instruction matches. It also implements branch instruction parsing
> specifically for LoongArch. With this patch, we will be able to see the
> arrowed line.
>
> 0.79 │3ec: ori $a1, $zero, 0x63
> │ move $a2, $zero
> 10.32 │3f4:┌─→addi.d $a3, $a2, 1(0x1)
> │ │ sltu $a4, $a3, $s7
> 10.44 │ │ masknez $a4, $s7, $a4
> │ │ sub.d $a3, $a3, $a4
> 14.17 │ │ st.d $a1, $fp, 24(0x18)
> │ │ st.d $a3, $fp, 16(0x10)
> 13.15 │ │ slli.d $a2, $a2, 0x2
> │ │ ldx.w $a2, $s8, $a2
> 11.00 │ │ st.w $a2, $sp, 724(0x2d4)
> │ │ st.w $s0, $sp, 720(0x2d0)
> 8.00 │ │ addi.d $a2, $sp, 720(0x2d0)
> │ │ addi.d $a1, $a1, -1(0xfff)
> 11.99 │ │ move $a2, $a3
> │ └──bne $a1, $s3, 3f4
> 3.17 │ addi.d $a0, $a0, 1(0x1)
>
> Signed-off-by: WANG Rui <[email protected]>
Applied to perf-tools-next, thanks!