x86: fix operand size checking

Currently mov to/from control, debug, and test register insns accept any
size GPR operand (general pattern: templates with D set and both
operands being registers in distinct register files). This is due to
improper checking of the reverse case, including not informing the
caller whether a straight and/or reverse match was successful.

The helper functions need to be told two indexes: One to index the given
operand types array, and the other to index the template one. The caller
must attempt a further straight match only if the function reported a
straight match (and respectively for reverse matches).
This commit is contained in:
Jan Beulich 2018-07-16 08:19:21 +02:00 committed by Jan Beulich
parent 4ad422a635
commit 3ac21baa84
4 changed files with 123 additions and 86 deletions

View File

@ -1,3 +1,19 @@
2018-07-16 Jan Beulich <jbeulich@suse.com>
* config/tc-i386.c (match_reg_size): Split second parameter
into two.
(match_simd_size): Likewise.
(match_mem_size): Likewise.
(MATCH_STRAIGHT, MATCH_REVERSE): Define.
(operand_size_match): Change return type. New local variable
"match". Always check for reverse match when opcode_modifier.d
is set.
(match_template) New local variable "size_match". Skip further
matching if operand_size_match() did not report a respective
match.
* testsuite/gas/i386/inval.s: Add control register reads/writes.
* testsuite/gas/i386/inval.l: Adjust expectations.
2018-07-13 Nick Clifton <nickc@redhat.com> 2018-07-13 Nick Clifton <nickc@redhat.com>
* testsuite/gas/elf/missing-build-notes.s: New test. Checks that * testsuite/gas/elf/missing-build-notes.s: New test. Checks that

View File

@ -1901,70 +1901,74 @@ operand_type_check (i386_operand_type t, enum operand_type c)
operand J for instruction template T. */ operand J for instruction template T. */
static INLINE int static INLINE int
match_reg_size (const insn_template *t, unsigned int j) match_reg_size (const insn_template *t, unsigned int wanted, unsigned int given)
{ {
return !((i.types[j].bitfield.byte return !((i.types[given].bitfield.byte
&& !t->operand_types[j].bitfield.byte) && !t->operand_types[wanted].bitfield.byte)
|| (i.types[j].bitfield.word || (i.types[given].bitfield.word
&& !t->operand_types[j].bitfield.word) && !t->operand_types[wanted].bitfield.word)
|| (i.types[j].bitfield.dword || (i.types[given].bitfield.dword
&& !t->operand_types[j].bitfield.dword) && !t->operand_types[wanted].bitfield.dword)
|| (i.types[j].bitfield.qword || (i.types[given].bitfield.qword
&& !t->operand_types[j].bitfield.qword) && !t->operand_types[wanted].bitfield.qword)
|| (i.types[j].bitfield.tbyte || (i.types[given].bitfield.tbyte
&& !t->operand_types[j].bitfield.tbyte)); && !t->operand_types[wanted].bitfield.tbyte));
} }
/* Return 1 if there is no conflict in SIMD register on /* Return 1 if there is no conflict in SIMD register on
operand J for instruction template T. */ operand J for instruction template T. */
static INLINE int static INLINE int
match_simd_size (const insn_template *t, unsigned int j) match_simd_size (const insn_template *t, unsigned int wanted, unsigned int given)
{ {
return !((i.types[j].bitfield.xmmword return !((i.types[given].bitfield.xmmword
&& !t->operand_types[j].bitfield.xmmword) && !t->operand_types[wanted].bitfield.xmmword)
|| (i.types[j].bitfield.ymmword || (i.types[given].bitfield.ymmword
&& !t->operand_types[j].bitfield.ymmword) && !t->operand_types[wanted].bitfield.ymmword)
|| (i.types[j].bitfield.zmmword || (i.types[given].bitfield.zmmword
&& !t->operand_types[j].bitfield.zmmword)); && !t->operand_types[wanted].bitfield.zmmword));
} }
/* Return 1 if there is no conflict in any size on operand J for /* Return 1 if there is no conflict in any size on operand J for
instruction template T. */ instruction template T. */
static INLINE int static INLINE int
match_mem_size (const insn_template *t, unsigned int j) match_mem_size (const insn_template *t, unsigned int wanted, unsigned int given)
{ {
return (match_reg_size (t, j) return (match_reg_size (t, wanted, given)
&& !((i.types[j].bitfield.unspecified && !((i.types[given].bitfield.unspecified
&& !i.broadcast && !i.broadcast
&& !t->operand_types[j].bitfield.unspecified) && !t->operand_types[wanted].bitfield.unspecified)
|| (i.types[j].bitfield.fword || (i.types[given].bitfield.fword
&& !t->operand_types[j].bitfield.fword) && !t->operand_types[wanted].bitfield.fword)
/* For scalar opcode templates to allow register and memory /* For scalar opcode templates to allow register and memory
operands at the same time, some special casing is needed operands at the same time, some special casing is needed
here. Also for v{,p}broadcast*, {,v}pmov{s,z}*, and here. Also for v{,p}broadcast*, {,v}pmov{s,z}*, and
down-conversion vpmov*. */ down-conversion vpmov*. */
|| ((t->operand_types[j].bitfield.regsimd || ((t->operand_types[wanted].bitfield.regsimd
&& !t->opcode_modifier.broadcast && !t->opcode_modifier.broadcast
&& (t->operand_types[j].bitfield.byte && (t->operand_types[wanted].bitfield.byte
|| t->operand_types[j].bitfield.word || t->operand_types[wanted].bitfield.word
|| t->operand_types[j].bitfield.dword || t->operand_types[wanted].bitfield.dword
|| t->operand_types[j].bitfield.qword)) || t->operand_types[wanted].bitfield.qword))
? (i.types[j].bitfield.xmmword ? (i.types[given].bitfield.xmmword
|| i.types[j].bitfield.ymmword || i.types[given].bitfield.ymmword
|| i.types[j].bitfield.zmmword) || i.types[given].bitfield.zmmword)
: !match_simd_size(t, j)))); : !match_simd_size(t, wanted, given))));
} }
/* Return 1 if there is no size conflict on any operands for /* Return value has MATCH_STRAIGHT set if there is no size conflict on any
instruction template T. */ operands for instruction template T, and it has MATCH_REVERSE set if there
is no size conflict on any operands for the template with operands reversed
(and the template allows for reversing in the first place). */
static INLINE int #define MATCH_STRAIGHT 1
#define MATCH_REVERSE 2
static INLINE unsigned int
operand_size_match (const insn_template *t) operand_size_match (const insn_template *t)
{ {
unsigned int j; unsigned int j, match = MATCH_STRAIGHT;
int match = 1;
/* Don't check jump instructions. */ /* Don't check jump instructions. */
if (t->opcode_modifier.jump if (t->opcode_modifier.jump
@ -1981,59 +1985,57 @@ operand_size_match (const insn_template *t)
continue; continue;
if (t->operand_types[j].bitfield.reg if (t->operand_types[j].bitfield.reg
&& !match_reg_size (t, j)) && !match_reg_size (t, j, j))
{ {
match = 0; match = 0;
break; break;
} }
if (t->operand_types[j].bitfield.regsimd if (t->operand_types[j].bitfield.regsimd
&& !match_simd_size (t, j)) && !match_simd_size (t, j, j))
{ {
match = 0; match = 0;
break; break;
} }
if (t->operand_types[j].bitfield.acc if (t->operand_types[j].bitfield.acc
&& (!match_reg_size (t, j) || !match_simd_size (t, j))) && (!match_reg_size (t, j, j) || !match_simd_size (t, j, j)))
{ {
match = 0; match = 0;
break; break;
} }
if (i.types[j].bitfield.mem && !match_mem_size (t, j)) if (i.types[j].bitfield.mem && !match_mem_size (t, j, j))
{ {
match = 0; match = 0;
break; break;
} }
} }
if (match) if (!t->opcode_modifier.d)
return match;
else if (!t->opcode_modifier.d)
{ {
mismatch: mismatch:
i.error = operand_size_mismatch; if (!match)
return 0; i.error = operand_size_mismatch;
return match;
} }
/* Check reverse. */ /* Check reverse. */
gas_assert (i.operands == 2); gas_assert (i.operands == 2);
match = 1;
for (j = 0; j < 2; j++) for (j = 0; j < 2; j++)
{ {
if ((t->operand_types[j].bitfield.reg if ((t->operand_types[j].bitfield.reg
|| t->operand_types[j].bitfield.acc) || t->operand_types[j].bitfield.acc)
&& !match_reg_size (t, j ? 0 : 1)) && !match_reg_size (t, j, !j))
goto mismatch; goto mismatch;
if (i.types[j].bitfield.mem if (i.types[!j].bitfield.mem
&& !match_mem_size (t, j ? 0 : 1)) && !match_mem_size (t, j, !j))
goto mismatch; goto mismatch;
} }
return match; return match | MATCH_REVERSE;
} }
static INLINE int static INLINE int
@ -5286,7 +5288,7 @@ match_template (char mnem_suffix)
i386_operand_type operand_types [MAX_OPERANDS]; i386_operand_type operand_types [MAX_OPERANDS];
int addr_prefix_disp; int addr_prefix_disp;
unsigned int j; unsigned int j;
unsigned int found_cpu_match; unsigned int found_cpu_match, size_match;
unsigned int check_register; unsigned int check_register;
enum i386_error specific_error = 0; enum i386_error specific_error = 0;
@ -5375,7 +5377,8 @@ match_template (char mnem_suffix)
|| (t->opcode_modifier.no_ldsuf && mnemsuf_check.no_ldsuf)) || (t->opcode_modifier.no_ldsuf && mnemsuf_check.no_ldsuf))
continue; continue;
if (!operand_size_match (t)) size_match = operand_size_match (t);
if (!size_match)
continue; continue;
for (j = 0; j < MAX_OPERANDS; j++) for (j = 0; j < MAX_OPERANDS; j++)
@ -5502,6 +5505,8 @@ match_template (char mnem_suffix)
&& i.types[0].bitfield.acc && i.types[0].bitfield.acc
&& operand_type_check (i.types[1], anymem)) && operand_type_check (i.types[1], anymem))
continue; continue;
if (!(size_match & MATCH_STRAIGHT))
goto check_reverse;
/* If we want store form, we reverse direction of operands. */ /* If we want store form, we reverse direction of operands. */
if (i.dir_encoding == dir_encoding_store if (i.dir_encoding == dir_encoding_store
&& t->opcode_modifier.d) && t->opcode_modifier.d)
@ -5531,6 +5536,8 @@ match_template (char mnem_suffix)
continue; continue;
check_reverse: check_reverse:
if (!(size_match & MATCH_REVERSE))
continue;
/* Try reversing direction of operands. */ /* Try reversing direction of operands. */
overlap0 = operand_type_and (i.types[0], operand_types[1]); overlap0 = operand_type_and (i.types[0], operand_types[1]);
overlap1 = operand_type_and (i.types[1], operand_types[0]); overlap1 = operand_type_and (i.types[1], operand_types[0]);

View File

@ -59,11 +59,10 @@
.*:63: Error: .* .*:63: Error: .*
.*:64: Error: .* .*:64: Error: .*
.*:65: Error: .* .*:65: Error: .*
.*:68: Error: .* .*:67: Error: .*mov.*
.*:69: Error: .* .*:68: Error: .*mov.*
.*:70: Error: .* .*:69: Error: .*mov.*
.*:71: Error: .* .*:70: Error: .*mov.*
.*:72: Error: .*
.*:73: Error: .* .*:73: Error: .*
.*:74: Error: .* .*:74: Error: .*
.*:75: Error: .* .*:75: Error: .*
@ -75,14 +74,19 @@
.*:81: Error: .* .*:81: Error: .*
.*:82: Error: .* .*:82: Error: .*
.*:83: Error: .* .*:83: Error: .*
.*:84: Error: .*
.*:85: Error: .* .*:85: Error: .*
.*:86: Error: .* .*:86: Error: .*
.*:87: Error: .* .*:87: Error: .*
.*:88: Error: .* .*:88: Error: .*
.*:90: Error: .* .*:90: Error: .*
.*:92: Error: .*shl.* .*:91: Error: .*
.*:93: Error: .*rol.* .*:92: Error: .*
.*:94: Error: .*rcl.* .*:93: Error: .*
.*:95: Error: .*
.*:97: Error: .*shl.*
.*:98: Error: .*rol.*
.*:99: Error: .*rcl.*
GAS LISTING .* GAS LISTING .*
@ -155,30 +159,35 @@ GAS LISTING .*
[ ]*64[ ]+add \(%eiz\), %eax [ ]*64[ ]+add \(%eiz\), %eax
[ ]*65[ ]+add \(%eax\), %eiz [ ]*65[ ]+add \(%eax\), %eiz
[ ]*66[ ]+ [ ]*66[ ]+
[ ]*67[ ]+\.intel_syntax noprefix [ ]*[1-9][0-9]*[ ]+mov %cr0, %di
[ ]*68[ ]+cvtsi2ss xmm1,QWORD PTR \[eax\] [ ]*[1-9][0-9]*[ ]+mov %ax, %cr7
[ ]*69[ ]+cvtsi2sd xmm1,QWORD PTR \[eax\] [ ]*[1-9][0-9]*[ ]+mov %cr0, %bh
[ ]*70[ ]+cvtsi2ssq xmm1,QWORD PTR \[eax\] [ ]*[1-9][0-9]*[ ]+mov %al, %cr7
[ ]*71[ ]+cvtsi2sdq xmm1,QWORD PTR \[eax\] [ ]*[1-9][0-9]*[ ]+
[ ]*72[ ]+movq xmm1, XMMWORD PTR \[esp\] [ ]*[1-9][0-9]*[ ]+\.intel_syntax noprefix
[ ]*73[ ]+movq xmm1, DWORD PTR \[esp\] [ ]*[1-9][0-9]*[ ]+cvtsi2ss xmm1,QWORD PTR \[eax\]
[ ]*74[ ]+movq xmm1, WORD PTR \[esp\] [ ]*[1-9][0-9]*[ ]+cvtsi2sd xmm1,QWORD PTR \[eax\]
[ ]*75[ ]+movq xmm1, BYTE PTR \[esp\] [ ]*[1-9][0-9]*[ ]+cvtsi2ssq xmm1,QWORD PTR \[eax\]
[ ]*76[ ]+movq XMMWORD PTR \[esp\],xmm1 [ ]*[1-9][0-9]*[ ]+cvtsi2sdq xmm1,QWORD PTR \[eax\]
[ ]*77[ ]+movq DWORD PTR \[esp\],xmm1 [ ]*[1-9][0-9]*[ ]+movq xmm1, XMMWORD PTR \[esp\]
[ ]*78[ ]+movq WORD PTR \[esp\],xmm1 [ ]*[1-9][0-9]*[ ]+movq xmm1, DWORD PTR \[esp\]
[ ]*79[ ]+movq BYTE PTR \[esp\],xmm1 [ ]*[1-9][0-9]*[ ]+movq xmm1, WORD PTR \[esp\]
[ ]*80[ ]+fnstsw eax [ ]*[1-9][0-9]*[ ]+movq xmm1, BYTE PTR \[esp\]
[ ]*81[ ]+fnstsw al [ ]*[1-9][0-9]*[ ]+movq XMMWORD PTR \[esp\],xmm1
[ ]*82[ ]+fstsw eax [ ]*[1-9][0-9]*[ ]+movq DWORD PTR \[esp\],xmm1
[ ]*83[ ]+fstsw al [ ]*[1-9][0-9]*[ ]+movq WORD PTR \[esp\],xmm1
[ ]*84[ ]+ [ ]*[1-9][0-9]*[ ]+movq BYTE PTR \[esp\],xmm1
[ ]*85[ ]+movsx ax, \[eax\] [ ]*[1-9][0-9]*[ ]+fnstsw eax
[ ]*86[ ]+movsx eax, \[eax\] [ ]*[1-9][0-9]*[ ]+fnstsw al
[ ]*87[ ]+movzx ax, \[eax\] [ ]*[1-9][0-9]*[ ]+fstsw eax
[ ]*88[ ]+movzx eax, \[eax\] [ ]*[1-9][0-9]*[ ]+fstsw al
[ ]*89[ ]+ [ ]*[1-9][0-9]*[ ]+
[ ]*90[ ]+movnti word ptr \[eax\], ax [ ]*[1-9][0-9]*[ ]+movsx ax, \[eax\]
[ ]*[1-9][0-9]*[ ]+movsx eax, \[eax\]
[ ]*[1-9][0-9]*[ ]+movzx ax, \[eax\]
[ ]*[1-9][0-9]*[ ]+movzx eax, \[eax\]
[ ]*[1-9][0-9]*[ ]+
[ ]*[1-9][0-9]*[ ]+movnti word ptr \[eax\], ax
[ ]*[1-9][0-9]*[ ]+ [ ]*[1-9][0-9]*[ ]+
[ ]*[1-9][0-9]*[ ]+shl \[eax\], 1 [ ]*[1-9][0-9]*[ ]+shl \[eax\], 1
[ ]*[1-9][0-9]*[ ]+rol \[ecx\], 2 [ ]*[1-9][0-9]*[ ]+rol \[ecx\], 2

View File

@ -64,6 +64,11 @@ movntiw %ax, (%eax)
add (%eiz), %eax add (%eiz), %eax
add (%eax), %eiz add (%eax), %eiz
mov %cr0, %di
mov %ax, %cr7
mov %cr0, %bh
mov %al, %cr7
.intel_syntax noprefix .intel_syntax noprefix
cvtsi2ss xmm1,QWORD PTR [eax] cvtsi2ss xmm1,QWORD PTR [eax]
cvtsi2sd xmm1,QWORD PTR [eax] cvtsi2sd xmm1,QWORD PTR [eax]