+2007-05-26 Alan Modra <amodra@bigpond.net.au>
+
+ * config/tc-ppc.c (ppc_insert_operand): Truncate sign bits in
+ top 32 bits of 64 bit value if so doing results in passing
+ range check. Rewrite sign extension fudges similarly. Enable
+ fudges for powerpc64 too. Report user value if range check
+ fails rather than fudged value. Negate PPC_OPERAND_NEGATIVE
+ range rather than value, also to report user value on failure.
+
2007-03-25 Paul Brook <paul@codesourcery.com>
* config/tc-arm.c (T2_SUBS_PC_LR): Define.
static bfd_boolean register_name PARAMS ((expressionS *));
static void ppc_set_cpu PARAMS ((void));
-static unsigned long ppc_insert_operand
- PARAMS ((unsigned long insn, const struct powerpc_operand *operand,
- offsetT val, char *file, unsigned int line));
static void ppc_macro PARAMS ((char *str, const struct powerpc_macro *macro));
static void ppc_byte PARAMS ((int));
/* Insert an operand value into an instruction. */
static unsigned long
-ppc_insert_operand (insn, operand, val, file, line)
- unsigned long insn;
- const struct powerpc_operand *operand;
- offsetT val;
- char *file;
- unsigned int line;
+ppc_insert_operand (unsigned long insn,
+ const struct powerpc_operand *operand,
+ offsetT val,
+ char *file,
+ unsigned int line)
{
long min, max, right;
- offsetT test;
max = operand->bitm;
right = max & -max;
if ((operand->flags & PPC_OPERAND_SIGNOPT) == 0)
max = (max >> 1) & -right;
min = ~max & -right;
-
- if (!ppc_obj64)
- {
- /* Some people write 32 bit hex constants with the sign
- extension done by hand. This shouldn't really be
- valid, but, to permit this code to assemble on a 64
- bit host, we sign extend the 32 bit value. */
- if (val > 0
- && (val & (offsetT) 0x80000000) != 0
- && (val & (offsetT) 0xffffffff) == val)
- {
- val -= 0x80000000;
- val -= 0x80000000;
- }
- }
}
if ((operand->flags & PPC_OPERAND_PLUS1) != 0)
max++;
if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0)
- test = - val;
- else
- test = val;
-
- if ((min <= max && (test < (offsetT) min || test > (offsetT) max))
- || (test & (right - 1)) != 0)
- as_bad_value_out_of_range (_("operand"),
- test, (offsetT) min, (offsetT) max, file, line);
+ {
+ long tmp = min;
+ min = -max;
+ max = -tmp;
+ }
+
+ if (min <= max)
+ {
+ /* Some people write constants with the sign extension done by
+ hand but only up to 32 bits. This shouldn't really be valid,
+ but, to permit this code to assemble on a 64-bit host, we
+ sign extend the 32-bit value to 64 bits if so doing makes the
+ value valid. */
+ if (val > max
+ && (offsetT) (val - 0x80000000 - 0x80000000) >= min
+ && (offsetT) (val - 0x80000000 - 0x80000000) <= max
+ && ((val - 0x80000000 - 0x80000000) & (right - 1)) == 0)
+ val = val - 0x80000000 - 0x80000000;
+
+ /* Similarly, people write expressions like ~(1<<15), and expect
+ this to be OK for a 32-bit unsigned value. */
+ else if (val < min
+ && (offsetT) (val + 0x80000000 + 0x80000000) >= min
+ && (offsetT) (val + 0x80000000 + 0x80000000) <= max
+ && ((val + 0x80000000 + 0x80000000) & (right - 1)) == 0)
+ val = val + 0x80000000 + 0x80000000;
+
+ else if (val < min
+ || val > max
+ || (val & (right - 1)) != 0)
+ as_bad_value_out_of_range (_("operand"), val, min, max, file, line);
+ }
if (operand->insert)
{