aboutsummaryrefslogtreecommitdiff
path: root/gas/expr.c
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2023-05-19 09:16:04 +0200
committerJan Beulich <jbeulich@suse.com>2023-05-19 09:16:04 +0200
commit762acf217c4013bed5a4cc679e4bac78d13ce23a (patch)
tree4f20ebf4c32d4a30e9e8c036a6f623f06145ccea /gas/expr.c
parentdf81d460b2d9ec7327a0c1ab2344d7ec62874ce0 (diff)
downloadbinutils-762acf217c4013bed5a4cc679e4bac78d13ce23a.zip
binutils-762acf217c4013bed5a4cc679e4bac78d13ce23a.tar.gz
binutils-762acf217c4013bed5a4cc679e4bac78d13ce23a.tar.bz2
gas: maintain O_constant signedness in more cases
Unary '~' doesn't really produce an unsigned result. Neither does subtraction (unless taking operand values into consideration). And an abstract operator applied to two operands which aren't both unsigned can't be assumed to yield an unsigned result; exceptions are - shifts, where only signedness of the left hand operand matters, - comparisons, which - unlike unary '!' - produce signed results (they deliver 0 or ~0, as opposed to '!', which yields 0 or 1), - logical operators (yielding 0 or 1 and hence treated like unary '!'). While doing this (specifically while extending the all/quad testcase), update .quad and .8byte documentation: With 64-bit architectures now being common, it is highly inappropriate to state that these directives unconditionally require bignums.
Diffstat (limited to 'gas/expr.c')
-rw-r--r--gas/expr.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/gas/expr.c b/gas/expr.c
index 055745f..b83296c 100644
--- a/gas/expr.c
+++ b/gas/expr.c
@@ -1056,6 +1056,7 @@ operand (expressionS *expressionP, enum expr_mode mode)
{
expressionP->X_add_number = ~ expressionP->X_add_number;
expressionP->X_extrabit ^= 1;
+ expressionP->X_unsigned = 0;
}
else if (c == '!')
{
@@ -1816,6 +1817,7 @@ expr (int rankarg, /* Larger # is higher rank. */
while (op_left != O_illegal && op_rank[(int) op_left] > rank)
{
segT rightseg;
+ bool is_unsigned;
offsetT frag_off;
input_line_pointer += op_chars; /* -> after operator. */
@@ -1883,6 +1885,8 @@ expr (int rankarg, /* Larger # is higher rank. */
right.X_op_symbol = NULL;
}
+ is_unsigned = resultP->X_unsigned && right.X_unsigned;
+
if (mode == expr_defer
&& ((resultP->X_add_symbol != NULL
&& S_IS_FORWARD_REF (resultP->X_add_symbol))
@@ -1895,7 +1899,7 @@ expr (int rankarg, /* Larger # is higher rank. */
if (md_optimize_expr (resultP, op_left, &right))
{
/* Skip. */
- ;
+ is_unsigned = resultP->X_unsigned;
}
else
#endif
@@ -1928,12 +1932,14 @@ expr (int rankarg, /* Larger # is higher rank. */
add_to_result (resultP, symval_diff, symval_diff < 0);
resultP->X_op = O_constant;
resultP->X_add_symbol = 0;
+ is_unsigned = false;
}
else if (op_left == O_subtract && right.X_op == O_constant
&& (md_register_arithmetic || resultP->X_op != O_register))
{
/* X - constant. */
subtract_from_result (resultP, right.X_add_number, right.X_extrabit);
+ is_unsigned = false;
}
else if (op_left == O_add && resultP->X_op == O_constant
&& (md_register_arithmetic || right.X_op != O_register))
@@ -1988,6 +1994,7 @@ expr (int rankarg, /* Larger # is higher rank. */
else
resultP->X_add_number
= (valueT) resultP->X_add_number >> (valueT) v;
+ is_unsigned = resultP->X_unsigned;
break;
case O_bit_inclusive_or: resultP->X_add_number |= v; break;
case O_bit_or_not: resultP->X_add_number |= ~v; break;
@@ -1998,36 +2005,45 @@ expr (int rankarg, /* Larger # is higher rank. */
here. */
case O_subtract:
subtract_from_result (resultP, v, 0);
+ is_unsigned = false;
break;
case O_eq:
resultP->X_add_number =
resultP->X_add_number == v ? ~ (offsetT) 0 : 0;
+ is_unsigned = false;
break;
case O_ne:
resultP->X_add_number =
resultP->X_add_number != v ? ~ (offsetT) 0 : 0;
+ is_unsigned = false;
break;
case O_lt:
resultP->X_add_number =
resultP->X_add_number < v ? ~ (offsetT) 0 : 0;
+ is_unsigned = false;
break;
case O_le:
resultP->X_add_number =
resultP->X_add_number <= v ? ~ (offsetT) 0 : 0;
+ is_unsigned = false;
break;
case O_ge:
resultP->X_add_number =
resultP->X_add_number >= v ? ~ (offsetT) 0 : 0;
+ is_unsigned = false;
break;
case O_gt:
resultP->X_add_number =
resultP->X_add_number > v ? ~ (offsetT) 0 : 0;
+ is_unsigned = false;
break;
case O_logical_and:
resultP->X_add_number = resultP->X_add_number && v;
+ is_unsigned = true;
break;
case O_logical_or:
resultP->X_add_number = resultP->X_add_number || v;
+ is_unsigned = true;
break;
}
}
@@ -2065,10 +2081,11 @@ expr (int rankarg, /* Larger # is higher rank. */
resultP->X_op_symbol = make_expr_symbol (&right);
resultP->X_op = op_left;
resultP->X_add_number = 0;
- resultP->X_unsigned = 1;
resultP->X_extrabit = 0;
}
+ resultP->X_unsigned = is_unsigned;
+
if (retval != rightseg)
{
if (retval == undefined_section)