diff options
author | Jan Beulich <jbeulich@suse.com> | 2023-05-19 09:16:04 +0200 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2023-05-19 09:16:04 +0200 |
commit | 762acf217c4013bed5a4cc679e4bac78d13ce23a (patch) | |
tree | 4f20ebf4c32d4a30e9e8c036a6f623f06145ccea /gas/expr.c | |
parent | df81d460b2d9ec7327a0c1ab2344d7ec62874ce0 (diff) | |
download | gdb-762acf217c4013bed5a4cc679e4bac78d13ce23a.zip gdb-762acf217c4013bed5a4cc679e4bac78d13ce23a.tar.gz gdb-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.c | 21 |
1 files changed, 19 insertions, 2 deletions
@@ -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) |