[PATCH 6/6] x86: improve matching diagnostics when %st is involved
Jan Beulich
jbeulich@suse.com
Wed Apr 30 13:31:22 GMT 2025
Diagnosing operand size vs operand type mismatches doesn't work very
well when GPRs and FPRs are in the same register class, distinguished
just by size. Introduce a separate RegFP class.
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -2510,8 +2510,8 @@ operand_type_check (i386_operand_type t,
return 0;
}
-/* Return 1 if there is no conflict in 8bit/16bit/32bit/64bit/80bit size
- between operand GIVEN and opeand WANTED for instruction template T. */
+/* Return 1 if there is no conflict in 8bit/16bit/32bit/64bit size
+ between operand GIVEN and operand WANTED for instruction template T. */
static INLINE int
match_operand_size (const insn_template *t, unsigned int wanted,
@@ -2531,13 +2531,22 @@ match_operand_size (const insn_template
|| (intel_syntax
&& flag_code != CODE_64BIT
&& (t->operand_types[wanted].bitfield.class == Reg
- || t->opcode_modifier.isstring))))
- || (i.types[given].bitfield.tbyte
- && !t->operand_types[wanted].bitfield.tbyte));
+ || t->opcode_modifier.isstring)))));
+}
+
+/* Return 1 if there is no conflict in 80bit size
+ between operand GIVEN and operand WANTED for instruction template T. */
+
+static INLINE int
+match_fp_size (const insn_template *t, unsigned int wanted,
+ unsigned int given)
+{
+ return !i.types[given].bitfield.tbyte
+ || t->operand_types[wanted].bitfield.tbyte;
}
/* Return 1 if there is no conflict in SIMD register between operand
- GIVEN and opeand WANTED for instruction template T. */
+ GIVEN and operand WANTED for instruction template T. */
static INLINE int
match_simd_size (const insn_template *t, unsigned int wanted,
@@ -2554,13 +2563,15 @@ match_simd_size (const insn_template *t,
}
/* Return 1 if there is no conflict in any size between operand GIVEN
- and opeand WANTED for instruction template T. */
+ and operand WANTED for instruction template T. */
static INLINE int
match_mem_size (const insn_template *t, unsigned int wanted,
unsigned int given)
{
return (match_operand_size (t, wanted, given)
+ && (!i.types[given].bitfield.tbyte
+ || t->operand_types[wanted].bitfield.tbyte)
&& !((i.types[given].bitfield.unspecified
&& !i.broadcast.type
&& !i.broadcast.bytes
@@ -2610,14 +2621,23 @@ operand_size_match (const insn_template
&& (t->operand_types[j].bitfield.byte
|| t->operand_types[j].bitfield.word
|| t->operand_types[j].bitfield.dword
- || t->operand_types[j].bitfield.qword
- || t->operand_types[j].bitfield.tbyte)))
+ || t->operand_types[j].bitfield.qword)))
&& !match_operand_size (t, j, j))
{
match = 0;
break;
}
+ if (i.types[j].bitfield.class == RegFP
+ && (t->operand_types[j].bitfield.class == RegFP
+ || (t->operand_types[j].bitfield.instance == Accum
+ && t->operand_types[j].bitfield.tbyte))
+ && !match_fp_size (t, j, j))
+ {
+ match = 0;
+ break;
+ }
+
if (i.types[j].bitfield.class == RegSIMD
&& (t->operand_types[j].bitfield.class == RegSIMD
|| (t->operand_types[j].bitfield.instance == Accum
@@ -2667,6 +2687,13 @@ operand_size_match (const insn_template
&& !match_operand_size (t, j, given))
return match;
+ if (i.types[given].bitfield.class == RegFP
+ && (t->operand_types[j].bitfield.class == RegFP
+ || (t->operand_types[j].bitfield.instance == Accum
+ && t->operand_types[j].bitfield.tbyte))
+ && !match_fp_size (t, j, given))
+ return match;
+
/* No need to check for Accum here: There are no such templates with D
set. */
if (i.types[given].bitfield.class == RegSIMD
@@ -3602,14 +3629,14 @@ md_begin (void)
if (regtab->reg_type.bitfield.instance == Accum)
reg_eax = regtab;
}
- else if (regtab->reg_type.bitfield.tbyte)
- {
- /* There's no point inserting st(<N>) in the hash table, as
- parentheses aren't included in register_chars[] anyway. */
- if (regtab->reg_type.bitfield.instance != Accum)
- continue;
- reg_st0 = regtab;
- }
+ break;
+
+ case RegFP:
+ /* There's no point inserting st(<N>) in the hash table, as
+ parentheses aren't included in register_chars[] anyway. */
+ if (regtab->reg_type.bitfield.instance != Accum)
+ continue;
+ reg_st0 = regtab;
break;
case SReg:
@@ -3744,6 +3771,7 @@ pi (const char *line, i386_insn *x)
pt (x->types[j]);
fprintf (stdout, "\n");
if (x->types[j].bitfield.class == Reg
+ || x->types[j].bitfield.class == RegFP
|| x->types[j].bitfield.class == RegMMX
|| x->types[j].bitfield.class == RegSIMD
|| x->types[j].bitfield.class == RegMask
@@ -3852,7 +3880,7 @@ const type_names[] =
{ { .bitfield = { .class = RegCR } }, "control reg" },
{ { .bitfield = { .class = RegTR } }, "test reg" },
{ { .bitfield = { .class = RegDR } }, "debug reg" },
- { { .bitfield = { .class = Reg, .tbyte = 1 } }, "FReg" },
+ { { .bitfield = { .class = RegFP, .tbyte = 1 } }, "FReg" },
{ { .bitfield = { .instance = Accum, .tbyte = 1 } }, "FAcc" },
{ { .bitfield = { .class = SReg } }, "SReg" },
{ { .bitfield = { .class = RegMMX } }, "rMMX" },
--- a/gas/testsuite/gas/i386/inval-type.l
+++ b/gas/testsuite/gas/i386/inval-type.l
@@ -4,7 +4,10 @@
.*: Error: operand type mismatch for .bsf.
.*: Error: operand type mismatch for .bswap.
.*: Error: operand type mismatch for .bswap.
+.*: Error: operand type mismatch for .bswap.
+.*: Error: operand type mismatch for .fcomi.
.*: Error: operand type mismatch for .fcomi.
.*: Error: operand type mismatch for .in.
+.*: Error: operand type mismatch for .in.
.*: Error: operand type mismatch for .movntdqa.
.*: Error: operand type mismatch for .movntdq.
--- a/gas/testsuite/gas/i386/inval-type.s
+++ b/gas/testsuite/gas/i386/inval-type.s
@@ -6,9 +6,12 @@
blendvps %eax, %xmm1, %xmm2
blendvps %st, %xmm1, %xmm2
bsf %eax, (%eax)
+ bswap %st
bswap %mm0
bswapl %xmm0
+ fcomi %st(1), %eax
fcomi %st(1), %xmm0
+ inl $0, %st
inl $0, %xmm0
movntdqa %xmm0, (%eax)
movntdq (%eax), %xmm0
--- a/opcodes/i386-gen.c
+++ b/opcodes/i386-gen.c
@@ -540,6 +540,7 @@ static const struct {
} operand_classes[] = {
CLASS (Reg),
CLASS (SReg),
+ CLASS (RegFP),
CLASS (RegCR),
CLASS (RegDR),
CLASS (RegTR),
--- a/opcodes/i386-opc.h
+++ b/opcodes/i386-opc.h
@@ -863,8 +863,9 @@ typedef struct i386_opcode_modifier
enum operand_class
{
ClassNone,
- Reg, /* GPRs and FP regs, distinguished by operand size */
+ Reg, /* GPRs, distinguished by operand size */
SReg, /* Segment register */
+ RegFP, /* FP regs */
RegCR, /* Control register */
RegDR, /* Debug register */
RegTR, /* Test register */
--- a/opcodes/i386-opc.tbl
+++ b/opcodes/i386-opc.tbl
@@ -44,7 +44,7 @@
#define InOutPortReg RegD|Word
#define FloatAcc Acc|Tbyte
-#define FloatReg Class=Reg|Tbyte
+#define FloatReg Class=RegFP|Tbyte
#define SReg Class=SReg
--- a/opcodes/i386-reg.tbl
+++ b/opcodes/i386-reg.tbl
@@ -367,14 +367,14 @@ eip, Dword, RegRex64, RegIP, 8, Dw2Inval
riz, Qword|BaseIndex, RegRex64, RegIZ, Dw2Inval, Dw2Inval
eiz, Dword|BaseIndex, 0, RegIZ, Dw2Inval, Dw2Inval
// fp regs. No need for an explicit st(0) here.
-st, Class=Reg|Instance=Accum|Tbyte, 0, 0, 11, 33
-st(1), Class=Reg|Tbyte, 0, 1, 12, 34
-st(2), Class=Reg|Tbyte, 0, 2, 13, 35
-st(3), Class=Reg|Tbyte, 0, 3, 14, 36
-st(4), Class=Reg|Tbyte, 0, 4, 15, 37
-st(5), Class=Reg|Tbyte, 0, 5, 16, 38
-st(6), Class=Reg|Tbyte, 0, 6, 17, 39
-st(7), Class=Reg|Tbyte, 0, 7, 18, 40
+st, Class=RegFP|Instance=Accum|Tbyte, 0, 0, 11, 33
+st(1), Class=RegFP|Tbyte, 0, 1, 12, 34
+st(2), Class=RegFP|Tbyte, 0, 2, 13, 35
+st(3), Class=RegFP|Tbyte, 0, 3, 14, 36
+st(4), Class=RegFP|Tbyte, 0, 4, 15, 37
+st(5), Class=RegFP|Tbyte, 0, 5, 16, 38
+st(6), Class=RegFP|Tbyte, 0, 6, 17, 39
+st(7), Class=RegFP|Tbyte, 0, 7, 18, 40
// Pseudo-register names only used in .cfi_* directives
eflags, 0, 0, 0, 9, 49
rflags, 0, 0, 0, Dw2Inval, 49
More information about the Binutils
mailing list