root/tools/perf/util/annotate-arch/annotate-sparc.c
// SPDX-License-Identifier: GPL-2.0
#include <string.h>
#include <linux/compiler.h>
#include <linux/zalloc.h>
#include "../../util/disasm.h"

static int is_branch_cond(const char *cond)
{
        if (cond[0] == '\0')
                return 1;

        if (cond[0] == 'a' && cond[1] == '\0')
                return 1;

        if (cond[0] == 'c' &&
            (cond[1] == 'c' || cond[1] == 's') &&
            cond[2] == '\0')
                return 1;

        if (cond[0] == 'e' &&
            (cond[1] == '\0' ||
             (cond[1] == 'q' && cond[2] == '\0')))
                return 1;

        if (cond[0] == 'g' &&
            (cond[1] == '\0' ||
             (cond[1] == 't' && cond[2] == '\0') ||
             (cond[1] == 'e' && cond[2] == '\0') ||
             (cond[1] == 'e' && cond[2] == 'u' && cond[3] == '\0')))
                return 1;

        if (cond[0] == 'l' &&
            (cond[1] == '\0' ||
             (cond[1] == 't' && cond[2] == '\0') ||
             (cond[1] == 'u' && cond[2] == '\0') ||
             (cond[1] == 'e' && cond[2] == '\0') ||
             (cond[1] == 'e' && cond[2] == 'u' && cond[3] == '\0')))
                return 1;

        if (cond[0] == 'n' &&
            (cond[1] == '\0' ||
             (cond[1] == 'e' && cond[2] == '\0') ||
             (cond[1] == 'z' && cond[2] == '\0') ||
             (cond[1] == 'e' && cond[2] == 'g' && cond[3] == '\0')))
                return 1;

        if (cond[0] == 'b' &&
            cond[1] == 'p' &&
            cond[2] == 'o' &&
            cond[3] == 's' &&
            cond[4] == '\0')
                return 1;

        if (cond[0] == 'v' &&
            (cond[1] == 'c' || cond[1] == 's') &&
            cond[2] == '\0')
                return 1;

        if (cond[0] == 'b' &&
            cond[1] == 'z' &&
            cond[2] == '\0')
                return 1;

        return 0;
}

static int is_branch_reg_cond(const char *cond)
{
        if ((cond[0] == 'n' || cond[0] == 'l') &&
            cond[1] == 'z' &&
            cond[2] == '\0')
                return 1;

        if (cond[0] == 'z' &&
            cond[1] == '\0')
                return 1;

        if ((cond[0] == 'g' || cond[0] == 'l') &&
            cond[1] == 'e' &&
            cond[2] == 'z' &&
            cond[3] == '\0')
                return 1;

        if (cond[0] == 'g' &&
            cond[1] == 'z' &&
            cond[2] == '\0')
                return 1;

        return 0;
}

static int is_branch_float_cond(const char *cond)
{
        if (cond[0] == '\0')
                return 1;

        if ((cond[0] == 'a' || cond[0] == 'e' ||
             cond[0] == 'z' || cond[0] == 'g' ||
             cond[0] == 'l' || cond[0] == 'n' ||
             cond[0] == 'o' || cond[0] == 'u') &&
            cond[1] == '\0')
                return 1;

        if (((cond[0] == 'g' && cond[1] == 'e') ||
             (cond[0] == 'l' && (cond[1] == 'e' ||
                                 cond[1] == 'g')) ||
             (cond[0] == 'n' && (cond[1] == 'e' ||
                                 cond[1] == 'z')) ||
             (cond[0] == 'u' && (cond[1] == 'e' ||
                                 cond[1] == 'g' ||
                                 cond[1] == 'l'))) &&
            cond[2] == '\0')
                return 1;

        if (cond[0] == 'u' &&
            (cond[1] == 'g' || cond[1] == 'l') &&
            cond[2] == 'e' &&
            cond[3] == '\0')
                return 1;

        return 0;
}

static const struct ins_ops *sparc__associate_instruction_ops(struct arch *arch, const char *name)
{
        const struct ins_ops *ops = NULL;

        if (!strcmp(name, "call") ||
            !strcmp(name, "jmp") ||
            !strcmp(name, "jmpl")) {
                ops = &call_ops;
        } else if (!strcmp(name, "ret") ||
                   !strcmp(name, "retl") ||
                   !strcmp(name, "return")) {
                ops = &ret_ops;
        } else if (!strcmp(name, "mov")) {
                ops = &mov_ops;
        } else {
                if (name[0] == 'c' &&
                    (name[1] == 'w' || name[1] == 'x'))
                        name += 2;

                if (name[0] == 'b') {
                        const char *cond = name + 1;

                        if (cond[0] == 'r') {
                                if (is_branch_reg_cond(cond + 1))
                                        ops = &jump_ops;
                        } else if (is_branch_cond(cond)) {
                                ops = &jump_ops;
                        }
                } else if (name[0] == 'f' && name[1] == 'b') {
                        if (is_branch_float_cond(name + 2))
                                ops = &jump_ops;
                }
        }

        if (ops)
                arch__associate_ins_ops(arch, name, ops);

        return ops;
}

const struct arch *arch__new_sparc(const struct e_machine_and_e_flags *id,
                                   const char *cpuid __maybe_unused)
{
        struct arch *arch = zalloc(sizeof(*arch));

        if (!arch)
                return NULL;

        arch->name = "sparc";
        arch->id = *id;
        arch->associate_instruction_ops = sparc__associate_instruction_ops;
        arch->objdump.comment_char = '#';
        return arch;
}