aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2022-12-12 13:52:15 +0100
committerJan Beulich <jbeulich@suse.com>2022-12-12 13:52:15 +0100
commit9db83a32776e946ab9738dd5a2bd3a4018641feb (patch)
tree5a432e5ca8b36e33189b77922a561fa8f3acb8c1 /gas/config
parent04784e33fabb45c4de7a901587f468d4bc169649 (diff)
downloadgdb-9db83a32776e946ab9738dd5a2bd3a4018641feb.zip
gdb-9db83a32776e946ab9738dd5a2bd3a4018641feb.tar.gz
gdb-9db83a32776e946ab9738dd5a2bd3a4018641feb.tar.bz2
ix86: don't recognize/derive Q suffix in the common case
Have its use, except where actually legitimate, result in the same "only supported in 64-bit mode" diagnostic as emitted for other 64-bit only insns. Also suppress deriving of the suffix in Intel mode except in the legitimate cases. This in exchange allows dropping the respective code from match_template(). To maintain reasonable diagnostics (in particular to avoid "`mov' is only supported in 64-bit mode" on the SIMD forms of MOVQ) we need to defer parse_insn()'s emitting of errors unrelated to prefix parsing. Utilize i.error just like match_template() does. Oddly enough despite gcc's preference towards FILDQ and FIST{,T}Q we had no testcase whatsoever for these. Therefore such tests are being added. Note that the removed line in the x86-64-lfence-load testcase was redundant with the exact same one a few lines up.
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-i386-intel.c2
-rw-r--r--gas/config/tc-i386.c104
2 files changed, 81 insertions, 25 deletions
diff --git a/gas/config/tc-i386-intel.c b/gas/config/tc-i386-intel.c
index ca18f5e..c07f93f 100644
--- a/gas/config/tc-i386-intel.c
+++ b/gas/config/tc-i386-intel.c
@@ -828,7 +828,7 @@ i386_intel_operand (char *operand_string, int got_a_float)
continue;
break;
case QWORD_MNEM_SUFFIX:
- if (t->opcode_modifier.no_qsuf)
+ if (t->opcode_modifier.no_qsuf || !q_suffix_allowed (t))
continue;
break;
case SHORT_MNEM_SUFFIX:
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 870e2d1..92fdbc1 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -237,6 +237,8 @@ enum i386_error
unsupported_with_intel_mnemonic,
unsupported_syntax,
unsupported,
+ unsupported_on_arch,
+ unsupported_64bit,
invalid_sib_address,
invalid_vsib_address,
invalid_vector_register_set,
@@ -2013,7 +2015,15 @@ match_operand_size (const insn_template *t, unsigned int wanted,
|| (i.types[given].bitfield.dword
&& !t->operand_types[wanted].bitfield.dword)
|| (i.types[given].bitfield.qword
- && !t->operand_types[wanted].bitfield.qword)
+ && (!t->operand_types[wanted].bitfield.qword
+ /* Don't allow 64-bit (memory) operands outside of 64-bit
+ mode, when they're used where a 64-bit GPR could also
+ be used. Checking is needed for Intel Syntax only. */
+ || (intel_syntax
+ && flag_code != CODE_64BIT
+ && (t->operand_types[wanted].bitfield.class == Reg
+ || t->operand_types[wanted].bitfield.class == Accum
+ || t->opcode_modifier.isstring))))
|| (i.types[given].bitfield.tbyte
&& !t->operand_types[wanted].bitfield.tbyte));
}
@@ -4861,7 +4871,7 @@ void
md_assemble (char *line)
{
unsigned int j;
- char mnemonic[MAX_MNEM_SIZE], mnem_suffix, *copy = NULL;
+ char mnemonic[MAX_MNEM_SIZE], mnem_suffix = 0, *copy = NULL;
const char *end, *pass1_mnem = NULL;
enum i386_error pass1_err = 0;
const insn_template *t;
@@ -4886,6 +4896,16 @@ md_assemble (char *line)
{
if (pass1_mnem != NULL)
goto match_error;
+ if (i.error != no_error)
+ {
+ gas_assert (current_templates != NULL);
+ if (may_need_pass2 (current_templates->start) && !i.suffix)
+ goto no_match;
+ /* No point in trying a 2nd pass - it'll only find the same suffix
+ again. */
+ mnem_suffix = i.suffix;
+ goto match_error;
+ }
return;
}
if (may_need_pass2 (current_templates->start))
@@ -4987,12 +5007,21 @@ md_assemble (char *line)
{
line = copy;
copy = NULL;
+ no_match:
pass1_err = i.error;
pass1_mnem = current_templates->start->name;
goto retry;
}
- free (copy);
+
+ /* If a non-/only-64bit template (group) was found in pass 1, and if
+ _some_ template (group) was found in pass 2, squash pass 1's
+ error. */
+ if (pass1_err == unsupported_64bit)
+ pass1_mnem = NULL;
+
match_error:
+ free (copy);
+
switch (pass1_mnem ? pass1_err : i.error)
{
default:
@@ -5025,6 +5054,23 @@ md_assemble (char *line)
as_bad (_("unsupported instruction `%s'"),
pass1_mnem ? pass1_mnem : current_templates->start->name);
return;
+ case unsupported_on_arch:
+ as_bad (_("`%s' is not supported on `%s%s'"),
+ pass1_mnem ? pass1_mnem : current_templates->start->name,
+ cpu_arch_name ? cpu_arch_name : default_arch,
+ cpu_sub_arch_name ? cpu_sub_arch_name : "");
+ return;
+ case unsupported_64bit:
+ if (ISLOWER (mnem_suffix))
+ as_bad (_("`%s%c' is %s supported in 64-bit mode"),
+ pass1_mnem ? pass1_mnem : current_templates->start->name,
+ mnem_suffix,
+ flag_code == CODE_64BIT ? _("not") : _("only"));
+ else
+ as_bad (_("`%s' is %s supported in 64-bit mode"),
+ pass1_mnem ? pass1_mnem : current_templates->start->name,
+ flag_code == CODE_64BIT ? _("not") : _("only"));
+ return;
case invalid_sib_address:
err_msg = _("invalid SIB address");
break;
@@ -5382,6 +5428,23 @@ md_assemble (char *line)
last_insn.kind = last_insn_other;
}
+/* The Q suffix is generally valid only in 64-bit mode, with very few
+ exceptions: fild, fistp, fisttp, and cmpxchg8b. Note that for fild
+ and fisttp only one of their two templates is matched below: That's
+ sufficient since other relevant attributes are the same between both
+ respective templates. */
+static INLINE bool q_suffix_allowed(const insn_template *t)
+{
+ return flag_code == CODE_64BIT
+ || (t->opcode_modifier.opcodespace == 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 */;
+}
+
static const char *
parse_insn (const char *line, char *mnemonic)
{
@@ -5677,20 +5740,21 @@ parse_insn (const char *line, char *mnemonic)
for (t = current_templates->start; t < current_templates->end; ++t)
{
supported |= cpu_flags_match (t);
+
+ if (i.suffix == QWORD_MNEM_SUFFIX && !q_suffix_allowed (t))
+ supported &= ~CPU_FLAGS_64BIT_MATCH;
+
if (supported == CPU_FLAGS_PERFECT_MATCH)
return l;
}
- if (!(supported & CPU_FLAGS_64BIT_MATCH))
- as_bad (flag_code == CODE_64BIT
- ? _("`%s' is not supported in 64-bit mode")
- : _("`%s' is only supported in 64-bit mode"),
- current_templates->start->name);
- else
- as_bad (_("`%s' is not supported on `%s%s'"),
- current_templates->start->name,
- cpu_arch_name ? cpu_arch_name : default_arch,
- cpu_sub_arch_name ? cpu_sub_arch_name : "");
+ if (pass1)
+ {
+ if (supported & CPU_FLAGS_64BIT_MATCH)
+ i.error = unsupported_on_arch;
+ else
+ i.error = unsupported_64bit;
+ }
return NULL;
}
@@ -6687,20 +6751,12 @@ match_template (char mnem_suffix)
for (j = 0; j < MAX_OPERANDS; j++)
operand_types[j] = t->operand_types[j];
- /* In general, don't allow
- - 64-bit operands outside of 64-bit mode,
- - 32-bit operands on pre-386. */
+ /* In general, don't allow 32-bit operands on pre-386. */
specific_error = progress (mnem_suffix ? invalid_instruction_suffix
: operand_size_mismatch);
j = i.imm_operands + (t->operands > i.imm_operands + 1);
- if (((i.suffix == QWORD_MNEM_SUFFIX
- && flag_code != CODE_64BIT
- && !(t->opcode_modifier.opcodespace == SPACE_0F
- && t->base_opcode == 0xc7
- && t->opcode_modifier.opcodeprefix == PREFIX_NONE
- && t->extension_opcode == 1) /* cmpxchg8b */)
- || (i.suffix == LONG_MNEM_SUFFIX
- && !cpu_arch_flags.bitfield.cpui386))
+ if (i.suffix == LONG_MNEM_SUFFIX
+ && !cpu_arch_flags.bitfield.cpui386
&& (intel_syntax
? (t->opcode_modifier.mnemonicsize != IGNORESIZE
&& !intel_float_operand (t->name))