[PATCH v3 7/9] Support APX Push2/Pop2
Cui, Lili
lili.cui@intel.com
Fri Dec 15 08:38:26 GMT 2023
> On 24.11.2023 08:02, Cui, Lili wrote:
> > --- a/gas/config/tc-i386.c
> > +++ b/gas/config/tc-i386.c
> > @@ -248,6 +248,7 @@ enum i386_error
> > invalid_vector_register_set,
> > invalid_tmm_register_set,
> > invalid_dest_and_src_register_set,
> > + invalid_src_register_set,
> > invalid_pseudo_prefix,
> > unsupported_vector_index_register,
> > unsupported_broadcast,
> > @@ -256,6 +257,7 @@ enum i386_error
> > mask_not_on_destination,
> > no_default_mask,
> > unsupported_rc_sae,
> > + unsupported_rsp_register,
> > invalid_register_operand,
> > internal_error,
> > };
> > @@ -5398,6 +5400,9 @@ md_assemble (char *line)
> > case invalid_dest_and_src_register_set:
> > err_msg = _("destination and source registers must be distinct");
> > break;
> > + case invalid_src_register_set:
>
> Did you mean invalid_dest_register_set and ...
>
> > + err_msg = _("two source registers must be distinct");
>
> ... "two destination ..."? This is for POP2, after all, which has no source register
> at all.
>
Done.
> > @@ -5422,6 +5427,9 @@ md_assemble (char *line)
> > case unsupported_rc_sae:
> > err_msg = _("unsupported static rounding/sae");
> > break;
> > + case unsupported_rsp_register:
> > + err_msg = _("cannot be used with %rsp register");
> > + break;
>
> While this wording looks okay as visible here, please consider it in the context
> it is used in: "cannot be used with %rsp register for `push2'"
> is, I'm sorry to say that, clumsy at best. If you want to stick to setting err_msg,
> how about "%rsp register cannot be used"? Personally I'd prefer a resulting
> output of "%rsp register cannot be used with `push2'", but I wouldn't insist on
> you going that route if you don't like that.
>
"%rsp register cannot be used" ,this is much better, thanks.
> > @@ -7113,6 +7121,33 @@ check_EgprOperands (const insn_template *t)
> > return 0;
> > }
> >
> > +/* Check if APX operands are valid for the instruction. */ static
> > +int
>
> Please can functions returning boolean indicators have a return type of "bool"
> (and perhaps use "true" as the success indicator, not "false")?
>
Done.
> > +check_APX_operands (const insn_template *t) {
> > + /* Push2* and Pop2* cannot use RSP and Pop2* cannot pop two same
> registers.
> > + */
> > + if (t->mnem_off == MN_push2 || t->mnem_off == MN_push2p
> > + || t->mnem_off == MN_pop2 || t->mnem_off == MN_pop2p)
>
> Considering (perhaps just theoretical) further additions here, did you consider
> using switch()? Even without further additions this would imo be more legible
> (due to there being slightly less redundancy).
>
Done.
/* Push2* and Pop2* cannot use RSP and Pop2* cannot pop two same registers.
*/
switch (t->mnem_off)
{
case MN_pop2:
case MN_pop2p:
if (register_number (i.op[0].regs) == register_number (i.op[1].regs))
{
i.error = invalid_dest_register_set;
return 1;
}
case MN_push2:
case MN_push2p:
if (register_number (i.op[0].regs) == 4
|| register_number (i.op[1].regs) == 4)
{
i.error = unsupported_rsp_register;
return 1;
}
}
> > --- a/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.s
> > +++ b/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.s
> > @@ -28,3 +28,9 @@ _start:
> > .byte 0xff
> > #{evex} inc %rax %rbx EVEX.vvvv' != 1111 && EVEX.ND = 0.
> > .insn EVEX.L0.NP.M4.W1 0xff, %rax, %rbx
> > + .byte 0xff
> > + # pop2 %rax, %rbx set EVEX.ND=0.
> > + .byte 0x62,0xf4,0x64,0x08,0x8f,0xc0
> > + .byte 0xff, 0xff, 0xff
> > + # pop2 %rax set EVEX.vvvv' = 1111.
>
> Another instance of the unclear EVEX.vvvv' (i.e. the questionable nature if '
> here). Yet then - what is the test below checking? EVEX.vvvv encodes one of
> the two operands, so all values are valid? Isn't this about both operands being
> the same? That would better be said then explicitly, e.g.
> simply
>
> # pop2 %rax, %rax (twice same destination)
>
> > + .byte 0x62,0xf4,0x7c,0x18,0x8f,0xc0
>
> Also again both new tests use .byte instead of .insn: Is there a particular
> reason? Here are a couple of examples that I have readily available (Intel
> syntax again, ftaod):
>
> .insn EVEX.L0.M4.W0 0x8f/0, r8, rax{sae} ; pop2 r8, rax
> .insn EVEX.L0.M4.W0 0x8f/0, xmm16, rax{sae} ; pop2 r16, rax
> .insn EVEX.L0.M4.W0 0x8f/0, rax, r8{sae} ; pop2 rax, r8
> .insn EVEX.L0.M12.W0 0x8f/0, rax, rax{sae} ; pop2 rax, r16
> .insn EVEX.L0.M4.W1 0x8f/0, rax, rcx{sae} ; pop2.x rax, rcx
>
> I'm sure you can derive from them what you're actually after.
>
Thanks!
# pop2 %rax, %r8 set EVEX.ND=0.
.insn EVEX.L0.M4.W0 0x8f/0, %rax, %r8
.byte 0xff, 0xff, 0xff
# pop2 %rax, %r8 set EVEX.vvvv = 1111.
.insn EVEX.L0.M4.W0 0x8f, %rax, {rn-sae},%r8
# pop2 %r8, %r8.
.insn EVEX.L0.M4.W0 0x8f/0, %r8,{rn-sae}, %r8
> > --- /dev/null
> > +++ b/gas/testsuite/gas/i386/x86-64-apx-push2pop2.s
> > @@ -0,0 +1,39 @@
> > +# Check 64bit APX-Push2Pop2 instructions
> > +
> > + .allow_index_reg
> > + .text
> > +_start:
> > + push2 %rbx, %rax
> > + push2 %r17, %r8
> > + push2 %r9, %r31
> > + push2 %r31, %r24
> > + push2p %rbx, %rax
> > + push2p %r17, %r8
> > + push2p %r9, %r31
> > + push2p %r31, %r24
> > + pop2 %rax, %rbx
> > + pop2 %r8, %r17
> > + pop2 %r31, %r9
> > + pop2 %r24, %r31
> > + pop2p %rax, %rbx
> > + pop2p %r8, %r17
> > + pop2p %r31, %r9
> > + pop2p %r24, %r31
> > +
> > +.intel_syntax noprefix
>
> Nit: Un-indented directive again.
Done.
>
> > --- a/opcodes/i386-dis.c
> > +++ b/opcodes/i386-dis.c
> > @@ -105,6 +105,7 @@ static bool FXSAVE_Fixup (instr_info *, int, int);
> > static bool MOVSXD_Fixup (instr_info *, int, int); static bool
> > DistinctDest_Fixup (instr_info *, int, int); static bool
> > PREFETCHI_Fixup (instr_info *, int, int);
> > +static bool PUSH2_POP2_Fixup (instr_info *, int, int);
> >
> > static void ATTRIBUTE_PRINTF_3 i386_dis_printf (const disassemble_info *,
> > enum disassembler_style,
> > @@ -225,6 +226,9 @@ struct instr_info
> > }
> > vex;
> >
> > +/* For APX EVEX-promoted prefix, EVEX.ND shares the same bit as
> > +vex.b. */ #define nd b
>
> Can this be moved ahead to patch 4, such that it can be used there (instead of
> vex.b) as well? IOW ...
>
> > @@ -9125,7 +9133,7 @@ get_valid_dis386 (const struct dis386 *dp,
> > instr_info *ins)
> >
> > /* EVEX from legacy instructions, when the EVEX.ND bit is 0,
> > all bits of EVEX.vvvv and EVEX.V' must be 1. */
> > - if (ins->evex_type == evex_from_legacy && !ins->vex.b
> > + if (ins->evex_type == evex_from_legacy && !ins->vex.nd
> > && (ins->vex.register_specifier || !ins->vex.v))
> > return &bad_opcode;
>
> ... neither this nor ...
>
> > @@ -13388,11 +13396,10 @@ OP_VEX (instr_info *ins, int bytemode, int
> sizeflag ATTRIBUTE_UNUSED)
> > if (!ins->need_vex)
> > return true;
> >
> > - /* Here vex.b is treated as "EVEX.ND". */
> > if (ins->evex_type == evex_from_legacy)
> > {
> > ins->evex_used |= EVEX_b_used;
> > - if (!ins->vex.b)
> > + if (!ins->vex.nd)
> > return true;
> > }
>
> ... this should require touching here.
>
I moved them into NDD patch, , which adds these checks.
> > @@ -13884,3 +13894,26 @@ PREFETCHI_Fixup (instr_info *ins, int
> > bytemode, int sizeflag)
> >
> > return OP_M (ins, bytemode, sizeflag); }
> > +
> > +static bool
> > +PUSH2_POP2_Fixup (instr_info *ins, int bytemode, int sizeflag) {
> > + if (ins->modrm.mod != 3 || !ins->vex.b)
>
> Did you mean vex.nd? Plus, considering the vex.nd check further down, why is
> this checked both here and there?
>
Dropped.
> > + return true;
>
> Doesn't this result in silently bogus/wrong output? Shouldn't you print
> "(bad)" like you do further down? At which point it may make sense to simply
> fold both if()s?
>
> > --- a/opcodes/i386-opc.h
> > +++ b/opcodes/i386-opc.h
> > @@ -807,6 +807,7 @@ typedef struct i386_opcode_modifier
> > unsigned int isa64:2;
> > unsigned int noegpr:1;
> > unsigned int nf:1;
> > + unsigned int push2pop2:1;
> > } i386_opcode_modifier;
>
> Still a new modifier despite my earlier request to avoid adding one when you
> easily can? Here OperandConstraint is actually fully applicable to use, as what
> you want to enforce is a constraint on operands.
>
I also found this issue and removed it locally.
Thanks,
Lili.
More information about the Binutils
mailing list