summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2021-03-30 14:05:42 +0200
committerJan Beulich <jbeulich@suse.com>2021-03-30 14:05:42 +0200
commit6225c532b4ce85661c5148d513335c0d8bd90e4f (patch)
treecf785a513f09ba77afc5718d500d9904831ae246
parent783c187b8ce8a2b414ca0145e27ae9747d857e98 (diff)
downloadbinutils-gdb-6225c532b4ce85661c5148d513335c0d8bd90e4f.tar.gz
x86: integrate mask_op into struct _i386_insn
There's no need for the extra level of indirection and the extra storage needed for the pointer, pointing from one piece of static data to another. Key checking of masking being in effect off of the register field of the structure instead.
-rw-r--r--gas/ChangeLog14
-rw-r--r--gas/config/tc-i386.c110
2 files changed, 69 insertions, 55 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 49cbc6b433d..94c7cc4271d 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,19 @@
2021-03-30 Jan Beulich <jbeulich@suse.com>
+ * config/tc-i386.c (reg_k0): New.
+ (mask_op): Delete.
+ (struct Mask_Operation): Move ...
+ (struct _i386_insn): ... here. Change field "mask".
+ (md_begin): Initialize reg_k0.
+ (build_evex_prefix): Adjust mask processing.
+ (swap_2_operands): Likewise.
+ (check_VecOperands): Likewise.
+ (check_VecOperations): Likewise.
+ (optimize_encoding): Adjust checks for masking.
+ (output_insn): Likewise.
+
+2021-03-30 Jan Beulich <jbeulich@suse.com>
+
* config/tc-i386.c (swap_2_operands): Switch parameters to
unsigned.
(struct RC_Operation): Switch operand field to unsigned.
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 03bd7b6d314..d5baf95da95 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -214,6 +214,8 @@ static const char *default_arch = DEFAULT_ARCH;
static const reg_entry bad_reg = { "<bad>", OPERAND_TYPE_NONE, 0, 0,
{ Dw2Inval, Dw2Inval } };
+static const reg_entry *reg_k0;
+
/* This struct describes rounding control and SAE in the instruction. */
struct RC_Operation
{
@@ -230,19 +232,6 @@ struct RC_Operation
static struct RC_Operation rc_op;
-/* The struct describes masking, applied to OPERAND in the instruction.
- MASK is a pointer to the corresponding mask register. ZEROING tells
- whether merging or zeroing mask is used. */
-struct Mask_Operation
-{
- const reg_entry *mask;
- unsigned int zeroing;
- /* The operand where this operation is associated. */
- unsigned int operand;
-};
-
-static struct Mask_Operation mask_op;
-
/* The struct describes broadcasting, applied to OPERAND. FACTOR is
broadcast factor. */
struct Broadcast_Operation
@@ -393,8 +382,18 @@ struct _i386_insn
sib_byte sib;
vex_prefix vex;
- /* Masking attributes. */
- struct Mask_Operation *mask;
+ /* Masking attributes.
+
+ The struct describes masking, applied to OPERAND in the instruction.
+ REG is a pointer to the corresponding mask register. ZEROING tells
+ whether merging or zeroing mask is used. */
+ struct Mask_Operation
+ {
+ const reg_entry *reg;
+ unsigned int zeroing;
+ /* The operand where this operation is associated. */
+ unsigned int operand;
+ } mask;
/* Rounding control and SAE attributes. */
struct RC_Operation *rounding;
@@ -3093,8 +3092,13 @@ md_begin (void)
unsigned int regtab_size = i386_regtab_size;
for (regtab = i386_regtab; regtab_size--; regtab++)
- if (str_hash_insert (reg_hash, regtab->reg_name, regtab, 0) != NULL)
- as_fatal (_("duplicate %s"), regtab->reg_name);
+ {
+ if (str_hash_insert (reg_hash, regtab->reg_name, regtab, 0) != NULL)
+ as_fatal (_("duplicate %s"), regtab->reg_name);
+
+ if (regtab->reg_type.bitfield.class == RegMask && !regtab->reg_num)
+ reg_k0 = regtab;
+ }
}
/* Fill in lexical tables: mnemonic_chars, operand_chars. */
@@ -3871,7 +3875,7 @@ build_evex_prefix (void)
/* The fourth byte of the EVEX prefix. */
/* The zeroing-masking bit. */
- if (i.mask && i.mask->zeroing)
+ if (i.mask.reg && i.mask.zeroing)
i.vex.bytes[3] |= 0x80;
/* Don't always set the broadcast bit if there is no RC. */
@@ -3962,8 +3966,8 @@ build_evex_prefix (void)
i.vex.bytes[3] |= 0x10 | (evexrcig << 5);
}
- if (i.mask && i.mask->mask)
- i.vex.bytes[3] |= i.mask->mask->reg_num;
+ if (i.mask.reg)
+ i.vex.bytes[3] |= i.mask.reg->reg_num;
}
static void
@@ -4164,7 +4168,7 @@ optimize_encoding (void)
&& i.op[0].regs == i.op[1].regs
&& !i.types[2].bitfield.xmmword
&& (i.tm.opcode_modifier.vex
- || ((!i.mask || i.mask->zeroing)
+ || ((!i.mask.reg || i.mask.zeroing)
&& !i.rounding
&& is_evex_encoding (&i.tm)
&& (i.vec_encoding != vex_encoding_evex
@@ -4250,7 +4254,7 @@ optimize_encoding (void)
else if (i.vec_encoding != vex_encoding_evex
&& !i.types[0].bitfield.zmmword
&& !i.types[1].bitfield.zmmword
- && !i.mask
+ && !i.mask.reg
&& !i.broadcast
&& is_evex_encoding (&i.tm)
&& ((i.tm.base_opcode & ~Opcode_SIMD_IntD) == 0x6f
@@ -5461,12 +5465,12 @@ swap_2_operands (unsigned int xchg1, unsigned int xchg2)
i.reloc[xchg2] = i.reloc[xchg1];
i.reloc[xchg1] = temp_reloc;
- if (i.mask)
+ if (i.mask.reg)
{
- if (i.mask->operand == xchg1)
- i.mask->operand = xchg2;
- else if (i.mask->operand == xchg2)
- i.mask->operand = xchg1;
+ if (i.mask.operand == xchg1)
+ i.mask.operand = xchg2;
+ else if (i.mask.operand == xchg2)
+ i.mask.operand = xchg1;
}
if (i.broadcast)
{
@@ -5802,7 +5806,7 @@ check_VecOperands (const insn_template *t)
/* Check if default mask is allowed. */
if (t->opcode_modifier.nodefmask
- && (!i.mask || i.mask->mask->reg_num == 0))
+ && (!i.mask.reg || i.mask.reg->reg_num == 0))
{
i.error = no_default_mask;
return 1;
@@ -5824,8 +5828,8 @@ check_VecOperands (const insn_template *t)
return 1;
}
- gas_assert (i.reg_operands == 2 || i.mask);
- if (i.reg_operands == 2 && !i.mask)
+ gas_assert (i.reg_operands == 2 || i.mask.reg);
+ if (i.reg_operands == 2 && !i.mask.reg)
{
gas_assert (i.types[0].bitfield.class == RegSIMD);
gas_assert (i.types[0].bitfield.xmmword
@@ -5849,7 +5853,7 @@ check_VecOperands (const insn_template *t)
}
as_warn (_("mask, index, and destination registers should be distinct"));
}
- else if (i.reg_operands == 1 && i.mask)
+ else if (i.reg_operands == 1 && i.mask.reg)
{
if (i.types[1].bitfield.class == RegSIMD
&& (i.types[1].bitfield.xmmword
@@ -5982,14 +5986,14 @@ check_VecOperands (const insn_template *t)
op = MAX_OPERANDS - 1; /* Avoid uninitialized variable warning. */
/* Check if requested masking is supported. */
- if (i.mask)
+ if (i.mask.reg)
{
switch (t->opcode_modifier.masking)
{
case BOTH_MASKING:
break;
case MERGING_MASKING:
- if (i.mask->zeroing)
+ if (i.mask.zeroing)
{
case 0:
i.error = unsupported_masking;
@@ -5998,7 +6002,7 @@ check_VecOperands (const insn_template *t)
break;
case DYNAMIC_MASKING:
/* Memory destinations allow only merging masking. */
- if (i.mask->zeroing && i.mem_operands)
+ if (i.mask.zeroing && i.mem_operands)
{
/* Find memory operand. */
for (op = 0; op < i.operands; op++)
@@ -6018,7 +6022,7 @@ check_VecOperands (const insn_template *t)
}
/* Check if masking is applied to dest operand. */
- if (i.mask && (i.mask->operand != i.operands - 1))
+ if (i.mask.reg && (i.mask.operand != i.operands - 1))
{
i.error = mask_not_on_destination;
return 1;
@@ -9230,7 +9234,7 @@ output_insn (void)
x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_YMM;
if ((i.xstate & xstate_zmm) == xstate_zmm)
x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_ZMM;
- if (i.mask || (i.xstate & xstate_mask) == xstate_mask)
+ if (i.mask.reg || (i.xstate & xstate_mask) == xstate_mask)
x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_MASK;
if (i.tm.cpu_flags.bitfield.cpufxsr)
x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_FXSR;
@@ -10431,23 +10435,20 @@ check_VecOperations (char *op_string, char *op_end)
return NULL;
}
- if (!i.mask)
+ if (!i.mask.reg)
{
- mask_op.mask = mask;
- mask_op.zeroing = 0;
- mask_op.operand = this_operand;
- i.mask = &mask_op;
+ i.mask.reg = mask;
+ i.mask.operand = this_operand;
}
+ else if (i.mask.reg->reg_num)
+ goto duplicated_vec_op;
else
{
- if (i.mask->mask)
- goto duplicated_vec_op;
-
- i.mask->mask = mask;
+ i.mask.reg = mask;
/* Only "{z}" is allowed here. No need to check
zeroing mask explicitly. */
- if (i.mask->operand != (unsigned int) this_operand)
+ if (i.mask.operand != (unsigned int) this_operand)
{
as_bad (_("invalid write mask `%s'"), saved);
return NULL;
@@ -10459,27 +10460,26 @@ check_VecOperations (char *op_string, char *op_end)
/* Check zeroing-flag for masking operation. */
else if (*op_string == 'z')
{
- if (!i.mask)
+ if (!i.mask.reg)
{
- mask_op.mask = NULL;
- mask_op.zeroing = 1;
- mask_op.operand = this_operand;
- i.mask = &mask_op;
+ i.mask.reg = reg_k0;
+ i.mask.zeroing = 1;
+ i.mask.operand = this_operand;
}
else
{
- if (i.mask->zeroing)
+ if (i.mask.zeroing)
{
duplicated_vec_op:
as_bad (_("duplicated `%s'"), saved);
return NULL;
}
- i.mask->zeroing = 1;
+ i.mask.zeroing = 1;
/* Only "{%k}" is allowed here. No need to check mask
register explicitly. */
- if (i.mask->operand != (unsigned int) this_operand)
+ if (i.mask.operand != (unsigned int) this_operand)
{
as_bad (_("invalid zeroing-masking `%s'"),
saved);
@@ -10512,7 +10512,7 @@ check_VecOperations (char *op_string, char *op_end)
return NULL;
}
- if (i.mask && i.mask->zeroing && !i.mask->mask)
+ if (i.mask.reg && i.mask.zeroing && !i.mask.reg->reg_num)
{
as_bad (_("zeroing-masking only allowed with write mask"));
return NULL;