summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Brown <julian@codesourcery.com>2006-04-26 16:24:26 +0000
committerJulian Brown <julian@codesourcery.com>2006-04-26 16:24:26 +0000
commite0edc91a922804bb4e76f2c0de656abf2acda78e (patch)
tree3cea1fe07d8e9c69f469c703922af421e9d8564c
parent961c0e3bfb01b566eb6418703c7e4edfe7952c02 (diff)
downloadbinutils-gdb-e0edc91a922804bb4e76f2c0de656abf2acda78e.tar.gz
* gas/config/tc-arm.c (neon_is_quarter_float): Move, and rename to...
(is_quarter_float): Rename from above. Simplify slightly. (parse_qfloat_immediate): Parse a "quarter precision" floating-point number. (parse_neon_mov): Parse floating-point constants. (neon_qfloat_bits): Fix encoding. (neon_cmode_for_move_imm): Tweak to use floating-point encoding in preference to integer encoding when using the F32 type. * gas/testsuite/gas/arm/neon-const.s: New testcase. Neon floating-point constants. * gas/testsuite/gas/arm/neon-const.d: Expected output of above. * gas/testsuite/gas/arm/neon-cov.d: Expect floating-point disassembly for VMOV.F32. * opcodes/arm-dis.c (print_insn_neon): Disassemble floating-point constant VMOV.
-rw-r--r--ChangeLog.csl20
-rw-r--r--gas/config/tc-arm.c95
-rw-r--r--gas/testsuite/gas/arm/neon-cov.d4
-rw-r--r--opcodes/arm-dis.c27
4 files changed, 116 insertions, 30 deletions
diff --git a/ChangeLog.csl b/ChangeLog.csl
index d0cc33389e7..271df1dab61 100644
--- a/ChangeLog.csl
+++ b/ChangeLog.csl
@@ -1,3 +1,23 @@
+2006-04-26 Julian Brown <julian@codesourcery.com>
+
+ * gas/config/tc-arm.c (neon_is_quarter_float): Move, and rename to...
+ (is_quarter_float): Rename from above. Simplify slightly.
+ (parse_qfloat_immediate): Parse a "quarter precision" floating-point
+ number.
+ (parse_neon_mov): Parse floating-point constants.
+ (neon_qfloat_bits): Fix encoding.
+ (neon_cmode_for_move_imm): Tweak to use floating-point encoding in
+ preference to integer encoding when using the F32 type.
+
+ * gas/testsuite/gas/arm/neon-const.s: New testcase. Neon floating-point
+ constants.
+ * gas/testsuite/gas/arm/neon-const.d: Expected output of above.
+ * gas/testsuite/gas/arm/neon-cov.d: Expect floating-point disassembly
+ for VMOV.F32.
+
+ * opcodes/arm-dis.c (print_insn_neon): Disassemble floating-point
+ constant VMOV.
+
2006-04-24 Julian Brown <julian@codesourcery.com>
* libiberty/floatformat.c (floatformat_to_double): Fix (biased)
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 44c7d99618e..1447af461ca 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -3994,6 +3994,55 @@ parse_fpa_immediate (char ** str)
return FAIL;
}
+/* Returns 1 if a number has "quarter-precision" float format
+ 0baBbbbbbc defgh000 00000000 00000000. */
+
+static int
+is_quarter_float (unsigned imm)
+{
+ int bs = (imm & 0x20000000) ? 0x3e000000 : 0x40000000;
+ return (imm & 0x7ffff) == 0 && ((imm & 0x7e000000) ^ bs) == 0;
+}
+
+/* Parse an 8-bit "quarter-precision" floating point number of the form:
+ 0baBbbbbbc defgh000 00000000 00000000.
+ The minus-zero case needs special handling, since it can't be encoded in the
+ "quarter-precision" float format, but can nonetheless be loaded as an integer
+ constant. */
+
+static unsigned
+parse_qfloat_immediate (char **ccp, int *immed)
+{
+ char *str = *ccp;
+ LITTLENUM_TYPE words[MAX_LITTLENUMS];
+
+ skip_past_char (&str, '#');
+
+ if ((str = atof_ieee (str, 's', words)) != NULL)
+ {
+ unsigned fpword = 0;
+ int i;
+
+ /* Our FP word must be 32 bits (single-precision FP). */
+ for (i = 0; i < 32 / LITTLENUM_NUMBER_OF_BITS; i++)
+ {
+ fpword <<= LITTLENUM_NUMBER_OF_BITS;
+ fpword |= words[i];
+ }
+
+ if (is_quarter_float (fpword) || fpword == 0x80000000)
+ *immed = fpword;
+ else
+ return FAIL;
+
+ *ccp = str;
+
+ return SUCCESS;
+ }
+
+ return FAIL;
+}
+
/* Shift operands. */
enum shift_kind
{
@@ -4702,6 +4751,13 @@ parse_neon_mov (char **str, int *which_operand)
inst.operands[i].isreg = 1;
inst.operands[i].present = 1;
}
+ else if (parse_qfloat_immediate (&ptr, &inst.operands[i].imm) == SUCCESS)
+ {
+ /* Case 2: VMOV<c><q>.<dt> <Qd>, #<float-imm>
+ Case 3: VMOV<c><q>.<dt> <Dd>, #<float-imm> */
+ if (!thumb_mode && (inst.instruction & 0xf0000000) != 0xe0000000)
+ goto bad_cond;
+ }
else if (parse_big_immediate (&ptr, i) == SUCCESS)
{
/* Case 2: VMOV<c><q>.<dt> <Qd>, #<imm>
@@ -10214,25 +10270,12 @@ neon_squash_bits (unsigned imm)
| ((imm & 0x01000000) >> 21);
}
-/* Returns 1 if a number has "quarter-precision" float format
- 0baBbbbbbc defgh000 00000000 00000000. */
-
-static int
-neon_is_quarter_float (unsigned imm)
-{
- int b = (imm & 0x20000000) != 0;
- int bs = (b << 25) | (b << 26) | (b << 27) | (b << 28) | (b << 29)
- | ((!b) << 30);
- return (imm & 0x81ffffff) == (imm & 0x81f80000)
- && ((imm & 0x7e000000) ^ bs) == 0;
-}
-
-/* Compress above representation to 0b...000 abcdefgh. */
+/* Compress quarter-float representation to 0b...000 abcdefgh. */
static unsigned
neon_qfloat_bits (unsigned imm)
{
- return ((imm >> 19) & 0x7f) | (imm >> 24);
+ return ((imm >> 19) & 0x7f) | ((imm >> 24) & 0x80);
}
/* Returns CMODE. IMMBITS [7:0] is set to bits suitable for inserting into
@@ -10243,9 +10286,16 @@ neon_qfloat_bits (unsigned imm)
static int
neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, unsigned *immbits,
- int *op, int size)
+ int *op, int size, enum neon_el_type type)
{
- if (size == 64 && neon_bits_same_in_bytes (immhi)
+ if (type == NT_float && is_quarter_float (immlo) && immhi == 0)
+ {
+ if (size != 32 || *op == 1)
+ return FAIL;
+ *immbits = neon_qfloat_bits (immlo);
+ return 0xf;
+ }
+ else if (size == 64 && neon_bits_same_in_bytes (immhi)
&& neon_bits_same_in_bytes (immlo))
{
/* Check this one first so we don't have to bother with immhi in later
@@ -10303,13 +10353,6 @@ neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, unsigned *immbits,
*immbits = (immlo >> 16) & 0xff;
return 0xd;
}
- else if (neon_is_quarter_float (immlo))
- {
- if (size != 32 || *op == 1)
- return FAIL;
- *immbits = neon_qfloat_bits (immlo);
- return 0xf;
- }
return FAIL;
}
@@ -10996,7 +11039,7 @@ neon_move_immediate (void)
_("immediate has bits set outside the operand size"));
if ((cmode = neon_cmode_for_move_imm (immlo, immhi, &immbits, &op,
- et.size)) == FAIL)
+ et.size, et.type)) == FAIL)
{
/* Invert relevant bits only. */
neon_invert_size (&immlo, &immhi, et.size);
@@ -11005,7 +11048,7 @@ neon_move_immediate (void)
neon_cmode_for_move_imm. */
op = !op;
if ((cmode = neon_cmode_for_move_imm (immlo, immhi, &immbits, &op,
- et.size)) == FAIL)
+ et.size, et.type)) == FAIL)
{
first_error (_("immediate out of range"));
return;
diff --git a/gas/testsuite/gas/arm/neon-cov.d b/gas/testsuite/gas/arm/neon-cov.d
index c2ef0eb9c8b..d4de661ab90 100644
--- a/gas/testsuite/gas/arm/neon-cov.d
+++ b/gas/testsuite/gas/arm/neon-cov.d
@@ -989,8 +989,8 @@ Disassembly of section \.text:
0[0-9a-f]+ <[^>]+> f2870e17 vmov\.i8 d0, #119 ; 0x77
0[0-9a-f]+ <[^>]+> f3810e71 vmov\.i64 q0, #0xff0000ff000000ff
0[0-9a-f]+ <[^>]+> f3810e31 vmov\.i64 d0, #0xff0000ff000000ff
-0[0-9a-f]+ <[^>]+> f2850f51 vmov\.f32 q0, #1027866624 ; 0x3d440000
-0[0-9a-f]+ <[^>]+> f2850f11 vmov\.f32 d0, #1027866624 ; 0x3d440000
+0[0-9a-f]+ <[^>]+> f2810f51 vmov\.f32 q0, #4\.25 ; 0x40880000
+0[0-9a-f]+ <[^>]+> f2810f11 vmov\.f32 d0, #4\.25 ; 0x40880000
0[0-9a-f]+ <[^>]+> f3b005c0 vmvn q0, q0
0[0-9a-f]+ <[^>]+> f3b005c0 vmvn q0, q0
0[0-9a-f]+ <[^>]+> f3b00580 vmvn d0, d0
diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c
index f6cac6563c3..6ca93335d38 100644
--- a/opcodes/arm-dis.c
+++ b/opcodes/arm-dis.c
@@ -26,6 +26,7 @@
#include "opcode/arm.h"
#include "opintl.h"
#include "safe-ctype.h"
+#include "floatformat.h"
/* FIXME: This shouldn't be done here. */
#include "coff/internal.h"
@@ -2283,6 +2284,7 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
unsigned long value = 0, hival = 0;
unsigned shift;
int size = 0;
+ int isfloat = 0;
bits |= ((given >> 24) & 1) << 7;
bits |= ((given >> 16) & 7) << 4;
@@ -2339,11 +2341,12 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
/* floating point encoding */
int tmp;
- value = (unsigned long)(bits & 0x7f) << (24 - 6);
+ value = (unsigned long)(bits & 0x7f) << 19;
value |= (unsigned long)(bits & 0x80) << 24;
tmp = bits & 0x40 ? 0x3c : 0x40;
value |= (unsigned long)tmp << 24;
size = 32;
+ isfloat = 1;
}
else
{
@@ -2363,7 +2366,27 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
break;
case 32:
- func (stream, "#%ld\t; 0x%.8lx", value, value);
+ if (isfloat)
+ {
+ unsigned char valbytes[4];
+ double fvalue;
+
+ /* Do this a byte at a time so we don't have to
+ worry about the host's endianness. */
+ valbytes[0] = value & 0xff;
+ valbytes[1] = (value >> 8) & 0xff;
+ valbytes[2] = (value >> 16) & 0xff;
+ valbytes[3] = (value >> 24) & 0xff;
+
+ floatformat_to_double
+ (&floatformat_ieee_single_little, valbytes,
+ &fvalue);
+
+ func (stream, "#%.7g\t; 0x%.8lx", fvalue,
+ value);
+ }
+ else
+ func (stream, "#%ld\t; 0x%.8lx", value, value);
break;
case 64: