[PATCH v2] Support APX CCMP and CTEST
Cui, Lili
lili.cui@intel.com
Thu Jun 6 13:45:13 GMT 2024
> On 03.06.2024 12:29, Cui, Lili wrote:
> > For the encoder part, add function check_Scc_OszcOperation to parse '{
> > dfv=of , sf, sf, cf}', store scc in the lower 4 bits of base_opcode,
> > and adjust base_opcode to its normal meaning before install_template.
>
> Looks like you're now doing this in install_template(), not before?
>
Done.
> > --- a/gas/config/tc-i386.c
> > +++ b/gas/config/tc-i386.c
> > @@ -416,6 +416,16 @@ struct _i386_insn
> > /* Compressed disp8*N attribute. */
> > unsigned int memshift;
> >
> > + /* SCC = EVEX.[SC3,SC2,SC1,SC0]. */
> > + unsigned int scc;
> > +
> > + /* Store 4 bits of EVEX.[OF,SF,ZF,CF]. */ #define OSZC_CF 0
> > +#define OSZC_ZF 1 #define OSZC_SF 2 #define OSZC_OF 3
>
> I should have spotted this before: Are you actually using the bit _positions_
> anywhere? Else ...
>
> > + unsigned int oszc_flags;
> > +
> > /* Prefer load or store in encoding. */
> > enum
> > {
> > @@ -1929,6 +1939,98 @@ static INLINE bool need_evex_encoding (const
> > insn_template *t) #define CPU_FLAGS_PERFECT_MATCH \
> > (CPU_FLAGS_ARCH_MATCH | CPU_FLAGS_64BIT_MATCH)
> >
> > +static INLINE void set_oszc_flags (unsigned int oszc_shift) {
> > + if (i.oszc_flags & (1 << oszc_shift))
>
> ... the shift here and below can be avoided.
>
Done.
> > + as_bad (_("same oszc flag used twice"));
> > + i.oszc_flags |= 1 << oszc_shift;
> > +}
>
> I also think this diagnostic would better be limited to once per parsed insn.
>
Do you mean to put it at the end of parse_insn ?
> > +/* Handle SCC OSZC flags. */
> > +
> > +static int
> > +check_Scc_OszcOperations (const char *l) {
> > + const char *suffix_string = l;
> > + while (is_space_char (*suffix_string))
> > + suffix_string++;
> > +
> > + /* If {oszc flags} is absent, just return l. */ if
> > + (*suffix_string != '{')
> > + return 0;
>
> Hmm, the comment says l is being returned here?
>
Done.
> > + /* Parse '{dfv='. */
> > + while (*suffix_string)
> > + {
> > + if (is_space_char (*suffix_string) || *suffix_string == '{')
> > + suffix_string++;
>
> Why would we want to accept multiple consecutive { on a single insn?
> You found the { ahead of the loop. Just increment the pointer there, look for
> only blanks here.
>
Done.
> > + else if (*suffix_string == '=')
> > + {
> > + suffix_string++;
> > + break;
> > + }
> > + else
> > + {
> > + if (startswith (suffix_string, "dfv"))
> > + suffix_string += 3;
> > + else
> > + {
> > + as_bad (_("Unrecognized oszc flags"));
> > + return -1;
> > + }
> > + }
>
> Please avoid unnecessarily deep indentation here. You already have one "else
> if". Just make the startswith() check another one.
>
> As to the diagnostic: You haven't parsed "dfv=" yet, so mentioning "oszc" may
> be misleading. We simply don't know what kind of pseudo- suffix this is, so
> perhaps that's also what the diagnostic should say.
>
> Additionally, just like for { you also want to refuse multiple "dfv" for a single
> insn.
>
Added check for multiple 'dfv' and test case.
> > + }
> > +
> > + /* Parse 'of , sf, zf, cf}'. */
> > + while (*suffix_string)
> > + {
> > + if (*suffix_string == ',' || is_space_char (*suffix_string))
> > + suffix_string++;
> > + else if (*suffix_string == '}')
> > + {
> > + suffix_string++;
> > + return suffix_string - l;
> > + }
> > + else
> > + {
> > + /* For oszc flags are updated as follows:
> > + – OF = EVEX.OF
> > + – SF = EVEX.SF
> > + – ZF = EVEX.ZF
> > + – CF = EVEX.CF
> > + – PF = EVEX.CF
> > + – AF = 0. */
> > + if (suffix_string[1] != 'f')
> > + {
> > + as_bad (_("Unrecognized oszc flags"));
> > + return -1;
> > + }
> > + switch (suffix_string[0])
> > + {
> > + case 'o':
> > + set_oszc_flags (OSZC_OF);
> > + break;
> > + case 's':
> > + set_oszc_flags (OSZC_SF);
> > + break;
> > + case 'z':
> > + set_oszc_flags (OSZC_ZF);
> > + break;
> > + case 'c':
> > + set_oszc_flags (OSZC_CF);
> > + break;
> > + default:
> > + as_bad (_("Unrecognized oszc flags"));
> > + return -1;
> > + }
> > + suffix_string += 2;
> > + }
> > + }
> > +
> > + as_bad (_("Unbalanced parenthesis in suffix"));
>
> Maybe better use `}' here. To me parenthesis means ( and ) only, but I'm aware
> that people use that, brace, and bracket in mixed associations. Hence best to
> be explicit about what is meant.
>
Changed it to '}'. I'm not sure if it should be `}'?
> > @@ -3793,10 +3895,19 @@ install_template (const insn_template *t)
> > }
> > }
> >
> > + /* For CCMP and CTEST the template has SCC in base_opcode. Move it out
> of
> > + there, to then adjust base_opcode to obtain its normal meaning.
> > + */ if (i.tm.opcode_modifier.operandconstraint == SCC)
>
> With the very use of SCC here, the comment might better disambiguate things
> and e.g. say "... has EVEX.SCC encode in base_opcode."
>
Done.
> > + {
> > + /* Store scc in the lower 4 bits of base_opcode. */
> > + i.scc = i.tm.base_opcode & 0xf;
> > + i.tm.base_opcode >>= 8;
>
> If there is a comment, it wants to be accurate. The code does not do what the
> comment says.
>
Changed it to
/* Get EVEX.SCC value from the lower 4 bits of base_opcode. */
> > @@ -4290,6 +4401,18 @@ build_apx_evex_prefix (void)
> > || i.tm.opcode_modifier.zu)
> > i.vex.bytes[3] |= 0x10;
> >
> > + /* Encode SCC and oszc flags bits. */ if
> > + (i.tm.opcode_modifier.operandconstraint == SCC)
> > + {
> > + /* The default value of vvvv is 1111 and needs to be cleared. */
> > + i.vex.bytes[2] &= ~0x78;
> > + i.vex.bytes[2] |= (i.oszc_flags << 3);
> > + /* ND and aaa bits shold be 0. */
> > + know (!(i.vex.bytes[3] & ~0xe8));
> > + /* The default value of V' is 1 and needs to be cleared. */
> > + i.vex.bytes[3] = (i.vex.bytes[3] & 0xf7) | i.scc;
>
> Better ~8 or ~0x08 to be in line with the clearing further up.
> Whereas in the know() I'd be inclined to ask that you avoid ~ and use 0x17
> directly.
>
Done.
> > --- /dev/null
> > +++ b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest.s
> > @@ -0,0 +1,208 @@
> > +# Check 64bit APX_F CCMP and CTEST instructions
> > +
> > + .text
> > +_start:
> > + ccmpbq {dfv=cf} $0x7b,0x123(%r8,%rax,4)
> > + ccmpb {dfv=cf} %r15w,%ax
> > + ccmpb {dfv=cf} 0x123(%r8,%rax,4),%r15d
> > + ccmpb {dfv=of, cf} $0x7b,%r15w
> > + ccmpbb {dfv=of, cf} $0x7b,0x123(%r8,%rax,4)
> > + ccmpbw {dfv=of, sf, cf} $0x7b,0x123(%r8,%rax,4)
> > + ccmpb {dfv=of, sf, cf} %r15,0x123(%r8,%rax,4)
> > + ccmpbw {dfv=of, sf, zf, cf} $0x7b,0x123(%r8,%rax,4)
> > + ccmpbq {dfv=of, sf, zf, cf} $0x7b,0x123(%r8,%rax,4)
> > + ccmpbl {dfv=of, sf, zf} $0x7b,0x123(%r8,%rax,4)
> > + ccmpb {dfv=of, sf, zf} %r15,0x123(%r8,%rax,4)
> > + ccmpbq {dfv=of, sf} $0x7b,0x123(%r8,%rax,4)
> > + ccmpb {dfv=of, sf} 0x123(%r8,%rax,4),%r8b
> > + ccmpbl {dfv=of, zf, cf} $0x7b,0x123(%r8,%rax,4)
> > + ccmpb {dfv=of, zf, cf} %r8b,0x123(%r8,%rax,4)
> > + ccmpbw {dfv=of, zf} $0x7b,0x123(%r8,%rax,4)
> > + ccmpb {dfv=of, zf} %r8b,%dl
> > + ccmpb {dfv=of} %r15d,%edx
> > + ccmpb {dfv=of} 0x123(%r8,%rax,4),%r15w
> > + ccmpb {dfv=sf, cf} $0x7b,%r8b
> > + ccmpb {dfv=sf, cf} %r15d,0x123(%r8,%rax,4)
> > + ccmpb {dfv=sf, cf} 0x123(%r8,%rax,4),%r15
> > + ccmpb {dfv=sf, zf, cf} $0x7b,%r15d
> > + ccmpb {dfv=sf, zf, cf} 0x123(%r8,%rax,4),%r15w
> > + ccmpb {dfv=sf, zf} $0x7b,%r15d
> > + ccmpb {dfv=sf, zf} %r15d,0x123(%r8,%rax,4)
> > + ccmpbq {dfv=sf} $0x7b,0x123(%r8,%rax,4)
> > + ccmpb {dfv=sf} %r15,%r15
> > + ccmpb {dfv=sf} 0x123(%r8,%rax,4),%r15
> > + ccmpb {dfv=zf, cf} $0x7b,%r15
> > + ccmpbl {dfv=zf, cf} $0x7b,0x123(%r8,%rax,4)
> > + ccmpb {dfv=zf, cf} %r15w,0x123(%r8,%rax,4)
> > + ccmpb {dfv=zf} $0x7b,%r15
> > + ccmpbw {dfv=zf} $0x7b,0x123(%r8,%rax,4)
> > + ccmpb {dfv=zf} %r15w,0x123(%r8,%rax,4)
> > + ccmpb {dfv=} $0x7b,%r15w
> > + ccmpbl {dfv=} $0x7b,0x123(%r8,%rax,4)
> > + ccmpb {dfv=} 0x123(%r8,%rax,4),%r15d
> > + ccmpo {dfv=of} $0x7b,%r16
> > + ccmpno {dfv=of} $0x7b,%r17
> > + ccmpb {dfv=of} $0x7b,%r18
> > + ccmpae {dfv=of} $0x7b,%r19
> > + ccmpe {dfv=of} $0x7b,%r20
> > + ccmpne {dfv=of} $0x7b,%r21
> > + ccmpbe {dfv=of} $0x7b,%r22
> > + ccmpa {dfv=of} $0x7b,%r23
>
> Is the odd padding here and ...
>
> > + ccmps {dfv=of} $0x7b,%r24
> > + ccmpns {dfv=of} $0x7b,%r25
> > + ccmpt {dfv=of} $0x7b,%r26
> > + ccmpf {dfv=of} $0x7b,%r27
> > + ccmpl {dfv=of} $0x7b,%r28
> > + ccmpge {dfv=of} $0x7b,%r29
> > + ccmple {dfv=of} $0x7b,%r30
> > + ccmpg {dfv=of} $0x7b,%r31
>
> ... here deliberate, to specifically test something unusual?
>
This is a typo, probably introduced when I was performing a suffix replacement (changing scc to something like jcc ).
> > + ctestb {dfv=cf} $0x7b,%r15
> > + ctestbw {dfv=cf} $0x7b,0x123(%r8,%rax,4)
> > + ctestbb {dfv=of, cf} $0x7b,0x123(%r8,%rax,4)
> > + ctestb {dfv=of, cf} %r15,0x123(%r8,%rax,4)
> > + ctestbq {dfv=of, sf, cf} $0x7b,0x123(%r8,%rax,4)
> > + ctestbl {dfv=of, sf, zf, cf} $0x7b,0x123(%r8,%rax,4)
> > + ctestbw {dfv=of, sf, zf} $0x7b,0x123(%r8,%rax,4)
> > + ctestbl {dfv=of, sf} $0x7b,0x123(%r8,%rax,4)
> > + ctestb {dfv=of, sf} %r15w,0x123(%r8,%rax,4)
> > + ctestbw {dfv=of, zf, cf} $0x7b,0x123(%r8,%rax,4)
> > + ctestb {dfv=of, zf, cf} %r15w,0x123(%r8,%rax,4)
> > + ctestbb {dfv=of, zf} $0x7b,0x123(%r8,%rax,4)
> > + ctestb {dfv=of, zf} %r15,0x123(%r8,%rax,4)
> > + ctestb {dfv=of} %r15d,0x123(%r8,%rax,4)
> > + ctestb {dfv=of} %r8b,0x123(%r8,%rax,4)
> > + ctestbl {dfv=sf, cf} $0x7b,0x123(%r8,%rax,4)
> > + ctestb {dfv=sf, cf} %r15d,%edx
> > + ctestb {dfv=sf, zf, cf} %r15d,0x123(%r8,%rax,4)
> > + ctestb {dfv=sf, zf, cf} %r8b,%dl
> > + ctestb {dfv=sf, zf} $0x7b,%r15w
> > + ctestbq {dfv=sf, zf} $0x7b,0x123(%r8,%rax,4)
> > + ctestb {dfv=sf} $0x7b,%r15d
> > + ctestbw {dfv=sf} $0x7b,0x123(%r8,%rax,4)
> > + ctestb {dfv=zf, cf} $0x7b,%r8b
> > + ctestbq {dfv=zf, cf} $0x7b,0x123(%r8,%rax,4)
> > + ctestbl {dfv=zf} $0x7b,0x123(%r8,%rax,4)
> > + ctestb {dfv=zf} %r15,%r15
> > + ctestbq {dfv=} $0x7b,0x123(%r8,%rax,4)
> > + ctestb {dfv=} %r15w,%ax
> > + ctesto {dfv=of} $0x7b,%r16
> > + ctestno {dfv=of} $0x7b,%r17
> > + ctestb {dfv=of} $0x7b,%r18
> > + ctestnb {dfv=of} $0x7b,%r19
> > + ctestz {dfv=of} $0x7b,%r20
> > + ctestnz {dfv=of} $0x7b,%r21
> > + ctestbe {dfv=of} $0x7b,%r22
> > + ctestnbe {dfv=of} $0x7b,%r23
> > + ctests {dfv=of} $0x7b,%r24
> > + ctestns {dfv=of} $0x7b,%r25
> > + ctestt {dfv=of} $0x7b,%r26
> > + ctestf {dfv=of} $0x7b,%r27
> > + ctestl {dfv=of} $0x7b,%r28
> > + ctestnl {dfv=of} $0x7b,%r29
> > + ctestle {dfv=of} $0x7b,%r30
> > + ctestnle {dfv=of} $0x7b,%r31
> > + {evex} cmp $0x7b,%r18
> > + {evex} test $0x7b,%r18
>
> Would be nice if each insn template was covered at least once.
>
OK.
> Also, question: Wouldn't it make sense to also disassemble these as simple
> CMP/TEST (with {evex} prefix), at least by default (e.g. by slightly abusing
> suffix-always mode to also cover the case here)?
>
> > @@ -10331,6 +10348,18 @@ static const char *const fgrps[][8] = {
> > },
> > };
> >
> > +static const char *const oszc_flags[16] = {
> > + " {dfv=}", " {dfv=cf}", " {dfv=zf}", " {dfv=zf, cf}", " {dfv=sf}",
> > + " {dfv=sf, cf}", " {dfv=sf, zf}", " {dfv=sf, zf, cf}", " {dfv=of}",
> > + " {dfv=of, cf}", " {dfv=of, zf}", " {dfv=of, zf, cf}", " {dfv=of,
> > +sf}",
> > + " {dfv=of, sf, cf}", " {dfv=of, sf, zf}", " {dfv=of, sf, zf, cf}"
> > +};
>
> I find repeating " {dfv=" 16 times here quite odd, but I'm not going to insist
> that you reduce this redundancy.
I try to avoid repeating 16 times with this way, but the {} is split into two parts, which looks a bit strange. What are your thoughts?
/* Add { dfv=of, sf, zf, cf} flags. */
oappend (ins, "{ dfv=");
oappend (ins, oszc_flags[oszc_value]);
static const char *const oszc_flags[16] = {
"}", "cf}", ...
};
>
> > @@ -10505,16 +10534,38 @@ putop (instr_info *ins, const char
> *in_template, int sizeflag)
> > abort ();
> > break;
> > case 'C':
> > - if (ins->intel_syntax && !alt)
> > - break;
> > - if ((ins->prefixes & PREFIX_DATA) || (sizeflag & SUFFIX_ALWAYS))
> > + if (l == 0)
> > {
> > - if (sizeflag & DFLAG)
> > - *ins->obufp++ = ins->intel_syntax ? 'd' : 'l';
> > - else
> > - *ins->obufp++ = ins->intel_syntax ? 'w' : 's';
> > - ins->used_prefixes |= (ins->prefixes & PREFIX_DATA);
> > + if (ins->intel_syntax && !alt)
> > + break;
> > + if ((ins->prefixes & PREFIX_DATA) || (sizeflag & SUFFIX_ALWAYS))
> > + {
> > + if (sizeflag & DFLAG)
> > + *ins->obufp++ = ins->intel_syntax ? 'd' : 'l';
> > + else
> > + *ins->obufp++ = ins->intel_syntax ? 'w' : 's';
> > + ins->used_prefixes |= (ins->prefixes & PREFIX_DATA);
> > + }
> > + }
> > + else if (l == 1 && last[0] == 'S')
> > + {
> > + /* Add scc suffix. */
> > + ins->obufp = stpcpy (ins->obufp, scc_suffix[ins->vex.scc]);
>
> Why not oappend()?
>
Added it and changed staging_area from 40 to 50 for some special cases that we used append () 3 times and exceeds the size of staging_area.
For example,
oappend (ins, scc_suffix[ins->vex.scc]);
oappend (ins, "(bad)");
oappend (ins, oszc_flags[oszc_value]);
> > + /* For SCC insns, the ND bit is required to be set to 0. */
> > + if (ins->vex.nd)
> > + {
> > + oappend (ins, "(bad)");
> > + break;
> > + }
> > +
> > + /* These bits have been consumed and should be cleared or
> restored to default
> > + values. */
Done.
Thanks,
Lili.
More information about the Binutils
mailing list