aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-i386.c146
1 files changed, 145 insertions, 1 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index e0c6964..b8fc3c4 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;
+
+ /* Store 4 bits of EVEX.[OF,SF,ZF,CF]. */
+#define OSZC_CF 1
+#define OSZC_ZF 2
+#define OSZC_SF 4
+#define OSZC_OF 8
+ unsigned int oszc_flags;
+
/* Prefer load or store in encoding. */
enum
{
@@ -1929,6 +1939,110 @@ static INLINE bool need_evex_encoding (const insn_template *t)
#define CPU_FLAGS_PERFECT_MATCH \
(CPU_FLAGS_ARCH_MATCH | CPU_FLAGS_64BIT_MATCH)
+static INLINE bool set_oszc_flags (unsigned int oszc_shift)
+{
+ if (i.oszc_flags & oszc_shift)
+ {
+ as_bad (_("same oszc flag used twice"));
+ return false;
+ }
+ i.oszc_flags |= oszc_shift;
+ return true;
+}
+
+/* Handle SCC OSZC flags. */
+
+static int
+check_Scc_OszcOperations (const char *l)
+{
+ const char *suffix_string = l;
+
+ while (is_space_char (*suffix_string))
+ suffix_string++;
+
+ /* If {oszc flags} is absent, just return. */
+ if (*suffix_string != '{')
+ return 0;
+
+ /* Skip '{'. */
+ suffix_string++;
+
+ /* Parse 'dfv='. */
+ while (is_space_char (*suffix_string))
+ suffix_string++;
+
+ if (strncasecmp (suffix_string, "dfv", 3) == 0)
+ suffix_string += 3;
+ else
+ {
+ as_bad (_("unrecognized pseudo-suffix"));
+ return -1;
+ }
+
+ while (is_space_char (*suffix_string))
+ suffix_string++;
+
+ if (*suffix_string == '=')
+ suffix_string++;
+ else
+ {
+ as_bad (_("unrecognized pseudo-suffix"));
+ return -1;
+ }
+
+ /* Parse 'of, sf, zf, cf}'. */
+ while (*suffix_string)
+ {
+ while (is_space_char (*suffix_string))
+ suffix_string++;
+
+ /* Return for '{dfv=}'. */
+ if (*suffix_string == '}')
+ return suffix_string + 1 - l;
+
+ if (strncasecmp (suffix_string, "of", 2) == 0)
+ {
+ if (!set_oszc_flags (OSZC_OF))
+ return -1;
+ }
+ else if (strncasecmp (suffix_string, "sf", 2) == 0)
+ {
+ if (!set_oszc_flags (OSZC_SF))
+ return -1;
+ }
+ else if (strncasecmp (suffix_string, "zf", 2) == 0)
+ {
+ if (!set_oszc_flags (OSZC_ZF))
+ return -1;
+ }
+ else if (strncasecmp (suffix_string, "cf", 2) == 0)
+ {
+ if (!set_oszc_flags (OSZC_CF))
+ return -1;
+ }
+ else
+ {
+ as_bad (_("unrecognized oszc flags or illegal `,' in pseudo-suffix"));
+ return -1;
+ }
+
+ suffix_string += 2;
+
+ while (is_space_char (*suffix_string))
+ suffix_string++;
+
+ if (*suffix_string == '}')
+ return ++suffix_string - l;
+
+ if (*suffix_string != ',')
+ break;
+ suffix_string ++;
+ }
+
+ as_bad (_("missing `}' or `,' in pseudo-suffix"));
+ return -1;
+}
+
/* Return CPU flags match bits. */
static int
@@ -3793,10 +3907,19 @@ install_template (const insn_template *t)
}
}
+ /* For CCMP and CTEST the template has EVEX.SCC in base_opcode. Move it out of
+ there, to then adjust base_opcode to obtain its normal meaning. */
+ if (i.tm.opcode_modifier.operandconstraint == SCC)
+ {
+ /* Get EVEX.SCC value from 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 +4413,18 @@ build_apx_evex_prefix (void)
|| i.tm.opcode_modifier.operandconstraint == ZERO_UPPER)
i.vex.bytes[3] |= 0x10;
+ /* Encode SCC and oszc flags bits. */
+ if (i.tm.opcode_modifier.operandconstraint == SCC)
+ {
+ /* The default value of vvvv is 1111 and needs to be cleared. */
+ i.vex.bytes[2] &= ~0x78;
+ i.vex.bytes[2] |= (i.oszc_flags << 3);
+ /* ND and aaa bits shold be 0. */
+ know (!(i.vex.bytes[3] & 0x17));
+ /* The default value of V' is 1 and needs to be cleared. */
+ i.vex.bytes[3] = (i.vex.bytes[3] & ~0x08) | i.scc;
+ }
+
/* Encode the NF bit. */
if (i.has_nf)
i.vex.bytes[3] |= 0x04;
@@ -7428,6 +7563,15 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
}
}
+ /* Handle SCC OSZC flgs. */
+ if (current_templates.start->opcode_modifier.operandconstraint == SCC)
+ {
+ int length = check_Scc_OszcOperations (l);
+ if (length < 0)
+ return NULL;
+ l += length;
+ }
+
if (current_templates.start->opcode_modifier.jump == JUMP
|| current_templates.start->opcode_modifier.jump == JUMP_BYTE)
{