Add support for converting VLDR <reg>,=<constant> to a VMOV instruction when appropriate.

PR gas/18500
gas	* config/tc-arm.c (is_double_a_single): New function.
	(double_to_single): New function.
	(move_or_literal_pool): Add support for	converting VLDR to VMOV.

tests	* gas/arm/vfpv2-ldr_immediate.s: New test case.
	* gas/arm/vfpv2-ldr_immediate.d: Expected disassembly.
	* gas/arm/vfpv3-ldr_immediate.s: New test case.
	* gas/arm/vfpv3-ldr_immediate.d: Expected disassembly.
	* gas/arm/vfpv3xd-ldr_immediate.s: New test case.
	* gas/arm/vfpv3xd-ldr_immediate.d: Expected disassembly.
This commit is contained in:
Alessandro Marzocchi 2015-06-17 12:56:17 +01:00 committed by Nick Clifton
parent fc24848555
commit ba592044bc
10 changed files with 459 additions and 68 deletions

View File

@ -1,3 +1,10 @@
2015-06-17 Alessandro Marzocchi <alessandro.marzocchi@gmail.com>
PR gas/18500
* config/tc-arm.c (is_double_a_single): New function.
(double_to_single): New function.
(move_or_literal_pool): Add support for converting VLDR to VMOV.
2015-06-17 Nicolas Pitre <nico@linaro.org>
* as.c (show_usage): Document --sectname-subst.

View File

@ -4924,7 +4924,9 @@ parse_fpa_immediate (char ** str)
{
/* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
Ditto for 15. */
if (gen_to_words (words, 5, (long) 15) == 0)
#define X_PRECISION 5
#define E_PRECISION 15L
if (gen_to_words (words, X_PRECISION, E_PRECISION) == 0)
{
for (i = 0; i < NUM_FLOAT_VALS; i++)
{
@ -7750,6 +7752,52 @@ neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, int float_p,
return FAIL;
}
/* Returns TRUE if double precision value V may be cast
to single precision without loss of accuracy. */
static bfd_boolean
is_double_a_single (long int v)
{
int exp = (int) (v >> 52) & 0x7FF;
long int mantissa = (v & 0xFFFFFFFFFFFFFl);
return (exp == 0 || exp == 0x7FF
|| (exp >= 1023 - 126 && exp <= 1023 + 127))
&& (mantissa & 0x1FFFFFFFl) == 0;
}
/* Returns a double precision value casted to single precision
(ignoring the least significant bits in exponent and mantissa). */
static int
double_to_single (long int v)
{
int sign = (int) ((v >> 63) & 1l);
int exp = (int) (v >> 52) & 0x7FF;
long int mantissa = (v & 0xFFFFFFFFFFFFFl);
if (exp == 0x7FF)
exp = 0xFF;
else
{
exp = exp - 1023 + 127;
if (exp >= 0xFF)
{
/* Infinity. */
exp = 0x7F;
mantissa = 0;
}
else if (exp < 0)
{
/* No denormalized numbers. */
exp = 0;
mantissa = 0;
}
}
mantissa >>= 29;
return (sign << 31) | (exp << 23) | mantissa;
}
enum lit_type
{
CONST_THUMB,
@ -7757,6 +7805,8 @@ enum lit_type
CONST_VEC
};
static void do_vfp_nsyn_opcode (const char *);
/* inst.reloc.exp describes an "=expr" load pseudo-operation.
Determine whether it can be performed with a move instruction; if
it can, convert inst.instruction to that move instruction and
@ -7772,7 +7822,6 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
unsigned long tbit;
bfd_boolean thumb_p = (t == CONST_THUMB);
bfd_boolean arm_p = (t == CONST_ARM);
bfd_boolean vec64_p = (t == CONST_VEC) && !inst.operands[i].issingle;
if (thumb_p)
tbit = (inst.instruction > 0xffff) ? THUMB2_LOAD_BIT : THUMB_LOAD_BIT;
@ -7784,6 +7833,7 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
inst.error = _("invalid pseudo operation");
return TRUE;
}
if (inst.reloc.exp.X_op != O_constant
&& inst.reloc.exp.X_op != O_symbol
&& inst.reloc.exp.X_op != O_big)
@ -7791,77 +7841,130 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
inst.error = _("constant expression expected");
return TRUE;
}
if ((inst.reloc.exp.X_op == O_constant
|| inst.reloc.exp.X_op == O_big)
&& !inst.operands[i].issingle)
if (inst.reloc.exp.X_op == O_constant
|| inst.reloc.exp.X_op == O_big)
{
if (thumb_p && inst.reloc.exp.X_op == O_constant)
offsetT v;
if (inst.reloc.exp.X_op == O_big)
{
if (!unified_syntax && (inst.reloc.exp.X_add_number & ~0xFF) == 0)
LITTLENUM_TYPE w[X_PRECISION];
LITTLENUM_TYPE * l;
if (inst.reloc.exp.X_add_number == -1)
{
/* This can be done with a mov(1) instruction. */
inst.instruction = T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8);
inst.instruction |= inst.reloc.exp.X_add_number;
return TRUE;
gen_to_words (w, X_PRECISION, E_PRECISION);
l = w;
/* FIXME: Should we check words w[2..5] ? */
}
else
l = generic_bignum;
v = ((l[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS)
| (l[0] & LITTLENUM_MASK);
}
else
v = inst.reloc.exp.X_add_number;
if (!inst.operands[i].issingle)
{
if (thumb_p && inst.reloc.exp.X_op == O_constant)
{
if (!unified_syntax && (v & ~0xFF) == 0)
{
/* This can be done with a mov(1) instruction. */
inst.instruction = T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8);
inst.instruction |= v;
return TRUE;
}
}
else if (arm_p && inst.reloc.exp.X_op == O_constant)
{
int value = encode_arm_immediate (v);
if (value != FAIL)
{
/* This can be done with a mov instruction. */
inst.instruction &= LITERAL_MASK;
inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
inst.instruction |= value & 0xfff;
return TRUE;
}
value = encode_arm_immediate (~ v);
if (value != FAIL)
{
/* This can be done with a mvn instruction. */
inst.instruction &= LITERAL_MASK;
inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
inst.instruction |= value & 0xfff;
return TRUE;
}
}
else if (t == CONST_VEC)
{
int op = 0;
unsigned immbits = 0;
unsigned immlo = inst.operands[1].imm;
unsigned immhi = inst.operands[1].regisimm
? inst.operands[1].reg
: inst.reloc.exp.X_unsigned
? 0
: ((bfd_int64_t)((int) immlo)) >> 32;
int cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits,
&op, 64, NT_invtype);
if (cmode == FAIL)
{
neon_invert_size (&immlo, &immhi, 64);
op = !op;
cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits,
&op, 64, NT_invtype);
}
if (cmode != FAIL)
{
inst.instruction = (inst.instruction & VLDR_VMOV_SAME)
| (1 << 23)
| (cmode << 8)
| (op << 5)
| (1 << 4);
/* Fill other bits in vmov encoding for both thumb and arm. */
if (thumb_mode)
inst.instruction |= (0x7 << 29) | (0xF << 24);
else
inst.instruction |= (0xF << 28) | (0x1 << 25);
neon_write_immbits (immbits);
return TRUE;
}
}
}
else if (arm_p && inst.reloc.exp.X_op == O_constant)
{
int value = encode_arm_immediate (inst.reloc.exp.X_add_number);
if (value != FAIL)
{
/* This can be done with a mov instruction. */
inst.instruction &= LITERAL_MASK;
inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
inst.instruction |= value & 0xfff;
return TRUE;
}
value = encode_arm_immediate (~inst.reloc.exp.X_add_number);
if (value != FAIL)
{
/* This can be done with a mvn instruction. */
inst.instruction &= LITERAL_MASK;
inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
inst.instruction |= value & 0xfff;
return TRUE;
}
}
else if (vec64_p)
if (t == CONST_VEC)
{
int op = 0;
unsigned immbits = 0;
unsigned immlo = inst.operands[1].imm;
unsigned immhi = inst.operands[1].regisimm
? inst.operands[1].reg
: inst.reloc.exp.X_unsigned
? 0
: ((bfd_int64_t)((int) immlo)) >> 32;
int cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits,
&op, 64, NT_invtype);
if (cmode == FAIL)
/* Check if vldr Rx, =constant could be optimized to vmov Rx, #constant. */
if (inst.operands[i].issingle
&& is_quarter_float (inst.operands[1].imm)
&& ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3xd))
{
neon_invert_size (&immlo, &immhi, 64);
op = !op;
cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits,
&op, 64, NT_invtype);
}
if (cmode != FAIL)
{
inst.instruction = (inst.instruction & VLDR_VMOV_SAME)
| (1 << 23)
| (cmode << 8)
| (op << 5)
| (1 << 4);
/* Fill other bits in vmov encoding for both thumb and arm. */
if (thumb_mode)
inst.instruction |= (0x7 << 29) | (0xF << 24);
else
inst.instruction |= (0xF << 28) | (0x1 << 25);
neon_write_immbits (immbits);
inst.operands[1].imm =
neon_qfloat_bits (v);
do_vfp_nsyn_opcode ("fconsts");
return TRUE;
}
else if (!inst.operands[1].issingle
&& ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3))
{
if (is_double_a_single (v)
&& is_quarter_float (double_to_single (v)))
{
inst.operands[1].imm =
neon_qfloat_bits (double_to_single (v));
do_vfp_nsyn_opcode ("fconstd");
return TRUE;
}
}
}
}
@ -8799,8 +8902,6 @@ do_mov16 (void)
}
}
static void do_vfp_nsyn_opcode (const char *);
static int
do_vfp_nsyn_mrs (void)
{

View File

@ -1,3 +1,13 @@
2015-06-17 Alessandro Marzocchi <alessandro.marzocchi@gmail.com>
PR gas/18500
* gas/arm/vfpv2-ldr_immediate.s: New test case.
* gas/arm/vfpv2-ldr_immediate.d: Expected disassembly.
* gas/arm/vfpv3-ldr_immediate.s: New test case.
* gas/arm/vfpv3-ldr_immediate.d: Expected disassembly.
* gas/arm/vfpv3xd-ldr_immediate.s: New test case.
* gas/arm/vfpv3xd-ldr_immediate.d: Expected disassembly.
2015-06-16 Matthew Wahab <matthew.wahab@arm.com>
* sysreg.d: Add id_mmfr4_el1, update expected output.

View File

@ -0,0 +1,50 @@
# name: VFPv2 vldr to vmov
# as: -mfpu=vfpv2
# objdump: -dr --prefix-addresses --show-raw-insn
.*: +file format .*arm.*
Disassembly of section \.text:
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*ed9f0a01 vldr s0, \[pc, #4\].*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*3fbe0000 .*
0[0-9a-fx]+ .*3df00000 .*
.*
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*ed9f0a01 vldr s0, \[pc, #4\].*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*bfc00000 .*
0[0-9a-fx]+ .*be000000 .*
.*
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*ed9f0a01 vldr s0, \[pc, #4\].*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*3fc00000 .*
0[0-9a-fx]+ .*3e000000 .*
.*
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*ed9f0a01 vldr s0, \[pc, #4\].*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*3fe08000 .*
0[0-9a-fx]+ .*3f040000 .*
.*
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*ed9f0a01 vldr s0, \[pc, #4\].*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*3fef0000 .*
0[0-9a-fx]+ .*3f780000 .*
.*
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*ed9f0a01 vldr s0, \[pc, #4\].*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*403f0000 .*
0[0-9a-fx]+ .*41f80000 .*
.*
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*ed9f0a01 vldr s0, \[pc, #4\].*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*40400000 .*
0[0-9a-fx]+ .*42000000 .*
#pass

View File

@ -0,0 +1,48 @@
.arm
.syntax unified
# VFPv2 has no VMOV instruction... all vldr will be kept
# 15 * 2^-7 =0.1171875 VMOV does not exists
.align 3
vldr d0,=0x3FBE000000000000
vldr s0,=0x3df00000
.pool
# -16 * 2^-7 =0.125 VMOV does not exists
.align 3
vldr d0,=0xbfc0000000000000
vldr s0,=0xbe000000
.pool
# 16 * 2^-7 =0.125 VMOV does not exists
.align 3
vldr d0,=0x3fc0000000000000
vldr s0,=0x3e000000
.pool
# 16.5 * 2^-7 =0.125 VMOV does not exists
.align 3
vldr d0,=0x3fe0800000000000
vldr s0,=0x3f040000
.pool
# 31 * 2^-5 = 0.96875 VMOV does not exists
.align 3
vldr d0,=0x3fef000000000000
vldr s0,=0x3f780000
.pool
# 31 * 2^ 0 = 31 VMOV does not exists
.align 3
vldr d0,=0x403F000000000000
vldr s0,=0x41f80000
.pool
# 16 * 2^ 1 = 32 VMOV does not exists
.align 3
vldr d0,=0x4040000000000000
vldr s0,=0x42000000
.pool
nop

View File

@ -0,0 +1,35 @@
# name: VFPv3 vldr to vmov
# as: -mfpu=vfp3
# objdump: -dr --prefix-addresses --show-raw-insn
.*: +file format .*arm.*
Disassembly of section \.text:
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*ed9f0a01 vldr s0, \[pc, #4\].*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*3fbe0000 .*
0[0-9a-fx]+ .*3df00000 .*
.*
0[0-9a-fx]+ .*eebc0b00 (vmov\.f64|fconstd) d0, #192.*
0[0-9a-fx]+ .*eebc0a00 (vmov\.f32|fconsts) s0, #192.*
0[0-9a-fx]+ .*eeb40b00 (vmov\.f64|fconstd) d0, #64.*
0[0-9a-fx]+ .*eeb40a00 (vmov\.f32|fconsts) s0, #64.*
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*ed9f0a01 vldr s0, \[pc, #4\].*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*3fe08000 .*
0[0-9a-fx]+ .*3f040000 .*
.*
0[0-9a-fx]+ .*eeb60b0f (vmov\.f64|fconstd) d0, #111.*
0[0-9a-fx]+ .*eeb60a0f (vmov\.f32|fconsts) s0, #111.*
0[0-9a-fx]+ .*eeb30b0f (vmov\.f64|fconstd) d0, #63.*
0[0-9a-fx]+ .*eeb30a0f (vmov\.f32|fconsts) s0, #63.*
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*ed9f0a01 vldr s0, \[pc, #4\].*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*40400000 .*
0[0-9a-fx]+ .*42000000 .*
#pass

View File

@ -0,0 +1,46 @@
.arm
.syntax unified
# 15 * 2^-7 =0.1171875 Not convertible to VMOV
.align 3
vldr d0,=0x3FBE000000000000
vldr s0,=0x3df00000
.pool
# -16 * 2^-7 =-0.125 Convertible to VMOV
.align 3
vldr d0,=0xbfc0000000000000
vldr s0,=0xbe000000
.pool
# 16 * 2^-7 =0.125 Convertible to VMOV
.align 3
vldr d0,=0x3fc0000000000000
vldr s0,=0x3e000000
.pool
# 16.5 * 2^-7 =0.125 Not convertible to VMOV
.align 3
vldr d0,=0x3fe0800000000000
vldr s0,=0x3f040000
.pool
# 31 * 2^-5 = 0.96875 Convertible to VMOV
.align 3
vldr d0,=0x3fef000000000000
vldr s0,=0x3f780000
.pool
# 31 * 2^ 0 = 31 Convertible to VMOV
.align 3
vldr d0,=0x403F000000000000
vldr s0,=0x41f80000
.pool
# 16 * 2^ 1 = 32 Not convertible to VMOV
.align 3
vldr d0,=0x4040000000000000
vldr s0,=0x42000000
.pool
nop

View File

@ -0,0 +1,42 @@
# name: VFPv3xd vldr to vmov
# as: -mfpu=vfpv3xd
# objdump: -dr --prefix-addresses --show-raw-insn
.*: +file format .*arm.*
Disassembly of section \.text:
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*ed9f0a01 vldr s0, \[pc, #4\].*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*3fbe0000 .*
0[0-9a-fx]+ .*3df00000 .*
.*
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*eebc0a00 (vmov\.f32|fconsts) s0, #192.*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*bfc00000 .*
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*eeb40a00 (vmov\.f32|fconsts) s0, #64.*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*3fc00000 .*
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*ed9f0a01 vldr s0, \[pc, #4\].*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*3fe08000 .*
0[0-9a-fx]+ .*3f040000 .*
.*
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*eeb60a0f (vmov\.f32|fconsts) s0, #111.*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*3fef0000 .*
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*eeb30a0f (vmov\.f32|fconsts) s0, #63.*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*403f0000 .*
0[0-9a-fx]+ .*ed9f0b00 vldr d0, \[pc\].*
0[0-9a-fx]+ .*ed9f0a01 vldr s0, \[pc, #4\].*
0[0-9a-fx]+ .*00000000 .*
0[0-9a-fx]+ .*40400000 .*
0[0-9a-fx]+ .*42000000 .*
#pass

View File

@ -0,0 +1,47 @@
.arm
.syntax unified
# VFPv3xD has no VMOV instruction for double precision registers...
# 15 * 2^-7 =0.1171875 Not convertible to VMOV
.align 3
vldr d0,=0x3FBE000000000000
vldr s0,=0x3df00000
.pool
# -16 * 2^-7 =0.125 Convertible to VMOV
.align 3
vldr d0,=0xbfc0000000000000
vldr s0,=0xbe000000
.pool
# 16 * 2^-7 =0.125 Convertible to VMOV
.align 3
vldr d0,=0x3fc0000000000000
vldr s0,=0x3e000000
.pool
# 16.5 * 2^-7 =0.125 Not convertible to VMOV
.align 3
vldr d0,=0x3fe0800000000000
vldr s0,=0x3f040000
.pool
# 31 * 2^-5 = 0.96875 Convertible to VMOV
.align 3
vldr d0,=0x3fef000000000000
vldr s0,=0x3f780000
.pool
# 31 * 2^ 0 = 31 Convertible to VMOV
.align 3
vldr d0,=0x403F000000000000
vldr s0,=0x41f80000
.pool
# 16 * 2^ 1 = 32 Not convertible to VMOV
.align 3
vldr d0,=0x4040000000000000
vldr s0,=0x42000000
.pool
nop

View File

@ -1585,7 +1585,9 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED,
f->fr_literal, (file_ptr) offset,
(bfd_size_type) f->fr_fix);
if (!x)
as_fatal (_("can't write %s: %s"), stdoutput->filename,
as_fatal (_("can't write %ld bytes to section %s of %s because: '%s'"),
(long) f->fr_fix, sec->name,
stdoutput->filename,
bfd_errmsg (bfd_get_error ()));
offset += f->fr_fix;
}
@ -1606,7 +1608,9 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED,
(file_ptr) offset,
(bfd_size_type) fill_size);
if (!x)
as_fatal (_("can't write %s: %s"), stdoutput->filename,
as_fatal (_("can't fill %ld bytes in section %s of %s because '%s'"),
(long) fill_size, sec->name,
stdoutput->filename,
bfd_errmsg (bfd_get_error ()));
offset += fill_size;
}
@ -1636,7 +1640,8 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED,
(stdoutput, sec, buf, (file_ptr) offset,
(bfd_size_type) n_per_buf * fill_size);
if (!x)
as_fatal (_("cannot write to output file '%s': %s"),
as_fatal (_("cannot fill %ld bytes in section %s of %s because: '%s'"),
(long)(n_per_buf * fill_size), sec->name,
stdoutput->filename,
bfd_errmsg (bfd_get_error ()));
offset += n_per_buf * fill_size;