Skip to content

Commit

Permalink
x86: handle immediate operands for .insn
Browse files Browse the repository at this point in the history
Since we have no insn suffix and it's also not realistic to infer
immediate size from the size of other (typically register) operands
(like optimize_imm() does), and since we also don't have a template
telling us permitted size(s), a new syntax construct is introduced to
allow size (and signedness) specification. In the absence of such, the
size is inferred from significant bits (which obviously may yield
inconsistent results at least for effectively negative values, depending
on whether BFD64 is enabled), and only if supplied expressions can be
evaluated at parsing time. Being explicit is generally recommended to
users.

Size specification is permitted at bit granularity, but of course the
eventually emitted immediate values will be padded up to 8-, 16-, 32-,
or 64-bit fields.
  • Loading branch information
jbeulich authored and ouuleilei-bot committed Mar 7, 2023
1 parent 59a330f commit 0620fba
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 4 deletions.
9 changes: 8 additions & 1 deletion gas/config/tc-i386-intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,8 @@ i386_intel_operand (char *operand_string, int got_a_float)
i386_operand_type temp;

/* Register operand. */
if (intel_state.base || intel_state.index || intel_state.seg)
if (intel_state.base || intel_state.index || intel_state.seg
|| i.imm_bits[this_operand])
{
as_bad (_("invalid operand"));
return 0;
Expand Down Expand Up @@ -998,6 +999,12 @@ i386_intel_operand (char *operand_string, int got_a_float)
|| intel_state.is_mem)
{
/* Memory operand. */
if (i.imm_bits[this_operand])
{
as_bad (_("invalid operand"));
return 0;
}

if (i.mem_operands)
{
/* Handle
Expand Down
102 changes: 100 additions & 2 deletions gas/config/tc-i386.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ struct _i386_insn
unsigned int flags[MAX_OPERANDS];
#define Operand_PCrel 1
#define Operand_Mem 2
#define Operand_Signed 4 /* .insn only */

/* Relocation type for operand */
enum bfd_reloc_code_real reloc[MAX_OPERANDS];
Expand All @@ -310,6 +311,9 @@ struct _i386_insn
/* .insn allows for reserved opcode spaces. */
unsigned char insn_opcode_space;

/* .insn also allows (requires) specifying immediate size. */
unsigned char imm_bits[MAX_OPERANDS];

/* Register is in low 3 bits of opcode. */
bool short_form;

Expand Down Expand Up @@ -5938,6 +5942,10 @@ swap_2_operands (unsigned int xchg1, unsigned int xchg2)
i.reloc[xchg2] = i.reloc[xchg1];
i.reloc[xchg1] = temp_reloc;

temp_flags = i.imm_bits[xchg2];
i.imm_bits[xchg2] = i.imm_bits[xchg1];
i.imm_bits[xchg1] = temp_flags;

if (i.mask.reg)
{
if (i.mask.operand == xchg1)
Expand Down Expand Up @@ -10203,7 +10211,8 @@ output_imm (fragS *insn_start_frag, offsetT insn_start_off)

if (i.types[n].bitfield.imm32s
&& (i.suffix == QWORD_MNEM_SUFFIX
|| (!i.suffix && i.tm.opcode_modifier.no_lsuf)))
|| (!i.suffix && i.tm.opcode_modifier.no_lsuf)
|| dot_insn ()))
sign = 1;
else
sign = 0;
Expand Down Expand Up @@ -11231,6 +11240,57 @@ s_insn (int dummy ATTRIBUTE_UNUSED)
if (i.disp_operands && !optimize_disp (&i.tm))
goto done;

/* Establish size for immediate operands. */
for (j = 0; j < i.imm_operands; ++j)
{
expressionS *expP = i.op[j].imms;

gas_assert (operand_type_check (i.types[j], imm));
operand_type_set (&i.types[j], 0);

if (i.imm_bits[j] > 32)
i.types[j].bitfield.imm64 = 1;
else if (i.imm_bits[j] > 16)
{
if (flag_code == CODE_64BIT && (i.flags[j] & Operand_Signed))
i.types[j].bitfield.imm32s = 1;
else
i.types[j].bitfield.imm32 = 1;
}
else if (i.imm_bits[j] > 8)
i.types[j].bitfield.imm16 = 1;
else if (i.imm_bits[j] > 0)
{
if (i.flags[j] & Operand_Signed)
i.types[j].bitfield.imm8s = 1;
else
i.types[j].bitfield.imm8 = 1;
}
else if (expP->X_op == O_constant)
{
i.types[j] = smallest_imm_type (expP->X_add_number);
i.types[j].bitfield.imm1 = 0;
/* Oddly enough imm_size() checks imm64 first, so the bit needs
zapping since smallest_imm_type() sets it unconditionally. */
if (flag_code != CODE_64BIT)
{
i.types[j].bitfield.imm64 = 0;
i.types[j].bitfield.imm32s = 0;
i.types[j].bitfield.imm32 = 1;
}
else if (i.types[j].bitfield.imm32 || i.types[j].bitfield.imm32s)
i.types[j].bitfield.imm64 = 0;
}
else
/* Non-constant expressions are sized heuristically. */
switch (flag_code)
{
case CODE_64BIT: i.types[j].bitfield.imm32s = 1; break;
case CODE_32BIT: i.types[j].bitfield.imm32 = 1; break;
case CODE_16BIT: i.types[j].bitfield.imm16 = 1; break;
}
}

for (j = 0; j < i.operands; ++j)
i.tm.operand_types[j] = i.types[j];

Expand Down Expand Up @@ -11411,10 +11471,11 @@ check_VecOperations (char *op_string)
else if (dot_insn () && *op_string == ':')
{
dot_insn_modifier:
if (op_string[1] == 'd')
switch (op_string[1])
{
unsigned long n;

case 'd':
if (i.memshift < 32)
goto duplicated_vec_op;

Expand All @@ -11424,6 +11485,27 @@ check_VecOperations (char *op_string)
++i.memshift;
if (i.memshift < 32 && n == 1)
op_string = end_op;
break;

case 's': case 'u':
/* This isn't really a "vector" operation, but a sign/size
specifier for immediate operands of .insn. Note that AT&T
syntax handles the same in i386_immediate(). */
if (!intel_syntax)
break;

if (i.imm_bits[this_operand])
goto duplicated_vec_op;

n = strtoul (op_string + 2, &end_op, 0);
if (n && n <= (flag_code == CODE_64BIT ? 64 : 32))
{
i.imm_bits[this_operand] = n;
if (op_string[1] == 's')
i.flags[this_operand] |= Operand_Signed;
op_string = end_op;
}
break;
}
}
/* Check masking operation. */
Expand Down Expand Up @@ -11562,6 +11644,22 @@ i386_immediate (char *imm_start)

exp_seg = expression (exp);

/* For .insn immediates there may be a size specifier. */
if (dot_insn () && *input_line_pointer == '{' && input_line_pointer[1] == ':'
&& (input_line_pointer[2] == 's' || input_line_pointer[2] == 'u'))
{
char *e;
unsigned long n = strtoul (input_line_pointer + 3, &e, 0);

if (*e == '}' && n && n <= (flag_code == CODE_64BIT ? 64 : 32))
{
i.imm_bits[this_operand] = n;
if (input_line_pointer[2] == 's')
i.flags[this_operand] |= Operand_Signed;
input_line_pointer = e + 1;
}
}

SKIP_WHITESPACE ();
if (*input_line_pointer)
as_bad (_("junk `%s' after expression"), input_line_pointer);
Expand Down
11 changes: 11 additions & 0 deletions gas/testsuite/gas/i386/insn-32.d
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@ Disassembly of section .text:
[ ]*[a-f0-9]+: f3 90[ ]+pause
[ ]*[a-f0-9]+: f3 90[ ]+pause
[ ]*[a-f0-9]+: d9 ee[ ]+fldz
[ ]*[a-f0-9]+: d9 ee[ ]+fldz
[ ]*[a-f0-9]+: f3 0f 01 e8[ ]+setssbsy
[ ]*[a-f0-9]+: 8b c1[ ]+mov %ecx,%eax
[ ]*[a-f0-9]+: 66 8b c8[ ]+mov %ax,%cx
[ ]*[a-f0-9]+: 89 48 04[ ]+mov %ecx,0x4\(%eax\)
[ ]*[a-f0-9]+: 8b 0c 05 44 44 00 00[ ]+mov 0x4444\(,%eax,1\),%ecx
[ ]*[a-f0-9]+: 66 0f b6 cc[ ]+movzbw %ah,%cx
[ ]*[a-f0-9]+: 0f b7 c8[ ]+movzwl %ax,%ecx
[ ]*[a-f0-9]+: 64 f0 80 30 01[ ]+lock xorb \$(0x)?1,%fs:\(%eax\)
[ ]*[a-f0-9]+: 0f ca[ ]+bswap %edx
[ ]*[a-f0-9]+: c7 f8 02 00 00 00[ ]+xbegin [0-9a-f]+ <insn\+.*>
[ ]*[a-f0-9]+: e2 f8[ ]+loop [0-9a-f]+ <insn\+.*>
[ ]*[a-f0-9]+: c5 fc 77[ ]+vzeroall
[ ]*[a-f0-9]+: c4 e1 7c 77[ ]+vzeroall
[ ]*[a-f0-9]+: c5 f1 58 d0[ ]+vaddpd %xmm0,%xmm1,%xmm2
Expand All @@ -27,6 +31,9 @@ Disassembly of section .text:
[ ]*[a-f0-9]+: c4 e3 69 68 19 00[ ]+vfmaddps %xmm0,\(%ecx\),%xmm2,%xmm3
[ ]*[a-f0-9]+: c4 e3 e9 68 19 00[ ]+vfmaddps \(%ecx\),%xmm0,%xmm2,%xmm3
[ ]*[a-f0-9]+: c4 e3 e9 68 18 10[ ]+vfmaddps \(%eax\),%xmm1,%xmm2,%xmm3
[ ]*[a-f0-9]+: c4 e3 69 48 19 00[ ]+vpermil2ps \$(0x)?0,%xmm0,\(%ecx\),%xmm2,%xmm3
[ ]*[a-f0-9]+: c4 e3 e9 48 19 02[ ]+vpermil2ps \$(0x)?2,\(%ecx\),%xmm0,%xmm2,%xmm3
[ ]*[a-f0-9]+: c4 e3 e9 48 18 13[ ]+vpermil2ps \$(0x)?3,\(%eax\),%xmm1,%xmm2,%xmm3
[ ]*[a-f0-9]+: c5 f8 92 c8[ ]+kmovw %eax,%k1
[ ]*[a-f0-9]+: c5 f8 93 c1[ ]+kmovw %k1,%eax
[ ]*[a-f0-9]+: 62 f1 74 18 58 d0[ ]+vaddps \{rn-sae\},%zmm0,%zmm1,%zmm2
Expand All @@ -41,4 +48,8 @@ Disassembly of section .text:
[ ]*[a-f0-9]+: 62 f5 fd 58 5a 40 01[ ]+vcvtpd2ph (0x)?8\(%eax\)\{1to8\},%xmm0
[ ]*[a-f0-9]+: 62 f5 7c 48 5a 40 01[ ]+vcvtph2pd 0x10\(%eax\),%zmm0
[ ]*[a-f0-9]+: 62 f5 7c 58 5a 40 01[ ]+vcvtph2pd (0x)?2\(%eax\)\{1to8\},%zmm0
[ ]*[a-f0-9]+: 62 f3 7d 28 66 40 01 ff[ ]+vfpclasspsy \$0xff,0x20\(%eax\),%k0
[ ]*[a-f0-9]+: 62 f3 7d 28 66 40 01 ff[ ]+vfpclasspsy \$0xff,0x20\(%eax\),%k0
[ ]*[a-f0-9]+: 62 f3 7d 38 66 40 01 ff[ ]+vfpclassps \$0xff,(0x)?4\(%eax\)\{1to8\},%k0
[ ]*[a-f0-9]+: 62 f3 7d 38 66 40 01 ff[ ]+vfpclassps \$0xff,(0x)?4\(%eax\)\{1to8\},%k0
#pass
24 changes: 24 additions & 0 deletions gas/testsuite/gas/i386/insn-32.s
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ insn:

# fldz
.insn 0xd9ee
.insn 0xd9, $0xee

# setssbsy
.insn 0xf30f01e8
Expand All @@ -23,9 +24,20 @@ insn:
.insn 0x0fb6, %ah, %cx
.insn 0x0fb7, %eax, %ecx

# xorb
.insn lock 0x80/6, $1, %fs:(%eax)

# bswap
.insn 0x0fc8+r, %edx

1:
# xbegin 3f
.insn 0xc7f8, $3f-2f{:s32}
2:
# loop 1b
.insn 0xe2, $1b-3f{:s8}
3:

# vzeroall
.insn VEX.256.0F.WIG 0x77
.insn {vex3} VEX.L1 0x0f77
Expand All @@ -43,6 +55,11 @@ insn:
.insn VEX.66.0F3A.W1 0x68, %xmm0, (%ecx), %xmm2, %xmm3
.insn VEX.66.0F3A.W1 0x68, (%eax), %xmm1, %xmm2, %xmm3

# vpermil2ps
.insn VEX.66.0F3A.W0 0x48, $0, %xmm0, (%ecx), %xmm2, %xmm3
.insn VEX.66.0F3A.W1 0x48, $2, %xmm0, (%ecx), %xmm2, %xmm3
.insn VEX.66.0F3A.W1 0x48, $3, (%eax), %xmm1, %xmm2, %xmm3

# kmovw
.insn VEX.L0.0F.W0 0x92, %eax, %k1
.insn VEX.L0.0F.W0 0x93, %k1, %eax
Expand All @@ -68,3 +85,10 @@ insn:
# vcvtph2pd
.insn EVEX.M5.W0 0x5a, 16(%eax){:d16}, %zmm0
.insn EVEX.M5.W0 0x5a, 2(%eax){1to8:d2}, %zmm0

.intel_syntax noprefix
# vfpclassps
.insn EVEX.256.66.0f3a.W0 0x66, k0, [eax+32], 0xff
.insn EVEX.66.0f3a.W0 0x66, k0, ymmword ptr [eax+32], 0xff
.insn EVEX.256.66.0f3a.W0 0x66, k0, [eax+4]{1to8}, 0xff
.insn EVEX.66.0f3a.W0 0x66, k0, dword ptr [eax+4]{1to8}, 0xff
11 changes: 10 additions & 1 deletion gas/testsuite/gas/i386/insn-64.d
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#objdump: -dw
#objdump: -dwr
#name: .insn (64-bit code)

.*: +file format .*
Expand All @@ -18,8 +18,14 @@ Disassembly of section .text:
[ ]*[a-f0-9]+: 66 0f be cc[ ]+movsbw %ah,%cx
[ ]*[a-f0-9]+: 0f bf c8[ ]+movswl %ax,%ecx
[ ]*[a-f0-9]+: 48 63 c8[ ]+movslq %eax,%rcx
[ ]*[a-f0-9]+: f0 80 35 00 00 00 00 01[ ]+lock xorb \$(0x)?1,(0x)?0\(%rip\) *# .*: R_X86_64_PC32 lock-(0x)?5
[ ]*[a-f0-9]+: 48 0f ca[ ]+bswap %rdx
[ ]*[a-f0-9]+: 41 0f c8[ ]+bswap %r8d
[ ]*[a-f0-9]+: c7 f8 02 00 00 00[ ]+xbegin [0-9a-f]+ <insn\+.*>
[ ]*[a-f0-9]+: e2 f8[ ]+loop [0-9a-f]+ <insn\+.*>
[ ]*[a-f0-9]+: 05 00 00 00 00[ ]+add \$(0x)?0,%eax .*: R_X86_64_32 var
[ ]*[a-f0-9]+: 48 05 00 00 00 00[ ]+add \$(0x)?0,%rax .*: R_X86_64_32S var
[ ]*[a-f0-9]+: 81 3d 00 00 00 00 13 12 23 21[ ]+cmpl \$0x21231213,(0x)?0\(%rip\) *# .*: R_X86_64_PC32 var-(0x)?8
[ ]*[a-f0-9]+: c5 fc 77[ ]+vzeroall
[ ]*[a-f0-9]+: c4 e1 7c 77[ ]+vzeroall
[ ]*[a-f0-9]+: c4 c1 71 58 d0[ ]+vaddpd %xmm8,%xmm1,%xmm2
Expand All @@ -29,6 +35,9 @@ Disassembly of section .text:
[ ]*[a-f0-9]+: c4 e3 69 68 19 80[ ]+vfmaddps %xmm8,\(%rcx\),%xmm2,%xmm3
[ ]*[a-f0-9]+: 67 c4 e3 e9 68 19 00[ ]+vfmaddps \(%ecx\),%xmm0,%xmm2,%xmm3
[ ]*[a-f0-9]+: c4 c3 e9 68 18 10[ ]+vfmaddps \(%r8\),%xmm1,%xmm2,%xmm3
[ ]*[a-f0-9]+: c4 e3 69 48 19 80[ ]+vpermil2ps \$(0x)0,%xmm8,\(%rcx\),%xmm2,%xmm3
[ ]*[a-f0-9]+: 67 c4 e3 e9 48 19 02[ ]+vpermil2ps \$(0x)2,\(%ecx\),%xmm0,%xmm2,%xmm3
[ ]*[a-f0-9]+: c4 c3 e9 48 18 13[ ]+vpermil2ps \$(0x)3,\(%r8\),%xmm1,%xmm2,%xmm3
[ ]*[a-f0-9]+: c4 c1 78 92 c8[ ]+kmovw %r8d,%k1
[ ]*[a-f0-9]+: c5 78 93 c1[ ]+kmovw %k1,%r8d
[ ]*[a-f0-9]+: 62 b1 74 38 58 d0[ ]+vaddps \{rd-sae\},%zmm16,%zmm1,%zmm2
Expand Down
25 changes: 25 additions & 0 deletions gas/testsuite/gas/i386/insn-64.s
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,30 @@ insn:
.insn 0x0fbf, %eax, %ecx
.insn 0x63, %rax, %rcx

# xorb
.insn lock 0x80/6, $1, lock(%rip)

# bswap
.insn 0x0fc8+r, %rdx
.insn 0x0fc8+r, %r8d

1:
# xbegin 3f
.insn 0xc7f8, $3f-2f{:s32}
2:
# loop 1b
.insn 0xe2, $1b-3f{:s8}
3:

# add $var, %eax
.insn 0x05, $var{:u32}

# add $var, %rax
.insn rex.w 0x05, $var{:s32}

# cmpl (32-bit immediate split into two 16-bit halves)
.insn 0x81/7, $0x1213, $0x2123, var(%rip)

# vzeroall
.insn VEX.256.0F.WIG 0x77
.insn {vex3} VEX.L1 0x0f77
Expand All @@ -45,6 +65,11 @@ insn:
.insn VEX.66.0F3A.W1 0x68, %xmm0, (%ecx), %xmm2, %xmm3
.insn VEX.66.0F3A.W1 0x68, (%r8), %xmm1, %xmm2, %xmm3

# vpermil2ps
.insn VEX.66.0F3A.W0 0x48, $0, %xmm8, (%rcx), %xmm2, %xmm3
.insn VEX.66.0F3A.W1 0x48, $2, %xmm0, (%ecx), %xmm2, %xmm3
.insn VEX.66.0F3A.W1 0x48, $3, (%r8), %xmm1, %xmm2, %xmm3

# kmovw
.insn VEX.L0.0F.W0 0x92, %r8d, %k1
.insn VEX.L0.0F.W0 0x93, %k1, %r8d
Expand Down

0 comments on commit 0620fba

Please sign in to comment.