[PATCH] Support APX CFCMOV

Cui, Lili lili.cui@intel.com
Mon Jun 24 08:04:48 GMT 2024


> On 17.06.2024 08:18, Cui, Lili wrote:
> > --- /dev/null
> > +++ b/gas/testsuite/gas/i386/x86-64-apx-cfcmov.s
> > @@ -0,0 +1,680 @@
> > +# Check 64bit EVEX-promoted CMOVcc instructions
> > +
> > +	.text
> > +_start:
> > +	cfcmovb	%dx,%ax
> 
> What about cmova or cmovae? Others look to not be covered either. Every
> condition code mnemonic suffix should imo be tested at least once.

For the assembler, I used <cc> as recommended by spec, cmova = comvnbe/ cmovae = cmovnb
For the disassembler, I used the same format as jcc.

> 
> > +	cfcmovb.s	%dx,%ax
> > +	cfcmovb	%dx,%ax,%r31w
> > +	cfcmovb	%dx,291(%r8,%rax,4)
> > +	cfcmovb	%ecx,%edx
> > +	cfcmovb	%ecx,%edx,%r10d
> > +	cfcmovb	%ecx,291(%r8,%rax,4)
> > +	cfcmovb	%r31,%r15
> > +	cfcmovb	%r31,%r15,%r11
> > +	cfcmovb	%r31,291(%r8,%rax,4)
> > +	cfcmovb	291(%r8,%rax,4),%dx
> > +	cfcmovb	291(%r8,%rax,4),%dx,%ax
> > +	cfcmovb	291(%r8,%rax,4),%ecx
> > +	cfcmovb	291(%r8,%rax,4),%ecx,%edx
> > +	cfcmovb	291(%r8,%rax,4),%r31
> > +	cfcmovb	291(%r8,%rax,4),%r31,%r15
> > +	cfcmovbe	%dx,%ax
> > +	cfcmovbe	%dx,%ax,%r31w
> > +	cfcmovbe	%dx,291(%r8,%rax,4)
> > +	cfcmovbe	%ecx,%edx
> > +	cfcmovbe	%ecx,%edx,%r10d
> > +	cfcmovbe	%ecx,291(%r8,%rax,4)
> > +	cfcmovbe	%r31,%r15
> > +	cfcmovbe	%r31,%r15,%r11
> > +	cfcmovbe	%r31,291(%r8,%rax,4)
> > +	cfcmovbe	291(%r8,%rax,4),%dx
> > +	cfcmovbe	291(%r8,%rax,4),%dx,%ax
> > +	cfcmovbe	291(%r8,%rax,4),%ecx
> > +	cfcmovbe	291(%r8,%rax,4),%ecx,%edx
> > +	cfcmovbe	291(%r8,%rax,4),%r31
> > +	cfcmovbe	291(%r8,%rax,4),%r31,%r15
> 
> If I'm not mistaken, operands are all the same between the condition code
> groups. In such a case, did you consider using .irp to reduce source volume
> (and redundancy) quite a bit?
> 

Yes, good idea.

> > +	cmovb	%dx,%ax,%r31w
> > +	cmovb	%ecx,%edx,%r10d
> 
> Don't we have cmov<cc> tests already? I don't mind having more, but in such
> a case that's once again something to mention in the description.
> 

Ok, I'll add descriptions in the changelog.

> > @@ -10565,7 +10567,17 @@ putop (instr_info *ins, const char
> *in_template, int sizeflag)
> >  		}
> >  	    }
> >  	  else if (l == 1 && last[0] == 'C')
> > -	    break;
> > +	    {
> > +	      if (ins->vex.nd && !ins->vex.nf)
> > +		break;
> > +	      else
> 
> Nit: This is again one of these odd "else". Without it code, beyond being a tiny
> bit shorter, ...
> 
> > +		{
> > +		  *ins->obufp++ = 'c';
> > +		  *ins->obufp++ = 'f';
> > +		  /* Skip printing {evex} */
> > +		  evex_printed = true;
> > +		}
> 
> ... will also get away with less indentation (and no braces) here.
> 

Done.

> > @@ -14046,3 +14058,39 @@ JMPABS_Fixup (instr_info *ins, int bytemode,
> int sizeflag)
> >      return OP_IMREG (ins, bytemode, sizeflag);
> >    return OP_OFF64 (ins, bytemode, sizeflag);  }
> > +
> > +static bool
> > +CFCMOV_Fixup_op0 (instr_info *ins, int bytemode, int sizeflag) {
> > +  /* EVEX.NF is used as a direction bit in the 2-operand case to reverse the
> > +     source and destination operands. */
> > +  if (!ins->vex.nd && ins->vex.nf)
> > +    {
> > +      bytemode = v_swap_mode;
> 
> Why is this? Iirc *_swap_mode are used when alternative encodings for the
> same operand combinations exist, which wouldn't be recognizable. They also
> look to only take effect in suffix-always mode, yet you don't add any respective
> testing. (Which isn't to mean I think you should add such. But if this line above
> was really meaningful, then such testing would be needed, to show its effects
> and to ensure those effects won't go away going forward.)
> 

I enabled "-Msuffix" in x86-64-apx-cfcmov-intel.d, unfortunately, it wasn't obvious where I put it. I will add more tests and put it at the end of the tests.
 
[       ]*[a-f0-9]+:[   ]*62 f4 7d 0c 42 d0[    ]+cfcmovb.s ax,dx

> > +      return OP_E (ins, bytemode, sizeflag);
> > +    }
> > +  else
> > +    {
> > +      return OP_G (ins, bytemode, sizeflag);
> > +    }
> > +}
> > +
> > +static bool
> > +CFCMOV_Fixup_op1 (instr_info *ins, int bytemode, int sizeflag) {
> > +  /* EVEX.NF is used as a direction bit in the 2-operand case to reverse the
> > +     source and destination operands. */
> > +  if (!ins->vex.nd && ins->vex.nf)
> > +    {
> > +      /* These bits have been consumed and should be cleared.  */
> > +      ins->vex.nf = false;
> > +      ins->vex.mask_register_specifier = 0;
> > +      return OP_G (ins, bytemode, sizeflag);
> > +    }
> > +  else
> > +    {
> > +      ins->vex.nf = false;
> > +      ins->vex.mask_register_specifier = 0;
> 
> It's certainly a little odd for this to be done identically in if and else.
> 

Done.

> > +      return OP_E (ins, bytemode, sizeflag);
> > +    }
> > +}
> 
> I wonder anyway whether we actually need two functions here. The mode put
> in the table entries is only ever v_mode. By slightly abusing that, you could use
> that parameter to indicate which operand it is, then passing v_mode explicitly
> to OP_E() / OP_G(). We apparently have a precedent for this already:
> NOP_Fixup() is quite similar in this regard. A few others also don't really have
> a mode passed, but they're somewhat different in nature.
> 
It is a good example, changed.

Thanks,
Lili.



More information about the Binutils mailing list