x86: improve match_template()'s diagnostics

At the example of

	extractps $0, %xmm0, %xmm0
	insertps $0, %xmm0, %eax

(both having respectively the same mistake of using the wrong kind of
destination register) it is easy to see that current behavior is far
from ideal: The former results in "unsupported instruction" for 32-bit
code simply because the 2nd template we have is a Cpu64 one. Instead we
should aim at emitting the "best" possible error, which will typically
be the one where we passed the largest number of checks. Generalize the
original "specific_error" approach by making it apply to the entire
matching loop, utilizing that line numbers increase as we pass further
checks.
This commit is contained in:
Jan Beulich
2022-09-30 10:13:39 +02:00
parent 1cb0ab18ad
commit 7b94647ad0
7 changed files with 86 additions and 67 deletions

View File

@ -2083,12 +2083,7 @@ operand_size_match (const insn_template *t)
} }
if (!t->opcode_modifier.d) if (!t->opcode_modifier.d)
{ return match;
mismatch:
if (!match)
i.error = operand_size_mismatch;
return match;
}
/* Check reverse. */ /* Check reverse. */
gas_assert ((i.operands >= 2 && i.operands <= 3) gas_assert ((i.operands >= 2 && i.operands <= 3)
@ -2105,19 +2100,19 @@ operand_size_match (const insn_template *t)
if (t->operand_types[j].bitfield.class == Reg if (t->operand_types[j].bitfield.class == Reg
&& !match_operand_size (t, j, given)) && !match_operand_size (t, j, given))
goto mismatch; return match;
if (t->operand_types[j].bitfield.class == RegSIMD if (t->operand_types[j].bitfield.class == RegSIMD
&& !match_simd_size (t, j, given)) && !match_simd_size (t, j, given))
goto mismatch; return match;
if (t->operand_types[j].bitfield.instance == Accum if (t->operand_types[j].bitfield.instance == Accum
&& (!match_operand_size (t, j, given) && (!match_operand_size (t, j, given)
|| !match_simd_size (t, j, given))) || !match_simd_size (t, j, given)))
goto mismatch; return match;
if ((i.flags[given] & Operand_Mem) && !match_mem_size (t, j, given)) if ((i.flags[given] & Operand_Mem) && !match_mem_size (t, j, given))
goto mismatch; return match;
} }
return match | MATCH_REVERSE; return match | MATCH_REVERSE;
@ -6386,6 +6381,17 @@ VEX_check_encoding (const insn_template *t)
return 0; return 0;
} }
/* Helper function for the progress() macro in match_template(). */
static INLINE enum i386_error progress (enum i386_error new,
enum i386_error last,
unsigned int line, unsigned int *line_p)
{
if (line <= *line_p)
return last;
*line_p = line;
return new;
}
static const insn_template * static const insn_template *
match_template (char mnem_suffix) match_template (char mnem_suffix)
{ {
@ -6397,8 +6403,9 @@ match_template (char mnem_suffix)
i386_opcode_modifier suffix_check; i386_opcode_modifier suffix_check;
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, size_match, check_register; unsigned int j, size_match, check_register, errline = __LINE__;
enum i386_error specific_error = 0; enum i386_error specific_error = number_of_operands_mismatch;
#define progress(err) progress (err, specific_error, __LINE__, &errline)
#if MAX_OPERANDS != 5 #if MAX_OPERANDS != 5
# error "MAX_OPERANDS must be 5." # error "MAX_OPERANDS must be 5."
@ -6436,36 +6443,33 @@ match_template (char mnem_suffix)
suffix_check.no_ldsuf = 1; suffix_check.no_ldsuf = 1;
} }
/* Must have right number of operands. */
i.error = number_of_operands_mismatch;
for (t = current_templates->start; t < current_templates->end; t++) for (t = current_templates->start; t < current_templates->end; t++)
{ {
addr_prefix_disp = -1; addr_prefix_disp = -1;
found_reverse_match = 0; found_reverse_match = 0;
/* Must have right number of operands. */
if (i.operands != t->operands) if (i.operands != t->operands)
continue; continue;
/* Check processor support. */ /* Check processor support. */
i.error = unsupported; specific_error = progress (unsupported);
if (cpu_flags_match (t) != CPU_FLAGS_PERFECT_MATCH) if (cpu_flags_match (t) != CPU_FLAGS_PERFECT_MATCH)
continue; continue;
/* Check Pseudo Prefix. */ /* Check Pseudo Prefix. */
i.error = unsupported;
if (t->opcode_modifier.pseudovexprefix if (t->opcode_modifier.pseudovexprefix
&& !(i.vec_encoding == vex_encoding_vex && !(i.vec_encoding == vex_encoding_vex
|| i.vec_encoding == vex_encoding_vex3)) || i.vec_encoding == vex_encoding_vex3))
continue; continue;
/* Check AT&T mnemonic. */ /* Check AT&T mnemonic. */
i.error = unsupported_with_intel_mnemonic; specific_error = progress (unsupported_with_intel_mnemonic);
if (intel_mnemonic && t->opcode_modifier.attmnemonic) if (intel_mnemonic && t->opcode_modifier.attmnemonic)
continue; continue;
/* Check AT&T/Intel syntax. */ /* Check AT&T/Intel syntax. */
i.error = unsupported_syntax; specific_error = progress (unsupported_syntax);
if ((intel_syntax && t->opcode_modifier.attsyntax) if ((intel_syntax && t->opcode_modifier.attsyntax)
|| (!intel_syntax && t->opcode_modifier.intelsyntax)) || (!intel_syntax && t->opcode_modifier.intelsyntax))
continue; continue;
@ -6491,7 +6495,7 @@ match_template (char mnem_suffix)
} }
/* Check the suffix. */ /* Check the suffix. */
i.error = invalid_instruction_suffix; specific_error = progress (invalid_instruction_suffix);
if ((t->opcode_modifier.no_bsuf && suffix_check.no_bsuf) if ((t->opcode_modifier.no_bsuf && suffix_check.no_bsuf)
|| (t->opcode_modifier.no_wsuf && suffix_check.no_wsuf) || (t->opcode_modifier.no_wsuf && suffix_check.no_wsuf)
|| (t->opcode_modifier.no_lsuf && suffix_check.no_lsuf) || (t->opcode_modifier.no_lsuf && suffix_check.no_lsuf)
@ -6500,6 +6504,7 @@ match_template (char mnem_suffix)
|| (t->opcode_modifier.no_ldsuf && suffix_check.no_ldsuf)) || (t->opcode_modifier.no_ldsuf && suffix_check.no_ldsuf))
continue; continue;
specific_error = progress (operand_size_mismatch);
size_match = operand_size_match (t); size_match = operand_size_match (t);
if (!size_match) if (!size_match)
continue; continue;
@ -6510,11 +6515,9 @@ match_template (char mnem_suffix)
as the case of a missing * on the operand is accepted (perhaps with as the case of a missing * on the operand is accepted (perhaps with
a warning, issued further down). */ a warning, issued further down). */
specific_error = progress (operand_type_mismatch);
if (i.jumpabsolute && t->opcode_modifier.jump != JUMP_ABSOLUTE) if (i.jumpabsolute && t->opcode_modifier.jump != JUMP_ABSOLUTE)
{ continue;
i.error = operand_type_mismatch;
continue;
}
for (j = 0; j < MAX_OPERANDS; j++) for (j = 0; j < MAX_OPERANDS; j++)
operand_types[j] = t->operand_types[j]; operand_types[j] = t->operand_types[j];
@ -6522,6 +6525,8 @@ match_template (char mnem_suffix)
/* In general, don't allow /* In general, don't allow
- 64-bit operands outside of 64-bit mode, - 64-bit operands outside of 64-bit mode,
- 32-bit operands on pre-386. */ - 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); j = i.imm_operands + (t->operands > i.imm_operands + 1);
if (((i.suffix == QWORD_MNEM_SUFFIX if (((i.suffix == QWORD_MNEM_SUFFIX
&& flag_code != CODE_64BIT && flag_code != CODE_64BIT
@ -6550,7 +6555,7 @@ match_template (char mnem_suffix)
{ {
if (VEX_check_encoding (t)) if (VEX_check_encoding (t))
{ {
specific_error = i.error; specific_error = progress (i.error);
continue; continue;
} }
@ -6711,6 +6716,8 @@ match_template (char mnem_suffix)
i.types[1], i.types[1],
operand_types[1]))) operand_types[1])))
{ {
specific_error = progress (i.error);
/* Check if other direction is valid ... */ /* Check if other direction is valid ... */
if (!t->opcode_modifier.d) if (!t->opcode_modifier.d)
continue; continue;
@ -6735,6 +6742,7 @@ match_template (char mnem_suffix)
operand_types[0]))) operand_types[0])))
{ {
/* Does not match either direction. */ /* Does not match either direction. */
specific_error = progress (i.error);
continue; continue;
} }
/* found_reverse_match holds which of D or FloatR /* found_reverse_match holds which of D or FloatR
@ -6773,7 +6781,10 @@ match_template (char mnem_suffix)
operand_types[3], operand_types[3],
i.types[4], i.types[4],
operand_types[4])) operand_types[4]))
continue; {
specific_error = progress (i.error);
continue;
}
/* Fall through. */ /* Fall through. */
case 4: case 4:
overlap3 = operand_type_and (i.types[3], operand_types[3]); overlap3 = operand_type_and (i.types[3], operand_types[3]);
@ -6788,7 +6799,10 @@ match_template (char mnem_suffix)
operand_types[2], operand_types[2],
i.types[3], i.types[3],
operand_types[3]))) operand_types[3])))
continue; {
specific_error = progress (i.error);
continue;
}
/* Fall through. */ /* Fall through. */
case 3: case 3:
overlap2 = operand_type_and (i.types[2], operand_types[2]); overlap2 = operand_type_and (i.types[2], operand_types[2]);
@ -6803,7 +6817,10 @@ match_template (char mnem_suffix)
operand_types[1], operand_types[1],
i.types[2], i.types[2],
operand_types[2]))) operand_types[2])))
continue; {
specific_error = progress (i.error);
continue;
}
break; break;
} }
} }
@ -6814,14 +6831,14 @@ match_template (char mnem_suffix)
/* Check if vector operands are valid. */ /* Check if vector operands are valid. */
if (check_VecOperands (t)) if (check_VecOperands (t))
{ {
specific_error = i.error; specific_error = progress (i.error);
continue; continue;
} }
/* Check if VEX/EVEX encoding requirements can be satisfied. */ /* Check if VEX/EVEX encoding requirements can be satisfied. */
if (VEX_check_encoding (t)) if (VEX_check_encoding (t))
{ {
specific_error = i.error; specific_error = progress (i.error);
continue; continue;
} }
@ -6829,11 +6846,13 @@ match_template (char mnem_suffix)
break; break;
} }
#undef progress
if (t == current_templates->end) if (t == current_templates->end)
{ {
/* We found no match. */ /* We found no match. */
const char *err_msg; const char *err_msg;
switch (specific_error ? specific_error : i.error) switch (specific_error)
{ {
default: default:
abort (); abort ();

View File

@ -1,3 +1,3 @@
.*: Assembler messages: .*: Assembler messages:
.*:3: Error: operand size mismatch for `kmovd' .*:3: Error: .* `kmovd'
.*:4: Error: operand size mismatch for `kmovd' .*:4: Error: .* `kmovd'

View File

@ -1,14 +1,14 @@
.*: Assembler messages: .*: Assembler messages:
.*:25: Error: .*unsupported instruction.* .*:25: Error: .*operand size mismatch.*
.*:26: Error: .*unsupported masking.* .*:26: Error: .*unsupported masking.*
.*:27: Error: .*unsupported masking.* .*:27: Error: .*unsupported masking.*
.*:47: Error: .*unsupported instruction.* .*:47: Error: .*operand size mismatch.*
.*:48: Error: .*unsupported masking.* .*:48: Error: .*unsupported masking.*
.*:49: Error: .*unsupported masking.* .*:49: Error: .*unsupported masking.*
.*:50: Error: .*not supported.* .*:50: Error: .*not supported.*
.*:51: Error: .*not supported.* .*:51: Error: .*not supported.*
.*:52: Error: .*not supported.* .*:52: Error: .*not supported.*
.*:69: Error: .*unsupported instruction.* .*:69: Error: .*operand size mismatch.*
.*:70: Error: .*unsupported masking.* .*:70: Error: .*unsupported masking.*
.*:71: Error: .*unsupported masking.* .*:71: Error: .*unsupported masking.*
.*:72: Error: .*not supported.* .*:72: Error: .*not supported.*
@ -17,7 +17,7 @@
.*:75: Error: .*not supported.* .*:75: Error: .*not supported.*
.*:76: Error: .*not supported.* .*:76: Error: .*not supported.*
.*:77: Error: .*not supported.* .*:77: Error: .*not supported.*
.*:91: Error: .*unsupported instruction.* .*:91: Error: .*operand size mismatch.*
.*:92: Error: .*unsupported masking.* .*:92: Error: .*unsupported masking.*
.*:93: Error: .*unsupported masking.* .*:93: Error: .*unsupported masking.*
.*:94: Error: .*not supported.* .*:94: Error: .*not supported.*
@ -27,7 +27,7 @@
.*:98: Error: .*not supported.* .*:98: Error: .*not supported.*
.*:99: Error: .*not supported.* .*:99: Error: .*not supported.*
.*:100: Error: .*not supported.* .*:100: Error: .*not supported.*
.*:113: Error: .*unsupported instruction.* .*:113: Error: .*operand size mismatch.*
.*:114: Error: .*unsupported masking.* .*:114: Error: .*unsupported masking.*
.*:115: Error: .*unsupported masking.* .*:115: Error: .*unsupported masking.*
.*:116: Error: .*not supported.* .*:116: Error: .*not supported.*
@ -40,7 +40,7 @@
.*:126: Error: .*not supported.* .*:126: Error: .*not supported.*
.*:127: Error: .*not supported.* .*:127: Error: .*not supported.*
.*:128: Error: .*not supported.* .*:128: Error: .*not supported.*
.*:135: Error: .*unsupported instruction.* .*:135: Error: .*operand size mismatch.*
.*:136: Error: .*unsupported masking.* .*:136: Error: .*unsupported masking.*
.*:137: Error: .*unsupported masking.* .*:137: Error: .*unsupported masking.*
.*:138: Error: .*not supported.* .*:138: Error: .*not supported.*
@ -54,7 +54,7 @@
.*:149: Error: .*not supported.* .*:149: Error: .*not supported.*
.*:150: Error: .*not supported.* .*:150: Error: .*not supported.*
.*:151: Error: .*not supported.* .*:151: Error: .*not supported.*
.*:157: Error: .*unsupported instruction.* .*:157: Error: .*operand size mismatch.*
.*:158: Error: .*unsupported masking.* .*:158: Error: .*unsupported masking.*
.*:159: Error: .*unsupported masking.* .*:159: Error: .*unsupported masking.*
.*:160: Error: .*not supported.* .*:160: Error: .*not supported.*

View File

@ -1,12 +1,12 @@
.*: Assembler messages: .*: Assembler messages:
.*:26: Error: .*unsupported instruction.* .*:26: Error: .*unsupported masking.*
.*:27: Error: .*unsupported instruction.* .*:27: Error: .*unsupported masking.*
.*:29: Error: .*unsupported instruction.* .*:29: Error: .*unsupported instruction.*
.*:30: Error: .*unsupported instruction.* .*:30: Error: .*unsupported instruction.*
.*:32: Error: .*unsupported instruction.* .*:32: Error: .*unsupported instruction.*
.*:33: Error: .*unsupported instruction.* .*:33: Error: .*unsupported instruction.*
.*:36: Error: .*unsupported instruction.* .*:36: Error: .*unsupported masking.*
.*:37: Error: .*unsupported instruction.* .*:37: Error: .*unsupported masking.*
.*:39: Error: .*unsupported instruction.* .*:39: Error: .*unsupported instruction.*
.*:40: Error: .*unsupported instruction.* .*:40: Error: .*unsupported instruction.*
.*:43: Error: .*unsupported instruction.* .*:43: Error: .*unsupported instruction.*

View File

@ -1,19 +1,19 @@
.*: Assembler messages: .*: Assembler messages:
.*:2: Error: invalid instruction suffix for `call' .*:2: Error: invalid instruction suffix for `call'
.*:3: Error: invalid instruction suffix for `call' .*:3: Error: invalid instruction suffix for `call'
.*:4: Error: operand type mismatch for `jmp' .*:4: Error: operand (size|type) mismatch for `jmp'
.*:5: Error: invalid instruction suffix for `jmp' .*:5: Error: invalid instruction suffix for `jmp'
.*:6: Error: invalid instruction suffix for `jmp' .*:6: Error: invalid instruction suffix for `jmp'
.*:7: Error: invalid instruction suffix for `ret' .*:7: Error: invalid instruction suffix for `ret'
.*:8: Error: invalid instruction suffix for `ret' .*:8: Error: invalid instruction suffix for `ret'
.*:11: Error: operand type mismatch for `call' .*:11: Error: operand (size|type) mismatch for `call'
.*:12: Error: invalid instruction suffix for `call' .*:12: Error: invalid instruction suffix for `call'
.*:13: Error: invalid instruction suffix for `call' .*:13: Error: invalid instruction suffix for `call'
.*:14: Error: operand size mismatch for `call' .*:14: Error: operand (size|type) mismatch for `call'
.*:15: Error: operand type mismatch for `jmp' .*:15: Error: operand (size|type) mismatch for `jmp'
.*:16: Error: invalid instruction suffix for `jmp' .*:16: Error: invalid instruction suffix for `jmp'
.*:17: Error: invalid instruction suffix for `jmp' .*:17: Error: invalid instruction suffix for `jmp'
.*:18: Error: operand size mismatch for `jmp' .*:18: Error: operand (size|type) mismatch for `jmp'
.*:19: Error: invalid instruction suffix for `ret' .*:19: Error: invalid instruction suffix for `ret'
.*:20: Error: invalid instruction suffix for `ret' .*:20: Error: invalid instruction suffix for `ret'
GAS LISTING .* GAS LISTING .*

View File

@ -1,19 +1,19 @@
.*: Assembler messages: .*: Assembler messages:
.*:2: Error: unsupported syntax for `lcall' .*:2: Error: invalid instruction suffix for `lcall'
.*:3: Error: unsupported syntax for `lfs' .*:3: Error: operand size mismatch for `lfs'
.*:4: Error: unsupported syntax for `lfs' .*:4: Error: invalid instruction suffix for `lfs'
.*:5: Error: unsupported syntax for `lgs' .*:5: Error: operand size mismatch for `lgs'
.*:6: Error: unsupported syntax for `lgs' .*:6: Error: invalid instruction suffix for `lgs'
.*:7: Error: unsupported syntax for `ljmp' .*:7: Error: invalid instruction suffix for `ljmp'
.*:8: Error: unsupported syntax for `lss' .*:8: Error: operand size mismatch for `lss'
.*:9: Error: unsupported syntax for `lss' .*:9: Error: invalid instruction suffix for `lss'
.*:12: Error: unsupported syntax for `call' .*:12: Error: operand (size|type) mismatch for `call'
.*:13: Error: unsupported syntax for `lfs' .*:13: Error: operand size mismatch for `lfs'
.*:14: Error: unsupported syntax for `lfs' .*:14: Error: operand size mismatch for `lfs'
.*:15: Error: unsupported syntax for `lgs' .*:15: Error: operand size mismatch for `lgs'
.*:16: Error: unsupported syntax for `lgs' .*:16: Error: operand size mismatch for `lgs'
.*:17: Error: unsupported syntax for `jmp' .*:17: Error: operand (size|type) mismatch for `jmp'
.*:18: Error: unsupported syntax for `lss' .*:18: Error: operand size mismatch for `lss'
.*:19: Error: unsupported syntax for `lss' .*:19: Error: operand size mismatch for `lss'
GAS LISTING .* GAS LISTING .*
#pass #pass

View File

@ -1,3 +1,3 @@
.*: Assembler messages: .*: Assembler messages:
.*:3: Error: operand size mismatch for `kmovq' .*:3: Error: .* `kmovq'
.*:4: Error: operand size mismatch for `kmovq' .*:4: Error: .* `kmovq'