From: "Naveen N. Rao" <naveen.n....@linux.vnet.ibm.com>

Powerpc has long list of branch instructions and hardcoding them in table
appears to be error-prone. So, add new function to find instruction
instead of creating table.

Signed-off-by: Naveen N. Rao <naveen.n....@linux.vnet.ibm.com>
Signed-off-by: Ravi Bangoria <ravi.bango...@linux.vnet.ibm.com>
---
 tools/perf/util/annotate.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 634daf5..ad01825 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -492,6 +492,68 @@ static struct ins *ins__find(const char *name)
                       sizeof(struct ins), ins__key_cmp);
 }
 
+static struct ins *ins__find_powerpc(const char *name)
+{
+       int i;
+       struct ins *ins;
+
+       ins = zalloc(sizeof(struct ins));
+       if (!ins)
+               return NULL;
+
+       ins->name = strdup(name);
+       if (!ins->name)
+               return NULL;
+
+       if (name[0] == 'b') {
+               /* branch instructions */
+               ins->ops = &jump_ops;
+
+               /*
+                * - Few start with 'b', but aren't branch instructions.
+                * - Let's also ignore instructions involving 'ctr' and
+                *   'tar' since target branch addresses for those can't
+                *   be determined statically.
+                */
+               if (!strncmp(name, "bcd", 3)   ||
+                   !strncmp(name, "brinc", 5) ||
+                   !strncmp(name, "bper", 4)  ||
+                   strstr(name, "ctr")        ||
+                   strstr(name, "tar"))
+                       return NULL;
+
+               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-"))
+                               ins->ops = &call_ops;
+               }
+               if (name[i] == 'r' && name[i-1] == 'l')
+                       /*
+                        * instructions ending with 'lr' are considered to be
+                        * return instructions
+                        */
+                       ins->ops = &ret_ops;
+
+               return ins;
+       }
+       return NULL;
+}
+
 static void __init_arch_ins(const char *arch, struct ins *instructions,
                            int size, struct ins *(*func)(const char *))
 {
@@ -513,6 +575,8 @@ static int _init_arch_ins(const char *norm_arch)
                __init_arch_ins(norm_arch, instructions_arm,
                                ARRAY_SIZE(instructions_arm),
                                ins__find);
+       else if (!strcmp(norm_arch, PERF_ARCH_POWERPC))
+               __init_arch_ins(norm_arch, NULL, 0, ins__find_powerpc);
        else
                return -1;
 
-- 
2.5.5

Reply via email to