unsigned int len:8; /* arch string length */
bool skip:1; /* show_arch should skip this. */
enum processor_type type; /* arch type */
+ enum { vsz_none, vsz_set, vsz_reset } vsz; /* vector size control */
i386_cpu_flags enable; /* cpu feature enable flags */
i386_cpu_flags disable; /* cpu feature disable flags */
}
arch_entry;
static void update_code_flag (int, int);
+static void s_insn (int);
static void set_code_flag (int);
static void set_16bit_gcc_code_flag (int);
static void set_intel_syntax (int);
static int i386_intel_operand (char *, int);
static int i386_intel_simplify (expressionS *);
static int i386_intel_parse_name (const char *, expressionS *);
-static const reg_entry *parse_register (char *, char **);
-static const char *parse_insn (const char *, char *);
+static const reg_entry *parse_register (const char *, char **);
+static const char *parse_insn (const char *, char *, bool);
static char *parse_operands (char *, const char *);
static void swap_operands (void);
static void swap_2_operands (unsigned int, unsigned int);
-static enum flag_code i386_addressing_mode (void);
+static enum i386_flag_code i386_addressing_mode (void);
static void optimize_imm (void);
-static void optimize_disp (void);
+static bool optimize_disp (const insn_template *t);
static const insn_template *match_template (char);
static int check_string (void);
static int process_suffix (void);
no_default_mask,
unsupported_rc_sae,
invalid_register_operand,
+ internal_error,
};
struct _i386_insn
unsigned int flags[MAX_OPERANDS];
#define Operand_PCrel 1
#define Operand_Mem 2
+#define Operand_Signed 4 /* .insn only */
/* Relocation type for operand */
enum bfd_reloc_code_real reloc[MAX_OPERANDS];
unsigned int prefixes;
unsigned char prefix[MAX_PREFIXES];
+ /* .insn allows for reserved opcode spaces. */
+ unsigned char insn_opcode_space;
+
+ /* .insn also allows (requires) specifying immediate size. */
+ unsigned char imm_bits[MAX_OPERANDS];
+
/* Register is in low 3 bits of opcode. */
bool short_form;
vex_encoding_vex,
vex_encoding_vex3,
vex_encoding_evex,
+ vex_encoding_evex512,
vex_encoding_error
} vec_encoding;
static char mnemonic_chars[256];
static char register_chars[256];
static char operand_chars[256];
-static char identifier_chars[256];
/* Lexical macros. */
-#define is_mnemonic_char(x) (mnemonic_chars[(unsigned char) x])
#define is_operand_char(x) (operand_chars[(unsigned char) x])
#define is_register_char(x) (register_chars[(unsigned char) x])
#define is_space_char(x) ((x) == ' ')
-#define is_identifier_char(x) (identifier_chars[(unsigned char) x])
-/* All non-digit non-letter characters that may occur in an operand. */
-static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:[@]";
+/* All non-digit non-letter characters that may occur in an operand and
+ which aren't already in extra_symbol_chars[]. */
+static const char operand_special_chars[] = "$+,)._~/<>|&^!=:@]";
/* md_assemble() always leaves the strings it's passed unaltered. To
effect this we maintain a stack of saved characters that we've smashed
/* Current operand we are working on. */
static int this_operand = -1;
-/* We support four different modes. FLAG_CODE variable is used to distinguish
- these. */
+/* Are we processing a .insn directive? */
+#define dot_insn() (i.tm.mnem_off == MN__insn)
-enum flag_code {
- CODE_32BIT,
- CODE_16BIT,
- CODE_64BIT };
-
-static enum flag_code flag_code;
+enum i386_flag_code i386_flag_code;
+#define flag_code i386_flag_code /* Permit to continue using original name. */
static unsigned int object_64bit;
static unsigned int disallow_64bit_reloc;
static int use_rela_relocations = 0;
static char *cpu_sub_arch_name = NULL;
/* CPU feature flags. */
-static i386_cpu_flags cpu_arch_flags = CPU_UNKNOWN_FLAGS;
+i386_cpu_flags cpu_arch_flags = CPU_UNKNOWN_FLAGS;
/* If we have selected a cpu we are generating instructions for. */
static int cpu_arch_tune_set = 0;
/* Cpu we are generating instructions for. */
enum processor_type cpu_arch_tune = PROCESSOR_UNKNOWN;
-/* CPU feature flags of cpu we are generating instructions for. */
-static i386_cpu_flags cpu_arch_tune_flags;
-
/* CPU instruction set architecture used. */
enum processor_type cpu_arch_isa = PROCESSOR_UNKNOWN;
larger than a byte offset. */
static bool no_cond_jump_promotion = false;
+/* This will be set from an expression parser hook if there's any
+ applicable operator involved in an expression. */
+static enum {
+ expr_operator_none,
+ expr_operator_present,
+ expr_large_value,
+} expr_mode;
+
/* Encode SSE instructions with VEX prefix. */
static unsigned int sse2avx;
/* Encode aligned vector move as unaligned vector move. */
static unsigned int use_unaligned_vector_move;
+/* Maximum permitted vector size. */
+#define VSZ_DEFAULT VSZ512
+static unsigned int vector_size = VSZ_DEFAULT;
+
/* Encode scalar AVX instructions with specific vector length. */
static enum
{
};
#define ARCH(n, t, f, s) \
- { STRING_COMMA_LEN (#n), s, PROCESSOR_ ## t, CPU_ ## f ## _FLAGS, \
+ { STRING_COMMA_LEN (#n), s, PROCESSOR_ ## t, vsz_none, CPU_ ## f ## _FLAGS, \
CPU_NONE_FLAGS }
#define SUBARCH(n, e, d, s) \
- { STRING_COMMA_LEN (#n), s, PROCESSOR_NONE, CPU_ ## e ## _FLAGS, \
+ { STRING_COMMA_LEN (#n), s, PROCESSOR_NONE, vsz_none, CPU_ ## e ## _FLAGS, \
CPU_ ## d ## _FLAGS }
+#define VECARCH(n, e, d, v) \
+ { STRING_COMMA_LEN (#n), false, PROCESSOR_NONE, vsz_ ## v, \
+ CPU_ ## e ## _FLAGS, CPU_ ## d ## _FLAGS }
static const arch_entry cpu_arch[] =
{
ARCH (i386, I386, 386, false),
ARCH (i486, I486, 486, false),
ARCH (i586, PENTIUM, 586, false),
- ARCH (i686, PENTIUMPRO, 686, false),
ARCH (pentium, PENTIUM, 586, false),
+ ARCH (i686, I686, 686, false),
ARCH (pentiumpro, PENTIUMPRO, PENTIUMPRO, false),
ARCH (pentiumii, PENTIUMPRO, P2, false),
ARCH (pentiumiii, PENTIUMPRO, P3, false),
SUBARCH (sse4.1, SSE4_1, ANY_SSE4_1, false),
SUBARCH (sse4.2, SSE4_2, ANY_SSE4_2, false),
SUBARCH (sse4, SSE4_2, ANY_SSE4_1, false),
- SUBARCH (avx, AVX, ANY_AVX, false),
- SUBARCH (avx2, AVX2, ANY_AVX2, false),
- SUBARCH (avx512f, AVX512F, ANY_AVX512F, false),
- SUBARCH (avx512cd, AVX512CD, ANY_AVX512CD, false),
- SUBARCH (avx512er, AVX512ER, ANY_AVX512ER, false),
- SUBARCH (avx512pf, AVX512PF, ANY_AVX512PF, false),
- SUBARCH (avx512dq, AVX512DQ, ANY_AVX512DQ, false),
- SUBARCH (avx512bw, AVX512BW, ANY_AVX512BW, false),
- SUBARCH (avx512vl, AVX512VL, ANY_AVX512VL, false),
+ VECARCH (avx, AVX, ANY_AVX, reset),
+ VECARCH (avx2, AVX2, ANY_AVX2, reset),
+ VECARCH (avx512f, AVX512F, ANY_AVX512F, reset),
+ VECARCH (avx512cd, AVX512CD, ANY_AVX512CD, reset),
+ VECARCH (avx512er, AVX512ER, ANY_AVX512ER, reset),
+ VECARCH (avx512pf, AVX512PF, ANY_AVX512PF, reset),
+ VECARCH (avx512dq, AVX512DQ, ANY_AVX512DQ, reset),
+ VECARCH (avx512bw, AVX512BW, ANY_AVX512BW, reset),
+ VECARCH (avx512vl, AVX512VL, ANY_AVX512VL, reset),
+ SUBARCH (monitor, MONITOR, MONITOR, false),
SUBARCH (vmx, VMX, ANY_VMX, false),
SUBARCH (vmfunc, VMFUNC, ANY_VMFUNC, false),
SUBARCH (smx, SMX, SMX, false),
SUBARCH (xsavec, XSAVEC, ANY_XSAVEC, false),
SUBARCH (xsaves, XSAVES, ANY_XSAVES, false),
SUBARCH (aes, AES, ANY_AES, false),
- SUBARCH (pclmul, PCLMUL, ANY_PCLMUL, false),
- SUBARCH (clmul, PCLMUL, ANY_PCLMUL, true),
+ SUBARCH (pclmul, PCLMULQDQ, ANY_PCLMULQDQ, false),
+ SUBARCH (clmul, PCLMULQDQ, ANY_PCLMULQDQ, true),
SUBARCH (fsgsbase, FSGSBASE, FSGSBASE, false),
SUBARCH (rdrnd, RDRND, RDRND, false),
SUBARCH (f16c, F16C, ANY_F16C, false),
SUBARCH (lwp, LWP, ANY_LWP, false),
SUBARCH (movbe, MOVBE, MOVBE, false),
SUBARCH (cx16, CX16, CX16, false),
+ SUBARCH (lahf_sahf, LAHF_SAHF, LAHF_SAHF, false),
SUBARCH (ept, EPT, ANY_EPT, false),
SUBARCH (lzcnt, LZCNT, LZCNT, false),
SUBARCH (popcnt, POPCNT, POPCNT, false),
SUBARCH (prefetchwt1, PREFETCHWT1, PREFETCHWT1, false),
SUBARCH (se1, SE1, SE1, false),
SUBARCH (clwb, CLWB, CLWB, false),
- SUBARCH (avx512ifma, AVX512IFMA, ANY_AVX512IFMA, false),
- SUBARCH (avx512vbmi, AVX512VBMI, ANY_AVX512VBMI, false),
- SUBARCH (avx512_4fmaps, AVX512_4FMAPS, ANY_AVX512_4FMAPS, false),
- SUBARCH (avx512_4vnniw, AVX512_4VNNIW, ANY_AVX512_4VNNIW, false),
- SUBARCH (avx512_vpopcntdq, AVX512_VPOPCNTDQ, ANY_AVX512_VPOPCNTDQ, false),
- SUBARCH (avx512_vbmi2, AVX512_VBMI2, ANY_AVX512_VBMI2, false),
- SUBARCH (avx512_vnni, AVX512_VNNI, ANY_AVX512_VNNI, false),
- SUBARCH (avx512_bitalg, AVX512_BITALG, ANY_AVX512_BITALG, false),
- SUBARCH (avx_vnni, AVX_VNNI, ANY_AVX_VNNI, false),
+ VECARCH (avx512ifma, AVX512IFMA, ANY_AVX512IFMA, reset),
+ VECARCH (avx512vbmi, AVX512VBMI, ANY_AVX512VBMI, reset),
+ VECARCH (avx512_4fmaps, AVX512_4FMAPS, ANY_AVX512_4FMAPS, reset),
+ VECARCH (avx512_4vnniw, AVX512_4VNNIW, ANY_AVX512_4VNNIW, reset),
+ VECARCH (avx512_vpopcntdq, AVX512_VPOPCNTDQ, ANY_AVX512_VPOPCNTDQ, reset),
+ VECARCH (avx512_vbmi2, AVX512_VBMI2, ANY_AVX512_VBMI2, reset),
+ VECARCH (avx512_vnni, AVX512_VNNI, ANY_AVX512_VNNI, reset),
+ VECARCH (avx512_bitalg, AVX512_BITALG, ANY_AVX512_BITALG, reset),
+ VECARCH (avx_vnni, AVX_VNNI, ANY_AVX_VNNI, reset),
SUBARCH (clzero, CLZERO, CLZERO, false),
SUBARCH (mwaitx, MWAITX, MWAITX, false),
SUBARCH (ospke, OSPKE, ANY_OSPKE, false),
SUBARCH (ibt, IBT, IBT, false),
SUBARCH (shstk, SHSTK, SHSTK, false),
SUBARCH (gfni, GFNI, ANY_GFNI, false),
- SUBARCH (vaes, VAES, ANY_VAES, false),
- SUBARCH (vpclmulqdq, VPCLMULQDQ, ANY_VPCLMULQDQ, false),
+ VECARCH (vaes, VAES, ANY_VAES, reset),
+ VECARCH (vpclmulqdq, VPCLMULQDQ, ANY_VPCLMULQDQ, reset),
SUBARCH (wbnoinvd, WBNOINVD, WBNOINVD, false),
SUBARCH (pconfig, PCONFIG, PCONFIG, false),
SUBARCH (waitpkg, WAITPKG, WAITPKG, false),
SUBARCH (amx_int8, AMX_INT8, ANY_AMX_INT8, false),
SUBARCH (amx_bf16, AMX_BF16, ANY_AMX_BF16, false),
SUBARCH (amx_fp16, AMX_FP16, ANY_AMX_FP16, false),
+ SUBARCH (amx_complex, AMX_COMPLEX, ANY_AMX_COMPLEX, false),
SUBARCH (amx_tile, AMX_TILE, ANY_AMX_TILE, false),
SUBARCH (movdiri, MOVDIRI, MOVDIRI, false),
SUBARCH (movdir64b, MOVDIR64B, MOVDIR64B, false),
- SUBARCH (avx512_bf16, AVX512_BF16, ANY_AVX512_BF16, false),
- SUBARCH (avx512_vp2intersect, AVX512_VP2INTERSECT,
- ANY_AVX512_VP2INTERSECT, false),
+ VECARCH (avx512_bf16, AVX512_BF16, ANY_AVX512_BF16, reset),
+ VECARCH (avx512_vp2intersect, AVX512_VP2INTERSECT,
+ ANY_AVX512_VP2INTERSECT, reset),
SUBARCH (tdx, TDX, TDX, false),
SUBARCH (enqcmd, ENQCMD, ENQCMD, false),
SUBARCH (serialize, SERIALIZE, SERIALIZE, false),
SUBARCH (widekl, WIDEKL, ANY_WIDEKL, false),
SUBARCH (uintr, UINTR, UINTR, false),
SUBARCH (hreset, HRESET, HRESET, false),
- SUBARCH (avx512_fp16, AVX512_FP16, ANY_AVX512_FP16, false),
+ VECARCH (avx512_fp16, AVX512_FP16, ANY_AVX512_FP16, reset),
SUBARCH (prefetchi, PREFETCHI, PREFETCHI, false),
- SUBARCH (avx_ifma, AVX_IFMA, ANY_AVX_IFMA, false),
- SUBARCH (avx_vnni_int8, AVX_VNNI_INT8, ANY_AVX_VNNI_INT8, false),
+ VECARCH (avx_ifma, AVX_IFMA, ANY_AVX_IFMA, reset),
+ VECARCH (avx_vnni_int8, AVX_VNNI_INT8, ANY_AVX_VNNI_INT8, reset),
SUBARCH (cmpccxadd, CMPCCXADD, CMPCCXADD, false),
SUBARCH (wrmsrns, WRMSRNS, WRMSRNS, false),
SUBARCH (msrlist, MSRLIST, MSRLIST, false),
- SUBARCH (avx_ne_convert, AVX_NE_CONVERT, ANY_AVX_NE_CONVERT, false),
+ VECARCH (avx_ne_convert, AVX_NE_CONVERT, ANY_AVX_NE_CONVERT, reset),
SUBARCH (rao_int, RAO_INT, RAO_INT, false),
SUBARCH (rmpquery, RMPQUERY, ANY_RMPQUERY, false),
+ SUBARCH (fred, FRED, ANY_FRED, false),
+ SUBARCH (lkgs, LKGS, ANY_LKGS, false),
+ VECARCH (avx_vnni_int16, AVX_VNNI_INT16, ANY_AVX_VNNI_INT16, reset),
+ VECARCH (sha512, SHA512, ANY_SHA512, reset),
+ VECARCH (sm3, SM3, ANY_SM3, reset),
+ VECARCH (sm4, SM4, ANY_SM4, reset),
+ SUBARCH (pbndkb, PBNDKB, PBNDKB, false),
+ VECARCH (avx10.1, AVX10_1, ANY_AVX512F, set),
};
#undef SUBARCH
{"bfloat16", float_cons, 'b'},
{"value", cons, 2},
{"slong", signed_cons, 4},
+ {"insn", s_insn, 0},
{"noopt", s_ignore, 0},
{"optim", s_ignore, 0},
{"code16gcc", set_16bit_gcc_code_flag, CODE_16BIT},
{0x66,0x90}; /* xchg %ax,%ax */
static const unsigned char f32_3[] =
{0x8d,0x76,0x00}; /* leal 0(%esi),%esi */
-static const unsigned char f32_4[] =
- {0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */
+#define f32_4 (f32_5 + 1) /* leal 0(%esi,%eiz),%esi */
+static const unsigned char f32_5[] =
+ {0x2e,0x8d,0x74,0x26,0x00}; /* leal %cs:0(%esi,%eiz),%esi */
static const unsigned char f32_6[] =
{0x8d,0xb6,0x00,0x00,0x00,0x00}; /* leal 0L(%esi),%esi */
-static const unsigned char f32_7[] =
- {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */
+#define f32_7 (f32_8 + 1) /* leal 0L(%esi,%eiz),%esi */
+static const unsigned char f32_8[] =
+ {0x2e,0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal %cs:0L(%esi,%eiz),%esi */
+static const unsigned char f64_3[] =
+ {0x48,0x89,0xf6}; /* mov %rsi,%rsi */
+static const unsigned char f64_4[] =
+ {0x48,0x8d,0x76,0x00}; /* lea 0(%rsi),%rsi */
+#define f64_5 (f64_6 + 1) /* lea 0(%rsi,%riz),%rsi */
+static const unsigned char f64_6[] =
+ {0x2e,0x48,0x8d,0x74,0x26,0x00}; /* lea %cs:0(%rsi,%riz),%rsi */
+static const unsigned char f64_7[] =
+ {0x48,0x8d,0xb6,0x00,0x00,0x00,0x00}; /* lea 0L(%rsi),%rsi */
+#define f64_8 (f64_9 + 1) /* lea 0L(%rsi,%riz),%rsi */
+static const unsigned char f64_9[] =
+ {0x2e,0x48,0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* lea %cs:0L(%rsi,%riz),%rsi */
+#define f16_2 (f64_3 + 1) /* mov %si,%si */
static const unsigned char f16_3[] =
{0x8d,0x74,0x00}; /* lea 0(%si),%si */
-static const unsigned char f16_4[] =
- {0x8d,0xb4,0x00,0x00}; /* lea 0W(%si),%si */
+#define f16_4 (f16_5 + 1) /* lea 0W(%si),%si */
+static const unsigned char f16_5[] =
+ {0x2e,0x8d,0xb4,0x00,0x00}; /* lea %cs:0W(%si),%si */
static const unsigned char jump_disp8[] =
{0xeb}; /* jmp disp8 */
static const unsigned char jump32_disp32[] =
{0x66,0xe9}; /* jmp disp32 */
/* 32-bit NOPs patterns. */
static const unsigned char *const f32_patt[] = {
- f32_1, f32_2, f32_3, f32_4, NULL, f32_6, f32_7
+ f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8
+};
+/* 64-bit NOPs patterns. */
+static const unsigned char *const f64_patt[] = {
+ f32_1, f32_2, f64_3, f64_4, f64_5, f64_6, f64_7, f64_8, f64_9
};
/* 16-bit NOPs patterns. */
static const unsigned char *const f16_patt[] = {
- f32_1, f32_2, f16_3, f16_4
+ f32_1, f16_2, f16_3, f16_4, f16_5
};
/* nopl (%[re]ax) */
static const unsigned char alt_3[] =
static const unsigned char alt_4[] =
{0x0f,0x1f,0x40,0x00};
/* nopl 0(%[re]ax,%[re]ax,1) */
-static const unsigned char alt_5[] =
- {0x0f,0x1f,0x44,0x00,0x00};
+#define alt_5 (alt_6 + 1)
/* nopw 0(%[re]ax,%[re]ax,1) */
static const unsigned char alt_6[] =
{0x66,0x0f,0x1f,0x44,0x00,0x00};
static const unsigned char alt_7[] =
{0x0f,0x1f,0x80,0x00,0x00,0x00,0x00};
/* nopl 0L(%[re]ax,%[re]ax,1) */
-static const unsigned char alt_8[] =
- {0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
+#define alt_8 (alt_9 + 1)
/* nopw 0L(%[re]ax,%[re]ax,1) */
static const unsigned char alt_9[] =
{0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
/* nopw %cs:0L(%[re]ax,%[re]ax,1) */
-static const unsigned char alt_10[] =
- {0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
+#define alt_10 (alt_11 + 1)
/* data16 nopw %cs:0L(%eax,%eax,1) */
static const unsigned char alt_11[] =
{0x66,0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
}
nops = patt[max_single_nop_size - 1];
-
- /* Use the smaller one if the requsted one isn't available. */
- if (nops == NULL)
- {
- max_single_nop_size--;
- nops = patt[max_single_nop_size - 1];
- }
-
last = count % max_single_nop_size;
count -= last;
if (last)
{
nops = patt[last - 1];
- if (nops == NULL)
- {
- /* Use the smaller one plus one-byte NOP if the needed one
- isn't available. */
- last--;
- nops = patt[last - 1];
- memcpy (where + offset, nops, last);
- where[offset + last] = *patt[0];
- }
- else
- memcpy (where + offset, nops, last);
+ memcpy (where + offset, nops, last);
}
}
/* We need to decide which NOP sequence to use for 32bit and
64bit. When -mtune= is used:
- 1. For PROCESSOR_I386, PROCESSOR_I486, PROCESSOR_PENTIUM and
+ 1. For PROCESSOR_I?86, PROCESSOR_PENTIUM, PROCESSOR_IAMCU, and
PROCESSOR_GENERIC32, f32_patt will be used.
2. For the rest, alt_patt will be used.
When -mtune= isn't used, alt_patt will be used if
- cpu_arch_isa_flags has CpuNop. Otherwise, f32_patt will
+ cpu_arch_isa_flags has CpuNop. Otherwise, f32_patt/f64_patt will
be used.
When -march= or .arch is used, we can't use anything beyond
cpu_arch_isa_flags. */
- if (flag_code == CODE_16BIT)
+ if (fragP->tc_frag_data.code == CODE_16BIT)
{
patt = f16_patt;
max_single_nop_size = sizeof (f16_patt) / sizeof (f16_patt[0]);
}
else
{
+ patt = fragP->tc_frag_data.code == CODE_64BIT ? f64_patt : f32_patt;
if (fragP->tc_frag_data.isa == PROCESSOR_UNKNOWN)
{
- /* PROCESSOR_UNKNOWN means that all ISAs may be used. */
- switch (cpu_arch_tune)
+ /* PROCESSOR_UNKNOWN means that all ISAs may be used, unless
+ explicitly disabled. */
+ switch (fragP->tc_frag_data.tune)
{
case PROCESSOR_UNKNOWN:
/* We use cpu_arch_isa_flags to check if we SHOULD
optimize with nops. */
- if (fragP->tc_frag_data.isa_flags.bitfield.cpunop)
+ if (fragP->tc_frag_data.isanop)
patt = alt_patt;
- else
- patt = f32_patt;
break;
+
+ case PROCESSOR_PENTIUMPRO:
case PROCESSOR_PENTIUM4:
case PROCESSOR_NOCONA:
case PROCESSOR_CORE:
case PROCESSOR_BD:
case PROCESSOR_ZNVER:
case PROCESSOR_BT:
- patt = alt_patt;
+ if (fragP->tc_frag_data.cpunop)
+ patt = alt_patt;
break;
+
case PROCESSOR_I386:
case PROCESSOR_I486:
case PROCESSOR_PENTIUM:
- case PROCESSOR_PENTIUMPRO:
+ case PROCESSOR_I686:
case PROCESSOR_IAMCU:
case PROCESSOR_GENERIC32:
- patt = f32_patt;
break;
case PROCESSOR_NONE:
abort ();
abort ();
break;
- case PROCESSOR_I386:
- case PROCESSOR_I486:
- case PROCESSOR_PENTIUM:
- case PROCESSOR_IAMCU:
- case PROCESSOR_K6:
- case PROCESSOR_ATHLON:
- case PROCESSOR_K8:
- case PROCESSOR_AMDFAM10:
- case PROCESSOR_BD:
- case PROCESSOR_ZNVER:
- case PROCESSOR_BT:
- case PROCESSOR_GENERIC32:
+ default:
/* We use cpu_arch_isa_flags to check if we CAN optimize
with nops. */
- if (fragP->tc_frag_data.isa_flags.bitfield.cpunop)
- patt = alt_patt;
- else
- patt = f32_patt;
- break;
- case PROCESSOR_PENTIUMPRO:
- case PROCESSOR_PENTIUM4:
- case PROCESSOR_NOCONA:
- case PROCESSOR_CORE:
- case PROCESSOR_CORE2:
- case PROCESSOR_COREI7:
- if (fragP->tc_frag_data.isa_flags.bitfield.cpunop)
+ if (fragP->tc_frag_data.isanop)
patt = alt_patt;
- else
- patt = f32_patt;
- break;
- case PROCESSOR_GENERIC64:
- patt = alt_patt;
break;
+
case PROCESSOR_NONE:
abort ();
}
}
- if (patt == f32_patt)
+ if (patt != alt_patt)
{
- max_single_nop_size = sizeof (f32_patt) / sizeof (f32_patt[0]);
+ max_single_nop_size = patt == f32_patt ? ARRAY_SIZE (f32_patt)
+ : ARRAY_SIZE (f64_patt);
/* Limit number of NOPs to 2 for older processors. */
max_number_of_nops = 2;
}
}
}
+static INLINE bool
+is_cpu (const insn_template *t, enum i386_cpu cpu)
+{
+ switch (cpu)
+ {
+ case Cpu287: return t->cpu.bitfield.cpu287;
+ case Cpu387: return t->cpu.bitfield.cpu387;
+ case Cpu3dnow: return t->cpu.bitfield.cpu3dnow;
+ case Cpu3dnowA: return t->cpu.bitfield.cpu3dnowa;
+ case CpuAVX: return t->cpu.bitfield.cpuavx;
+ case CpuHLE: return t->cpu.bitfield.cpuhle;
+ case CpuAVX512F: return t->cpu.bitfield.cpuavx512f;
+ case CpuAVX512VL: return t->cpu.bitfield.cpuavx512vl;
+ case Cpu64: return t->cpu.bitfield.cpu64;
+ case CpuNo64: return t->cpu.bitfield.cpuno64;
+ default:
+ gas_assert (cpu < CpuAttrEnums);
+ }
+ return t->cpu.bitfield.isa == cpu + 1u;
+}
+
+static i386_cpu_flags cpu_flags_from_attr (i386_cpu_attr a)
+{
+ const unsigned int bps = sizeof (a.array[0]) * CHAR_BIT;
+ i386_cpu_flags f = { .array[0] = 0 };
+
+ switch (ARRAY_SIZE(a.array))
+ {
+ case 1:
+ f.array[CpuAttrEnums / bps]
+ |= (a.array[0] >> CpuIsaBits) << (CpuAttrEnums % bps);
+ if (CpuAttrEnums % bps > CpuIsaBits)
+ f.array[CpuAttrEnums / bps + 1]
+ = (a.array[0] >> CpuIsaBits) >> (bps - CpuAttrEnums % bps);
+ break;
+ default:
+ abort ();
+ }
+
+ if (a.bitfield.isa)
+ f.array[(a.bitfield.isa - 1) / bps] |= 1u << ((a.bitfield.isa - 1) % bps);
+
+ return f;
+}
+
static INLINE int
cpu_flags_all_zero (const union i386_cpu_flags *x)
{
}
static INLINE int
-cpu_flags_check_cpu64 (i386_cpu_flags f)
+cpu_flags_check_cpu64 (const insn_template *t)
{
- return !((flag_code == CODE_64BIT && f.bitfield.cpuno64)
- || (flag_code != CODE_64BIT && f.bitfield.cpu64));
+ return flag_code == CODE_64BIT
+ ? !t->cpu.bitfield.cpuno64
+ : !t->cpu.bitfield.cpu64;
}
static INLINE i386_cpu_flags
static const i386_cpu_flags avx512 = CPU_ANY_AVX512F_FLAGS;
+static INLINE bool need_evex_encoding (void)
+{
+ return i.vec_encoding == vex_encoding_evex
+ || i.vec_encoding == vex_encoding_evex512
+ || i.mask.reg;
+}
+
#define CPU_FLAGS_ARCH_MATCH 0x1
#define CPU_FLAGS_64BIT_MATCH 0x2
static int
cpu_flags_match (const insn_template *t)
{
- i386_cpu_flags x = t->cpu_flags;
- int match = cpu_flags_check_cpu64 (x) ? CPU_FLAGS_64BIT_MATCH : 0;
+ i386_cpu_flags x = cpu_flags_from_attr (t->cpu);
+ int match = cpu_flags_check_cpu64 (t) ? CPU_FLAGS_64BIT_MATCH : 0;
x.bitfield.cpu64 = 0;
x.bitfield.cpuno64 = 0;
/* This instruction is available only on some archs. */
i386_cpu_flags cpu = cpu_arch_flags;
+ /* Dual VEX/EVEX templates may need stripping of one of the flags. */
+ if (t->opcode_modifier.vex && t->opcode_modifier.evex)
+ {
+ /* Dual AVX/AVX512F templates need to retain AVX512F only if we already
+ know that EVEX encoding will be needed. */
+ if ((x.bitfield.cpuavx || x.bitfield.cpuavx2)
+ && x.bitfield.cpuavx512f)
+ {
+ if (need_evex_encoding ())
+ {
+ x.bitfield.cpuavx = 0;
+ x.bitfield.cpuavx2 = 0;
+ }
+ /* need_evex_encoding() isn't reliable before operands were
+ parsed. */
+ else if (i.operands)
+ {
+ x.bitfield.cpuavx512f = 0;
+ x.bitfield.cpuavx512vl = 0;
+ if (x.bitfield.cpufma && !cpu.bitfield.cpufma)
+ x.bitfield.cpuavx = 0;
+ }
+ }
+ }
+
/* AVX512VL is no standalone feature - match it and then strip it. */
if (x.bitfield.cpuavx512vl && !cpu.bitfield.cpuavx512vl)
return match;
cpu = cpu_flags_and (x, cpu);
if (!cpu_flags_all_zero (&cpu))
{
- if (x.bitfield.cpuavx)
+ if (t->cpu.bitfield.cpuavx && t->cpu.bitfield.cpuavx512f)
+ {
+ if ((need_evex_encoding ()
+ ? cpu.bitfield.cpuavx512f
+ : cpu.bitfield.cpuavx)
+ && (!x.bitfield.cpufma || cpu.bitfield.cpufma
+ || cpu_arch_flags.bitfield.cpuavx512f)
+ && (!x.bitfield.cpugfni || cpu.bitfield.cpugfni)
+ && (!x.bitfield.cpuvaes || cpu.bitfield.cpuvaes)
+ && (!x.bitfield.cpuvpclmulqdq || cpu.bitfield.cpuvpclmulqdq))
+ match |= CPU_FLAGS_ARCH_MATCH;
+ }
+ else if (x.bitfield.cpuavx)
{
/* We need to check a few extra flags with AVX. */
if (cpu.bitfield.cpuavx
|| (sse2avx && !i.prefix[DATA_PREFIX]))
&& (!x.bitfield.cpuaes || cpu.bitfield.cpuaes)
&& (!x.bitfield.cpugfni || cpu.bitfield.cpugfni)
- && (!x.bitfield.cpupclmul || cpu.bitfield.cpupclmul))
+ && (!x.bitfield.cpupclmulqdq || cpu.bitfield.cpupclmulqdq))
match |= CPU_FLAGS_ARCH_MATCH;
}
+ else if (x.bitfield.cpuavx2 && cpu.bitfield.cpuavx2)
+ match |= CPU_FLAGS_ARCH_MATCH;
else if (x.bitfield.cpuavx512f)
{
/* We need to check a few extra flags with AVX512F. */
if (cpu.bitfield.cpuavx512f
- && (!x.bitfield.cpugfni || cpu.bitfield.cpugfni)
- && (!x.bitfield.cpuvaes || cpu.bitfield.cpuvaes)
- && (!x.bitfield.cpuvpclmulqdq || cpu.bitfield.cpuvpclmulqdq))
+ && (!x.bitfield.cpugfni || cpu.bitfield.cpugfni))
match |= CPU_FLAGS_ARCH_MATCH;
}
else
return match;
/* Check reverse. */
- gas_assert ((i.operands >= 2 && i.operands <= 3)
- || t->opcode_modifier.vexsources);
+ gas_assert (i.operands >= 2);
for (j = 0; j < i.operands; j++)
{
unsigned int given = i.operands - j - 1;
- /* For 4- and 5-operand insns VEX.W controls just the first two
+ /* For FMA4 and XOP insns VEX.W controls just the first two
register operands. */
- if (t->opcode_modifier.vexsources)
+ if (is_cpu (t, CpuFMA4) || is_cpu (t, CpuXOP))
given = j < 2 ? 1 - j : j;
if (t->operand_types[j].bitfield.class == Reg
static INLINE int
fits_in_imm4 (offsetT num)
{
- return (num & 0xf) == num;
+ /* Despite the name, check for imm3 if we're dealing with EVEX. */
+ return (num & (i.vec_encoding != vex_encoding_evex ? 0xf : 7)) == num;
}
static i386_operand_type
}
else if (fits_in_signed_byte (num))
{
- t.bitfield.imm8 = 1;
+ if (fits_in_unsigned_byte (num))
+ t.bitfield.imm8 = 1;
t.bitfield.imm8s = 1;
t.bitfield.imm16 = 1;
t.bitfield.imm32 = 1;
static void
update_code_flag (int value, int check)
{
- PRINTF_LIKE ((*as_error));
+ PRINTF_LIKE ((*as_error)) = check ? as_fatal : as_bad;
- flag_code = (enum flag_code) value;
- if (flag_code == CODE_64BIT)
- {
- cpu_arch_flags.bitfield.cpu64 = 1;
- cpu_arch_flags.bitfield.cpuno64 = 0;
- }
- else
- {
- cpu_arch_flags.bitfield.cpu64 = 0;
- cpu_arch_flags.bitfield.cpuno64 = 1;
- }
- if (value == CODE_64BIT && !cpu_arch_flags.bitfield.cpulm )
+ if (value == CODE_64BIT && !cpu_arch_flags.bitfield.cpu64 )
{
- if (check)
- as_error = as_fatal;
- else
- as_error = as_bad;
- (*as_error) (_("64bit mode not supported on `%s'."),
- cpu_arch_name ? cpu_arch_name : default_arch);
+ as_error (_("64bit mode not supported on `%s'."),
+ cpu_arch_name ? cpu_arch_name : default_arch);
+ return;
}
+
if (value == CODE_32BIT && !cpu_arch_flags.bitfield.cpui386)
{
- if (check)
- as_error = as_fatal;
- else
- as_error = as_bad;
- (*as_error) (_("32bit mode not supported on `%s'."),
- cpu_arch_name ? cpu_arch_name : default_arch);
+ as_error (_("32bit mode not supported on `%s'."),
+ cpu_arch_name ? cpu_arch_name : default_arch);
+ return;
}
+
+ flag_code = (enum flag_code) value;
+
stackop_size = '\0';
}
flag_code = (enum flag_code) new_code_flag;
if (flag_code != CODE_16BIT)
abort ();
- cpu_arch_flags.bitfield.cpu64 = 0;
- cpu_arch_flags.bitfield.cpuno64 = 1;
stackop_size = LONG_MNEM_SUFFIX;
}
expr_set_rank (O_full_ptr, syntax_flag ? 10 : 0);
- identifier_chars['%'] = intel_syntax && allow_naked_reg ? '%' : 0;
- identifier_chars['$'] = intel_syntax ? '$' : 0;
register_prefix = allow_naked_reg ? "" : "%";
}
}
static void
-extend_cpu_sub_arch_name (const char *name)
+extend_cpu_sub_arch_name (const char *pfx, const char *name)
{
if (cpu_sub_arch_name)
cpu_sub_arch_name = reconcat (cpu_sub_arch_name, cpu_sub_arch_name,
- ".", name, (const char *) NULL);
+ pfx, name, (const char *) NULL);
else
- cpu_sub_arch_name = concat (".", name, (const char *) NULL);
+ cpu_sub_arch_name = concat (pfx, name, (const char *) NULL);
+}
+
+static void isa_enable (unsigned int idx)
+{
+ i386_cpu_flags flags = cpu_flags_or (cpu_arch_flags, cpu_arch[idx].enable);
+
+ if (!cpu_flags_equal (&flags, &cpu_arch_flags))
+ {
+ extend_cpu_sub_arch_name (".", cpu_arch[idx].name);
+ cpu_arch_flags = flags;
+ }
+
+ cpu_arch_isa_flags = cpu_flags_or (cpu_arch_isa_flags, cpu_arch[idx].enable);
+}
+
+static void isa_disable (unsigned int idx)
+{
+ i386_cpu_flags flags
+ = cpu_flags_and_not (cpu_arch_flags, cpu_arch[idx].disable);
+
+ if (!cpu_flags_equal (&flags, &cpu_arch_flags))
+ {
+ extend_cpu_sub_arch_name (".no", cpu_arch[idx].name);
+ cpu_arch_flags = flags;
+ }
+
+ cpu_arch_isa_flags
+ = cpu_flags_and_not (cpu_arch_isa_flags, cpu_arch[idx].disable);
}
static void
i386_cpu_flags isa_flags;
enum processor_type isa;
enum flag_code flag_code;
+ unsigned int vector_size;
char stackop_size;
bool no_cond_jump_promotion;
} arch_stack_entry;
static const arch_stack_entry *arch_stack_top;
+ char *s;
+ int e;
+ const char *string;
+ unsigned int j = 0;
SKIP_WHITESPACE ();
- if (!is_end_of_line[(unsigned char) *input_line_pointer])
+ if (is_end_of_line[(unsigned char) *input_line_pointer])
+ {
+ as_bad (_("missing cpu architecture"));
+ input_line_pointer++;
+ return;
+ }
+
+ e = get_symbol_name (&s);
+ string = s;
+
+ if (strcmp (string, "push") == 0)
+ {
+ arch_stack_entry *top = XNEW (arch_stack_entry);
+
+ top->name = cpu_arch_name;
+ if (cpu_sub_arch_name)
+ top->sub_name = xstrdup (cpu_sub_arch_name);
+ else
+ top->sub_name = NULL;
+ top->flags = cpu_arch_flags;
+ top->isa = cpu_arch_isa;
+ top->isa_flags = cpu_arch_isa_flags;
+ top->flag_code = flag_code;
+ top->vector_size = vector_size;
+ top->stackop_size = stackop_size;
+ top->no_cond_jump_promotion = no_cond_jump_promotion;
+
+ top->prev = arch_stack_top;
+ arch_stack_top = top;
+
+ (void) restore_line_pointer (e);
+ demand_empty_rest_of_line ();
+ return;
+ }
+
+ if (strcmp (string, "pop") == 0)
{
- char *s;
- int e = get_symbol_name (&s);
- const char *string = s;
- unsigned int j = 0;
- i386_cpu_flags flags;
+ const arch_stack_entry *top = arch_stack_top;
- if (strcmp (string, "default") == 0)
+ if (!top)
+ as_bad (_(".arch stack is empty"));
+ else if (top->flag_code != flag_code
+ || top->stackop_size != stackop_size)
{
- if (strcmp (default_arch, "iamcu") == 0)
- string = default_arch;
- else
- {
- static const i386_cpu_flags cpu_unknown_flags = CPU_UNKNOWN_FLAGS;
+ static const unsigned int bits[] = {
+ [CODE_16BIT] = 16,
+ [CODE_32BIT] = 32,
+ [CODE_64BIT] = 64,
+ };
- cpu_arch_name = NULL;
- free (cpu_sub_arch_name);
- cpu_sub_arch_name = NULL;
- cpu_arch_flags = cpu_unknown_flags;
- if (flag_code == CODE_64BIT)
- {
- cpu_arch_flags.bitfield.cpu64 = 1;
- cpu_arch_flags.bitfield.cpuno64 = 0;
- }
- else
- {
- cpu_arch_flags.bitfield.cpu64 = 0;
- cpu_arch_flags.bitfield.cpuno64 = 1;
- }
- cpu_arch_isa = PROCESSOR_UNKNOWN;
- cpu_arch_isa_flags = cpu_arch[flag_code == CODE_64BIT].enable;
- if (!cpu_arch_tune_set)
- {
- cpu_arch_tune = cpu_arch_isa;
- cpu_arch_tune_flags = cpu_arch_isa_flags;
- }
+ as_bad (_("this `.arch pop' requires `.code%u%s' to be in effect"),
+ bits[top->flag_code],
+ top->stackop_size == LONG_MNEM_SUFFIX ? "gcc" : "");
+ }
+ else
+ {
+ arch_stack_top = top->prev;
- j = ARRAY_SIZE (cpu_arch) + 1;
- }
+ cpu_arch_name = top->name;
+ free (cpu_sub_arch_name);
+ cpu_sub_arch_name = top->sub_name;
+ cpu_arch_flags = top->flags;
+ cpu_arch_isa = top->isa;
+ cpu_arch_isa_flags = top->isa_flags;
+ vector_size = top->vector_size;
+ no_cond_jump_promotion = top->no_cond_jump_promotion;
+
+ XDELETE (top);
}
- else if (strcmp (string, "push") == 0)
+
+ (void) restore_line_pointer (e);
+ demand_empty_rest_of_line ();
+ return;
+ }
+
+ if (strcmp (string, "default") == 0)
+ {
+ if (strcmp (default_arch, "iamcu") == 0)
+ string = default_arch;
+ else
{
- arch_stack_entry *top = XNEW (arch_stack_entry);
+ static const i386_cpu_flags cpu_unknown_flags = CPU_UNKNOWN_FLAGS;
- top->name = cpu_arch_name;
- if (cpu_sub_arch_name)
- top->sub_name = xstrdup (cpu_sub_arch_name);
- else
- top->sub_name = NULL;
- top->flags = cpu_arch_flags;
- top->isa = cpu_arch_isa;
- top->isa_flags = cpu_arch_isa_flags;
- top->flag_code = flag_code;
- top->stackop_size = stackop_size;
- top->no_cond_jump_promotion = no_cond_jump_promotion;
+ cpu_arch_name = NULL;
+ free (cpu_sub_arch_name);
+ cpu_sub_arch_name = NULL;
+ cpu_arch_flags = cpu_unknown_flags;
+ cpu_arch_isa = PROCESSOR_UNKNOWN;
+ cpu_arch_isa_flags = cpu_arch[flag_code == CODE_64BIT].enable;
+ if (!cpu_arch_tune_set)
+ cpu_arch_tune = PROCESSOR_UNKNOWN;
- top->prev = arch_stack_top;
- arch_stack_top = top;
+ vector_size = VSZ_DEFAULT;
- (void) restore_line_pointer (e);
- demand_empty_rest_of_line ();
- return;
+ j = ARRAY_SIZE (cpu_arch) + 1;
}
- else if (strcmp (string, "pop") == 0)
- {
- const arch_stack_entry *top = arch_stack_top;
+ }
- if (!top)
- as_bad (_(".arch stack is empty"));
- else if (top->flag_code != flag_code
- || top->stackop_size != stackop_size)
+ for (; j < ARRAY_SIZE (cpu_arch); j++)
+ {
+ if (strcmp (string + (*string == '.'), cpu_arch[j].name) == 0
+ && (*string == '.') == (cpu_arch[j].type == PROCESSOR_NONE))
+ {
+ if (*string != '.')
{
- static const unsigned int bits[] = {
- [CODE_16BIT] = 16,
- [CODE_32BIT] = 32,
- [CODE_64BIT] = 64,
- };
+ check_cpu_arch_compatible (string, cpu_arch[j].enable);
- as_bad (_("this `.arch pop' requires `.code%u%s' to be in effect"),
- bits[top->flag_code],
- top->stackop_size == LONG_MNEM_SUFFIX ? "gcc" : "");
- }
- else
- {
- arch_stack_top = top->prev;
+ if (flag_code == CODE_64BIT && !cpu_arch[j].enable.bitfield.cpu64 )
+ {
+ as_bad (_("64bit mode not supported on `%s'."),
+ cpu_arch[j].name);
+ (void) restore_line_pointer (e);
+ ignore_rest_of_line ();
+ return;
+ }
+
+ if (flag_code == CODE_32BIT && !cpu_arch[j].enable.bitfield.cpui386)
+ {
+ as_bad (_("32bit mode not supported on `%s'."),
+ cpu_arch[j].name);
+ (void) restore_line_pointer (e);
+ ignore_rest_of_line ();
+ return;
+ }
- cpu_arch_name = top->name;
+ cpu_arch_name = cpu_arch[j].name;
free (cpu_sub_arch_name);
- cpu_sub_arch_name = top->sub_name;
- cpu_arch_flags = top->flags;
- cpu_arch_isa = top->isa;
- cpu_arch_isa_flags = top->isa_flags;
- no_cond_jump_promotion = top->no_cond_jump_promotion;
+ cpu_sub_arch_name = NULL;
+ cpu_arch_flags = cpu_arch[j].enable;
+ cpu_arch_isa = cpu_arch[j].type;
+ cpu_arch_isa_flags = cpu_arch[j].enable;
+ if (!cpu_arch_tune_set)
+ cpu_arch_tune = cpu_arch_isa;
+
+ vector_size = VSZ_DEFAULT;
- XDELETE (top);
+ pre_386_16bit_warned = false;
+ break;
}
+ if (cpu_flags_all_zero (&cpu_arch[j].enable))
+ continue;
+
+ isa_enable (j);
+
(void) restore_line_pointer (e);
- demand_empty_rest_of_line ();
- return;
- }
- for (; j < ARRAY_SIZE (cpu_arch); j++)
- {
- if (strcmp (string + (*string == '.'), cpu_arch[j].name) == 0
- && (*string == '.') == (cpu_arch[j].type == PROCESSOR_NONE))
+ switch (cpu_arch[j].vsz)
{
- if (*string != '.')
- {
- check_cpu_arch_compatible (string, cpu_arch[j].enable);
+ default:
+ break;
- cpu_arch_name = cpu_arch[j].name;
- free (cpu_sub_arch_name);
- cpu_sub_arch_name = NULL;
- cpu_arch_flags = cpu_arch[j].enable;
- if (flag_code == CODE_64BIT)
- {
- cpu_arch_flags.bitfield.cpu64 = 1;
- cpu_arch_flags.bitfield.cpuno64 = 0;
- }
- else
- {
- cpu_arch_flags.bitfield.cpu64 = 0;
- cpu_arch_flags.bitfield.cpuno64 = 1;
- }
- cpu_arch_isa = cpu_arch[j].type;
- cpu_arch_isa_flags = cpu_arch[j].enable;
- if (!cpu_arch_tune_set)
+ case vsz_set:
+#ifdef SVR4_COMMENT_CHARS
+ if (*input_line_pointer == ':' || *input_line_pointer == '/')
+#else
+ if (*input_line_pointer == '/')
+#endif
+ {
+ ++input_line_pointer;
+ switch (get_absolute_expression ())
{
- cpu_arch_tune = cpu_arch_isa;
- cpu_arch_tune_flags = cpu_arch_isa_flags;
+ case 512: vector_size = VSZ512; break;
+ case 256: vector_size = VSZ256; break;
+ case 128: vector_size = VSZ128; break;
+ default:
+ as_bad (_("Unrecognized vector size specifier"));
+ ignore_rest_of_line ();
+ return;
}
- pre_386_16bit_warned = false;
break;
}
-
- if (cpu_flags_all_zero (&cpu_arch[j].enable))
- continue;
-
- flags = cpu_flags_or (cpu_arch_flags,
- cpu_arch[j].enable);
-
- if (!cpu_flags_equal (&flags, &cpu_arch_flags))
- {
- extend_cpu_sub_arch_name (string + 1);
- cpu_arch_flags = flags;
- cpu_arch_isa_flags = flags;
- }
- else
- cpu_arch_isa_flags
- = cpu_flags_or (cpu_arch_isa_flags,
- cpu_arch[j].enable);
- (void) restore_line_pointer (e);
- demand_empty_rest_of_line ();
- return;
+ /* Fall through. */
+ case vsz_reset:
+ vector_size = VSZ_DEFAULT;
+ break;
}
- }
- if (startswith (string, ".no") && j >= ARRAY_SIZE (cpu_arch))
- {
- /* Disable an ISA extension. */
- for (j = 0; j < ARRAY_SIZE (cpu_arch); j++)
- if (cpu_arch[j].type == PROCESSOR_NONE
- && strcmp (string + 3, cpu_arch[j].name) == 0)
- {
- flags = cpu_flags_and_not (cpu_arch_flags,
- cpu_arch[j].disable);
- if (!cpu_flags_equal (&flags, &cpu_arch_flags))
- {
- extend_cpu_sub_arch_name (string + 1);
- cpu_arch_flags = flags;
- cpu_arch_isa_flags = flags;
- }
- (void) restore_line_pointer (e);
- demand_empty_rest_of_line ();
- return;
- }
+ demand_empty_rest_of_line ();
+ return;
}
+ }
+
+ if (startswith (string, ".no") && j >= ARRAY_SIZE (cpu_arch))
+ {
+ /* Disable an ISA extension. */
+ for (j = 0; j < ARRAY_SIZE (cpu_arch); j++)
+ if (cpu_arch[j].type == PROCESSOR_NONE
+ && strcmp (string + 3, cpu_arch[j].name) == 0)
+ {
+ isa_disable (j);
- if (j == ARRAY_SIZE (cpu_arch))
- as_bad (_("no such architecture: `%s'"), string);
+ if (cpu_arch[j].vsz == vsz_set)
+ vector_size = VSZ_DEFAULT;
- *input_line_pointer = e;
+ (void) restore_line_pointer (e);
+ demand_empty_rest_of_line ();
+ return;
+ }
}
- else
- as_bad (_("missing cpu architecture"));
+
+ if (j == ARRAY_SIZE (cpu_arch))
+ as_bad (_("no such architecture: `%s'"), string);
+
+ *input_line_pointer = e;
no_cond_jump_promotion = 0;
if (*input_line_pointer == ','
&& !is_end_of_line[(unsigned char) input_line_pointer[1]])
{
- char *string;
- char e;
-
++input_line_pointer;
- e = get_symbol_name (&string);
+ e = get_symbol_name (&s);
+ string = s;
if (strcmp (string, "nojumps") == 0)
no_cond_jump_promotion = 1;
/* Fill in lexical tables: mnemonic_chars, operand_chars. */
{
int c;
- char *p;
+ const char *p;
for (c = 0; c < 256; c++)
{
register_chars[c] = mnemonic_chars[c];
operand_chars[c] = c;
}
- else if (c == '{' || c == '}')
- {
- mnemonic_chars[c] = c;
- operand_chars[c] = c;
- }
#ifdef SVR4_COMMENT_CHARS
else if (c == '\\' && strchr (i386_comment_chars, '/'))
operand_chars[c] = c;
#endif
- if (ISALPHA (c) || ISDIGIT (c))
- identifier_chars[c] = c;
- else if (c >= 128)
- {
- identifier_chars[c] = c;
- operand_chars[c] = c;
- }
+ if (c >= 128)
+ operand_chars[c] = c;
}
-#ifdef LEX_AT
- identifier_chars['@'] = '@';
-#endif
-#ifdef LEX_QM
- identifier_chars['?'] = '?';
- operand_chars['?'] = '?';
-#endif
mnemonic_chars['_'] = '_';
mnemonic_chars['-'] = '-';
mnemonic_chars['.'] = '.';
- identifier_chars['_'] = '_';
- identifier_chars['.'] = '.';
+ for (p = extra_symbol_chars; *p != '\0'; p++)
+ operand_chars[(unsigned char) *p] = *p;
for (p = operand_special_chars; *p != '\0'; p++)
operand_chars[(unsigned char) *p] = *p;
}
fprintf (stdout, " %d operands ", t->operands);
if (opc_pfx[t->opcode_modifier.opcodeprefix])
fprintf (stdout, "pfx %x ", opc_pfx[t->opcode_modifier.opcodeprefix]);
- if (opc_spc[t->opcode_modifier.opcodespace])
- fprintf (stdout, "space %s ", opc_spc[t->opcode_modifier.opcodespace]);
+ if (opc_spc[t->opcode_space])
+ fprintf (stdout, "space %s ", opc_spc[t->opcode_space]);
fprintf (stdout, "opcode %x ", t->base_opcode);
if (t->extension_opcode != None)
fprintf (stdout, "ext %x ", t->extension_opcode);
{
return flag_code != CODE_64BIT
|| i.prefix[ADDR_PREFIX]
- || (t->base_opcode == 0x8d
- && t->opcode_modifier.opcodespace == SPACE_BASE
+ || (t->mnem_off == MN_lea
&& (!i.types[1].bitfield.qword
|| t->opcode_modifier.size == SIZE32));
}
i.tm = *t;
- /* Note that for pseudo prefixes this produces a length of 1. But for them
+ /* Dual VEX/EVEX templates need stripping one of the possible variants. */
+ if (t->opcode_modifier.vex && t->opcode_modifier.evex)
+ {
+ if ((is_cpu (t, CpuAVX) || is_cpu (t, CpuAVX2))
+ && is_cpu (t, CpuAVX512F))
+ {
+ if (need_evex_encoding ())
+ {
+ i.tm.opcode_modifier.vex = 0;
+ i.tm.cpu.bitfield.cpuavx = 0;
+ if (is_cpu (&i.tm, CpuAVX2))
+ i.tm.cpu.bitfield.isa = 0;
+ }
+ else
+ {
+ i.tm.opcode_modifier.evex = 0;
+ i.tm.cpu.bitfield.cpuavx512f = 0;
+ }
+ }
+ }
+
+ /* Note that for pseudo prefixes this produces a length of 1. But for them
the length isn't interesting at all. */
for (l = 1; l < 4; ++l)
if (!(t->base_opcode >> (8 * l)))
&& i.dir_encoding == dir_encoding_default
&& i.operands == i.reg_operands
&& operand_type_equal (&i.types[0], &i.types[i.operands - 1])
- && i.tm.opcode_modifier.opcodespace == SPACE_0F
+ && i.tm.opcode_space == SPACE_0F
&& (i.tm.opcode_modifier.load || i.tm.opcode_modifier.d)
&& i.rex == REX_B)
{
- unsigned int xchg = i.operands - 1;
- union i386_op temp_op;
- i386_operand_type temp_type;
+ unsigned int xchg;
- temp_type = i.types[xchg];
- i.types[xchg] = i.types[0];
- i.types[0] = temp_type;
- temp_op = i.op[xchg];
- i.op[xchg] = i.op[0];
- i.op[0] = temp_op;
+ swap_2_operands (0, i.operands - 1);
gas_assert (i.rm.mode == 3);
&& i.reg_operands == i.operands - i.imm_operands
&& i.tm.opcode_modifier.vex
&& i.tm.opcode_modifier.commutative
- && (i.tm.opcode_modifier.sse2avx || optimize > 1)
+ && (i.tm.opcode_modifier.sse2avx
+ || (optimize > 1 && !i.no_optimize))
&& i.rex == REX_B
&& i.vex.register_specifier
&& !(i.vex.register_specifier->reg_flags & RegRex))
{
unsigned int xchg = i.operands - i.reg_operands;
- union i386_op temp_op;
- i386_operand_type temp_type;
- gas_assert (i.tm.opcode_modifier.opcodespace == SPACE_0F);
+ gas_assert (i.tm.opcode_space == SPACE_0F);
gas_assert (!i.tm.opcode_modifier.sae);
gas_assert (operand_type_equal (&i.types[i.operands - 2],
&i.types[i.operands - 3]));
gas_assert (i.rm.mode == 3);
- temp_type = i.types[xchg];
- i.types[xchg] = i.types[xchg + 1];
- i.types[xchg + 1] = temp_type;
- temp_op = i.op[xchg];
- i.op[xchg] = i.op[xchg + 1];
- i.op[xchg + 1] = temp_op;
+ swap_2_operands (xchg, xchg + 1);
i.rex = 0;
xchg = i.rm.regmem | 8;
vector_length = avxscalar;
else if (i.tm.opcode_modifier.vex == VEX256)
vector_length = 1;
+ else if (dot_insn () && i.tm.opcode_modifier.vex == VEX128)
+ vector_length = 0;
else
{
unsigned int op;
/* Use 2-byte VEX prefix if possible. */
if (w == 0
&& i.vec_encoding != vex_encoding_vex3
- && i.tm.opcode_modifier.opcodespace == SPACE_0F
+ && i.tm.opcode_space == SPACE_0F
&& (i.rex & (REX_W | REX_X | REX_B)) == 0)
{
/* 2-byte VEX prefix. */
/* 3-byte VEX prefix. */
i.vex.length = 3;
- switch (i.tm.opcode_modifier.opcodespace)
+ switch (i.tm.opcode_space)
{
case SPACE_0F:
case SPACE_0F38:
/* The high 3 bits of the second VEX byte are 1's compliment
of RXB bits from REX. */
- i.vex.bytes[1] = (~i.rex & 0x7) << 5 | i.tm.opcode_modifier.opcodespace;
+ i.vex.bytes[1] = ((~i.rex & 7) << 5)
+ | (!dot_insn () ? i.tm.opcode_space
+ : i.insn_opcode_space);
i.vex.bytes[2] = (w << 7
| register_specifier << 3
const i386_operand_type *types;
if (i.broadcast.type)
- return i.broadcast.bytes = ((1 << (t->opcode_modifier.broadcast - 1))
- * i.broadcast.type);
+ return (1 << (t->opcode_modifier.broadcast - 1)) * i.broadcast.type;
gas_assert (intel_syntax);
/* The high 3 bits of the second EVEX byte are 1's compliment of RXB
bits from REX. */
- gas_assert (i.tm.opcode_modifier.opcodespace >= SPACE_0F);
- gas_assert (i.tm.opcode_modifier.opcodespace <= SPACE_EVEXMAP6);
- i.vex.bytes[1] = (~i.rex & 0x7) << 5 | i.tm.opcode_modifier.opcodespace;
+ gas_assert (i.tm.opcode_space >= SPACE_0F);
+ gas_assert (i.tm.opcode_space <= SPACE_EVEXMAP6);
+ i.vex.bytes[1] = ((~i.rex & 7) << 5)
+ | (!dot_insn () ? i.tm.opcode_space
+ : i.insn_opcode_space);
/* The fifth bit of the second EVEX byte is 1's compliment of the
REX_R bit in VREX. */
i.tm.opcode_modifier.evex = EVEX128;
break;
}
- else if (i.broadcast.bytes && op == i.broadcast.operand)
+ else if ((i.broadcast.type || i.broadcast.bytes)
+ && op == i.broadcast.operand)
{
switch (get_broadcast_bytes (&i.tm, true))
{
case EVEX512:
vec_length = 2 << 5;
break;
+ case EVEX_L3:
+ if (dot_insn ())
+ {
+ vec_length = 3 << 5;
+ break;
+ }
+ /* Fall through. */
default:
abort ();
break;
}
i.vex.bytes[3] |= vec_length;
/* Encode the broadcast bit. */
- if (i.broadcast.bytes)
+ if (i.broadcast.type || i.broadcast.bytes)
i.vex.bytes[3] |= 0x10;
}
else if (i.rounding.type != saeonly)
case 0x28: /* Load instructions. */
case 0x29: /* Store instructions. */
/* movaps/movapd/vmovaps/vmovapd. */
- if (i.tm.opcode_modifier.opcodespace == SPACE_0F
+ if (i.tm.opcode_space == SPACE_0F
&& i.tm.opcode_modifier.opcodeprefix <= PREFIX_0X66)
i.tm.base_opcode = 0x10 | (i.tm.base_opcode & 1);
break;
case 0x6f: /* Load instructions. */
case 0x7f: /* Store instructions. */
/* movdqa/vmovdqa/vmovdqa64/vmovdqa32. */
- if (i.tm.opcode_modifier.opcodespace == SPACE_0F
+ if (i.tm.opcode_space == SPACE_0F
&& i.tm.opcode_modifier.opcodeprefix == PREFIX_0X66)
i.tm.opcode_modifier.opcodeprefix = PREFIX_0XF3;
break;
{
unsigned int j;
- if (i.tm.opcode_modifier.opcodespace == SPACE_BASE
- && i.tm.base_opcode == 0x8d)
+ if (i.tm.mnem_off == MN_lea)
{
/* Optimize: -O:
lea symbol, %rN -> mov $symbol, %rN
{
if (flag_code != CODE_32BIT)
return;
- i.tm.opcode_modifier.opcodespace = SPACE_0F;
+ i.tm.opcode_space = SPACE_0F;
i.tm.base_opcode = 0xb7;
}
else
}
if (optimize_for_space
- && i.tm.opcode_modifier.opcodespace == SPACE_BASE
+ && i.tm.mnem_off == MN_test
&& i.reg_operands == 1
&& i.imm_operands == 1
&& !i.types[1].bitfield.byte
&& i.op[0].imms->X_op == O_constant
- && fits_in_imm7 (i.op[0].imms->X_add_number)
- && (i.tm.base_opcode == 0xa8
- || (i.tm.base_opcode == 0xf6
- && i.tm.extension_opcode == 0x0)))
+ && fits_in_imm7 (i.op[0].imms->X_add_number))
{
/* Optimize: -Os:
test $imm7, %r64/%r32/%r16 -> test $imm7, %r8
}
}
else if (flag_code == CODE_64BIT
- && i.tm.opcode_modifier.opcodespace == SPACE_BASE
+ && i.tm.opcode_space == SPACE_BASE
&& ((i.types[1].bitfield.qword
&& i.reg_operands == 1
&& i.imm_operands == 1
&& i.tm.extension_opcode == None
&& fits_in_unsigned_long (i.op[0].imms->X_add_number))
|| (fits_in_imm31 (i.op[0].imms->X_add_number)
- && ((i.tm.base_opcode == 0x24
- || i.tm.base_opcode == 0xa8)
+ && (i.tm.base_opcode == 0x24
|| (i.tm.base_opcode == 0x80
&& i.tm.extension_opcode == 0x4)
- || ((i.tm.base_opcode == 0xf6
- || (i.tm.base_opcode | 1) == 0xc7)
+ || i.tm.mnem_off == MN_test
+ || ((i.tm.base_opcode | 1) == 0xc7
&& i.tm.extension_opcode == 0x0)))
|| (fits_in_imm7 (i.op[0].imms->X_add_number)
&& i.tm.base_opcode == 0x83
|| (i.types[0].bitfield.qword
&& ((i.reg_operands == 2
&& i.op[0].regs == i.op[1].regs
- && (i.tm.base_opcode == 0x30
- || i.tm.base_opcode == 0x28))
- || (i.reg_operands == 1
- && i.operands == 1
- && i.tm.base_opcode == 0x30)))))
+ && (i.tm.mnem_off == MN_xor
+ || i.tm.mnem_off == MN_sub))
+ || i.tm.mnem_off == MN_clr))))
{
/* Optimize: -O:
andq $imm31, %r64 -> andl $imm31, %r32
}
i.types[1].bitfield.dword = 1;
i.types[1].bitfield.qword = 0;
- if (i.tm.base_opcode == 0xb8 || (i.tm.base_opcode | 1) == 0xc7)
+ if (i.tm.mnem_off == MN_mov || i.tm.mnem_off == MN_lea)
{
/* Handle
movq $imm31, %r64 -> movl $imm31, %r32
}
else if (optimize > 1
&& !optimize_for_space
- && i.tm.opcode_modifier.opcodespace == SPACE_BASE
&& i.reg_operands == 2
&& i.op[0].regs == i.op[1].regs
- && ((i.tm.base_opcode & ~(Opcode_D | 1)) == 0x8
- || (i.tm.base_opcode & ~(Opcode_D | 1)) == 0x20)
+ && (i.tm.mnem_off == MN_and || i.tm.mnem_off == MN_or)
&& (flag_code != CODE_64BIT || !i.types[0].bitfield.dword))
{
/* Optimize: -O2:
*/
i.tm.base_opcode = 0x84 | (i.tm.base_opcode & 1);
}
+ else if (i.tm.base_opcode == 0xba
+ && i.tm.opcode_space == SPACE_0F
+ && i.reg_operands == 1
+ && i.op[0].imms->X_op == O_constant
+ && i.op[0].imms->X_add_number >= 0)
+ {
+ /* Optimize: -O:
+ btw $n, %rN -> btl $n, %rN (outside of 16-bit mode, n < 16)
+ btq $n, %rN -> btl $n, %rN (in 64-bit mode, n < 32, N < 8)
+ btl $n, %rN -> btw $n, %rN (in 16-bit mode, n < 16)
+
+ With <BT> one of bts, btr, and bts also:
+ <BT>w $n, %rN -> btl $n, %rN (in 32-bit mode, n < 16)
+ <BT>l $n, %rN -> btw $n, %rN (in 16-bit mode, n < 16)
+ */
+ switch (flag_code)
+ {
+ case CODE_64BIT:
+ if (i.tm.extension_opcode != 4)
+ break;
+ if (i.types[1].bitfield.qword
+ && i.op[0].imms->X_add_number < 32
+ && !(i.op[1].regs->reg_flags & RegRex))
+ i.tm.opcode_modifier.size = SIZE32;
+ /* Fall through. */
+ case CODE_32BIT:
+ if (i.types[1].bitfield.word
+ && i.op[0].imms->X_add_number < 16)
+ i.tm.opcode_modifier.size = SIZE32;
+ break;
+ case CODE_16BIT:
+ if (i.op[0].imms->X_add_number < 16)
+ i.tm.opcode_modifier.size = SIZE16;
+ break;
+ }
+ }
else if (i.reg_operands == 3
&& i.op[0].regs == i.op[1].regs
&& !i.types[2].bitfield.xmmword
&& is_evex_encoding (&i.tm)
&& (i.vec_encoding != vex_encoding_evex
|| cpu_arch_isa_flags.bitfield.cpuavx512vl
- || i.tm.cpu_flags.bitfield.cpuavx512vl
+ || is_cpu (&i.tm, CpuAVX512VL)
|| (i.tm.operand_types[2].bitfield.zmmword
&& i.types[2].bitfield.ymmword))))
- && i.tm.opcode_modifier.opcodespace == SPACE_0F
+ && i.tm.opcode_space == SPACE_0F
&& ((i.tm.base_opcode | 2) == 0x57
|| i.tm.base_opcode == 0xdf
|| i.tm.base_opcode == 0xef
i.tm.opcode_modifier.vex = VEX128;
i.tm.opcode_modifier.vexw = VEXW0;
i.tm.opcode_modifier.evex = 0;
+ i.vec_encoding = vex_encoding_vex;
+ i.mask.reg = NULL;
}
else if (optimize > 1)
i.tm.opcode_modifier.evex = EVEX128;
&& !i.types[0].bitfield.zmmword
&& !i.types[1].bitfield.zmmword
&& !i.mask.reg
+ && !i.broadcast.type
&& !i.broadcast.bytes
&& is_evex_encoding (&i.tm)
&& ((i.tm.base_opcode & ~Opcode_SIMD_IntD) == 0x6f
i.types[j].bitfield.disp8
= fits_in_disp8 (i.op[j].disps->X_add_number);
}
+ else if (optimize_for_space
+ && i.tm.base_opcode == 0x29
+ && i.tm.opcode_space == SPACE_0F38
+ && i.operands == i.reg_operands
+ && i.op[0].regs == i.op[1].regs
+ && (!i.tm.opcode_modifier.vex
+ || !(i.op[0].regs->reg_flags & RegRex))
+ && !is_evex_encoding (&i.tm))
+ {
+ /* Optimize: -Os:
+ pcmpeqq %xmmN, %xmmN -> pcmpeqd %xmmN, %xmmN
+ vpcmpeqq %xmmN, %xmmN, %xmmM -> vpcmpeqd %xmmN, %xmmN, %xmmM (N < 8)
+ vpcmpeqq %ymmN, %ymmN, %ymmM -> vpcmpeqd %ymmN, %ymmN, %ymmM (N < 8)
+ */
+ i.tm.opcode_space = SPACE_0F;
+ i.tm.base_opcode = 0x76;
+ }
+ else if (((i.tm.base_opcode >= 0x64
+ && i.tm.base_opcode <= 0x66
+ && i.tm.opcode_space == SPACE_0F)
+ || (i.tm.base_opcode == 0x37
+ && i.tm.opcode_space == SPACE_0F38))
+ && i.operands == i.reg_operands
+ && i.op[0].regs == i.op[1].regs
+ && !is_evex_encoding (&i.tm))
+ {
+ /* Optimize: -O:
+ pcmpgt[bwd] %mmN, %mmN -> pxor %mmN, %mmN
+ pcmpgt[bwdq] %xmmN, %xmmN -> pxor %xmmN, %xmmN
+ vpcmpgt[bwdq] %xmmN, %xmmN, %xmmM -> vpxor %xmmN, %xmmN, %xmmM (N < 8)
+ vpcmpgt[bwdq] %xmmN, %xmmN, %xmmM -> vpxor %xmm0, %xmm0, %xmmM (N > 7)
+ vpcmpgt[bwdq] %ymmN, %ymmN, %ymmM -> vpxor %ymmN, %ymmN, %ymmM (N < 8)
+ vpcmpgt[bwdq] %ymmN, %ymmN, %ymmM -> vpxor %ymm0, %ymm0, %ymmM (N > 7)
+ */
+ i.tm.opcode_space = SPACE_0F;
+ i.tm.base_opcode = 0xef;
+ if (i.tm.opcode_modifier.vex && (i.op[0].regs->reg_flags & RegRex))
+ {
+ if (i.operands == 2)
+ {
+ gas_assert (i.tm.opcode_modifier.sse2avx);
+
+ i.operands = 3;
+ i.reg_operands = 3;
+ i.tm.operands = 3;
+
+ i.op[2].regs = i.op[0].regs;
+ i.types[2] = i.types[0];
+ i.flags[2] = i.flags[0];
+ i.tm.operand_types[2] = i.tm.operand_types[0];
+
+ i.tm.opcode_modifier.sse2avx = 0;
+ }
+ i.op[0].regs -= i.op[0].regs->reg_num + 8;
+ i.op[1].regs = i.op[0].regs;
+ }
+ }
+ else if (optimize_for_space
+ && i.tm.base_opcode == 0x59
+ && i.tm.opcode_space == SPACE_0F38
+ && i.operands == i.reg_operands
+ && i.tm.opcode_modifier.vex
+ && !(i.op[0].regs->reg_flags & RegRex)
+ && i.op[0].regs->reg_type.bitfield.xmmword
+ && i.vec_encoding != vex_encoding_vex3)
+ {
+ /* Optimize: -Os:
+ vpbroadcastq %xmmN, %xmmM -> vpunpcklqdq %xmmN, %xmmN, %xmmM (N < 8)
+ */
+ i.tm.opcode_space = SPACE_0F;
+ i.tm.base_opcode = 0x6c;
+ i.tm.opcode_modifier.vexvvvv = 1;
+
+ ++i.operands;
+ ++i.reg_operands;
+ ++i.tm.operands;
+
+ i.op[2].regs = i.op[0].regs;
+ i.types[2] = i.types[0];
+ i.flags[2] = i.flags[0];
+ i.tm.operand_types[2] = i.tm.operand_types[0];
+
+ swap_2_operands (1, 2);
+ }
}
/* Return non-zero for load instruction. */
return 1;
}
- if (i.tm.opcode_modifier.opcodespace == SPACE_BASE)
+ if (i.tm.opcode_space == SPACE_BASE)
{
/* popf, popa. */
if (i.tm.base_opcode == 0x9d
if (any_vex_p)
{
- /* vldmxcsr. */
- if (i.tm.base_opcode == 0xae
- && i.tm.opcode_modifier.vex
- && i.tm.opcode_modifier.opcodespace == SPACE_0F
- && i.tm.opcode_modifier.opcodeprefix == PREFIX_NONE
- && i.tm.extension_opcode == 2)
+ if (i.tm.mnem_off == MN_vldmxcsr)
return 1;
}
- else if (i.tm.opcode_modifier.opcodespace == SPACE_BASE)
+ else if (i.tm.opcode_space == SPACE_BASE)
{
/* test, not, neg, mul, imul, div, idiv. */
- if ((i.tm.base_opcode == 0xf6 || i.tm.base_opcode == 0xf7)
- && i.tm.extension_opcode != 1)
+ if (base_opcode == 0xf7 && i.tm.extension_opcode != 1)
return 1;
/* inc, dec. */
return 1;
/* rol, ror, rcl, rcr, shl/sal, shr, sar. */
- if ((base_opcode == 0xc1
- || (i.tm.base_opcode >= 0xd0 && i.tm.base_opcode <= 0xd3))
+ if ((base_opcode == 0xc1 || (base_opcode | 2) == 0xd3)
&& i.tm.extension_opcode != 6)
return 1;
/* Check for x87 instructions. */
- if (base_opcode >= 0xd8 && base_opcode <= 0xdf)
+ if ((base_opcode | 6) == 0xdf)
{
/* Skip fst, fstp, fstenv, fstcw. */
if (i.tm.base_opcode == 0xd9
return 1;
}
}
- else if (i.tm.opcode_modifier.opcodespace == SPACE_0F)
+ else if (i.tm.opcode_space == SPACE_0F)
{
/* bt, bts, btr, btc. */
if (i.tm.base_opcode == 0xba
- && (i.tm.extension_opcode >= 4 && i.tm.extension_opcode <= 7))
+ && (i.tm.extension_opcode | 3) == 7)
return 1;
/* cmpxchg8b, cmpxchg16b, xrstors, vmptrld. */
/* Check fake imm8 operand and 3 source operands. */
if ((i.tm.opcode_modifier.immext
- || i.tm.opcode_modifier.vexsources == VEX3SOURCES)
+ || i.reg_operands + i.mem_operands == 4)
&& i.types[dest].bitfield.imm8)
dest--;
/* add, or, adc, sbb, and, sub, xor, cmp, test, xchg. */
- if (i.tm.opcode_modifier.opcodespace == SPACE_BASE
- && (base_opcode == 0x1
- || base_opcode == 0x9
- || base_opcode == 0x11
- || base_opcode == 0x19
- || base_opcode == 0x21
- || base_opcode == 0x29
- || base_opcode == 0x31
- || base_opcode == 0x39
+ if (i.tm.opcode_space == SPACE_BASE
+ && ((base_opcode | 0x38) == 0x39
|| (base_opcode | 2) == 0x87))
return 1;
- /* xadd. */
- if (i.tm.opcode_modifier.opcodespace == SPACE_0F
- && base_opcode == 0xc1)
+ if (i.tm.mnem_off == MN_xadd)
return 1;
/* Check for load instruction. */
chosen by the adversary using an LVI method,
then this data-dependent behavior may leak some aspect
of the secret. */
- if (((i.tm.base_opcode | 0x1) == 0xa7
- || (i.tm.base_opcode | 0x1) == 0xaf)
+ if (((i.tm.base_opcode | 0x9) == 0xaf)
&& i.prefix[REP_PREFIX])
{
as_warn (_("`%s` changes flags which would affect control flow behavior"),
{
char *p;
- if (i.tm.opcode_modifier.opcodespace != SPACE_BASE)
+ if (i.tm.opcode_space != SPACE_BASE)
return;
if (i.tm.base_opcode == 0xff
/* Output or/not/shl and lfence before near ret. */
if (lfence_before_ret != lfence_before_ret_none
- && (i.tm.base_opcode == 0xc2
- || i.tm.base_opcode == 0xc3))
+ && (i.tm.base_opcode | 1) == 0xc3)
{
if (last_insn.kind != last_insn_other
&& last_insn.seg == now_seg)
}
}
+/* Shared helper for md_assemble() and s_insn(). */
+static void init_globals (void)
+{
+ unsigned int j;
+
+ memset (&i, '\0', sizeof (i));
+ i.rounding.type = rc_none;
+ for (j = 0; j < MAX_OPERANDS; j++)
+ i.reloc[j] = NO_RELOC;
+ memset (disp_expressions, '\0', sizeof (disp_expressions));
+ memset (im_expressions, '\0', sizeof (im_expressions));
+ save_stack_p = save_stack;
+}
+
/* Helper for md_assemble() to decide whether to prepare for a possible 2nd
parsing pass. Instead of introducing a rarely use new insn attribute this
utilizes a common pattern between affected templates. It is deemed
return t->opcode_modifier.sse2avx
/* Note that all SSE2AVX templates have at least one operand. */
? t->operand_types[t->operands - 1].bitfield.class == RegSIMD
- : (t->opcode_modifier.opcodespace == SPACE_0F
+ : (t->opcode_space == SPACE_0F
&& (t->base_opcode | 1) == 0xbf)
- || (t->opcode_modifier.opcodespace == SPACE_BASE
+ || (t->opcode_space == SPACE_BASE
&& t->base_opcode == 0x63);
}
/* Initialize globals. */
current_templates = NULL;
retry:
- memset (&i, '\0', sizeof (i));
- i.rounding.type = rc_none;
- for (j = 0; j < MAX_OPERANDS; j++)
- i.reloc[j] = NO_RELOC;
- memset (disp_expressions, '\0', sizeof (disp_expressions));
- memset (im_expressions, '\0', sizeof (im_expressions));
- save_stack_p = save_stack;
+ init_globals ();
/* First parse an instruction mnemonic & call i386_operand for the operands.
We assume that the scrubber has arranged it so that line[0] is the valid
start of a (possibly prefixed) mnemonic. */
- end = parse_insn (line, mnemonic);
+ end = parse_insn (line, mnemonic, false);
if (end == NULL)
{
if (pass1_mnem != NULL)
if (i.imm_operands)
optimize_imm ();
- if (i.disp_operands && !want_disp32 (t)
- && (!t->opcode_modifier.jump
- || i.jumpabsolute || i.types[0].bitfield.baseindex))
- {
- for (j = 0; j < i.operands; ++j)
- {
- const expressionS *exp = i.op[j].disps;
-
- if (!operand_type_check (i.types[j], disp))
- continue;
-
- if (exp->X_op != O_constant)
- continue;
-
- /* Since displacement is signed extended to 64bit, don't allow
- disp32 if it is out of range. */
- if (fits_in_signed_long (exp->X_add_number))
- continue;
-
- i.types[j].bitfield.disp32 = 0;
- if (i.types[j].bitfield.baseindex)
- {
- as_bad (_("0x%" PRIx64 " out of range of signed 32bit displacement"),
- (uint64_t) exp->X_add_number);
- return;
- }
- }
- }
-
- /* Don't optimize displacement for movabs since it only takes 64bit
- displacement. */
- if (i.disp_operands
- && i.disp_encoding <= disp_encoding_8bit
- && (flag_code != CODE_64BIT
- || strcmp (mnemonic, "movabs") != 0))
- optimize_disp ();
+ if (i.disp_operands && !optimize_disp (t))
+ return;
/* Next, we find a template that matches the given insn,
making sure the overlap of the given operands types is consistent
case invalid_register_operand:
err_msg = _("invalid register operand");
break;
+ case internal_error:
+ err_msg = _("internal error");
+ break;
}
as_bad (_("%s for `%s'"), err_msg,
pass1_mnem ? pass1_mnem : insn_name (current_templates->start));
if (sse_check != check_none
/* The opcode space check isn't strictly needed; it's there only to
bypass the logic below when easily possible. */
- && t->opcode_modifier.opcodespace >= SPACE_0F
- && t->opcode_modifier.opcodespace <= SPACE_0F3A
- && !i.tm.cpu_flags.bitfield.cpusse4a
+ && t->opcode_space >= SPACE_0F
+ && t->opcode_space <= SPACE_0F3A
+ && !is_cpu (&i.tm, CpuSSE4a)
&& !is_any_vex_encoding (t))
{
bool simd = false;
/* Check for lock without a lockable instruction. Destination operand
must be memory unless it is xchg (0x86). */
- if (i.prefix[LOCK_PREFIX]
- && (i.tm.opcode_modifier.prefixok < PrefixLock
+ if (i.prefix[LOCK_PREFIX])
+ {
+ if (i.tm.opcode_modifier.prefixok < PrefixLock
|| i.mem_operands == 0
|| (i.tm.base_opcode != 0x86
- && !(i.flags[i.operands - 1] & Operand_Mem))))
- {
- as_bad (_("expecting lockable instruction after `lock'"));
- return;
+ && !(i.flags[i.operands - 1] & Operand_Mem)))
+ {
+ as_bad (_("expecting lockable instruction after `lock'"));
+ return;
+ }
+
+ /* Zap the redundant prefix from XCHG when optimizing. */
+ if (i.tm.base_opcode == 0x86 && optimize && !i.no_optimize)
+ i.prefix[LOCK_PREFIX] = 0;
}
if (is_any_vex_encoding (&i.tm)
if (i.notrack_prefix && i.tm.opcode_modifier.prefixok != PrefixNoTrack)
as_bad (_("expecting indirect branch instruction after `notrack'"));
- if (i.tm.cpu_flags.bitfield.cpumpx)
+ if (is_cpu (&i.tm, CpuMPX))
{
if (flag_code == CODE_64BIT && i.prefix[ADDR_PREFIX])
as_bad (_("32-bit address isn't allowed in 64-bit MPX instructions."));
instructions (base opcodes: 0x6c, 0x6e, 0xec, 0xee). */
if (i.input_output_operand
&& ((i.tm.base_opcode | 0x82) != 0xee
- || i.tm.opcode_modifier.opcodespace != SPACE_BASE))
+ || i.tm.opcode_space != SPACE_BASE))
{
as_bad (_("input/output port address isn't allowed with `%s'"),
insn_name (&i.tm));
if (optimize && !i.no_optimize && i.tm.opcode_modifier.optimize)
optimize_encoding ();
+ /* Past optimization there's no need to distinguish vex_encoding_evex and
+ vex_encoding_evex512 anymore. */
+ if (i.vec_encoding == vex_encoding_evex512)
+ i.vec_encoding = vex_encoding_evex;
+
if (use_unaligned_vector_move)
encode_with_unaligned_vector_move ();
return;
/* Check if IP-relative addressing requirements can be satisfied. */
- if (i.tm.cpu_flags.bitfield.cpuprefetchi
+ if (is_cpu (&i.tm, CpuPREFETCHI)
&& !(i.base_reg && i.base_reg->reg_num == RegIP))
as_warn (_("'%s' only supports RIP-relative address"), insn_name (&i.tm));
case RegSIMD:
if (i.tm.operand_types[j].bitfield.tmmword)
i.xstate |= xstate_tmm;
- else if (i.tm.operand_types[j].bitfield.zmmword)
+ else if (i.tm.operand_types[j].bitfield.zmmword
+ && !i.tm.opcode_modifier.vex
+ && vector_size >= VSZ512)
i.xstate |= xstate_zmm;
- else if (i.tm.operand_types[j].bitfield.ymmword)
+ else if (i.tm.operand_types[j].bitfield.ymmword
+ && vector_size >= VSZ256)
i.xstate |= xstate_ymm;
else if (i.tm.operand_types[j].bitfield.xmmword)
i.xstate |= xstate_xmm;
i.rex &= REX_OPCODE;
}
- /* Handle conversion of 'int $3' --> special int3 insn. XOP or FMA4
- instructions may define INT_OPCODE as well, so avoid this corner
- case for those instructions that use MODRM. */
- if (i.tm.opcode_modifier.opcodespace == SPACE_BASE
- && i.tm.base_opcode == INT_OPCODE
- && !i.tm.opcode_modifier.modrm
+ /* Handle conversion of 'int $3' --> special int3 insn. */
+ if (i.tm.mnem_off == MN_int
&& i.op[0].imms->X_add_number == 3)
{
i.tm.base_opcode = INT3_OPCODE;
static INLINE bool q_suffix_allowed(const insn_template *t)
{
return flag_code == CODE_64BIT
- || (t->opcode_modifier.opcodespace == SPACE_BASE
+ || (t->opcode_space == SPACE_BASE
&& t->base_opcode == 0xdf
&& (t->extension_opcode & 1)) /* fild / fistp / fisttp */
- || (t->opcode_modifier.opcodespace == SPACE_0F
- && t->base_opcode == 0xc7
- && t->opcode_modifier.opcodeprefix == PREFIX_NONE
- && t->extension_opcode == 1) /* cmpxchg8b */;
+ || t->mnem_off == MN_cmpxchg8b;
}
static const char *
-parse_insn (const char *line, char *mnemonic)
+parse_insn (const char *line, char *mnemonic, bool prefix_only)
{
const char *l = line, *token_start = l;
char *mnem_p;
while (1)
{
mnem_p = mnemonic;
+ /* Pseudo-prefixes start with an opening figure brace. */
+ if ((*mnem_p = *l) == '{')
+ {
+ ++mnem_p;
+ ++l;
+ }
while ((*mnem_p = mnemonic_chars[(unsigned char) *l]) != 0)
{
if (*mnem_p == '.')
mnem_p++;
if (mnem_p >= mnemonic + MAX_MNEM_SIZE)
{
+ too_long:
as_bad (_("no such instruction: `%s'"), token_start);
return NULL;
}
l++;
}
- if (!is_space_char (*l)
- && *l != END_OF_INSN
- && (intel_syntax
- || (*l != PREFIX_SEPARATOR
- && *l != ',')))
+ /* Pseudo-prefixes end with a closing figure brace. */
+ if (*mnemonic == '{' && *l == '}')
+ {
+ *mnem_p++ = *l++;
+ if (mnem_p >= mnemonic + MAX_MNEM_SIZE)
+ goto too_long;
+ *mnem_p = '\0';
+
+ /* Point l at the closing brace if there's no other separator. */
+ if (*l != END_OF_INSN && !is_space_char (*l)
+ && *l != PREFIX_SEPARATOR)
+ --l;
+ }
+ else if (!is_space_char (*l)
+ && *l != END_OF_INSN
+ && (intel_syntax
+ || (*l != PREFIX_SEPARATOR && *l != ',')))
{
+ if (prefix_only)
+ break;
as_bad (_("invalid character %s in mnemonic"),
output_invalid (*l));
return NULL;
&& current_templates
&& current_templates->start->opcode_modifier.isprefix)
{
- if (!cpu_flags_check_cpu64 (current_templates->start->cpu_flags))
+ if (!cpu_flags_check_cpu64 (current_templates->start))
{
as_bad ((flag_code != CODE_64BIT
? _("`%s' is only supported in 64-bit mode")
case PREFIX_EXIST:
return NULL;
case PREFIX_DS:
- if (current_templates->start->cpu_flags.bitfield.cpuibt)
+ if (is_cpu (current_templates->start, CpuIBT))
i.notrack_prefix = insn_name (current_templates->start);
break;
case PREFIX_REP:
- if (current_templates->start->cpu_flags.bitfield.cpuhle)
+ if (is_cpu (current_templates->start, CpuHLE))
i.hle_prefix = insn_name (current_templates->start);
- else if (current_templates->start->cpu_flags.bitfield.cpumpx)
+ else if (is_cpu (current_templates->start, CpuMPX))
i.bnd_prefix = insn_name (current_templates->start);
else
i.rep_prefix = insn_name (current_templates->start);
break;
}
+ if (prefix_only)
+ return token_start;
+
if (!current_templates)
{
/* Deprecated functionality (new code should use pseudo-prefixes instead):
if (current_templates != NULL
/* MOVS or CMPS */
&& (current_templates->start->base_opcode | 2) == 0xa6
- && current_templates->start->opcode_modifier.opcodespace
+ && current_templates->start->opcode_space
== SPACE_BASE
&& mnem_p[-2] == 's')
{
i.reloc[xchg2] = i.reloc[xchg1];
i.reloc[xchg1] = temp_reloc;
+ temp_flags = i.imm_bits[xchg2];
+ i.imm_bits[xchg2] = i.imm_bits[xchg1];
+ i.imm_bits[xchg1] = temp_flags;
+
if (i.mask.reg)
{
if (i.mask.operand == xchg1)
break;
}
}
- else if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0))
+ else if ((flag_code == CODE_16BIT)
+ ^ (i.prefix[DATA_PREFIX] != 0 && !(i.prefix[REX_PREFIX] & REX_W)))
guess_suffix = WORD_MNEM_SUFFIX;
+ else if (flag_code != CODE_64BIT
+ || (!(i.prefix[REX_PREFIX] & REX_W)
+ /* A more generic (but also more involved) way of dealing
+ with the special case(s) would be to go look for
+ DefaultSize attributes on any of the templates. */
+ && current_templates->start->mnem_off != MN_push))
+ guess_suffix = LONG_MNEM_SUFFIX;
for (op = i.operands; --op >= 0;)
if (operand_type_check (i.types[op], imm))
}
/* Try to use the smallest displacement type too. */
-static void
-optimize_disp (void)
+static bool
+optimize_disp (const insn_template *t)
{
- int op;
+ unsigned int op;
- for (op = i.operands; --op >= 0;)
+ if (!want_disp32 (t)
+ && (!t->opcode_modifier.jump
+ || i.jumpabsolute || i.types[0].bitfield.baseindex))
+ {
+ for (op = 0; op < i.operands; ++op)
+ {
+ const expressionS *exp = i.op[op].disps;
+
+ if (!operand_type_check (i.types[op], disp))
+ continue;
+
+ if (exp->X_op != O_constant)
+ continue;
+
+ /* Since displacement is signed extended to 64bit, don't allow
+ disp32 if it is out of range. */
+ if (fits_in_signed_long (exp->X_add_number))
+ continue;
+
+ i.types[op].bitfield.disp32 = 0;
+ if (i.types[op].bitfield.baseindex)
+ {
+ as_bad (_("0x%" PRIx64 " out of range of signed 32bit displacement"),
+ (uint64_t) exp->X_add_number);
+ return false;
+ }
+ }
+ }
+
+ /* Don't optimize displacement for movabs since it only takes 64bit
+ displacement. */
+ if (i.disp_encoding > disp_encoding_8bit
+ || (flag_code == CODE_64BIT && t->mnem_off == MN_movabs))
+ return true;
+
+ for (op = i.operands; op-- > 0;)
if (operand_type_check (i.types[op], disp))
{
if (i.op[op].disps->X_op == O_constant)
/* Optimize 64-bit displacement to 32-bit for 64-bit BFD. */
if ((flag_code != CODE_64BIT
? i.types[op].bitfield.disp32
- : want_disp32 (current_templates->start)
- && (!current_templates->start->opcode_modifier.jump
+ : want_disp32 (t)
+ && (!t->opcode_modifier.jump
|| i.jumpabsolute || i.types[op].bitfield.baseindex))
&& fits_in_unsigned_long (op_disp))
{
/* We only support 64bit displacement on constants. */
i.types[op].bitfield.disp64 = 0;
}
+
+ return true;
}
/* Return 1 if there is a match in broadcast bytes between operand
operand size is YMMword or XMMword. Since this function runs after
template matching, there's no need to check for YMMword/XMMword in
the template. */
- cpu = cpu_flags_and (t->cpu_flags, avx512);
+ cpu = cpu_flags_and (cpu_flags_from_attr (t->cpu), avx512);
if (!cpu_flags_all_zero (&cpu)
- && !t->cpu_flags.bitfield.cpuavx512vl
- && !cpu_arch_flags.bitfield.cpuavx512vl)
+ && !is_cpu (t, CpuAVX512VL)
+ && !cpu_arch_flags.bitfield.cpuavx512vl
+ && (!t->opcode_modifier.vex || need_evex_encoding ()))
{
for (op = 0; op < t->operands; ++op)
{
/* Somewhat similarly, templates specifying both AVX and AVX2 are
requiring AVX2 support if the actual operand size is YMMword. */
- if (t->cpu_flags.bitfield.cpuavx
- && t->cpu_flags.bitfield.cpuavx2
+ if (is_cpu (t, CpuAVX) && is_cpu (t, CpuAVX2)
&& !cpu_arch_flags.bitfield.cpuavx2)
{
for (op = 0; op < t->operands; ++op)
return 1;
}
- if (i.broadcast.type)
- i.broadcast.bytes = ((1 << (t->opcode_modifier.broadcast - 1))
- * i.broadcast.type);
operand_type_set (&type, 0);
switch (get_broadcast_bytes (t, false))
{
type.bitfield.xmmword = 1;
break;
case 32:
+ if (vector_size < VSZ256)
+ goto bad_broadcast;
type.bitfield.ymmword = 1;
break;
case 64:
+ if (vector_size < VSZ512)
+ goto bad_broadcast;
type.bitfield.zmmword = 1;
break;
default:
/* Check if requested masking is supported. */
if (i.mask.reg)
{
- switch (t->opcode_modifier.masking)
+ if (!t->opcode_modifier.masking)
{
- case BOTH_MASKING:
- break;
- case MERGING_MASKING:
- if (i.mask.zeroing)
- {
- case 0:
- i.error = unsupported_masking;
- return 1;
- }
- break;
- case DYNAMIC_MASKING:
- /* Memory destinations allow only merging masking. */
- if (i.mask.zeroing && i.mem_operands)
- {
- /* Find memory operand. */
- for (op = 0; op < i.operands; op++)
- if (i.flags[op] & Operand_Mem)
- break;
- gas_assert (op < i.operands);
- if (op == i.operands - 1)
- {
- i.error = unsupported_masking;
- return 1;
- }
- }
- break;
- default:
- abort ();
+ i.error = unsupported_masking;
+ return 1;
+ }
+
+ /* Common rules for masking:
+ - mask register destinations permit only zeroing-masking, without
+ that actually being expressed by a {z} operand suffix or EVEX.z,
+ - memory destinations allow only merging-masking,
+ - scatter/gather insns (i.e. ones using vSIB) only allow merging-
+ masking. */
+ if (i.mask.zeroing
+ && (t->operand_types[t->operands - 1].bitfield.class == RegMask
+ || (i.flags[t->operands - 1] & Operand_Mem)
+ || t->opcode_modifier.sib))
+ {
+ i.error = unsupported_masking;
+ return 1;
}
}
}
/* Check the special Imm4 cases; must be the first operand. */
- if (t->cpu_flags.bitfield.cpuxop && t->operands == 5)
+ if (is_cpu (t, CpuXOP) && t->operands == 5)
{
if (i.op[0].imms->X_op != O_constant
|| !fits_in_imm4 (i.op[0].imms->X_add_number))
/* Check vector Disp8 operand. */
if (t->opcode_modifier.disp8memshift
+ && (!t->opcode_modifier.vex
+ || need_evex_encoding ())
&& i.disp_encoding <= disp_encoding_8bit)
{
- if (i.broadcast.bytes)
+ if (i.broadcast.type || i.broadcast.bytes)
i.memshift = t->opcode_modifier.broadcast - 1;
else if (t->opcode_modifier.disp8memshift != DISP8_SHIFT_VL)
i.memshift = t->opcode_modifier.disp8memshift;
return 1;
}
- if (i.vec_encoding == vex_encoding_evex)
+ /* Vector size restrictions. */
+ if ((vector_size < VSZ512
+ && (t->opcode_modifier.evex == EVEX512
+ || t->opcode_modifier.vsz >= VSZ512))
+ || (vector_size < VSZ256
+ && (t->opcode_modifier.evex == EVEX256
+ || t->opcode_modifier.vex == VEX256
+ || t->opcode_modifier.vsz >= VSZ256)))
+ {
+ i.error = unsupported;
+ return 1;
+ }
+
+ if (i.vec_encoding == vex_encoding_evex
+ || i.vec_encoding == vex_encoding_evex512)
{
/* This instruction must be encoded with EVEX prefix. */
if (!is_evex_encoding (t))
case 1:
if (!operand_type_match (overlap0, i.types[0]))
continue;
+
+ /* Allow the ModR/M encoding to be requested by using the {load} or
+ {store} pseudo prefix on an applicable insn. */
+ if (!t->opcode_modifier.modrm
+ && i.reg_operands == 1
+ && ((i.dir_encoding == dir_encoding_load
+ && t->mnem_off != MN_pop)
+ || (i.dir_encoding == dir_encoding_store
+ && t->mnem_off != MN_push))
+ /* Avoid BSWAP. */
+ && t->mnem_off != MN_bswap)
+ continue;
break;
+
case 2:
/* xchg %eax, %eax is a special case. It is an alias for nop
only in 32bit mode and we can use opcode 0x90. In 64bit
mode, we can't use 0x90 for xchg %eax, %eax since it should
zero-extend %eax to %rax. */
- if (flag_code == CODE_64BIT
- && t->base_opcode == 0x90
- && t->opcode_modifier.opcodespace == SPACE_BASE
- && i.types[0].bitfield.instance == Accum
- && i.types[0].bitfield.dword
- && i.types[1].bitfield.instance == Accum)
- continue;
+ if (t->base_opcode == 0x90
+ && t->opcode_space == SPACE_BASE)
+ {
+ if (flag_code == CODE_64BIT
+ && i.types[0].bitfield.instance == Accum
+ && i.types[0].bitfield.dword
+ && i.types[1].bitfield.instance == Accum)
+ continue;
+
+ /* Allow the ModR/M encoding to be requested by using the
+ {load} or {store} pseudo prefix. */
+ if (i.dir_encoding == dir_encoding_load
+ || i.dir_encoding == dir_encoding_store)
+ continue;
+ }
if (t->base_opcode == MOV_AX_DISP32
- && t->opcode_modifier.opcodespace == SPACE_BASE)
+ && t->opcode_space == SPACE_BASE
+ && t->mnem_off != MN_movabs)
{
/* Force 0x8b encoding for "mov foo@GOT, %eax". */
if (i.reloc[0] == BFD_RELOC_386_GOT32)
match the accumulator-only encoding of mov. */
if (i.hle_prefix)
continue;
+
+ /* Allow the ModR/M encoding to be requested by using a suitable
+ {load} or {store} pseudo prefix. */
+ if (i.dir_encoding == (i.types[0].bitfield.instance == Accum
+ ? dir_encoding_store
+ : dir_encoding_load)
+ && !i.types[0].bitfield.disp64
+ && !i.types[1].bitfield.disp64)
+ continue;
+ }
+
+ /* Allow the ModR/M encoding to be requested by using the {load} or
+ {store} pseudo prefix on an applicable insn. */
+ if (!t->opcode_modifier.modrm
+ && i.reg_operands == 1
+ && i.imm_operands == 1
+ && (i.dir_encoding == dir_encoding_load
+ || i.dir_encoding == dir_encoding_store)
+ && t->opcode_space == SPACE_BASE)
+ {
+ if (t->base_opcode == 0xb0 /* mov $imm, %reg */
+ && i.dir_encoding == dir_encoding_store)
+ continue;
+
+ if ((t->base_opcode | 0x38) == 0x3c /* <alu> $imm, %acc */
+ && (t->base_opcode != 0x3c /* cmp $imm, %acc */
+ || i.dir_encoding == dir_encoding_load))
+ continue;
+
+ if (t->base_opcode == 0xa8 /* test $imm, %acc */
+ && i.dir_encoding == dir_encoding_load)
+ continue;
}
/* Fall through. */
if (!(size_match & MATCH_REVERSE))
continue;
/* Try reversing direction of operands. */
- j = t->opcode_modifier.vexsources ? 1 : i.operands - 1;
+ j = is_cpu (t, CpuFMA4)
+ || is_cpu (t, CpuXOP) ? 1 : i.operands - 1;
overlap0 = operand_type_and (i.types[0], operand_types[j]);
overlap1 = operand_type_and (i.types[j], operand_types[0]);
overlap2 = operand_type_and (i.types[1], operand_types[1]);
&& (intel_syntax || intel_mnemonic))
found_reverse_match |= Opcode_FloatR;
}
- else if (t->opcode_modifier.vexsources)
+ else if (is_cpu (t, CpuFMA4) || is_cpu (t, CpuXOP))
{
found_reverse_match = Opcode_VexW;
goto check_operands_345;
}
- else if (t->opcode_modifier.opcodespace != SPACE_BASE
- && (t->opcode_modifier.opcodespace != SPACE_0F
+ else if (t->opcode_space != SPACE_BASE
+ && (t->opcode_space != SPACE_0F
/* MOV to/from CR/DR/TR, as an exception, follow
the base opcode space encoding model. */
|| (t->base_opcode | 7) != 0x27))
continue;
}
+ /* Check whether to use the shorter VEX encoding for certain insns where
+ the EVEX enconding comes first in the table. This requires the respective
+ AVX-* feature to be explicitly enabled. */
+ if (t == current_templates->start
+ && t->opcode_modifier.disp8memshift
+ && !t->opcode_modifier.vex
+ && !need_evex_encoding ()
+ && t + 1 < current_templates->end
+ && t[1].opcode_modifier.vex)
+ {
+ i386_cpu_flags cpu;
+ unsigned int memshift = i.memshift;
+
+ i.memshift = 0;
+ cpu = cpu_flags_and (cpu_flags_from_attr (t[1].cpu), cpu_arch_isa_flags);
+ if (!cpu_flags_all_zero (&cpu)
+ && (!i.types[0].bitfield.disp8
+ || !operand_type_check (i.types[0], disp)
+ || i.op[0].disps->X_op != O_constant
+ || fits_in_disp8 (i.op[0].disps->X_add_number)))
+ {
+ specific_error = progress (internal_error);
+ continue;
+ }
+ i.memshift = memshift;
+ }
+
/* We've found a match; break out of loop. */
break;
}
static int
process_suffix (void)
{
- bool is_crc32 = false, is_movx = false;
+ bool is_movx = false;
/* If matched instruction specifies an explicit instruction mnemonic
suffix, use it. */
unsigned int numop = i.operands;
/* MOVSX/MOVZX */
- is_movx = (i.tm.opcode_modifier.opcodespace == SPACE_0F
+ is_movx = (i.tm.opcode_space == SPACE_0F
&& (i.tm.base_opcode | 8) == 0xbe)
- || (i.tm.opcode_modifier.opcodespace == SPACE_BASE
+ || (i.tm.opcode_space == SPACE_BASE
&& i.tm.base_opcode == 0x63
- && i.tm.cpu_flags.bitfield.cpu64);
-
- /* CRC32 */
- is_crc32 = (i.tm.base_opcode == 0xf0
- && i.tm.opcode_modifier.opcodespace == SPACE_0F38
- && i.tm.opcode_modifier.opcodeprefix == PREFIX_0XF2);
+ && is_cpu (&i.tm, Cpu64));
/* movsx/movzx want only their source operand considered here, for the
ambiguity checking below. The suffix will be replaced afterwards
--i.operands;
/* crc32 needs REX.W set regardless of suffix / source operand size. */
- if (is_crc32 && i.tm.operand_types[1].bitfield.qword)
+ if (i.tm.mnem_off == MN_crc32 && i.tm.operand_types[1].bitfield.qword)
i.rex |= REX_W;
/* If there's no instruction mnemonic suffix we try to invent one
Destination register type is more significant than source
register type. crc32 in SSE4.2 prefers source register
type. */
- unsigned int op = is_crc32 ? 1 : i.operands;
+ unsigned int op = i.tm.mnem_off == MN_crc32 ? 1 : i.operands;
while (op--)
if (i.tm.operand_types[op].bitfield.instance == InstanceNone
&& (i.tm.opcode_modifier.jump == JUMP_ABSOLUTE
|| i.tm.opcode_modifier.jump == JUMP_BYTE
|| i.tm.opcode_modifier.jump == JUMP_INTERSEGMENT
- || (i.tm.opcode_modifier.opcodespace == SPACE_0F
+ || (i.tm.opcode_space == SPACE_0F
&& i.tm.base_opcode == 0x01 /* [ls][gi]dt */
&& i.tm.extension_opcode <= 3)))
{
for (op = 0; op < i.tm.operands; ++op)
{
- if (is_evex_encoding (&i.tm)
- && !cpu_arch_flags.bitfield.cpuavx512vl)
+ if (vector_size < VSZ512)
+ {
+ i.tm.operand_types[op].bitfield.zmmword = 0;
+ if (vector_size < VSZ256)
+ {
+ i.tm.operand_types[op].bitfield.ymmword = 0;
+ if (i.tm.operand_types[op].bitfield.xmmword
+ && (i.tm.opcode_modifier.evex == EVEXDYN
+ || (!i.tm.opcode_modifier.evex
+ && is_evex_encoding (&i.tm))))
+ i.tm.opcode_modifier.evex = EVEX128;
+ }
+ else if (i.tm.operand_types[op].bitfield.ymmword
+ && !i.tm.operand_types[op].bitfield.xmmword
+ && (i.tm.opcode_modifier.evex == EVEXDYN
+ || (!i.tm.opcode_modifier.evex
+ && is_evex_encoding (&i.tm))))
+ i.tm.opcode_modifier.evex = EVEX256;
+ }
+ else if (is_evex_encoding (&i.tm)
+ && !cpu_arch_flags.bitfield.cpuavx512vl)
{
if (i.tm.operand_types[op].bitfield.ymmword)
i.tm.operand_types[op].bitfield.xmmword = 0;
need rex64. */
&& ! (i.operands == 2
&& i.tm.base_opcode == 0x90
- && i.tm.opcode_modifier.opcodespace == SPACE_BASE
+ && i.tm.opcode_space == SPACE_BASE
&& i.types[0].bitfield.instance == Accum
&& i.types[0].bitfield.qword
&& i.types[1].bitfield.instance == Accum))
/* InOutPortReg */
|| i.tm.operand_types[0].bitfield.instance == RegD
|| i.tm.operand_types[1].bitfield.instance == RegD
- /* CRC32 */
- || is_crc32))))
+ || i.tm.mnem_off == MN_crc32))))
i.tm.base_opcode |= 1;
break;
}
continue;
/* crc32 only wants its source operand checked here. */
- if (i.tm.base_opcode == 0xf0
- && i.tm.opcode_modifier.opcodespace == SPACE_0F38
- && i.tm.opcode_modifier.opcodeprefix == PREFIX_0XF2
- && op != 0)
+ if (i.tm.mnem_off == MN_crc32 && op != 0)
continue;
/* Any other register is bad. */
update_imm (unsigned int j)
{
i386_operand_type overlap = i.types[j];
+
+ if (i.tm.operand_types[j].bitfield.imm8
+ && i.tm.operand_types[j].bitfield.imm8s
+ && overlap.bitfield.imm8 && overlap.bitfield.imm8s)
+ {
+ /* This combination is used on 8-bit immediates where e.g. $~0 is
+ desirable to permit. We're past operand type matching, so simply
+ put things back in the shape they were before introducing the
+ distinction between Imm8, Imm8S, and Imm8|Imm8S. */
+ overlap.bitfield.imm8s = 0;
+ }
+
if (overlap.bitfield.imm8
+ overlap.bitfield.imm8s
+ overlap.bitfield.imm16
|| operand_type_equal (&overlap, &imm16_32)
|| operand_type_equal (&overlap, &imm16_32s))
{
- if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0))
+ if ((flag_code == CODE_16BIT)
+ ^ (i.prefix[DATA_PREFIX] != 0 && !(i.prefix[REX_PREFIX] & REX_W)))
overlap = imm16;
else
overlap = imm32s;
return 1;
}
+static INLINE void set_rex_vrex (const reg_entry *r, unsigned int rex_bit,
+ bool do_sse2avx)
+{
+ if (r->reg_flags & RegRex)
+ {
+ if (i.rex & rex_bit)
+ as_bad (_("same type of prefix used twice"));
+ i.rex |= rex_bit;
+ }
+ else if (do_sse2avx && (i.rex & rex_bit) && i.vex.register_specifier)
+ {
+ gas_assert (i.vex.register_specifier == r);
+ i.vex.register_specifier += 8;
+ }
+
+ if (r->reg_flags & RegVRex)
+ i.vrex |= rex_bit;
+}
+
static int
process_operands (void)
{
else if (i.tm.opcode_modifier.immext)
process_immext ();
+ /* TILEZERO is unusual in that it has a single operand encoded in ModR/M.reg,
+ not ModR/M.rm. To avoid special casing this in build_modrm_byte(), fake a
+ new destination operand here, while converting the source one to register
+ number 0. */
+ if (i.tm.mnem_off == MN_tilezero)
+ {
+ i.op[1].regs = i.op[0].regs;
+ i.op[0].regs -= i.op[0].regs->reg_num;
+ i.types[1] = i.types[0];
+ i.tm.operand_types[1] = i.tm.operand_types[0];
+ i.flags[1] = i.flags[0];
+ i.operands++;
+ i.reg_operands++;
+ i.tm.operands++;
+ }
+
if (i.tm.opcode_modifier.sse2avx && i.tm.opcode_modifier.vexvvvv)
{
static const i386_operand_type regxmm = {
if (i.tm.operand_types[0].bitfield.instance == Accum
&& i.tm.operand_types[0].bitfield.xmmword)
{
- gas_assert (i.tm.opcode_modifier.vexsources == VEX3SOURCES);
/* Keep xmm0 for instructions with VEX prefix and 3
sources. */
i.tm.operand_types[0].bitfield.instance = InstanceNone;
if (i.tm.opcode_modifier.operandconstraint == IMPLICIT_1ST_XMM0)
{
- gas_assert ((MAX_OPERANDS - 1) > dupl
- && (i.tm.opcode_modifier.vexsources
- == VEX3SOURCES));
+ gas_assert ((MAX_OPERANDS - 1) > dupl);
/* Add the implicit xmm0 for instructions with VEX prefix
and 3 sources. */
}
}
}
- else if (i.types[0].bitfield.class == SReg)
+ else if (i.types[0].bitfield.class == SReg && !dot_insn ())
{
if (flag_code != CODE_64BIT
? i.tm.base_opcode == POP_SEG_SHORT
return 0;
}
if (i.op[0].regs->reg_num > 3
- && i.tm.opcode_modifier.opcodespace == SPACE_BASE )
+ && i.tm.opcode_space == SPACE_BASE )
{
i.tm.base_opcode ^= (POP_SEG_SHORT ^ POP_SEG386_SHORT) & 0xff;
- i.tm.opcode_modifier.opcodespace = SPACE_0F;
+ i.tm.opcode_space = SPACE_0F;
}
i.tm.base_opcode |= (i.op[0].regs->reg_num << 3);
}
- else if (i.tm.opcode_modifier.opcodespace == SPACE_BASE
+ else if (i.tm.opcode_space == SPACE_BASE
&& (i.tm.base_opcode & ~3) == MOV_AX_DISP32)
{
default_seg = reg_ds;
}
else if (i.short_form)
{
- /* The register operand is in operand 0 or 1. */
- const reg_entry *r = i.op[0].regs;
+ /* The register operand is in the 1st or 2nd non-immediate operand. */
+ const reg_entry *r = i.op[i.imm_operands].regs;
- if (i.imm_operands
- || (r->reg_type.bitfield.instance == Accum && i.op[1].regs))
- r = i.op[1].regs;
+ if (!dot_insn ()
+ && r->reg_type.bitfield.instance == Accum
+ && i.op[i.imm_operands + 1].regs)
+ r = i.op[i.imm_operands + 1].regs;
/* Register goes in low 3 bits of opcode. */
i.tm.base_opcode |= r->reg_num;
- if ((r->reg_flags & RegRex) != 0)
- i.rex |= REX_B;
+ set_rex_vrex (r, REX_B, false);
+
+ if (dot_insn () && i.reg_operands == 2)
+ {
+ gas_assert (is_any_vex_encoding (&i.tm)
+ || i.vec_encoding != vex_encoding_default);
+ i.vex.register_specifier = i.op[i.operands - 1].regs;
+ }
+ }
+ else if (i.reg_operands == 1
+ && !i.flags[i.operands - 1]
+ && i.tm.operand_types[i.operands - 1].bitfield.instance
+ == InstanceNone)
+ {
+ gas_assert (is_any_vex_encoding (&i.tm)
+ || i.vec_encoding != vex_encoding_default);
+ i.vex.register_specifier = i.op[i.operands - 1].regs;
}
if ((i.seg[0] || i.prefix[SEG_PREFIX])
- && i.tm.base_opcode == 0x8d /* lea */
- && i.tm.opcode_modifier.opcodespace == SPACE_BASE
- && !is_any_vex_encoding(&i.tm))
+ && i.tm.mnem_off == MN_lea)
{
if (!quiet_warnings)
as_warn (_("segment override on `%s' is ineffectual"), insn_name (&i.tm));
- if (optimize)
+ if (optimize && !i.no_optimize)
{
i.seg[0] = NULL;
i.prefix[SEG_PREFIX] = 0;
return 1;
}
-static INLINE void set_rex_vrex (const reg_entry *r, unsigned int rex_bit,
- bool do_sse2avx)
-{
- if (r->reg_flags & RegRex)
- {
- if (i.rex & rex_bit)
- as_bad (_("same type of prefix used twice"));
- i.rex |= rex_bit;
- }
- else if (do_sse2avx && (i.rex & rex_bit) && i.vex.register_specifier)
- {
- gas_assert (i.vex.register_specifier == r);
- i.vex.register_specifier += 8;
- }
-
- if (r->reg_flags & RegVRex)
- i.vrex |= rex_bit;
-}
-
-static const reg_entry *
-build_modrm_byte (void)
+static const reg_entry *
+build_modrm_byte (void)
{
const reg_entry *default_seg = NULL;
- unsigned int source, dest;
- int vex_3_sources;
+ unsigned int source = i.imm_operands - i.tm.opcode_modifier.immext
+ /* Compensate for kludge in md_assemble(). */
+ + i.tm.operand_types[0].bitfield.imm1;
+ unsigned int dest = i.operands - 1 - i.tm.opcode_modifier.immext;
+ unsigned int v, op, reg_slot = ~0;
+
+ /* Accumulator (in particular %st), shift count (%cl), and alike need
+ to be skipped just like immediate operands do. */
+ if (i.tm.operand_types[source].bitfield.instance)
+ ++source;
+ while (i.tm.operand_types[dest].bitfield.instance)
+ --dest;
+
+ for (op = source; op < i.operands; ++op)
+ if (i.tm.operand_types[op].bitfield.baseindex)
+ break;
- vex_3_sources = i.tm.opcode_modifier.vexsources == VEX3SOURCES;
- if (vex_3_sources)
+ if (i.reg_operands + i.mem_operands + (i.tm.extension_opcode != None) == 4)
{
- unsigned int nds, reg_slot;
expressionS *exp;
- dest = i.operands - 1;
- nds = dest - 1;
-
/* There are 2 kinds of instructions:
1. 5 operands: 4 register operands or 3 register operands
plus 1 memory operand plus one Imm4 operand, VexXDS, and
VexW0 or VexW1. The destination must be either XMM, YMM or
ZMM register.
2. 4 operands: 4 register operands or 3 register operands
- plus 1 memory operand, with VexXDS. */
- gas_assert ((i.reg_operands == 4
- || (i.reg_operands == 3 && i.mem_operands == 1))
- && i.tm.opcode_modifier.vexvvvv == VEXXDS
- && i.tm.opcode_modifier.vexw
- && i.tm.operand_types[dest].bitfield.class == RegSIMD);
+ plus 1 memory operand, with VexXDS.
+ 3. Other equivalent combinations when coming from s_insn(). */
+ gas_assert (i.tm.opcode_modifier.vexvvvv
+ && i.tm.opcode_modifier.vexw);
+ gas_assert (dot_insn ()
+ || i.tm.operand_types[dest].bitfield.class == RegSIMD);
+
+ /* Of the first two non-immediate operands the one with the template
+ not allowing for a memory one is encoded in the immediate operand. */
+ if (source == op)
+ reg_slot = source + 1;
+ else
+ reg_slot = source++;
- /* If VexW1 is set, the first non-immediate operand is the source and
- the second non-immediate one is encoded in the immediate operand. */
- if (i.tm.opcode_modifier.vexw == VEXW1)
+ if (!dot_insn ())
{
- source = i.imm_operands;
- reg_slot = i.imm_operands + 1;
+ gas_assert (i.tm.operand_types[reg_slot].bitfield.class == RegSIMD);
+ gas_assert (!(i.op[reg_slot].regs->reg_flags & RegVRex));
}
else
- {
- source = i.imm_operands + 1;
- reg_slot = i.imm_operands;
- }
+ gas_assert (i.tm.operand_types[reg_slot].bitfield.class != ClassNone);
if (i.imm_operands == 0)
{
i.types[i.operands].bitfield.imm8 = 1;
i.operands++;
- gas_assert (i.tm.operand_types[reg_slot].bitfield.class == RegSIMD);
exp->X_op = O_constant;
- exp->X_add_number = register_number (i.op[reg_slot].regs) << 4;
- gas_assert ((i.op[reg_slot].regs->reg_flags & RegVRex) == 0);
}
else
{
/* Turn on Imm8 again so that output_imm will generate it. */
i.types[0].bitfield.imm8 = 1;
- gas_assert (i.tm.operand_types[reg_slot].bitfield.class == RegSIMD);
- i.op[0].imms->X_add_number
- |= register_number (i.op[reg_slot].regs) << 4;
- gas_assert ((i.op[reg_slot].regs->reg_flags & RegVRex) == 0);
+ exp = i.op[0].imms;
}
-
- gas_assert (i.tm.operand_types[nds].bitfield.class == RegSIMD);
- i.vex.register_specifier = i.op[nds].regs;
+ exp->X_add_number |= register_number (i.op[reg_slot].regs)
+ << (3 + !(is_evex_encoding (&i.tm)
+ || i.vec_encoding == vex_encoding_evex));
}
- else
- source = dest = 0;
-
- /* i.reg_operands MUST be the number of real register operands;
- implicit registers do not count. If there are 3 register
- operands, it must be a instruction with VexNDS. For a
- instruction with VexNDD, the destination register is encoded
- in VEX prefix. If there are 4 register operands, it must be
- a instruction with VEX prefix and 3 sources. */
- if (i.mem_operands == 0
- && ((i.reg_operands == 2
- && i.tm.opcode_modifier.vexvvvv <= VEXXDS)
- || (i.reg_operands == 3
- && i.tm.opcode_modifier.vexvvvv == VEXXDS)
- || (i.reg_operands == 4 && vex_3_sources)))
- {
- switch (i.operands)
- {
- case 2:
- source = 0;
- break;
- case 3:
- /* When there are 3 operands, one of them may be immediate,
- which may be the first or the last operand. Otherwise,
- the first operand must be shift count register (cl) or it
- is an instruction with VexNDS. */
- gas_assert (i.imm_operands == 1
- || (i.imm_operands == 0
- && (i.tm.opcode_modifier.vexvvvv == VEXXDS
- || (i.types[0].bitfield.instance == RegC
- && i.types[0].bitfield.byte))));
- if (operand_type_check (i.types[0], imm)
- || (i.types[0].bitfield.instance == RegC
- && i.types[0].bitfield.byte))
- source = 1;
- else
- source = 0;
- break;
- case 4:
- /* When there are 4 operands, the first two must be 8bit
- immediate operands. The source operand will be the 3rd
- one.
-
- For instructions with VexNDS, if the first operand
- an imm8, the source operand is the 2nd one. If the last
- operand is imm8, the source operand is the first one. */
- gas_assert ((i.imm_operands == 2
- && i.types[0].bitfield.imm8
- && i.types[1].bitfield.imm8)
- || (i.tm.opcode_modifier.vexvvvv == VEXXDS
- && i.imm_operands == 1
- && (i.types[0].bitfield.imm8
- || i.types[i.operands - 1].bitfield.imm8)));
- if (i.imm_operands == 2)
- source = 2;
- else
- {
- if (i.types[0].bitfield.imm8)
- source = 1;
- else
- source = 0;
- }
- break;
- case 5:
- gas_assert (!is_evex_encoding (&i.tm));
- gas_assert (i.imm_operands == 1 && vex_3_sources);
- break;
- default:
- abort ();
- }
-
- if (!vex_3_sources)
- {
- dest = source + 1;
-
- if (i.tm.opcode_modifier.vexvvvv == VEXXDS)
- {
- /* For instructions with VexNDS, the register-only source
- operand must be a 32/64bit integer, XMM, YMM, ZMM, or mask
- register. It is encoded in VEX prefix. */
- i386_operand_type op;
- unsigned int vvvv;
+ for (v = source + 1; v < dest; ++v)
+ if (v != reg_slot)
+ break;
+ if (v >= dest)
+ v = ~0;
+ if (i.tm.extension_opcode != None)
+ {
+ if (dest != source)
+ v = dest;
+ dest = ~0;
+ }
+ gas_assert (source < dest);
+ if (i.tm.opcode_modifier.operandconstraint == SWAP_SOURCES
+ && source != op)
+ {
+ unsigned int tmp = source;
- /* Swap two source operands if needed. */
- if (i.tm.opcode_modifier.operandconstraint == SWAP_SOURCES)
- {
- vvvv = source;
- source = dest;
- }
- else
- vvvv = dest;
-
- op = i.tm.operand_types[vvvv];
- if ((dest + 1) >= i.operands
- || ((op.bitfield.class != Reg
- || (!op.bitfield.dword && !op.bitfield.qword))
- && op.bitfield.class != RegSIMD
- && op.bitfield.class != RegMask))
- abort ();
- i.vex.register_specifier = i.op[vvvv].regs;
- dest++;
- }
- }
+ source = v;
+ v = tmp;
+ }
- i.rm.mode = 3;
- /* One of the register operands will be encoded in the i.rm.reg
- field, the other in the combined i.rm.mode and i.rm.regmem
- fields. If no form of this instruction supports a memory
- destination operand, then we assume the source operand may
- sometimes be a memory operand and so we need to store the
- destination in the i.rm.reg field. */
- if (!i.tm.opcode_modifier.regmem
- && operand_type_check (i.tm.operand_types[dest], anymem) == 0)
- {
- i.rm.reg = i.op[dest].regs->reg_num;
- i.rm.regmem = i.op[source].regs->reg_num;
- set_rex_vrex (i.op[dest].regs, REX_R, i.tm.opcode_modifier.sse2avx);
- set_rex_vrex (i.op[source].regs, REX_B, false);
- }
- else
- {
- i.rm.reg = i.op[source].regs->reg_num;
- i.rm.regmem = i.op[dest].regs->reg_num;
- set_rex_vrex (i.op[dest].regs, REX_B, i.tm.opcode_modifier.sse2avx);
- set_rex_vrex (i.op[source].regs, REX_R, false);
- }
- if (flag_code != CODE_64BIT && (i.rex & REX_R))
- {
- if (i.types[!i.tm.opcode_modifier.regmem].bitfield.class != RegCR)
- abort ();
- i.rex &= ~REX_R;
- add_prefix (LOCK_PREFIX_OPCODE);
- }
+ if (v < MAX_OPERANDS)
+ {
+ gas_assert (i.tm.opcode_modifier.vexvvvv);
+ i.vex.register_specifier = i.op[v].regs;
}
- else
- { /* If it's not 2 reg operands... */
- unsigned int mem;
+ if (op < i.operands)
+ {
if (i.mem_operands)
{
unsigned int fake_zero_displacement = 0;
- unsigned int op;
- for (op = 0; op < i.operands; op++)
- if (i.flags[op] & Operand_Mem)
- break;
- gas_assert (op < i.operands);
+ gas_assert (i.flags[op] & Operand_Mem);
if (i.tm.opcode_modifier.sib)
{
exp->X_add_symbol = (symbolS *) 0;
exp->X_op_symbol = (symbolS *) 0;
}
-
- mem = op;
}
- else
- mem = ~0;
-
- if (i.tm.opcode_modifier.vexsources == XOP2SOURCES)
+ else
{
- if (operand_type_check (i.types[0], imm))
- i.vex.register_specifier = NULL;
- else
- {
- /* VEX.vvvv encodes one of the sources when the first
- operand is not an immediate. */
- if (i.tm.opcode_modifier.vexw == VEXW0)
- i.vex.register_specifier = i.op[0].regs;
- else
- i.vex.register_specifier = i.op[1].regs;
- }
-
- /* Destination is a XMM register encoded in the ModRM.reg
- and VEX.R bit. */
- i.rm.reg = i.op[2].regs->reg_num;
- if ((i.op[2].regs->reg_flags & RegRex) != 0)
- i.rex |= REX_R;
-
- /* ModRM.rm and VEX.B encodes the other source. */
- if (!i.mem_operands)
- {
- i.rm.mode = 3;
-
- if (i.tm.opcode_modifier.vexw == VEXW0)
- i.rm.regmem = i.op[1].regs->reg_num;
- else
- i.rm.regmem = i.op[0].regs->reg_num;
-
- if ((i.op[1].regs->reg_flags & RegRex) != 0)
- i.rex |= REX_B;
- }
+ i.rm.mode = 3;
+ i.rm.regmem = i.op[op].regs->reg_num;
+ set_rex_vrex (i.op[op].regs, REX_B, false);
}
- else if (i.tm.opcode_modifier.vexvvvv == VEXLWP)
+
+ if (op == dest)
+ dest = ~0;
+ if (op == source)
+ source = ~0;
+ }
+ else
+ {
+ i.rm.mode = 3;
+ if (!i.tm.opcode_modifier.regmem)
{
- i.vex.register_specifier = i.op[2].regs;
- if (!i.mem_operands)
- {
- i.rm.mode = 3;
- i.rm.regmem = i.op[1].regs->reg_num;
- if ((i.op[1].regs->reg_flags & RegRex) != 0)
- i.rex |= REX_B;
- }
+ gas_assert (source < MAX_OPERANDS);
+ i.rm.regmem = i.op[source].regs->reg_num;
+ set_rex_vrex (i.op[source].regs, REX_B,
+ dest >= MAX_OPERANDS && i.tm.opcode_modifier.sse2avx);
+ source = ~0;
}
- /* Fill in i.rm.reg or i.rm.regmem field with register operand
- (if any) based on i.tm.extension_opcode. Again, we must be
- careful to make sure that segment/control/debug/test/MMX
- registers are coded into the i.rm.reg field. */
- else if (i.reg_operands)
+ else
{
- unsigned int op;
- unsigned int vex_reg = ~0;
-
- for (op = 0; op < i.operands; op++)
- if (i.types[op].bitfield.class == Reg
- || i.types[op].bitfield.class == RegBND
- || i.types[op].bitfield.class == RegMask
- || i.types[op].bitfield.class == SReg
- || i.types[op].bitfield.class == RegCR
- || i.types[op].bitfield.class == RegDR
- || i.types[op].bitfield.class == RegTR
- || i.types[op].bitfield.class == RegSIMD
- || i.types[op].bitfield.class == RegMMX)
- break;
-
- if (vex_3_sources)
- op = dest;
- else if (i.tm.opcode_modifier.vexvvvv == VEXXDS)
- {
- /* For instructions with VexNDS, the register-only
- source operand is encoded in VEX prefix. */
- gas_assert (mem != (unsigned int) ~0);
-
- if (op > mem || i.tm.cpu_flags.bitfield.cpucmpccxadd)
- {
- vex_reg = op++;
- gas_assert (op < i.operands);
- }
- else
- {
- /* Check register-only source operand when two source
- operands are swapped. */
- if (!i.tm.operand_types[op].bitfield.baseindex
- && i.tm.operand_types[op + 1].bitfield.baseindex)
- {
- vex_reg = op;
- op += 2;
- gas_assert (mem == (vex_reg + 1)
- && op < i.operands);
- }
- else
- {
- vex_reg = op + 1;
- gas_assert (vex_reg < i.operands);
- }
- }
- }
- else if (i.tm.opcode_modifier.vexvvvv == VEXNDD)
- {
- /* For instructions with VexNDD, the register destination
- is encoded in VEX prefix. */
- if (i.mem_operands == 0)
- {
- /* There is no memory operand. */
- gas_assert ((op + 2) == i.operands);
- vex_reg = op + 1;
- }
- else
- {
- /* There are only 2 non-immediate operands. */
- gas_assert (op < i.imm_operands + 2
- && i.operands == i.imm_operands + 2);
- vex_reg = i.imm_operands + 1;
- }
- }
- else
- gas_assert (op < i.operands);
-
- if (vex_reg != (unsigned int) ~0)
- {
- i386_operand_type *type = &i.tm.operand_types[vex_reg];
-
- if ((type->bitfield.class != Reg
- || (!type->bitfield.dword && !type->bitfield.qword))
- && type->bitfield.class != RegSIMD
- && type->bitfield.class != RegMask)
- abort ();
-
- i.vex.register_specifier = i.op[vex_reg].regs;
- }
-
- /* Don't set OP operand twice. */
- if (vex_reg != op)
- {
- /* If there is an extension opcode to put here, the
- register number must be put into the regmem field. */
- if (i.tm.extension_opcode != None)
- {
- i.rm.regmem = i.op[op].regs->reg_num;
- set_rex_vrex (i.op[op].regs, REX_B,
- i.tm.opcode_modifier.sse2avx);
- }
- else
- {
- i.rm.reg = i.op[op].regs->reg_num;
- set_rex_vrex (i.op[op].regs, REX_R,
- i.tm.opcode_modifier.sse2avx);
- }
- }
-
- /* Now, if no memory operand has set i.rm.mode = 0, 1, 2 we
- must set it to 3 to indicate this is a register operand
- in the regmem field. */
- if (!i.mem_operands)
- i.rm.mode = 3;
+ gas_assert (dest < MAX_OPERANDS);
+ i.rm.regmem = i.op[dest].regs->reg_num;
+ set_rex_vrex (i.op[dest].regs, REX_B, i.tm.opcode_modifier.sse2avx);
+ dest = ~0;
}
+ }
+
+ /* Fill in i.rm.reg field with extension opcode (if any) or the
+ appropriate register. */
+ if (i.tm.extension_opcode != None)
+ i.rm.reg = i.tm.extension_opcode;
+ else if (!i.tm.opcode_modifier.regmem && dest < MAX_OPERANDS)
+ {
+ i.rm.reg = i.op[dest].regs->reg_num;
+ set_rex_vrex (i.op[dest].regs, REX_R, i.tm.opcode_modifier.sse2avx);
+ }
+ else
+ {
+ gas_assert (source < MAX_OPERANDS);
+ i.rm.reg = i.op[source].regs->reg_num;
+ set_rex_vrex (i.op[source].regs, REX_R, false);
+ }
- /* Fill in i.rm.reg field with extension opcode (if any). */
- if (i.tm.extension_opcode != None)
- i.rm.reg = i.tm.extension_opcode;
+ if (flag_code != CODE_64BIT && (i.rex & REX_R))
+ {
+ gas_assert (i.types[!i.tm.opcode_modifier.regmem].bitfield.class == RegCR);
+ i.rex &= ~REX_R;
+ add_prefix (LOCK_PREFIX_OPCODE);
}
+
return default_seg;
}
off = 0;
}
- frag_now->tc_frag_data.code64 = flag_code == CODE_64BIT;
-
/* 1 possible extra opcode + 4 byte displacement go in var part.
Pass reloc in fr_var. */
frag_var (rs_machine_dependent, 5, i.reloc[0], subtype, sym, off, p);
break;
case 2:
- if (i.tm.base_opcode == 0xc7f8)
+ if (i.tm.mnem_off == MN_xbegin)
fixP->fx_signed = 1;
break;
return 0;
/* No opcodes outside of base encoding space. */
- if (i.tm.opcode_modifier.opcodespace != SPACE_BASE)
+ if (i.tm.opcode_space != SPACE_BASE)
return 0;
/* add, sub without add/sub m, imm. */
}
/* inc, dec without inc/dec m. */
- if ((i.tm.cpu_flags.bitfield.cpuno64
+ if ((is_cpu (&i.tm, CpuNo64)
&& (i.tm.base_opcode | 0xf) == 0x4f)
|| ((i.tm.base_opcode | 1) == 0xff
&& i.tm.extension_opcode <= 0x1))
if (!align_branch_power
|| !align_branch_prefix_size
|| now_seg == absolute_section
- || i.tm.cpu_flags.bitfield.cpupadlock
+ || is_cpu (&i.tm, CpuPadLock)
|| !cpu_arch_flags.bitfield.cpui386)
return 0;
if (!align_branch_power
|| now_seg == absolute_section
|| !cpu_arch_flags.bitfield.cpui386
- || i.tm.opcode_modifier.opcodespace != SPACE_BASE)
+ || i.tm.opcode_space != SPACE_BASE)
return 0;
add_padding = 0;
if (IS_ELF && x86_used_note && now_seg != absolute_section)
{
if ((i.xstate & xstate_tmm) == xstate_tmm
- || i.tm.cpu_flags.bitfield.cpuamx_tile)
+ || is_cpu (&i.tm, CpuAMX_TILE))
x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_TMM;
- if (i.tm.cpu_flags.bitfield.cpu8087
- || i.tm.cpu_flags.bitfield.cpu287
- || i.tm.cpu_flags.bitfield.cpu387
- || i.tm.cpu_flags.bitfield.cpu687
- || i.tm.cpu_flags.bitfield.cpufisttp)
+ if (is_cpu (&i.tm, Cpu8087)
+ || is_cpu (&i.tm, Cpu287)
+ || is_cpu (&i.tm, Cpu387)
+ || is_cpu (&i.tm, Cpu687)
+ || is_cpu (&i.tm, CpuFISTTP))
x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_X87;
if ((i.xstate & xstate_mmx)
- || (i.tm.opcode_modifier.opcodespace == SPACE_0F
- && !is_any_vex_encoding (&i.tm)
- && (i.tm.base_opcode == 0x77 /* emms */
- || i.tm.base_opcode == 0x0e /* femms */)))
+ || i.tm.mnem_off == MN_emms
+ || i.tm.mnem_off == MN_femms)
x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_MMX;
if (i.index_reg)
}
/* vzeroall / vzeroupper */
- if (i.tm.base_opcode == 0x77 && i.tm.cpu_flags.bitfield.cpuavx)
+ if (i.tm.base_opcode == 0x77 && is_cpu (&i.tm, CpuAVX))
i.xstate |= xstate_ymm;
if ((i.xstate & xstate_xmm)
/* ldmxcsr / stmxcsr / vldmxcsr / vstmxcsr */
|| (i.tm.base_opcode == 0xae
- && (i.tm.cpu_flags.bitfield.cpusse
- || i.tm.cpu_flags.bitfield.cpuavx))
- || i.tm.cpu_flags.bitfield.cpuwidekl
- || i.tm.cpu_flags.bitfield.cpukl)
+ && (is_cpu (&i.tm, CpuSSE)
+ || is_cpu (&i.tm, CpuAVX)))
+ || is_cpu (&i.tm, CpuWideKL)
+ || is_cpu (&i.tm, CpuKL))
x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_XMM;
if ((i.xstate & xstate_ymm) == xstate_ymm)
x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_ZMM;
if (i.mask.reg || (i.xstate & xstate_mask) == xstate_mask)
x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_MASK;
- if (i.tm.cpu_flags.bitfield.cpufxsr)
+ if (is_cpu (&i.tm, CpuFXSR))
x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_FXSR;
- if (i.tm.cpu_flags.bitfield.cpuxsave)
+ if (is_cpu (&i.tm, CpuXsave))
x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_XSAVE;
- if (i.tm.cpu_flags.bitfield.cpuxsaveopt)
+ if (is_cpu (&i.tm, CpuXsaveopt))
x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_XSAVEOPT;
- if (i.tm.cpu_flags.bitfield.cpuxsavec)
+ if (is_cpu (&i.tm, CpuXSAVEC))
x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_XSAVEC;
if (x86_feature_2_used
- || i.tm.cpu_flags.bitfield.cpucmov
- || i.tm.cpu_flags.bitfield.cpusyscall
- || (i.tm.opcode_modifier.opcodespace == SPACE_0F
- && i.tm.base_opcode == 0xc7
- && i.tm.opcode_modifier.opcodeprefix == PREFIX_NONE
- && i.tm.extension_opcode == 1) /* cmpxchg8b */)
+ || is_cpu (&i.tm, CpuCMOV)
+ || is_cpu (&i.tm, CpuSYSCALL)
+ || i.tm.mnem_off == MN_cmpxchg8b)
x86_isa_1_used |= GNU_PROPERTY_X86_ISA_1_BASELINE;
- if (i.tm.cpu_flags.bitfield.cpusse3
- || i.tm.cpu_flags.bitfield.cpussse3
- || i.tm.cpu_flags.bitfield.cpusse4_1
- || i.tm.cpu_flags.bitfield.cpusse4_2
- || i.tm.cpu_flags.bitfield.cpucx16
- || i.tm.cpu_flags.bitfield.cpupopcnt
+ if (is_cpu (&i.tm, CpuSSE3)
+ || is_cpu (&i.tm, CpuSSSE3)
+ || is_cpu (&i.tm, CpuSSE4_1)
+ || is_cpu (&i.tm, CpuSSE4_2)
+ || is_cpu (&i.tm, CpuCX16)
+ || is_cpu (&i.tm, CpuPOPCNT)
/* LAHF-SAHF insns in 64-bit mode. */
|| (flag_code == CODE_64BIT
&& (i.tm.base_opcode | 1) == 0x9f
- && i.tm.opcode_modifier.opcodespace == SPACE_BASE))
+ && i.tm.opcode_space == SPACE_BASE))
x86_isa_1_used |= GNU_PROPERTY_X86_ISA_1_V2;
- if (i.tm.cpu_flags.bitfield.cpuavx
- || i.tm.cpu_flags.bitfield.cpuavx2
+ if (is_cpu (&i.tm, CpuAVX)
+ || is_cpu (&i.tm, CpuAVX2)
/* Any VEX encoded insns execpt for AVX512F, AVX512BW, AVX512DQ,
XOP, FMA4, LPW, TBM, and AMX. */
|| (i.tm.opcode_modifier.vex
- && !i.tm.cpu_flags.bitfield.cpuavx512f
- && !i.tm.cpu_flags.bitfield.cpuavx512bw
- && !i.tm.cpu_flags.bitfield.cpuavx512dq
- && !i.tm.cpu_flags.bitfield.cpuxop
- && !i.tm.cpu_flags.bitfield.cpufma4
- && !i.tm.cpu_flags.bitfield.cpulwp
- && !i.tm.cpu_flags.bitfield.cputbm
+ && !is_cpu (&i.tm, CpuAVX512F)
+ && !is_cpu (&i.tm, CpuAVX512BW)
+ && !is_cpu (&i.tm, CpuAVX512DQ)
+ && !is_cpu (&i.tm, CpuXOP)
+ && !is_cpu (&i.tm, CpuFMA4)
+ && !is_cpu (&i.tm, CpuLWP)
+ && !is_cpu (&i.tm, CpuTBM)
&& !(x86_feature_2_used & GNU_PROPERTY_X86_FEATURE_2_TMM))
- || i.tm.cpu_flags.bitfield.cpuf16c
- || i.tm.cpu_flags.bitfield.cpufma
- || i.tm.cpu_flags.bitfield.cpulzcnt
- || i.tm.cpu_flags.bitfield.cpumovbe
- || i.tm.cpu_flags.bitfield.cpuxsaves
+ || is_cpu (&i.tm, CpuF16C)
+ || is_cpu (&i.tm, CpuFMA)
+ || is_cpu (&i.tm, CpuLZCNT)
+ || is_cpu (&i.tm, CpuMovbe)
+ || is_cpu (&i.tm, CpuXSAVES)
|| (x86_feature_2_used
& (GNU_PROPERTY_X86_FEATURE_2_XSAVE
| GNU_PROPERTY_X86_FEATURE_2_XSAVEOPT
| GNU_PROPERTY_X86_FEATURE_2_XSAVEC)) != 0)
x86_isa_1_used |= GNU_PROPERTY_X86_ISA_1_V3;
- if (i.tm.cpu_flags.bitfield.cpuavx512f
- || i.tm.cpu_flags.bitfield.cpuavx512bw
- || i.tm.cpu_flags.bitfield.cpuavx512dq
- || i.tm.cpu_flags.bitfield.cpuavx512vl
+ if (is_cpu (&i.tm, CpuAVX512F)
+ || is_cpu (&i.tm, CpuAVX512BW)
+ || is_cpu (&i.tm, CpuAVX512DQ)
+ || is_cpu (&i.tm, CpuAVX512VL)
/* Any EVEX encoded insns except for AVX512ER, AVX512PF,
AVX512-4FMAPS, and AVX512-4VNNIW. */
|| (i.tm.opcode_modifier.evex
- && !i.tm.cpu_flags.bitfield.cpuavx512er
- && !i.tm.cpu_flags.bitfield.cpuavx512pf
- && !i.tm.cpu_flags.bitfield.cpuavx512_4fmaps
- && !i.tm.cpu_flags.bitfield.cpuavx512_4vnniw))
+ && !is_cpu (&i.tm, CpuAVX512ER)
+ && !is_cpu (&i.tm, CpuAVX512PF)
+ && !is_cpu (&i.tm, CpuAVX512_4FMAPS)
+ && !is_cpu (&i.tm, CpuAVX512_4VNNIW)))
x86_isa_1_used |= GNU_PROPERTY_X86_ISA_1_V4;
}
#endif
add_prefix (0xf2);
break;
case PREFIX_0XF3:
- if (!i.tm.cpu_flags.bitfield.cpupadlock
+ if (!is_cpu (&i.tm, CpuPadLock)
|| (i.prefix[REP_PREFIX] != 0xf3))
add_prefix (0xf3);
break;
/* Now the opcode; be careful about word order here! */
j = i.opcode_length;
if (!i.vex.length)
- switch (i.tm.opcode_modifier.opcodespace)
+ switch (i.tm.opcode_space)
{
case SPACE_BASE:
break;
{
p = frag_more (j);
if (!i.vex.length
- && i.tm.opcode_modifier.opcodespace != SPACE_BASE)
+ && i.tm.opcode_space != SPACE_BASE)
{
*p++ = 0x0f;
- if (i.tm.opcode_modifier.opcodespace != SPACE_0F)
- *p++ = i.tm.opcode_modifier.opcodespace == SPACE_0F38
+ if (i.tm.opcode_space != SPACE_0F)
+ *p++ = i.tm.opcode_space == SPACE_0F38
? 0x38 : 0x3a;
}
/* Count prefixes for extended opcode maps. */
if (!i.vex.length)
- switch (i.tm.opcode_modifier.opcodespace)
+ switch (i.tm.opcode_space)
{
case SPACE_BASE:
break;
if (operand_type_check (i.types[n1], imm))
{
/* Only one immediate is allowed for PC
- relative address. */
- gas_assert (sz == 0);
- sz = imm_size (n1);
- i.op[n].disps->X_add_number -= sz;
+ relative address, except with .insn. */
+ gas_assert (sz == 0 || dot_insn ());
+ sz += imm_size (n1);
}
- /* We should find the immediate. */
+ /* We should find at least one immediate. */
gas_assert (sz != 0);
+ i.op[n].disps->X_add_number -= sz;
}
p = frag_more (size);
&& i.rm.regmem == 5))
&& (i.rm.mode == 2
|| (i.rm.mode == 0 && i.rm.regmem == 5))
- && i.tm.opcode_modifier.opcodespace == SPACE_BASE
+ && i.tm.opcode_space == SPACE_BASE
&& ((i.operands == 1
&& i.tm.base_opcode == 0xff
&& (i.rm.reg == 2 || i.rm.reg == 4))
if (i.types[n].bitfield.imm32s
&& (i.suffix == QWORD_MNEM_SUFFIX
- || (!i.suffix && i.tm.opcode_modifier.no_lsuf)))
+ || (!i.suffix && i.tm.opcode_modifier.no_lsuf)
+ || (i.prefix[REX_PREFIX] & REX_W)
+ || dot_insn ()))
sign = 1;
else
sign = 0;
return NULL;
#endif
- for (cp = input_line_pointer; *cp != '@'; cp++)
- if (is_end_of_line[(unsigned char) *cp] || *cp == ',')
- return NULL;
+ for (cp = input_line_pointer; *cp != '@'; cp++)
+ if (is_end_of_line[(unsigned char) *cp] || *cp == ',')
+ return NULL;
+
+ for (j = 0; j < ARRAY_SIZE (gotrel); j++)
+ {
+ int len = gotrel[j].len;
+ if (strncasecmp (cp + 1, gotrel[j].str, len) == 0)
+ {
+ if (gotrel[j].rel[object_64bit] != 0)
+ {
+ int first, second;
+ char *tmpbuf, *past_reloc;
+
+ *rel = gotrel[j].rel[object_64bit];
+
+ if (types)
+ {
+ if (flag_code != CODE_64BIT)
+ {
+ types->bitfield.imm32 = 1;
+ types->bitfield.disp32 = 1;
+ }
+ else
+ *types = gotrel[j].types64;
+ }
+
+ if (gotrel[j].need_GOT_symbol && GOT_symbol == NULL)
+ GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
+
+ /* The length of the first part of our input line. */
+ first = cp - input_line_pointer;
+
+ /* The second part goes from after the reloc token until
+ (and including) an end_of_line char or comma. */
+ past_reloc = cp + 1 + len;
+ cp = past_reloc;
+ while (!is_end_of_line[(unsigned char) *cp] && *cp != ',')
+ ++cp;
+ second = cp + 1 - past_reloc;
+
+ /* Allocate and copy string. The trailing NUL shouldn't
+ be necessary, but be safe. */
+ tmpbuf = XNEWVEC (char, first + second + 2);
+ memcpy (tmpbuf, input_line_pointer, first);
+ if (second != 0 && *past_reloc != ' ')
+ /* Replace the relocation token with ' ', so that
+ errors like foo@GOTOFF1 will be detected. */
+ tmpbuf[first++] = ' ';
+ else
+ /* Increment length by 1 if the relocation token is
+ removed. */
+ len++;
+ if (adjust)
+ *adjust = len;
+ memcpy (tmpbuf + first, past_reloc, second);
+ tmpbuf[first + second] = '\0';
+ return tmpbuf;
+ }
+
+ as_bad (_("@%s reloc is not supported with %d-bit output format"),
+ gotrel[j].str, 1 << (5 + object_64bit));
+ return NULL;
+ }
+ }
+
+ /* Might be a symbol version string. Don't as_bad here. */
+ return NULL;
+}
+#endif
+
+bfd_reloc_code_real_type
+x86_cons (expressionS *exp, int size)
+{
+ bfd_reloc_code_real_type got_reloc = NO_RELOC;
+
+ intel_syntax = -intel_syntax;
+ exp->X_md = 0;
+ expr_mode = expr_operator_none;
+
+#if ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \
+ && !defined (LEX_AT)) \
+ || defined (TE_PE)
+ if (size == 4 || (object_64bit && size == 8))
+ {
+ /* Handle @GOTOFF and the like in an expression. */
+ char *save;
+ char *gotfree_input_line;
+ int adjust = 0;
+
+ save = input_line_pointer;
+ gotfree_input_line = lex_got (&got_reloc, &adjust, NULL);
+ if (gotfree_input_line)
+ input_line_pointer = gotfree_input_line;
+
+ expression (exp);
+
+ if (gotfree_input_line)
+ {
+ /* expression () has merrily parsed up to the end of line,
+ or a comma - in the wrong buffer. Transfer how far
+ input_line_pointer has moved to the right buffer. */
+ input_line_pointer = (save
+ + (input_line_pointer - gotfree_input_line)
+ + adjust);
+ free (gotfree_input_line);
+ if (exp->X_op == O_constant
+ || exp->X_op == O_absent
+ || exp->X_op == O_illegal
+ || exp->X_op == O_register
+ || exp->X_op == O_big)
+ {
+ char c = *input_line_pointer;
+ *input_line_pointer = 0;
+ as_bad (_("missing or invalid expression `%s'"), save);
+ *input_line_pointer = c;
+ }
+ else if ((got_reloc == BFD_RELOC_386_PLT32
+ || got_reloc == BFD_RELOC_X86_64_PLT32)
+ && exp->X_op != O_symbol)
+ {
+ char c = *input_line_pointer;
+ *input_line_pointer = 0;
+ as_bad (_("invalid PLT expression `%s'"), save);
+ *input_line_pointer = c;
+ }
+ }
+ }
+ else
+#endif
+ expression (exp);
+
+ intel_syntax = -intel_syntax;
+
+ if (intel_syntax)
+ i386_intel_simplify (exp);
+
+ /* If not 64bit, massage value, to account for wraparound when !BFD64. */
+ if (size <= 4 && expr_mode == expr_operator_present
+ && exp->X_op == O_constant && !object_64bit)
+ exp->X_add_number = extend_to_32bit_address (exp->X_add_number);
+
+ return got_reloc;
+}
+
+static void
+signed_cons (int size)
+{
+ if (object_64bit)
+ cons_sign = 1;
+ cons (size);
+ cons_sign = -1;
+}
+
+static void
+s_insn (int dummy ATTRIBUTE_UNUSED)
+{
+ char mnemonic[MAX_MNEM_SIZE], *line = input_line_pointer, *ptr;
+ char *saved_ilp = find_end_of_line (line, false), saved_char;
+ const char *end;
+ unsigned int j;
+ valueT val;
+ bool vex = false, xop = false, evex = false;
+ static const templates tt = { &i.tm, &i.tm + 1 };
+
+ init_globals ();
+
+ saved_char = *saved_ilp;
+ *saved_ilp = 0;
+
+ end = parse_insn (line, mnemonic, true);
+ if (end == NULL)
+ {
+ bad:
+ *saved_ilp = saved_char;
+ ignore_rest_of_line ();
+ i.tm.mnem_off = 0;
+ return;
+ }
+ line += end - line;
+
+ current_templates = &tt;
+ i.tm.mnem_off = MN__insn;
+ i.tm.extension_opcode = None;
+
+ if (startswith (line, "VEX")
+ && (line[3] == '.' || is_space_char (line[3])))
+ {
+ vex = true;
+ line += 3;
+ }
+ else if (startswith (line, "XOP") && ISDIGIT (line[3]))
+ {
+ char *e;
+ unsigned long n = strtoul (line + 3, &e, 16);
+
+ if (e == line + 5 && n >= 0x08 && n <= 0x1f
+ && (*e == '.' || is_space_char (*e)))
+ {
+ xop = true;
+ /* Arrange for build_vex_prefix() to emit 0x8f. */
+ i.tm.opcode_space = SPACE_XOP08;
+ i.insn_opcode_space = n;
+ line = e;
+ }
+ }
+ else if (startswith (line, "EVEX")
+ && (line[4] == '.' || is_space_char (line[4])))
+ {
+ evex = true;
+ line += 4;
+ }
+
+ if (vex || xop
+ ? i.vec_encoding == vex_encoding_evex
+ : evex
+ ? i.vec_encoding == vex_encoding_vex
+ || i.vec_encoding == vex_encoding_vex3
+ : i.vec_encoding != vex_encoding_default)
+ {
+ as_bad (_("pseudo-prefix conflicts with encoding specifier"));
+ goto bad;
+ }
+
+ if (line > end && i.vec_encoding == vex_encoding_default)
+ i.vec_encoding = evex ? vex_encoding_evex : vex_encoding_vex;
+
+ if (i.vec_encoding != vex_encoding_default)
+ {
+ /* Only address size and segment override prefixes are permitted with
+ VEX/XOP/EVEX encodings. */
+ const unsigned char *p = i.prefix;
+
+ for (j = 0; j < ARRAY_SIZE (i.prefix); ++j, ++p)
+ {
+ if (!*p)
+ continue;
+
+ switch (j)
+ {
+ case SEG_PREFIX:
+ case ADDR_PREFIX:
+ break;
+ default:
+ as_bad (_("illegal prefix used with VEX/XOP/EVEX"));
+ goto bad;
+ }
+ }
+ }
+
+ if (line > end && *line == '.')
+ {
+ /* Length specifier (VEX.L, XOP.L, EVEX.L'L). */
+ switch (line[1])
+ {
+ case 'L':
+ switch (line[2])
+ {
+ case '0':
+ if (evex)
+ i.tm.opcode_modifier.evex = EVEX128;
+ else
+ i.tm.opcode_modifier.vex = VEX128;
+ break;
+
+ case '1':
+ if (evex)
+ i.tm.opcode_modifier.evex = EVEX256;
+ else
+ i.tm.opcode_modifier.vex = VEX256;
+ break;
+
+ case '2':
+ if (evex)
+ i.tm.opcode_modifier.evex = EVEX512;
+ break;
+
+ case '3':
+ if (evex)
+ i.tm.opcode_modifier.evex = EVEX_L3;
+ break;
+
+ case 'I':
+ if (line[3] == 'G')
+ {
+ if (evex)
+ i.tm.opcode_modifier.evex = EVEXLIG;
+ else
+ i.tm.opcode_modifier.vex = VEXScalar; /* LIG */
+ ++line;
+ }
+ break;
+ }
+
+ if (i.tm.opcode_modifier.vex || i.tm.opcode_modifier.evex)
+ line += 3;
+ break;
+
+ case '1':
+ if (line[2] == '2' && line[3] == '8')
+ {
+ if (evex)
+ i.tm.opcode_modifier.evex = EVEX128;
+ else
+ i.tm.opcode_modifier.vex = VEX128;
+ line += 4;
+ }
+ break;
+
+ case '2':
+ if (line[2] == '5' && line[3] == '6')
+ {
+ if (evex)
+ i.tm.opcode_modifier.evex = EVEX256;
+ else
+ i.tm.opcode_modifier.vex = VEX256;
+ line += 4;
+ }
+ break;
+
+ case '5':
+ if (evex && line[2] == '1' && line[3] == '2')
+ {
+ i.tm.opcode_modifier.evex = EVEX512;
+ line += 4;
+ }
+ break;
+ }
+ }
+
+ if (line > end && *line == '.')
+ {
+ /* embedded prefix (VEX.pp, XOP.pp, EVEX.pp). */
+ switch (line[1])
+ {
+ case 'N':
+ if (line[2] == 'P')
+ line += 3;
+ break;
+
+ case '6':
+ if (line[2] == '6')
+ {
+ i.tm.opcode_modifier.opcodeprefix = PREFIX_0X66;
+ line += 3;
+ }
+ break;
+
+ case 'F': case 'f':
+ if (line[2] == '3')
+ {
+ i.tm.opcode_modifier.opcodeprefix = PREFIX_0XF3;
+ line += 3;
+ }
+ else if (line[2] == '2')
+ {
+ i.tm.opcode_modifier.opcodeprefix = PREFIX_0XF2;
+ line += 3;
+ }
+ break;
+ }
+ }
+
+ if (line > end && !xop && *line == '.')
+ {
+ /* Encoding space (VEX.mmmmm, EVEX.mmmm). */
+ switch (line[1])
+ {
+ case '0':
+ if (TOUPPER (line[2]) != 'F')
+ break;
+ if (line[3] == '.' || is_space_char (line[3]))
+ {
+ i.insn_opcode_space = SPACE_0F;
+ line += 3;
+ }
+ else if (line[3] == '3'
+ && (line[4] == '8' || TOUPPER (line[4]) == 'A')
+ && (line[5] == '.' || is_space_char (line[5])))
+ {
+ i.insn_opcode_space = line[4] == '8' ? SPACE_0F38 : SPACE_0F3A;
+ line += 5;
+ }
+ break;
+
+ case 'M':
+ if (ISDIGIT (line[2]) && line[2] != '0')
+ {
+ char *e;
+ unsigned long n = strtoul (line + 2, &e, 10);
+
+ if (n <= (evex ? 15 : 31)
+ && (*e == '.' || is_space_char (*e)))
+ {
+ i.insn_opcode_space = n;
+ line = e;
+ }
+ }
+ break;
+ }
+ }
+
+ if (line > end && *line == '.' && line[1] == 'W')
+ {
+ /* VEX.W, XOP.W, EVEX.W */
+ switch (line[2])
+ {
+ case '0':
+ i.tm.opcode_modifier.vexw = VEXW0;
+ break;
+
+ case '1':
+ i.tm.opcode_modifier.vexw = VEXW1;
+ break;
+
+ case 'I':
+ if (line[3] == 'G')
+ {
+ i.tm.opcode_modifier.vexw = VEXWIG;
+ ++line;
+ }
+ break;
+ }
+
+ if (i.tm.opcode_modifier.vexw)
+ line += 3;
+ }
+
+ if (line > end && *line && !is_space_char (*line))
+ {
+ /* Improve diagnostic a little. */
+ if (*line == '.' && line[1] && !is_space_char (line[1]))
+ ++line;
+ goto done;
+ }
+
+ /* Before processing the opcode expression, find trailing "+r" or
+ "/<digit>" specifiers. */
+ for (ptr = line; ; ++ptr)
+ {
+ unsigned long n;
+ char *e;
+
+ ptr = strpbrk (ptr, "+/,");
+ if (ptr == NULL || *ptr == ',')
+ break;
+
+ if (*ptr == '+' && ptr[1] == 'r'
+ && (ptr[2] == ',' || (is_space_char (ptr[2]) && ptr[3] == ',')))
+ {
+ *ptr = ' ';
+ ptr[1] = ' ';
+ i.short_form = true;
+ break;
+ }
+
+ if (*ptr == '/' && ISDIGIT (ptr[1])
+ && (n = strtoul (ptr + 1, &e, 8)) < 8
+ && e == ptr + 2
+ && (ptr[2] == ',' || (is_space_char (ptr[2]) && ptr[3] == ',')))
+ {
+ *ptr = ' ';
+ ptr[1] = ' ';
+ i.tm.extension_opcode = n;
+ i.tm.opcode_modifier.modrm = 1;
+ break;
+ }
+ }
+
+ input_line_pointer = line;
+ val = get_absolute_expression ();
+ line = input_line_pointer;
+
+ if (i.short_form && (val & 7))
+ as_warn ("`+r' assumes low three opcode bits to be clear");
+
+ for (j = 1; j < sizeof(val); ++j)
+ if (!(val >> (j * 8)))
+ break;
+
+ /* Trim off a prefix if present. */
+ if (j > 1 && !vex && !xop && !evex)
+ {
+ uint8_t byte = val >> ((j - 1) * 8);
+
+ switch (byte)
+ {
+ case DATA_PREFIX_OPCODE:
+ case REPE_PREFIX_OPCODE:
+ case REPNE_PREFIX_OPCODE:
+ if (!add_prefix (byte))
+ goto bad;
+ val &= ((uint64_t)1 << (--j * 8)) - 1;
+ break;
+ }
+ }
+
+ /* Trim off encoding space. */
+ if (j > 1 && !i.insn_opcode_space && (val >> ((j - 1) * 8)) == 0x0f)
+ {
+ uint8_t byte = val >> ((--j - 1) * 8);
+
+ i.insn_opcode_space = SPACE_0F;
+ switch (byte & -(j > 1))
+ {
+ case 0x38:
+ i.insn_opcode_space = SPACE_0F38;
+ --j;
+ break;
+ case 0x3a:
+ i.insn_opcode_space = SPACE_0F3A;
+ --j;
+ break;
+ }
+ i.tm.opcode_space = i.insn_opcode_space;
+ val &= ((uint64_t)1 << (j * 8)) - 1;
+ }
+ if (!i.tm.opcode_space && (vex || evex))
+ /* Arrange for build_vex_prefix() to properly emit 0xC4/0xC5.
+ Also avoid hitting abort() there or in build_evex_prefix(). */
+ i.tm.opcode_space = i.insn_opcode_space == SPACE_0F ? SPACE_0F
+ : SPACE_0F38;
+
+ if (j > 2)
+ {
+ as_bad (_("opcode residual (%#"PRIx64") too wide"), (uint64_t) val);
+ goto bad;
+ }
+ i.opcode_length = j;
+
+ /* Handle operands, if any. */
+ if (*line == ',')
+ {
+ i386_operand_type combined;
+ expressionS *disp_exp = NULL;
+ bool changed;
+
+ i.memshift = -1;
+
+ ptr = parse_operands (line + 1, &i386_mnemonics[MN__insn]);
+ this_operand = -1;
+ if (!ptr)
+ goto bad;
+ line = ptr;
+
+ if (!i.operands)
+ {
+ as_bad (_("expecting operand after ','; got nothing"));
+ goto done;
+ }
+
+ if (i.mem_operands > 1)
+ {
+ as_bad (_("too many memory references for `%s'"),
+ &i386_mnemonics[MN__insn]);
+ goto done;
+ }
+
+ /* No need to distinguish vex_encoding_evex and vex_encoding_evex512. */
+ if (i.vec_encoding == vex_encoding_evex512)
+ i.vec_encoding = vex_encoding_evex;
+
+ /* Are we to emit ModR/M encoding? */
+ if (!i.short_form
+ && (i.mem_operands
+ || i.reg_operands > (i.vec_encoding != vex_encoding_default)
+ || i.tm.extension_opcode != None))
+ i.tm.opcode_modifier.modrm = 1;
+
+ if (!i.tm.opcode_modifier.modrm
+ && (i.reg_operands
+ > i.short_form + 0U + (i.vec_encoding != vex_encoding_default)
+ || i.mem_operands))
+ {
+ as_bad (_("too many register/memory operands"));
+ goto done;
+ }
+
+ /* Enforce certain constraints on operands. */
+ switch (i.reg_operands + i.mem_operands
+ + (i.tm.extension_opcode != None))
+ {
+ case 0:
+ if (i.short_form)
+ {
+ as_bad (_("too few register/memory operands"));
+ goto done;
+ }
+ /* Fall through. */
+ case 1:
+ if (i.tm.opcode_modifier.modrm)
+ {
+ as_bad (_("too few register/memory operands"));
+ goto done;
+ }
+ break;
+
+ case 2:
+ break;
+
+ case 4:
+ if (i.imm_operands
+ && (i.op[0].imms->X_op != O_constant
+ || !fits_in_imm4 (i.op[0].imms->X_add_number)))
+ {
+ as_bad (_("constant doesn't fit in %d bits"), evex ? 3 : 4);
+ goto done;
+ }
+ /* Fall through. */
+ case 3:
+ if (i.vec_encoding != vex_encoding_default)
+ {
+ i.tm.opcode_modifier.vexvvvv = 1;
+ break;
+ }
+ /* Fall through. */
+ default:
+ as_bad (_("too many register/memory operands"));
+ goto done;
+ }
+
+ /* Bring operands into canonical order (imm, mem, reg). */
+ do
+ {
+ changed = false;
+
+ for (j = 1; j < i.operands; ++j)
+ {
+ if ((!operand_type_check (i.types[j - 1], imm)
+ && operand_type_check (i.types[j], imm))
+ || (i.types[j - 1].bitfield.class != ClassNone
+ && i.types[j].bitfield.class == ClassNone))
+ {
+ swap_2_operands (j - 1, j);
+ changed = true;
+ }
+ }
+ }
+ while (changed);
+
+ /* For Intel syntax swap the order of register operands. */
+ if (intel_syntax)
+ switch (i.reg_operands)
+ {
+ case 0:
+ case 1:
+ break;
+
+ case 4:
+ swap_2_operands (i.imm_operands + i.mem_operands + 1, i.operands - 2);
+ /* Fall through. */
+ case 3:
+ case 2:
+ swap_2_operands (i.imm_operands + i.mem_operands, i.operands - 1);
+ break;
+
+ default:
+ abort ();
+ }
+
+ /* Enforce constraints when using VSIB. */
+ if (i.index_reg
+ && (i.index_reg->reg_type.bitfield.xmmword
+ || i.index_reg->reg_type.bitfield.ymmword
+ || i.index_reg->reg_type.bitfield.zmmword))
+ {
+ if (i.vec_encoding == vex_encoding_default)
+ {
+ as_bad (_("VSIB unavailable with legacy encoding"));
+ goto done;
+ }
+
+ if (i.vec_encoding == vex_encoding_evex
+ && i.reg_operands > 1)
+ {
+ /* We could allow two register operands, encoding the 2nd one in
+ an 8-bit immediate like for 4-register-operand insns, but that
+ would require ugly fiddling with process_operands() and/or
+ build_modrm_byte(). */
+ as_bad (_("too many register operands with VSIB"));
+ goto done;
+ }
+
+ i.tm.opcode_modifier.sib = 1;
+ }
+
+ /* Establish operand size encoding. */
+ operand_type_set (&combined, 0);
+
+ for (j = i.imm_operands; j < i.operands; ++j)
+ {
+ i.types[j].bitfield.instance = InstanceNone;
+
+ if (operand_type_check (i.types[j], disp))
+ {
+ i.types[j].bitfield.baseindex = 1;
+ disp_exp = i.op[j].disps;
+ }
+
+ if (evex && i.types[j].bitfield.baseindex)
+ {
+ unsigned int n = i.memshift;
+
+ if (i.types[j].bitfield.byte)
+ n = 0;
+ else if (i.types[j].bitfield.word)
+ n = 1;
+ else if (i.types[j].bitfield.dword)
+ n = 2;
+ else if (i.types[j].bitfield.qword)
+ n = 3;
+ else if (i.types[j].bitfield.xmmword)
+ n = 4;
+ else if (i.types[j].bitfield.ymmword)
+ n = 5;
+ else if (i.types[j].bitfield.zmmword)
+ n = 6;
+
+ if (i.memshift < 32 && n != i.memshift)
+ as_warn ("conflicting memory operand size specifiers");
+ i.memshift = n;
+ }
+
+ if ((i.broadcast.type || i.broadcast.bytes)
+ && j == i.broadcast.operand)
+ continue;
+
+ combined = operand_type_or (combined, i.types[j]);
+ combined.bitfield.class = ClassNone;
+ }
+
+ switch ((i.broadcast.type ? i.broadcast.type : 1)
+ << (i.memshift < 32 ? i.memshift : 0))
+ {
+ case 64: combined.bitfield.zmmword = 1; break;
+ case 32: combined.bitfield.ymmword = 1; break;
+ case 16: combined.bitfield.xmmword = 1; break;
+ case 8: combined.bitfield.qword = 1; break;
+ case 4: combined.bitfield.dword = 1; break;
+ }
+
+ if (i.vec_encoding == vex_encoding_default)
+ {
+ if (flag_code == CODE_64BIT && combined.bitfield.qword)
+ i.rex |= REX_W;
+ else if ((flag_code == CODE_16BIT ? combined.bitfield.dword
+ : combined.bitfield.word)
+ && !add_prefix (DATA_PREFIX_OPCODE))
+ goto done;
+ }
+ else if (!i.tm.opcode_modifier.vexw)
+ {
+ if (flag_code == CODE_64BIT)
+ {
+ if (combined.bitfield.qword)
+ i.tm.opcode_modifier.vexw = VEXW1;
+ else if (combined.bitfield.dword)
+ i.tm.opcode_modifier.vexw = VEXW0;
+ }
+
+ if (!i.tm.opcode_modifier.vexw)
+ i.tm.opcode_modifier.vexw = VEXWIG;
+ }
- for (j = 0; j < ARRAY_SIZE (gotrel); j++)
- {
- int len = gotrel[j].len;
- if (strncasecmp (cp + 1, gotrel[j].str, len) == 0)
+ if (vex || xop)
{
- if (gotrel[j].rel[object_64bit] != 0)
+ if (!i.tm.opcode_modifier.vex)
{
- int first, second;
- char *tmpbuf, *past_reloc;
+ if (combined.bitfield.ymmword)
+ i.tm.opcode_modifier.vex = VEX256;
+ else if (combined.bitfield.xmmword)
+ i.tm.opcode_modifier.vex = VEX128;
+ }
+ }
+ else if (evex)
+ {
+ if (!i.tm.opcode_modifier.evex)
+ {
+ /* Do _not_ consider AVX512VL here. */
+ if (i.rounding.type != rc_none || combined.bitfield.zmmword)
+ i.tm.opcode_modifier.evex = EVEX512;
+ else if (combined.bitfield.ymmword)
+ i.tm.opcode_modifier.evex = EVEX256;
+ else if (combined.bitfield.xmmword)
+ i.tm.opcode_modifier.evex = EVEX128;
+ }
- *rel = gotrel[j].rel[object_64bit];
+ if (i.memshift >= 32)
+ {
+ unsigned int n = 0;
- if (types)
+ switch (i.tm.opcode_modifier.evex)
{
- if (flag_code != CODE_64BIT)
- {
- types->bitfield.imm32 = 1;
- types->bitfield.disp32 = 1;
- }
- else
- *types = gotrel[j].types64;
+ case EVEX512: n = 64; break;
+ case EVEX256: n = 32; break;
+ case EVEX128: n = 16; break;
}
- if (gotrel[j].need_GOT_symbol && GOT_symbol == NULL)
- GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
+ if (i.broadcast.type)
+ n /= i.broadcast.type;
+
+ if (n > 0)
+ for (i.memshift = 0; !(n & 1); n >>= 1)
+ ++i.memshift;
+ else if (disp_exp != NULL && disp_exp->X_op == O_constant
+ && disp_exp->X_add_number != 0
+ && i.disp_encoding != disp_encoding_32bit)
+ {
+ if (!quiet_warnings)
+ as_warn ("cannot determine memory operand size");
+ i.disp_encoding = disp_encoding_32bit;
+ }
+ }
+ }
- /* The length of the first part of our input line. */
- first = cp - input_line_pointer;
+ if (i.memshift >= 32)
+ i.memshift = 0;
+ else if (!evex)
+ i.vec_encoding = vex_encoding_error;
- /* The second part goes from after the reloc token until
- (and including) an end_of_line char or comma. */
- past_reloc = cp + 1 + len;
- cp = past_reloc;
- while (!is_end_of_line[(unsigned char) *cp] && *cp != ',')
- ++cp;
- second = cp + 1 - past_reloc;
+ if (i.disp_operands && !optimize_disp (&i.tm))
+ goto done;
- /* Allocate and copy string. The trailing NUL shouldn't
- be necessary, but be safe. */
- tmpbuf = XNEWVEC (char, first + second + 2);
- memcpy (tmpbuf, input_line_pointer, first);
- if (second != 0 && *past_reloc != ' ')
- /* Replace the relocation token with ' ', so that
- errors like foo@GOTOFF1 will be detected. */
- tmpbuf[first++] = ' ';
+ /* Establish size for immediate operands. */
+ for (j = 0; j < i.imm_operands; ++j)
+ {
+ expressionS *expP = i.op[j].imms;
+
+ gas_assert (operand_type_check (i.types[j], imm));
+ operand_type_set (&i.types[j], 0);
+
+ if (i.imm_bits[j] > 32)
+ i.types[j].bitfield.imm64 = 1;
+ else if (i.imm_bits[j] > 16)
+ {
+ if (flag_code == CODE_64BIT && (i.flags[j] & Operand_Signed))
+ i.types[j].bitfield.imm32s = 1;
else
- /* Increment length by 1 if the relocation token is
- removed. */
- len++;
- if (adjust)
- *adjust = len;
- memcpy (tmpbuf + first, past_reloc, second);
- tmpbuf[first + second] = '\0';
- return tmpbuf;
+ i.types[j].bitfield.imm32 = 1;
}
-
- as_bad (_("@%s reloc is not supported with %d-bit output format"),
- gotrel[j].str, 1 << (5 + object_64bit));
- return NULL;
+ else if (i.imm_bits[j] > 8)
+ i.types[j].bitfield.imm16 = 1;
+ else if (i.imm_bits[j] > 0)
+ {
+ if (i.flags[j] & Operand_Signed)
+ i.types[j].bitfield.imm8s = 1;
+ else
+ i.types[j].bitfield.imm8 = 1;
+ }
+ else if (expP->X_op == O_constant)
+ {
+ i.types[j] = smallest_imm_type (expP->X_add_number);
+ i.types[j].bitfield.imm1 = 0;
+ /* Oddly enough imm_size() checks imm64 first, so the bit needs
+ zapping since smallest_imm_type() sets it unconditionally. */
+ if (flag_code != CODE_64BIT)
+ {
+ i.types[j].bitfield.imm64 = 0;
+ i.types[j].bitfield.imm32s = 0;
+ i.types[j].bitfield.imm32 = 1;
+ }
+ else if (i.types[j].bitfield.imm32 || i.types[j].bitfield.imm32s)
+ i.types[j].bitfield.imm64 = 0;
+ }
+ else
+ /* Non-constant expressions are sized heuristically. */
+ switch (flag_code)
+ {
+ case CODE_64BIT: i.types[j].bitfield.imm32s = 1; break;
+ case CODE_32BIT: i.types[j].bitfield.imm32 = 1; break;
+ case CODE_16BIT: i.types[j].bitfield.imm16 = 1; break;
+ }
}
- }
- /* Might be a symbol version string. Don't as_bad here. */
- return NULL;
-}
-#endif
+ for (j = 0; j < i.operands; ++j)
+ i.tm.operand_types[j] = i.types[j];
-bfd_reloc_code_real_type
-x86_cons (expressionS *exp, int size)
-{
- bfd_reloc_code_real_type got_reloc = NO_RELOC;
+ process_operands ();
+ }
-#if ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \
- && !defined (LEX_AT)) \
- || defined (TE_PE)
- intel_syntax = -intel_syntax;
+ /* Don't set opcode until after processing operands, to avoid any
+ potential special casing there. */
+ i.tm.base_opcode |= val;
- exp->X_md = 0;
- if (size == 4 || (object_64bit && size == 8))
+ if (i.vec_encoding == vex_encoding_error
+ || (i.vec_encoding != vex_encoding_evex
+ ? i.broadcast.type || i.broadcast.bytes
+ || i.rounding.type != rc_none
+ || i.mask.reg
+ : (i.mem_operands && i.rounding.type != rc_none)
+ || ((i.broadcast.type || i.broadcast.bytes)
+ && !(i.flags[i.broadcast.operand] & Operand_Mem))))
{
- /* Handle @GOTOFF and the like in an expression. */
- char *save;
- char *gotfree_input_line;
- int adjust = 0;
-
- save = input_line_pointer;
- gotfree_input_line = lex_got (&got_reloc, &adjust, NULL);
- if (gotfree_input_line)
- input_line_pointer = gotfree_input_line;
+ as_bad (_("conflicting .insn operands"));
+ goto done;
+ }
- expression (exp);
+ if (vex || xop)
+ {
+ if (!i.tm.opcode_modifier.vex)
+ i.tm.opcode_modifier.vex = VEXScalar; /* LIG */
- if (gotfree_input_line)
- {
- /* expression () has merrily parsed up to the end of line,
- or a comma - in the wrong buffer. Transfer how far
- input_line_pointer has moved to the right buffer. */
- input_line_pointer = (save
- + (input_line_pointer - gotfree_input_line)
- + adjust);
- free (gotfree_input_line);
- if (exp->X_op == O_constant
- || exp->X_op == O_absent
- || exp->X_op == O_illegal
- || exp->X_op == O_register
- || exp->X_op == O_big)
- {
- char c = *input_line_pointer;
- *input_line_pointer = 0;
- as_bad (_("missing or invalid expression `%s'"), save);
- *input_line_pointer = c;
- }
- else if ((got_reloc == BFD_RELOC_386_PLT32
- || got_reloc == BFD_RELOC_X86_64_PLT32)
- && exp->X_op != O_symbol)
- {
- char c = *input_line_pointer;
- *input_line_pointer = 0;
- as_bad (_("invalid PLT expression `%s'"), save);
- *input_line_pointer = c;
- }
- }
+ build_vex_prefix (NULL);
+ i.rex &= REX_OPCODE;
}
- else
- expression (exp);
+ else if (evex)
+ {
+ if (!i.tm.opcode_modifier.evex)
+ i.tm.opcode_modifier.evex = EVEXLIG;
- intel_syntax = -intel_syntax;
+ build_evex_prefix ();
+ i.rex &= REX_OPCODE;
+ }
+ else if (i.rex != 0)
+ add_prefix (REX_OPCODE | i.rex);
- if (intel_syntax)
- i386_intel_simplify (exp);
-#else
- expression (exp);
-#endif
+ output_insn ();
- /* If not 64bit, massage value, to account for wraparound when !BFD64. */
- if (size == 4 && exp->X_op == O_constant && !object_64bit)
- exp->X_add_number = extend_to_32bit_address (exp->X_add_number);
+ done:
+ *saved_ilp = saved_char;
+ input_line_pointer = line;
- return got_reloc;
-}
+ demand_empty_rest_of_line ();
-static void
-signed_cons (int size)
-{
- if (object_64bit)
- cons_sign = 1;
- cons (size);
- cons_sign = -1;
+ /* Make sure dot_insn() won't yield "true" anymore. */
+ i.tm.mnem_off = 0;
}
#ifdef TE_PE
return NULL;
}
+ if (i.vec_encoding == vex_encoding_default)
+ i.vec_encoding = vex_encoding_evex512;
+ else if (i.vec_encoding != vex_encoding_evex
+ && i.vec_encoding != vex_encoding_evex512)
+ return NULL;
+
i.rounding.type = RC_NamesTable[j].type;
return (char *)(pstr + RC_NamesTable[j].len);
}
op_string++;
+ if (i.vec_encoding == vex_encoding_default)
+ i.vec_encoding = vex_encoding_evex;
+ else if (i.vec_encoding != vex_encoding_evex
+ && i.vec_encoding != vex_encoding_evex512)
+ goto unknown_vec_op;
+
i.broadcast.type = bcst_type;
i.broadcast.operand = this_operand;
+
+ /* For .insn a data size specifier may be appended. */
+ if (dot_insn () && *op_string == ':')
+ goto dot_insn_modifier;
+ }
+ /* Check .insn special cases. */
+ else if (dot_insn () && *op_string == ':')
+ {
+ dot_insn_modifier:
+ switch (op_string[1])
+ {
+ unsigned long n;
+
+ case 'd':
+ if (i.memshift < 32)
+ goto duplicated_vec_op;
+
+ n = strtoul (op_string + 2, &end_op, 0);
+ if (n)
+ for (i.memshift = 0; !(n & 1); n >>= 1)
+ ++i.memshift;
+ if (i.memshift < 32 && n == 1)
+ op_string = end_op;
+ break;
+
+ case 's': case 'u':
+ /* This isn't really a "vector" operation, but a sign/size
+ specifier for immediate operands of .insn. Note that AT&T
+ syntax handles the same in i386_immediate(). */
+ if (!intel_syntax)
+ break;
+
+ if (i.imm_bits[this_operand])
+ goto duplicated_vec_op;
+
+ n = strtoul (op_string + 2, &end_op, 0);
+ if (n && n <= (flag_code == CODE_64BIT ? 64 : 32))
+ {
+ i.imm_bits[this_operand] = n;
+ if (op_string[1] == 's')
+ i.flags[this_operand] |= Operand_Signed;
+ op_string = end_op;
+ }
+ break;
+ }
}
/* Check masking operation. */
else if ((mask = parse_register (op_string, &end_op)) != NULL)
if (gotfree_input_line)
input_line_pointer = gotfree_input_line;
+ expr_mode = expr_operator_none;
exp_seg = expression (exp);
+ /* For .insn immediates there may be a size specifier. */
+ if (dot_insn () && *input_line_pointer == '{' && input_line_pointer[1] == ':'
+ && (input_line_pointer[2] == 's' || input_line_pointer[2] == 'u'))
+ {
+ char *e;
+ unsigned long n = strtoul (input_line_pointer + 3, &e, 0);
+
+ if (*e == '}' && n && n <= (flag_code == CODE_64BIT ? 64 : 32))
+ {
+ i.imm_bits[this_operand] = n;
+ if (input_line_pointer[2] == 's')
+ i.flags[this_operand] |= Operand_Signed;
+ input_line_pointer = e + 1;
+ }
+ }
+
SKIP_WHITESPACE ();
if (*input_line_pointer)
as_bad (_("junk `%s' after expression"), input_line_pointer);
/* If not 64bit, sign/zero extend val, to account for wraparound
when !BFD64. */
- if (flag_code != CODE_64BIT)
+ if (expr_mode == expr_operator_present
+ && flag_code != CODE_64BIT && !object_64bit)
exp->X_add_number = extend_to_32bit_address (exp->X_add_number);
}
#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
if (gotfree_input_line)
input_line_pointer = gotfree_input_line;
+ expr_mode = expr_operator_none;
exp_seg = expression (exp);
SKIP_WHITESPACE ();
If not 64bit, sign/zero extend val, to account for wraparound
when !BFD64. */
- if (flag_code != CODE_64BIT)
+ if (expr_mode == expr_operator_present
+ && flag_code != CODE_64BIT && !object_64bit)
exp->X_add_number = extend_to_32bit_address (exp->X_add_number);
}
if (i.prefix[ADDR_PREFIX])
addr_mode = flag_code == CODE_32BIT ? CODE_16BIT : CODE_32BIT;
else if (flag_code == CODE_16BIT
- && current_templates->start->cpu_flags.bitfield.cpumpx
+ && is_cpu (current_templates->start, CpuMPX)
/* Avoid replacing the "16-bit addressing not allowed" diagnostic
from md_assemble() by "is not a valid base/index expression"
when there is a base and/or index. */
/* Memory operands of string insns are special in that they only allow
a single register (rDI, rSI, or rBX) as their memory address. */
const reg_entry *expected_reg;
- static const char *di_si[][2] =
+ static const char di_si[][2][4] =
{
{ "esi", "edi" },
{ "si", "di" },
{ "rsi", "rdi" }
};
- static const char *bx[] = { "ebx", "bx", "rbx" };
+ static const char bx[][4] = { "ebx", "bx", "rbx" };
kind = "string address";
goto bad_address;
/* bndmk, bndldx, bndstx and mandatory non-vector SIB have special restrictions. */
- if ((t->opcode_modifier.opcodeprefix == PREFIX_0XF3
- && t->opcode_modifier.opcodespace == SPACE_0F
- && t->base_opcode == 0x1b)
- || (t->opcode_modifier.opcodeprefix == PREFIX_NONE
- && t->opcode_modifier.opcodespace == SPACE_0F
- && (t->base_opcode & ~1) == 0x1a)
+ if (t->mnem_off == MN_bndmk
+ || t->mnem_off == MN_bndldx
+ || t->mnem_off == MN_bndstx
|| t->opcode_modifier.sib == SIBMEM)
{
/* They cannot use RIP-relative addressing. */
}
/* bndldx and bndstx ignore their scale factor. */
- if (t->opcode_modifier.opcodeprefix == PREFIX_NONE
- && t->opcode_modifier.opcodespace == SPACE_0F
- && (t->base_opcode & ~1) == 0x1a
+ if ((t->mnem_off == MN_bndldx || t->mnem_off == MN_bndstx)
&& i.log2_scale_factor)
as_warn (_("register scaling is being ignored here"));
}
static INLINE bool starts_memory_operand (char c)
{
return ISDIGIT (c)
- || is_identifier_char (c)
+ || is_name_beginner (c)
|| strchr ("([\"+-!~", c);
}
/* We check for an absolute prefix (differentiating,
for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */
- if (*op_string == ABSOLUTE_PREFIX)
+ if (*op_string == ABSOLUTE_PREFIX
+ && current_templates->start->opcode_modifier.jump)
{
++op_string;
if (is_space_char (*op_string))
++op_string;
/* Handle case of %es:*foo. */
- if (!i.jumpabsolute && *op_string == ABSOLUTE_PREFIX)
+ if (!i.jumpabsolute && *op_string == ABSOLUTE_PREFIX
+ && current_templates->start->opcode_modifier.jump)
{
++op_string;
if (is_space_char (*op_string))
as_bad (_("junk `%s' after register"), op_string);
return 0;
}
+
+ /* Reject pseudo registers for .insn. */
+ if (dot_insn () && r->reg_type.bitfield.class == ClassNone)
+ {
+ as_bad (_("`%s%s' cannot be used here"),
+ register_prefix, r->reg_name);
+ return 0;
+ }
+
temp = r->reg_type;
temp.bitfield.baseindex = 0;
i.types[this_operand] = operand_type_or (i.types[this_operand],
else if (size == 2)
reloc_type = BFD_RELOC_16_PCREL;
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
- else if (fragP->tc_frag_data.code64 && fragP->fr_offset == 0
+ else if (fragP->tc_frag_data.code == CODE_64BIT
+ && fragP->fr_offset == 0
&& need_plt32_p (fragP->fr_symbol))
reloc_type = BFD_RELOC_X86_64_PLT32;
#endif
}
}
+ if (r->reg_type.bitfield.zmmword)
+ {
+ if (vector_size < VSZ512)
+ return false;
+
+ if (i.vec_encoding == vex_encoding_default)
+ i.vec_encoding = vex_encoding_evex512;
+ else if (i.vec_encoding != vex_encoding_evex
+ && i.vec_encoding != vex_encoding_evex512)
+ i.vec_encoding = vex_encoding_error;
+ }
+
+ if (vector_size < VSZ256 && r->reg_type.bitfield.ymmword)
+ return false;
+
if (r->reg_type.bitfield.tmmword
&& (!cpu_arch_flags.bitfield.cpuamx_tile
|| flag_code != CODE_64BIT))
|| flag_code != CODE_64BIT)
return false;
- if (i.vec_encoding == vex_encoding_default)
+ if (i.vec_encoding == vex_encoding_default
+ || i.vec_encoding == vex_encoding_evex512)
i.vec_encoding = vex_encoding_evex;
else if (i.vec_encoding != vex_encoding_evex)
i.vec_encoding = vex_encoding_error;
}
if (((r->reg_flags & (RegRex64 | RegRex)) || r->reg_type.bitfield.qword)
- && (!cpu_arch_flags.bitfield.cpulm || r->reg_type.bitfield.class != RegCR)
+ && (!cpu_arch_flags.bitfield.cpu64
+ || r->reg_type.bitfield.class != RegCR
+ || dot_insn ())
&& flag_code != CODE_64BIT)
return false;
/* REG_STRING starts *before* REGISTER_PREFIX. */
static const reg_entry *
-parse_real_register (char *reg_string, char **end_op)
+parse_real_register (const char *reg_string, char **end_op)
{
- char *s = reg_string;
+ const char *s = reg_string;
char *p;
char reg_name_given[MAX_REG_NAME_SIZE + 1];
const reg_entry *r;
s++;
}
- /* For naked regs, make sure that we are not dealing with an identifier.
- This prevents confusing an identifier like `eax_var' with register
- `eax'. */
- if (allow_naked_reg && identifier_chars[(unsigned char) *s])
+ if (is_part_of_name (*s))
return (const reg_entry *) NULL;
- *end_op = s;
+ *end_op = (char *) s;
r = (const reg_entry *) str_hash_find (reg_hash, reg_name_given);
++s;
if (*s == ')')
{
- *end_op = s + 1;
+ *end_op = (char *) s + 1;
know (r[fpr].reg_num == fpr);
return r + fpr;
}
/* REG_STRING starts *before* REGISTER_PREFIX. */
static const reg_entry *
-parse_register (char *reg_string, char **end_op)
+parse_register (const char *reg_string, char **end_op)
{
const reg_entry *r;
if (!r)
{
char *save = input_line_pointer;
- char c;
+ char *buf = xstrdup (reg_string), *name;
symbolS *symbolP;
- input_line_pointer = reg_string;
- c = get_symbol_name (®_string);
- symbolP = symbol_find (reg_string);
- while (symbolP && S_GET_SEGMENT (symbolP) != reg_section)
+ input_line_pointer = buf;
+ get_symbol_name (&name);
+ symbolP = symbol_find (name);
+ while (symbolP && symbol_equated_p (symbolP))
{
const expressionS *e = symbol_get_value_expression(symbolP);
- if (e->X_op != O_symbol || e->X_add_number)
+ if (e->X_add_number)
break;
symbolP = e->X_add_symbol;
}
{
const expressionS *e = symbol_get_value_expression (symbolP);
- know (e->X_op == O_register);
- know (e->X_add_number >= 0
- && (valueT) e->X_add_number < i386_regtab_size);
- r = i386_regtab + e->X_add_number;
- if (!check_register (r))
+ if (e->X_op == O_register)
+ {
+ know (e->X_add_number >= 0
+ && (valueT) e->X_add_number < i386_regtab_size);
+ r = i386_regtab + e->X_add_number;
+ *end_op = (char *) reg_string + (input_line_pointer - buf);
+ }
+ if (r && !check_register (r))
{
as_bad (_("register '%s%s' cannot be used here"),
register_prefix, r->reg_name);
r = &bad_reg;
}
- *end_op = input_line_pointer;
}
- *input_line_pointer = c;
input_line_pointer = save;
+ free (buf);
}
return r;
}
const reg_entry *r = NULL;
char *end = input_line_pointer;
+ /* We only know the terminating character here. It being double quote could
+ be the closing one of a quoted symbol name, or an opening one from a
+ following string (or another quoted symbol name). Since the latter can't
+ be valid syntax for anything, bailing in either case is good enough. */
+ if (*nextcharP == '"')
+ return 0;
+
*end = *nextcharP;
if (*name == REGISTER_PREFIX || allow_naked_reg)
r = parse_real_register (name, &input_line_pointer);
{
*nextcharP = *input_line_pointer;
*input_line_pointer = 0;
- if (r != &bad_reg)
- {
- e->X_op = O_register;
- e->X_add_number = r - i386_regtab;
- }
- else
- e->X_op = O_illegal;
+ e->X_op = O_register;
+ e->X_add_number = r - i386_regtab;
return 1;
}
input_line_pointer = end;
}
}
+#ifdef BFD64
+/* To maintain consistency with !BFD64 builds of gas record, whether any
+ (binary) operator was involved in an expression. As expressions are
+ evaluated in only 32 bits when !BFD64, we use this to decide whether to
+ truncate results. */
+bool i386_record_operator (operatorT op,
+ const expressionS *left,
+ const expressionS *right)
+{
+ if (op == O_absent)
+ return false;
+
+ if (!left)
+ {
+ /* Since the expression parser applies unary operators fine to bignum
+ operands, we don't need to be concerned of respective operands not
+ fitting in 32 bits. */
+ if (right->X_op == O_constant && right->X_unsigned
+ && !fits_in_unsigned_long (right->X_add_number))
+ return false;
+ }
+ /* This isn't entirely right: The pattern can also result when constant
+ expressions are folded (e.g. 0xffffffff + 1). */
+ else if ((left->X_op == O_constant && left->X_unsigned
+ && !fits_in_unsigned_long (left->X_add_number))
+ || (right->X_op == O_constant && right->X_unsigned
+ && !fits_in_unsigned_long (right->X_add_number)))
+ expr_mode = expr_large_value;
+
+ if (expr_mode != expr_large_value)
+ expr_mode = expr_operator_present;
+
+ return false;
+}
+#endif
\f
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
const char *md_shortopts = "kVQ:sqnO::";
#endif
case OPTION_32:
- default_arch = "i386";
+ {
+ const char **list, **l;
+
+ list = bfd_target_list ();
+ for (l = list; *l != NULL; l++)
+ if (strstr (*l, "-i386")
+ || strstr (*l, "-go32"))
+ {
+ default_arch = "i386";
+ break;
+ }
+ if (*l == NULL)
+ as_fatal (_("no compiled in support for ix86"));
+ free (list);
+ }
break;
case OPTION_DIVIDE:
arch++;
do
{
+ char *vsz;
+
if (*arch == '.')
as_fatal (_("invalid -march= option: `%s'"), arg);
next = strchr (arch, '+');
if (next)
*next++ = '\0';
+ vsz = strchr (arch, '/');
+ if (vsz)
+ *vsz++ = '\0';
for (j = 0; j < ARRAY_SIZE (cpu_arch); j++)
{
+ if (vsz && cpu_arch[j].vsz != vsz_set)
+ continue;
+
if (arch == saved && cpu_arch[j].type != PROCESSOR_NONE
&& strcmp (arch, cpu_arch[j].name) == 0)
{
cpu_arch_isa = cpu_arch[j].type;
cpu_arch_isa_flags = cpu_arch[j].enable;
if (!cpu_arch_tune_set)
- {
- cpu_arch_tune = cpu_arch_isa;
- cpu_arch_tune_flags = cpu_arch_isa_flags;
- }
+ cpu_arch_tune = cpu_arch_isa;
+ vector_size = VSZ_DEFAULT;
break;
}
else if (cpu_arch[j].type == PROCESSOR_NONE
&& !cpu_flags_all_zero (&cpu_arch[j].enable))
{
/* ISA extension. */
- i386_cpu_flags flags;
-
- flags = cpu_flags_or (cpu_arch_flags,
- cpu_arch[j].enable);
+ isa_enable (j);
- if (!cpu_flags_equal (&flags, &cpu_arch_flags))
+ switch (cpu_arch[j].vsz)
{
- extend_cpu_sub_arch_name (arch);
- cpu_arch_flags = flags;
- cpu_arch_isa_flags = flags;
+ default:
+ break;
+
+ case vsz_set:
+ if (vsz)
+ {
+ char *end;
+ unsigned long val = strtoul (vsz, &end, 0);
+
+ if (*end)
+ val = 0;
+ switch (val)
+ {
+ case 512: vector_size = VSZ512; break;
+ case 256: vector_size = VSZ256; break;
+ case 128: vector_size = VSZ128; break;
+ default:
+ as_warn (_("Unrecognized vector size specifier ignored"));
+ break;
+ }
+ break;
+ }
+ /* Fall through. */
+ case vsz_reset:
+ vector_size = VSZ_DEFAULT;
+ break;
}
- else
- cpu_arch_isa_flags
- = cpu_flags_or (cpu_arch_isa_flags,
- cpu_arch[j].enable);
+
break;
}
}
if (cpu_arch[j].type == PROCESSOR_NONE
&& strcmp (arch + 2, cpu_arch[j].name) == 0)
{
- i386_cpu_flags flags;
-
- flags = cpu_flags_and_not (cpu_arch_flags,
- cpu_arch[j].disable);
- if (!cpu_flags_equal (&flags, &cpu_arch_flags))
- {
- extend_cpu_sub_arch_name (arch);
- cpu_arch_flags = flags;
- cpu_arch_isa_flags = flags;
- }
+ isa_disable (j);
+ if (cpu_arch[j].vsz == vsz_set)
+ vector_size = VSZ_DEFAULT;
break;
}
}
{
cpu_arch_tune_set = 1;
cpu_arch_tune = cpu_arch [j].type;
- cpu_arch_tune_flags = cpu_arch[j].enable;
break;
}
}
cpu_arch_isa = PROCESSOR_IAMCU;
cpu_arch_isa_flags = iamcu_flags;
if (!cpu_arch_tune_set)
- {
- cpu_arch_tune = cpu_arch_isa;
- cpu_arch_tune_flags = cpu_arch_isa_flags;
- }
+ cpu_arch_tune = PROCESSOR_IAMCU;
}
else if (cpu_arch_isa != PROCESSOR_IAMCU)
as_fatal (_("Intel MCU doesn't support `%s' architecture"),
if (cpu_flags_all_zero (&cpu_arch_isa_flags))
cpu_arch_isa_flags = cpu_arch[flag_code == CODE_64BIT].enable;
- if (cpu_flags_all_zero (&cpu_arch_tune_flags))
- cpu_arch_tune_flags = cpu_arch[flag_code == CODE_64BIT].enable;
switch (OUTPUT_FLAVOR)
{
return -1;
}
-bfd_vma
-x86_64_section_word (char *str, size_t len)
-{
- if (len == 5 && flag_code == CODE_64BIT && startswith (str, "large"))
- return SHF_X86_64_LARGE;
-
- return -1;
-}
-
static void
handle_large_common (int small ATTRIBUTE_UNUSED)
{