This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [PATCH 3/4] x86: fold RegXMM/RegYMM/RegZMM into RegSIMD
On Fri, Dec 15, 2017 at 2:34 AM, Jan Beulich <JBeulich@suse.com> wrote:
> ... qualified by their respective sizes, allowing to drop FirstXmm0 at
> the same time.
>
> gas/
> 2017-12-15 Jan Beulich <jbeulich@suse.com>
>
> * config/tc-i386.c (match_simd_size): New.
> (match_mem_size): Use it.
> (operand_size_match): Likewise. Split .reg and .acc checks.
> (pi, check_VecOperands, match_template, check_byte_reg,
> check_long_reg, check_qword_reg, build_modrm_byte,
> parse_real_register): Replace .regxmm, .regymm, and .regzmm
> checks.
> (md_assemble): Qualify .acc check with .xmmword one.
> (bad_implicit_operand): Delete.
> (process_operands): Replace .firstxmm0 checks with .acc plus
> .xmmword ones. Drop now pointless assertions. Convert .acc to
> .regsimd.
> * config/tc-i386-intel.c (i386_intel_simplify_register): Replace
> .regxmm, .regymm, and .regzmm checks.
> * testsuite/gas/i386/x86-64-specific-reg.l: Adjust expectations.
>
> opcodes/
> 2017-12-15 Jan Beulich <jbeulich@suse.com>
>
> * i386-gen.c (operand_type_shorthands): Add RegXMM, RegYMM, and
> RegZMM.
> (opcode_modifiers): Drop FirstXmm0.
> (operand_types): Replace RegXMM, RegYMM, and RegZMM with just
> RegSIMD.
> * i386-opc.h (enum of opcode modifiers): Drop FirstXmm0.
> (struct i386_opcode_modifier): Drop firstxmm0.
> (enum of operand types): Replace RegXMM, RegYMM, and RegZMM with
> just RegSIMD. Extend comment.
> (union i386_operand_type): Replace regxmm, regymm, and regzmm
> with just regsimd.
> * i386-opc.tbl (blendvpd, blendvps, pblendvb, sha256rnds2): Use
> Acc|Xmmword.
> * i386-reg.tbl (xmm0): Add Acc.
> * i386-init.h, i386-tbl.h: Re-generate.
>
> --- a/gas/config/tc-i386-intel.c
> +++ b/gas/config/tc-i386-intel.c
> @@ -286,9 +286,9 @@ i386_intel_simplify_register (expression
> i.op[this_operand].regs = i386_regtab + reg_num;
> }
> else if (!intel_state.index
> - && (i386_regtab[reg_num].reg_type.bitfield.regxmm
> - || i386_regtab[reg_num].reg_type.bitfield.regymm
> - || i386_regtab[reg_num].reg_type.bitfield.regzmm
> + && (i386_regtab[reg_num].reg_type.bitfield.xmmword
> + || i386_regtab[reg_num].reg_type.bitfield.ymmword
> + || i386_regtab[reg_num].reg_type.bitfield.zmmword
> || i386_regtab[reg_num].reg_num == RegRiz
> || i386_regtab[reg_num].reg_num == RegEiz))
> intel_state.index = i386_regtab + reg_num;
> --- a/gas/config/tc-i386.c
> +++ b/gas/config/tc-i386.c
> @@ -1825,6 +1825,20 @@ match_reg_size (const insn_template *t,
> && !t->operand_types[j].bitfield.tbyte));
> }
>
> +/* Return 1 if there is no conflict in SIMD register on
> + operand J for instruction template T. */
> +
> +static INLINE int
> +match_simd_size (const insn_template *t, unsigned int j)
> +{
> + return !((i.types[j].bitfield.xmmword
> + && !t->operand_types[j].bitfield.xmmword)
> + || (i.types[j].bitfield.ymmword
> + && !t->operand_types[j].bitfield.ymmword)
> + || (i.types[j].bitfield.zmmword
> + && !t->operand_types[j].bitfield.zmmword));
> +}
> +
> /* Return 1 if there is no conflict in any size on operand J for
> instruction template T. */
>
> @@ -1837,12 +1851,17 @@ match_mem_size (const insn_template *t,
> && !t->operand_types[j].bitfield.unspecified)
> || (i.types[j].bitfield.fword
> && !t->operand_types[j].bitfield.fword)
> - || (i.types[j].bitfield.xmmword
> - && !t->operand_types[j].bitfield.xmmword)
> - || (i.types[j].bitfield.ymmword
> - && !t->operand_types[j].bitfield.ymmword)
> - || (i.types[j].bitfield.zmmword
> - && !t->operand_types[j].bitfield.zmmword)));
> + /* For scalar opcode templates to allow register and memory
> + operands at the same time, some special casing is needed
> + here. */
> + || ((t->operand_types[j].bitfield.regsimd
> + && !t->opcode_modifier.broadcast
> + && (t->operand_types[j].bitfield.dword
> + || t->operand_types[j].bitfield.qword))
> + ? (i.types[j].bitfield.xmmword
> + || i.types[j].bitfield.ymmword
> + || i.types[j].bitfield.zmmword)
> + : !match_simd_size(t, j))));
> }
>
> /* Return 1 if there is no size conflict on any operands for
> @@ -1864,17 +1883,31 @@ operand_size_match (const insn_template
> /* Check memory and accumulator operand size. */
> for (j = 0; j < i.operands; j++)
> {
> - if (!i.types[j].bitfield.reg && t->operand_types[j].bitfield.anysize)
> + if (!i.types[j].bitfield.reg && !i.types[j].bitfield.regsimd
> + && t->operand_types[j].bitfield.anysize)
> continue;
>
> - if ((t->operand_types[j].bitfield.reg
> - || t->operand_types[j].bitfield.acc)
> + if (t->operand_types[j].bitfield.reg
> && !match_reg_size (t, j))
> {
> match = 0;
> break;
> }
>
> + if (t->operand_types[j].bitfield.regsimd
> + && !match_simd_size (t, j))
> + {
> + match = 0;
> + break;
> + }
> +
> + if (t->operand_types[j].bitfield.acc
> + && (!match_reg_size (t, j) || !match_simd_size (t, j)))
> + {
> + match = 0;
> + break;
> + }
> +
> if (i.types[j].bitfield.mem && !match_mem_size (t, j))
> {
> match = 0;
> @@ -2804,9 +2837,7 @@ pi (char *line, i386_insn *x)
> fprintf (stdout, "\n");
> if (x->types[j].bitfield.reg
> || x->types[j].bitfield.regmmx
> - || x->types[j].bitfield.regxmm
> - || x->types[j].bitfield.regymm
> - || x->types[j].bitfield.regzmm
> + || x->types[j].bitfield.regsimd
> || x->types[j].bitfield.sreg2
> || x->types[j].bitfield.sreg3
> || x->types[j].bitfield.control
> @@ -3768,7 +3799,7 @@ md_assemble (char *line)
> for (j = 0; j < i.operands; j++)
> if (i.types[j].bitfield.inoutportreg
> || i.types[j].bitfield.shiftcount
> - || i.types[j].bitfield.acc)
> + || (i.types[j].bitfield.acc && !i.types[j].bitfield.xmmword))
> i.reg_operands--;
>
> /* ImmExt should be processed after SSE2AVX. */
> @@ -4576,9 +4607,9 @@ check_VecOperands (const insn_template *
> /* Without VSIB byte, we can't have a vector register for index. */
> if (!t->opcode_modifier.vecsib
> && i.index_reg
> - && (i.index_reg->reg_type.bitfield.regxmm
> - || i.index_reg->reg_type.bitfield.regymm
> - || i.index_reg->reg_type.bitfield.regzmm))
> + && (i.index_reg->reg_type.bitfield.xmmword
> + || i.index_reg->reg_type.bitfield.ymmword
> + || i.index_reg->reg_type.bitfield.zmmword))
> {
> i.error = unsupported_vector_index_register;
> return 1;
> @@ -4598,11 +4629,11 @@ check_VecOperands (const insn_template *
> {
> if (!i.index_reg
> || !((t->opcode_modifier.vecsib == VecSIB128
> - && i.index_reg->reg_type.bitfield.regxmm)
> + && i.index_reg->reg_type.bitfield.xmmword)
> || (t->opcode_modifier.vecsib == VecSIB256
> - && i.index_reg->reg_type.bitfield.regymm)
> + && i.index_reg->reg_type.bitfield.ymmword)
> || (t->opcode_modifier.vecsib == VecSIB512
> - && i.index_reg->reg_type.bitfield.regzmm)))
> + && i.index_reg->reg_type.bitfield.zmmword)))
> {
> i.error = invalid_vsib_address;
> return 1;
> @@ -4611,10 +4642,12 @@ check_VecOperands (const insn_template *
> gas_assert (i.reg_operands == 2 || i.mask);
> if (i.reg_operands == 2 && !i.mask)
> {
> - gas_assert (i.types[0].bitfield.regxmm
> - || i.types[0].bitfield.regymm);
> - gas_assert (i.types[2].bitfield.regxmm
> - || i.types[2].bitfield.regymm);
> + gas_assert (i.types[0].bitfield.regsimd);
> + gas_assert (i.types[0].bitfield.xmmword
> + || i.types[0].bitfield.ymmword);
> + gas_assert (i.types[2].bitfield.regsimd);
> + gas_assert (i.types[2].bitfield.xmmword
> + || i.types[2].bitfield.ymmword);
> if (operand_check == check_none)
> return 0;
> if (register_number (i.op[0].regs)
> @@ -4633,9 +4666,10 @@ check_VecOperands (const insn_template *
> }
> else if (i.reg_operands == 1 && i.mask)
> {
> - if ((i.types[1].bitfield.regxmm
> - || i.types[1].bitfield.regymm
> - || i.types[1].bitfield.regzmm)
> + if (i.types[1].bitfield.regsimd
> + && (i.types[1].bitfield.xmmword
> + || i.types[1].bitfield.ymmword
> + || i.types[1].bitfield.zmmword)
> && (register_number (i.op[1].regs)
> == register_number (i.index_reg)))
> {
> @@ -4941,13 +4975,9 @@ match_template (char mnem_suffix)
> && !intel_float_operand (t->name))
> : intel_float_operand (t->name) != 2)
> && ((!operand_types[0].bitfield.regmmx
> - && !operand_types[0].bitfield.regxmm
> - && !operand_types[0].bitfield.regymm
> - && !operand_types[0].bitfield.regzmm)
> + && !operand_types[0].bitfield.regsimd)
> || (!operand_types[t->operands > 1].bitfield.regmmx
> - && !operand_types[t->operands > 1].bitfield.regxmm
> - && !operand_types[t->operands > 1].bitfield.regymm
> - && !operand_types[t->operands > 1].bitfield.regzmm))
> + && !operand_types[t->operands > 1].bitfield.regsimd))
> && (t->base_opcode != 0x0fc7
> || t->extension_opcode != 1 /* cmpxchg8b */))
> continue;
> @@ -4960,9 +4990,9 @@ match_template (char mnem_suffix)
> && !intel_float_operand (t->name))
> : intel_float_operand (t->name) != 2)
> && ((!operand_types[0].bitfield.regmmx
> - && !operand_types[0].bitfield.regxmm)
> + && !operand_types[0].bitfield.regsimd)
> || (!operand_types[t->operands > 1].bitfield.regmmx
> - && !operand_types[t->operands > 1].bitfield.regxmm)))
> + && !operand_types[t->operands > 1].bitfield.regsimd)))
> continue;
>
> /* Do not verify operands when there are none. */
> @@ -5653,9 +5683,7 @@ check_byte_reg (void)
> /* Any other register is bad. */
> if (i.types[op].bitfield.reg
> || i.types[op].bitfield.regmmx
> - || i.types[op].bitfield.regxmm
> - || i.types[op].bitfield.regymm
> - || i.types[op].bitfield.regzmm
> + || i.types[op].bitfield.regsimd
> || i.types[op].bitfield.sreg2
> || i.types[op].bitfield.sreg3
> || i.types[op].bitfield.control
> @@ -5728,7 +5756,7 @@ check_long_reg (void)
> {
> if (intel_syntax
> && i.tm.opcode_modifier.toqword
> - && !i.types[0].bitfield.regxmm)
> + && !i.types[0].bitfield.regsimd)
> {
> /* Convert to QWORD. We want REX byte. */
> i.suffix = QWORD_MNEM_SUFFIX;
> @@ -5779,7 +5807,7 @@ check_qword_reg (void)
> lowering is more complicated. */
> if (intel_syntax
> && i.tm.opcode_modifier.todword
> - && !i.types[0].bitfield.regxmm)
> + && !i.types[0].bitfield.regsimd)
> {
> /* Convert to DWORD. We don't want REX byte. */
> i.suffix = LONG_MNEM_SUFFIX;
> @@ -5930,20 +5958,6 @@ finalize_imm (void)
> }
>
> static int
> -bad_implicit_operand (int xmm)
> -{
> - const char *ireg = xmm ? "xmm0" : "ymm0";
> -
> - if (intel_syntax)
> - as_bad (_("the last operand of `%s' must be `%s%s'"),
> - i.tm.name, register_prefix, ireg);
> - else
> - as_bad (_("the first operand of `%s' must be `%s%s'"),
> - i.tm.name, register_prefix, ireg);
> - return 0;
> -}
> -
Will we miss the assembly operand error checking?
--
H.J.