[PATCH 4/8] Support APX NDD
Cui, Lili
lili.cui@intel.com
Tue Oct 24 11:39:57 GMT 2023
> Subject: Re: [PATCH 4/8] Support APX NDD
>
> 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.
>
As I commented in another email, I want to move instructions like adcx into this NDD patch. Do you think it is ok?
> > --- 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), ...
Done.
>
> > + /* 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.
>
Done.
> > @@ -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?
Oh, I've duplicated some of the checks in the above code and removed the duplicated parts.
if (ins->evex_type == evex_from_legacy)
{
/* EVEX from legacy instructions, when the EVEX.ND bit is 0,
all bits of EVEX.vvvv and EVEX.V' must be 1. */
if (!ins->vex.b && (ins->vex.register_specifier
|| !ins->vex.v))
return &bad_opcode;
ins->rex |= REX_OPCODE;
}
/* EVEX from legacy instructions require that EVEX.L’L, EVEX.z and the
lower 2 bits of EVEX.aaa must be 0.
EVEX from evex instrucions require that EVEX.L’L and the lower 2 bits of
EVEX.aaa must be 0. */
if (ins->evex_type == evex_from_legacy || ins->evex_type == evex_from_vex)
{
if ((*ins->codep & 0x3) != 0
|| (*ins->codep >> 6 & 0x3) != 0
|| (ins->evex_type == evex_from_legacy
&& (*ins->codep >> 5 & 0x1) != 0)
|| (ins->evex_type == evex_from_vex
&& !ins->vex.b))
return &bad_opcode;
}
>
> > + ins->rex |= REX_OPCODE;
>
> This, otoh, may truly be evex_from_legacy-only (but I'm not entirely certain).
>
Added after separation.
> > @@ -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.
>
Not found in this function, but found a place that needs to be qualified in print_insn.
/* Check whether rounding control was enabled for an insn not
supporting it. */
if (ins.modrm.mod == 3 && ins.vex.b
&& !(ins.evex_used & EVEX_b_used))
{
for (i = 0; i < MAX_OPERANDS; ++i)
{
ins.obufp = ins.op_out[i];
if (*ins.obufp)
continue;
oappend (&ins, names_rounding[ins.vex.ll]);
oappend (&ins, "bad}");
break;
}
}
> > @@ -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, ...
>
Done.
> > @@ -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.
>
Sure, moved it.
> > @@ -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.
>
Added comment and adjusted the formatting, I think we need if/else like "adox " which supports EVEX.ND=0/1.
/* PREFIX_0F38F6 */
{
{ "wrssK", { M, Gdq }, 0 },
{ "adoxS", { VexGdq, Gdq, Edq}, 0 },
adox, 0xf366, ADX|APX_F, Modrm|CheckOperandSize|IgnoreSize|No_bSuf|No_wSuf|No_sSuf|EVex128|EVexMap4, { Reg32|Reg64|Unspecified|BaseIndex, Reg32|Reg64 }
adox, 0xf366, ADX|APX_F, Modrm|CheckOperandSize|IgnoreSize|No_bSuf|No_wSuf|No_sSuf|VexVVVVDest|EVex128|EVexMap4, { Reg32|Reg64|Unspecified|BaseIndex, Reg32|Reg64, Reg32|Reg64 }
Thanks,
Lili.
More information about the Binutils
mailing list