The VGATHER group of instructions requires that all three involved xmm/ymm registers are distinct. This patch adds code to check for this, and at once eliminates a superfluous check for not using PC-relative addressing for these instructions (the fact that an index register is required here already excludes valid PC-relative addresses). The severity of the resulting diagnostics can be controlled via command line option or directive. Note that this patch depends on the introduction of register_number(), which is being done by the patch at http://www.sourceware.org/ml/binutils/2012-08/msg00119.html. gas/ 2012-08-07 Jan Beulich * config/tc-i386.c (set_check): Renamed from set_sse_check. Generalize to also handle operand checking option. (enum i386_error): New enumerator 'invalid_vector_register_set'. (match_template): Handle it. (enum check_kind): Give it a tag. Drop sse_ prefixes from enumerators. (operand_check): New. (md_pseudo_table): Add "operand_check". (check_VecOperands): Don't special case RIP addressing. Check that vSIB operands use distinct vector registers unless no checking was requested. (OPTION_MOPERAND_CHECK): New. (md_parse_option): Handle it. (OPTION_MAVXSCALAR, OPTION_X32): Adjust. (md_longopts): Add "moperand-check". (md_show_usage): Add help text for it. gas/testsuite/ 2012-08-07 Jan Beulich * gas/i386/vgather-check-error.{s,l}: New. * gas/i386/vgather-check-none.{s,d}: New. * gas/i386/vgather-check-warn.{d,e}: New. * gas/i386/vgather-check.{s,d}: New. * gas/i386/x86-64-vgather-check-error.{s,l}: New. * gas/i386/x86-64-vgather-check-none.{s,d}: New. * gas/i386/x86-64-vgather-check-warn.{d,e}: New. * gas/i386/x86-64-vgather-check.{s,d}: New. * gas/i386/i386.exp: Run new tests. --- 2012-08-07/gas/config/tc-i386.c 2012-07-31 09:45:03.000000000 +0200 +++ 2012-08-07/gas/config/tc-i386.c 2012-08-07 11:53:37.000000000 +0200 @@ -144,7 +144,7 @@ static void set_16bit_gcc_code_flag (int static void set_intel_syntax (int); static void set_intel_mnemonic (int); static void set_allow_index_reg (int); -static void set_sse_check (int); +static void set_check (int); static void set_cpu_arch (int); #ifdef TE_PE static void pe_directive_secrel (int); @@ -221,6 +221,7 @@ enum i386_error unsupported_syntax, unsupported, invalid_vsib_address, + invalid_vector_register_set, unsupported_vector_index_register }; @@ -449,13 +450,13 @@ static int allow_naked_reg = 0; /* 1 if pseudo index register, eiz/riz, is allowed . */ static int allow_index_reg = 0; -static enum +static enum check_kind { - sse_check_none = 0, - sse_check_warning, - sse_check_error + check_none = 0, + check_warning, + check_error } -sse_check; +sse_check, operand_check = check_warning; /* Register prefix used for error message. */ static const char *register_prefix = "%"; @@ -847,7 +848,8 @@ const pseudo_typeS md_pseudo_table[] = {"att_mnemonic", set_intel_mnemonic, 0}, {"allow_index_reg", set_allow_index_reg, 1}, {"disallow_index_reg", set_allow_index_reg, 0}, - {"sse_check", set_sse_check, 0}, + {"sse_check", set_check, 0}, + {"operand_check", set_check, 1}, #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) {"largecomm", handle_large_common, 0}, #else @@ -2111,8 +2113,22 @@ set_allow_index_reg (int flag) } static void -set_sse_check (int dummy ATTRIBUTE_UNUSED) +set_check (int what) { + enum check_kind *kind; + const char *str; + + if (what) + { + kind = &operand_check; + str = "operand"; + } + else + { + kind = &sse_check; + str = "sse"; + } + SKIP_WHITESPACE (); if (!is_end_of_line[(unsigned char) *input_line_pointer]) @@ -2121,17 +2137,17 @@ set_sse_check (int dummy ATTRIBUTE_UNUSE int e = get_symbol_end (); if (strcmp (string, "none") == 0) - sse_check = sse_check_none; + *kind = check_none; else if (strcmp (string, "warning") == 0) - sse_check = sse_check_warning; + *kind = check_warning; else if (strcmp (string, "error") == 0) - sse_check = sse_check_error; + *kind = check_error; else - as_bad (_("bad argument to sse_check directive.")); + as_bad (_("bad argument to %s_check directive."), str); *input_line_pointer = e; } else - as_bad (_("missing argument for sse_check directive")); + as_bad (_("missing argument for %s_check directive"), str); demand_empty_rest_of_line (); } @@ -3140,7 +3156,7 @@ md_assemble (char *line) if (!(t = match_template ())) return; - if (sse_check != sse_check_none + if (sse_check != check_none && !i.tm.opcode_modifier.noavx && (i.tm.cpu_flags.bitfield.cpusse || i.tm.cpu_flags.bitfield.cpusse2 @@ -3149,7 +3165,7 @@ md_assemble (char *line) || i.tm.cpu_flags.bitfield.cpusse4_1 || i.tm.cpu_flags.bitfield.cpusse4_2)) { - (sse_check == sse_check_warning + (sse_check == check_warning ? as_warn : as_bad) (_("SSE instruction `%s' is used"), i.tm.name); } @@ -3969,18 +3985,38 @@ check_VecOperands (const insn_template * return 1; } - /* For VSIB byte, we need a vector register for index and no PC - relative addressing is allowed. */ - if (t->opcode_modifier.vecsib - && (!i.index_reg + /* For VSIB byte, we need a vector register for index, and all vector + registers must be distinct. */ + if (t->opcode_modifier.vecsib) + { + if (!i.index_reg || !((t->opcode_modifier.vecsib == VecSIB128 && i.index_reg->reg_type.bitfield.regxmm) || (t->opcode_modifier.vecsib == VecSIB256 - && i.index_reg->reg_type.bitfield.regymm)) - || (i.base_reg && i.base_reg->reg_num == RegRip))) - { - i.error = invalid_vsib_address; - return 1; + && i.index_reg->reg_type.bitfield.regymm))) + { + i.error = invalid_vsib_address; + return 1; + } + + gas_assert (i.reg_operands == 2); + gas_assert (i.types[0].bitfield.regxmm + || i.types[0].bitfield.regymm); + gas_assert (i.types[2].bitfield.regxmm + || i.types[2].bitfield.regymm); + + if (operand_check == check_none) + return 0; + if (register_number (i.op[0].regs) != register_number (i.index_reg) + && register_number (i.op[2].regs) != register_number (i.index_reg) + && register_number (i.op[0].regs) != register_number (i.op[2].regs)) + return 0; + if (operand_check == check_error) + { + i.error = invalid_vector_register_set; + return 1; + } + as_warn (_("mask, index, and destination registers should be distinct")); } return 0; @@ -4376,6 +4412,9 @@ check_reverse: case invalid_vsib_address: err_msg = _("invalid VSIB address"); break; + case invalid_vector_register_set: + err_msg = _("mask, index, and destination registers must be distinct"); + break; case unsupported_vector_index_register: err_msg = _("unsupported vector index register"); break; @@ -8408,8 +8447,9 @@ const char *md_shortopts = "qn"; #define OPTION_MOLD_GCC (OPTION_MD_BASE + 9) #define OPTION_MSSE2AVX (OPTION_MD_BASE + 10) #define OPTION_MSSE_CHECK (OPTION_MD_BASE + 11) -#define OPTION_MAVXSCALAR (OPTION_MD_BASE + 12) -#define OPTION_X32 (OPTION_MD_BASE + 13) +#define OPTION_MOPERAND_CHECK (OPTION_MD_BASE + 12) +#define OPTION_MAVXSCALAR (OPTION_MD_BASE + 13) +#define OPTION_X32 (OPTION_MD_BASE + 14) struct option md_longopts[] = { @@ -8431,6 +8471,7 @@ struct option md_longopts[] = {"mold-gcc", no_argument, NULL, OPTION_MOLD_GCC}, {"msse2avx", no_argument, NULL, OPTION_MSSE2AVX}, {"msse-check", required_argument, NULL, OPTION_MSSE_CHECK}, + {"moperand-check", required_argument, NULL, OPTION_MOPERAND_CHECK}, {"mavxscalar", required_argument, NULL, OPTION_MAVXSCALAR}, {NULL, no_argument, NULL, 0} }; @@ -8660,15 +8701,26 @@ md_parse_option (int c, char *arg) case OPTION_MSSE_CHECK: if (strcasecmp (arg, "error") == 0) - sse_check = sse_check_error; + sse_check = check_error; else if (strcasecmp (arg, "warning") == 0) - sse_check = sse_check_warning; + sse_check = check_warning; else if (strcasecmp (arg, "none") == 0) - sse_check = sse_check_none; + sse_check = check_none; else as_fatal (_("invalid -msse-check= option: `%s'"), arg); break; + case OPTION_MOPERAND_CHECK: + if (strcasecmp (arg, "error") == 0) + operand_check = check_error; + else if (strcasecmp (arg, "warning") == 0) + operand_check = check_warning; + else if (strcasecmp (arg, "none") == 0) + operand_check = check_none; + else + as_fatal (_("invalid -moperand-check= option: `%s'"), arg); + break; + case OPTION_MAVXSCALAR: if (strcasecmp (arg, "128") == 0) avxscalar = vex128; @@ -8807,6 +8859,9 @@ md_show_usage (FILE *stream) -msse-check=[none|error|warning]\n\ check SSE instructions\n")); fprintf (stream, _("\ + -moperand-check=[none|error|warning]\n\ + check operand combinations for validity\n")); + fprintf (stream, _("\ -mavxscalar=[128|256] encode scalar AVX instructions with specific vector\n\ length\n")); fprintf (stream, _("\ --- 2012-08-07/gas/testsuite/gas/i386/i386.exp 2012-07-24 14:52:59.000000000 +0200 +++ 2012-08-07/gas/testsuite/gas/i386/i386.exp 2012-08-07 11:53:38.000000000 +0200 @@ -160,6 +160,10 @@ if [expr ([istarget "i*86-*-*"] || [ist run_dump_test "sse-check-none" run_dump_test "sse-check-warn" run_list_test "sse-check-error" "-msse-check=error -I${srcdir}/$subdir -al" + run_dump_test "vgather-check" + run_dump_test "vgather-check-none" + run_dump_test "vgather-check-warn" + run_list_test "vgather-check-error" "-moperand-check=error -I${srcdir}/$subdir" run_dump_test "sse-noavx" run_dump_test "movbe" run_dump_test "movbe-intel" @@ -402,6 +406,10 @@ if [expr ([istarget "i*86-*-*"] || [ista run_dump_test "x86-64-sse-check-none" run_dump_test "x86-64-sse-check-warn" run_list_test "x86-64-sse-check-error" "-msse-check=error -I${srcdir}/$subdir -al" + run_dump_test "x86-64-vgather-check" + run_dump_test "x86-64-vgather-check-none" + run_dump_test "x86-64-vgather-check-warn" + run_list_test "x86-64-vgather-check-error" "-moperand-check=error -I${srcdir}/$subdir" run_dump_test "x86-64-sse-noavx" run_dump_test "x86-64-movbe" run_dump_test "x86-64-movbe-intel" --- 2012-08-07/gas/testsuite/gas/i386/vgather-check-error.l 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/vgather-check-error.l 2012-08-03 16:45:09.000000000 +0200 @@ -0,0 +1,4 @@ +.*: Assembler messages: +.*:6: Error: .* +.*:7: Error: .* +.*:8: Error: .* --- 2012-08-07/gas/testsuite/gas/i386/vgather-check-error.s 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/vgather-check-error.s 2012-08-03 16:24:53.000000000 +0200 @@ -0,0 +1 @@ +.include "vgather-check.s" --- 2012-08-07/gas/testsuite/gas/i386/vgather-check-none.d 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/vgather-check-none.d 2012-08-03 16:51:24.000000000 +0200 @@ -0,0 +1,14 @@ +#as: -moperand-check=error -I${srcdir}/$subdir +#objdump: -dw +#name: i386 vgather check (.operand_check none) + +.*: file format .* + +Disassembly of section .text: + +0+ : +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 04 08[ ]+vgatherdps %xmm2,\(%eax,%xmm1,1\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 14 48[ ]+vgatherdps %xmm2,\(%eax,%xmm1,2\),%xmm2 +[ ]*[a-f0-9]+:[ ]+c4 e2 71 92 04 88[ ]+vgatherdps %xmm1,\(%eax,%xmm1,4\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 0c c8[ ]+vgatherdps %xmm2,\(%eax,%xmm1,8\),%xmm1 +#pass --- 2012-08-07/gas/testsuite/gas/i386/vgather-check-none.s 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/vgather-check-none.s 2012-08-03 16:24:46.000000000 +0200 @@ -0,0 +1,2 @@ +.operand_check none +.include "vgather-check.s" --- 2012-08-07/gas/testsuite/gas/i386/vgather-check-warn.d 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/vgather-check-warn.d 2012-08-03 16:46:15.000000000 +0200 @@ -0,0 +1,15 @@ +#source: vgather-check.s +#stderr: vgather-check-warn.e +#objdump: -dw +#name: i386 vgather check (warning) + +.*: file format .* + +Disassembly of section .text: + +0+ : +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 04 08[ ]+vgatherdps %xmm2,\(%eax,%xmm1,1\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 14 48[ ]+vgatherdps %xmm2,\(%eax,%xmm1,2\),%xmm2 +[ ]*[a-f0-9]+:[ ]+c4 e2 71 92 04 88[ ]+vgatherdps %xmm1,\(%eax,%xmm1,4\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 0c c8[ ]+vgatherdps %xmm2,\(%eax,%xmm1,8\),%xmm1 +#pass --- 2012-08-07/gas/testsuite/gas/i386/vgather-check-warn.e 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/vgather-check-warn.e 2012-08-03 16:49:48.000000000 +0200 @@ -0,0 +1,4 @@ +.*: Assembler messages: +.*:6: Warning: .* +.*:7: Warning: .* +.*:8: Warning: .* --- 2012-08-07/gas/testsuite/gas/i386/vgather-check.d 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/vgather-check.d 2012-08-03 17:28:17.000000000 +0200 @@ -0,0 +1,14 @@ +#as: -moperand-check=none +#objdump: -dw +#name: i386 vgather check (-moperand-check=none) + +.*: file format .* + +Disassembly of section .text: + +0+ : +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 04 08[ ]+vgatherdps %xmm2,\(%eax,%xmm1,1\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 14 48[ ]+vgatherdps %xmm2,\(%eax,%xmm1,2\),%xmm2 +[ ]*[a-f0-9]+:[ ]+c4 e2 71 92 04 88[ ]+vgatherdps %xmm1,\(%eax,%xmm1,4\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 0c c8[ ]+vgatherdps %xmm2,\(%eax,%xmm1,8\),%xmm1 +#pass --- 2012-08-07/gas/testsuite/gas/i386/vgather-check.s 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/vgather-check.s 2012-08-03 16:36:48.000000000 +0200 @@ -0,0 +1,8 @@ +# Check vgather instructions + + .text +vgather: + vgatherdps %xmm2,(%eax,%xmm1,1),%xmm0 + vgatherdps %xmm2,(%eax,%xmm1,2),%xmm2 + vgatherdps %xmm1,(%eax,%xmm1,4),%xmm0 + vgatherdps %xmm2,(%eax,%xmm1,8),%xmm1 --- 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check-error.l 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check-error.l 2012-08-03 16:55:49.000000000 +0200 @@ -0,0 +1,4 @@ +.*: Assembler messages: +.*:6: Error: .* +.*:8: Error: .* +.*:10: Error: .* --- 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check-error.s 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check-error.s 2012-08-03 16:54:09.000000000 +0200 @@ -0,0 +1 @@ +.include "x86-64-vgather-check.s" --- 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check-none.d 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check-none.d 2012-08-03 17:27:38.000000000 +0200 @@ -0,0 +1,17 @@ +#as: -moperand-check=error -I${srcdir}/$subdir +#objdump: -dw +#name: x86-64 vgather check (.operand_check none) + +.*: file format .* + +Disassembly of section .text: + +0+ : +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 04 08[ ]+vgatherdps %xmm2,\(%rax,%xmm1,1\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 14 48[ ]+vgatherdps %xmm2,\(%rax,%xmm1,2\),%xmm2 +[ ]*[a-f0-9]+:[ ]+c4 62 69 92 14 48[ ]+vgatherdps %xmm2,\(%rax,%xmm1,2\),%xmm10 +[ ]*[a-f0-9]+:[ ]+c4 e2 71 92 04 88[ ]+vgatherdps %xmm1,\(%rax,%xmm1,4\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 31 92 04 88[ ]+vgatherdps %xmm9,\(%rax,%xmm1,4\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 0c c8[ ]+vgatherdps %xmm2,\(%rax,%xmm1,8\),%xmm1 +[ ]*[a-f0-9]+:[ ]+c4 62 69 92 0c c8[ ]+vgatherdps %xmm2,\(%rax,%xmm1,8\),%xmm9 +#pass --- 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check-none.s 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check-none.s 2012-08-03 16:54:26.000000000 +0200 @@ -0,0 +1,2 @@ +.operand_check none +.include "x86-64-vgather-check.s" --- 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check-warn.d 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check-warn.d 2012-08-03 17:27:42.000000000 +0200 @@ -0,0 +1,18 @@ +#source: x86-64-vgather-check.s +#stderr: x86-64-vgather-check-warn.e +#objdump: -dw +#name: x86-64 vgather check (warning) + +.*: file format .* + +Disassembly of section .text: + +0+ : +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 04 08[ ]+vgatherdps %xmm2,\(%rax,%xmm1,1\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 14 48[ ]+vgatherdps %xmm2,\(%rax,%xmm1,2\),%xmm2 +[ ]*[a-f0-9]+:[ ]+c4 62 69 92 14 48[ ]+vgatherdps %xmm2,\(%rax,%xmm1,2\),%xmm10 +[ ]*[a-f0-9]+:[ ]+c4 e2 71 92 04 88[ ]+vgatherdps %xmm1,\(%rax,%xmm1,4\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 31 92 04 88[ ]+vgatherdps %xmm9,\(%rax,%xmm1,4\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 0c c8[ ]+vgatherdps %xmm2,\(%rax,%xmm1,8\),%xmm1 +[ ]*[a-f0-9]+:[ ]+c4 62 69 92 0c c8[ ]+vgatherdps %xmm2,\(%rax,%xmm1,8\),%xmm9 +#pass --- 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check-warn.e 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check-warn.e 2012-08-03 16:56:00.000000000 +0200 @@ -0,0 +1,4 @@ +.*: Assembler messages: +.*:6: Warning: .* +.*:8: Warning: .* +.*:10: Warning: .* --- 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check.d 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check.d 2012-08-03 17:28:12.000000000 +0200 @@ -0,0 +1,17 @@ +#as: -moperand-check=none +#objdump: -dw +#name: x86-64 vgather check (-moperand-check=none) + +.*: file format .* + +Disassembly of section .text: + +0+ : +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 04 08[ ]+vgatherdps %xmm2,\(%rax,%xmm1,1\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 14 48[ ]+vgatherdps %xmm2,\(%rax,%xmm1,2\),%xmm2 +[ ]*[a-f0-9]+:[ ]+c4 62 69 92 14 48[ ]+vgatherdps %xmm2,\(%rax,%xmm1,2\),%xmm10 +[ ]*[a-f0-9]+:[ ]+c4 e2 71 92 04 88[ ]+vgatherdps %xmm1,\(%rax,%xmm1,4\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 31 92 04 88[ ]+vgatherdps %xmm9,\(%rax,%xmm1,4\),%xmm0 +[ ]*[a-f0-9]+:[ ]+c4 e2 69 92 0c c8[ ]+vgatherdps %xmm2,\(%rax,%xmm1,8\),%xmm1 +[ ]*[a-f0-9]+:[ ]+c4 62 69 92 0c c8[ ]+vgatherdps %xmm2,\(%rax,%xmm1,8\),%xmm9 +#pass --- 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check.s 1970-01-01 01:00:00.000000000 +0100 +++ 2012-08-07/gas/testsuite/gas/i386/x86-64-vgather-check.s 2012-08-03 16:56:53.000000000 +0200 @@ -0,0 +1,11 @@ +# Check vgather instructions + + .text +vgather: + vgatherdps %xmm2,(%rax,%xmm1,1),%xmm0 + vgatherdps %xmm2,(%rax,%xmm1,2),%xmm2 + vgatherdps %xmm2,(%rax,%xmm1,2),%xmm10 + vgatherdps %xmm1,(%rax,%xmm1,4),%xmm0 + vgatherdps %xmm9,(%rax,%xmm1,4),%xmm0 + vgatherdps %xmm2,(%rax,%xmm1,8),%xmm1 + vgatherdps %xmm2,(%rax,%xmm1,8),%xmm9