linux/tools/perf/arch/x86/annotate/instructions.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2static struct ins x86__instructions[] = {
   3        { .name = "adc",        .ops = &mov_ops,  },
   4        { .name = "adcb",       .ops = &mov_ops,  },
   5        { .name = "adcl",       .ops = &mov_ops,  },
   6        { .name = "add",        .ops = &mov_ops,  },
   7        { .name = "addl",       .ops = &mov_ops,  },
   8        { .name = "addq",       .ops = &mov_ops,  },
   9        { .name = "addsd",      .ops = &mov_ops,  },
  10        { .name = "addw",       .ops = &mov_ops,  },
  11        { .name = "and",        .ops = &mov_ops,  },
  12        { .name = "andb",       .ops = &mov_ops,  },
  13        { .name = "andl",       .ops = &mov_ops,  },
  14        { .name = "andpd",      .ops = &mov_ops,  },
  15        { .name = "andps",      .ops = &mov_ops,  },
  16        { .name = "andq",       .ops = &mov_ops,  },
  17        { .name = "andw",       .ops = &mov_ops,  },
  18        { .name = "bsr",        .ops = &mov_ops,  },
  19        { .name = "bt",         .ops = &mov_ops,  },
  20        { .name = "btr",        .ops = &mov_ops,  },
  21        { .name = "bts",        .ops = &mov_ops,  },
  22        { .name = "btsq",       .ops = &mov_ops,  },
  23        { .name = "call",       .ops = &call_ops, },
  24        { .name = "callq",      .ops = &call_ops, },
  25        { .name = "cmovbe",     .ops = &mov_ops,  },
  26        { .name = "cmove",      .ops = &mov_ops,  },
  27        { .name = "cmovae",     .ops = &mov_ops,  },
  28        { .name = "cmp",        .ops = &mov_ops,  },
  29        { .name = "cmpb",       .ops = &mov_ops,  },
  30        { .name = "cmpl",       .ops = &mov_ops,  },
  31        { .name = "cmpq",       .ops = &mov_ops,  },
  32        { .name = "cmpw",       .ops = &mov_ops,  },
  33        { .name = "cmpxch",     .ops = &mov_ops,  },
  34        { .name = "cmpxchg",    .ops = &mov_ops,  },
  35        { .name = "cs",         .ops = &mov_ops,  },
  36        { .name = "dec",        .ops = &dec_ops,  },
  37        { .name = "decl",       .ops = &dec_ops,  },
  38        { .name = "divsd",      .ops = &mov_ops,  },
  39        { .name = "divss",      .ops = &mov_ops,  },
  40        { .name = "gs",         .ops = &mov_ops,  },
  41        { .name = "imul",       .ops = &mov_ops,  },
  42        { .name = "inc",        .ops = &dec_ops,  },
  43        { .name = "incl",       .ops = &dec_ops,  },
  44        { .name = "ja",         .ops = &jump_ops, },
  45        { .name = "jae",        .ops = &jump_ops, },
  46        { .name = "jb",         .ops = &jump_ops, },
  47        { .name = "jbe",        .ops = &jump_ops, },
  48        { .name = "jc",         .ops = &jump_ops, },
  49        { .name = "jcxz",       .ops = &jump_ops, },
  50        { .name = "je",         .ops = &jump_ops, },
  51        { .name = "jecxz",      .ops = &jump_ops, },
  52        { .name = "jg",         .ops = &jump_ops, },
  53        { .name = "jge",        .ops = &jump_ops, },
  54        { .name = "jl",         .ops = &jump_ops, },
  55        { .name = "jle",        .ops = &jump_ops, },
  56        { .name = "jmp",        .ops = &jump_ops, },
  57        { .name = "jmpq",       .ops = &jump_ops, },
  58        { .name = "jna",        .ops = &jump_ops, },
  59        { .name = "jnae",       .ops = &jump_ops, },
  60        { .name = "jnb",        .ops = &jump_ops, },
  61        { .name = "jnbe",       .ops = &jump_ops, },
  62        { .name = "jnc",        .ops = &jump_ops, },
  63        { .name = "jne",        .ops = &jump_ops, },
  64        { .name = "jng",        .ops = &jump_ops, },
  65        { .name = "jnge",       .ops = &jump_ops, },
  66        { .name = "jnl",        .ops = &jump_ops, },
  67        { .name = "jnle",       .ops = &jump_ops, },
  68        { .name = "jno",        .ops = &jump_ops, },
  69        { .name = "jnp",        .ops = &jump_ops, },
  70        { .name = "jns",        .ops = &jump_ops, },
  71        { .name = "jnz",        .ops = &jump_ops, },
  72        { .name = "jo",         .ops = &jump_ops, },
  73        { .name = "jp",         .ops = &jump_ops, },
  74        { .name = "jpe",        .ops = &jump_ops, },
  75        { .name = "jpo",        .ops = &jump_ops, },
  76        { .name = "jrcxz",      .ops = &jump_ops, },
  77        { .name = "js",         .ops = &jump_ops, },
  78        { .name = "jz",         .ops = &jump_ops, },
  79        { .name = "lea",        .ops = &mov_ops,  },
  80        { .name = "lock",       .ops = &lock_ops, },
  81        { .name = "mov",        .ops = &mov_ops,  },
  82        { .name = "movapd",     .ops = &mov_ops,  },
  83        { .name = "movaps",     .ops = &mov_ops,  },
  84        { .name = "movb",       .ops = &mov_ops,  },
  85        { .name = "movdqa",     .ops = &mov_ops,  },
  86        { .name = "movdqu",     .ops = &mov_ops,  },
  87        { .name = "movl",       .ops = &mov_ops,  },
  88        { .name = "movq",       .ops = &mov_ops,  },
  89        { .name = "movsd",      .ops = &mov_ops,  },
  90        { .name = "movslq",     .ops = &mov_ops,  },
  91        { .name = "movss",      .ops = &mov_ops,  },
  92        { .name = "movupd",     .ops = &mov_ops,  },
  93        { .name = "movups",     .ops = &mov_ops,  },
  94        { .name = "movw",       .ops = &mov_ops,  },
  95        { .name = "movzbl",     .ops = &mov_ops,  },
  96        { .name = "movzwl",     .ops = &mov_ops,  },
  97        { .name = "mulsd",      .ops = &mov_ops,  },
  98        { .name = "mulss",      .ops = &mov_ops,  },
  99        { .name = "nop",        .ops = &nop_ops,  },
 100        { .name = "nopl",       .ops = &nop_ops,  },
 101        { .name = "nopw",       .ops = &nop_ops,  },
 102        { .name = "or",         .ops = &mov_ops,  },
 103        { .name = "orb",        .ops = &mov_ops,  },
 104        { .name = "orl",        .ops = &mov_ops,  },
 105        { .name = "orps",       .ops = &mov_ops,  },
 106        { .name = "orq",        .ops = &mov_ops,  },
 107        { .name = "pand",       .ops = &mov_ops,  },
 108        { .name = "paddq",      .ops = &mov_ops,  },
 109        { .name = "pcmpeqb",    .ops = &mov_ops,  },
 110        { .name = "por",        .ops = &mov_ops,  },
 111        { .name = "rclb",       .ops = &mov_ops,  },
 112        { .name = "rcll",       .ops = &mov_ops,  },
 113        { .name = "ret",        .ops = &ret_ops,  },
 114        { .name = "retq",       .ops = &ret_ops,  },
 115        { .name = "sbb",        .ops = &mov_ops,  },
 116        { .name = "sbbl",       .ops = &mov_ops,  },
 117        { .name = "sete",       .ops = &mov_ops,  },
 118        { .name = "sub",        .ops = &mov_ops,  },
 119        { .name = "subl",       .ops = &mov_ops,  },
 120        { .name = "subq",       .ops = &mov_ops,  },
 121        { .name = "subsd",      .ops = &mov_ops,  },
 122        { .name = "subw",       .ops = &mov_ops,  },
 123        { .name = "test",       .ops = &mov_ops,  },
 124        { .name = "testb",      .ops = &mov_ops,  },
 125        { .name = "testl",      .ops = &mov_ops,  },
 126        { .name = "ucomisd",    .ops = &mov_ops,  },
 127        { .name = "ucomiss",    .ops = &mov_ops,  },
 128        { .name = "vaddsd",     .ops = &mov_ops,  },
 129        { .name = "vandpd",     .ops = &mov_ops,  },
 130        { .name = "vmovdqa",    .ops = &mov_ops,  },
 131        { .name = "vmovq",      .ops = &mov_ops,  },
 132        { .name = "vmovsd",     .ops = &mov_ops,  },
 133        { .name = "vmulsd",     .ops = &mov_ops,  },
 134        { .name = "vorpd",      .ops = &mov_ops,  },
 135        { .name = "vsubsd",     .ops = &mov_ops,  },
 136        { .name = "vucomisd",   .ops = &mov_ops,  },
 137        { .name = "xadd",       .ops = &mov_ops,  },
 138        { .name = "xbeginl",    .ops = &jump_ops, },
 139        { .name = "xbeginq",    .ops = &jump_ops, },
 140        { .name = "xchg",       .ops = &mov_ops,  },
 141        { .name = "xor",        .ops = &mov_ops, },
 142        { .name = "xorb",       .ops = &mov_ops, },
 143        { .name = "xorpd",      .ops = &mov_ops, },
 144        { .name = "xorps",      .ops = &mov_ops, },
 145};
 146
 147static bool amd__ins_is_fused(struct arch *arch, const char *ins1,
 148                              const char *ins2)
 149{
 150        if (strstr(ins2, "jmp"))
 151                return false;
 152
 153        /* Family >= 15h supports cmp/test + branch fusion */
 154        if (arch->family >= 0x15 && (strstarts(ins1, "test") ||
 155            (strstarts(ins1, "cmp") && !strstr(ins1, "xchg")))) {
 156                return true;
 157        }
 158
 159        /* Family >= 19h supports some ALU + branch fusion */
 160        if (arch->family >= 0x19 && (strstarts(ins1, "add") ||
 161            strstarts(ins1, "sub") || strstarts(ins1, "and") ||
 162            strstarts(ins1, "inc") || strstarts(ins1, "dec") ||
 163            strstarts(ins1, "or") || strstarts(ins1, "xor"))) {
 164                return true;
 165        }
 166
 167        return false;
 168}
 169
 170static bool intel__ins_is_fused(struct arch *arch, const char *ins1,
 171                                const char *ins2)
 172{
 173        if (arch->family != 6 || arch->model < 0x1e || strstr(ins2, "jmp"))
 174                return false;
 175
 176        if (arch->model == 0x1e) {
 177                /* Nehalem */
 178                if ((strstr(ins1, "cmp") && !strstr(ins1, "xchg")) ||
 179                     strstr(ins1, "test")) {
 180                        return true;
 181                }
 182        } else {
 183                /* Newer platform */
 184                if ((strstr(ins1, "cmp") && !strstr(ins1, "xchg")) ||
 185                     strstr(ins1, "test") ||
 186                     strstr(ins1, "add") ||
 187                     strstr(ins1, "sub") ||
 188                     strstr(ins1, "and") ||
 189                     strstr(ins1, "inc") ||
 190                     strstr(ins1, "dec")) {
 191                        return true;
 192                }
 193        }
 194
 195        return false;
 196}
 197
 198static int x86__cpuid_parse(struct arch *arch, char *cpuid)
 199{
 200        unsigned int family, model, stepping;
 201        int ret;
 202
 203        /*
 204         * cpuid = "GenuineIntel,family,model,stepping"
 205         */
 206        ret = sscanf(cpuid, "%*[^,],%u,%u,%u", &family, &model, &stepping);
 207        if (ret == 3) {
 208                arch->family = family;
 209                arch->model = model;
 210                arch->ins_is_fused = strstarts(cpuid, "AuthenticAMD") ?
 211                                        amd__ins_is_fused :
 212                                        intel__ins_is_fused;
 213                return 0;
 214        }
 215
 216        return -1;
 217}
 218
 219static int x86__annotate_init(struct arch *arch, char *cpuid)
 220{
 221        int err = 0;
 222
 223        if (arch->initialized)
 224                return 0;
 225
 226        if (cpuid) {
 227                if (x86__cpuid_parse(arch, cpuid))
 228                        err = SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING;
 229        }
 230
 231        arch->initialized = true;
 232        return err;
 233}
 234