* value.h (unop_promote, binop_promote): Add prototypes.

* eval.c (unop_promote, binop_promote): New functions.
	* valarith.c (unop_result_type, binop_result_type): Remove.
	(value_binop): Call binop_promote or unop_promote.
	Inline remaining parts of binop_result_type.  Remove special
	code to truncate integer values for unsigned operations.
	(value_pos): Call unop_promote.  Inline remaining parts of
	unop_result_type.
	(value_neg, value_complement): Likewise.
This commit is contained in:
Ulrich Weigand 2008-09-11 14:14:20 +00:00
parent 89eef11460
commit 4066e64672
4 changed files with 294 additions and 328 deletions

View File

@ -1,3 +1,15 @@
2008-09-11 Ulrich Weigand <uweigand@de.ibm.com>
* value.h (unop_promote, binop_promote): Add prototypes.
* eval.c (unop_promote, binop_promote): New functions.
* valarith.c (unop_result_type, binop_result_type): Remove.
(value_binop): Call binop_promote or unop_promote.
Inline remaining parts of binop_result_type. Remove special
code to truncate integer values for unsigned operations.
(value_pos): Call unop_promote. Inline remaining parts of
unop_result_type.
(value_neg, value_complement): Likewise.
2008-09-11 Ulrich Weigand <uweigand@de.ibm.com>
* value.h (value_add, value_sub): Remove.

View File

@ -439,6 +439,199 @@ value_f90_subarray (struct value *array,
return value_slice (array, low_bound, high_bound - low_bound + 1);
}
/* Promote value ARG1 as appropriate before performing a unary operation
on this argument.
If the result is not appropriate for any particular language then it
needs to patch this function. */
void
unop_promote (const struct language_defn *language, struct gdbarch *gdbarch,
struct value **arg1)
{
struct type *type1;
*arg1 = coerce_ref (*arg1);
type1 = check_typedef (value_type (*arg1));
if (is_integral_type (type1))
{
switch (language->la_language)
{
default:
/* Perform integral promotion for ANSI C/C++.
If not appropropriate for any particular language
it needs to modify this function. */
{
struct type *builtin_int = builtin_type (gdbarch)->builtin_int;
if (TYPE_LENGTH (type1) < TYPE_LENGTH (builtin_int))
*arg1 = value_cast (builtin_int, *arg1);
}
break;
}
}
}
/* Promote values ARG1 and ARG2 as appropriate before performing a binary
operation on those two operands.
If the result is not appropriate for any particular language then it
needs to patch this function. */
void
binop_promote (const struct language_defn *language, struct gdbarch *gdbarch,
struct value **arg1, struct value **arg2)
{
struct type *promoted_type = NULL;
struct type *type1;
struct type *type2;
*arg1 = coerce_ref (*arg1);
*arg2 = coerce_ref (*arg2);
type1 = check_typedef (value_type (*arg1));
type2 = check_typedef (value_type (*arg2));
if ((TYPE_CODE (type1) != TYPE_CODE_FLT
&& TYPE_CODE (type1) != TYPE_CODE_DECFLOAT
&& !is_integral_type (type1))
|| (TYPE_CODE (type2) != TYPE_CODE_FLT
&& TYPE_CODE (type2) != TYPE_CODE_DECFLOAT
&& !is_integral_type (type2)))
return;
if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
|| TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
{
/* No promotion required. */
}
else if (TYPE_CODE (type1) == TYPE_CODE_FLT
|| TYPE_CODE (type2) == TYPE_CODE_FLT)
{
switch (language->la_language)
{
case language_c:
case language_cplus:
case language_asm:
case language_objc:
/* No promotion required. */
break;
default:
/* For other languages the result type is unchanged from gdb
version 6.7 for backward compatibility.
If either arg was long double, make sure that value is also long
double. Otherwise use double. */
if (TYPE_LENGTH (type1) * 8 > gdbarch_double_bit (gdbarch)
|| TYPE_LENGTH (type2) * 8 > gdbarch_double_bit (gdbarch))
promoted_type = builtin_type (gdbarch)->builtin_long_double;
else
promoted_type = builtin_type (gdbarch)->builtin_double;
break;
}
}
else if (TYPE_CODE (type1) == TYPE_CODE_BOOL
&& TYPE_CODE (type2) == TYPE_CODE_BOOL)
{
/* No promotion required. */
}
else
/* Integral operations here. */
/* FIXME: Also mixed integral/booleans, with result an integer. */
{
const struct builtin_type *builtin = builtin_type (gdbarch);
unsigned int promoted_len1 = TYPE_LENGTH (type1);
unsigned int promoted_len2 = TYPE_LENGTH (type2);
int is_unsigned1 = TYPE_UNSIGNED (type1);
int is_unsigned2 = TYPE_UNSIGNED (type2);
unsigned int result_len;
int unsigned_operation;
/* Determine type length and signedness after promotion for
both operands. */
if (promoted_len1 < TYPE_LENGTH (builtin->builtin_int))
{
is_unsigned1 = 0;
promoted_len1 = TYPE_LENGTH (builtin->builtin_int);
}
if (promoted_len2 < TYPE_LENGTH (builtin->builtin_int))
{
is_unsigned2 = 0;
promoted_len2 = TYPE_LENGTH (builtin->builtin_int);
}
if (promoted_len1 > promoted_len2)
{
unsigned_operation = is_unsigned1;
result_len = promoted_len1;
}
else if (promoted_len2 > promoted_len1)
{
unsigned_operation = is_unsigned2;
result_len = promoted_len2;
}
else
{
unsigned_operation = is_unsigned1 || is_unsigned2;
result_len = promoted_len1;
}
switch (language->la_language)
{
case language_c:
case language_cplus:
case language_asm:
case language_objc:
if (result_len <= TYPE_LENGTH (builtin->builtin_int))
{
promoted_type = (unsigned_operation
? builtin->builtin_unsigned_int
: builtin->builtin_int);
}
else if (result_len <= TYPE_LENGTH (builtin->builtin_long))
{
promoted_type = (unsigned_operation
? builtin->builtin_unsigned_long
: builtin->builtin_long);
}
else
{
promoted_type = (unsigned_operation
? builtin->builtin_unsigned_long_long
: builtin->builtin_long_long);
}
break;
default:
/* For other languages the result type is unchanged from gdb
version 6.7 for backward compatibility.
If either arg was long long, make sure that value is also long
long. Otherwise use long. */
if (unsigned_operation)
{
if (result_len > gdbarch_long_bit (gdbarch) / HOST_CHAR_BIT)
promoted_type = builtin->builtin_unsigned_long_long;
else
promoted_type = builtin->builtin_unsigned_long;
}
else
{
if (result_len > gdbarch_long_bit (gdbarch) / HOST_CHAR_BIT)
promoted_type = builtin->builtin_long_long;
else
promoted_type = builtin->builtin_long;
}
break;
}
}
if (promoted_type)
{
/* Promote both operands to common type. */
*arg1 = value_cast (promoted_type, *arg1);
*arg2 = value_cast (promoted_type, *arg2);
}
}
static int
ptrmath_type_p (struct type *type)
{

View File

@ -39,10 +39,6 @@
#define TRUNCATION_TOWARDS_ZERO ((-5 / 2) == -2)
#endif
static struct type *unop_result_type (enum exp_opcode op, struct type *type1);
static struct type *binop_result_type (enum exp_opcode op, struct type *type1,
struct type *type2);
void _initialize_valarith (void);
@ -751,294 +747,6 @@ value_concat (struct value *arg1, struct value *arg2)
return (outval);
}
/* Return result type of OP performed on TYPE1.
The result type follows ANSI C rules.
If the result is not appropropriate for any particular language then it
needs to patch this function to return the correct type. */
static struct type *
unop_result_type (enum exp_opcode op, struct type *type1)
{
struct type *result_type;
type1 = check_typedef (type1);
result_type = type1;
switch (op)
{
case UNOP_PLUS:
case UNOP_NEG:
break;
case UNOP_COMPLEMENT:
/* Reject floats and decimal floats. */
if (!is_integral_type (type1))
error (_("Argument to complement operation not an integer or boolean."));
break;
default:
error (_("Invalid unary operation on numbers."));
}
if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
|| TYPE_CODE (type1) == TYPE_CODE_FLT)
{
return result_type;
}
else if (is_integral_type (type1))
{
/* Perform integral promotion for ANSI C/C++.
If not appropropriate for any particular language it needs to
modify this function to return the correct result for it. */
if (TYPE_LENGTH (type1) < TYPE_LENGTH (builtin_type_int))
result_type = builtin_type_int;
return result_type;
}
else
{
error (_("Argument to unary operation not a number."));
return 0; /* For lint -- never reached */
}
}
/* Return result type of OP performed on TYPE1, TYPE2.
If the result is not appropropriate for any particular language then it
needs to patch this function to return the correct type. */
static struct type *
binop_result_type (enum exp_opcode op, struct type *type1, struct type *type2)
{
type1 = check_typedef (type1);
type2 = check_typedef (type2);
if ((TYPE_CODE (type1) != TYPE_CODE_FLT
&& TYPE_CODE (type1) != TYPE_CODE_DECFLOAT
&& !is_integral_type (type1))
||
(TYPE_CODE (type2) != TYPE_CODE_FLT
&& TYPE_CODE (type2) != TYPE_CODE_DECFLOAT
&& !is_integral_type (type2)))
error (_("Argument to arithmetic operation not a number or boolean."));
if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
|| TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
{
switch (op)
{
case BINOP_ADD:
case BINOP_SUB:
case BINOP_MUL:
case BINOP_DIV:
case BINOP_EXP:
break;
default:
error (_("Operation not valid for decimal floating point number."));
}
if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT)
/* If type1 is not a decimal float, the type of the result is the type
of the decimal float argument, type2. */
return type2;
else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT)
/* Same logic, for the case where type2 is not a decimal float. */
return type1;
else
/* Both are decimal floats, the type of the result is the bigger
of the two. */
return (TYPE_LENGTH (type1) > TYPE_LENGTH (type2)) ? type1 : type2;
}
else if (TYPE_CODE (type1) == TYPE_CODE_FLT
|| TYPE_CODE (type2) == TYPE_CODE_FLT)
{
switch (op)
{
case BINOP_ADD:
case BINOP_SUB:
case BINOP_MUL:
case BINOP_DIV:
case BINOP_EXP:
case BINOP_MIN:
case BINOP_MAX:
break;
default:
error (_("Integer-only operation on floating point number."));
}
switch (current_language->la_language)
{
case language_c:
case language_cplus:
case language_asm:
case language_objc:
/* Perform ANSI/ISO-C promotions.
If only one type is float, use its type.
Otherwise use the bigger type. */
if (TYPE_CODE (type1) != TYPE_CODE_FLT)
return type2;
else if (TYPE_CODE (type2) != TYPE_CODE_FLT)
return type1;
else
return (TYPE_LENGTH (type1) > TYPE_LENGTH (type2)) ? type1 : type2;
default:
/* For other languages the result type is unchanged from gdb
version 6.7 for backward compatibility.
If either arg was long double, make sure that value is also long
double. Otherwise use double. */
if (TYPE_LENGTH (type1) * 8 > gdbarch_double_bit (current_gdbarch)
|| TYPE_LENGTH (type2) * 8 > gdbarch_double_bit (current_gdbarch))
return builtin_type_long_double;
else
return builtin_type_double;
}
}
else if (TYPE_CODE (type1) == TYPE_CODE_BOOL
&& TYPE_CODE (type2) == TYPE_CODE_BOOL)
{
switch (op)
{
case BINOP_BITWISE_AND:
case BINOP_BITWISE_IOR:
case BINOP_BITWISE_XOR:
case BINOP_EQUAL:
case BINOP_NOTEQUAL:
break;
default:
error (_("Invalid operation on booleans."));
}
return type1;
}
else
/* Integral operations here. */
/* FIXME: Also mixed integral/booleans, with result an integer. */
{
unsigned int promoted_len1 = TYPE_LENGTH (type1);
unsigned int promoted_len2 = TYPE_LENGTH (type2);
int is_unsigned1 = TYPE_UNSIGNED (type1);
int is_unsigned2 = TYPE_UNSIGNED (type2);
unsigned int result_len;
int unsigned_operation;
/* Determine type length and signedness after promotion for
both operands. */
if (promoted_len1 < TYPE_LENGTH (builtin_type_int))
{
is_unsigned1 = 0;
promoted_len1 = TYPE_LENGTH (builtin_type_int);
}
if (promoted_len2 < TYPE_LENGTH (builtin_type_int))
{
is_unsigned2 = 0;
promoted_len2 = TYPE_LENGTH (builtin_type_int);
}
/* Determine type length of the result, and if the operation should
be done unsigned. For exponentiation and shift operators,
use the length and type of the left operand. Otherwise,
use the signedness of the operand with the greater length.
If both operands are of equal length, use unsigned operation
if one of the operands is unsigned. */
if (op == BINOP_RSH || op == BINOP_LSH || op == BINOP_EXP)
{
/* In case of the shift operators and exponentiation the type of
the result only depends on the type of the left operand. */
unsigned_operation = is_unsigned1;
result_len = promoted_len1;
}
else if (promoted_len1 > promoted_len2)
{
unsigned_operation = is_unsigned1;
result_len = promoted_len1;
}
else if (promoted_len2 > promoted_len1)
{
unsigned_operation = is_unsigned2;
result_len = promoted_len2;
}
else
{
unsigned_operation = is_unsigned1 || is_unsigned2;
result_len = promoted_len1;
}
switch (op)
{
case BINOP_ADD:
case BINOP_SUB:
case BINOP_MUL:
case BINOP_DIV:
case BINOP_INTDIV:
case BINOP_EXP:
case BINOP_REM:
case BINOP_MOD:
case BINOP_LSH:
case BINOP_RSH:
case BINOP_BITWISE_AND:
case BINOP_BITWISE_IOR:
case BINOP_BITWISE_XOR:
case BINOP_LOGICAL_AND:
case BINOP_LOGICAL_OR:
case BINOP_MIN:
case BINOP_MAX:
case BINOP_EQUAL:
case BINOP_NOTEQUAL:
case BINOP_LESS:
break;
default:
error (_("Invalid binary operation on numbers."));
}
switch (current_language->la_language)
{
case language_c:
case language_cplus:
case language_asm:
case language_objc:
if (result_len <= TYPE_LENGTH (builtin_type_int))
{
return (unsigned_operation
? builtin_type_unsigned_int
: builtin_type_int);
}
else if (result_len <= TYPE_LENGTH (builtin_type_long))
{
return (unsigned_operation
? builtin_type_unsigned_long
: builtin_type_long);
}
else
{
return (unsigned_operation
? builtin_type_unsigned_long_long
: builtin_type_long_long);
}
default:
/* For other languages the result type is unchanged from gdb
version 6.7 for backward compatibility.
If either arg was long long, make sure that value is also long
long. Otherwise use long. */
if (unsigned_operation)
{
if (result_len > gdbarch_long_bit (current_gdbarch) / HOST_CHAR_BIT)
return builtin_type_unsigned_long_long;
else
return builtin_type_unsigned_long;
}
else
{
if (result_len > gdbarch_long_bit (current_gdbarch) / HOST_CHAR_BIT)
return builtin_type_long_long;
else
return builtin_type_long;
}
}
}
return NULL; /* avoid -Wall warning */
}
/* Integer exponentiation: V1**V2, where both arguments are
integers. Requires V1 != 0 if V2 < 0. Returns 1 for 0 ** 0. */
static LONGEST
@ -1166,14 +874,32 @@ struct value *
value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
{
struct value *val;
struct type *result_type;
struct type *type1, *type2, *result_type;
/* For shift and integer exponentiation operations,
only promote the first argument. */
if ((op == BINOP_LSH || op == BINOP_RSH || op == BINOP_EXP)
&& is_integral_type (value_type (arg2)))
unop_promote (current_language, current_gdbarch, &arg1);
else
binop_promote (current_language, current_gdbarch, &arg1, &arg2);
arg1 = coerce_ref (arg1);
arg2 = coerce_ref (arg2);
result_type = binop_result_type (op, value_type (arg1), value_type (arg2));
type1 = check_typedef (value_type (arg1));
type2 = check_typedef (value_type (arg2));
if (TYPE_CODE (result_type) == TYPE_CODE_DECFLOAT)
if ((TYPE_CODE (type1) != TYPE_CODE_FLT
&& TYPE_CODE (type1) != TYPE_CODE_DECFLOAT
&& !is_integral_type (type1))
|| (TYPE_CODE (type2) != TYPE_CODE_FLT
&& TYPE_CODE (type2) != TYPE_CODE_DECFLOAT
&& !is_integral_type (type2)))
error (_("Argument to arithmetic operation not a number or boolean."));
if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
|| TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
{
struct type *v_type;
int len_v1, len_v2, len_v;
@ -1196,9 +922,21 @@ value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
error (_("Operation not valid for decimal floating point number."));
}
/* If only one type is decimal float, use its type.
Otherwise use the bigger type. */
if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT)
result_type = type2;
else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT)
result_type = type1;
else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1))
result_type = type2;
else
result_type = type1;
val = value_from_decfloat (result_type, v);
}
else if (TYPE_CODE (result_type) == TYPE_CODE_FLT)
else if (TYPE_CODE (type1) == TYPE_CODE_FLT
|| TYPE_CODE (type2) == TYPE_CODE_FLT)
{
/* FIXME-if-picky-about-floating-accuracy: Should be doing this
in target format. real.c in GCC probably has the necessary
@ -1244,10 +982,22 @@ value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
error (_("Integer-only operation on floating point number."));
}
/* If only one type is float, use its type.
Otherwise use the bigger type. */
if (TYPE_CODE (type1) != TYPE_CODE_FLT)
result_type = type2;
else if (TYPE_CODE (type2) != TYPE_CODE_FLT)
result_type = type1;
else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1))
result_type = type2;
else
result_type = type1;
val = allocate_value (result_type);
store_typed_floating (value_contents_raw (val), value_type (val), v);
}
else if (TYPE_CODE (result_type) == TYPE_CODE_BOOL)
else if (TYPE_CODE (type1) == TYPE_CODE_BOOL
|| TYPE_CODE (type2) == TYPE_CODE_BOOL)
{
LONGEST v1, v2, v = 0;
v1 = value_as_long (arg1);
@ -1279,6 +1029,8 @@ value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
error (_("Invalid operation on booleans."));
}
result_type = type1;
val = allocate_value (result_type);
store_signed_integer (value_contents_raw (val),
TYPE_LENGTH (result_type),
@ -1287,31 +1039,32 @@ value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
else
/* Integral operations here. */
{
int unsigned_operation = TYPE_UNSIGNED (result_type);
/* Determine type length of the result, and if the operation should
be done unsigned. For exponentiation and shift operators,
use the length and type of the left operand. Otherwise,
use the signedness of the operand with the greater length.
If both operands are of equal length, use unsigned operation
if one of the operands is unsigned. */
if (op == BINOP_RSH || op == BINOP_LSH || op == BINOP_EXP)
result_type = type1;
else if (TYPE_LENGTH (type1) > TYPE_LENGTH (type2))
result_type = type1;
else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1))
result_type = type2;
else if (TYPE_UNSIGNED (type1))
result_type = type1;
else if (TYPE_UNSIGNED (type2))
result_type = type2;
else
result_type = type1;
if (unsigned_operation)
if (TYPE_UNSIGNED (result_type))
{
unsigned int len1, len2, result_len;
LONGEST v2_signed = value_as_long (arg2);
ULONGEST v1, v2, v = 0;
v1 = (ULONGEST) value_as_long (arg1);
v2 = (ULONGEST) v2_signed;
/* Truncate values to the type length of the result.
Things are mildly tricky because binop_result_type may
return a long which on amd64 is 8 bytes, and that's a problem if
ARG1, ARG2 are both <= 4 bytes: we need to truncate the values
at 4 bytes not 8. So fetch the lengths of the original types
and truncate at the larger of the two. */
len1 = TYPE_LENGTH (value_type (arg1));
len2 = TYPE_LENGTH (value_type (arg1));
result_len = len1 > len2 ? len1 : len2;
if (result_len < sizeof (ULONGEST))
{
v1 &= ((LONGEST) 1 << HOST_CHAR_BIT * result_len) - 1;
v2 &= ((LONGEST) 1 << HOST_CHAR_BIT * result_len) - 1;
}
switch (op)
{
case BINOP_ADD:
@ -1735,19 +1488,19 @@ struct value *
value_pos (struct value *arg1)
{
struct type *type;
struct type *result_type;
unop_promote (current_language, current_gdbarch, &arg1);
arg1 = coerce_ref (arg1);
type = check_typedef (value_type (arg1));
result_type = unop_result_type (UNOP_PLUS, value_type (arg1));
if (TYPE_CODE (type) == TYPE_CODE_FLT)
return value_from_double (result_type, value_as_double (arg1));
return value_from_double (type, value_as_double (arg1));
else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
return value_from_decfloat (result_type, value_contents (arg1));
return value_from_decfloat (type, value_contents (arg1));
else if (is_integral_type (type))
{
return value_from_longest (result_type, value_as_long (arg1));
return value_from_longest (type, value_as_long (arg1));
}
else
{
@ -1760,15 +1513,15 @@ struct value *
value_neg (struct value *arg1)
{
struct type *type;
struct type *result_type;
unop_promote (current_language, current_gdbarch, &arg1);
arg1 = coerce_ref (arg1);
type = check_typedef (value_type (arg1));
result_type = unop_result_type (UNOP_NEG, value_type (arg1));
if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
{
struct value *val = allocate_value (result_type);
struct value *val = allocate_value (type);
int len = TYPE_LENGTH (type);
gdb_byte decbytes[16]; /* a decfloat is at most 128 bits long */
@ -1783,10 +1536,10 @@ value_neg (struct value *arg1)
return val;
}
else if (TYPE_CODE (type) == TYPE_CODE_FLT)
return value_from_double (result_type, -value_as_double (arg1));
return value_from_double (type, -value_as_double (arg1));
else if (is_integral_type (type))
{
return value_from_longest (result_type, -value_as_long (arg1));
return value_from_longest (type, -value_as_long (arg1));
}
else
{
@ -1799,16 +1552,16 @@ struct value *
value_complement (struct value *arg1)
{
struct type *type;
struct type *result_type;
unop_promote (current_language, current_gdbarch, &arg1);
arg1 = coerce_ref (arg1);
type = check_typedef (value_type (arg1));
result_type = unop_result_type (UNOP_COMPLEMENT, value_type (arg1));
if (!is_integral_type (type))
error (_("Argument to complement operation not an integer or boolean."));
return value_from_longest (result_type, ~value_as_long (arg1));
return value_from_longest (type, ~value_as_long (arg1));
}
/* The INDEX'th bit of SET value whose value_type is TYPE,

View File

@ -446,6 +446,14 @@ extern CORE_ADDR parse_and_eval_address_1 (char **expptr);
extern LONGEST parse_and_eval_long (char *exp);
extern void unop_promote (const struct language_defn *language,
struct gdbarch *gdbarch,
struct value **arg1);
extern void binop_promote (const struct language_defn *language,
struct gdbarch *gdbarch,
struct value **arg1, struct value **arg2);
extern struct value *access_value_history (int num);
extern struct value *value_of_internalvar (struct internalvar *var);