diff options
author | Julian Brown <julian@codesourcery.com> | 2006-04-26 16:24:26 +0000 |
---|---|---|
committer | Julian Brown <julian@codesourcery.com> | 2006-04-26 16:24:26 +0000 |
commit | e0edc91a922804bb4e76f2c0de656abf2acda78e (patch) | |
tree | 3cea1fe07d8e9c69f469c703922af421e9d8564c | |
parent | 961c0e3bfb01b566eb6418703c7e4edfe7952c02 (diff) | |
download | binutils-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.csl | 20 | ||||
-rw-r--r-- | gas/config/tc-arm.c | 95 | ||||
-rw-r--r-- | gas/testsuite/gas/arm/neon-cov.d | 4 | ||||
-rw-r--r-- | opcodes/arm-dis.c | 27 |
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: |