+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.
{
/* 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++)
{
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,
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
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;
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)
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 if (arm_p && inst.reloc.exp.X_op == O_constant)
+ else
+ v = inst.reloc.exp.X_add_number;
+
+ if (!inst.operands[i].issingle)
{
- int value = encode_arm_immediate (inst.reloc.exp.X_add_number);
- if (value != FAIL)
+ if (thumb_p && inst.reloc.exp.X_op == O_constant)
{
- /* 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;
+ 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 (~inst.reloc.exp.X_add_number);
- if (value != FAIL)
+ 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)
{
- /* 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;
+ 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 (vec64_p)
- {
- 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)
+ if (t == CONST_VEC)
+ {
+ /* 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);
+ inst.operands[1].imm =
+ neon_qfloat_bits (v);
+ do_vfp_nsyn_opcode ("fconsts");
+ return TRUE;
}
- if (cmode != FAIL)
+ else if (!inst.operands[1].issingle
+ && ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3))
{
- 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;
+ 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;
+ }
}
}
}
}
}
-static void do_vfp_nsyn_opcode (const char *);
-
static int
do_vfp_nsyn_mrs (void)
{
+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.
--- /dev/null
+# 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
--- /dev/null
+.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
+
--- /dev/null
+# 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
--- /dev/null
+.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
+
--- /dev/null
+# 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
--- /dev/null
+.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
+
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;
}
(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;
}
(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;