aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorSebastian Pop <sebastian.pop@amd.com>2010-02-11 05:06:14 +0000
committerSebastian Pop <sebastian.pop@amd.com>2010-02-11 05:06:14 +0000
commita683cc34e4d115f13d4ef510f2f1f59d7e3947e4 (patch)
tree5902dd6675e665c5c6bd1440dd96ceb6977344f1 /gas/config
parente543c8cb7042c243c76636ef07d2f0b0ffd03733 (diff)
downloadfsf-binutils-gdb-a683cc34e4d115f13d4ef510f2f1f59d7e3947e4.zip
fsf-binutils-gdb-a683cc34e4d115f13d4ef510f2f1f59d7e3947e4.tar.gz
fsf-binutils-gdb-a683cc34e4d115f13d4ef510f2f1f59d7e3947e4.tar.bz2
2010-02-10 Quentin Neill <quentin.neill@amd.com>
Sebastian Pop <sebastian.pop@amd.com> gas: * config/tc-i386.c (vec_imm4) New operand type. (fits_in_imm4): New. (VEX_check_operands): New. (check_reverse): Call VEX_check_operands. (build_modrm_byte): Reintroduce code for 5 operand insns. Fix whitespace. gas/testsuite: * gas/i386/x86-64-xop.d: Add vpermil2p[sd] tests. * gas/i386/x86-64-xop.s: Likewise. * gas/i386/xop.d: Likewise. * gas/i386/xop.s: Likewise. opcodes: * i386-dis.c (OP_EX_VexImmW): Reintroduced function to handle 5th imm8 operand. (PREFIX_VEX_3A48): Added. (PREFIX_VEX_3A49): Added. (VEX_W_3A48_P_2): Added. (VEX_W_3A49_P_2): Added. (prefix table): Added entries for PREFIX_VEX_3A48 and PREFIX_VEX_3A49. (vex table): Added entries for VEX_W_3A48_P_2 and and VEX_W_3A49_P_2. * i386-gen.c (operand_type_init): Added OPERAND_TYPE_VEC_IMM4 for Vec_Imm4 operands. * i386-opc.h (enum): Added Vec_Imm4. (i386_operand_type): Added vec_imm4. * i386-opc.tbl: Add entries for vpermilp[ds]. * i386-init.h: Regenerated. * i386-tbl.h: Regenerated.
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-i386.c184
1 files changed, 142 insertions, 42 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index f091aa2..d9b9de4 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -1436,6 +1436,7 @@ static const i386_operand_type imm64 = OPERAND_TYPE_IMM64;
static const i386_operand_type imm16_32 = OPERAND_TYPE_IMM16_32;
static const i386_operand_type imm16_32s = OPERAND_TYPE_IMM16_32S;
static const i386_operand_type imm16_32_32s = OPERAND_TYPE_IMM16_32_32S;
+static const i386_operand_type vec_imm4 = OPERAND_TYPE_VEC_IMM4;
enum operand_type
{
@@ -1711,6 +1712,12 @@ fits_in_unsigned_long (offsetT num ATTRIBUTE_UNUSED)
#endif
} /* fits_in_unsigned_long() */
+static INLINE int
+fits_in_imm4 (offsetT num)
+{
+ return (num & 0xf) == num;
+}
+
static i386_operand_type
smallest_imm_type (offsetT num)
{
@@ -3724,6 +3731,29 @@ optimize_disp (void)
}
}
+/* Check if operands are valid for the instrucrtion. Update VEX
+ operand types. */
+
+static int
+VEX_check_operands (const insn_template *t)
+{
+ if (!t->opcode_modifier.vex)
+ return 0;
+
+ /* Only check VEX_Imm4, which must be the first operand. */
+ if (t->operand_types[0].bitfield.vec_imm4)
+ {
+ if (i.op[0].imms->X_op != O_constant
+ || !fits_in_imm4 (i.op[0].imms->X_add_number))
+ return 1;
+
+ /* Turn off Imm8 so that update_imm won't complain. */
+ i.types[0] = vec_imm4;
+ }
+
+ return 0;
+}
+
static const insn_template *
match_template (void)
{
@@ -4028,6 +4058,10 @@ check_reverse:
continue;
}
+ /* Check if VEX operands are valid. */
+ if (VEX_check_operands (t))
+ continue;
+
/* We've found a match; break out of loop. */
break;
}
@@ -4960,53 +4994,119 @@ build_modrm_byte (void)
expressionS *exp;
if (i.tm.opcode_modifier.veximmext
- && i.tm.opcode_modifier.immext)
- {
- dest = i.operands - 2;
- gas_assert (dest == 3);
- }
+ && i.tm.opcode_modifier.immext)
+ {
+ dest = i.operands - 2;
+ gas_assert (dest == 3);
+ }
else
- dest = i.operands - 1;
+ dest = i.operands - 1;
nds = dest - 1;
- /* This instruction must have 4 register operands
- or 3 register operands plus 1 memory operand.
- It must have VexNDS and VexImmExt. */
+ /* There are 2 kinds of instructions:
+ 1. 5 operands: 4 register operands or 3 register operands
+ plus 1 memory operand plus one Vec_Imm4 operand, VexXDS, and
+ VexW0 or VexW1. The destination must be either XMM or YMM
+ register.
+ 2. 4 operands: 4 register operands or 3 register operands
+ plus 1 memory operand, VexXDS, and VexImmExt */
gas_assert ((i.reg_operands == 4
- || (i.reg_operands == 3 && i.mem_operands == 1))
- && i.tm.opcode_modifier.vexvvvv == VEXXDS
- && i.tm.opcode_modifier.veximmext
- && (operand_type_equal (&i.tm.operand_types[dest], &regxmm)
- || operand_type_equal (&i.tm.operand_types[dest], &regymm)));
-
- /* Generate an 8bit immediate operand to encode the register
- operand. */
- exp = &im_expressions[i.imm_operands++];
- i.op[i.operands].imms = exp;
- i.types[i.operands] = imm8;
- i.operands++;
- /* If VexW1 is set, the first operand is the source and
- the second operand is encoded in the immediate operand. */
- if (i.tm.opcode_modifier.vexw == VEXW1)
- {
- source = 0;
- reg_slot = 1;
- }
+ || (i.reg_operands == 3 && i.mem_operands == 1))
+ && i.tm.opcode_modifier.vexvvvv == VEXXDS
+ && (i.tm.opcode_modifier.veximmext
+ || (i.imm_operands == 1
+ && i.types[0].bitfield.vec_imm4
+ && (i.tm.opcode_modifier.vexw == VEXW0
+ || i.tm.opcode_modifier.vexw == VEXW1)
+ && (operand_type_equal (&i.tm.operand_types[dest], &regxmm)
+ || operand_type_equal (&i.tm.operand_types[dest], &regymm)))));
+
+ if (i.imm_operands == 0)
+ {
+ /* When there is no immediate operand, generate an 8bit
+ immediate operand to encode the first operand. */
+ exp = &im_expressions[i.imm_operands++];
+ i.op[i.operands].imms = exp;
+ i.types[i.operands] = imm8;
+ i.operands++;
+ /* If VexW1 is set, the first operand is the source and
+ the second operand is encoded in the immediate operand. */
+ if (i.tm.opcode_modifier.vexw == VEXW1)
+ {
+ source = 0;
+ reg_slot = 1;
+ }
+ else
+ {
+ source = 1;
+ reg_slot = 0;
+ }
+
+ /* FMA swaps REG and NDS. */
+ if (i.tm.cpu_flags.bitfield.cpufma)
+ {
+ unsigned int tmp;
+ tmp = reg_slot;
+ reg_slot = nds;
+ nds = tmp;
+ }
+
+ gas_assert (operand_type_equal (&i.tm.operand_types[reg_slot], &regxmm)
+ || operand_type_equal (&i.tm.operand_types[reg_slot],
+ &regymm));
+ exp->X_op = O_constant;
+ exp->X_add_number
+ = ((i.op[reg_slot].regs->reg_num
+ + ((i.op[reg_slot].regs->reg_flags & RegRex) ? 8 : 0)) << 4);
+ }
else
- {
- source = 1;
- reg_slot = 0;
- }
- gas_assert ((operand_type_equal (&i.tm.operand_types[reg_slot], &regxmm)
- || operand_type_equal (&i.tm.operand_types[reg_slot],
- &regymm))
- && (operand_type_equal (&i.tm.operand_types[nds], &regxmm)
- || operand_type_equal (&i.tm.operand_types[nds],
- &regymm)));
- exp->X_op = O_constant;
- exp->X_add_number
- = ((i.op[reg_slot].regs->reg_num
- + ((i.op[reg_slot].regs->reg_flags & RegRex) ? 8 : 0)) << 4);
+ {
+ unsigned int imm_slot;
+
+ if (i.tm.opcode_modifier.vexw == VEXW0)
+ {
+ /* If VexW0 is set, the third operand is the source and
+ the second operand is encoded in the immediate
+ operand. */
+ source = 2;
+ reg_slot = 1;
+ }
+ else
+ {
+ /* VexW1 is set, the second operand is the source and
+ the third operand is encoded in the immediate
+ operand. */
+ source = 1;
+ reg_slot = 2;
+ }
+
+ if (i.tm.opcode_modifier.immext)
+ {
+ /* When ImmExt is set, the immdiate byte is the last
+ operand. */
+ imm_slot = i.operands - 1;
+ source--;
+ reg_slot--;
+ }
+ else
+ {
+ imm_slot = 0;
+
+ /* Turn on Imm8 so that output_imm will generate it. */
+ i.types[imm_slot].bitfield.imm8 = 1;
+ }
+
+ gas_assert (operand_type_equal (&i.tm.operand_types[reg_slot], &regxmm)
+ || operand_type_equal (&i.tm.operand_types[reg_slot],
+ &regymm));
+ i.op[imm_slot].imms->X_add_number
+ |= ((i.op[reg_slot].regs->reg_num
+ + ((i.op[reg_slot].regs->reg_flags & RegRex) ? 8 : 0)) << 4);
+ }
+
+ gas_assert (operand_type_equal (&i.tm.operand_types[nds], &regxmm)
+ || operand_type_equal (&i.tm.operand_types[nds],
+ &regymm));
i.vex.register_specifier = i.op[nds].regs;
}
else