x86: improve matching diagnostics when %st is involved

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.
This commit is contained in:
Jan Beulich 2025-05-16 10:32:19 +02:00
parent a7148a799b
commit 101b4bb8f4
8 changed files with 7476 additions and 7440 deletions

View file

@ -2497,8 +2497,8 @@ operand_type_check (i386_operand_type t, enum operand_type c)
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,
@ -2518,13 +2518,22 @@ match_operand_size (const insn_template *t, unsigned int wanted,
|| (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,
@ -2541,13 +2550,15 @@ match_simd_size (const insn_template *t, unsigned int wanted,
}
/* 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)
&& (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 *t)
&& !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" },

View file

@ -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.

View file

@ -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

View file

@ -540,6 +540,7 @@ static const struct {
} operand_classes[] = {
CLASS (Reg),
CLASS (SReg),
CLASS (RegFP),
CLASS (RegCR),
CLASS (RegDR),
CLASS (RegTR),

View file

@ -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 */

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff