/* tc-i386.c -- Assemble code for the Intel 80386
Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#define INFER_ADDR_PREFIX 1
#endif
-#ifndef SCALE1_WHEN_NO_INDEX
-/* Specifying a scale factor besides 1 when there is no index is
- futile. eg. `mov (%ebx,2),%al' does exactly the same as
- `mov (%ebx),%al'. To slavishly follow what the programmer
- specified, set SCALE1_WHEN_NO_INDEX to 0. */
-#define SCALE1_WHEN_NO_INDEX 1
-#endif
-
#ifndef DEFAULT_ARCH
#define DEFAULT_ARCH "i386"
#endif
static void set_code_flag (int);
static void set_16bit_gcc_code_flag (int);
static void set_intel_syntax (int);
+static void set_intel_mnemonic (int);
+static void set_allow_index_reg (int);
static void set_cpu_arch (int);
#ifdef TE_PE
static void pe_directive_secrel (int);
#endif
static void signed_cons (int);
static char *output_invalid (int c);
-static int i386_operand (char *);
+static int i386_att_operand (char *);
static int i386_intel_operand (char *, int);
static const reg_entry *parse_register (char *, char **);
static char *parse_insn (char *, char *);
static int check_qword_reg (void);
static int check_word_reg (void);
static int finalize_imm (void);
+static void process_drex (void);
static int process_operands (void);
static const seg_entry *build_modrm_byte (void);
static void output_insn (void);
unsigned char prefix[MAX_PREFIXES];
/* RM and SIB are the modrm byte and the sib byte where the
- addressing modes of this insn are encoded. */
+ addressing modes of this insn are encoded. DREX is the byte
+ added by the SSE5 instructions. */
modrm_byte rm;
rex_byte rex;
sib_byte sib;
+ drex_byte drex;
};
typedef struct _i386_insn i386_insn;
CODE_32BIT,
CODE_16BIT,
CODE_64BIT };
-#define NUM_FLAG_CODE ((int) CODE_64BIT + 1)
static enum flag_code flag_code;
static unsigned int object_64bit;
0 if att syntax. */
static int intel_syntax = 0;
+/* 1 for intel mnemonic,
+ 0 if att mnemonic. */
+static int intel_mnemonic = !SYSV386_COMPAT;
+
+/* 1 if support old (<= 2.8.1) versions of gcc. */
+static int old_gcc = OLDGCC_COMPAT;
+
/* 1 if register prefix % not required. */
static int allow_naked_reg = 0;
+/* 1 if pseudo index register, eiz/riz, is allowed . */
+static int allow_index_reg = 0;
+
/* Register prefix used for error message. */
static const char *register_prefix = "%";
/* CPU feature flags. */
static i386_cpu_flags cpu_arch_flags = CPU_UNKNOWN_FLAGS;
-/* Bitwise NOT of cpu_arch_flags. */
-static i386_cpu_flags cpu_arch_flags_not;
-
/* If we have selected a cpu we are generating instructions for. */
static int cpu_arch_tune_set = 0;
CPU_SSE4A_FLAGS },
{".abm", PROCESSOR_UNKNOWN,
CPU_ABM_FLAGS },
+ {".sse5", PROCESSOR_UNKNOWN,
+ CPU_SSE5_FLAGS },
};
const pseudo_typeS md_pseudo_table[] =
{"code64", set_code_flag, CODE_64BIT},
{"intel_syntax", set_intel_syntax, 1},
{"att_syntax", set_intel_syntax, 0},
+ {"intel_mnemonic", set_intel_mnemonic, 1},
+ {"att_mnemonic", set_intel_mnemonic, 0},
+ {"allow_index_reg", set_allow_index_reg, 1},
+ {"disallow_index_reg", set_allow_index_reg, 0},
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
{"largecomm", handle_large_common, 0},
#else
}
static INLINE i386_cpu_flags
-cpu_flags_not (i386_cpu_flags x)
-{
- switch (ARRAY_SIZE (x.array))
- {
- case 3:
- x.array [2] = ~x.array [2];
- case 2:
- x.array [1] = ~x.array [1];
- case 1:
- x.array [0] = ~x.array [0];
- break;
- default:
- abort ();
- }
-
-#ifdef CpuUnused
- x.bitfield.unused = 0;
-#endif
-
- return x;
-}
-
-static INLINE i386_cpu_flags
cpu_flags_and (i386_cpu_flags x, i386_cpu_flags y)
{
switch (ARRAY_SIZE (x.array))
return x;
}
+/* Return 3 if there is a perfect match, 2 if compatible with 64bit,
+ 1 if compatible with arch, 0 if there is no match. */
+
static int
cpu_flags_match (i386_cpu_flags x)
{
- i386_cpu_flags not = cpu_arch_flags_not;
-
- not.bitfield.cpu64 = 1;
- not.bitfield.cpuno64 = 1;
+ int overlap = cpu_flags_check_cpu64 (x) ? 2 : 0;
x.bitfield.cpu64 = 0;
x.bitfield.cpuno64 = 0;
- not = cpu_flags_and (x, not);
- return UINTS_ALL_ZERO (not);
+ if (UINTS_ALL_ZERO (x))
+ overlap |= 1;
+ else
+ {
+ i386_cpu_flags cpu = cpu_arch_flags;
+
+ cpu.bitfield.cpu64 = 0;
+ cpu.bitfield.cpuno64 = 0;
+ cpu = cpu_flags_and (x, cpu);
+ overlap |= UINTS_ALL_ZERO (cpu) ? 0 : 1;
+ }
+ return overlap;
}
static INLINE i386_operand_type
static const i386_operand_type disp16_32 = OPERAND_TYPE_DISP16_32;
static const i386_operand_type anydisp
= OPERAND_TYPE_ANYDISP;
-static const i386_operand_type baseindex = OPERAND_TYPE_BASEINDEX;
static const i386_operand_type regxmm = OPERAND_TYPE_REGXMM;
static const i386_operand_type imm8 = OPERAND_TYPE_IMM8;
static const i386_operand_type imm8s = OPERAND_TYPE_IMM8S;
{
cpu_arch_flags.bitfield.cpu64 = 1;
cpu_arch_flags.bitfield.cpuno64 = 0;
- cpu_arch_flags_not.bitfield.cpu64 = 0;
- cpu_arch_flags_not.bitfield.cpuno64 = 1;
}
else
{
cpu_arch_flags.bitfield.cpu64 = 0;
cpu_arch_flags.bitfield.cpuno64 = 1;
- cpu_arch_flags_not.bitfield.cpu64 = 1;
- cpu_arch_flags_not.bitfield.cpuno64 = 0;
}
if (value == CODE_64BIT && !cpu_arch_flags.bitfield.cpulm )
{
abort ();
cpu_arch_flags.bitfield.cpu64 = 0;
cpu_arch_flags.bitfield.cpuno64 = 1;
- cpu_arch_flags_not.bitfield.cpu64 = 1;
- cpu_arch_flags_not.bitfield.cpuno64 = 0;
stackop_size = LONG_MNEM_SUFFIX;
}
}
static void
+set_intel_mnemonic (int mnemonic_flag)
+{
+ intel_mnemonic = mnemonic_flag;
+}
+
+static void
+set_allow_index_reg (int flag)
+{
+ allow_index_reg = flag;
+}
+
+static void
set_cpu_arch (int dummy ATTRIBUTE_UNUSED)
{
SKIP_WHITESPACE ();
cpu_arch_flags.bitfield.cpu64 = 0;
cpu_arch_flags.bitfield.cpuno64 = 1;
}
- cpu_arch_flags_not = cpu_flags_not (cpu_arch_flags);
cpu_arch_isa = cpu_arch[i].type;
cpu_arch_isa_flags = cpu_arch[i].flags;
if (!cpu_arch_tune_set)
{
cpu_sub_arch_name = cpu_arch[i].name;
cpu_arch_flags = flags;
- cpu_arch_flags_not = cpu_flags_not (cpu_arch_flags);
}
*input_line_pointer = e;
demand_empty_rest_of_line ();
{
const char *hash_err;
- cpu_arch_flags_not = cpu_flags_not (cpu_arch_flags);
-
/* Initialize op_hash hash table. */
op_hash = hash_new ();
(x->rex & REX_R) != 0,
(x->rex & REX_X) != 0,
(x->rex & REX_B) != 0);
+ fprintf (stdout, " drex: reg %d rex 0x%x\n",
+ x->drex.reg, x->drex.rex);
for (i = 0; i < x->operands; i++)
{
fprintf (stdout, " #%d: ", i + 1);
if (line == NULL)
return;
- /* The order of the immediates should be reversed
- for 2 immediates extrq and insertq instructions */
- if ((i.imm_operands == 2)
- && ((strcmp (mnemonic, "extrq") == 0)
- || (strcmp (mnemonic, "insertq") == 0)))
- {
- swap_2_operands (0, 1);
- /* "extrq" and insertq" are the only two instructions whose operands
- have to be reversed even though they have two immediate operands.
- */
- if (intel_syntax)
- swap_operands ();
- }
-
/* Now we've parsed the mnemonic into a set of templates, and have the
operands at hand. */
&& operand_type_check (i.types[1], imm)))
swap_operands ();
+ /* The order of the immediates should be reversed
+ for 2 immediates extrq and insertq instructions */
+ if (i.imm_operands == 2
+ && (strcmp (mnemonic, "extrq") == 0
+ || strcmp (mnemonic, "insertq") == 0))
+ swap_2_operands (0, 1);
+
if (i.imm_operands)
optimize_imm ();
if (intel_syntax)
{
- /* Undo SYSV386_COMPAT brokenness when in Intel mode. See i386.h */
- if (SYSV386_COMPAT
- && (i.tm.base_opcode & 0xfffffde0) == 0xdce0)
- i.tm.base_opcode ^= Opcode_FloatR;
-
/* Zap movzx and movsx suffix. The suffix may have been set from
"word ptr" or "byte ptr" on the source operand, but we'll use
the suffix later to choose the destination register. */
|| !i.tm.opcode_modifier.no_wsuf
|| !i.tm.opcode_modifier.no_lsuf
|| !i.tm.opcode_modifier.no_ssuf
- || !i.tm.opcode_modifier.no_xsuf
+ || !i.tm.opcode_modifier.no_ldsuf
|| !i.tm.opcode_modifier.no_qsuf))
as_bad (_("ambiguous operand size for `%s'"), i.tm.name);
/* These AMD 3DNow! and Intel Katmai New Instructions have an
opcode suffix which is coded in the same place as an 8-bit
immediate field would be. Here we fake an 8-bit immediate
- operand from the opcode suffix stored in tm.extension_opcode. */
+ operand from the opcode suffix stored in tm.extension_opcode.
+ SSE5 also uses this encoding, for some of its 3 argument
+ instructions. */
- assert (i.imm_operands == 0 && i.operands <= 2 && 2 < MAX_OPERANDS);
+ assert (i.imm_operands == 0
+ && (i.operands <= 2
+ || (i.tm.cpu_flags.bitfield.cpusse5
+ && i.operands <= 3)));
exp = &im_expressions[i.imm_operands++];
i.op[i.operands].imms = exp;
}
}
- if (i.rex != 0)
+ /* If the instruction has the DREX attribute (aka SSE5), don't emit a
+ REX prefix. */
+ if (i.tm.opcode_modifier.drex || i.tm.opcode_modifier.drexc)
+ {
+ i.drex.rex = i.rex;
+ i.rex = 0;
+ }
+ else if (i.rex != 0)
add_prefix (REX_OPCODE | i.rex);
/* We are ready to output the insn. */
supported = 0;
for (t = current_templates->start; t < current_templates->end; ++t)
{
- if (cpu_flags_match (t->cpu_flags))
- supported |= 1;
- if (cpu_flags_check_cpu64 (t->cpu_flags))
- supported |= 2;
+ supported |= cpu_flags_match (t->cpu_flags);
+ if (supported == 3)
+ goto skip;
}
+
if (!(supported & 2))
{
as_bad (flag_code == CODE_64BIT
}
if (!(supported & 1))
{
- as_warn (_("`%s' is not supported on `%s%s'"),
- current_templates->start->name,
- cpu_arch_name,
- cpu_sub_arch_name ? cpu_sub_arch_name : "");
+ as_bad (_("`%s' is not supported on `%s%s'"),
+ current_templates->start->name, cpu_arch_name,
+ cpu_sub_arch_name ? cpu_sub_arch_name : "");
+ return NULL;
}
- else if (!cpu_arch_flags.bitfield.cpui386
+
+skip:
+ if (!cpu_arch_flags.bitfield.cpui386
&& (flag_code != CODE_16BIT))
{
as_warn (_("use .code16 to ensure correct addressing mode"));
i386_intel_operand (token_start,
intel_float_operand (mnemonic));
else
- operand_ok = i386_operand (token_start);
+ operand_ok = i386_att_operand (token_start);
RESTORE_END_STRING (l);
if (!operand_ok)
i386_operand_type operand_types [MAX_OPERANDS];
int addr_prefix_disp;
unsigned int j;
- i386_cpu_flags overlap;
+ unsigned int found_cpu_match;
+ unsigned int check_register;
#if MAX_OPERANDS != 4
# error "MAX_OPERANDS must be 4."
else if (i.suffix == QWORD_MNEM_SUFFIX)
suffix_check.no_qsuf = 1;
else if (i.suffix == LONG_DOUBLE_MNEM_SUFFIX)
- suffix_check.no_xsuf = 1;
+ suffix_check.no_ldsuf = 1;
+ else if (i.suffix == XMMWORD_MNEM_SUFFIX)
+ suffix_check.xmmword = 1;
for (t = current_templates->start; t < current_templates->end; t++)
{
if (i.operands != t->operands)
continue;
+ /* Check old gcc support. */
+ if (!old_gcc && t->opcode_modifier.oldgcc)
+ continue;
+
+ /* Check AT&T mnemonic. */
+ if (intel_mnemonic && t->opcode_modifier.attmnemonic)
+ continue;
+
+ /* Check Intel syntax. */
+ if (intel_syntax && t->opcode_modifier.attsyntax)
+ continue;
+
/* Check the suffix, except for some instructions in intel mode. */
- if (((t->opcode_modifier.no_bsuf & suffix_check.no_bsuf)
- || (t->opcode_modifier.no_wsuf & suffix_check.no_wsuf)
- || (t->opcode_modifier.no_lsuf & suffix_check.no_lsuf)
- || (t->opcode_modifier.no_ssuf & suffix_check.no_ssuf)
- || (t->opcode_modifier.no_qsuf & suffix_check.no_qsuf)
- || (t->opcode_modifier.no_xsuf & suffix_check.no_xsuf))
- && !(intel_syntax && t->opcode_modifier.ignoresize))
+ if ((!intel_syntax || !t->opcode_modifier.ignoresize)
+ && ((t->opcode_modifier.no_bsuf && suffix_check.no_bsuf)
+ || (t->opcode_modifier.no_wsuf && suffix_check.no_wsuf)
+ || (t->opcode_modifier.no_lsuf && suffix_check.no_lsuf)
+ || (t->opcode_modifier.no_ssuf && suffix_check.no_ssuf)
+ || (t->opcode_modifier.no_qsuf && suffix_check.no_qsuf)
+ || (t->opcode_modifier.no_ldsuf && suffix_check.no_ldsuf)))
+ continue;
+
+ /* Check the memory size in Intel mode when it is provided if
+ needed. */
+ if (intel_syntax
+ && i.suffix
+ && t->opcode_modifier.checksize
+ && (!t->opcode_modifier.byte || !suffix_check.no_bsuf)
+ && (!t->opcode_modifier.word || !suffix_check.no_wsuf)
+ && (!t->opcode_modifier.dword || !suffix_check.no_lsuf)
+ && (!t->opcode_modifier.qword || !suffix_check.no_qsuf)
+ && (!t->opcode_modifier.xmmword || !suffix_check.xmmword))
continue;
for (j = 0; j < MAX_OPERANDS; j++)
/* Do not verify operands when there are none. */
else
{
- overlap = cpu_flags_and (t->cpu_flags, cpu_arch_flags_not);
+ found_cpu_match = cpu_flags_match (t->cpu_flags) == 3;
if (!t->operands)
{
- if (!UINTS_ALL_ZERO (overlap))
+ if (!found_cpu_match)
continue;
/* We've found a match; break out of loop. */
break;
}
}
+ /* We check register size only if size of operands can be
+ encoded the canonical way. */
+ check_register = t->opcode_modifier.w;
overlap0 = operand_type_and (i.types[0], operand_types[0]);
switch (t->operands)
{
overlap1 = operand_type_and (i.types[1], operand_types[1]);
if (!operand_type_match (overlap0, i.types[0])
|| !operand_type_match (overlap1, i.types[1])
- /* monitor in SSE3 is a very special case. The first
- register and the second register may have different
- sizes. The same applies to crc32 in SSE4.2. It is
- also true for invlpga, vmload, vmrun and vmsave in
- SVME. */
- || !((t->base_opcode == 0x0f01
- && (t->extension_opcode == 0xc8
- || t->extension_opcode == 0xd8
- || t->extension_opcode == 0xda
- || t->extension_opcode == 0xdb
- || t->extension_opcode == 0xdf))
- || t->base_opcode == 0xf20f38f1
- || operand_type_register_match (overlap0, i.types[0],
+ || (check_register
+ && !operand_type_register_match (overlap0, i.types[0],
operand_types[0],
overlap1, i.types[1],
operand_types[1])))
overlap1 = operand_type_and (i.types[1], operand_types[0]);
if (!operand_type_match (overlap0, i.types[0])
|| !operand_type_match (overlap1, i.types[1])
- || !operand_type_register_match (overlap0, i.types[0],
- operand_types[1],
- overlap1, i.types[1],
- operand_types[0]))
+ || (check_register
+ && !operand_type_register_match (overlap0,
+ i.types[0],
+ operand_types[1],
+ overlap1,
+ i.types[1],
+ operand_types[0])))
{
/* Does not match either direction. */
continue;
{
case 4:
if (!operand_type_match (overlap3, i.types[3])
- || !operand_type_register_match (overlap2,
- i.types[2],
- operand_types[2],
- overlap3,
- i.types[3],
- operand_types[3]))
+ || (check_register
+ && !operand_type_register_match (overlap2,
+ i.types[2],
+ operand_types[2],
+ overlap3,
+ i.types[3],
+ operand_types[3])))
continue;
case 3:
/* Here we make use of the fact that there are no
operand instructions only need to be checked for
register consistency between operands 2 and 3. */
if (!operand_type_match (overlap2, i.types[2])
- || !operand_type_register_match (overlap1,
- i.types[1],
- operand_types[1],
- overlap2,
- i.types[2],
- operand_types[2]))
+ || (check_register
+ && !operand_type_register_match (overlap1,
+ i.types[1],
+ operand_types[1],
+ overlap2,
+ i.types[2],
+ operand_types[2])))
continue;
break;
}
/* Found either forward/reverse 2, 3 or 4 operand match here:
slip through to break. */
}
- if (!UINTS_ALL_ZERO (overlap))
+ if (!found_cpu_match)
{
found_reverse_match = 0;
continue;
}
else if (i.suffix == QWORD_MNEM_SUFFIX)
{
- if (!check_qword_reg ())
+ if (intel_syntax
+ && i.tm.opcode_modifier.ignoresize
+ && i.tm.opcode_modifier.no_qsuf)
+ i.suffix = 0;
+ else if (!check_qword_reg ())
return 0;
}
else if (i.suffix == WORD_MNEM_SUFFIX)
if (!check_word_reg ())
return 0;
}
+ else if (i.suffix == XMMWORD_MNEM_SUFFIX)
+ {
+ /* Skip if the instruction has x suffix. match_template
+ should check if it is a valid suffix. */
+ }
else if (intel_syntax && i.tm.opcode_modifier.ignoresize)
/* Do nothing if the instruction is going to ignore the prefix. */
;
suffixes |= 1 << 1;
if (!i.tm.opcode_modifier.no_lsuf)
suffixes |= 1 << 2;
- if (!i.tm.opcode_modifier.no_lsuf)
+ if (!i.tm.opcode_modifier.no_ldsuf)
suffixes |= 1 << 3;
if (!i.tm.opcode_modifier.no_ssuf)
suffixes |= 1 << 4;
/* Change the opcode based on the operand size given by i.suffix;
We don't need to change things for byte insns. */
- if (i.suffix && i.suffix != BYTE_MNEM_SUFFIX)
+ if (i.suffix
+ && i.suffix != BYTE_MNEM_SUFFIX
+ && i.suffix != XMMWORD_MNEM_SUFFIX)
{
/* It's not a byte, select word/dword operation. */
if (i.tm.opcode_modifier.w)
/* Now select between word & dword operations via the operand
size prefix, except for instructions that will ignore this
prefix anyway. */
- if (i.tm.base_opcode == 0x0f01
- && (i.tm.extension_opcode == 0xc8
- || i.tm.extension_opcode == 0xd8
- || i.tm.extension_opcode == 0xda
- || i.tm.extension_opcode == 0xdb
- || i.tm.extension_opcode == 0xdf))
- {
- /* monitor in SSE3 is a very special case. The default size
- of AX is the size of mode. The address size override
- prefix will change the size of AX. It is also true for
- invlpga, vmload, vmrun and vmsave in SVME. */
+ if (i.tm.opcode_modifier.addrprefixop0)
+ {
+ /* The address size override prefix changes the size of the
+ first operand. */
if ((flag_code == CODE_32BIT
&& i.op->regs[0].reg_type.bitfield.reg16)
|| (flag_code != CODE_32BIT
if (i.types[op].bitfield.reg8)
continue;
- /* movzx, movsx, pextrb and pinsrb should not generate this
- warning. */
- if (intel_syntax
- && (i.tm.base_opcode == 0xfb7
- || i.tm.base_opcode == 0xfb6
- || i.tm.base_opcode == 0x63
- || i.tm.base_opcode == 0xfbe
- || i.tm.base_opcode == 0xfbf
- || i.tm.base_opcode == 0x660f3a14
- || i.tm.base_opcode == 0x660f3a20))
+ /* Don't generate this warning if not needed. */
+ if (intel_syntax && i.tm.opcode_modifier.byteokintel)
continue;
/* crc32 doesn't generate this warning. */
|| i.tm.operand_types[op].bitfield.acc))
{
if (intel_syntax
- && i.tm.base_opcode == 0xf30f2d
+ && i.tm.opcode_modifier.toqword
&& !i.types[0].bitfield.regxmm)
{
- /* cvtss2si converts DWORD memory to Reg64. We want
- REX byte. */
+ /* Convert to QWORD. We want REX byte. */
i.suffix = QWORD_MNEM_SUFFIX;
}
else
/* Prohibit these changes in the 64bit mode, since the
lowering is more complicated. */
if (intel_syntax
- && i.tm.base_opcode == 0xf20f2d
+ && i.tm.opcode_modifier.todword
&& !i.types[0].bitfield.regxmm)
{
- /* cvtsd2si converts QWORD memory to Reg32. We don't want
- REX byte. */
+ /* Convert to DWORD. We don't want REX byte. */
i.suffix = LONG_MNEM_SUFFIX;
}
else
return 1;
}
+static void
+process_drex (void)
+{
+ i.drex.modrm_reg = 0;
+ i.drex.modrm_regmem = 0;
+
+ /* SSE5 4 operand instructions must have the destination the same as
+ one of the inputs. Figure out the destination register and cache
+ it away in the drex field, and remember which fields to use for
+ the modrm byte. */
+ if (i.tm.opcode_modifier.drex
+ && i.tm.opcode_modifier.drexv
+ && i.operands == 4)
+ {
+ i.tm.extension_opcode = None;
+
+ /* Case 1: 4 operand insn, dest = src1, src3 = register. */
+ if (i.types[0].bitfield.regxmm != 0
+ && i.types[1].bitfield.regxmm != 0
+ && i.types[2].bitfield.regxmm != 0
+ && i.types[3].bitfield.regxmm != 0
+ && i.op[0].regs->reg_num == i.op[3].regs->reg_num
+ && i.op[0].regs->reg_flags == i.op[3].regs->reg_flags)
+ {
+ /* Clear the arguments that are stored in drex. */
+ UINTS_CLEAR (i.types[0]);
+ UINTS_CLEAR (i.types[3]);
+ i.reg_operands -= 2;
+
+ /* There are two different ways to encode a 4 operand
+ instruction with all registers that uses OC1 set to
+ 0 or 1. Favor setting OC1 to 0 since this mimics the
+ actions of other SSE5 assemblers. Use modrm encoding 2
+ for register/register. Include the high order bit that
+ is normally stored in the REX byte in the register
+ field. */
+ i.tm.extension_opcode = DREX_X1_XMEM_X2_X1;
+ i.drex.modrm_reg = 2;
+ i.drex.modrm_regmem = 1;
+ i.drex.reg = (i.op[3].regs->reg_num
+ + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0));
+ }
+
+ /* Case 2: 4 operand insn, dest = src1, src3 = memory. */
+ else if (i.types[0].bitfield.regxmm != 0
+ && i.types[1].bitfield.regxmm != 0
+ && (i.types[2].bitfield.regxmm
+ || operand_type_check (i.types[2], anymem))
+ && i.types[3].bitfield.regxmm != 0
+ && i.op[0].regs->reg_num == i.op[3].regs->reg_num
+ && i.op[0].regs->reg_flags == i.op[3].regs->reg_flags)
+ {
+ /* clear the arguments that are stored in drex */
+ UINTS_CLEAR (i.types[0]);
+ UINTS_CLEAR (i.types[3]);
+ i.reg_operands -= 2;
+
+ /* Specify the modrm encoding for memory addressing. Include
+ the high order bit that is normally stored in the REX byte
+ in the register field. */
+ i.tm.extension_opcode = DREX_X1_X2_XMEM_X1;
+ i.drex.modrm_reg = 1;
+ i.drex.modrm_regmem = 2;
+ i.drex.reg = (i.op[3].regs->reg_num
+ + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0));
+ }
+
+ /* Case 3: 4 operand insn, dest = src1, src2 = memory. */
+ else if (i.types[0].bitfield.regxmm != 0
+ && operand_type_check (i.types[1], anymem) != 0
+ && i.types[2].bitfield.regxmm != 0
+ && i.types[3].bitfield.regxmm != 0
+ && i.op[0].regs->reg_num == i.op[3].regs->reg_num
+ && i.op[0].regs->reg_flags == i.op[3].regs->reg_flags)
+ {
+ /* Clear the arguments that are stored in drex. */
+ UINTS_CLEAR (i.types[0]);
+ UINTS_CLEAR (i.types[3]);
+ i.reg_operands -= 2;
+
+ /* Specify the modrm encoding for memory addressing. Include
+ the high order bit that is normally stored in the REX byte
+ in the register field. */
+ i.tm.extension_opcode = DREX_X1_XMEM_X2_X1;
+ i.drex.modrm_reg = 2;
+ i.drex.modrm_regmem = 1;
+ i.drex.reg = (i.op[3].regs->reg_num
+ + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0));
+ }
+
+ /* Case 4: 4 operand insn, dest = src3, src2 = register. */
+ else if (i.types[0].bitfield.regxmm != 0
+ && i.types[1].bitfield.regxmm != 0
+ && i.types[2].bitfield.regxmm != 0
+ && i.types[3].bitfield.regxmm != 0
+ && i.op[2].regs->reg_num == i.op[3].regs->reg_num
+ && i.op[2].regs->reg_flags == i.op[3].regs->reg_flags)
+ {
+ /* clear the arguments that are stored in drex */
+ UINTS_CLEAR (i.types[2]);
+ UINTS_CLEAR (i.types[3]);
+ i.reg_operands -= 2;
+
+ /* There are two different ways to encode a 4 operand
+ instruction with all registers that uses OC1 set to
+ 0 or 1. Favor setting OC1 to 0 since this mimics the
+ actions of other SSE5 assemblers. Use modrm encoding
+ 2 for register/register. Include the high order bit that
+ is normally stored in the REX byte in the register
+ field. */
+ i.tm.extension_opcode = DREX_XMEM_X1_X2_X2;
+ i.drex.modrm_reg = 1;
+ i.drex.modrm_regmem = 0;
+
+ /* Remember the register, including the upper bits */
+ i.drex.reg = (i.op[3].regs->reg_num
+ + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0));
+ }
+
+ /* Case 5: 4 operand insn, dest = src3, src2 = memory. */
+ else if (i.types[0].bitfield.regxmm != 0
+ && (i.types[1].bitfield.regxmm
+ || operand_type_check (i.types[1], anymem))
+ && i.types[2].bitfield.regxmm != 0
+ && i.types[3].bitfield.regxmm != 0
+ && i.op[2].regs->reg_num == i.op[3].regs->reg_num
+ && i.op[2].regs->reg_flags == i.op[3].regs->reg_flags)
+ {
+ /* Clear the arguments that are stored in drex. */
+ UINTS_CLEAR (i.types[2]);
+ UINTS_CLEAR (i.types[3]);
+ i.reg_operands -= 2;
+
+ /* Specify the modrm encoding and remember the register
+ including the bits normally stored in the REX byte. */
+ i.tm.extension_opcode = DREX_X1_XMEM_X2_X2;
+ i.drex.modrm_reg = 0;
+ i.drex.modrm_regmem = 1;
+ i.drex.reg = (i.op[3].regs->reg_num
+ + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0));
+ }
+
+ /* Case 6: 4 operand insn, dest = src3, src1 = memory. */
+ else if (operand_type_check (i.types[0], anymem) != 0
+ && i.types[1].bitfield.regxmm != 0
+ && i.types[2].bitfield.regxmm != 0
+ && i.types[3].bitfield.regxmm != 0
+ && i.op[2].regs->reg_num == i.op[3].regs->reg_num
+ && i.op[2].regs->reg_flags == i.op[3].regs->reg_flags)
+ {
+ /* clear the arguments that are stored in drex */
+ UINTS_CLEAR (i.types[2]);
+ UINTS_CLEAR (i.types[3]);
+ i.reg_operands -= 2;
+
+ /* Specify the modrm encoding and remember the register
+ including the bits normally stored in the REX byte. */
+ i.tm.extension_opcode = DREX_XMEM_X1_X2_X2;
+ i.drex.modrm_reg = 1;
+ i.drex.modrm_regmem = 0;
+ i.drex.reg = (i.op[3].regs->reg_num
+ + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0));
+ }
+
+ else
+ as_bad (_("Incorrect operands for the '%s' instruction"),
+ i.tm.name);
+ }
+
+ /* SSE5 instructions with the DREX byte where the only memory operand
+ is in the 2nd argument, and the first and last xmm register must
+ match, and is encoded in the DREX byte. */
+ else if (i.tm.opcode_modifier.drex
+ && !i.tm.opcode_modifier.drexv
+ && i.operands == 4)
+ {
+ /* Case 1: 4 operand insn, dest = src1, src3 = reg/mem. */
+ if (i.types[0].bitfield.regxmm != 0
+ && (i.types[1].bitfield.regxmm
+ || operand_type_check(i.types[1], anymem))
+ && i.types[2].bitfield.regxmm != 0
+ && i.types[3].bitfield.regxmm != 0
+ && i.op[0].regs->reg_num == i.op[3].regs->reg_num
+ && i.op[0].regs->reg_flags == i.op[3].regs->reg_flags)
+ {
+ /* clear the arguments that are stored in drex */
+ UINTS_CLEAR (i.types[0]);
+ UINTS_CLEAR (i.types[3]);
+ i.reg_operands -= 2;
+
+ /* Specify the modrm encoding and remember the register
+ including the high bit normally stored in the REX
+ byte. */
+ i.drex.modrm_reg = 2;
+ i.drex.modrm_regmem = 1;
+ i.drex.reg = (i.op[3].regs->reg_num
+ + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0));
+ }
+
+ else
+ as_bad (_("Incorrect operands for the '%s' instruction"),
+ i.tm.name);
+ }
+
+ /* SSE5 3 operand instructions that the result is a register, being
+ either operand can be a memory operand, using OC0 to note which
+ one is the memory. */
+ else if (i.tm.opcode_modifier.drex
+ && i.tm.opcode_modifier.drexv
+ && i.operands == 3)
+ {
+ i.tm.extension_opcode = None;
+
+ /* Case 1: 3 operand insn, src1 = register. */
+ if (i.types[0].bitfield.regxmm != 0
+ && i.types[1].bitfield.regxmm != 0
+ && i.types[2].bitfield.regxmm != 0)
+ {
+ /* Clear the arguments that are stored in drex. */
+ UINTS_CLEAR (i.types[2]);
+ i.reg_operands--;
+
+ /* Specify the modrm encoding and remember the register
+ including the high bit normally stored in the REX byte. */
+ i.tm.extension_opcode = DREX_XMEM_X1_X2;
+ i.drex.modrm_reg = 1;
+ i.drex.modrm_regmem = 0;
+ i.drex.reg = (i.op[2].regs->reg_num
+ + ((i.op[2].regs->reg_flags & RegRex) ? 8 : 0));
+ }
+
+ /* Case 2: 3 operand insn, src1 = memory. */
+ else if (operand_type_check (i.types[0], anymem) != 0
+ && i.types[1].bitfield.regxmm != 0
+ && i.types[2].bitfield.regxmm != 0)
+ {
+ /* Clear the arguments that are stored in drex. */
+ UINTS_CLEAR (i.types[2]);
+ i.reg_operands--;
+
+ /* Specify the modrm encoding and remember the register
+ including the high bit normally stored in the REX
+ byte. */
+ i.tm.extension_opcode = DREX_XMEM_X1_X2;
+ i.drex.modrm_reg = 1;
+ i.drex.modrm_regmem = 0;
+ i.drex.reg = (i.op[2].regs->reg_num
+ + ((i.op[2].regs->reg_flags & RegRex) ? 8 : 0));
+ }
+
+ /* Case 3: 3 operand insn, src2 = memory. */
+ else if (i.types[0].bitfield.regxmm != 0
+ && operand_type_check (i.types[1], anymem) != 0
+ && i.types[2].bitfield.regxmm != 0)
+ {
+ /* Clear the arguments that are stored in drex. */
+ UINTS_CLEAR (i.types[2]);
+ i.reg_operands--;
+
+ /* Specify the modrm encoding and remember the register
+ including the high bit normally stored in the REX byte. */
+ i.tm.extension_opcode = DREX_X1_XMEM_X2;
+ i.drex.modrm_reg = 0;
+ i.drex.modrm_regmem = 1;
+ i.drex.reg = (i.op[2].regs->reg_num
+ + ((i.op[2].regs->reg_flags & RegRex) ? 8 : 0));
+ }
+
+ else
+ as_bad (_("Incorrect operands for the '%s' instruction"),
+ i.tm.name);
+ }
+
+ /* SSE5 4 operand instructions that are the comparison instructions
+ where the first operand is the immediate value of the comparison
+ to be done. */
+ else if (i.tm.opcode_modifier.drexc != 0 && i.operands == 4)
+ {
+ /* Case 1: 4 operand insn, src1 = reg/memory. */
+ if (operand_type_check (i.types[0], imm) != 0
+ && (i.types[1].bitfield.regxmm
+ || operand_type_check (i.types[1], anymem))
+ && i.types[2].bitfield.regxmm != 0
+ && i.types[3].bitfield.regxmm != 0)
+ {
+ /* clear the arguments that are stored in drex */
+ UINTS_CLEAR (i.types[3]);
+ i.reg_operands--;
+
+ /* Specify the modrm encoding and remember the register
+ including the high bit normally stored in the REX byte. */
+ i.drex.modrm_reg = 2;
+ i.drex.modrm_regmem = 1;
+ i.drex.reg = (i.op[3].regs->reg_num
+ + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0));
+ }
+
+ /* Case 2: 3 operand insn with ImmExt that places the
+ opcode_extension as an immediate argument. This is used for
+ all of the varients of comparison that supplies the appropriate
+ value as part of the instruction. */
+ else if ((i.types[0].bitfield.regxmm
+ || operand_type_check (i.types[0], anymem))
+ && i.types[1].bitfield.regxmm != 0
+ && i.types[2].bitfield.regxmm != 0
+ && operand_type_check (i.types[3], imm) != 0)
+ {
+ /* clear the arguments that are stored in drex */
+ UINTS_CLEAR (i.types[2]);
+ i.reg_operands--;
+
+ /* Specify the modrm encoding and remember the register
+ including the high bit normally stored in the REX byte. */
+ i.drex.modrm_reg = 1;
+ i.drex.modrm_regmem = 0;
+ i.drex.reg = (i.op[2].regs->reg_num
+ + ((i.op[2].regs->reg_flags & RegRex) ? 8 : 0));
+ }
+
+ else
+ as_bad (_("Incorrect operands for the '%s' instruction"),
+ i.tm.name);
+ }
+
+ else if (i.tm.opcode_modifier.drex
+ || i.tm.opcode_modifier.drexv
+ || i.tm.opcode_modifier.drexc)
+ as_bad (_("Internal error for the '%s' instruction"), i.tm.name);
+}
+
static int
process_operands (void)
{
unnecessary segment overrides. */
const seg_entry *default_seg = 0;
- /* The imul $imm, %reg instruction is converted into
- imul $imm, %reg, %reg, and the clr %reg instruction
- is converted into xor %reg, %reg. */
- if (i.tm.opcode_modifier.regkludge)
- {
- if (i.tm.cpu_flags.bitfield.cpusse4_1)
- {
- /* The first operand in instruction blendvpd, blendvps and
- pblendvb in SSE4.1 is implicit and must be xmm0. */
- assert (i.operands == 3
- && i.reg_operands >= 2
- && UINTS_EQUAL (i.types[0], regxmm));
- if (i.op[0].regs->reg_num != 0)
- {
- if (intel_syntax)
- as_bad (_("the last operand of `%s' must be `%sxmm0'"),
- i.tm.name, register_prefix);
- else
- as_bad (_("the first operand of `%s' must be `%sxmm0'"),
- i.tm.name, register_prefix);
- return 0;
- }
- i.op[0] = i.op[1];
- i.op[1] = i.op[2];
- i.types[0] = i.types[1];
- i.types[1] = i.types[2];
- i.operands--;
- i.reg_operands--;
-
- /* We need to adjust fields in i.tm since they are used by
- build_modrm_byte. */
- i.tm.operand_types [0] = i.tm.operand_types [1];
- i.tm.operand_types [1] = i.tm.operand_types [2];
- i.tm.operands--;
- }
- else
- {
- unsigned int first_reg_op;
-
- if (operand_type_check (i.types[0], reg))
- first_reg_op = 0;
- else
- first_reg_op = 1;
- /* Pretend we saw the extra register operand. */
- assert (i.reg_operands == 1
- && i.op[first_reg_op + 1].regs == 0);
- i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs;
- i.types[first_reg_op + 1] = i.types[first_reg_op];
- i.operands++;
- i.reg_operands++;
- }
+ /* Handle all of the DREX munging that SSE5 needs. */
+ if (i.tm.opcode_modifier.drex
+ || i.tm.opcode_modifier.drexv
+ || i.tm.opcode_modifier.drexc)
+ process_drex ();
+
+ if (i.tm.opcode_modifier.firstxmm0)
+ {
+ unsigned int j;
+
+ /* The first operand is implicit and must be xmm0. */
+ assert (i.reg_operands && UINTS_EQUAL (i.types[0], regxmm));
+ if (i.op[0].regs->reg_num != 0)
+ {
+ if (intel_syntax)
+ as_bad (_("the last operand of `%s' must be `%sxmm0'"),
+ i.tm.name, register_prefix);
+ else
+ as_bad (_("the first operand of `%s' must be `%sxmm0'"),
+ i.tm.name, register_prefix);
+ return 0;
+ }
+
+ for (j = 1; j < i.operands; j++)
+ {
+ i.op[j - 1] = i.op[j];
+ i.types[j - 1] = i.types[j];
+
+ /* We need to adjust fields in i.tm since they are used by
+ build_modrm_byte. */
+ i.tm.operand_types [j - 1] = i.tm.operand_types [j];
+ }
+
+ i.operands--;
+ i.reg_operands--;
+ i.tm.operands--;
+ }
+ else if (i.tm.opcode_modifier.regkludge)
+ {
+ /* The imul $imm, %reg instruction is converted into
+ imul $imm, %reg, %reg, and the clr %reg instruction
+ is converted into xor %reg, %reg. */
+
+ unsigned int first_reg_op;
+
+ if (operand_type_check (i.types[0], reg))
+ first_reg_op = 0;
+ else
+ first_reg_op = 1;
+ /* Pretend we saw the extra register operand. */
+ assert (i.reg_operands == 1
+ && i.op[first_reg_op + 1].regs == 0);
+ i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs;
+ i.types[first_reg_op + 1] = i.types[first_reg_op];
+ i.operands++;
+ i.reg_operands++;
}
if (i.tm.opcode_modifier.shortform)
}
else
{
- /* The register or float register operand is in operand 0 or 1. */
+ /* The register or float register operand is in operand
+ 0 or 1. */
unsigned int op;
if (i.types[0].bitfield.floatreg
{
const seg_entry *default_seg = 0;
+ /* SSE5 4 operand instructions are encoded in such a way that one of
+ the inputs must match the destination register. Process_drex hides
+ the 3rd argument in the drex field, so that by the time we get
+ here, it looks to GAS as if this is a 2 operand instruction. */
+ if ((i.tm.opcode_modifier.drex
+ || i.tm.opcode_modifier.drexv
+ || i.tm.opcode_modifier.drexc)
+ && i.reg_operands == 2)
+ {
+ const reg_entry *reg = i.op[i.drex.modrm_reg].regs;
+ const reg_entry *regmem = i.op[i.drex.modrm_regmem].regs;
+
+ i.rm.reg = reg->reg_num;
+ i.rm.regmem = regmem->reg_num;
+ i.rm.mode = 3;
+ if ((reg->reg_flags & RegRex) != 0)
+ i.rex |= REX_R;
+ if ((regmem->reg_flags & RegRex) != 0)
+ i.rex |= REX_B;
+ }
+
/* i.reg_operands MUST be the number of real register operands;
implicit registers do not count. */
- if (i.reg_operands == 2)
+ else if (i.reg_operands == 2)
{
unsigned int source, dest;
source = 0;
break;
case 4:
- /* When there are 4 operands, the first two must be immediate
- operands. The source operand will be the 3rd one. */
+ /* When there are 4 operands, the first two must be 8bit
+ immediate operands. The source operand will be the 3rd
+ one. */
assert (i.imm_operands == 2
- && operand_type_check (i.types[0], imm)
- && operand_type_check (i.types[1], imm));
+ && i.types[0].bitfield.imm8
+ && i.types[1].bitfield.imm8);
source = 2;
break;
default:
unsigned int fake_zero_displacement = 0;
unsigned int op;
- for (op = 0; op < i.operands; op++)
- if (operand_type_check (i.types[op], anymem))
- break;
- assert (op < i.operands);
+ /* This has been precalculated for SSE5 instructions
+ that have a DREX field earlier in process_drex. */
+ if (i.tm.opcode_modifier.drex
+ || i.tm.opcode_modifier.drexv
+ || i.tm.opcode_modifier.drexc)
+ op = i.drex.modrm_regmem;
+ else
+ {
+ for (op = 0; op < i.operands; op++)
+ if (operand_type_check (i.types[op], anymem))
+ break;
+ assert (op < i.operands);
+ }
default_seg = &ds;
}
else /* !i.base_reg && i.index_reg */
{
- i.sib.index = i.index_reg->reg_num;
+ if (i.index_reg->reg_num == RegEiz
+ || i.index_reg->reg_num == RegRiz)
+ i.sib.index = NO_INDEX_REGISTER;
+ else
+ i.sib.index = i.index_reg->reg_num;
i.sib.base = NO_BASE_REGISTER;
i.sib.scale = i.log2_scale_factor;
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
}
}
/* RIP addressing for 64bit mode. */
- else if (UINTS_EQUAL (i.base_reg->reg_type, baseindex))
+ else if (i.base_reg->reg_num == RegRip ||
+ i.base_reg->reg_num == RegEip)
{
i.rm.regmem = NO_BASE_REGISTER;
i.types[op].bitfield.disp8 = 0;
Any base register besides %esp will not use the
extra modrm byte. */
i.sib.index = NO_INDEX_REGISTER;
-#if !SCALE1_WHEN_NO_INDEX
- /* Another case where we force the second modrm byte. */
- if (i.log2_scale_factor)
- i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
-#endif
}
else
{
- i.sib.index = i.index_reg->reg_num;
+ if (i.index_reg->reg_num == RegEiz
+ || i.index_reg->reg_num == RegRiz)
+ i.sib.index = NO_INDEX_REGISTER;
+ else
+ i.sib.index = i.index_reg->reg_num;
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
if ((i.index_reg->reg_flags & RegRex) != 0)
i.rex |= REX_X;
{
unsigned int op;
- for (op = 0; op < i.operands; op++)
- if (i.types[op].bitfield.reg8
- || i.types[op].bitfield.reg16
- || i.types[op].bitfield.reg32
- || i.types[op].bitfield.reg64
- || i.types[op].bitfield.regmmx
- || i.types[op].bitfield.regxmm
- || i.types[op].bitfield.sreg2
- || i.types[op].bitfield.sreg3
- || i.types[op].bitfield.control
- || i.types[op].bitfield.debug
- || i.types[op].bitfield.test)
- break;
- assert (op < i.operands);
-
- /* 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)
+ /* This has been precalculated for SSE5 instructions
+ that have a DREX field earlier in process_drex. */
+ if (i.tm.opcode_modifier.drex
+ || i.tm.opcode_modifier.drexv
+ || i.tm.opcode_modifier.drexc)
{
- i.rm.regmem = i.op[op].regs->reg_num;
+ op = i.drex.modrm_reg;
+ i.rm.reg = i.op[op].regs->reg_num;
if ((i.op[op].regs->reg_flags & RegRex) != 0)
- i.rex |= REX_B;
+ i.rex |= REX_R;
}
else
{
- i.rm.reg = i.op[op].regs->reg_num;
- if ((i.op[op].regs->reg_flags & RegRex) != 0)
- i.rex |= REX_R;
+ for (op = 0; op < i.operands; op++)
+ if (i.types[op].bitfield.reg8
+ || i.types[op].bitfield.reg16
+ || i.types[op].bitfield.reg32
+ || i.types[op].bitfield.reg64
+ || i.types[op].bitfield.regmmx
+ || i.types[op].bitfield.regxmm
+ || i.types[op].bitfield.sreg2
+ || i.types[op].bitfield.sreg3
+ || i.types[op].bitfield.control
+ || i.types[op].bitfield.debug
+ || i.types[op].bitfield.test)
+ break;
+
+ assert (op < i.operands);
+
+ /* 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;
+ if ((i.op[op].regs->reg_flags & RegRex) != 0)
+ i.rex |= REX_B;
+ }
+ else
+ {
+ i.rm.reg = i.op[op].regs->reg_num;
+ if ((i.op[op].regs->reg_flags & RegRex) != 0)
+ i.rex |= REX_R;
+ }
}
/* Now, if no memory operand has set i.rm.mode = 0, 1, 2 we
}
/* Fill in i.rm.reg field with extension opcode (if any). */
- if (i.tm.extension_opcode != None)
+ if (i.tm.extension_opcode != None
+ && !(i.tm.opcode_modifier.drex
+ || i.tm.opcode_modifier.drexv
+ || i.tm.opcode_modifier.drexc))
i.rm.reg = i.tm.extension_opcode;
}
return default_seg;
/* Output normal instructions here. */
char *p;
unsigned char *q;
+ unsigned int j;
unsigned int prefix;
- int opc_3b;
-
- /* All opcodes on i386 have either 1 or 2 bytes. SSSE3 and
- SSE4 instructions have 3 bytes. We may use one more higher
- byte to specify a prefix the instruction requires. Exclude
- instructions which are in both SSE4.2 and ABM. */
- opc_3b = (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.cpuabm));
- if (opc_3b)
+
+ switch (i.tm.opcode_length)
{
+ case 3:
if (i.tm.base_opcode & 0xff000000)
{
prefix = (i.tm.base_opcode >> 24) & 0xff;
goto check_prefix;
}
- }
- else if ((i.tm.base_opcode & 0xff0000) != 0)
- {
- prefix = (i.tm.base_opcode >> 16) & 0xff;
- if (i.tm.cpu_flags.bitfield.cpupadlock)
+ break;
+ case 2:
+ if ((i.tm.base_opcode & 0xff0000) != 0)
{
- check_prefix:
- if (prefix != REPE_PREFIX_OPCODE
- || i.prefix[LOCKREP_PREFIX] != REPE_PREFIX_OPCODE)
+ prefix = (i.tm.base_opcode >> 16) & 0xff;
+ if (i.tm.cpu_flags.bitfield.cpupadlock)
+ {
+check_prefix:
+ if (prefix != REPE_PREFIX_OPCODE
+ || i.prefix[LOCKREP_PREFIX] != REPE_PREFIX_OPCODE)
+ add_prefix (prefix);
+ }
+ else
add_prefix (prefix);
}
- else
- add_prefix (prefix);
+ break;
+ case 1:
+ break;
+ default:
+ abort ();
}
/* The prefix bytes. */
- for (q = i.prefix;
- q < i.prefix + sizeof (i.prefix) / sizeof (i.prefix[0]);
- q++)
- {
- if (*q)
- {
- p = frag_more (1);
- md_number_to_chars (p, (valueT) *q, 1);
- }
- }
+ for (j = ARRAY_SIZE (i.prefix), q = i.prefix; j > 0; j--, q++)
+ if (*q)
+ FRAG_APPEND_1_CHAR (*q);
/* Now the opcode; be careful about word order here! */
- if (fits_in_unsigned_byte (i.tm.base_opcode))
+ if (i.tm.opcode_length == 1)
{
FRAG_APPEND_1_CHAR (i.tm.base_opcode);
}
else
{
- if (opc_3b)
+ switch (i.tm.opcode_length)
{
+ case 3:
p = frag_more (3);
*p++ = (i.tm.base_opcode >> 16) & 0xff;
+ break;
+ case 2:
+ p = frag_more (2);
+ break;
+ default:
+ abort ();
+ break;
}
- else
- p = frag_more (2);
/* Put out high byte first: can't use md_number_to_chars! */
*p++ = (i.tm.base_opcode >> 8) & 0xff;
*p = i.tm.base_opcode & 0xff;
+
+ /* On SSE5, encode the OC1 bit in the DREX field if this
+ encoding has multiple formats. */
+ if (i.tm.opcode_modifier.drex
+ && i.tm.opcode_modifier.drexv
+ && DREX_OC1 (i.tm.extension_opcode))
+ *p |= DREX_OC1_MASK;
}
/* Now the modrm byte and sib byte (if present). */
if (i.tm.opcode_modifier.modrm)
{
- p = frag_more (1);
- md_number_to_chars (p,
- (valueT) (i.rm.regmem << 0
- | i.rm.reg << 3
- | i.rm.mode << 6),
- 1);
+ FRAG_APPEND_1_CHAR ((i.rm.regmem << 0
+ | i.rm.reg << 3
+ | i.rm.mode << 6));
/* If i.rm.regmem == ESP (4)
&& i.rm.mode != (Register mode)
&& not 16 bit
if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING
&& i.rm.mode != 3
&& !(i.base_reg && i.base_reg->reg_type.bitfield.reg16))
- {
- p = frag_more (1);
- md_number_to_chars (p,
- (valueT) (i.sib.base << 0
- | i.sib.index << 3
- | i.sib.scale << 6),
- 1);
- }
+ FRAG_APPEND_1_CHAR ((i.sib.base << 0
+ | i.sib.index << 3
+ | i.sib.scale << 6));
+ }
+
+ /* Write the DREX byte if needed. */
+ if (i.tm.opcode_modifier.drex || i.tm.opcode_modifier.drexc)
+ {
+ p = frag_more (1);
+ *p = (((i.drex.reg & 0xf) << 4) | (i.drex.rex & 0x7));
+
+ /* Encode the OC0 bit if this encoding has multiple
+ formats. */
+ if ((i.tm.opcode_modifier.drex
+ || i.tm.opcode_modifier.drexv)
+ && DREX_OC0 (i.tm.extension_opcode))
+ *p |= DREX_OC0_MASK;
}
if (i.disp_operands)
if (is_end_of_line[(unsigned char) *cp] || *cp == ',')
return NULL;
- for (j = 0; j < sizeof (gotrel) / sizeof (gotrel[0]); j++)
+ for (j = 0; j < ARRAY_SIZE (gotrel); j++)
{
int len;
{
as_warn (_("scale factor of %d without an index register"),
1 << i.log2_scale_factor);
-#if SCALE1_WHEN_NO_INDEX
i.log2_scale_factor = 0;
-#endif
}
scale = input_line_pointer;
input_line_pointer = save;
|| (i.prefix[ADDR_PREFIX]
&& !i.base_reg->reg_type.bitfield.reg32))
&& (i.index_reg
- || !UINTS_EQUAL (i.base_reg->reg_type, baseindex)))
+ || i.base_reg->reg_num !=
+ (i.prefix[ADDR_PREFIX] == 0 ? RegRip : RegEip)))
|| (i.index_reg
&& (!i.index_reg->reg_type.bitfield.baseindex
|| (i.prefix[ADDR_PREFIX] == 0
- && !i.index_reg->reg_type.bitfield.reg64)
+ && i.index_reg->reg_num != RegRiz
+ && !i.index_reg->reg_type.bitfield.reg64
+ )
|| (i.prefix[ADDR_PREFIX]
+ && i.index_reg->reg_num != RegEiz
&& !i.index_reg->reg_type.bitfield.reg32))))
ok = 0;
}
if ((i.base_reg
&& !i.base_reg->reg_type.bitfield.reg32)
|| (i.index_reg
- && (!i.index_reg->reg_type.bitfield.reg32
+ && ((!i.index_reg->reg_type.bitfield.reg32
+ && i.index_reg->reg_num != RegEiz)
|| !i.index_reg->reg_type.bitfield.baseindex)))
ok = 0;
}
on error. */
static int
-i386_operand (char *operand_string)
+i386_att_operand (char *operand_string)
{
const reg_entry *r;
char *end_op;
fragP->fr_fix += extension;
}
\f
-/* Size of byte displacement jmp. */
-int md_short_jump_size = 2;
-
-/* Size of dword displacement jmp. */
-int md_long_jump_size = 5;
-
-void
-md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
- char *ptr;
- addressT from_addr, to_addr;
- fragS *frag ATTRIBUTE_UNUSED;
- symbolS *to_symbol ATTRIBUTE_UNUSED;
-{
- offsetT offset;
-
- offset = to_addr - (from_addr + 2);
- /* Opcode for byte-disp jump. */
- md_number_to_chars (ptr, (valueT) 0xeb, 1);
- md_number_to_chars (ptr + 1, (valueT) offset, 1);
-}
-
-void
-md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
- char *ptr;
- addressT from_addr, to_addr;
- fragS *frag ATTRIBUTE_UNUSED;
- symbolS *to_symbol ATTRIBUTE_UNUSED;
-{
- offsetT offset;
-
- offset = to_addr - (from_addr + 5);
- md_number_to_chars (ptr, (valueT) 0xe9, 1);
- md_number_to_chars (ptr + 1, (valueT) offset, 4);
-}
-\f
/* Apply a fixup (fixS) to segment data, once it has been determined
by our caller that we have all the info we need to fix it up.
md_number_to_chars (p, value, fixP->fx_size);
}
\f
-#define MAX_LITTLENUMS 6
-
-/* Turn the string pointed to by litP into a floating point constant
- of type TYPE, and emit the appropriate bytes. The number of
- LITTLENUMS emitted is stored in *SIZEP. An error message is
- returned, or NULL on OK. */
-
char *
-md_atof (type, litP, sizeP)
- int type;
- char *litP;
- int *sizeP;
+md_atof (int type, char *litP, int *sizeP)
{
- int prec;
- LITTLENUM_TYPE words[MAX_LITTLENUMS];
- LITTLENUM_TYPE *wordP;
- char *t;
-
- switch (type)
- {
- case 'f':
- case 'F':
- prec = 2;
- break;
-
- case 'd':
- case 'D':
- prec = 4;
- break;
-
- case 'x':
- case 'X':
- prec = 5;
- break;
-
- default:
- *sizeP = 0;
- return _("Bad call to md_atof ()");
- }
- t = atof_ieee (input_line_pointer, type, words);
- if (t)
- input_line_pointer = t;
-
- *sizeP = prec * sizeof (LITTLENUM_TYPE);
- /* This loops outputs the LITTLENUMs in REVERSE order; in accord with
- the bigendian 386. */
- for (wordP = words + prec - 1; prec--;)
- {
- md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE));
- litP += sizeof (LITTLENUM_TYPE);
- }
- return 0;
+ /* This outputs the LITTLENUMs in REVERSE order;
+ in accord with the bigendian 386. */
+ return ieee_md_atof (type, litP, sizeP, FALSE);
}
\f
static char output_invalid_buf[sizeof (unsigned char) * 2 + 6];
}
}
+ /* Don't allow fake index register unless allow_index_reg isn't 0. */
+ if (r != NULL
+ && !allow_index_reg
+ && (r->reg_num == RegEiz || r->reg_num == RegRiz))
+ return (const reg_entry *) NULL;
+
if (r != NULL
&& ((r->reg_flags & (RegRex64 | RegRex))
|| r->reg_type.bitfield.reg64)
#define OPTION_DIVIDE (OPTION_MD_BASE + 2)
#define OPTION_MARCH (OPTION_MD_BASE + 3)
#define OPTION_MTUNE (OPTION_MD_BASE + 4)
+#define OPTION_MMNEMONIC (OPTION_MD_BASE + 5)
+#define OPTION_MSYNTAX (OPTION_MD_BASE + 6)
+#define OPTION_MINDEX_REG (OPTION_MD_BASE + 7)
+#define OPTION_MNAKED_REG (OPTION_MD_BASE + 8)
+#define OPTION_MOLD_GCC (OPTION_MD_BASE + 9)
struct option md_longopts[] =
{
{"divide", no_argument, NULL, OPTION_DIVIDE},
{"march", required_argument, NULL, OPTION_MARCH},
{"mtune", required_argument, NULL, OPTION_MTUNE},
+ {"mmnemonic", required_argument, NULL, OPTION_MMNEMONIC},
+ {"msyntax", required_argument, NULL, OPTION_MSYNTAX},
+ {"mindex-reg", no_argument, NULL, OPTION_MINDEX_REG},
+ {"mnaked-reg", no_argument, NULL, OPTION_MNAKED_REG},
+ {"mold-gcc", no_argument, NULL, OPTION_MOLD_GCC},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
as_fatal (_("Invalid -mtune= option: `%s'"), arg);
break;
+ case OPTION_MMNEMONIC:
+ if (strcasecmp (arg, "att") == 0)
+ intel_mnemonic = 0;
+ else if (strcasecmp (arg, "intel") == 0)
+ intel_mnemonic = 1;
+ else
+ as_fatal (_("Invalid -mmnemonic= option: `%s'"), arg);
+ break;
+
+ case OPTION_MSYNTAX:
+ if (strcasecmp (arg, "att") == 0)
+ intel_syntax = 0;
+ else if (strcasecmp (arg, "intel") == 0)
+ intel_syntax = 1;
+ else
+ as_fatal (_("Invalid -msyntax= option: `%s'"), arg);
+ break;
+
+ case OPTION_MINDEX_REG:
+ allow_index_reg = 1;
+ break;
+
+ case OPTION_MNAKED_REG:
+ allow_naked_reg = 1;
+ break;
+
+ case OPTION_MOLD_GCC:
+ old_gcc = 1;
+ break;
+
default:
return 0;
}
-march=CPU/-mtune=CPU generate code/optimize for CPU, where CPU is one of:\n\
i386, i486, pentium, pentiumpro, pentium4, nocona,\n\
core, core2, k6, athlon, k8, generic32, generic64\n"));
-
+ fprintf (stream, _("\
+ -mmnemonic=[att|intel] use AT&T/Intel mnemonic\n"));
+ fprintf (stream, _("\
+ -msyntax=[att|intel] use AT&T/Intel syntax\n"));
+ fprintf (stream, _("\
+ -mindex-reg support pseudo index registers\n"));
+ fprintf (stream, _("\
+ -mnaked-reg don't require `%%' prefix for registers\n"));
+ fprintf (stream, _("\
+ -mold-gcc support old (<= 2.8.1) versions of gcc\n"));
}
#if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \
else if (prev_token.code == T_XMMWORD)
{
- /* XXX ignored for now, but accepted since gcc uses it */
- suffix = 0;
+ suffix = XMMWORD_MNEM_SUFFIX;
}
else