Support APX CCMP and CTEST

Message ID 20240523061221.2022556-1-lili.cui@intel.com
State New
Headers
Series Support APX CCMP and CTEST |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Testing passed

Commit Message

Cui, Lili May 23, 2024, 6:12 a.m. UTC
  With the new macro %NP (no prefix) introduced in this patch, we can remove %ME of movbe.

CCMP and CTEST are two new sets of instructions for conditional CMP
and TEST, SCC and OSZC flags are given as suffixes of CCMP or CTEST
in the instruction mnemonic, e.g.:

ccmp<cc> { dfv=sf , cf , of }

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
(like the legacy instructions), and restore it to i.tm.base_opcode in
install_template.
For the decoder part, add function SCC_And_OSZC_Flags_Fixup to add scc
and oszc flags suffixes.

gas/ChangeLog:

        * config/tc-i386-intel.c (i386_intel_operand): Handle
	check_Scc_OszcOperations.
        * config/tc-i386.c (struct _i386_insn):
        (install_template): Add scc and oszc_flags.
        (build_apx_evex_prefix): Encode SCC and oszc flags bits.
        (parse_operands): Change it for oszc flags.
        (check_Scc_OszcOperations):  Handle SCC OSZC flags.
        (i386_att_operand): Ditto.
        * testsuite/gas/i386/x86-64-apx-evex-promoted-bad.d: Add ivalid test
	case for ccmp.
        * testsuite/gas/i386/x86-64-apx-evex-promoted-bad.s: Ditto.
        * testsuite/gas/i386/x86-64.exp: Add test for ccmp and ctest.
        * testsuite/gas/i386/x86-64-apx-ccmp-ctest-intel.d: New test.
        * testsuite/gas/i386/x86-64-apx-ccmp-ctest-inval.l: Ditto.
        * testsuite/gas/i386/x86-64-apx-ccmp-ctest-inval.s: Ditto.
        * testsuite/gas/i386/x86-64-apx-ccmp-ctest.d: Ditto.
        * testsuite/gas/i386/x86-64-apx-ccmp-ctest.s: Ditto.

opcodes/ChangeLog:

        * i386-dis-evex-reg.h: Add ccmp and ctest.
        * i386-dis-evex.h: Ditto.
        * i386-dis.c (SCC_And_OSZC_Flags_Fixup): New.
        (struct instr_info): Ditto.
        (SCC_And_OSZC_Flags): Ditto.
        (struct dis386): Add new micro 'NP'.
        (get_valid_dis386): Move MAP4 invalid check to print_insn.
        (putop): Handle %NP.
        (print_insn): Ditto.
        * i386-gen.c: Add SCC.
        * i386-opc.h: Ditto.
        * i386-opc.tbl: Add ccmp and ctest.
        * i386-mnem.h: Regenerated.
        * i386-tbl.h: Ditto.
---
 gas/config/tc-i386-intel.c                    |   8 +
 gas/config/tc-i386.c                          | 133 ++++++++++-
 .../gas/i386/x86-64-apx-ccmp-ctest-intel.d    | 220 ++++++++++++++++++
 .../gas/i386/x86-64-apx-ccmp-ctest-inval.l    |   5 +
 .../gas/i386/x86-64-apx-ccmp-ctest-inval.s    |   6 +
 .../gas/i386/x86-64-apx-ccmp-ctest.d          | 220 ++++++++++++++++++
 .../gas/i386/x86-64-apx-ccmp-ctest.s          | 217 +++++++++++++++++
 .../gas/i386/x86-64-apx-evex-promoted-bad.d   |  22 +-
 .../gas/i386/x86-64-apx-evex-promoted-bad.s   |   6 +-
 gas/testsuite/gas/i386/x86-64.exp             |   3 +
 opcodes/i386-dis-evex-reg.h                   |  11 +-
 opcodes/i386-dis-evex.h                       |  12 +-
 opcodes/i386-dis.c                            | 101 ++++++--
 opcodes/i386-gen.c                            |   1 +
 opcodes/i386-opc.h                            |   4 +
 opcodes/i386-opc.tbl                          |  13 +-
 16 files changed, 939 insertions(+), 43 deletions(-)
 create mode 100644 gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-intel.d
 create mode 100644 gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-inval.l
 create mode 100644 gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-inval.s
 create mode 100644 gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest.d
 create mode 100644 gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest.s
  

Comments

Jan Beulich May 27, 2024, 3:08 p.m. UTC | #1
On 23.05.2024 08:12, Cui, Lili wrote:
> With the new macro %NP (no prefix) introduced in this patch, we can remove %ME of movbe.

What are you describing here? I can't spot a respective change in the
patch. If this is meant to say "we then could ...", please put such
remarks outside of the commit message area.

> CCMP and CTEST are two new sets of instructions for conditional CMP
> and TEST, SCC and OSZC flags are given as suffixes of CCMP or CTEST
> in the instruction mnemonic, e.g.:
> 
> ccmp<cc> { dfv=sf , cf , of }
> 
> 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
> (like the legacy instructions), and restore it to i.tm.base_opcode in
> install_template.

What do you mean by "restore it to i.tm.base_opcode"? I don't think this
comes anywhere near what you're actually doing.

Just for the record: I also consider this syntax pretty odd, but I
understand that's what "Assembly Syntax Recommendations" suggests. It
would imo be quite a bit less convoluted if it simply was a separate
pseudo-immediate operand (much like e.g. {sae} is in AT&T syntax).

> --- a/gas/config/tc-i386-intel.c
> +++ b/gas/config/tc-i386-intel.c
> @@ -619,6 +619,14 @@ i386_intel_operand (char *operand_string, int got_a_float)
>    bool rc_sae_modifier = i.rounding.type != rc_none && i.rounding.modifier;
>    int ret;
>  
> +  /* Handle SCC OSZC flgs.  */
> +  if (current_templates.start->opcode_modifier.scc)
> +    {
> +      operand_string = check_Scc_OszcOperations (operand_string);
> +      if (operand_string == NULL)
> +	return 0;
> +    }

This doesn't look right to me: We're parsing an operand here (at any
position), yet the OSZC specifier is effectively a mnemonic pseudo-
suffix (or else there would need to be a separating comma between it
and the other operand). This is also shown in the doc, where this
always follows the mnemonic, irrespective of AT&T vs Intel operand
order.

> --- 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;
> +
> +    #define CF 0
> +    #define ZF 1
> +    #define SF 2
> +    #define OF 3

These names are misleading - they suggest they somehow enumerate EFLAGS.CF
etc. Perhaps OSZC_CF etc?

Also #define-s starting in the first column, please (blanks between # and
define are okay-ish, if so desired).

> +    /* Store 4 bits of EVEX.[OF,SF,ZF,CF].  */
> +    unsigned int oszc_flags;
> +
>      /* Prefer load or store in encoding.  */
>      enum
>        {
> @@ -3793,10 +3803,19 @@ install_template (const insn_template *t)
>  	}
>      }
>  
> +  /* For the ccmp and ctest instructions we use base_opcode like the legacy
> +     instructions and restore it in i.tm.base_opcode.  */
> +  if (i.tm.opcode_modifier.scc)
> +    {
> +      /* Store scc in the lower 4 bits of base_opcode.  */
> +      i.scc = i.tm.base_opcode & 0xf;
> +      i.tm.base_opcode >>= 8;
> +    }

As noted on the description already: You don't mean "restore" here, as there's
no "save" counterpart anywhere. "like the legacy insns" isn't quite right
either. Maybe

  /* 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.  */

?

> @@ -4290,6 +4309,16 @@ 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.scc)
> +    {
> +      i.vex.bytes[2] &= ~0x78;

Is there any way these 4 bits may be set before coming here? I hope there
isn't, in which case an assertion (or know()) would seem more appropriate.

> +      i.vex.bytes[2] |= (i.oszc_flags << 3);
> +      i.vex.bytes[3] = (i.vex.bytes[3] & 0xf0) | i.scc;

Same question for these 4 bits, and ...

> +      /* The ND bit is required to be set to 0.  */
> +      i.vex.bytes[3] &= 0xef;

... for ND.

> @@ -7539,13 +7568,14 @@ parse_operands (char *l, const char *mnemonic)
>  		      i.operands + 1);
>  	      return NULL;
>  	    }
> -	  if (!intel_syntax && !in_quotes)
> +	  if (!in_quotes)
>  	    {
> -	      if (*l == '(')
> +	      if (*l == '(' || *l == '{')
>  		++paren_not_balanced;
> -	      if (*l == ')')
> +	      if (*l == ')' || *l == '}')
>  		--paren_not_balanced;
>  	    }

This isn't right either (closing } shouldn't match an opening parenthesis),
but will go away anyway as you move the parsing from operand handling to
mnemonic handling.

> @@ -13578,6 +13608,93 @@ RC_SAE_specifier (const char *pstr)
>    return NULL;
>  }
>  
> +/* Handle SCC OSZC flags.  */
> +
> +static char *
> +check_Scc_OszcOperations (char *op_string)
> +{
> +  /* If {oszc flags} is absent, just return op_string.  */
> +  if (*op_string != '{')
> +    return op_string;
> +  else

Please help limiting indentation by omitting such an "else".

> +    {
> +      bool has_equal;
> +      /* Parse '{dfv='.  */
> +      while (*op_string)
> +	{
> +	  if (*op_string != '=')
> +	    op_string++;
> +	  else
> +	    {
> +	      has_equal = true;
> +	      op_string++;
> +	      break;
> +	    }
> +	}
> +
> +      if (!has_equal)
> +	{
> +	  /* If there is no '=', report bad.  */
> +	  as_bad (_("Unrecognized oszc flags"));
> +	  ignore_rest_of_line ();
> +	}
> +    }

Where does "dfv" actually get checked? You can't just look for '=' and
hope the rest is fine.

ignore_rest_of_line() also looks wrong to use here, as you're not
consuming from input_line_pointer. Instead I think you want to return
NULL there instead.

> +  /* Parse 'of , sf, sf, cf}'.  */

"sf" twice?

> +  while (*op_string)
> +    {
> +      if (*op_string == ',' || is_space_char (*op_string))
> +	op_string++;
> +      else if (*op_string == '}')
> +	{
> +	  op_string++;
> +	  while (is_space_char (*op_string))
> +	    op_string++;
> +	  return op_string;
> +	}
> +      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 (op_string[1] != 'f')
> +	    {
> +	      as_bad (_("Unrecognized oszc flags"));
> +	      ignore_rest_of_line ();
> +	      return NULL;
> +	    }
> +	  switch (op_string[0])
> +	    {
> +	    case 'o':
> +	      i.oszc_flags |= (1 << OF);
> +	      break;
> +	    case 's':
> +	      i.oszc_flags |= (1 << SF);
> +	      break;
> +	    case 'z':
> +	      i.oszc_flags |= (1 << ZF);
> +	      break;
> +	    case 'c':
> +	    case 'p':

I don't think "pf" should be recognized here. As terminology says here and
in the spec, it's OSZC (no P in there).

> +	      i.oszc_flags |= (1 << CF);
> +	      break;

Shouldn't you further reject redundant settings, as in

	ccmpe {dfv=cf,cf} ...

?

> +	    case 'a':
> +	      break;

"af" pretty certainly may not be recognized here, as that would imply
EFLAGS.AF becoming set, not cleared.

> +	    default:
> +	      as_bad (_("Unrecognized oszc flags"));
> +	      ignore_rest_of_line ();
> +	      return NULL;
> +	    }
> +	  op_string += 2;
> +	}
> +    }
> +  return op_string;
> +}
> +
>  /* Handle Vector operations.  */
>  
>  static char *
> @@ -14486,6 +14603,14 @@ i386_att_operand (char *operand_string)
>        i.jumpabsolute = true;
>      }
>  
> +  /* Handle SCC OSZC flgs.  */
> +  if (current_templates.start->opcode_modifier.scc)
> +    {
> +      op_string = check_Scc_OszcOperations (op_string);
> +      if (op_string == NULL)
> +	return 0;
> +    }

See remark on i386_intel_operand().

> --- /dev/null
> +++ b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-intel.d
> @@ -0,0 +1,220 @@
> +#as:
> +#objdump: -dw -Mintel
> +#name: x86_64 APX_F CCMP and CTEST insns (Intel disassembly)
> +#source: x86-64-apx-ccmp-ctest.s
> +
> +.*: +file format .*
> +
> +Disassembly of section \.text:
> +
> +0+ <_start>:
> +\s*[a-f0-9]+:\s*62 d4 8c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=cf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b

In order to spot possible issues, it helps is test expectations are readable.
\s is imo hampering readability, as in not being a visual separator. However,
what I strongly object to is a _mix_ of \s and [ 	].

> --- /dev/null
> +++ b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest.s
> @@ -0,0 +1,217 @@
> +# Check 64bit APX_F CCMP and CTEST instructions
> +
> + .text
> +_start:
> +	ccmpbq {dfv=pf} $0x7b,0x123(%r8,%rax,4)
> +	ccmpb  {dfv=pf} %r15w,%ax
> +	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
> +	ccmpb  {dfv=af} 0x123(%r8,%rax,4),%r15d
> +	ccmpo   {dfv=of} $0x7b,%r16

Why the discontinuity in padding? (As indicated elsewhere, imo the
OSZC specifier better wouldn't be in the operand area anyway, for not
being an operand in the way it is specified/handled right now.)

> +	ccmpno  {dfv=of} $0x7b,%r17
> +	ccmpb   {dfv=of} $0x7b,%r18
> +	ccmpnb  {dfv=of} $0x7b,%r19
> +	ccmpz   {dfv=of} $0x7b,%r20
> +	ccmpnz  {dfv=of} $0x7b,%r21
> +	ccmpbe  {dfv=of} $0x7b,%r22
> +	ccmpnbe {dfv=of} $0x7b,%r23
> +	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
> +	ccmpnl  {dfv=of} $0x7b,%r29
> +	ccmple  {dfv=of} $0x7b,%r30
> +	ccmpnle {dfv=of} $0x7b,%r31
> +	ctestb  {dfv=pf} $0x7b,%r15
> +	ctestbw {dfv=pf} $0x7b,0x123(%r8,%rax,4)
> +	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
> +	ctestb  {dfv=af} %r15w,%ax
> +	ctesto   {dfv=of} $0x7b,%r16

Yet another such disconinuity.

> --- a/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.s
> +++ b/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.s
> @@ -43,7 +43,7 @@ _start:
>  
>  	# pop2 %rax, %r8 set EVEX.ND=0.
>  	.byte 0x62, 0xf4, 0x3c, 0x08, 0x8f, 0xc0
> -	.byte 0xff, 0xff, 0xff
> +	.byte 0xff, 0xff

What's the reason for this and ...

> @@ -56,3 +56,7 @@ _start:
>  
>  	# EVEX_MAP4 movbe %r18w,%ax set EVEX.P[10] = 0.
>  	.byte 0x62, 0xfc, 0x79, 0x08, 0x60, 0xc2
> +	.byte 0xff, 0xff

... this adjustment? Preferably the existing by sequences would be
adjusted such that such extra 0xff won't be needed.

> +	# ccmps {dfv=of,sf,zf,cf} %r15, %rdx set EVEX.ND=0.
> +	.insn EVEX.L0.M4.W1 0x38, %r15, {rn-sae},%rdx

What's wrong about ND=0? IOW what is it that you're trying to check
here?

> --- a/opcodes/i386-dis.c
> +++ b/opcodes/i386-dis.c
> @@ -596,6 +598,7 @@ fetch_error (const instr_info *ins)
>  #define PCLMUL { PCLMUL_Fixup, 0 }
>  #define VPCMP { VPCMP_Fixup, 0 }
>  #define VPCOM { VPCOM_Fixup, 0 }
> +#define SCC_And_OSZC_Flags { SCC_And_OSZC_Flags_Fixup, 0 }

Can you perhaps drop "_Flags" from these names? That won't create ambiguity
yet help readability by shortening things.

> @@ -1832,6 +1835,8 @@ struct dis386 {
>  	   instruction.
>     "NF" => print "{nf} " pseudo prefix when EVEX.NF = 1 and print "{evex} "
>  	   pseudo prefix when instructions without NF, EGPR and VVVV,
> +   "NP" => don't print "{evex} " pseudo prefix for some special instructions
> +	   in MAP4.

"NP" pretty clearly means "no prefix". What you mean is "no {evex}", so
perhaps better %NE (albeit that may end up ambiguous down the road, yet
what do you do)?

> @@ -9181,22 +9187,8 @@ get_valid_dis386 (const struct dis386 *dp, instr_info *ins)
>  	  ins->rex2 &= ~REX_R;
>  	}
>  
> -      /* 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.nd
> -	  && (ins->vex.register_specifier || !ins->vex.v))
> -	return &bad_opcode;
> -
>        ins->need_vex = 4;
>  
> -      /* EVEX from legacy instructions require that EVEX.z, EVEX.L’L and the
> -	 lower 2 bits of EVEX.aaa must be 0.  */
> -      if (ins->evex_type == evex_from_legacy
> -	  && ((ins->vex.mask_register_specifier & 0x3) != 0
> -	      || ins->vex.ll != 0
> -	      || ins->vex.zeroing != 0))
> -	return &bad_opcode;
> -
>        ins->codep++;
>        vindex = *ins->codep++;
>        if (vex_table_index != EVEX_MAP7)
> @@ -9746,6 +9738,32 @@ print_insn (bfd_vma pc, disassemble_info *info, int intel_syntax)
>        }
>    }
>  
> +  /* The purpose of placing the check here is to wait for the EVEX prefix for
> +     conditional CMP and TEST to be consumed and cleared, and then make a
> +     unified judgment. Because they are both in map4, we can not distinguish
> +     EVEX prefix for conditional CMP and TEST from others during the
> +     EVEX prefix stage of parsing.  */
> +  /* 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.nd
> +      && (ins.vex.register_specifier || !ins.vex.v))
> +    {
> +      i386_dis_printf (info, dis_style_text, "(bad)");
> +      ret = ins.end_codep - priv.the_buffer;
> +      goto out;
> +    }
> +
> +  /* EVEX from legacy instructions require that EVEX.z, EVEX.L’L and the
> +     lower 2 bits of EVEX.aaa must be 0.  */
> +  if (ins.evex_type == evex_from_legacy
> +      && ((ins.vex.mask_register_specifier & 0x3) != 0
> +	  || ins.vex.ll != 0 || ins.vex.zeroing != 0))
> +    {
> +      i386_dis_printf (info, dis_style_text, "(bad)");
> +      ret = ins.end_codep - priv.the_buffer;
> +      goto out;
> +    }

With them now properly back-to-back, they want folding. That way the
initial (new) comment would also suitably cover both:

  /* The purpose of placing the check here is to wait for the EVEX prefix for
     conditional CMP and TEST to be consumed and cleared, and then make a
     unified judgment. Because they are both in map4, we can not distinguish
     EVEX prefix for conditional CMP and TEST from others during the
     EVEX prefix stage of parsing.  */
  if (ins.evex_type == evex_from_legacy)
    {
      ...

> @@ -14089,3 +14110,55 @@ JMPABS_Fixup (instr_info *ins, int bytemode, int sizeflag)
>      return OP_IMREG (ins, bytemode, sizeflag);
>    return OP_OFF64 (ins, bytemode, sizeflag);
>  }
> +
> +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}"
> +};
> +
> +static const char *const scc_suffix[16] = {
> +  "o", "no", "b", "nb", "z", "nz", "be", "nbe", "s", "ns", "t", "f",
> +  "l", "nl", "le", "nle"
> +};

Can these please be in sync with the forms we use for e.g. Jcc and SETcc?
I actually have a patch pending harmonizing these for CMPccXADD as well.

Also please have a separating blank line below here.

> +static bool
> +SCC_And_OSZC_Flags_Fixup (instr_info *ins, int bytemode ATTRIBUTE_UNUSED,
> +		 int sizeflag ATTRIBUTE_UNUSED)
> +{
> +  ins->obufp = ins->mnemonicendp;
> +
> +  /* Get oszc flags value from register_specifier.  */
> +  int oszc_value = ~ins->vex.register_specifier & 0xf;
> +
> +  /* If ccmp and ctest already have suffixes, they should be moved after the
> +     scc suffix.  */
> +  if (ins->obufp[-1] != 'p' && ins->obufp[-1] != 't')
> +    {
> +      char suffix = ins->obufp[-1];
> +      ins->obufp--;
> +      ins->obufp = stpcpy (ins->obufp, scc_suffix[ins->vex.scc]);
> +      *ins->obufp++ = suffix;
> +    }
> +  else
> +    /* Add scc suffix.  */
> +    ins->obufp = stpcpy (ins->obufp, scc_suffix[ins->vex.scc]);
> +
> +  /* Add { dfv=of, sf, zf, cf} flags.  */
> +  ins->obufp = stpcpy (ins->obufp, oszc_flags[oszc_value]);
> +
> +  /* For CCMP and CTEST, the ND bit is required to be set to 0.  */

Naming the two present insns in such a comment is liable to go stale in
case further SCC ones were introduced. Maybe better simply say "SCC insns"?

> +  if (ins->vex.nd)
> +    {
> +      oappend (ins, "(bad)");
> +      return true;
> +    }
> +
> +  /* These bits have been consumed and should be cleared.  */
> +  ins->vex.v = 1;

This isn't what I'd call "clearing".

> --- a/opcodes/i386-opc.h
> +++ b/opcodes/i386-opc.h
> @@ -757,6 +757,9 @@ enum
>    /* Support zero upper */
>    ZU,
>  
> +  /* Support zero upper */
> +  SCC,

Forgot to edit the comment after copy-and-paste?

> --- a/opcodes/i386-opc.tbl
> +++ b/opcodes/i386-opc.tbl
> @@ -341,9 +341,19 @@ cmp, 0x83/7, 0, Modrm|No_bSuf|No_sSuf, { Imm8S, Reg16|Reg32|Reg64|Unspecified|Ba
>  cmp, 0x3c, 0, W|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Acc|Byte|Word|Dword|Qword }
>  cmp, 0x80/7, 0, W|Modrm|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
>  
> +<cc:opc, o:0, no:1, b:2, c:2, nae:2, nb:3, nc:3, ae:3, e:4, z:4, ne:5, nz:5, be:6, na:6, nbe:7, a:7, +
> +         s:8, ns:9, t:a, p:a, pe:a, f:b, np:b, po:b, l:c, nge:c, nl:d, ge:d, le:e, ng:e, nle:f, g:f>
> +
> +ccmp<cc>, 0x380<cc:opc>, APX_F, D|W|CheckOperandSize|Modrm|EVexMap4|SCC|No_sSuf, { Reg8|Reg16|Reg32|Reg64, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> +ccmp<cc>, 0x830<cc:opc>/7, APX_F, Modrm|EVexMap4|SCC|No_bSuf|No_sSuf, { Imm8S, Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> +ccmp<cc>, 0x800<cc:opc>/7, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> +
>  test, 0x84, 0, D|W|C|CheckOperandSize|Modrm|No_sSuf, { Reg8|Reg16|Reg32|Reg64, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
>  test, 0xa8, 0, W|No_sSuf|Optimize, { Imm8|Imm16|Imm32|Imm32S, Acc|Byte|Word|Dword|Qword }
>  test, 0xf6/0, 0, W|Modrm|No_sSuf|Optimize, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> +ctest<cc>, 0x840<cc:opc>, APX_F, D|W|C|CheckOperandSize|Modrm|EVexMap4|SCC|No_sSuf, { Reg8|Reg16|Reg32|Reg64, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> +ctest<cc>, 0xf60<cc:opc>/0, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> +ctest<cc>, 0xf60<cc:opc>/1, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }

In the context of this patch (as a whole) - what meaning to we intend e.g.

	{evex} cmp %eax, %ecx

to have? Imo that should translate to CCMPT.

> @@ -505,9 +515,6 @@ enter, 0xc8, x64, ImplicitStackOp|DefaultSize|No_bSuf|No_lSuf|No_sSuf|NoRex64, {
>  leave, 0xc9, i186&No64, ImplicitStackOp|DefaultSize|No_bSuf|No_sSuf|No_qSuf, {}
>  leave, 0xc9, x64, ImplicitStackOp|DefaultSize|No_bSuf|No_lSuf|No_sSuf|NoRex64, {}
>  
> -<cc:opc, o:0, no:1, b:2, c:2, nae:2, nb:3, nc:3, ae:3, e:4, z:4, ne:5, nz:5, be:6, na:6, nbe:7, a:7, +
> -         s:8, ns:9, p:a, pe:a, np:b, po:b, l:c, nge:c, nl:d, ge:d, le:e, ng:e, nle:f, g:f>
> -

I don't think you can simply re-use this: p/pe and np/po don't exist in SCC
and need to be _replaced_ by t and f respectively. IOW you can neither
introduce e.g. invalid CCMPPE, nor can you suddenly introduce e.g. invalid
SETT. You'll want a new template named "scc".

Seeing that such a mistake was once made, please add "invalid" tests
demonstrating that e.g. SETT and CMPPE are properly diagnosed.

Jan
  
Cui, Lili May 29, 2024, 6:37 a.m. UTC | #2
> On 23.05.2024 08:12, Cui, Lili wrote:
> > With the new macro %NP (no prefix) introduced in this patch, we can
> remove %ME of movbe.
> 
> What are you describing here? I can't spot a respective change in the patch. If
> this is meant to say "we then could ...", please put such remarks outside of the
> commit message area.
> 
It's not part of the commit message, I will submit a separate patch for movbe and remove this message in the next version of the CCMP and CTEST patch.

> > CCMP and CTEST are two new sets of instructions for conditional CMP
> > and TEST, SCC and OSZC flags are given as suffixes of CCMP or CTEST in
> > the instruction mnemonic, e.g.:
> >
> > ccmp<cc> { dfv=sf , cf , of }
> >
> > 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
> > (like the legacy instructions), and restore it to i.tm.base_opcode in
> > install_template.
> 
> What do you mean by "restore it to i.tm.base_opcode"? I don't think this
> comes anywhere near what you're actually doing.
> 
> Just for the record: I also consider this syntax pretty odd, but I understand
> that's what "Assembly Syntax Recommendations" suggests. It would imo be
> quite a bit less convoluted if it simply was a separate pseudo-immediate
> operand (much like e.g. {sae} is in AT&T syntax).
> 
> > --- a/gas/config/tc-i386-intel.c
> > +++ b/gas/config/tc-i386-intel.c
> > @@ -619,6 +619,14 @@ i386_intel_operand (char *operand_string, int
> got_a_float)
> >    bool rc_sae_modifier = i.rounding.type != rc_none && i.rounding.modifier;
> >    int rc
> >
> > +  /* Handle SCC OSZC flgs.  */
> > +  if (current_templates.start->opcode_modifier.scc)
> > +    {
> > +      operand_string = check_Scc_OszcOperations (operand_string);
> > +      if (operand_string == NULL)
> > +	return 0;
> > +    }
> 
> This doesn't look right to me: We're parsing an operand here (at any position),
> yet the OSZC specifier is effectively a mnemonic pseudo- suffix (or else there
> would need to be a separating comma between it and the other operand). This
> is also shown in the doc, where this always follows the mnemonic, irrespective
> of AT&T vs Intel operand order.
> 

I previously thought that it is similar in function to SAE so I put it here, but if we emphasize that one is an operand and the other is a suffix, it is indeed more appropriate to put the latter at the end of parse_insn.

> > --- 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;
> > +
> > +    #define CF 0
> > +    #define ZF 1
> > +    #define SF 2
> > +    #define OF 3
> 
> These names are misleading - they suggest they somehow enumerate
> EFLAGS.CF etc. Perhaps OSZC_CF etc?
> 

They belong to oszc_flags, just after the definitions, I will move the comments before these definitions to avoid misunderstandings.

> Also #define-s starting in the first column, please (blanks between # and define
> are okay-ish, if so desired).
> 
Done.

> > +    /* Store 4 bits of EVEX.[OF,SF,ZF,CF].  */
> > +    unsigned int oszc_flags;
> > +
> >      /* Prefer load or store in encoding.  */
> >      enum
> >        {
> > @@ -3793,10 +3803,19 @@ install_template (const insn_template *t)
> >  	}
> >      }
> >
> > +  /* For the ccmp and ctest instructions we use base_opcode like the legacy
> > +     instructions and restore it in i.tm.base_opcode.  */  if
> > + (i.tm.opcode_modifier.scc)
> > +    {
> > +      /* Store scc in the lower 4 bits of base_opcode.  */
> > +      i.scc = i.tm.base_opcode & 0xf;
> > +      i.tm.base_opcode >>= 8;
> > +    }
> 
> As noted on the description already: You don't mean "restore" here, as there's
> no "save" counterpart anywhere. "like the legacy insns" isn't quite right either.
> Maybe
> 
>   /* 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.  */
> 
> ?

It is better, thanks.

> 
> > @@ -4290,6 +4309,16 @@ 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.scc)
> > +    {
> > +      i.vex.bytes[2] &= ~0x78;
> 
> Is there any way these 4 bits may be set before coming here? I hope there
> isn't, in which case an assertion (or know()) would seem more appropriate.
> 

They are the vvvv bits and the default value should be 1111. We need to clear them to 0000.

> > +      i.vex.bytes[2] |= (i.oszc_flags << 3);
> > +      i.vex.bytes[3] = (i.vex.bytes[3] & 0xf0) | i.scc;
> 
> Same question for these 4 bits, and ...
> 

They are V'aaa, V' defaults to 1 and needs to be cleared to 0, but we can add a check for aaa.

> > +      /* The ND bit is required to be set to 0.  */
> > +      i.vex.bytes[3] &= 0xef;
> 
> ... for ND.
> 
Together with aaa.

> > @@ -7539,13 +7568,14 @@ parse_operands (char *l, const char
> *mnemonic)
> >  		      i.operands + 1);
> >  	      return NULL;
> >  	    }
> > -	  if (!intel_syntax && !in_quotes)
> > +	  if (!in_quotes)
> >  	    {
> > -	      if (*l == '(')
> > +	      if (*l == '(' || *l == '{')
> >  		++paren_not_balanced;
> > -	      if (*l == ')')
> > +	      if (*l == ')' || *l == '}')
> >  		--paren_not_balanced;
> >  	    }
> 
> This isn't right either (closing } shouldn't match an opening parenthesis), but
> will go away anyway as you move the parsing from operand handling to
> mnemonic handling.
> 

Yes.

> > @@ -13578,6 +13608,93 @@ RC_SAE_specifier (const char *pstr)
> >    return NULL;
> >  }
> >
> > +/* Handle SCC OSZC flags.  */
> > +
> > +static char *
> > +check_Scc_OszcOperations (char *op_string) {
> > +  /* If {oszc flags} is absent, just return op_string.  */
> > +  if (*op_string != '{')
> > +    return op_string;
> > +  else
> 
> Please help limiting indentation by omitting such an "else".
> 

Done.

> > +    {
> > +      bool has_equal;
> > +      /* Parse '{dfv='.  */
> > +      while (*op_string)
> > +	{
> > +	  if (*op_string != '=')
> > +	    op_string++;
> > +	  else
> > +	    {
> > +	      has_equal = true;
> > +	      op_string++;
> > +	      break;
> > +	    }
> > +	}
> > +
> > +      if (!has_equal)
> > +	{
> > +	  /* If there is no '=', report bad.  */
> > +	  as_bad (_("Unrecognized oszc flags"));
> > +	  ignore_rest_of_line ();
> > +	}
> > +    }
> 
> Where does "dfv" actually get checked? You can't just look for '=' and hope the
> rest is fine.
> 
Changed it to check "dfv=".

> ignore_rest_of_line() also looks wrong to use here, as you're not consuming
> from input_line_pointer. Instead I think you want to return NULL there instead.
> 

Removed them.

> > +  /* Parse 'of , sf, sf, cf}'.  */
> 
> "sf" twice?
> 

Done.

> > +  while (*op_string)
> > +    {
> > +      if (*op_string == ',' || is_space_char (*op_string))
> > +	op_string++;
> > +      else if (*op_string == '}')
> > +	{
> > +	  op_string++;
> > +	  while (is_space_char (*op_string))
> > +	    op_string++;
> > +	  return op_string;
> > +	}
> > +      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 (op_string[1] != 'f')
> > +	    {
> > +	      as_bad (_("Unrecognized oszc flags"));
> > +	      ignore_rest_of_line ();
> > +	      return NULL;
> > +	    }
> > +	  switch (op_string[0])
> > +	    {
> > +	    case 'o':
> > +	      i.oszc_flags |= (1 << OF);
> > +	      break;
> > +	    case 's':
> > +	      i.oszc_flags |= (1 << SF);
> > +	      break;
> > +	    case 'z':
> > +	      i.oszc_flags |= (1 << ZF);
> > +	      break;
> > +	    case 'c':
> > +	    case 'p':
> 
> I don't think "pf" should be recognized here. As terminology says here and in
> the spec, it's OSZC (no P in there).

> > +	    case 'a':
> > +	      break;
> 
> "af" pretty certainly may not be recognized here, as that would imply
> EFLAGS.AF becoming set, not cleared.
>

I know what you mean, SCC cannot test PF.

• If SCC = 0b1010, then SCC evaluates to true regardless of the status flags value.
• If SCC = 0b1011, then SCC evaluates to false regardless of the status flags value.
Consequently, the SCC cannot test the parity flag PF.

But they are listed in another place, and we should assign PF to EVEX.CF and no update for AF.

• If SCC evaluates to false on the status flags, then the CMP or TEST is not executed and instead the
status flags are updated as follows:
– OF = EVEX.OF
– SF = EVEX.SF
– ZF = EVEX.ZF
– CF = EVEX.CF
– PF = EVEX.CF
– AF = 0

> 
> > +	      i.oszc_flags |= (1 << CF);
> > +	      break;
> 
> Shouldn't you further reject redundant settings, as in
> 
> 	ccmpe {dfv=cf,cf} ...
> 
> ?

How about keeping this compatibility? Like any other pseudo prefix.

> > +	    default:
> > +	      as_bad (_("Unrecognized oszc flags"));
> > +	      ignore_rest_of_line ();
> > +	      return NULL;
> > +	    }
> > +	  op_string += 2;
> > +	}
> > +    }
> > +  return op_string;
> > +}
> > +
> >  /* Handle Vector operations.  */
> >
> >  static char *
> > @@ -14486,6 +14603,14 @@ i386_att_operand (char *operand_string)
> >        i.jumpabsolute = true;
> >      }
> >
> > +  /* Handle SCC OSZC flgs.  */
> > +  if (current_templates.start->opcode_modifier.scc)
> > +    {
> > +      op_string = check_Scc_OszcOperations (op_string);
> > +      if (op_string == NULL)
> > +	return 0;
> > +    }
> 
> See remark on i386_intel_operand().
> 

I will respond to the decoder's comments in another email, thanks.

Lili.
  
Jan Beulich May 29, 2024, 6:51 a.m. UTC | #3
On 23.05.2024 08:12, Cui, Lili wrote:
> --- a/opcodes/i386-opc.h
> +++ b/opcodes/i386-opc.h
> @@ -757,6 +757,9 @@ enum
>    /* Support zero upper */
>    ZU,
>  
> +  /* Support zero upper */
> +  SCC,
> +
>    /* The last bitfield in i386_opcode_modifier.  */
>    Opcode_Modifier_Num
>  };

As for ZU the question again arises whether this (rarely used) property needs
to have its own attribute bit. I don't think it does, ...

> --- a/opcodes/i386-opc.tbl
> +++ b/opcodes/i386-opc.tbl
> @@ -341,9 +341,19 @@ cmp, 0x83/7, 0, Modrm|No_bSuf|No_sSuf, { Imm8S, Reg16|Reg32|Reg64|Unspecified|Ba
>  cmp, 0x3c, 0, W|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Acc|Byte|Word|Dword|Qword }
>  cmp, 0x80/7, 0, W|Modrm|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
>  
> +<cc:opc, o:0, no:1, b:2, c:2, nae:2, nb:3, nc:3, ae:3, e:4, z:4, ne:5, nz:5, be:6, na:6, nbe:7, a:7, +
> +         s:8, ns:9, t:a, p:a, pe:a, f:b, np:b, po:b, l:c, nge:c, nl:d, ge:d, le:e, ng:e, nle:f, g:f>
> +
> +ccmp<cc>, 0x380<cc:opc>, APX_F, D|W|CheckOperandSize|Modrm|EVexMap4|SCC|No_sSuf, { Reg8|Reg16|Reg32|Reg64, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> +ccmp<cc>, 0x830<cc:opc>/7, APX_F, Modrm|EVexMap4|SCC|No_bSuf|No_sSuf, { Imm8S, Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> +ccmp<cc>, 0x800<cc:opc>/7, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> +
>  test, 0x84, 0, D|W|C|CheckOperandSize|Modrm|No_sSuf, { Reg8|Reg16|Reg32|Reg64, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
>  test, 0xa8, 0, W|No_sSuf|Optimize, { Imm8|Imm16|Imm32|Imm32S, Acc|Byte|Word|Dword|Qword }
>  test, 0xf6/0, 0, W|Modrm|No_sSuf|Optimize, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> +ctest<cc>, 0x840<cc:opc>, APX_F, D|W|C|CheckOperandSize|Modrm|EVexMap4|SCC|No_sSuf, { Reg8|Reg16|Reg32|Reg64, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> +ctest<cc>, 0xf60<cc:opc>/0, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> +ctest<cc>, 0xf60<cc:opc>/1, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }

... as I see no other use of anything covered by OperandConstraint. And if
there were concerns with using OperandConstraint here, another option may
be to introduce EVEXSCC as another value for EVex.

And btw, I have a patch in the works undoing ZU needing a separate attribute
bit. That turned out pretty straightforward.

Jan
  
Jan Beulich May 29, 2024, 7:03 a.m. UTC | #4
On 29.05.2024 08:37, Cui, Lili wrote:
>> On 23.05.2024 08:12, Cui, Lili wrote:
>>> With the new macro %NP (no prefix) introduced in this patch, we can
>> remove %ME of movbe.
>>
>> What are you describing here? I can't spot a respective change in the patch. If
>> this is meant to say "we then could ...", please put such remarks outside of the
>> commit message area.
>>
> It's not part of the commit message, I will submit a separate patch for movbe and remove this message in the next version of the CCMP and CTEST patch.

For my own understanding: How would I as the reader have known it's not
part of the commit message?

>>> --- 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;
>>> +
>>> +    #define CF 0
>>> +    #define ZF 1
>>> +    #define SF 2
>>> +    #define OF 3
>>
>> These names are misleading - they suggest they somehow enumerate
>> EFLAGS.CF etc. Perhaps OSZC_CF etc?
>>
> 
> They belong to oszc_flags, just after the definitions, I will move the comments before these definitions to avoid misunderstandings.

With OSZC_ prefixes added I think the specific placement isn't going to
be as relevant anymore. Which isn't to say that I object to you moving
these closer to their corresponding field.

>>> @@ -4290,6 +4309,16 @@ 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.scc)
>>> +    {
>>> +      i.vex.bytes[2] &= ~0x78;
>>
>> Is there any way these 4 bits may be set before coming here? I hope there
>> isn't, in which case an assertion (or know()) would seem more appropriate.
>>
> 
> They are the vvvv bits and the default value should be 1111. We need to clear them to 0000.

Hmm, yes, clearing them is one way of dealing with this. In any event, please
add a comment here and ...

>>> +      i.vex.bytes[2] |= (i.oszc_flags << 3);
>>> +      i.vex.bytes[3] = (i.vex.bytes[3] & 0xf0) | i.scc;
>>
>> Same question for these 4 bits, and ...
> 
> They are V'aaa, V' defaults to 1 and needs to be cleared to 0, but we can add a check for aaa.

... here to help the reader follow the overlaying of bits (any why some would
need clearing).

>>> +    {
>>> +      bool has_equal;
>>> +      /* Parse '{dfv='.  */
>>> +      while (*op_string)
>>> +	{
>>> +	  if (*op_string != '=')
>>> +	    op_string++;
>>> +	  else
>>> +	    {
>>> +	      has_equal = true;
>>> +	      op_string++;
>>> +	      break;
>>> +	    }
>>> +	}
>>> +
>>> +      if (!has_equal)
>>> +	{
>>> +	  /* If there is no '=', report bad.  */
>>> +	  as_bad (_("Unrecognized oszc flags"));
>>> +	  ignore_rest_of_line ();
>>> +	}
>>> +    }
>>
>> Where does "dfv" actually get checked? You can't just look for '=' and hope the
>> rest is fine.
>>
> Changed it to check "dfv=".
> 
>> ignore_rest_of_line() also looks wrong to use here, as you're not consuming
>> from input_line_pointer. Instead I think you want to return NULL there instead.
>>
> 
> Removed them.
> 
>>> +  /* Parse 'of , sf, sf, cf}'.  */
>>
>> "sf" twice?
>>
> 
> Done.
> 
>>> +  while (*op_string)
>>> +    {
>>> +      if (*op_string == ',' || is_space_char (*op_string))
>>> +	op_string++;
>>> +      else if (*op_string == '}')
>>> +	{
>>> +	  op_string++;
>>> +	  while (is_space_char (*op_string))
>>> +	    op_string++;
>>> +	  return op_string;
>>> +	}
>>> +      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 (op_string[1] != 'f')
>>> +	    {
>>> +	      as_bad (_("Unrecognized oszc flags"));
>>> +	      ignore_rest_of_line ();
>>> +	      return NULL;
>>> +	    }
>>> +	  switch (op_string[0])
>>> +	    {
>>> +	    case 'o':
>>> +	      i.oszc_flags |= (1 << OF);
>>> +	      break;
>>> +	    case 's':
>>> +	      i.oszc_flags |= (1 << SF);
>>> +	      break;
>>> +	    case 'z':
>>> +	      i.oszc_flags |= (1 << ZF);
>>> +	      break;
>>> +	    case 'c':
>>> +	    case 'p':
>>
>> I don't think "pf" should be recognized here. As terminology says here and in
>> the spec, it's OSZC (no P in there).
> 
>>> +	    case 'a':
>>> +	      break;
>>
>> "af" pretty certainly may not be recognized here, as that would imply
>> EFLAGS.AF becoming set, not cleared.
>>
> 
> I know what you mean, SCC cannot test PF.
> 
> • If SCC = 0b1010, then SCC evaluates to true regardless of the status flags value.
> • If SCC = 0b1011, then SCC evaluates to false regardless of the status flags value.
> Consequently, the SCC cannot test the parity flag PF.

All of the code here is solely about OSZC; I don't see why you bring SCC
into the picture right here.

> But they are listed in another place, and we should assign PF to EVEX.CF and no update for AF.
> 
> • If SCC evaluates to false on the status flags, then the CMP or TEST is not executed and instead the
> status flags are updated as follows:
> – OF = EVEX.OF
> – SF = EVEX.SF
> – ZF = EVEX.ZF
> – CF = EVEX.CF
> – PF = EVEX.CF
> – AF = 0

Yes. But still even in what you write above it's EVEX.CF. There's no
EVEX.PF, and hence there also shouldn't be {dfv=pf}. (To be honest I
would have found it clearer if PF, like AF, was simply cleared. But
there are likely reasons for it not being that way. Sadly such
reasoning is never made publicly available ...)

>>
>>> +	      i.oszc_flags |= (1 << CF);
>>> +	      break;
>>
>> Shouldn't you further reject redundant settings, as in
>>
>> 	ccmpe {dfv=cf,cf} ...
>>
>> ?
> 
> How about keeping this compatibility? Like any other pseudo prefix.

Which "compatibility"? And why the reference to pseudo prefixes when
here we're dealing with something entirely new, a pseudo suffix?
Within a single {dfv=...} each flag should be mentioned at most once.
Anything else is a potential indication of a mistake the programmer
made. Separately from this we may consider whether to permit more
than one {dfv=...} for a single insn, with the latter than fully
replacing the former's effects. Personally I'd recommend against
that unless a clear use case could be provided, but I wouldn't object
to such being done right away.

Jan
  
Cui, Lili May 29, 2024, 7:07 a.m. UTC | #5
> On 23.05.2024 08:12, Cui, Lili wrote:
> > --- a/opcodes/i386-opc.h
> > +++ b/opcodes/i386-opc.h
> > @@ -757,6 +757,9 @@ enum
> >    /* Support zero upper */
> >    ZU,
> >
> > +  /* Support zero upper */
> > +  SCC,
> > +
> >    /* The last bitfield in i386_opcode_modifier.  */
> >    Opcode_Modifier_Num
> >  };
> 
> As for ZU the question again arises whether this (rarely used) property needs
> to have its own attribute bit. I don't think it does, ...
> 
> > --- a/opcodes/i386-opc.tbl
> > +++ b/opcodes/i386-opc.tbl
> > @@ -341,9 +341,19 @@ cmp, 0x83/7, 0, Modrm|No_bSuf|No_sSuf,
> { Imm8S,
> > Reg16|Reg32|Reg64|Unspecified|Ba  cmp, 0x3c, 0, W|No_sSuf, {
> > Imm8|Imm16|Imm32|Imm32S, Acc|Byte|Word|Dword|Qword }  cmp,
> 0x80/7, 0,
> > W|Modrm|No_sSuf, { Imm8|Imm16|Imm32|Imm32S,
> > Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> >
> > +<cc:opc, o:0, no:1, b:2, c:2, nae:2, nb:3, nc:3, ae:3, e:4, z:4, ne:5, nz:5,
> be:6, na:6, nbe:7, a:7, +
> > +         s:8, ns:9, t:a, p:a, pe:a, f:b, np:b, po:b, l:c, nge:c,
> > +nl:d, ge:d, le:e, ng:e, nle:f, g:f>
> > +
> > +ccmp<cc>, 0x380<cc:opc>, APX_F,
> > +D|W|CheckOperandSize|Modrm|EVexMap4|SCC|No_sSuf, {
> > +Reg8|Reg16|Reg32|Reg64,
> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
> > +} ccmp<cc>, 0x830<cc:opc>/7, APX_F,
> > +Modrm|EVexMap4|SCC|No_bSuf|No_sSuf, { Imm8S,
> > +Reg16|Reg32|Reg64|Unspecified|BaseIndex } ccmp<cc>,
> 0x800<cc:opc>/7,
> > +APX_F, W|Modrm|EVexMap4|SCC|No_sSuf,
> { Imm8|Imm16|Imm32|Imm32S,
> > +Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> > +
> >  test, 0x84, 0, D|W|C|CheckOperandSize|Modrm|No_sSuf, {
> > Reg8|Reg16|Reg32|Reg64,
> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> > test, 0xa8, 0, W|No_sSuf|Optimize, { Imm8|Imm16|Imm32|Imm32S,
> > Acc|Byte|Word|Dword|Qword }  test, 0xf6/0, 0,
> > W|Modrm|No_sSuf|Optimize, { Imm8|Imm16|Imm32|Imm32S,
> > Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> > +ctest<cc>, 0x840<cc:opc>, APX_F,
> > +D|W|C|CheckOperandSize|Modrm|EVexMap4|SCC|No_sSuf, {
> > +Reg8|Reg16|Reg32|Reg64,
> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
> > +} ctest<cc>, 0xf60<cc:opc>/0, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, {
> > +Imm8|Imm16|Imm32|Imm32S,
> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
> > +} ctest<cc>, 0xf60<cc:opc>/1, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, {
> > +Imm8|Imm16|Imm32|Imm32S,
> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
> > +}
> 
> ... as I see no other use of anything covered by OperandConstraint. And if there
> were concerns with using OperandConstraint here, another option may be to
> introduce EVEXSCC as another value for EVex.
> 
> And btw, I have a patch in the works undoing ZU needing a separate attribute
> bit. That turned out pretty straightforward.
> 
> Jan

I prefer to put it in OperandConstraint.

Lili.
  
Cui, Lili May 29, 2024, 8:44 a.m. UTC | #6
> On 29.05.2024 08:37, Cui, Lili wrote:
> >> On 23.05.2024 08:12, Cui, Lili wrote:
> >>> With the new macro %NP (no prefix) introduced in this patch, we can
> >> remove %ME of movbe.
> >>
> >> What are you describing here? I can't spot a respective change in the
> >> patch. If this is meant to say "we then could ...", please put such
> >> remarks outside of the commit message area.
> >>
> > It's not part of the commit message, I will submit a separate patch for
> movbe and remove this message in the next version of the CCMP and CTEST
> patch.
> 
> For my own understanding: How would I as the reader have known it's not
> part of the commit message?
> 

Next time I'll add some markers as separators.

> >>> --- 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;
> >>> +
> >>> +    #define CF 0
> >>> +    #define ZF 1
> >>> +    #define SF 2
> >>> +    #define OF 3
> >>
> >> These names are misleading - they suggest they somehow enumerate
> >> EFLAGS.CF etc. Perhaps OSZC_CF etc?
> >>
> >
> > They belong to oszc_flags, just after the definitions, I will move the
> comments before these definitions to avoid misunderstandings.
> 
> With OSZC_ prefixes added I think the specific placement isn't going to be as
> relevant anymore. Which isn't to say that I object to you moving these closer
> to their corresponding field.
> 
Ok.

> >>> @@ -4290,6 +4309,16 @@ 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.scc)
> >>> +    {
> >>> +      i.vex.bytes[2] &= ~0x78;
> >>
> >> Is there any way these 4 bits may be set before coming here? I hope
> >> there isn't, in which case an assertion (or know()) would seem more
> appropriate.
> >>
> >
> > They are the vvvv bits and the default value should be 1111. We need to
> clear them to 0000.
> 
> Hmm, yes, clearing them is one way of dealing with this. In any event, please
> add a comment here and ...
> 
> >>> +      i.vex.bytes[2] |= (i.oszc_flags << 3);
> >>> +      i.vex.bytes[3] = (i.vex.bytes[3] & 0xf0) | i.scc;
> >>
> >> Same question for these 4 bits, and ...
> >
> > They are V'aaa, V' defaults to 1 and needs to be cleared to 0, but we can add
> a check for aaa.
> 
> ... here to help the reader follow the overlaying of bits (any why some would
> need clearing).
> 
Ok.

> >>> +	  if (op_string[1] != 'f')
> >>> +	    {
> >>> +	      as_bad (_("Unrecognized oszc flags"));
> >>> +	      ignore_rest_of_line ();
> >>> +	      return NULL;
> >>> +	    }
> >>> +	  switch (op_string[0])
> >>> +	    {
> >>> +	    case 'o':
> >>> +	      i.oszc_flags |= (1 << OF);
> >>> +	      break;
> >>> +	    case 's':
> >>> +	      i.oszc_flags |= (1 << SF);
> >>> +	      break;
> >>> +	    case 'z':
> >>> +	      i.oszc_flags |= (1 << ZF);
> >>> +	      break;
> >>> +	    case 'c':
> >>> +	    case 'p':
> >>
> >> I don't think "pf" should be recognized here. As terminology says
> >> here and in the spec, it's OSZC (no P in there).
> >
> >>> +	    case 'a':
> >>> +	      break;
> >>
> >> "af" pretty certainly may not be recognized here, as that would imply
> >> EFLAGS.AF becoming set, not cleared.
> >>
> >
> > I know what you mean, SCC cannot test PF.
> >
> > • If SCC = 0b1010, then SCC evaluates to true regardless of the status flags
> value.
> > • If SCC = 0b1011, then SCC evaluates to false regardless of the status flags
> value.
> > Consequently, the SCC cannot test the parity flag PF.
> 
> All of the code here is solely about OSZC; I don't see why you bring SCC into
> the picture right here.
> 
> > But they are listed in another place, and we should assign PF to EVEX.CF and
> no update for AF.
> >
> > • If SCC evaluates to false on the status flags, then the CMP or TEST
> > is not executed and instead the status flags are updated as follows:
> > – OF = EVEX.OF
> > – SF = EVEX.SF
> > – ZF = EVEX.ZF
> > – CF = EVEX.CF
> > – PF = EVEX.CF
> > – AF = 0
> 
> Yes. But still even in what you write above it's EVEX.CF. There's no EVEX.PF, and
> hence there also shouldn't be {dfv=pf}. (To be honest I would have found it
> clearer if PF, like AF, was simply cleared. But there are likely reasons for it not
> being that way. Sadly such reasoning is never made publicly available ...)
> 

You are right, I should remove PF and AF here. I think it wants to give users a chance to set PF.

> >>
> >>> +	      i.oszc_flags |= (1 << CF);
> >>> +	      break;
> >>
> >> Shouldn't you further reject redundant settings, as in
> >>
> >> 	ccmpe {dfv=cf,cf} ...
> >>
> >> ?
> >
> > How about keeping this compatibility? Like any other pseudo prefix.
> 
> Which "compatibility"? And why the reference to pseudo prefixes when here
> we're dealing with something entirely new, a pseudo suffix?
> Within a single {dfv=...} each flag should be mentioned at most once.
> Anything else is a potential indication of a mistake the programmer made.
> Separately from this we may consider whether to permit more than one
> {dfv=...} for a single insn, with the latter than fully replacing the former's
> effects. Personally I'd recommend against that unless a clear use case could be
> provided, but I wouldn't object to such being done right away.
> 

It's a suffix, but I think we can tolerate multiple repetitions of a flag by just overwriting the previous one with the next one. Like the pseudo-prefix {vex} {vex} . If you insist on giving {dfv=cf,cf}  an error, I'd just put a check before the assignment.

Thanks,
Lili.
  
Jan Beulich May 29, 2024, 9:57 a.m. UTC | #7
On 29.05.2024 10:44, Cui, Lili wrote:
>> On 29.05.2024 08:37, Cui, Lili wrote:
>>>> On 23.05.2024 08:12, Cui, Lili wrote:
>>>>> +	  if (op_string[1] != 'f')
>>>>> +	    {
>>>>> +	      as_bad (_("Unrecognized oszc flags"));
>>>>> +	      ignore_rest_of_line ();
>>>>> +	      return NULL;
>>>>> +	    }
>>>>> +	  switch (op_string[0])
>>>>> +	    {
>>>>> +	    case 'o':
>>>>> +	      i.oszc_flags |= (1 << OF);
>>>>> +	      break;
>>>>> +	    case 's':
>>>>> +	      i.oszc_flags |= (1 << SF);
>>>>> +	      break;
>>>>> +	    case 'z':
>>>>> +	      i.oszc_flags |= (1 << ZF);
>>>>> +	      break;
>>>>> +	    case 'c':
>>>>> +	    case 'p':
>>>>
>>>> I don't think "pf" should be recognized here. As terminology says
>>>> here and in the spec, it's OSZC (no P in there).
>>>
>>>>> +	    case 'a':
>>>>> +	      break;
>>>>
>>>> "af" pretty certainly may not be recognized here, as that would imply
>>>> EFLAGS.AF becoming set, not cleared.
>>>>
>>>
>>> I know what you mean, SCC cannot test PF.
>>>
>>> • If SCC = 0b1010, then SCC evaluates to true regardless of the status flags
>> value.
>>> • If SCC = 0b1011, then SCC evaluates to false regardless of the status flags
>> value.
>>> Consequently, the SCC cannot test the parity flag PF.
>>
>> All of the code here is solely about OSZC; I don't see why you bring SCC into
>> the picture right here.
>>
>>> But they are listed in another place, and we should assign PF to EVEX.CF and
>> no update for AF.
>>>
>>> • If SCC evaluates to false on the status flags, then the CMP or TEST
>>> is not executed and instead the status flags are updated as follows:
>>> – OF = EVEX.OF
>>> – SF = EVEX.SF
>>> – ZF = EVEX.ZF
>>> – CF = EVEX.CF
>>> – PF = EVEX.CF
>>> – AF = 0
>>
>> Yes. But still even in what you write above it's EVEX.CF. There's no EVEX.PF, and
>> hence there also shouldn't be {dfv=pf}. (To be honest I would have found it
>> clearer if PF, like AF, was simply cleared. But there are likely reasons for it not
>> being that way. Sadly such reasoning is never made publicly available ...)
>>
> 
> You are right, I should remove PF and AF here. I think it wants to give users a chance to set PF.
> 
>>>>
>>>>> +	      i.oszc_flags |= (1 << CF);
>>>>> +	      break;
>>>>
>>>> Shouldn't you further reject redundant settings, as in
>>>>
>>>> 	ccmpe {dfv=cf,cf} ...
>>>>
>>>> ?
>>>
>>> How about keeping this compatibility? Like any other pseudo prefix.
>>
>> Which "compatibility"? And why the reference to pseudo prefixes when here
>> we're dealing with something entirely new, a pseudo suffix?
>> Within a single {dfv=...} each flag should be mentioned at most once.
>> Anything else is a potential indication of a mistake the programmer made.
>> Separately from this we may consider whether to permit more than one
>> {dfv=...} for a single insn, with the latter than fully replacing the former's
>> effects. Personally I'd recommend against that unless a clear use case could be
>> provided, but I wouldn't object to such being done right away.
>>
> 
> It's a suffix, but I think we can tolerate multiple repetitions of a flag by just overwriting the previous one with the next one. Like the pseudo-prefix {vex} {vex} . If you insist on giving {dfv=cf,cf}  an error, I'd just put a check before the assignment.

Well, if you think it may be useful, make it just a warning? Part of my desire
to see this diagnosed is related to your use of "overwriting" in the reply:
There's no real overwriting; things can only be cumulative here, as there's no
way to specify the clearing of one of the flags. Any flags to be cleared are
indicated as such by simply not mentioning them at all.

Jan
  
Cui, Lili May 29, 2024, 11:05 a.m. UTC | #8
> >>>>> +	      i.oszc_flags |= (1 << CF);
> >>>>> +	      break;
> >>>>
> >>>> Shouldn't you further reject redundant settings, as in
> >>>>
> >>>> 	ccmpe {dfv=cf,cf} ...
> >>>>
> >>>> ?
> >>>
> >>> How about keeping this compatibility? Like any other pseudo prefix.
> >>
> >> Which "compatibility"? And why the reference to pseudo prefixes when
> >> here we're dealing with something entirely new, a pseudo suffix?
> >> Within a single {dfv=...} each flag should be mentioned at most once.
> >> Anything else is a potential indication of a mistake the programmer made.
> >> Separately from this we may consider whether to permit more than one
> >> {dfv=...} for a single insn, with the latter than fully replacing the
> >> former's effects. Personally I'd recommend against that unless a
> >> clear use case could be provided, but I wouldn't object to such being done
> right away.
> >>
> >
> > It's a suffix, but I think we can tolerate multiple repetitions of a flag by just
> overwriting the previous one with the next one. Like the pseudo-prefix {vex}
> {vex} . If you insist on giving {dfv=cf,cf}  an error, I'd just put a check before the
> assignment.
> 
> Well, if you think it may be useful, make it just a warning? Part of my desire to
> see this diagnosed is related to your use of "overwriting" in the reply:
> There's no real overwriting; things can only be cumulative here, as there's no
> way to specify the clearing of one of the flags. Any flags to be cleared are
> indicated as such by simply not mentioning them at all.
> 

Yes, "overright" is not the right word. How about this?

+static INLINE void set_oszc_flags (unsigned int oszc_shift)
+{
+  if (i.oszc_flags && (1 << oszc_shift))
+    as_bad (_("same oszc flag used twice"));
+  i.oszc_flags |= 1 << oszc_shift;
+}
+
 /* Handle SCC OSZC flags.  */

 static int
@@ -1999,16 +2006,16 @@ check_Scc_OszcOperations (const char *l)
           switch (suffix_string[0])
             {
             case 'o':
-              i.oszc_flags |= (1 << OF);
+             set_oszc_flags (OF);
               break;
             case 's':
-              i.oszc_flags |= (1 << SF);
+             set_oszc_flags (SF);
               break;
             case 'z':
-              i.oszc_flags |= (1 << ZF);
+             set_oszc_flags (ZF);
               break;
             case 'c':
-              i.oszc_flags |= (1 << CF);
+             set_oszc_flags (CF);
               break;
             default:

Thanks,
Lili.
  
Jan Beulich May 29, 2024, 12:25 p.m. UTC | #9
On 29.05.2024 13:05, Cui, Lili wrote:
>>>>>>> +	      i.oszc_flags |= (1 << CF);
>>>>>>> +	      break;
>>>>>>
>>>>>> Shouldn't you further reject redundant settings, as in
>>>>>>
>>>>>> 	ccmpe {dfv=cf,cf} ...
>>>>>>
>>>>>> ?
>>>>>
>>>>> How about keeping this compatibility? Like any other pseudo prefix.
>>>>
>>>> Which "compatibility"? And why the reference to pseudo prefixes when
>>>> here we're dealing with something entirely new, a pseudo suffix?
>>>> Within a single {dfv=...} each flag should be mentioned at most once.
>>>> Anything else is a potential indication of a mistake the programmer made.
>>>> Separately from this we may consider whether to permit more than one
>>>> {dfv=...} for a single insn, with the latter than fully replacing the
>>>> former's effects. Personally I'd recommend against that unless a
>>>> clear use case could be provided, but I wouldn't object to such being done
>> right away.
>>>>
>>>
>>> It's a suffix, but I think we can tolerate multiple repetitions of a flag by just
>> overwriting the previous one with the next one. Like the pseudo-prefix {vex}
>> {vex} . If you insist on giving {dfv=cf,cf}  an error, I'd just put a check before the
>> assignment.
>>
>> Well, if you think it may be useful, make it just a warning? Part of my desire to
>> see this diagnosed is related to your use of "overwriting" in the reply:
>> There's no real overwriting; things can only be cumulative here, as there's no
>> way to specify the clearing of one of the flags. Any flags to be cleared are
>> indicated as such by simply not mentioning them at all.
>>
> 
> Yes, "overright" is not the right word. How about this?
> 
> +static INLINE void set_oszc_flags (unsigned int oszc_shift)
> +{
> +  if (i.oszc_flags && (1 << oszc_shift))

With && replaced by & here ...

> +    as_bad (_("same oszc flag used twice"));
> +  i.oszc_flags |= 1 << oszc_shift;
> +}
> +
>  /* Handle SCC OSZC flags.  */
> 
>  static int
> @@ -1999,16 +2006,16 @@ check_Scc_OszcOperations (const char *l)
>            switch (suffix_string[0])
>              {
>              case 'o':
> -              i.oszc_flags |= (1 << OF);
> +             set_oszc_flags (OF);
>                break;
>              case 's':
> -              i.oszc_flags |= (1 << SF);
> +             set_oszc_flags (SF);
>                break;
>              case 'z':
> -              i.oszc_flags |= (1 << ZF);
> +             set_oszc_flags (ZF);
>                break;
>              case 'c':
> -              i.oszc_flags |= (1 << CF);
> +             set_oszc_flags (CF);
>                break;
>              default:

... this looks okay to me (still pending the rename of the constant names,
though).

Jan
  
Cui, Lili May 30, 2024, 2:44 a.m. UTC | #10
> On 29.05.2024 13:05, Cui, Lili wrote:
> >>>>>>> +	      i.oszc_flags |= (1 << CF);
> >>>>>>> +	      break;
> >>>>>>
> >>>>>> Shouldn't you further reject redundant settings, as in
> >>>>>>
> >>>>>> 	ccmpe {dfv=cf,cf} ...
> >>>>>>
> >>>>>> ?
> >>>>>
> >>>>> How about keeping this compatibility? Like any other pseudo prefix.
> >>>>
> >>>> Which "compatibility"? And why the reference to pseudo prefixes
> >>>> when here we're dealing with something entirely new, a pseudo suffix?
> >>>> Within a single {dfv=...} each flag should be mentioned at most once.
> >>>> Anything else is a potential indication of a mistake the programmer made.
> >>>> Separately from this we may consider whether to permit more than
> >>>> one {dfv=...} for a single insn, with the latter than fully
> >>>> replacing the former's effects. Personally I'd recommend against
> >>>> that unless a clear use case could be provided, but I wouldn't
> >>>> object to such being done
> >> right away.
> >>>>
> >>>
> >>> It's a suffix, but I think we can tolerate multiple repetitions of a
> >>> flag by just
> >> overwriting the previous one with the next one. Like the
> >> pseudo-prefix {vex} {vex} . If you insist on giving {dfv=cf,cf}  an
> >> error, I'd just put a check before the assignment.
> >>
> >> Well, if you think it may be useful, make it just a warning? Part of
> >> my desire to see this diagnosed is related to your use of "overwriting" in the
> reply:
> >> There's no real overwriting; things can only be cumulative here, as
> >> there's no way to specify the clearing of one of the flags. Any flags
> >> to be cleared are indicated as such by simply not mentioning them at all.
> >>
> >
> > Yes, "overright" is not the right word. How about this?
> >
> > +static INLINE void set_oszc_flags (unsigned int oszc_shift) {
> > +  if (i.oszc_flags && (1 << oszc_shift))
> 
> With && replaced by & here ...
> 

Sorry, I pasted a wrong version here.

> > +    as_bad (_("same oszc flag used twice"));
> > +  i.oszc_flags |= 1 << oszc_shift;
> > +}
> > +
> >  /* Handle SCC OSZC flags.  */
> >
> >  static int
> > @@ -1999,16 +2006,16 @@ check_Scc_OszcOperations (const char *l)
> >            switch (suffix_string[0])
> >              {
> >              case 'o':
> > -              i.oszc_flags |= (1 << OF);
> > +             set_oszc_flags (OF);
> >                break;
> >              case 's':
> > -              i.oszc_flags |= (1 << SF);
> > +             set_oszc_flags (SF);
> >                break;
> >              case 'z':
> > -              i.oszc_flags |= (1 << ZF);
> > +             set_oszc_flags (ZF);
> >                break;
> >              case 'c':
> > -              i.oszc_flags |= (1 << CF);
> > +             set_oszc_flags (CF);
> >                break;
> >              default:
> 
> ... this looks okay to me (still pending the rename of the constant names,
> though).

I think you mean const char *l (suffix_string), I moved this function to parse_insn, and it needs to return a value for length (suffix_string - l).  More details will be provided in the next version. 

Thanks,
Lili.
  
Jan Beulich May 30, 2024, 6:31 a.m. UTC | #11
On 30.05.2024 04:44, Cui, Lili wrote:
>> On 29.05.2024 13:05, Cui, Lili wrote:
>>>>>>>>> +	      i.oszc_flags |= (1 << CF);
>>>>>>>>> +	      break;
>>>>>>>>
>>>>>>>> Shouldn't you further reject redundant settings, as in
>>>>>>>>
>>>>>>>> 	ccmpe {dfv=cf,cf} ...
>>>>>>>>
>>>>>>>> ?
>>>>>>>
>>>>>>> How about keeping this compatibility? Like any other pseudo prefix.
>>>>>>
>>>>>> Which "compatibility"? And why the reference to pseudo prefixes
>>>>>> when here we're dealing with something entirely new, a pseudo suffix?
>>>>>> Within a single {dfv=...} each flag should be mentioned at most once.
>>>>>> Anything else is a potential indication of a mistake the programmer made.
>>>>>> Separately from this we may consider whether to permit more than
>>>>>> one {dfv=...} for a single insn, with the latter than fully
>>>>>> replacing the former's effects. Personally I'd recommend against
>>>>>> that unless a clear use case could be provided, but I wouldn't
>>>>>> object to such being done
>>>> right away.
>>>>>>
>>>>>
>>>>> It's a suffix, but I think we can tolerate multiple repetitions of a
>>>>> flag by just
>>>> overwriting the previous one with the next one. Like the
>>>> pseudo-prefix {vex} {vex} . If you insist on giving {dfv=cf,cf}  an
>>>> error, I'd just put a check before the assignment.
>>>>
>>>> Well, if you think it may be useful, make it just a warning? Part of
>>>> my desire to see this diagnosed is related to your use of "overwriting" in the
>> reply:
>>>> There's no real overwriting; things can only be cumulative here, as
>>>> there's no way to specify the clearing of one of the flags. Any flags
>>>> to be cleared are indicated as such by simply not mentioning them at all.
>>>>
>>>
>>> Yes, "overright" is not the right word. How about this?
>>>
>>> +static INLINE void set_oszc_flags (unsigned int oszc_shift) {
>>> +  if (i.oszc_flags && (1 << oszc_shift))
>>
>> With && replaced by & here ...
>>
> 
> Sorry, I pasted a wrong version here.
> 
>>> +    as_bad (_("same oszc flag used twice"));
>>> +  i.oszc_flags |= 1 << oszc_shift;
>>> +}
>>> +
>>>  /* Handle SCC OSZC flags.  */
>>>
>>>  static int
>>> @@ -1999,16 +2006,16 @@ check_Scc_OszcOperations (const char *l)
>>>            switch (suffix_string[0])
>>>              {
>>>              case 'o':
>>> -              i.oszc_flags |= (1 << OF);
>>> +             set_oszc_flags (OF);
>>>                break;
>>>              case 's':
>>> -              i.oszc_flags |= (1 << SF);
>>> +             set_oszc_flags (SF);
>>>                break;
>>>              case 'z':
>>> -              i.oszc_flags |= (1 << ZF);
>>> +             set_oszc_flags (ZF);
>>>                break;
>>>              case 'c':
>>> -              i.oszc_flags |= (1 << CF);
>>> +             set_oszc_flags (CF);
>>>                break;
>>>              default:
>>
>> ... this looks okay to me (still pending the rename of the constant names,
>> though).
> 
> I think you mean const char *l (suffix_string),

No, I mean the CF, ZF, etc constants.

Jan

> I moved this function to parse_insn, and it needs to return a value for length (suffix_string - l).  More details will be provided in the next version. 
> 
> Thanks,
> Lili.
>
  
Cui, Lili May 30, 2024, 6:58 a.m. UTC | #12
> >>> +    as_bad (_("same oszc flag used twice"));
> >>> +  i.oszc_flags |= 1 << oszc_shift;
> >>> +}
> >>> +
> >>>  /* Handle SCC OSZC flags.  */
> >>>
> >>>  static int
> >>> @@ -1999,16 +2006,16 @@ check_Scc_OszcOperations (const char *l)
> >>>            switch (suffix_string[0])
> >>>              {
> >>>              case 'o':
> >>> -              i.oszc_flags |= (1 << OF);
> >>> +             set_oszc_flags (OF);
> >>>                break;
> >>>              case 's':
> >>> -              i.oszc_flags |= (1 << SF);
> >>> +             set_oszc_flags (SF);
> >>>                break;
> >>>              case 'z':
> >>> -              i.oszc_flags |= (1 << ZF);
> >>> +             set_oszc_flags (ZF);
> >>>                break;
> >>>              case 'c':
> >>> -              i.oszc_flags |= (1 << CF);
> >>> +             set_oszc_flags (CF);
> >>>                break;
> >>>              default:
> >>
> >> ... this looks okay to me (still pending the rename of the constant
> >> names, though).
> >
> > I think you mean const char *l (suffix_string),
> 
> No, I mean the CF, ZF, etc constants.

Do you have any suggestions for new names? Or just use the immediate value.
 
    /* Store 4 bits of EVEX.[OF,SF,ZF,CF].  */
#define CF 0
#define ZF 1
#define SF 2
#define OF 3
    unsigned int oszc_flags;

Thanks,
Lili.
  
Jan Beulich May 30, 2024, 3:17 p.m. UTC | #13
On 30.05.2024 08:58, Cui, Lili wrote:
>>>>> +    as_bad (_("same oszc flag used twice"));
>>>>> +  i.oszc_flags |= 1 << oszc_shift;
>>>>> +}
>>>>> +
>>>>>  /* Handle SCC OSZC flags.  */
>>>>>
>>>>>  static int
>>>>> @@ -1999,16 +2006,16 @@ check_Scc_OszcOperations (const char *l)
>>>>>            switch (suffix_string[0])
>>>>>              {
>>>>>              case 'o':
>>>>> -              i.oszc_flags |= (1 << OF);
>>>>> +             set_oszc_flags (OF);
>>>>>                break;
>>>>>              case 's':
>>>>> -              i.oszc_flags |= (1 << SF);
>>>>> +             set_oszc_flags (SF);
>>>>>                break;
>>>>>              case 'z':
>>>>> -              i.oszc_flags |= (1 << ZF);
>>>>> +             set_oszc_flags (ZF);
>>>>>                break;
>>>>>              case 'c':
>>>>> -              i.oszc_flags |= (1 << CF);
>>>>> +             set_oszc_flags (CF);
>>>>>                break;
>>>>>              default:
>>>>
>>>> ... this looks okay to me (still pending the rename of the constant
>>>> names, though).
>>>
>>> I think you mean const char *l (suffix_string),
>>
>> No, I mean the CF, ZF, etc constants.
> 
> Do you have any suggestions for new names?

I already suggested to name them OSZC_CF etc.

Jan
  
Cui, Lili May 31, 2024, 6:40 a.m. UTC | #14
> > --- /dev/null
> > +++ b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-intel.d
> > @@ -0,0 +1,220 @@
> > +#as:
> > +#objdump: -dw -Mintel
> > +#name: x86_64 APX_F CCMP and CTEST insns (Intel disassembly)
> > +#source: x86-64-apx-ccmp-ctest.s
> > +
> > +.*: +file format .*
> > +
> > +Disassembly of section \.text:
> > +
> > +0+ <_start>:
> > +\s*[a-f0-9]+:\s*62 d4 8c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb
> \{dfv=cf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
> 
> In order to spot possible issues, it helps is test expectations are readable.
> \s is imo hampering readability, as in not being a visual separator. However,
> what I strongly object to is a _mix_ of \s and [ 	].
> 

[space+tab] is certainly more intuitive, but it takes up too much screen space, especially for long assembler and disassembler instructions, so I prefer to use \s. I remember you asked in a previous comment to replace the last \s with [], so I replaced the last \s before I sent out the patch, resulting in the current hybrid state. Do you mind if I change the last [] to \s? Keep one style.

> > --- /dev/null
> > +++ b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest.s
> > @@ -0,0 +1,217 @@
> > +# Check 64bit APX_F CCMP and CTEST instructions
> > +	ccmpbl {dfv=} $0x7b,0x123(%r8,%rax,4)
> > +	ccmpb  {dfv=} 0x123(%r8,%rax,4),%r15d
> > +	ccmpb  {dfv=af} 0x123(%r8,%rax,4),%r15d
> > +	ccmpo   {dfv=of} $0x7b,%r16
> 
> Why the discontinuity in padding? (As indicated elsewhere, imo the OSZC
> specifier better wouldn't be in the operand area anyway, for not being an
> operand in the way it is specified/handled right now.)
> 
Done.

> > +	ctestb  {dfv=zf} %r15,%r15
> > +	ctestbq {dfv=} $0x7b,0x123(%r8,%rax,4)
> > +	ctestb  {dfv=} %r15w,%ax
> > +	ctestb  {dfv=af} %r15w,%ax
> > +	ctesto   {dfv=of} $0x7b,%r16
> 
> Yet another such disconinuity.
> 
Done.

> > --- a/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.s
> > +++ b/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.s
> > @@ -43,7 +43,7 @@ _start:
> >
> >  	# pop2 %rax, %r8 set EVEX.ND=0.
> >  	.byte 0x62, 0xf4, 0x3c, 0x08, 0x8f, 0xc0
> > -	.byte 0xff, 0xff, 0xff
> > +	.byte 0xff, 0xff
> 
> What's the reason for this and ...
> 

Because I moved the invalid check out of get_valid_dis386 (wait for CCMP and CCTEST).

> > @@ -56,3 +56,7 @@ _start:
> >
> >  	# EVEX_MAP4 movbe %r18w,%ax set EVEX.P[10] = 0.
> >  	.byte 0x62, 0xfc, 0x79, 0x08, 0x60, 0xc2
> > +	.byte 0xff, 0xff
> 
> ... this adjustment? Preferably the existing by sequences would be adjusted
> such that such extra 0xff won't be needed.

Done.

> 
> > +	# ccmps {dfv=of,sf,zf,cf} %r15, %rdx set EVEX.ND=0.
> > +	.insn EVEX.L0.M4.W1 0x38, %r15, {rn-sae},%rdx
> 
> What's wrong about ND=0? IOW what is it that you're trying to check here?
> 

It should be ND = 1.

> > --- a/opcodes/i386-dis.c
> > +++ b/opcodes/i386-dis.c
> > @@ -596,6 +598,7 @@ fetch_error (const instr_info *ins)  #define
> > PCLMUL { PCLMUL_Fixup, 0 }  #define VPCMP { VPCMP_Fixup, 0 }  #define
> > VPCOM { VPCOM_Fixup, 0 }
> > +#define SCC_And_OSZC_Flags { SCC_And_OSZC_Flags_Fixup, 0 }
> 
> Can you perhaps drop "_Flags" from these names? That won't create
> ambiguity yet help readability by shortening things.
> 

Ok.

> > @@ -1832,6 +1835,8 @@ struct dis386 {
> >  	   instruction.
> >     "NF" => print "{nf} " pseudo prefix when EVEX.NF = 1 and print "{evex} "
> >  	   pseudo prefix when instructions without NF, EGPR and VVVV,
> > +   "NP" => don't print "{evex} " pseudo prefix for some special instructions
> > +	   in MAP4.
> 
> "NP" pretty clearly means "no prefix". What you mean is "no {evex}", so
> perhaps better %NE (albeit that may end up ambiguous down the road, yet
> what do you do)?
> 
Yes, %NE is better. 

> > @@ -9181,22 +9187,8 @@ get_valid_dis386 (const struct dis386 *dp,
> instr_info *ins)
> > +  /* The purpose of placing the check here is to wait for the EVEX prefix for
> > +     conditional CMP and TEST to be consumed and cleared, and then make a
> > +     unified judgment. Because they are both in map4, we can not distinguish
> > +     EVEX prefix for conditional CMP and TEST from others during the
> > +     EVEX prefix stage of parsing.  */
> > +  /* 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.nd
> > +      && (ins.vex.register_specifier || !ins.vex.v))
> > +    {
> > +      i386_dis_printf (info, dis_style_text, "(bad)");
> > +      ret = ins.end_codep - priv.the_buffer;
> > +      goto out;
> > +    }
> > +
> > +  /* EVEX from legacy instructions require that EVEX.z, EVEX.L’L and the
> > +     lower 2 bits of EVEX.aaa must be 0.  */
> > +  if (ins.evex_type == evex_from_legacy
> > +      && ((ins.vex.mask_register_specifier & 0x3) != 0
> > +	  || ins.vex.ll != 0 || ins.vex.zeroing != 0))
> > +    {
> > +      i386_dis_printf (info, dis_style_text, "(bad)");
> > +      ret = ins.end_codep - priv.the_buffer;
> > +      goto out;
> > +    }
> 
> With them now properly back-to-back, they want folding. That way the initial
> (new) comment would also suitably cover both:
> 
>   /* The purpose of placing the check here is to wait for the EVEX prefix for
>      conditional CMP and TEST to be consumed and cleared, and then make a
>      unified judgment. Because they are both in map4, we can not distinguish
>      EVEX prefix for conditional CMP and TEST from others during the
>      EVEX prefix stage of parsing.  */
>   if (ins.evex_type == evex_from_legacy)
>     {
>       ...
> 

Ok.

> > @@ -14089,3 +14110,55 @@ JMPABS_Fixup (instr_info *ins, int bytemode,
> int sizeflag)
> >      return OP_IMREG (ins, bytemode, sizeflag);
> >    return OP_OFF64 (ins, bytemode, sizeflag);  }
> > +
> > +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}"
> > +};
> > +
> > +static const char *const scc_suffix[16] = {
> > +  "o", "no", "b", "nb", "z", "nz", "be", "nbe", "s", "ns", "t", "f",
> > +  "l", "nl", "le", "nle"
> > +};
> 
> Can these please be in sync with the forms we use for e.g. Jcc and SETcc?
> I actually have a patch pending harmonizing these for CMPccXADD as well.
> 

I'm ok to change it like Jcc, but there are still 2 bits that are different from JCC.

"SCC values 0b1010 and 0b1011 (which are P and NP in normal condition codes) should be written as T
and F because they now mean True and False."  -- apx-asm-syntax

static const char *const scc_suffix[16] = {
  "o", "no", "b", "ae", "e", "ne", "be", "a", "s", "ns", "t", "f",
  "l", "ge", "le", "g"
};

> > +static bool
> > +SCC_And_OSZC_Flags_Fixup (instr_info *ins, int bytemode
> ATTRIBUTE_UNUSED,
> > +		 int sizeflag ATTRIBUTE_UNUSED)
> > +{
> > +  ins->obufp = ins->mnemonicendp;
> > +
> > +  /* Get oszc flags value from register_specifier.  */  int
> > + oszc_value = ~ins->vex.register_specifier & 0xf;
> > +
> > +  /* If ccmp and ctest already have suffixes, they should be moved after the
> > +     scc suffix.  */
> > +  if (ins->obufp[-1] != 'p' && ins->obufp[-1] != 't')
> > +    {
> > +      char suffix = ins->obufp[-1];
> > +      ins->obufp--;
> > +      ins->obufp = stpcpy (ins->obufp, scc_suffix[ins->vex.scc]);
> > +      *ins->obufp++ = suffix;
> > +    }
> > +  else
> > +    /* Add scc suffix.  */
> > +    ins->obufp = stpcpy (ins->obufp, scc_suffix[ins->vex.scc]);
> > +
> > +  /* Add { dfv=of, sf, zf, cf} flags.  */  ins->obufp = stpcpy
> > + (ins->obufp, oszc_flags[oszc_value]);
> > +
> > +  /* For CCMP and CTEST, the ND bit is required to be set to 0.  */
> 
> Naming the two present insns in such a comment is liable to go stale in case
> further SCC ones were introduced. Maybe better simply say "SCC insns"?
> 

Done.

> > +  if (ins->vex.nd)
> > +    {
> > +      oappend (ins, "(bad)");
> > +      return true;
> > +    }
> > +
> > +  /* These bits have been consumed and should be cleared.  */
> > + ins->vex.v = 1;
> 
> This isn't what I'd call "clearing".
> 

Ok, adjusted the comment.

> > --- a/opcodes/i386-opc.h
> > +++ b/opcodes/i386-opc.h
> > @@ -757,6 +757,9 @@ enum
> >    /* Support zero upper */
> >    ZU,
> >
> > +  /* Support zero upper */
> > +  SCC,
> 
> Forgot to edit the comment after copy-and-paste?
> 

Done.

> > --- a/opcodes/i386-opc.tbl
> > +++ b/opcodes/i386-opc.tbl
> > @@ -341,9 +341,19 @@ cmp, 0x83/7, 0, Modrm|No_bSuf|No_sSuf,
> { Imm8S,
> > Reg16|Reg32|Reg64|Unspecified|Ba  cmp, 0x3c, 0, W|No_sSuf, {
> > Imm8|Imm16|Imm32|Imm32S, Acc|Byte|Word|Dword|Qword }  cmp,
> 0x80/7, 0,
> > W|Modrm|No_sSuf, { Imm8|Imm16|Imm32|Imm32S,
> > Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> >
> > +<cc:opc, o:0, no:1, b:2, c:2, nae:2, nb:3, nc:3, ae:3, e:4, z:4, ne:5, nz:5,
> be:6, na:6, nbe:7, a:7, +
> > +         s:8, ns:9, t:a, p:a, pe:a, f:b, np:b, po:b, l:c, nge:c,
> > +nl:d, ge:d, le:e, ng:e, nle:f, g:f>
> > +
> > +ccmp<cc>, 0x380<cc:opc>, APX_F,
> > +D|W|CheckOperandSize|Modrm|EVexMap4|SCC|No_sSuf, {
> > +Reg8|Reg16|Reg32|Reg64,
> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
> > +} ccmp<cc>, 0x830<cc:opc>/7, APX_F,
> > +Modrm|EVexMap4|SCC|No_bSuf|No_sSuf, { Imm8S,
> > +Reg16|Reg32|Reg64|Unspecified|BaseIndex } ccmp<cc>,
> 0x800<cc:opc>/7,
> > +APX_F, W|Modrm|EVexMap4|SCC|No_sSuf,
> { Imm8|Imm16|Imm32|Imm32S,
> > +Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> > +
> >  test, 0x84, 0, D|W|C|CheckOperandSize|Modrm|No_sSuf, {
> > Reg8|Reg16|Reg32|Reg64,
> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> > test, 0xa8, 0, W|No_sSuf|Optimize, { Imm8|Imm16|Imm32|Imm32S,
> > Acc|Byte|Word|Dword|Qword }  test, 0xf6/0, 0,
> > W|Modrm|No_sSuf|Optimize, { Imm8|Imm16|Imm32|Imm32S,
> > Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> > +ctest<cc>, 0x840<cc:opc>, APX_F,
> > +D|W|C|CheckOperandSize|Modrm|EVexMap4|SCC|No_sSuf, {
> > +Reg8|Reg16|Reg32|Reg64,
> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
> > +} ctest<cc>, 0xf60<cc:opc>/0, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, {
> > +Imm8|Imm16|Imm32|Imm32S,
> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
> > +} ctest<cc>, 0xf60<cc:opc>/1, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, {
> > +Imm8|Imm16|Imm32|Imm32S,
> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
> > +}
> 
> In the context of this patch (as a whole) - what meaning to we intend e.g.
> 
> 	{evex} cmp %eax, %ecx
> 
> to have? Imo that should translate to CCMPT.
>
 
Could you describe it in more detail? I'm a bit confused. Why should we support {evex} cmp %eax, %ecx ?

> > @@ -505,9 +515,6 @@ enter, 0xc8, x64,
> > ImplicitStackOp|DefaultSize|No_bSuf|No_lSuf|No_sSuf|NoRex64, {  leave,
> > 0xc9, i186&No64, ImplicitStackOp|DefaultSize|No_bSuf|No_sSuf|No_qSuf,
> > {}  leave, 0xc9, x64,
> > ImplicitStackOp|DefaultSize|No_bSuf|No_lSuf|No_sSuf|NoRex64, {}
> >
> > -<cc:opc, o:0, no:1, b:2, c:2, nae:2, nb:3, nc:3, ae:3, e:4, z:4, ne:5, nz:5, be:6,
> na:6, nbe:7, a:7, +
> > -         s:8, ns:9, p:a, pe:a, np:b, po:b, l:c, nge:c, nl:d, ge:d, le:e, ng:e, nle:f,
> g:f>
> > -
> 
> I don't think you can simply re-use this: p/pe and np/po don't exist in SCC and
> need to be _replaced_ by t and f respectively. IOW you can neither introduce
> e.g. invalid CCMPPE, nor can you suddenly introduce e.g. invalid SETT. You'll
> want a new template named "scc".
> 
> Seeing that such a mistake was once made, please add "invalid" tests
> demonstrating that e.g. SETT and CMPPE are properly diagnosed.
> 

DONE.

Thanks,
Lili.
  
Jan Beulich May 31, 2024, 6:59 a.m. UTC | #15
On 31.05.2024 08:40, Cui, Lili wrote:
>>> --- /dev/null
>>> +++ b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-intel.d
>>> @@ -0,0 +1,220 @@
>>> +#as:
>>> +#objdump: -dw -Mintel
>>> +#name: x86_64 APX_F CCMP and CTEST insns (Intel disassembly)
>>> +#source: x86-64-apx-ccmp-ctest.s
>>> +
>>> +.*: +file format .*
>>> +
>>> +Disassembly of section \.text:
>>> +
>>> +0+ <_start>:
>>> +\s*[a-f0-9]+:\s*62 d4 8c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb
>> \{dfv=cf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
>>
>> In order to spot possible issues, it helps is test expectations are readable.
>> \s is imo hampering readability, as in not being a visual separator. However,
>> what I strongly object to is a _mix_ of \s and [ 	].
>>
> 
> [space+tab] is certainly more intuitive, but it takes up too much screen space, especially for long assembler and disassembler instructions, so I prefer to use \s. I remember you asked in a previous comment to replace the last \s with [], so I replaced the last \s before I sent out the patch, resulting in the current hybrid state. Do you mind if I change the last [] to \s? Keep one style.

If \s is used, then consistently, yes. But "taking up screen space" is an imo
pretty week argument nowadays, considering on how wide typical monitors have
been already years ago. I won't veto \s uses, but I'd really like to ask you
to reconsider. In new tests I add I won't ever use \s, and I may go and
replace \s in expectations I need to touch anyway at more than just very few
lines.

>>> --- a/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.s
>>> +++ b/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.s
>>> @@ -43,7 +43,7 @@ _start:
>>>
>>>  	# pop2 %rax, %r8 set EVEX.ND=0.
>>>  	.byte 0x62, 0xf4, 0x3c, 0x08, 0x8f, 0xc0
>>> -	.byte 0xff, 0xff, 0xff
>>> +	.byte 0xff, 0xff
>>
>> What's the reason for this and ...
>>
> 
> Because I moved the invalid check out of get_valid_dis386 (wait for CCMP and CCTEST).

Hmm, may want to be a separate prereq change then. The way we presently
deal with bad encodings is pretty inconsistent, and hence any change
there wants making sure that things at least don't get yet worse.

>>> @@ -14089,3 +14110,55 @@ JMPABS_Fixup (instr_info *ins, int bytemode,
>> int sizeflag)
>>>      return OP_IMREG (ins, bytemode, sizeflag);
>>>    return OP_OFF64 (ins, bytemode, sizeflag);  }
>>> +
>>> +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}"
>>> +};
>>> +
>>> +static const char *const scc_suffix[16] = {
>>> +  "o", "no", "b", "nb", "z", "nz", "be", "nbe", "s", "ns", "t", "f",
>>> +  "l", "nl", "le", "nle"
>>> +};
>>
>> Can these please be in sync with the forms we use for e.g. Jcc and SETcc?
>> I actually have a patch pending harmonizing these for CMPccXADD as well.
>>
> 
> I'm ok to change it like Jcc, but there are still 2 bits that are different from JCC.

Of course.

> "SCC values 0b1010 and 0b1011 (which are P and NP in normal condition codes) should be written as T
> and F because they now mean True and False."  -- apx-asm-syntax
> 
> static const char *const scc_suffix[16] = {
>   "o", "no", "b", "ae", "e", "ne", "be", "a", "s", "ns", "t", "f",
>   "l", "ge", "le", "g"
> };

Looks better, yes, but please still consider introducing a %SC macro
paralleling the %CC I'm introducing in "x86: disassembler macro for
condition code". That'll then also avoid you needing to perhaps insert
stuff into the middle of something that was output before.

>>> --- a/opcodes/i386-opc.tbl
>>> +++ b/opcodes/i386-opc.tbl
>>> @@ -341,9 +341,19 @@ cmp, 0x83/7, 0, Modrm|No_bSuf|No_sSuf,
>> { Imm8S,
>>> Reg16|Reg32|Reg64|Unspecified|Ba  cmp, 0x3c, 0, W|No_sSuf, {
>>> Imm8|Imm16|Imm32|Imm32S, Acc|Byte|Word|Dword|Qword }  cmp,
>> 0x80/7, 0,
>>> W|Modrm|No_sSuf, { Imm8|Imm16|Imm32|Imm32S,
>>> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
>>>
>>> +<cc:opc, o:0, no:1, b:2, c:2, nae:2, nb:3, nc:3, ae:3, e:4, z:4, ne:5, nz:5,
>> be:6, na:6, nbe:7, a:7, +
>>> +         s:8, ns:9, t:a, p:a, pe:a, f:b, np:b, po:b, l:c, nge:c,
>>> +nl:d, ge:d, le:e, ng:e, nle:f, g:f>
>>> +
>>> +ccmp<cc>, 0x380<cc:opc>, APX_F,
>>> +D|W|CheckOperandSize|Modrm|EVexMap4|SCC|No_sSuf, {
>>> +Reg8|Reg16|Reg32|Reg64,
>> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
>>> +} ccmp<cc>, 0x830<cc:opc>/7, APX_F,
>>> +Modrm|EVexMap4|SCC|No_bSuf|No_sSuf, { Imm8S,
>>> +Reg16|Reg32|Reg64|Unspecified|BaseIndex } ccmp<cc>,
>> 0x800<cc:opc>/7,
>>> +APX_F, W|Modrm|EVexMap4|SCC|No_sSuf,
>> { Imm8|Imm16|Imm32|Imm32S,
>>> +Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
>>> +
>>>  test, 0x84, 0, D|W|C|CheckOperandSize|Modrm|No_sSuf, {
>>> Reg8|Reg16|Reg32|Reg64,
>> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
>>> test, 0xa8, 0, W|No_sSuf|Optimize, { Imm8|Imm16|Imm32|Imm32S,
>>> Acc|Byte|Word|Dword|Qword }  test, 0xf6/0, 0,
>>> W|Modrm|No_sSuf|Optimize, { Imm8|Imm16|Imm32|Imm32S,
>>> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
>>> +ctest<cc>, 0x840<cc:opc>, APX_F,
>>> +D|W|C|CheckOperandSize|Modrm|EVexMap4|SCC|No_sSuf, {
>>> +Reg8|Reg16|Reg32|Reg64,
>> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
>>> +} ctest<cc>, 0xf60<cc:opc>/0, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, {
>>> +Imm8|Imm16|Imm32|Imm32S,
>> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
>>> +} ctest<cc>, 0xf60<cc:opc>/1, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, {
>>> +Imm8|Imm16|Imm32|Imm32S,
>> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
>>> +}
>>
>> In the context of this patch (as a whole) - what meaning to we intend e.g.
>>
>> 	{evex} cmp %eax, %ecx
>>
>> to have? Imo that should translate to CCMPT.
>>
>  
> Could you describe it in more detail? I'm a bit confused. Why should we support {evex} cmp %eax, %ecx ?

To parallel {evex} use with other insns. And CCMPT really _is_ the EVEX encoding
of CMP, considering CCMPcc's placement(s) in the opcode map.

And just to mention it here: I also think there might better be a pseudo-insn
aliasing to one of CCMPF or CTESTF, with no operands. I.e. merely specifying the
new value for the respective EFLAGS bits. Yet adding such - requiring a mnemonic
which then won't be used elsewhere in the future - can't very well be done
without the assembler doc at least permitting for it.

Jan
  
Cui, Lili June 3, 2024, 6:31 a.m. UTC | #16
> On 31.05.2024 08:40, Cui, Lili wrote:
> >>> --- /dev/null
> >>> +++ b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-intel.d
> >>> @@ -0,0 +1,220 @@
> >>> +#as:
> >>> +#objdump: -dw -Mintel
> >>> +#name: x86_64 APX_F CCMP and CTEST insns (Intel disassembly)
> >>> +#source: x86-64-apx-ccmp-ctest.s
> >>> +
> >>> +.*: +file format .*
> >>> +
> >>> +Disassembly of section \.text:
> >>> +
> >>> +0+ <_start>:
> >>> +\s*[a-f0-9]+:\s*62 d4 8c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb
> >> \{dfv=cf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
> >>
> >> In order to spot possible issues, it helps is test expectations are readable.
> >> \s is imo hampering readability, as in not being a visual separator. However,
> >> what I strongly object to is a _mix_ of \s and [ 	].
> >>
> >
> > [space+tab] is certainly more intuitive, but it takes up too much screen
> space, especially for long assembler and disassembler instructions, so I prefer
> to use \s. I remember you asked in a previous comment to replace the last \s
> with [], so I replaced the last \s before I sent out the patch, resulting in the
> current hybrid state. Do you mind if I change the last [] to \s? Keep one style.
> 
> If \s is used, then consistently, yes. But "taking up screen space" is an imo
> pretty week argument nowadays, considering on how wide typical monitors
> have been already years ago. I won't veto \s uses, but I'd really like to ask you
> to reconsider. In new tests I add I won't ever use \s, and I may go and replace
> \s in expectations I need to touch anyway at more than just very few lines.
> 

Ok, [] is used here.

> >>> @@ -14089,3 +14110,55 @@ JMPABS_Fixup (instr_info *ins, int
> >>> bytemode,
> >> int sizeflag)
> >>>      return OP_IMREG (ins, bytemode, sizeflag);
> >>>    return OP_OFF64 (ins, bytemode, sizeflag);  }
> >>> +
> >>> +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}"
> >>> +};
> >>> +
> >>> +static const char *const scc_suffix[16] = {
> >>> +  "o", "no", "b", "nb", "z", "nz", "be", "nbe", "s", "ns", "t",
> >>> +"f",
> >>> +  "l", "nl", "le", "nle"
> >>> +};
> >>
> >> Can these please be in sync with the forms we use for e.g. Jcc and SETcc?
> >> I actually have a patch pending harmonizing these for CMPccXADD as well.
> >>
> >
> > I'm ok to change it like Jcc, but there are still 2 bits that are different from
> JCC.
> 
> Of course.
> 
> > "SCC values 0b1010 and 0b1011 (which are P and NP in normal condition
> > codes) should be written as T and F because they now mean True and
> > False."  -- apx-asm-syntax
> >
> > static const char *const scc_suffix[16] = {
> >   "o", "no", "b", "ae", "e", "ne", "be", "a", "s", "ns", "t", "f",
> >   "l", "ge", "le", "g"
> > };
> 
> Looks better, yes, but please still consider introducing a %SC macro paralleling
> the %CC I'm introducing in "x86: disassembler macro for condition code".
> That'll then also avoid you needing to perhaps insert stuff into the middle of
> something that was output before.
> 

Introduced %SC an %DF, and removed SCC_And_OSZC_Flags_Fixup.

> >>> --- a/opcodes/i386-opc.tbl
> >>> +++ b/opcodes/i386-opc.tbl
> >>> @@ -341,9 +341,19 @@ cmp, 0x83/7, 0, Modrm|No_bSuf|No_sSuf,
> >> { Imm8S,
> >>> Reg16|Reg32|Reg64|Unspecified|Ba  cmp, 0x3c, 0, W|No_sSuf, {
> >>> Imm8|Imm16|Imm32|Imm32S, Acc|Byte|Word|Dword|Qword }  cmp,
> >> 0x80/7, 0,
> >>> W|Modrm|No_sSuf, { Imm8|Imm16|Imm32|Imm32S,
> >>> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> >>>
> >>> +<cc:opc, o:0, no:1, b:2, c:2, nae:2, nb:3, nc:3, ae:3, e:4, z:4,
> >>> +ne:5, nz:5,
> >> be:6, na:6, nbe:7, a:7, +
> >>> +         s:8, ns:9, t:a, p:a, pe:a, f:b, np:b, po:b, l:c, nge:c,
> >>> +nl:d, ge:d, le:e, ng:e, nle:f, g:f>
> >>> +
> >>> +ccmp<cc>, 0x380<cc:opc>, APX_F,
> >>> +D|W|CheckOperandSize|Modrm|EVexMap4|SCC|No_sSuf, {
> >>> +Reg8|Reg16|Reg32|Reg64,
> >> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
> >>> +} ccmp<cc>, 0x830<cc:opc>/7, APX_F,
> >>> +Modrm|EVexMap4|SCC|No_bSuf|No_sSuf, { Imm8S,
> >>> +Reg16|Reg32|Reg64|Unspecified|BaseIndex } ccmp<cc>,
> >> 0x800<cc:opc>/7,
> >>> +APX_F, W|Modrm|EVexMap4|SCC|No_sSuf,
> >> { Imm8|Imm16|Imm32|Imm32S,
> >>> +Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> >>> +
> >>>  test, 0x84, 0, D|W|C|CheckOperandSize|Modrm|No_sSuf, {
> >>> Reg8|Reg16|Reg32|Reg64,
> >> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> >>> test, 0xa8, 0, W|No_sSuf|Optimize, { Imm8|Imm16|Imm32|Imm32S,
> >>> Acc|Byte|Word|Dword|Qword }  test, 0xf6/0, 0,
> >>> W|Modrm|No_sSuf|Optimize, { Imm8|Imm16|Imm32|Imm32S,
> >>> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
> >>> +ctest<cc>, 0x840<cc:opc>, APX_F,
> >>> +D|W|C|CheckOperandSize|Modrm|EVexMap4|SCC|No_sSuf, {
> >>> +Reg8|Reg16|Reg32|Reg64,
> >> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
> >>> +} ctest<cc>, 0xf60<cc:opc>/0, APX_F,
> W|Modrm|EVexMap4|SCC|No_sSuf,
> >>> +{
> >>> +Imm8|Imm16|Imm32|Imm32S,
> >> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
> >>> +} ctest<cc>, 0xf60<cc:opc>/1, APX_F,
> W|Modrm|EVexMap4|SCC|No_sSuf,
> >>> +{
> >>> +Imm8|Imm16|Imm32|Imm32S,
> >> Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex
> >>> +}
> >>
> >> In the context of this patch (as a whole) - what meaning to we intend e.g.
> >>
> >> 	{evex} cmp %eax, %ecx
> >>
> >> to have? Imo that should translate to CCMPT.
> >>
> >
> > Could you describe it in more detail? I'm a bit confused. Why should we
> support {evex} cmp %eax, %ecx ?
> 
> To parallel {evex} use with other insns. And CCMPT really _is_ the EVEX
> encoding of CMP, considering CCMPcc's placement(s) in the opcode map.
> 

Ok, got it, added templates and test cases.

> And just to mention it here: I also think there might better be a pseudo-insn
> aliasing to one of CCMPF or CTESTF, with no operands. I.e. merely specifying
> the new value for the respective EFLAGS bits. Yet adding such - requiring a
> mnemonic which then won't be used elsewhere in the future - can't very well
> be done without the assembler doc at least permitting for it.
> 

Ok, I'll feedback this issue.

Thanks,
Lili.
  
Cui, Lili June 5, 2024, 1:54 a.m. UTC | #17
> >> In the context of this patch (as a whole) - what meaning to we intend e.g.

> >>

> >>       {evex} cmp %eax, %ecx

> >>

> >> to have? Imo that should translate to CCMPT.

> >>

> >

> > Could you describe it in more detail? I'm a bit confused. Why should we

> support {evex} cmp %eax, %ecx ?

>

> To parallel {evex} use with other insns. And CCMPT really _is_ the EVEX

> encoding of CMP, considering CCMPcc's placement(s) in the opcode map.

>

> And just to mention it here: I also think there might better be a pseudo-insn

> aliasing to one of CCMPF or CTESTF, with no operands. I.e. merely specifying

> the new value for the respective EFLAGS bits. Yet adding such - requiring a

> mnemonic which then won't be used elsewhere in the future - can't very well

> be done without the assembler doc at least permitting for it.

>



For "ccmp {dfv = sf, cf, of, zf}" format, apx-asm-syntax will not be updated to keep it simple. If Binutil still wants to support this format, we need to pay attention to the following.


If one of the operands is memory, the instruction can page-fault even though the SCC is False.  From the APX spec:

[cid:image001.png@01DAB69F.77AEA340]



Thanks,

Lili.
  

Patch

diff --git a/gas/config/tc-i386-intel.c b/gas/config/tc-i386-intel.c
index f454ee93ecb..99f2b132294 100644
--- a/gas/config/tc-i386-intel.c
+++ b/gas/config/tc-i386-intel.c
@@ -619,6 +619,14 @@  i386_intel_operand (char *operand_string, int got_a_float)
   bool rc_sae_modifier = i.rounding.type != rc_none && i.rounding.modifier;
   int ret;
 
+  /* Handle SCC OSZC flgs.  */
+  if (current_templates.start->opcode_modifier.scc)
+    {
+      operand_string = check_Scc_OszcOperations (operand_string);
+      if (operand_string == NULL)
+	return 0;
+    }
+
   /* Handle vector immediates.  */
   if (RC_SAE_immediate (operand_string))
     {
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index a84e99977dc..e667b7791fd 100644
--- 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;
+
+    #define CF 0
+    #define ZF 1
+    #define SF 2
+    #define OF 3
+    /* Store 4 bits of EVEX.[OF,SF,ZF,CF].  */
+    unsigned int oszc_flags;
+
     /* Prefer load or store in encoding.  */
     enum
       {
@@ -3793,10 +3803,19 @@  install_template (const insn_template *t)
 	}
     }
 
+  /* For the ccmp and ctest instructions we use base_opcode like the legacy
+     instructions and restore it in i.tm.base_opcode.  */
+  if (i.tm.opcode_modifier.scc)
+    {
+      /* Store scc in the lower 4 bits of base_opcode.  */
+      i.scc = i.tm.base_opcode & 0xf;
+      i.tm.base_opcode >>= 8;
+    }
+
   /* Note that for pseudo prefixes this produces a length of 1. But for them
      the length isn't interesting at all.  */
   for (l = 1; l < 4; ++l)
-    if (!(t->base_opcode >> (8 * l)))
+    if (!(i.tm.base_opcode >> (8 * l)))
       break;
 
   i.opcode_length = l;
@@ -4290,6 +4309,16 @@  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.scc)
+    {
+      i.vex.bytes[2] &= ~0x78;
+      i.vex.bytes[2] |= (i.oszc_flags << 3);
+      i.vex.bytes[3] = (i.vex.bytes[3] & 0xf0) | i.scc;
+      /* The ND bit is required to be set to 0.  */
+      i.vex.bytes[3] &= 0xef;
+    }
+
   /* Encode the NF bit.  */
   if (i.has_nf)
     i.vex.bytes[3] |= 0x04;
@@ -7539,13 +7568,14 @@  parse_operands (char *l, const char *mnemonic)
 		      i.operands + 1);
 	      return NULL;
 	    }
-	  if (!intel_syntax && !in_quotes)
+	  if (!in_quotes)
 	    {
-	      if (*l == '(')
+	      if (*l == '(' || *l == '{')
 		++paren_not_balanced;
-	      if (*l == ')')
+	      if (*l == ')' || *l == '}')
 		--paren_not_balanced;
 	    }
+
 	  l++;
 	}
       if (l != token_start)
@@ -13578,6 +13608,93 @@  RC_SAE_specifier (const char *pstr)
   return NULL;
 }
 
+/* Handle SCC OSZC flags.  */
+
+static char *
+check_Scc_OszcOperations (char *op_string)
+{
+  /* If {oszc flags} is absent, just return op_string.  */
+  if (*op_string != '{')
+    return op_string;
+  else
+    {
+      bool has_equal;
+      /* Parse '{dfv='.  */
+      while (*op_string)
+	{
+	  if (*op_string != '=')
+	    op_string++;
+	  else
+	    {
+	      has_equal = true;
+	      op_string++;
+	      break;
+	    }
+	}
+
+      if (!has_equal)
+	{
+	  /* If there is no '=', report bad.  */
+	  as_bad (_("Unrecognized oszc flags"));
+	  ignore_rest_of_line ();
+	}
+    }
+
+  /* Parse 'of , sf, sf, cf}'.  */
+  while (*op_string)
+    {
+      if (*op_string == ',' || is_space_char (*op_string))
+	op_string++;
+      else if (*op_string == '}')
+	{
+	  op_string++;
+	  while (is_space_char (*op_string))
+	    op_string++;
+	  return op_string;
+	}
+      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 (op_string[1] != 'f')
+	    {
+	      as_bad (_("Unrecognized oszc flags"));
+	      ignore_rest_of_line ();
+	      return NULL;
+	    }
+	  switch (op_string[0])
+	    {
+	    case 'o':
+	      i.oszc_flags |= (1 << OF);
+	      break;
+	    case 's':
+	      i.oszc_flags |= (1 << SF);
+	      break;
+	    case 'z':
+	      i.oszc_flags |= (1 << ZF);
+	      break;
+	    case 'c':
+	    case 'p':
+	      i.oszc_flags |= (1 << CF);
+	      break;
+	    case 'a':
+	      break;
+	    default:
+	      as_bad (_("Unrecognized oszc flags"));
+	      ignore_rest_of_line ();
+	      return NULL;
+	    }
+	  op_string += 2;
+	}
+    }
+  return op_string;
+}
+
 /* Handle Vector operations.  */
 
 static char *
@@ -14486,6 +14603,14 @@  i386_att_operand (char *operand_string)
       i.jumpabsolute = true;
     }
 
+  /* Handle SCC OSZC flgs.  */
+  if (current_templates.start->opcode_modifier.scc)
+    {
+      op_string = check_Scc_OszcOperations (op_string);
+      if (op_string == NULL)
+	return 0;
+    }
+
   /* Check if operand is a register.  */
   if ((r = parse_register (op_string, &end_op)) != NULL)
     {
diff --git a/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-intel.d b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-intel.d
new file mode 100644
index 00000000000..de24281aff3
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-intel.d
@@ -0,0 +1,220 @@ 
+#as:
+#objdump: -dw -Mintel
+#name: x86_64 APX_F CCMP and CTEST insns (Intel disassembly)
+#source: x86-64-apx-ccmp-ctest.s
+
+.*: +file format .*
+
+Disassembly of section \.text:
+
+0+ <_start>:
+\s*[a-f0-9]+:\s*62 d4 8c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=cf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 74 0d 02 39 f8[ 	]+ccmpb \{dfv=cf\} ax,r15w
+\s*[a-f0-9]+:\s*62 d4 8c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=cf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 74 0d 02 39 f8[ 	]+ccmpb \{dfv=cf\} ax,r15w
+\s*[a-f0-9]+:\s*62 54 0c 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=cf\} r15d,DWORD PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 d4 4d 02 83 ff 7b[ 	]+ccmpb \{dfv=of, cf\} r15w,0x7b
+\s*[a-f0-9]+:\s*62 d4 4c 02 80 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, cf\} BYTE PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 6d 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, sf, cf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 ec 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=of, sf, cf\} QWORD PTR \[r8\+rax\*4\+0x123\],r15
+\s*[a-f0-9]+:\s*62 d4 7d 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, sf, zf, cf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 fc 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, sf, zf, cf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 74 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, sf, zf\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 f4 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=of, sf, zf\} QWORD PTR \[r8\+rax\*4\+0x123\],r15
+\s*[a-f0-9]+:\s*62 d4 e4 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, sf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 64 02 3a 84 80 23 01 00 00[ 	]+ccmpb \{dfv=of, sf\} r8b,BYTE PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 d4 5c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, zf, cf\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 5c 02 38 84 80 23 01 00 00[ 	]+ccmpb \{dfv=of, zf, cf\} BYTE PTR \[r8\+rax\*4\+0x123\],r8b
+\s*[a-f0-9]+:\s*62 d4 55 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, zf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 74 54 02 38 c2[ 	]+ccmpb \{dfv=of, zf\} dl,r8b
+\s*[a-f0-9]+:\s*62 74 44 02 39 fa[ 	]+ccmpb \{dfv=of\} edx,r15d
+\s*[a-f0-9]+:\s*62 54 45 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=of\} r15w,WORD PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 d4 2c 02 80 f8 7b[ 	]+ccmpb \{dfv=sf, cf\} r8b,0x7b
+\s*[a-f0-9]+:\s*62 54 2c 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, cf\} DWORD PTR \[r8\+rax\*4\+0x123\],r15d
+\s*[a-f0-9]+:\s*62 54 ac 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, cf\} r15,QWORD PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 d4 3c 02 83 ff 7b[ 	]+ccmpb \{dfv=sf, zf, cf\} r15d,0x7b
+\s*[a-f0-9]+:\s*62 54 3d 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, zf, cf\} r15w,WORD PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 d4 34 02 83 ff 7b[ 	]+ccmpb \{dfv=sf, zf\} r15d,0x7b
+\s*[a-f0-9]+:\s*62 54 34 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, zf\} DWORD PTR \[r8\+rax\*4\+0x123\],r15d
+\s*[a-f0-9]+:\s*62 d4 a4 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=sf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 a4 02 39 ff[ 	]+ccmpb \{dfv=sf\} r15,r15
+\s*[a-f0-9]+:\s*62 54 a4 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf\} r15,QWORD PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 d4 9c 02 83 ff 7b[ 	]+ccmpb \{dfv=zf, cf\} r15,0x7b
+\s*[a-f0-9]+:\s*62 d4 1c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=zf, cf\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 1d 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=zf, cf\} WORD PTR \[r8\+rax\*4\+0x123\],r15w
+\s*[a-f0-9]+:\s*62 d4 94 02 83 ff 7b[ 	]+ccmpb \{dfv=zf\} r15,0x7b
+\s*[a-f0-9]+:\s*62 d4 15 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=zf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 15 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=zf\} WORD PTR \[r8\+rax\*4\+0x123\],r15w
+\s*[a-f0-9]+:\s*62 d4 05 02 83 ff 7b[ 	]+ccmpb \{dfv=\} r15w,0x7b
+\s*[a-f0-9]+:\s*62 d4 04 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 04 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=\} r15d,DWORD PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 54 04 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=\} r15d,DWORD PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 fc c4 00 83 f8 7b[ 	]+ccmpo \{dfv=of\} r16,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 01 83 f9 7b[ 	]+ccmpno \{dfv=of\} r17,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 02 83 fa 7b[ 	]+ccmpb \{dfv=of\} r18,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 03 83 fb 7b[ 	]+ccmpnb \{dfv=of\} r19,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 04 83 fc 7b[ 	]+ccmpz \{dfv=of\} r20,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 05 83 fd 7b[ 	]+ccmpnz \{dfv=of\} r21,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 06 83 fe 7b[ 	]+ccmpbe \{dfv=of\} r22,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 07 83 ff 7b[ 	]+ccmpnbe \{dfv=of\} r23,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 08 83 f8 7b[ 	]+ccmps \{dfv=of\} r24,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 09 83 f9 7b[ 	]+ccmpns \{dfv=of\} r25,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0a 83 fa 7b[ 	]+ccmpt \{dfv=of\} r26,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0b 83 fb 7b[ 	]+ccmpf \{dfv=of\} r27,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0c 83 fc 7b[ 	]+ccmpl \{dfv=of\} r28,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0d 83 fd 7b[ 	]+ccmpnl \{dfv=of\} r29,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0e 83 fe 7b[ 	]+ccmple \{dfv=of\} r30,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0f 83 ff 7b[ 	]+ccmpnle \{dfv=of\} r31,0x7b
+\s*[a-f0-9]+:\s*62 d4 8c 02 f7 c7 7b 00 00 00[ 	]+ctestb \{dfv=cf\} r15,0x7b
+\s*[a-f0-9]+:\s*62 d4 0d 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestb \{dfv=cf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 8c 02 f7 c7 7b 00 00 00[ 	]+ctestb \{dfv=cf\} r15,0x7b
+\s*[a-f0-9]+:\s*62 d4 0d 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestb \{dfv=cf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 4c 02 f6 84 80 23 01 00 00 7b[ 	]+ctestb \{dfv=of, cf\} BYTE PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 cc 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, cf\} QWORD PTR \[r8\+rax\*4\+0x123\],r15
+\s*[a-f0-9]+:\s*62 d4 ec 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=of, sf, cf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 7c 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=of, sf, zf, cf\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 75 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestb \{dfv=of, sf, zf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 64 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=of, sf\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 65 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, sf\} WORD PTR \[r8\+rax\*4\+0x123\],r15w
+\s*[a-f0-9]+:\s*62 d4 5d 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestb \{dfv=of, zf, cf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 5d 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, zf, cf\} WORD PTR \[r8\+rax\*4\+0x123\],r15w
+\s*[a-f0-9]+:\s*62 d4 54 02 f6 84 80 23 01 00 00 7b[ 	]+ctestb \{dfv=of, zf\} BYTE PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 d4 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, zf\} QWORD PTR \[r8\+rax\*4\+0x123\],r15
+\s*[a-f0-9]+:\s*62 54 44 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of\} DWORD PTR \[r8\+rax\*4\+0x123\],r15d
+\s*[a-f0-9]+:\s*62 54 44 02 84 84 80 23 01 00 00[ 	]+ctestb \{dfv=of\} BYTE PTR \[r8\+rax\*4\+0x123\],r8b
+\s*[a-f0-9]+:\s*62 d4 2c 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=sf, cf\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 74 2c 02 85 fa[ 	]+ctestb \{dfv=sf, cf\} edx,r15d
+\s*[a-f0-9]+:\s*62 54 3c 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=sf, zf, cf\} DWORD PTR \[r8\+rax\*4\+0x123\],r15d
+\s*[a-f0-9]+:\s*62 74 3c 02 84 c2[ 	]+ctestb \{dfv=sf, zf, cf\} dl,r8b
+\s*[a-f0-9]+:\s*62 d4 35 02 f7 c7 7b 00[ 	]+ctestb \{dfv=sf, zf\} r15w,0x7b
+\s*[a-f0-9]+:\s*62 d4 b4 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=sf, zf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 24 02 f7 c7 7b 00 00 00[ 	]+ctestb \{dfv=sf\} r15d,0x7b
+\s*[a-f0-9]+:\s*62 d4 25 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestb \{dfv=sf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 1c 02 f6 c0 7b[ 	]+ctestb \{dfv=zf, cf\} r8b,0x7b
+\s*[a-f0-9]+:\s*62 d4 9c 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=zf, cf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 14 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=zf\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 94 02 85 ff[ 	]+ctestb \{dfv=zf\} r15,r15
+\s*[a-f0-9]+:\s*62 d4 84 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 74 05 02 85 f8[ 	]+ctestb \{dfv=\} ax,r15w
+\s*[a-f0-9]+:\s*62 74 05 02 85 f8[ 	]+ctestb \{dfv=\} ax,r15w
+\s*[a-f0-9]+:\s*62 fc c4 00 f7 c0 7b 00 00 00[ 	]+ctesto \{dfv=of\} r16,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 01 f7 c1 7b 00 00 00[ 	]+ctestno \{dfv=of\} r17,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 02 f7 c2 7b 00 00 00[ 	]+ctestb \{dfv=of\} r18,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 03 f7 c3 7b 00 00 00[ 	]+ctestnb \{dfv=of\} r19,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 04 f7 c4 7b 00 00 00[ 	]+ctestz \{dfv=of\} r20,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 05 f7 c5 7b 00 00 00[ 	]+ctestnz \{dfv=of\} r21,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 06 f7 c6 7b 00 00 00[ 	]+ctestbe \{dfv=of\} r22,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 07 f7 c7 7b 00 00 00[ 	]+ctestnbe \{dfv=of\} r23,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 08 f7 c0 7b 00 00 00[ 	]+ctests \{dfv=of\} r24,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 09 f7 c1 7b 00 00 00[ 	]+ctestns \{dfv=of\} r25,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0a f7 c2 7b 00 00 00[ 	]+ctestt \{dfv=of\} r26,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0b f7 c3 7b 00 00 00[ 	]+ctestf \{dfv=of\} r27,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0c f7 c4 7b 00 00 00[ 	]+ctestl \{dfv=of\} r28,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0d f7 c5 7b 00 00 00[ 	]+ctestnl \{dfv=of\} r29,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0e f7 c6 7b 00 00 00[ 	]+ctestle \{dfv=of\} r30,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0f f7 c7 7b 00 00 00[ 	]+ctestnle \{dfv=of\} r31,0x7b
+\s*[a-f0-9]+:\s*62 d4 8c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=cf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 74 0d 02 39 f8[ 	]+ccmpb \{dfv=cf\} ax,r15w
+\s*[a-f0-9]+:\s*62 d4 8c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=cf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 74 0d 02 39 f8[ 	]+ccmpb \{dfv=cf\} ax,r15w
+\s*[a-f0-9]+:\s*62 54 0c 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=cf\} r15d,DWORD PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 d4 4d 02 83 ff 7b[ 	]+ccmpb \{dfv=of, cf\} r15w,0x7b
+\s*[a-f0-9]+:\s*62 d4 4c 02 80 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, cf\} BYTE PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 6d 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, sf, cf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 ec 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=of, sf, cf\} QWORD PTR \[r8\+rax\*4\+0x123\],r15
+\s*[a-f0-9]+:\s*62 d4 7d 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, sf, zf, cf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 fc 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, sf, zf, cf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 74 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, sf, zf\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 f4 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=of, sf, zf\} QWORD PTR \[r8\+rax\*4\+0x123\],r15
+\s*[a-f0-9]+:\s*62 d4 e4 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, sf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 64 02 3a 84 80 23 01 00 00[ 	]+ccmpb \{dfv=of, sf\} r8b,BYTE PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 d4 5c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, zf, cf\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 5c 02 38 84 80 23 01 00 00[ 	]+ccmpb \{dfv=of, zf, cf\} BYTE PTR \[r8\+rax\*4\+0x123\],r8b
+\s*[a-f0-9]+:\s*62 d4 55 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=of, zf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 74 54 02 38 c2[ 	]+ccmpb \{dfv=of, zf\} dl,r8b
+\s*[a-f0-9]+:\s*62 74 44 02 39 fa[ 	]+ccmpb \{dfv=of\} edx,r15d
+\s*[a-f0-9]+:\s*62 54 45 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=of\} r15w,WORD PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 d4 2c 02 80 f8 7b[ 	]+ccmpb \{dfv=sf, cf\} r8b,0x7b
+\s*[a-f0-9]+:\s*62 54 2c 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, cf\} DWORD PTR \[r8\+rax\*4\+0x123\],r15d
+\s*[a-f0-9]+:\s*62 54 ac 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, cf\} r15,QWORD PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 d4 3c 02 83 ff 7b[ 	]+ccmpb \{dfv=sf, zf, cf\} r15d,0x7b
+\s*[a-f0-9]+:\s*62 54 3d 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, zf, cf\} r15w,WORD PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 d4 34 02 83 ff 7b[ 	]+ccmpb \{dfv=sf, zf\} r15d,0x7b
+\s*[a-f0-9]+:\s*62 54 34 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, zf\} DWORD PTR \[r8\+rax\*4\+0x123\],r15d
+\s*[a-f0-9]+:\s*62 d4 a4 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=sf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 a4 02 39 ff[ 	]+ccmpb \{dfv=sf\} r15,r15
+\s*[a-f0-9]+:\s*62 54 a4 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf\} r15,QWORD PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 d4 9c 02 83 ff 7b[ 	]+ccmpb \{dfv=zf, cf\} r15,0x7b
+\s*[a-f0-9]+:\s*62 d4 1c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=zf, cf\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 1d 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=zf, cf\} WORD PTR \[r8\+rax\*4\+0x123\],r15w
+\s*[a-f0-9]+:\s*62 d4 94 02 83 ff 7b[ 	]+ccmpb \{dfv=zf\} r15,0x7b
+\s*[a-f0-9]+:\s*62 d4 15 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=zf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 15 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=zf\} WORD PTR \[r8\+rax\*4\+0x123\],r15w
+\s*[a-f0-9]+:\s*62 d4 05 02 83 ff 7b[ 	]+ccmpb \{dfv=\} r15w,0x7b
+\s*[a-f0-9]+:\s*62 d4 04 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpb \{dfv=\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 04 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=\} r15d,DWORD PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 54 04 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=\} r15d,DWORD PTR \[r8\+rax\*4\+0x123\]
+\s*[a-f0-9]+:\s*62 fc c4 00 83 f8 7b[ 	]+ccmpo \{dfv=of\} r16,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 01 83 f9 7b[ 	]+ccmpno \{dfv=of\} r17,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 02 83 fa 7b[ 	]+ccmpb \{dfv=of\} r18,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 03 83 fb 7b[ 	]+ccmpnb \{dfv=of\} r19,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 04 83 fc 7b[ 	]+ccmpz \{dfv=of\} r20,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 05 83 fd 7b[ 	]+ccmpnz \{dfv=of\} r21,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 06 83 fe 7b[ 	]+ccmpbe \{dfv=of\} r22,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 07 83 ff 7b[ 	]+ccmpnbe \{dfv=of\} r23,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 08 83 f8 7b[ 	]+ccmps \{dfv=of\} r24,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 09 83 f9 7b[ 	]+ccmpns \{dfv=of\} r25,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0a 83 fa 7b[ 	]+ccmpt \{dfv=of\} r26,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0b 83 fb 7b[ 	]+ccmpf \{dfv=of\} r27,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0c 83 fc 7b[ 	]+ccmpl \{dfv=of\} r28,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0d 83 fd 7b[ 	]+ccmpnl \{dfv=of\} r29,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0e 83 fe 7b[ 	]+ccmple \{dfv=of\} r30,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0f 83 ff 7b[ 	]+ccmpnle \{dfv=of\} r31,0x7b
+\s*[a-f0-9]+:\s*62 d4 8c 02 f7 c7 7b 00 00 00[ 	]+ctestb \{dfv=cf\} r15,0x7b
+\s*[a-f0-9]+:\s*62 d4 0d 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestb \{dfv=cf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 8c 02 f7 c7 7b 00 00 00[ 	]+ctestb \{dfv=cf\} r15,0x7b
+\s*[a-f0-9]+:\s*62 d4 0d 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestb \{dfv=cf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 4c 02 f6 84 80 23 01 00 00 7b[ 	]+ctestb \{dfv=of, cf\} BYTE PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 cc 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, cf\} QWORD PTR \[r8\+rax\*4\+0x123\],r15
+\s*[a-f0-9]+:\s*62 d4 ec 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=of, sf, cf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 7c 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=of, sf, zf, cf\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 75 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestb \{dfv=of, sf, zf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 64 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=of, sf\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 65 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, sf\} WORD PTR \[r8\+rax\*4\+0x123\],r15w
+\s*[a-f0-9]+:\s*62 d4 5d 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestb \{dfv=of, zf, cf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 5d 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, zf, cf\} WORD PTR \[r8\+rax\*4\+0x123\],r15w
+\s*[a-f0-9]+:\s*62 d4 54 02 f6 84 80 23 01 00 00 7b[ 	]+ctestb \{dfv=of, zf\} BYTE PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 d4 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, zf\} QWORD PTR \[r8\+rax\*4\+0x123\],r15
+\s*[a-f0-9]+:\s*62 54 44 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of\} DWORD PTR \[r8\+rax\*4\+0x123\],r15d
+\s*[a-f0-9]+:\s*62 54 44 02 84 84 80 23 01 00 00[ 	]+ctestb \{dfv=of\} BYTE PTR \[r8\+rax\*4\+0x123\],r8b
+\s*[a-f0-9]+:\s*62 d4 2c 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=sf, cf\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 74 2c 02 85 fa[ 	]+ctestb \{dfv=sf, cf\} edx,r15d
+\s*[a-f0-9]+:\s*62 54 3c 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=sf, zf, cf\} DWORD PTR \[r8\+rax\*4\+0x123\],r15d
+\s*[a-f0-9]+:\s*62 74 3c 02 84 c2[ 	]+ctestb \{dfv=sf, zf, cf\} dl,r8b
+\s*[a-f0-9]+:\s*62 d4 35 02 f7 c7 7b 00[ 	]+ctestb \{dfv=sf, zf\} r15w,0x7b
+\s*[a-f0-9]+:\s*62 d4 b4 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=sf, zf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 24 02 f7 c7 7b 00 00 00[ 	]+ctestb \{dfv=sf\} r15d,0x7b
+\s*[a-f0-9]+:\s*62 d4 25 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestb \{dfv=sf\} WORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 1c 02 f6 c0 7b[ 	]+ctestb \{dfv=zf, cf\} r8b,0x7b
+\s*[a-f0-9]+:\s*62 d4 9c 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=zf, cf\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 d4 14 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=zf\} DWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 54 94 02 85 ff[ 	]+ctestb \{dfv=zf\} r15,r15
+\s*[a-f0-9]+:\s*62 d4 84 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestb \{dfv=\} QWORD PTR \[r8\+rax\*4\+0x123\],0x7b
+\s*[a-f0-9]+:\s*62 74 05 02 85 f8[ 	]+ctestb \{dfv=\} ax,r15w
+\s*[a-f0-9]+:\s*62 74 05 02 85 f8[ 	]+ctestb \{dfv=\} ax,r15w
+\s*[a-f0-9]+:\s*62 fc c4 00 f7 c0 7b 00 00 00[ 	]+ctesto \{dfv=of\} r16,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 01 f7 c1 7b 00 00 00[ 	]+ctestno \{dfv=of\} r17,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 02 f7 c2 7b 00 00 00[ 	]+ctestb \{dfv=of\} r18,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 03 f7 c3 7b 00 00 00[ 	]+ctestnb \{dfv=of\} r19,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 04 f7 c4 7b 00 00 00[ 	]+ctestz \{dfv=of\} r20,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 05 f7 c5 7b 00 00 00[ 	]+ctestnz \{dfv=of\} r21,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 06 f7 c6 7b 00 00 00[ 	]+ctestbe \{dfv=of\} r22,0x7b
+\s*[a-f0-9]+:\s*62 fc c4 07 f7 c7 7b 00 00 00[ 	]+ctestnbe \{dfv=of\} r23,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 08 f7 c0 7b 00 00 00[ 	]+ctests \{dfv=of\} r24,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 09 f7 c1 7b 00 00 00[ 	]+ctestns \{dfv=of\} r25,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0a f7 c2 7b 00 00 00[ 	]+ctestt \{dfv=of\} r26,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0b f7 c3 7b 00 00 00[ 	]+ctestf \{dfv=of\} r27,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0c f7 c4 7b 00 00 00[ 	]+ctestl \{dfv=of\} r28,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0d f7 c5 7b 00 00 00[ 	]+ctestnl \{dfv=of\} r29,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0e f7 c6 7b 00 00 00[ 	]+ctestle \{dfv=of\} r30,0x7b
+\s*[a-f0-9]+:\s*62 dc c4 0f f7 c7 7b 00 00 00[ 	]+ctestnle \{dfv=of\} r31,0x7b
diff --git a/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-inval.l b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-inval.l
new file mode 100644
index 00000000000..0f0dacca3ca
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-inval.l
@@ -0,0 +1,5 @@ 
+.* Assembler messages:
+.*:4: Error: Unrecognized oszc flags
+.*:5: Error: Unrecognized oszc flags
+.*:6: Error: unbalanced parenthesis in operand 1.
+#pass
diff --git a/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-inval.s b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-inval.s
new file mode 100644
index 00000000000..b27e058c750
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest-inval.s
@@ -0,0 +1,6 @@ 
+# Check APX_F ccmp ctest instructions with illegal instructions.
+
+	.text
+	ccmpb {dfv=ct} $0x7b,%r18
+	ctestb {dfv=sae} $0x7b,%r18
+	ccmpb { $0x7b,%r18
diff --git a/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest.d b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest.d
new file mode 100644
index 00000000000..d8a2ba916cc
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest.d
@@ -0,0 +1,220 @@ 
+#as:
+#objdump: -dw
+#name: x86_64 APX_F CCMP and CTEST insns
+#source: x86-64-apx-ccmp-ctest.s
+
+.*: +file format .*
+
+Disassembly of section \.text:
+
+0+ <_start>:
+\s*[a-f0-9]+:\s*62 d4 8c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbq \{dfv=cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 74 0d 02 39 f8[ 	]+ccmpb \{dfv=cf\} %r15w,%ax
+\s*[a-f0-9]+:\s*62 d4 8c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbq \{dfv=cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 74 0d 02 39 f8[ 	]+ccmpb \{dfv=cf\} %r15w,%ax
+\s*[a-f0-9]+:\s*62 54 0c 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=cf\}\s+0x123\(%r8,%rax,4\),%r15d
+\s*[a-f0-9]+:\s*62 d4 4d 02 83 ff 7b[ 	]+ccmpb \{dfv=of, cf\}\s+\$0x7b,%r15w
+\s*[a-f0-9]+:\s*62 d4 4c 02 80 bc 80 23 01 00 00 7b[ 	]+ccmpbb \{dfv=of, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 6d 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbw \{dfv=of, sf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 ec 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=of, sf, cf\} %r15,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 7d 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbw \{dfv=of, sf, zf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 fc 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbq \{dfv=of, sf, zf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 74 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbl \{dfv=of, sf, zf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 f4 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=of, sf, zf\} %r15,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 e4 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbq \{dfv=of, sf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 64 02 3a 84 80 23 01 00 00[ 	]+ccmpb \{dfv=of, sf\}\s+0x123\(%r8,%rax,4\),%r8b
+\s*[a-f0-9]+:\s*62 d4 5c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbl \{dfv=of, zf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 5c 02 38 84 80 23 01 00 00[ 	]+ccmpb \{dfv=of, zf, cf\} %r8b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 55 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbw \{dfv=of, zf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 74 54 02 38 c2[ 	]+ccmpb \{dfv=of, zf\} %r8b,%dl
+\s*[a-f0-9]+:\s*62 74 44 02 39 fa[ 	]+ccmpb \{dfv=of\} %r15d,%edx
+\s*[a-f0-9]+:\s*62 54 45 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=of\}\s+0x123\(%r8,%rax,4\),%r15w
+\s*[a-f0-9]+:\s*62 d4 2c 02 80 f8 7b[ 	]+ccmpb \{dfv=sf, cf\}\s+\$0x7b,%r8b
+\s*[a-f0-9]+:\s*62 54 2c 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, cf\} %r15d,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 ac 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, cf\}\s+0x123\(%r8,%rax,4\),%r15
+\s*[a-f0-9]+:\s*62 d4 3c 02 83 ff 7b[ 	]+ccmpb \{dfv=sf, zf, cf\}\s+\$0x7b,%r15d
+\s*[a-f0-9]+:\s*62 54 3d 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, zf, cf\}\s+0x123\(%r8,%rax,4\),%r15w
+\s*[a-f0-9]+:\s*62 d4 34 02 83 ff 7b[ 	]+ccmpb \{dfv=sf, zf\}\s+\$0x7b,%r15d
+\s*[a-f0-9]+:\s*62 54 34 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, zf\} %r15d,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 a4 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbq \{dfv=sf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 a4 02 39 ff[ 	]+ccmpb \{dfv=sf\} %r15,%r15
+\s*[a-f0-9]+:\s*62 54 a4 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf\}\s+0x123\(%r8,%rax,4\),%r15
+\s*[a-f0-9]+:\s*62 d4 9c 02 83 ff 7b[ 	]+ccmpb \{dfv=zf, cf\}\s+\$0x7b,%r15
+\s*[a-f0-9]+:\s*62 d4 1c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbl \{dfv=zf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 1d 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=zf, cf\} %r15w,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 94 02 83 ff 7b[ 	]+ccmpb \{dfv=zf\}\s+\$0x7b,%r15
+\s*[a-f0-9]+:\s*62 d4 15 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbw \{dfv=zf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 15 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=zf\} %r15w,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 05 02 83 ff 7b[ 	]+ccmpb \{dfv=\}\s+\$0x7b,%r15w
+\s*[a-f0-9]+:\s*62 d4 04 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbl \{dfv=\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 04 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=\}\s+0x123\(%r8,%rax,4\),%r15d
+\s*[a-f0-9]+:\s*62 54 04 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=\}\s+0x123\(%r8,%rax,4\),%r15d
+\s*[a-f0-9]+:\s*62 fc c4 00 83 f8 7b[ 	]+ccmpo \{dfv=of\} \$0x7b,%r16
+\s*[a-f0-9]+:\s*62 fc c4 01 83 f9 7b[ 	]+ccmpno \{dfv=of\} \$0x7b,%r17
+\s*[a-f0-9]+:\s*62 fc c4 02 83 fa 7b[ 	]+ccmpb \{dfv=of\} \$0x7b,%r18
+\s*[a-f0-9]+:\s*62 fc c4 03 83 fb 7b[ 	]+ccmpnb \{dfv=of\} \$0x7b,%r19
+\s*[a-f0-9]+:\s*62 fc c4 04 83 fc 7b[ 	]+ccmpz \{dfv=of\} \$0x7b,%r20
+\s*[a-f0-9]+:\s*62 fc c4 05 83 fd 7b[ 	]+ccmpnz \{dfv=of\} \$0x7b,%r21
+\s*[a-f0-9]+:\s*62 fc c4 06 83 fe 7b[ 	]+ccmpbe \{dfv=of\} \$0x7b,%r22
+\s*[a-f0-9]+:\s*62 fc c4 07 83 ff 7b[ 	]+ccmpnbe \{dfv=of\} \$0x7b,%r23
+\s*[a-f0-9]+:\s*62 dc c4 08 83 f8 7b[ 	]+ccmps \{dfv=of\} \$0x7b,%r24
+\s*[a-f0-9]+:\s*62 dc c4 09 83 f9 7b[ 	]+ccmpns \{dfv=of\} \$0x7b,%r25
+\s*[a-f0-9]+:\s*62 dc c4 0a 83 fa 7b[ 	]+ccmpt \{dfv=of\} \$0x7b,%r26
+\s*[a-f0-9]+:\s*62 dc c4 0b 83 fb 7b[ 	]+ccmpf \{dfv=of\} \$0x7b,%r27
+\s*[a-f0-9]+:\s*62 dc c4 0c 83 fc 7b[ 	]+ccmpl \{dfv=of\} \$0x7b,%r28
+\s*[a-f0-9]+:\s*62 dc c4 0d 83 fd 7b[ 	]+ccmpnl \{dfv=of\} \$0x7b,%r29
+\s*[a-f0-9]+:\s*62 dc c4 0e 83 fe 7b[ 	]+ccmple \{dfv=of\} \$0x7b,%r30
+\s*[a-f0-9]+:\s*62 dc c4 0f 83 ff 7b[ 	]+ccmpnle \{dfv=of\} \$0x7b,%r31
+\s*[a-f0-9]+:\s*62 d4 8c 02 f7 c7 7b 00 00 00[ 	]+ctestb \{dfv=cf\}\s+\$0x7b,%r15
+\s*[a-f0-9]+:\s*62 d4 0d 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestbw \{dfv=cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 8c 02 f7 c7 7b 00 00 00[ 	]+ctestb \{dfv=cf\}\s+\$0x7b,%r15
+\s*[a-f0-9]+:\s*62 d4 0d 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestbw \{dfv=cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 4c 02 f6 84 80 23 01 00 00 7b[ 	]+ctestbb \{dfv=of, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 cc 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, cf\} %r15,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 ec 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbq \{dfv=of, sf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 7c 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbl \{dfv=of, sf, zf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 75 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestbw \{dfv=of, sf, zf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 64 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbl \{dfv=of, sf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 65 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, sf\} %r15w,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 5d 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestbw \{dfv=of, zf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 5d 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, zf, cf\} %r15w,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 54 02 f6 84 80 23 01 00 00 7b[ 	]+ctestbb \{dfv=of, zf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 d4 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, zf\} %r15,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 44 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of\} %r15d,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 44 02 84 84 80 23 01 00 00[ 	]+ctestb \{dfv=of\} %r8b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 2c 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbl \{dfv=sf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 74 2c 02 85 fa[ 	]+ctestb \{dfv=sf, cf\} %r15d,%edx
+\s*[a-f0-9]+:\s*62 54 3c 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=sf, zf, cf\} %r15d,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 74 3c 02 84 c2[ 	]+ctestb \{dfv=sf, zf, cf\} %r8b,%dl
+\s*[a-f0-9]+:\s*62 d4 35 02 f7 c7 7b 00[ 	]+ctestb \{dfv=sf, zf\}\s+\$0x7b,%r15w
+\s*[a-f0-9]+:\s*62 d4 b4 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbq \{dfv=sf, zf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 24 02 f7 c7 7b 00 00 00[ 	]+ctestb \{dfv=sf\}\s+\$0x7b,%r15d
+\s*[a-f0-9]+:\s*62 d4 25 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestbw \{dfv=sf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 1c 02 f6 c0 7b[ 	]+ctestb \{dfv=zf, cf\}\s+\$0x7b,%r8b
+\s*[a-f0-9]+:\s*62 d4 9c 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbq \{dfv=zf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 14 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbl \{dfv=zf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 94 02 85 ff[ 	]+ctestb \{dfv=zf\} %r15,%r15
+\s*[a-f0-9]+:\s*62 d4 84 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbq \{dfv=\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 74 05 02 85 f8[ 	]+ctestb \{dfv=\} %r15w,%ax
+\s*[a-f0-9]+:\s*62 74 05 02 85 f8[ 	]+ctestb \{dfv=\} %r15w,%ax
+\s*[a-f0-9]+:\s*62 fc c4 00 f7 c0 7b 00 00 00[ 	]+ctesto \{dfv=of\} \$0x7b,%r16
+\s*[a-f0-9]+:\s*62 fc c4 01 f7 c1 7b 00 00 00[ 	]+ctestno \{dfv=of\} \$0x7b,%r17
+\s*[a-f0-9]+:\s*62 fc c4 02 f7 c2 7b 00 00 00[ 	]+ctestb \{dfv=of\} \$0x7b,%r18
+\s*[a-f0-9]+:\s*62 fc c4 03 f7 c3 7b 00 00 00[ 	]+ctestnb \{dfv=of\} \$0x7b,%r19
+\s*[a-f0-9]+:\s*62 fc c4 04 f7 c4 7b 00 00 00[ 	]+ctestz \{dfv=of\} \$0x7b,%r20
+\s*[a-f0-9]+:\s*62 fc c4 05 f7 c5 7b 00 00 00[ 	]+ctestnz \{dfv=of\} \$0x7b,%r21
+\s*[a-f0-9]+:\s*62 fc c4 06 f7 c6 7b 00 00 00[ 	]+ctestbe \{dfv=of\} \$0x7b,%r22
+\s*[a-f0-9]+:\s*62 fc c4 07 f7 c7 7b 00 00 00[ 	]+ctestnbe \{dfv=of\} \$0x7b,%r23
+\s*[a-f0-9]+:\s*62 dc c4 08 f7 c0 7b 00 00 00[ 	]+ctests \{dfv=of\} \$0x7b,%r24
+\s*[a-f0-9]+:\s*62 dc c4 09 f7 c1 7b 00 00 00[ 	]+ctestns \{dfv=of\} \$0x7b,%r25
+\s*[a-f0-9]+:\s*62 dc c4 0a f7 c2 7b 00 00 00[ 	]+ctestt \{dfv=of\} \$0x7b,%r26
+\s*[a-f0-9]+:\s*62 dc c4 0b f7 c3 7b 00 00 00[ 	]+ctestf \{dfv=of\} \$0x7b,%r27
+\s*[a-f0-9]+:\s*62 dc c4 0c f7 c4 7b 00 00 00[ 	]+ctestl \{dfv=of\} \$0x7b,%r28
+\s*[a-f0-9]+:\s*62 dc c4 0d f7 c5 7b 00 00 00[ 	]+ctestnl \{dfv=of\} \$0x7b,%r29
+\s*[a-f0-9]+:\s*62 dc c4 0e f7 c6 7b 00 00 00[ 	]+ctestle \{dfv=of\} \$0x7b,%r30
+\s*[a-f0-9]+:\s*62 dc c4 0f f7 c7 7b 00 00 00[ 	]+ctestnle \{dfv=of\} \$0x7b,%r31
+\s*[a-f0-9]+:\s*62 d4 8c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbq \{dfv=cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 74 0d 02 39 f8[ 	]+ccmpb \{dfv=cf\} %r15w,%ax
+\s*[a-f0-9]+:\s*62 d4 8c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbq \{dfv=cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 74 0d 02 39 f8[ 	]+ccmpb \{dfv=cf\} %r15w,%ax
+\s*[a-f0-9]+:\s*62 54 0c 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=cf\}\s+0x123\(%r8,%rax,4\),%r15d
+\s*[a-f0-9]+:\s*62 d4 4d 02 83 ff 7b[ 	]+ccmpb \{dfv=of, cf\}\s+\$0x7b,%r15w
+\s*[a-f0-9]+:\s*62 d4 4c 02 80 bc 80 23 01 00 00 7b[ 	]+ccmpbb \{dfv=of, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 6d 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbw \{dfv=of, sf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 ec 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=of, sf, cf\} %r15,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 7d 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbw \{dfv=of, sf, zf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 fc 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbq \{dfv=of, sf, zf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 74 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbl \{dfv=of, sf, zf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 f4 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=of, sf, zf\} %r15,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 e4 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbq \{dfv=of, sf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 64 02 3a 84 80 23 01 00 00[ 	]+ccmpb \{dfv=of, sf\}\s+0x123\(%r8,%rax,4\),%r8b
+\s*[a-f0-9]+:\s*62 d4 5c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbl \{dfv=of, zf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 5c 02 38 84 80 23 01 00 00[ 	]+ccmpb \{dfv=of, zf, cf\} %r8b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 55 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbw \{dfv=of, zf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 74 54 02 38 c2[ 	]+ccmpb \{dfv=of, zf\} %r8b,%dl
+\s*[a-f0-9]+:\s*62 74 44 02 39 fa[ 	]+ccmpb \{dfv=of\} %r15d,%edx
+\s*[a-f0-9]+:\s*62 54 45 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=of\}\s+0x123\(%r8,%rax,4\),%r15w
+\s*[a-f0-9]+:\s*62 d4 2c 02 80 f8 7b[ 	]+ccmpb \{dfv=sf, cf\}\s+\$0x7b,%r8b
+\s*[a-f0-9]+:\s*62 54 2c 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, cf\} %r15d,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 ac 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, cf\}\s+0x123\(%r8,%rax,4\),%r15
+\s*[a-f0-9]+:\s*62 d4 3c 02 83 ff 7b[ 	]+ccmpb \{dfv=sf, zf, cf\}\s+\$0x7b,%r15d
+\s*[a-f0-9]+:\s*62 54 3d 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, zf, cf\}\s+0x123\(%r8,%rax,4\),%r15w
+\s*[a-f0-9]+:\s*62 d4 34 02 83 ff 7b[ 	]+ccmpb \{dfv=sf, zf\}\s+\$0x7b,%r15d
+\s*[a-f0-9]+:\s*62 54 34 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf, zf\} %r15d,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 a4 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbq \{dfv=sf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 a4 02 39 ff[ 	]+ccmpb \{dfv=sf\} %r15,%r15
+\s*[a-f0-9]+:\s*62 54 a4 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=sf\}\s+0x123\(%r8,%rax,4\),%r15
+\s*[a-f0-9]+:\s*62 d4 9c 02 83 ff 7b[ 	]+ccmpb \{dfv=zf, cf\}\s+\$0x7b,%r15
+\s*[a-f0-9]+:\s*62 d4 1c 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbl \{dfv=zf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 1d 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=zf, cf\} %r15w,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 94 02 83 ff 7b[ 	]+ccmpb \{dfv=zf\}\s+\$0x7b,%r15
+\s*[a-f0-9]+:\s*62 d4 15 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbw \{dfv=zf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 15 02 39 bc 80 23 01 00 00[ 	]+ccmpb \{dfv=zf\} %r15w,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 05 02 83 ff 7b[ 	]+ccmpb \{dfv=\}\s+\$0x7b,%r15w
+\s*[a-f0-9]+:\s*62 d4 04 02 83 bc 80 23 01 00 00 7b[ 	]+ccmpbl \{dfv=\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 04 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=\}\s+0x123\(%r8,%rax,4\),%r15d
+\s*[a-f0-9]+:\s*62 54 04 02 3b bc 80 23 01 00 00[ 	]+ccmpb \{dfv=\}\s+0x123\(%r8,%rax,4\),%r15d
+\s*[a-f0-9]+:\s*62 fc c4 00 83 f8 7b[ 	]+ccmpo \{dfv=of\} \$0x7b,%r16
+\s*[a-f0-9]+:\s*62 fc c4 01 83 f9 7b[ 	]+ccmpno \{dfv=of\} \$0x7b,%r17
+\s*[a-f0-9]+:\s*62 fc c4 02 83 fa 7b[ 	]+ccmpb \{dfv=of\} \$0x7b,%r18
+\s*[a-f0-9]+:\s*62 fc c4 03 83 fb 7b[ 	]+ccmpnb \{dfv=of\} \$0x7b,%r19
+\s*[a-f0-9]+:\s*62 fc c4 04 83 fc 7b[ 	]+ccmpz \{dfv=of\} \$0x7b,%r20
+\s*[a-f0-9]+:\s*62 fc c4 05 83 fd 7b[ 	]+ccmpnz \{dfv=of\} \$0x7b,%r21
+\s*[a-f0-9]+:\s*62 fc c4 06 83 fe 7b[ 	]+ccmpbe \{dfv=of\} \$0x7b,%r22
+\s*[a-f0-9]+:\s*62 fc c4 07 83 ff 7b[ 	]+ccmpnbe \{dfv=of\} \$0x7b,%r23
+\s*[a-f0-9]+:\s*62 dc c4 08 83 f8 7b[ 	]+ccmps \{dfv=of\} \$0x7b,%r24
+\s*[a-f0-9]+:\s*62 dc c4 09 83 f9 7b[ 	]+ccmpns \{dfv=of\} \$0x7b,%r25
+\s*[a-f0-9]+:\s*62 dc c4 0a 83 fa 7b[ 	]+ccmpt \{dfv=of\} \$0x7b,%r26
+\s*[a-f0-9]+:\s*62 dc c4 0b 83 fb 7b[ 	]+ccmpf \{dfv=of\} \$0x7b,%r27
+\s*[a-f0-9]+:\s*62 dc c4 0c 83 fc 7b[ 	]+ccmpl \{dfv=of\} \$0x7b,%r28
+\s*[a-f0-9]+:\s*62 dc c4 0d 83 fd 7b[ 	]+ccmpnl \{dfv=of\} \$0x7b,%r29
+\s*[a-f0-9]+:\s*62 dc c4 0e 83 fe 7b[ 	]+ccmple \{dfv=of\} \$0x7b,%r30
+\s*[a-f0-9]+:\s*62 dc c4 0f 83 ff 7b[ 	]+ccmpnle \{dfv=of\} \$0x7b,%r31
+\s*[a-f0-9]+:\s*62 d4 8c 02 f7 c7 7b 00 00 00[ 	]+ctestb \{dfv=cf\}\s+\$0x7b,%r15
+\s*[a-f0-9]+:\s*62 d4 0d 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestbw \{dfv=cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 8c 02 f7 c7 7b 00 00 00[ 	]+ctestb \{dfv=cf\}\s+\$0x7b,%r15
+\s*[a-f0-9]+:\s*62 d4 0d 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestbw \{dfv=cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 4c 02 f6 84 80 23 01 00 00 7b[ 	]+ctestbb \{dfv=of, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 cc 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, cf\} %r15,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 ec 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbq \{dfv=of, sf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 7c 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbl \{dfv=of, sf, zf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 75 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestbw \{dfv=of, sf, zf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 64 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbl \{dfv=of, sf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 65 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, sf\} %r15w,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 5d 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestbw \{dfv=of, zf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 5d 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, zf, cf\} %r15w,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 54 02 f6 84 80 23 01 00 00 7b[ 	]+ctestbb \{dfv=of, zf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 d4 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of, zf\} %r15,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 44 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=of\} %r15d,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 44 02 84 84 80 23 01 00 00[ 	]+ctestb \{dfv=of\} %r8b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 2c 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbl \{dfv=sf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 74 2c 02 85 fa[ 	]+ctestb \{dfv=sf, cf\} %r15d,%edx
+\s*[a-f0-9]+:\s*62 54 3c 02 85 bc 80 23 01 00 00[ 	]+ctestb \{dfv=sf, zf, cf\} %r15d,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 74 3c 02 84 c2[ 	]+ctestb \{dfv=sf, zf, cf\} %r8b,%dl
+\s*[a-f0-9]+:\s*62 d4 35 02 f7 c7 7b 00[ 	]+ctestb \{dfv=sf, zf\}\s+\$0x7b,%r15w
+\s*[a-f0-9]+:\s*62 d4 b4 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbq \{dfv=sf, zf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 24 02 f7 c7 7b 00 00 00[ 	]+ctestb \{dfv=sf\}\s+\$0x7b,%r15d
+\s*[a-f0-9]+:\s*62 d4 25 02 f7 84 80 23 01 00 00 7b 00[ 	]+ctestbw \{dfv=sf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 1c 02 f6 c0 7b[ 	]+ctestb \{dfv=zf, cf\}\s+\$0x7b,%r8b
+\s*[a-f0-9]+:\s*62 d4 9c 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbq \{dfv=zf, cf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 d4 14 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbl \{dfv=zf\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 54 94 02 85 ff[ 	]+ctestb \{dfv=zf\} %r15,%r15
+\s*[a-f0-9]+:\s*62 d4 84 02 f7 84 80 23 01 00 00 7b 00 00 00[ 	]+ctestbq \{dfv=\}\s+\$0x7b,0x123\(%r8,%rax,4\)
+\s*[a-f0-9]+:\s*62 74 05 02 85 f8[ 	]+ctestb \{dfv=\} %r15w,%ax
+\s*[a-f0-9]+:\s*62 74 05 02 85 f8[ 	]+ctestb \{dfv=\} %r15w,%ax
+\s*[a-f0-9]+:\s*62 fc c4 00 f7 c0 7b 00 00 00[ 	]+ctesto \{dfv=of\} \$0x7b,%r16
+\s*[a-f0-9]+:\s*62 fc c4 01 f7 c1 7b 00 00 00[ 	]+ctestno \{dfv=of\} \$0x7b,%r17
+\s*[a-f0-9]+:\s*62 fc c4 02 f7 c2 7b 00 00 00[ 	]+ctestb \{dfv=of\} \$0x7b,%r18
+\s*[a-f0-9]+:\s*62 fc c4 03 f7 c3 7b 00 00 00[ 	]+ctestnb \{dfv=of\} \$0x7b,%r19
+\s*[a-f0-9]+:\s*62 fc c4 04 f7 c4 7b 00 00 00[ 	]+ctestz \{dfv=of\} \$0x7b,%r20
+\s*[a-f0-9]+:\s*62 fc c4 05 f7 c5 7b 00 00 00[ 	]+ctestnz \{dfv=of\} \$0x7b,%r21
+\s*[a-f0-9]+:\s*62 fc c4 06 f7 c6 7b 00 00 00[ 	]+ctestbe \{dfv=of\} \$0x7b,%r22
+\s*[a-f0-9]+:\s*62 fc c4 07 f7 c7 7b 00 00 00[ 	]+ctestnbe \{dfv=of\} \$0x7b,%r23
+\s*[a-f0-9]+:\s*62 dc c4 08 f7 c0 7b 00 00 00[ 	]+ctests \{dfv=of\} \$0x7b,%r24
+\s*[a-f0-9]+:\s*62 dc c4 09 f7 c1 7b 00 00 00[ 	]+ctestns \{dfv=of\} \$0x7b,%r25
+\s*[a-f0-9]+:\s*62 dc c4 0a f7 c2 7b 00 00 00[ 	]+ctestt \{dfv=of\} \$0x7b,%r26
+\s*[a-f0-9]+:\s*62 dc c4 0b f7 c3 7b 00 00 00[ 	]+ctestf \{dfv=of\} \$0x7b,%r27
+\s*[a-f0-9]+:\s*62 dc c4 0c f7 c4 7b 00 00 00[ 	]+ctestl \{dfv=of\} \$0x7b,%r28
+\s*[a-f0-9]+:\s*62 dc c4 0d f7 c5 7b 00 00 00[ 	]+ctestnl \{dfv=of\} \$0x7b,%r29
+\s*[a-f0-9]+:\s*62 dc c4 0e f7 c6 7b 00 00 00[ 	]+ctestle \{dfv=of\} \$0x7b,%r30
+\s*[a-f0-9]+:\s*62 dc c4 0f f7 c7 7b 00 00 00[ 	]+ctestnle \{dfv=of\} \$0x7b,%r31
diff --git a/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest.s b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest.s
new file mode 100644
index 00000000000..28c9aaa01c0
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-apx-ccmp-ctest.s
@@ -0,0 +1,217 @@ 
+# Check 64bit APX_F CCMP and CTEST instructions
+
+ .text
+_start:
+	ccmpbq {dfv=pf} $0x7b,0x123(%r8,%rax,4)
+	ccmpb  {dfv=pf} %r15w,%ax
+	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
+	ccmpb  {dfv=af} 0x123(%r8,%rax,4),%r15d
+	ccmpo   {dfv=of} $0x7b,%r16
+	ccmpno  {dfv=of} $0x7b,%r17
+	ccmpb   {dfv=of} $0x7b,%r18
+	ccmpnb  {dfv=of} $0x7b,%r19
+	ccmpz   {dfv=of} $0x7b,%r20
+	ccmpnz  {dfv=of} $0x7b,%r21
+	ccmpbe  {dfv=of} $0x7b,%r22
+	ccmpnbe {dfv=of} $0x7b,%r23
+	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
+	ccmpnl  {dfv=of} $0x7b,%r29
+	ccmple  {dfv=of} $0x7b,%r30
+	ccmpnle {dfv=of} $0x7b,%r31
+	ctestb  {dfv=pf} $0x7b,%r15
+	ctestbw {dfv=pf} $0x7b,0x123(%r8,%rax,4)
+	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
+	ctestb  {dfv=af} %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
+
+.intel_syntax noprefix
+	ccmpb {dfv=pf} QWORD PTR [r8+rax*4+0x123],0x7b
+	ccmpb {dfv=pf} ax,r15w
+	ccmpb {dfv=cf} QWORD PTR [r8+rax*4+0x123],0x7b
+	ccmpb {dfv=cf} ax,r15w
+	ccmpb {dfv=cf} r15d,DWORD PTR [r8+rax*4+0x123]
+	ccmpb {dfv=of, cf} r15w,0x7b
+	ccmpb {dfv=of, cf} BYTE PTR [r8+rax*4+0x123],0x7b
+	ccmpb {dfv=of, sf, cf} WORD PTR [r8+rax*4+0x123],0x7b
+	ccmpb {dfv=of, sf, cf} QWORD PTR [r8+rax*4+0x123],r15
+	ccmpb {dfv=of, sf, zf, cf} WORD PTR [r8+rax*4+0x123],0x7b
+	ccmpb {dfv=of, sf, zf, cf} QWORD PTR [r8+rax*4+0x123],0x7b
+	ccmpb {dfv=of, sf, zf} DWORD PTR [r8+rax*4+0x123],0x7b
+	ccmpb {dfv=of, sf, zf} QWORD PTR [r8+rax*4+0x123],r15
+	ccmpb {dfv=of, sf} QWORD PTR [r8+rax*4+0x123],0x7b
+	ccmpb {dfv=of, sf} r8b,BYTE PTR [r8+rax*4+0x123]
+	ccmpb {dfv=of, zf, cf} DWORD PTR [r8+rax*4+0x123],0x7b
+	ccmpb {dfv=of, zf, cf} BYTE PTR [r8+rax*4+0x123],r8b
+	ccmpb {dfv=of, zf} WORD PTR [r8+rax*4+0x123],0x7b
+	ccmpb {dfv=of, zf} dl,r8b
+	ccmpb {dfv=of} edx,r15d
+	ccmpb {dfv=of} r15w,WORD PTR [r8+rax*4+0x123]
+	ccmpb {dfv=sf, cf} r8b,0x7b
+	ccmpb {dfv=sf, cf} DWORD PTR [r8+rax*4+0x123],r15d
+	ccmpb {dfv=sf, cf} r15,QWORD PTR [r8+rax*4+0x123]
+	ccmpb {dfv=sf, zf, cf} r15d,0x7b
+	ccmpb {dfv=sf, zf, cf} r15w,WORD PTR [r8+rax*4+0x123]
+	ccmpb {dfv=sf, zf} r15d,0x7b
+	ccmpb {dfv=sf, zf} DWORD PTR [r8+rax*4+0x123],r15d
+	ccmpb {dfv=sf} QWORD PTR [r8+rax*4+0x123],0x7b
+	ccmpb {dfv=sf} r15,r15
+	ccmpb {dfv=sf} r15,QWORD PTR [r8+rax*4+0x123]
+	ccmpb {dfv=zf, cf} r15,0x7b
+	ccmpb {dfv=zf, cf} DWORD PTR [r8+rax*4+0x123],0x7b
+	ccmpb {dfv=zf, cf} WORD PTR [r8+rax*4+0x123],r15w
+	ccmpb {dfv=zf} r15,0x7b
+	ccmpb {dfv=zf} WORD PTR [r8+rax*4+0x123],0x7b
+	ccmpb {dfv=zf} WORD PTR [r8+rax*4+0x123],r15w
+	ccmpb {dfv=} r15w,0x7b
+	ccmpb {dfv=} DWORD PTR [r8+rax*4+0x123],0x7b
+	ccmpb {dfv=} r15d,DWORD PTR [r8+rax*4+0x123]
+	ccmpb {dfv=af} r15d,DWORD PTR [r8+rax*4+0x123]
+	ccmpo   {dfv=of} r16,0x7b
+	ccmpno  {dfv=of} r17,0x7b
+	ccmpb   {dfv=of} r18,0x7b
+	ccmpnb  {dfv=of} r19,0x7b
+	ccmpz   {dfv=of} r20,0x7b
+	ccmpnz  {dfv=of} r21,0x7b
+	ccmpbe  {dfv=of} r22,0x7b
+	ccmpnbe {dfv=of} r23,0x7b
+	ccmps   {dfv=of} r24,0x7b
+	ccmpns  {dfv=of} r25,0x7b
+	ccmpt   {dfv=of} r26,0x7b
+	ccmpf   {dfv=of} r27,0x7b
+	ccmpl   {dfv=of} r28,0x7b
+	ccmpnl  {dfv=of} r29,0x7b
+	ccmple  {dfv=of} r30,0x7b
+	ccmpnle {dfv=of} r31,0x7b
+	ctestb  {dfv=pf} r15,0x7b
+	ctestb  {dfv=pf} WORD PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=cf} r15,0x7b
+	ctestb  {dfv=cf} WORD PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=of, cf} BYTE PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=of, cf} QWORD PTR [r8+rax*4+0x123],r15
+	ctestb  {dfv=of, sf, cf} QWORD PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=of, sf, zf, cf} DWORD PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=of, sf, zf} WORD PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=of, sf} DWORD PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=of, sf} WORD PTR [r8+rax*4+0x123],r15w
+	ctestb  {dfv=of, zf, cf} WORD PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=of, zf, cf} WORD PTR [r8+rax*4+0x123],r15w
+	ctestb  {dfv=of, zf} BYTE PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=of, zf} QWORD PTR [r8+rax*4+0x123],r15
+	ctestb  {dfv=of} DWORD PTR [r8+rax*4+0x123],r15d
+	ctestb  {dfv=of} BYTE PTR [r8+rax*4+0x123],r8b
+	ctestb  {dfv=sf, cf} DWORD PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=sf, cf} edx,r15d
+	ctestb  {dfv=sf, zf, cf} DWORD PTR [r8+rax*4+0x123],r15d
+	ctestb  {dfv=sf, zf, cf} dl,r8b
+	ctestb  {dfv=sf, zf} r15w,0x7b
+	ctestb  {dfv=sf, zf} QWORD PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=sf} r15d,0x7b
+	ctestb  {dfv=sf} WORD PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=zf, cf} r8b,0x7b
+	ctestb  {dfv=zf, cf} QWORD PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=zf} DWORD PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=zf} r15,r15
+	ctestb  {dfv=} QWORD PTR [r8+rax*4+0x123],0x7b
+	ctestb  {dfv=} ax,r15w
+	ctestb  {dfv=af} ax,r15w
+	ctesto   {dfv=of} r16,0x7b
+	ctestno  {dfv=of} r17,0x7b
+	ctestb   {dfv=of} r18,0x7b
+	ctestnb  {dfv=of} r19,0x7b
+	ctestz   {dfv=of} r20,0x7b
+	ctestnz  {dfv=of} r21,0x7b
+	ctestbe  {dfv=of} r22,0x7b
+	ctestnbe {dfv=of} r23,0x7b
+	ctests   {dfv=of} r24,0x7b
+	ctestns  {dfv=of} r25,0x7b
+	ctestt   {dfv=of} r26,0x7b
+	ctestf   {dfv=of} r27,0x7b
+	ctestl   {dfv=of} r28,0x7b
+	ctestnl  {dfv=of} r29,0x7b
+	ctestle  {dfv=of} r30,0x7b
+	ctestnle {dfv=of} r31,0x7b
+
diff --git a/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.d b/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.d
index 6330367194c..ecd878ee116 100644
--- a/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.d
+++ b/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.d
@@ -15,13 +15,13 @@  Disassembly of section .text:
 [ 	]*[a-f0-9]+:[ 	]+62 e2 f9 41 91 84[ 	]+vpgatherqq \(bad\),%zmm16\{%k1\}
 [ 	]*[a-f0-9]+:[ 	]+cd ff[ 	]+int    \$0xff
 [ 	]*[a-f0-9]+:[ 	]+62 fd 7d 08 60[ 	]+\(bad\)
+[ 	]*[a-f0-9]+:[ 	]+c7[ 	]+.*
+[ 	]*[a-f0-9]+:[ 	]+62 fc 7d 09 60[ 	]+\(bad\).*
 [ 	]*[a-f0-9]+:[ 	]+c7[ 	]+\(bad\)
-[ 	]*[a-f0-9]+:[ 	]+62 fc 7d[ 	]+\(bad\).*
-[ 	]*[a-f0-9]+:[ 	]+09 60 c7[ 	]+or     %esp,-0x39\(%rax\)
-[ 	]*[a-f0-9]+:[ 	]+62 fc 7d[ 	]+\(bad\).*
-[ 	]*[a-f0-9]+:[ 	]+28 60 c7[ 	]+.*
-[ 	]*[a-f0-9]+:[ 	]+62 fc 7d[ 	]+\(bad\).*
-[ 	]*[a-f0-9]+:[ 	]+8b 60 c7[ 	]+.*
+[ 	]*[a-f0-9]+:[ 	]+62 fc 7d 28 60[ 	]+\(bad\).*
+[ 	]*[a-f0-9]+:[ 	]+c7[ 	]+.*
+[ 	]*[a-f0-9]+:[ 	]+62 fc 7d 8b 60[ 	]+\(bad\).*
+[ 	]*[a-f0-9]+:[ 	]+c7[ 	]+.*
 [ 	]*[a-f0-9]+:[ 	]+62 f2 fc 09 f5[ 	]+\(bad\).*
 [ 	]*[a-f0-9]+:[ 	]+0c 18[ 	]+or.*
 [ 	]*[a-f0-9]+:[ 	]+62 f2 fc 28 f5[ 	]+\(bad\)
@@ -30,15 +30,15 @@  Disassembly of section .text:
 [ 	]*[a-f0-9]+:[ 	]+0c 18[ 	]+or.*
 [ 	]*[a-f0-9]+:[ 	]+62 f2 fc 18 f5[ 	]+\(bad\)
 [ 	]*[a-f0-9]+:[ 	]+0c 18[ 	]+or.*
-[ 	]*[a-f0-9]+:[ 	]+62 f4 e4[ 	]+\(bad\)
-[ 	]*[a-f0-9]+:[ 	]+08 ff[ 	]+.*
+[ 	]*[a-f0-9]+:[ 	]+62 f4 e4 08 ff[ 	]+\(bad\)
 [ 	]*[a-f0-9]+:[ 	]+04 08[ 	]+.*
-[ 	]*[a-f0-9]+:[ 	]+62 f4 3c[ 	]+\(bad\)
-[ 	]*[a-f0-9]+:[ 	]+08 8f c0 ff ff ff[ 	]+or.*
+[ 	]*[a-f0-9]+:[ 	]+62 f4 3c 08 8f[ 	]+\(bad\)
+[ 	]*[a-f0-9]+:[ 	]+c0 ff ff[ 	]+.*
 [ 	]*[a-f0-9]+:[ 	]+62 74 7c 18 8f c0[ 	]+pop2   %rax,\(bad\)
 [ 	]*[a-f0-9]+:[ 	]+62 d4 24 18 8f[ 	]+\(bad\)
 [ 	]*[a-f0-9]+:[ 	]+c3[ 	]+.*
 [ 	]*[a-f0-9]+:[ 	]+62 fc 7d 0c 60 c7[ 	]+movbe  \{bad-nf\},%r23w,%ax
 [ 	]*[a-f0-9]+:[ 	]+62 fc 79 08 60[ 	]+\(bad\)
-[ 	]*[a-f0-9]+:[ 	]+c2[ 	]+.*
+[ 	]*[a-f0-9]+:[ 	]+c2 ff ff[ 	 ]+.*
+[ 	]*[a-f0-9]+:[ 	]+62 d4 fc 18 38 d7[ 	]+ccmps \{dfv=of, sf, zf, cf\}\(bad\) %dl,%r15b
 #pass
diff --git a/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.s b/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.s
index cbf34515bab..ad1ae6ecf81 100644
--- a/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.s
+++ b/gas/testsuite/gas/i386/x86-64-apx-evex-promoted-bad.s
@@ -43,7 +43,7 @@  _start:
 
 	# pop2 %rax, %r8 set EVEX.ND=0.
 	.byte 0x62, 0xf4, 0x3c, 0x08, 0x8f, 0xc0
-	.byte 0xff, 0xff, 0xff
+	.byte 0xff, 0xff
 
 	# pop2 %rax, %r8 set EVEX.vvvv = 1111.
 	.insn EVEX.L0.M4.W0 0x8f,  %rax, {rn-sae},%r8
@@ -56,3 +56,7 @@  _start:
 
 	# EVEX_MAP4 movbe %r18w,%ax set EVEX.P[10] = 0.
 	.byte 0x62, 0xfc, 0x79, 0x08, 0x60, 0xc2
+	.byte 0xff, 0xff
+
+	# ccmps {dfv=of,sf,zf,cf} %r15, %rdx set EVEX.ND=0.
+	.insn EVEX.L0.M4.W1 0x38, %r15, {rn-sae},%rdx
diff --git a/gas/testsuite/gas/i386/x86-64.exp b/gas/testsuite/gas/i386/x86-64.exp
index ef1ad2dfe8a..c6c01d3e322 100644
--- a/gas/testsuite/gas/i386/x86-64.exp
+++ b/gas/testsuite/gas/i386/x86-64.exp
@@ -352,6 +352,9 @@  run_dump_test "x86-64-avx512dq-rcigrne"
 run_dump_test "x86-64-apx-push2pop2"
 run_dump_test "x86-64-apx-push2pop2-intel"
 run_list_test "x86-64-apx-push2pop2-inval"
+run_dump_test "x86-64-apx-ccmp-ctest"
+run_dump_test "x86-64-apx-ccmp-ctest-intel"
+run_list_test "x86-64-apx-ccmp-ctest-inval"
 run_dump_test "x86-64-apx-pushp-popp"
 run_dump_test "x86-64-apx-pushp-popp-intel"
 run_list_test "x86-64-apx-pushp-popp-inval"
diff --git a/opcodes/i386-dis-evex-reg.h b/opcodes/i386-dis-evex-reg.h
index 7408295f8e5..6b0b66b71a7 100644
--- a/opcodes/i386-dis-evex-reg.h
+++ b/opcodes/i386-dis-evex-reg.h
@@ -58,6 +58,7 @@ 
     { "%NFandA",	{ VexGb, Eb, Ib }, NO_PREFIX },
     { "%NFsubA",	{ VexGb, Eb, Ib }, NO_PREFIX },
     { "%NFxorA",	{ VexGb, Eb, Ib }, NO_PREFIX },
+    { "%NPccmpA",	{ SCC_And_OSZC_Flags, Eb, Ib }, NO_PREFIX },
   },
   /* REG_EVEX_MAP4_81 */
   {
@@ -68,6 +69,7 @@ 
     { "%NFandQ",	{ VexGv, Ev, Iv }, PREFIX_NP_OR_DATA },
     { "%NFsubQ",	{ VexGv, Ev, Iv }, PREFIX_NP_OR_DATA },
     { "%NFxorQ",	{ VexGv, Ev, Iv }, PREFIX_NP_OR_DATA },
+    { "%NPccmpQ",	{ SCC_And_OSZC_Flags, Ev, Iv }, PREFIX_NP_OR_DATA },
   },
   /* REG_EVEX_MAP4_83 */
   {
@@ -78,6 +80,7 @@ 
     { "%NFandQ",	{ VexGv, Ev, sIb }, PREFIX_NP_OR_DATA },
     { "%NFsubQ",	{ VexGv, Ev, sIb }, PREFIX_NP_OR_DATA },
     { "%NFxorQ",	{ VexGv, Ev, sIb }, PREFIX_NP_OR_DATA },
+    { "%NPccmpQ",	{ SCC_And_OSZC_Flags, Ev, sIb }, PREFIX_NP_OR_DATA },
   },
   /* REG_EVEX_MAP4_8F */
   {
@@ -85,8 +88,8 @@ 
   },
   /* REG_EVEX_MAP4_F6 */
   {
-    { Bad_Opcode },
-    { Bad_Opcode },
+    { "%NPctestA",  { SCC_And_OSZC_Flags, Eb, Ib }, NO_PREFIX },
+    { "%NPctestA",  { SCC_And_OSZC_Flags, Eb, Ib }, NO_PREFIX },
     { "notA",	{ VexGb, Eb }, NO_PREFIX },
     { "%NFnegA",	{ VexGb, Eb }, NO_PREFIX },
     { "%NFmulA",	{ Eb }, NO_PREFIX },
@@ -96,8 +99,8 @@ 
   },
   /* REG_EVEX_MAP4_F7 */
   {
-    { Bad_Opcode },
-    { Bad_Opcode },
+    { "%NPctestQ",  { SCC_And_OSZC_Flags, Ev, Iv }, PREFIX_NP_OR_DATA },
+    { "%NPctestQ",  { SCC_And_OSZC_Flags, Ev, Iv }, PREFIX_NP_OR_DATA },
     { "notQ",	{ VexGv, Ev }, PREFIX_NP_OR_DATA },
     { "%NFnegQ",	{ VexGv, Ev }, PREFIX_NP_OR_DATA },
     { "%NFmulQ",	{ Ev }, PREFIX_NP_OR_DATA },
diff --git a/opcodes/i386-dis-evex.h b/opcodes/i386-dis-evex.h
index ebb3cc20aea..dc9937806d0 100644
--- a/opcodes/i386-dis-evex.h
+++ b/opcodes/i386-dis-evex.h
@@ -938,10 +938,10 @@  static const struct dis386 evex_table[][256] = {
     { Bad_Opcode },
     { Bad_Opcode },
     /* 38 */
-    { Bad_Opcode },
-    { Bad_Opcode },
-    { Bad_Opcode },
-    { Bad_Opcode },
+    { "%NPccmpB",		{ SCC_And_OSZC_Flags, Eb, Gb }, 0 },
+    { "%NPccmpS",		{ SCC_And_OSZC_Flags, Ev, Gv }, PREFIX_NP_OR_DATA },
+    { "%NPccmpB",		{ SCC_And_OSZC_Flags, Gb, EbS }, 0 },
+    { "%NPccmpS",		{ SCC_And_OSZC_Flags, Gv, EvS }, PREFIX_NP_OR_DATA },
     { Bad_Opcode },
     { Bad_Opcode },
     { Bad_Opcode },
@@ -1023,8 +1023,8 @@  static const struct dis386 evex_table[][256] = {
     { REG_TABLE (REG_EVEX_MAP4_81) },
     { Bad_Opcode },
     { REG_TABLE (REG_EVEX_MAP4_83) },
-    { Bad_Opcode },
-    { Bad_Opcode },
+    { "%NPctestB",	      { SCC_And_OSZC_Flags, Eb, Gb }, NO_PREFIX },
+    { "%NPctestS",	      { SCC_And_OSZC_Flags, Ev, Gv }, PREFIX_NP_OR_DATA },
     { Bad_Opcode },
     { Bad_Opcode },
     /* 88 */
diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c
index 46441974bb8..6ecd4bc417e 100644
--- a/opcodes/i386-dis.c
+++ b/opcodes/i386-dis.c
@@ -107,6 +107,7 @@  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 bool JMPABS_Fixup (instr_info *, int, int);
+static bool SCC_And_OSZC_Flags_Fixup (instr_info *, int, int);
 
 static void ATTRIBUTE_PRINTF_3 i386_dis_printf (const disassemble_info *,
 						enum disassembler_style,
@@ -218,6 +219,7 @@  struct instr_info
     int length;
     int prefix;
     int mask_register_specifier;
+    int scc;
     int ll;
     bool w;
     bool evex;
@@ -596,6 +598,7 @@  fetch_error (const instr_info *ins)
 #define PCLMUL { PCLMUL_Fixup, 0 }
 #define VPCMP { VPCMP_Fixup, 0 }
 #define VPCOM { VPCOM_Fixup, 0 }
+#define SCC_And_OSZC_Flags { SCC_And_OSZC_Flags_Fixup, 0 }
 
 #define EXxEVexR { OP_Rounding, evex_rounding_mode }
 #define EXxEVexR64 { OP_Rounding, evex_rounding_64_mode }
@@ -1832,6 +1835,8 @@  struct dis386 {
 	   instruction.
    "NF" => print "{nf} " pseudo prefix when EVEX.NF = 1 and print "{evex} "
 	   pseudo prefix when instructions without NF, EGPR and VVVV,
+   "NP" => don't print "{evex} " pseudo prefix for some special instructions
+	   in MAP4.
    "ZU" => print 'zu' if EVEX.ZU=1.
    "YK" keep unused, to avoid ambiguity with the combined use of Y and K.
    "YX" keep unused, to avoid ambiguity with the combined use of Y and X.
@@ -9164,6 +9169,7 @@  get_valid_dis386 (const struct dis386 *dp, instr_info *ins)
 
       ins->vex.v = *ins->codep & 0x8;
       ins->vex.mask_register_specifier = *ins->codep & 0x7;
+      ins->vex.scc = *ins->codep & 0xf;
       ins->vex.zeroing = *ins->codep & 0x80;
       /* Set the NF bit for EVEX-Promoted instructions, this bit will be cleared
 	 when it's an evex_default one.  */
@@ -9181,22 +9187,8 @@  get_valid_dis386 (const struct dis386 *dp, instr_info *ins)
 	  ins->rex2 &= ~REX_R;
 	}
 
-      /* 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.nd
-	  && (ins->vex.register_specifier || !ins->vex.v))
-	return &bad_opcode;
-
       ins->need_vex = 4;
 
-      /* EVEX from legacy instructions require that EVEX.z, EVEX.L’L and the
-	 lower 2 bits of EVEX.aaa must be 0.  */
-      if (ins->evex_type == evex_from_legacy
-	  && ((ins->vex.mask_register_specifier & 0x3) != 0
-	      || ins->vex.ll != 0
-	      || ins->vex.zeroing != 0))
-	return &bad_opcode;
-
       ins->codep++;
       vindex = *ins->codep++;
       if (vex_table_index != EVEX_MAP7)
@@ -9746,6 +9738,32 @@  print_insn (bfd_vma pc, disassemble_info *info, int intel_syntax)
       }
   }
 
+  /* The purpose of placing the check here is to wait for the EVEX prefix for
+     conditional CMP and TEST to be consumed and cleared, and then make a
+     unified judgment. Because they are both in map4, we can not distinguish
+     EVEX prefix for conditional CMP and TEST from others during the
+     EVEX prefix stage of parsing.  */
+  /* 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.nd
+      && (ins.vex.register_specifier || !ins.vex.v))
+    {
+      i386_dis_printf (info, dis_style_text, "(bad)");
+      ret = ins.end_codep - priv.the_buffer;
+      goto out;
+    }
+
+  /* EVEX from legacy instructions require that EVEX.z, EVEX.L’L and the
+     lower 2 bits of EVEX.aaa must be 0.  */
+  if (ins.evex_type == evex_from_legacy
+      && ((ins.vex.mask_register_specifier & 0x3) != 0
+	  || ins.vex.ll != 0 || ins.vex.zeroing != 0))
+    {
+      i386_dis_printf (info, dis_style_text, "(bad)");
+      ret = ins.end_codep - priv.the_buffer;
+      goto out;
+    }
+
   /* If VEX.vvvv and EVEX.vvvv are unused, they must be all 1s, which
      are all 0s in inverted form.  */
   if (ins.need_vex && ins.vex.register_specifier != 0)
@@ -10787,6 +10805,9 @@  putop (instr_info *ins, const char *in_template, int sizeflag)
 		    }
 		}
 	    }
+	  else if (l == 1 && last[0] == 'N')
+	      /* Skip printing {evex} for some special instructions in MAP4.  */
+	      evex_printed = true;
 	  else
 	    abort ();
 	  break;
@@ -14089,3 +14110,55 @@  JMPABS_Fixup (instr_info *ins, int bytemode, int sizeflag)
     return OP_IMREG (ins, bytemode, sizeflag);
   return OP_OFF64 (ins, bytemode, sizeflag);
 }
+
+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}"
+};
+
+static const char *const scc_suffix[16] = {
+  "o", "no", "b", "nb", "z", "nz", "be", "nbe", "s", "ns", "t", "f",
+  "l", "nl", "le", "nle"
+};
+static bool
+SCC_And_OSZC_Flags_Fixup (instr_info *ins, int bytemode ATTRIBUTE_UNUSED,
+		 int sizeflag ATTRIBUTE_UNUSED)
+{
+  ins->obufp = ins->mnemonicendp;
+
+  /* Get oszc flags value from register_specifier.  */
+  int oszc_value = ~ins->vex.register_specifier & 0xf;
+
+  /* If ccmp and ctest already have suffixes, they should be moved after the
+     scc suffix.  */
+  if (ins->obufp[-1] != 'p' && ins->obufp[-1] != 't')
+    {
+      char suffix = ins->obufp[-1];
+      ins->obufp--;
+      ins->obufp = stpcpy (ins->obufp, scc_suffix[ins->vex.scc]);
+      *ins->obufp++ = suffix;
+    }
+  else
+    /* Add scc suffix.  */
+    ins->obufp = stpcpy (ins->obufp, scc_suffix[ins->vex.scc]);
+
+  /* Add { dfv=of, sf, zf, cf} flags.  */
+  ins->obufp = stpcpy (ins->obufp, oszc_flags[oszc_value]);
+
+  /* For CCMP and CTEST, the ND bit is required to be set to 0.  */
+  if (ins->vex.nd)
+    {
+      oappend (ins, "(bad)");
+      return true;
+    }
+
+  /* These bits have been consumed and should be cleared.  */
+  ins->vex.v = 1;
+  ins->vex.nf = false;
+  ins->vex.mask_register_specifier = 0;
+  ins->vex.register_specifier = 0;
+
+  return true;
+}
diff --git a/opcodes/i386-gen.c b/opcodes/i386-gen.c
index fb4e78df3a2..94cf4eea8f8 100644
--- a/opcodes/i386-gen.c
+++ b/opcodes/i386-gen.c
@@ -492,6 +492,7 @@  static bitfield opcode_modifiers[] =
   BITFIELD (NF),
   BITFIELD (Rex2),
   BITFIELD (ZU),
+  BITFIELD (SCC),
 };
 
 #define CLASS(n) #n, n
diff --git a/opcodes/i386-opc.h b/opcodes/i386-opc.h
index b63ad7c13f5..ec253b9da1b 100644
--- a/opcodes/i386-opc.h
+++ b/opcodes/i386-opc.h
@@ -757,6 +757,9 @@  enum
   /* Support zero upper */
   ZU,
 
+  /* Support zero upper */
+  SCC,
+
   /* The last bitfield in i386_opcode_modifier.  */
   Opcode_Modifier_Num
 };
@@ -805,6 +808,7 @@  typedef struct i386_opcode_modifier
   unsigned int nf:1;
   unsigned int rex2:1;
   unsigned int zu:1;
+  unsigned int scc:1;
 } i386_opcode_modifier;
 
 /* Operand classes.  */
diff --git a/opcodes/i386-opc.tbl b/opcodes/i386-opc.tbl
index faaa92c8d11..d099615eec2 100644
--- a/opcodes/i386-opc.tbl
+++ b/opcodes/i386-opc.tbl
@@ -341,9 +341,19 @@  cmp, 0x83/7, 0, Modrm|No_bSuf|No_sSuf, { Imm8S, Reg16|Reg32|Reg64|Unspecified|Ba
 cmp, 0x3c, 0, W|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Acc|Byte|Word|Dword|Qword }
 cmp, 0x80/7, 0, W|Modrm|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
 
+<cc:opc, o:0, no:1, b:2, c:2, nae:2, nb:3, nc:3, ae:3, e:4, z:4, ne:5, nz:5, be:6, na:6, nbe:7, a:7, +
+         s:8, ns:9, t:a, p:a, pe:a, f:b, np:b, po:b, l:c, nge:c, nl:d, ge:d, le:e, ng:e, nle:f, g:f>
+
+ccmp<cc>, 0x380<cc:opc>, APX_F, D|W|CheckOperandSize|Modrm|EVexMap4|SCC|No_sSuf, { Reg8|Reg16|Reg32|Reg64, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
+ccmp<cc>, 0x830<cc:opc>/7, APX_F, Modrm|EVexMap4|SCC|No_bSuf|No_sSuf, { Imm8S, Reg16|Reg32|Reg64|Unspecified|BaseIndex }
+ccmp<cc>, 0x800<cc:opc>/7, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
+
 test, 0x84, 0, D|W|C|CheckOperandSize|Modrm|No_sSuf, { Reg8|Reg16|Reg32|Reg64, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
 test, 0xa8, 0, W|No_sSuf|Optimize, { Imm8|Imm16|Imm32|Imm32S, Acc|Byte|Word|Dword|Qword }
 test, 0xf6/0, 0, W|Modrm|No_sSuf|Optimize, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
+ctest<cc>, 0x840<cc:opc>, APX_F, D|W|C|CheckOperandSize|Modrm|EVexMap4|SCC|No_sSuf, { Reg8|Reg16|Reg32|Reg64, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
+ctest<cc>, 0xf60<cc:opc>/0, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
+ctest<cc>, 0xf60<cc:opc>/1, APX_F, W|Modrm|EVexMap4|SCC|No_sSuf, { Imm8|Imm16|Imm32|Imm32S, Reg8|Reg16|Reg32|Reg64|Unspecified|BaseIndex }
 
 <incdec:opc, inc:0, dec:1>
 
@@ -505,9 +515,6 @@  enter, 0xc8, x64, ImplicitStackOp|DefaultSize|No_bSuf|No_lSuf|No_sSuf|NoRex64, {
 leave, 0xc9, i186&No64, ImplicitStackOp|DefaultSize|No_bSuf|No_sSuf|No_qSuf, {}
 leave, 0xc9, x64, ImplicitStackOp|DefaultSize|No_bSuf|No_lSuf|No_sSuf|NoRex64, {}
 
-<cc:opc, o:0, no:1, b:2, c:2, nae:2, nb:3, nc:3, ae:3, e:4, z:4, ne:5, nz:5, be:6, na:6, nbe:7, a:7, +
-         s:8, ns:9, p:a, pe:a, np:b, po:b, l:c, nge:c, nl:d, ge:d, le:e, ng:e, nle:f, g:f>
-
 // Conditional jumps.
 j<cc>, 0x7<cc:opc>, 0, Jump|NoSuf|BNDPrefixOk, { Disp8|Disp16|Disp32 }