Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 static struct ins x86__instructions[] = {
0003     { .name = "adc",    .ops = &mov_ops,  },
0004     { .name = "adcb",   .ops = &mov_ops,  },
0005     { .name = "adcl",   .ops = &mov_ops,  },
0006     { .name = "add",    .ops = &mov_ops,  },
0007     { .name = "addl",   .ops = &mov_ops,  },
0008     { .name = "addq",   .ops = &mov_ops,  },
0009     { .name = "addsd",  .ops = &mov_ops,  },
0010     { .name = "addw",   .ops = &mov_ops,  },
0011     { .name = "and",    .ops = &mov_ops,  },
0012     { .name = "andb",   .ops = &mov_ops,  },
0013     { .name = "andl",   .ops = &mov_ops,  },
0014     { .name = "andpd",  .ops = &mov_ops,  },
0015     { .name = "andps",  .ops = &mov_ops,  },
0016     { .name = "andq",   .ops = &mov_ops,  },
0017     { .name = "andw",   .ops = &mov_ops,  },
0018     { .name = "bsr",    .ops = &mov_ops,  },
0019     { .name = "bt",     .ops = &mov_ops,  },
0020     { .name = "btr",    .ops = &mov_ops,  },
0021     { .name = "bts",    .ops = &mov_ops,  },
0022     { .name = "btsq",   .ops = &mov_ops,  },
0023     { .name = "call",   .ops = &call_ops, },
0024     { .name = "callq",  .ops = &call_ops, },
0025     { .name = "cmovbe", .ops = &mov_ops,  },
0026     { .name = "cmove",  .ops = &mov_ops,  },
0027     { .name = "cmovae", .ops = &mov_ops,  },
0028     { .name = "cmp",    .ops = &mov_ops,  },
0029     { .name = "cmpb",   .ops = &mov_ops,  },
0030     { .name = "cmpl",   .ops = &mov_ops,  },
0031     { .name = "cmpq",   .ops = &mov_ops,  },
0032     { .name = "cmpw",   .ops = &mov_ops,  },
0033     { .name = "cmpxch", .ops = &mov_ops,  },
0034     { .name = "cmpxchg",    .ops = &mov_ops,  },
0035     { .name = "cs",     .ops = &mov_ops,  },
0036     { .name = "dec",    .ops = &dec_ops,  },
0037     { .name = "decl",   .ops = &dec_ops,  },
0038     { .name = "divsd",  .ops = &mov_ops,  },
0039     { .name = "divss",  .ops = &mov_ops,  },
0040     { .name = "gs",     .ops = &mov_ops,  },
0041     { .name = "imul",   .ops = &mov_ops,  },
0042     { .name = "inc",    .ops = &dec_ops,  },
0043     { .name = "incl",   .ops = &dec_ops,  },
0044     { .name = "ja",     .ops = &jump_ops, },
0045     { .name = "jae",    .ops = &jump_ops, },
0046     { .name = "jb",     .ops = &jump_ops, },
0047     { .name = "jbe",    .ops = &jump_ops, },
0048     { .name = "jc",     .ops = &jump_ops, },
0049     { .name = "jcxz",   .ops = &jump_ops, },
0050     { .name = "je",     .ops = &jump_ops, },
0051     { .name = "jecxz",  .ops = &jump_ops, },
0052     { .name = "jg",     .ops = &jump_ops, },
0053     { .name = "jge",    .ops = &jump_ops, },
0054     { .name = "jl",     .ops = &jump_ops, },
0055     { .name = "jle",    .ops = &jump_ops, },
0056     { .name = "jmp",    .ops = &jump_ops, },
0057     { .name = "jmpq",   .ops = &jump_ops, },
0058     { .name = "jna",    .ops = &jump_ops, },
0059     { .name = "jnae",   .ops = &jump_ops, },
0060     { .name = "jnb",    .ops = &jump_ops, },
0061     { .name = "jnbe",   .ops = &jump_ops, },
0062     { .name = "jnc",    .ops = &jump_ops, },
0063     { .name = "jne",    .ops = &jump_ops, },
0064     { .name = "jng",    .ops = &jump_ops, },
0065     { .name = "jnge",   .ops = &jump_ops, },
0066     { .name = "jnl",    .ops = &jump_ops, },
0067     { .name = "jnle",   .ops = &jump_ops, },
0068     { .name = "jno",    .ops = &jump_ops, },
0069     { .name = "jnp",    .ops = &jump_ops, },
0070     { .name = "jns",    .ops = &jump_ops, },
0071     { .name = "jnz",    .ops = &jump_ops, },
0072     { .name = "jo",     .ops = &jump_ops, },
0073     { .name = "jp",     .ops = &jump_ops, },
0074     { .name = "jpe",    .ops = &jump_ops, },
0075     { .name = "jpo",    .ops = &jump_ops, },
0076     { .name = "jrcxz",  .ops = &jump_ops, },
0077     { .name = "js",     .ops = &jump_ops, },
0078     { .name = "jz",     .ops = &jump_ops, },
0079     { .name = "lea",    .ops = &mov_ops,  },
0080     { .name = "lock",   .ops = &lock_ops, },
0081     { .name = "mov",    .ops = &mov_ops,  },
0082     { .name = "movapd", .ops = &mov_ops,  },
0083     { .name = "movaps", .ops = &mov_ops,  },
0084     { .name = "movb",   .ops = &mov_ops,  },
0085     { .name = "movdqa", .ops = &mov_ops,  },
0086     { .name = "movdqu", .ops = &mov_ops,  },
0087     { .name = "movl",   .ops = &mov_ops,  },
0088     { .name = "movq",   .ops = &mov_ops,  },
0089     { .name = "movsd",  .ops = &mov_ops,  },
0090     { .name = "movslq", .ops = &mov_ops,  },
0091     { .name = "movss",  .ops = &mov_ops,  },
0092     { .name = "movupd", .ops = &mov_ops,  },
0093     { .name = "movups", .ops = &mov_ops,  },
0094     { .name = "movw",   .ops = &mov_ops,  },
0095     { .name = "movzbl", .ops = &mov_ops,  },
0096     { .name = "movzwl", .ops = &mov_ops,  },
0097     { .name = "mulsd",  .ops = &mov_ops,  },
0098     { .name = "mulss",  .ops = &mov_ops,  },
0099     { .name = "nop",    .ops = &nop_ops,  },
0100     { .name = "nopl",   .ops = &nop_ops,  },
0101     { .name = "nopw",   .ops = &nop_ops,  },
0102     { .name = "or",     .ops = &mov_ops,  },
0103     { .name = "orb",    .ops = &mov_ops,  },
0104     { .name = "orl",    .ops = &mov_ops,  },
0105     { .name = "orps",   .ops = &mov_ops,  },
0106     { .name = "orq",    .ops = &mov_ops,  },
0107     { .name = "pand",   .ops = &mov_ops,  },
0108     { .name = "paddq",  .ops = &mov_ops,  },
0109     { .name = "pcmpeqb",    .ops = &mov_ops,  },
0110     { .name = "por",    .ops = &mov_ops,  },
0111     { .name = "rclb",   .ops = &mov_ops,  },
0112     { .name = "rcll",   .ops = &mov_ops,  },
0113     { .name = "ret",    .ops = &ret_ops,  },
0114     { .name = "retq",   .ops = &ret_ops,  },
0115     { .name = "sbb",    .ops = &mov_ops,  },
0116     { .name = "sbbl",   .ops = &mov_ops,  },
0117     { .name = "sete",   .ops = &mov_ops,  },
0118     { .name = "sub",    .ops = &mov_ops,  },
0119     { .name = "subl",   .ops = &mov_ops,  },
0120     { .name = "subq",   .ops = &mov_ops,  },
0121     { .name = "subsd",  .ops = &mov_ops,  },
0122     { .name = "subw",   .ops = &mov_ops,  },
0123     { .name = "test",   .ops = &mov_ops,  },
0124     { .name = "testb",  .ops = &mov_ops,  },
0125     { .name = "testl",  .ops = &mov_ops,  },
0126     { .name = "ucomisd",    .ops = &mov_ops,  },
0127     { .name = "ucomiss",    .ops = &mov_ops,  },
0128     { .name = "vaddsd", .ops = &mov_ops,  },
0129     { .name = "vandpd", .ops = &mov_ops,  },
0130     { .name = "vmovdqa",    .ops = &mov_ops,  },
0131     { .name = "vmovq",  .ops = &mov_ops,  },
0132     { .name = "vmovsd", .ops = &mov_ops,  },
0133     { .name = "vmulsd", .ops = &mov_ops,  },
0134     { .name = "vorpd",  .ops = &mov_ops,  },
0135     { .name = "vsubsd", .ops = &mov_ops,  },
0136     { .name = "vucomisd",   .ops = &mov_ops,  },
0137     { .name = "xadd",   .ops = &mov_ops,  },
0138     { .name = "xbeginl",    .ops = &jump_ops, },
0139     { .name = "xbeginq",    .ops = &jump_ops, },
0140     { .name = "xchg",   .ops = &mov_ops,  },
0141     { .name = "xor",    .ops = &mov_ops, },
0142     { .name = "xorb",   .ops = &mov_ops, },
0143     { .name = "xorpd",  .ops = &mov_ops, },
0144     { .name = "xorps",  .ops = &mov_ops, },
0145 };
0146 
0147 static bool amd__ins_is_fused(struct arch *arch, const char *ins1,
0148                   const char *ins2)
0149 {
0150     if (strstr(ins2, "jmp"))
0151         return false;
0152 
0153     /* Family >= 15h supports cmp/test + branch fusion */
0154     if (arch->family >= 0x15 && (strstarts(ins1, "test") ||
0155         (strstarts(ins1, "cmp") && !strstr(ins1, "xchg")))) {
0156         return true;
0157     }
0158 
0159     /* Family >= 19h supports some ALU + branch fusion */
0160     if (arch->family >= 0x19 && (strstarts(ins1, "add") ||
0161         strstarts(ins1, "sub") || strstarts(ins1, "and") ||
0162         strstarts(ins1, "inc") || strstarts(ins1, "dec") ||
0163         strstarts(ins1, "or") || strstarts(ins1, "xor"))) {
0164         return true;
0165     }
0166 
0167     return false;
0168 }
0169 
0170 static bool intel__ins_is_fused(struct arch *arch, const char *ins1,
0171                 const char *ins2)
0172 {
0173     if (arch->family != 6 || arch->model < 0x1e || strstr(ins2, "jmp"))
0174         return false;
0175 
0176     if (arch->model == 0x1e) {
0177         /* Nehalem */
0178         if ((strstr(ins1, "cmp") && !strstr(ins1, "xchg")) ||
0179              strstr(ins1, "test")) {
0180             return true;
0181         }
0182     } else {
0183         /* Newer platform */
0184         if ((strstr(ins1, "cmp") && !strstr(ins1, "xchg")) ||
0185              strstr(ins1, "test") ||
0186              strstr(ins1, "add") ||
0187              strstr(ins1, "sub") ||
0188              strstr(ins1, "and") ||
0189              strstr(ins1, "inc") ||
0190              strstr(ins1, "dec")) {
0191             return true;
0192         }
0193     }
0194 
0195     return false;
0196 }
0197 
0198 static int x86__cpuid_parse(struct arch *arch, char *cpuid)
0199 {
0200     unsigned int family, model, stepping;
0201     int ret;
0202 
0203     /*
0204      * cpuid = "GenuineIntel,family,model,stepping"
0205      */
0206     ret = sscanf(cpuid, "%*[^,],%u,%u,%u", &family, &model, &stepping);
0207     if (ret == 3) {
0208         arch->family = family;
0209         arch->model = model;
0210         arch->ins_is_fused = strstarts(cpuid, "AuthenticAMD") ?
0211                     amd__ins_is_fused :
0212                     intel__ins_is_fused;
0213         return 0;
0214     }
0215 
0216     return -1;
0217 }
0218 
0219 static int x86__annotate_init(struct arch *arch, char *cpuid)
0220 {
0221     int err = 0;
0222 
0223     if (arch->initialized)
0224         return 0;
0225 
0226     if (cpuid) {
0227         if (x86__cpuid_parse(arch, cpuid))
0228             err = SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING;
0229     }
0230 
0231     arch->initialized = true;
0232     return err;
0233 }