[PATCH 4/8] Support APX NDD

Jan Beulich jbeulich@suse.com
Thu Sep 28 07:57:43 GMT 2023
On 19.09.2023 17:25, Cui, Lili wrote:
> --- a/opcodes/i386-dis-evex-prefix.h
> +++ b/opcodes/i386-dis-evex-prefix.h
> @@ -353,8 +353,8 @@
>    /* PREFIX_EVEX_MAP4_66 */
>    {
>      { MOD_TABLE (MOD_EVEX_MAP4_66_PREFIX_0) },
> -    { "adoxS",	{ Gdq, Edq }, 0 },
> -    { "adcxS",	{ Gdq, Edq }, 0 },
> +    { "adoxS",	{ VexGdq, Gdq, Edq }, 0 },
> +    { "adcxS",	{ VexGdq, Gdq, Edq }, 0 },

With the OP_VEX() change moved to the earlier patch, you wouldn't need to
alter again right away what was just added there.

> --- a/opcodes/i386-dis-evex-reg.h
> +++ b/opcodes/i386-dis-evex-reg.h
> @@ -56,6 +56,105 @@
>      { "blsmskS",	{ VexGdq, Edq }, 0 },
>      { "blsiS",		{ VexGdq, Edq }, 0 },
>    },
> +  /* REG_EVEX_MAP4_80 */
> +  {
> +    { "addA",	{ VexGb, Eb, Ib }, 0 },
> +    { "orA",	{ VexGb, Eb, Ib }, 0 },
> +    { "adcA",	{ VexGb, Eb, Ib }, 0 },
> +    { "sbbA",	{ VexGb, Eb, Ib }, 0 },

Aren't these two and other adc/sbb entries required already in the earlier
patch, for consistency with what you add there on the assembler side?

> +    { "andA",	{ VexGb, Eb, Ib }, 0 },
> +    { "subA",	{ VexGb, Eb, Ib }, 0 },
> +    { "xorA",	{ VexGb, Eb, Ib }, 0 },
> +    { Bad_Opcode },
> +  },
> +  /* REG_EVEX_MAP4_81 */
> +  {
> +    { "addQ",	{ VexGv, Ev, Iv }, 0 },
> +    { "orQ",	{ VexGv, Ev, Iv }, 0 },
> +    { "adcQ",	{ VexGv, Ev, Iv }, 0 },
> +    { "sbbQ",	{ VexGv, Ev, Iv }, 0 },
> +    { "andQ",	{ VexGv, Ev, Iv }, 0 },
> +    { "subQ",	{ VexGv, Ev, Iv }, 0 },
> +    { "xorQ",	{ VexGv, Ev, Iv }, 0 },
> +    { Bad_Opcode },
> +  },
> +  /* REG_EVEX_MAP4_83 */
> +  {
> +    { "addQ",	{ VexGv, Ev, sIb }, 0 },
> +    { "orQ",	{ VexGv, Ev, sIb }, 0 },
> +    { "adcQ",	{ VexGv, Ev, sIb }, 0 },
> +    { "sbbQ",	{ VexGv, Ev, sIb }, 0 },
> +    { "andQ",	{ VexGv, Ev, sIb }, 0 },
> +    { "subQ",	{ VexGv, Ev, sIb }, 0 },
> +    { "xorQ",	{ VexGv, Ev, sIb }, 0 },
> +    { Bad_Opcode },
> +  },

While these are needed because of the differences (from existing table
entries we have) in the last entry (albeit I don't think those last
entries need to actually be spelled out; you don't spell out trailing
invalid entries further down, and we don't do so elsewhere either), ...

> +  /* REG_EVEX_MAP4_C0 */
> +  {
> +    { "rolA",	{ VexGb, Eb, Ib }, 0 },
> +    { "rorA",	{ VexGb, Eb, Ib }, 0 },
> +    { "rclA",	{ VexGb, Eb, Ib }, 0 },
> +    { "rcrA",	{ VexGb, Eb, Ib }, 0 },
> +    { "shlA",	{ VexGb, Eb, Ib }, 0 },
> +    { "shrA",	{ VexGb, Eb, Ib }, 0 },
> +    { "shlA",	{ VexGb, Eb, Ib }, 0 },
> +    { "sarA",	{ VexGb, Eb, Ib }, 0 },
> +  },
> +  /* REG_EVEX_MAP4_C1 */
> +  {
> +    { "rolQ",	{ VexGv, Ev, Ib }, 0 },
> +    { "rorQ",	{ VexGv, Ev, Ib }, 0 },
> +    { "rclQ",	{ VexGv, Ev, Ib }, 0 },
> +    { "rcrQ",	{ VexGv, Ev, Ib }, 0 },
> +    { "shlQ",	{ VexGv, Ev, Ib }, 0 },
> +    { "shrQ",	{ VexGv, Ev, Ib }, 0 },
> +    { "shlQ",	{ VexGv, Ev, Ib }, 0 },
> +    { "sarQ",	{ VexGv, Ev, Ib }, 0 },
> +  },
> +  /* REG_EVEX_MAP4_D0 */
> +  {
> +    { "rolA",	{ VexGb, Eb, I1 }, 0 },
> +    { "rorA",	{ VexGb, Eb, I1 }, 0 },
> +    { "rclA",	{ VexGb, Eb, I1 }, 0 },
> +    { "rcrA",	{ VexGb, Eb, I1 }, 0 },
> +    { "shlA",	{ VexGb, Eb, I1 }, 0 },
> +    { "shrA",	{ VexGb, Eb, I1 }, 0 },
> +    { "shlA",	{ VexGb, Eb, I1 }, 0 },
> +    { "sarA",	{ VexGb, Eb, I1 }, 0 },
> +  },
> +  /* REG_EVEX_MAP4_D1 */
> +  {
> +    { "rolQ",	{ VexGv, Ev, I1 }, 0 },
> +    { "rorQ",	{ VexGv, Ev, I1 }, 0 },
> +    { "rclQ",	{ VexGv, Ev, I1 }, 0 },
> +    { "rcrQ",	{ VexGv, Ev, I1 }, 0 },
> +    { "shlQ",	{ VexGv, Ev, I1 }, 0 },
> +    { "shrQ",	{ VexGv, Ev, I1 }, 0 },
> +    { "shlQ",	{ VexGv, Ev, I1 }, 0 },
> +    { "sarQ",	{ VexGv, Ev, I1 }, 0 },
> +  },
> +  /* REG_EVEX_MAP4_D2 */
> +  {
> +    { "rolA",	{ VexGb, Eb, CL }, 0 },
> +    { "rorA",	{ VexGb, Eb, CL }, 0 },
> +    { "rclA",	{ VexGb, Eb, CL }, 0 },
> +    { "rcrA",	{ VexGb, Eb, CL }, 0 },
> +    { "shlA",	{ VexGb, Eb, CL }, 0 },
> +    { "shrA",	{ VexGb, Eb, CL }, 0 },
> +    { "shlA",	{ VexGb, Eb, CL }, 0 },
> +    { "sarA",	{ VexGb, Eb, CL }, 0 },
> +  },
> +  /* REG_EVEX_MAP4_D3 */
> +  {
> +    { "rolQ",	{ VexGv, Ev, CL }, 0 },
> +    { "rorQ",	{ VexGv, Ev, CL }, 0 },
> +    { "rclQ",	{ VexGv, Ev, CL }, 0 },
> +    { "rcrQ",	{ VexGv, Ev, CL }, 0 },
> +    { "shlQ",	{ VexGv, Ev, CL }, 0 },
> +    { "shrQ",	{ VexGv, Ev, CL }, 0 },
> +    { "shlQ",	{ VexGv, Ev, CL }, 0 },
> +    { "sarQ",	{ VexGv, Ev, CL }, 0 },
> +  },

... do we really need all these new entries? OP_VEX() checks need_vex first
thing, so simply adjusting and then re-using the existing entries would seem
possible.

> @@ -9070,6 +9085,14 @@ get_valid_dis386 (const struct dis386 *dp, instr_info *ins)
>  	  ins->rex &= ~REX_B;
>  	  ins->rex2 &= ~REX_R;
>  	}
> +      if (ins->evex_type == evex_from_legacy)
> +	{
> +	  if (ins->vex.ll || ins->vex.zeroing
> +	      || (!ins->vex.b && (ins->vex.register_specifier
> +				  || !ins->vex.v)))
> +	    return &bad_opcode;

Don't these checks also apply to evex_from_vex?

> +	  ins->rex |= REX_OPCODE;

This, otoh, may truly be evex_from_legacy-only (but I'm not entirely
certain).

> @@ -9080,7 +9103,7 @@ get_valid_dis386 (const struct dis386 *dp, instr_info *ins)
>  	return &err_opcode;
>  
>        /* Set vector length.  */
> -      if (ins->modrm.mod == 3 && ins->vex.b)
> +      if (ins->modrm.mod == 3 && ins->vex.b && ins->evex_type == evex_default)
>  	ins->vex.length = 512;

Down from here, still in the same function, there's another vex.b
check which I think also wants qualifying.

> @@ -10994,7 +11017,7 @@ print_displacement (instr_info *ins, bfd_signed_vma val)
>  static void
>  intel_operand_size (instr_info *ins, int bytemode, int sizeflag)
>  {
> -  if (ins->vex.b)
> +  if (ins->vex.b && ins->evex_type != evex_from_legacy)

Wouldn't this better be ins->evex_type == evex_default, ...

> @@ -11928,7 +11951,8 @@ OP_E_memory (instr_info *ins, int bytemode, int sizeflag)
>  	ins->vex.no_broadcast = true;
>  
>        if (!ins->vex.no_broadcast
> -	  && (!ins->intel_syntax || !(ins->evex_used & EVEX_len_used)))
> +	  && (!ins->intel_syntax || !(ins->evex_used & EVEX_len_used))
> +	  && ins->evex_type == evex_default)

... just like you have it here?

However, for this change, doesn't this need moving to the enclosing if()?
You should accidentally set EVEX_b_used here for APX insns.

> @@ -13280,6 +13304,14 @@ OP_VEX (instr_info *ins, int bytemode, int sizeflag ATTRIBUTE_UNUSED)
>    if (!ins->need_vex)
>      return true;
>  
> +  if (ins->evex_type == evex_from_legacy)
> +    {
> +      if (ins->vex.b)
> +	ins->evex_used |= EVEX_b_used;
> +      else
> +	 return true;
> +    }

When you reuse fields or definitions in places where their names don't
match their purpose (the field dealt with here is "nd" after all, not
"b"), a comment wants adding. There's also something odd with
indentation here, but I suppose an if/else construct isn't needed in
the first place.

Jan


More information about the Binutils mailing list