diff options
author | Sebastian Pop <sebastian.pop@amd.com> | 2010-02-11 05:06:14 +0000 |
---|---|---|
committer | Sebastian Pop <sebastian.pop@amd.com> | 2010-02-11 05:06:14 +0000 |
commit | a683cc34e4d115f13d4ef510f2f1f59d7e3947e4 (patch) | |
tree | 5902dd6675e665c5c6bd1440dd96ceb6977344f1 /gas/config | |
parent | e543c8cb7042c243c76636ef07d2f0b0ffd03733 (diff) | |
download | fsf-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.c | 184 |
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], ®xmm) - || operand_type_equal (&i.tm.operand_types[dest], ®ymm))); - - /* 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], ®xmm) + || operand_type_equal (&i.tm.operand_types[dest], ®ymm))))); + + 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], ®xmm) + || operand_type_equal (&i.tm.operand_types[reg_slot], + ®ymm)); + 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], ®xmm) - || operand_type_equal (&i.tm.operand_types[reg_slot], - ®ymm)) - && (operand_type_equal (&i.tm.operand_types[nds], ®xmm) - || operand_type_equal (&i.tm.operand_types[nds], - ®ymm))); - 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], ®xmm) + || operand_type_equal (&i.tm.operand_types[reg_slot], + ®ymm)); + 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], ®xmm) + || operand_type_equal (&i.tm.operand_types[nds], + ®ymm)); i.vex.register_specifier = i.op[nds].regs; } else |