Commit ab22c1fa by Chao-ying Fu Committed by Chao-ying Fu

c-common.h (enum rid): Add new enumeration values of RID_SAT, RID_FRACT, and RID_ACCUM.

	* c-common.h (enum rid): Add new enumeration values of RID_SAT,
	RID_FRACT, and RID_ACCUM.  RID_SAT needs to be inserted before
	RID_ONEWAY, so that it can be checked in declspecs_add_type.
	(c_common_fixed_point_type_for_size): Declare.
	* c-parser.c (reswords): Add _Fract, _Accum, and _Sat.
	(c_token_starts_typename): Handle RID_FRACT, RID_ACCUM, and RID_SAT.
	(c_token_starts_declspecs): Likewise.
	(c_parser_declspecs): Likewise.
	(c_parser_attributes): Likewise.
	* c-tree.h (enum c_typespec_keyword): Add cts_fract and cts_accum.
	(c_declspecs): Add saturating_p.
	* c-decl.c (build_null_declspecs): Initialize saturating_p.
	(declspecs_add_type): Avoid using complex with _Fract, _Accum, or _Sat.
	Handle RID_SAT.
	Avoid using void, bool, char, int, float, double, _Decimal32,
	_Decimal64, _Decimal128, and complex with _Sat.
	Handle RID_FRACT and RID_ACCUM.
	Make sure _Sat is used with _Fract or _Accum.
	(finish_declspecs): Handle cts_fract and cts_accum.
	* c-common.c (fixed-value.h): New include.
	(constant_expression_warning): Handle FIXED_CST.
	(overflow_warning): Likewise.
	(warnings_for_convert_and_check): Likewise.
	(c_common_fixed_point_type_for_size): New.
	(c_common_type_for_mode): Handle fixed-point modes to
	return various saturating/non-saturating, signed/unsigned types.
	(c_common_signed_or_unsigned_type): Support fixed-point types.
	(shorten_compare): Check fixed-point zero.
	Handle FIXED_POINT_TYPE.
	(c_common_truthvalue_conversion): Handle FIXED_CST.
	Handle FIXED_POINT_TYPE.
	(c_common_nodes_and_builtins): Record builtin types for fixed-point
	types.
	(handle_mode_attribute): Handle fixed-point modes.  Need to check
	if the signness of base type and fixed-point modes are consistent.
	(handle_vector_size_attribute): Handle fixed-point modes.
	(same_scalar_type_ignoring_signedness): Handle FIXED_POINT_TYPE.
	(warn_for_div_by_zero): Check fixed-point zero.
	* c-typeck.c (c_common_type): Check FIXED_POINT_TYPE.  Build
	a common fixed-point type based on fbit, ibit, sign, and saturation.
	(build_unary_op): Allow FIXED_POINT_TYPE for CONVERT_EXPR,
	NEGATE_EXPR, TRUTH_NOT_EXPR, PREINCREMENT_EXPR, POSTINCREMENT_EXPR,
	PREDECREMENT_EXPR, and POSTDECREMENT_EXPR.
	(convert_for_assignment): Support FIXED_POINT_TYPE.
	(digest_init): Handle FIXED_POINT_TYPE.
	(build_binary_op): Support FIXED_POINT_TYPE in *_DIV_EXPR,
	TRUTH_ANDIF_EXPR, TRUTH_ORIF_EXPR, TRUTH_AND_EXPR, TRUTH_OR_EXPR,
	TRUTH_XOR_EXPR, RSHIFT_EXPR, LSHIFT_EXPR, EQ_EXPR, NE_EXPR, LE_EXPR,
	GE_EXPR, LT_EXPR, GT_EXPR.
	* target-def.h (TARGET_FIXED_POINT_SUPPORTED_P): New.
	(TARGET_INITIALIZER): Add TARGET_FIXED_POINT_SUPPORTED_P.
	* target.h (gcc_target): Add fixed_point_supported_p.
	* targhooks.c (default_scalar_mode_supported_p): Handle MODE_FRACT,
	MODE_UFRACT, MODE_ACCUM, and MODE_UACCUM.
	(default_fixed_point_supported_p): Define.
	* targhooks.h (default_fixed_point_supported_p): Declare.
	* doc/tm.texi (TARGET_FIXED_POINT_SUPPORTED_P): Add.
	* doc/install.texi (Configuration): Add --enable-fixed-point.
	* configure.ac (--enable-fixed-point): New to enable fixed-point
	arithmetic extension to C.  For mips targets, we enable it by default.
	* configure, config.in: Regenerate.

From-SVN: r127652
parent 43f14744
2007-08-20 Chao-ying Fu <fu@mips.com>
* c-common.h (enum rid): Add new enumeration values of RID_SAT,
RID_FRACT, and RID_ACCUM. RID_SAT needs to be inserted before
RID_ONEWAY, so that it can be checked in declspecs_add_type.
(c_common_fixed_point_type_for_size): Declare.
* c-parser.c (reswords): Add _Fract, _Accum, and _Sat.
(c_token_starts_typename): Handle RID_FRACT, RID_ACCUM, and RID_SAT.
(c_token_starts_declspecs): Likewise.
(c_parser_declspecs): Likewise.
(c_parser_attributes): Likewise.
* c-tree.h (enum c_typespec_keyword): Add cts_fract and cts_accum.
(c_declspecs): Add saturating_p.
* c-decl.c (build_null_declspecs): Initialize saturating_p.
(declspecs_add_type): Avoid using complex with _Fract, _Accum, or _Sat.
Handle RID_SAT.
Avoid using void, bool, char, int, float, double, _Decimal32,
_Decimal64, _Decimal128, and complex with _Sat.
Handle RID_FRACT and RID_ACCUM.
Make sure _Sat is used with _Fract or _Accum.
(finish_declspecs): Handle cts_fract and cts_accum.
* c-common.c (fixed-value.h): New include.
(constant_expression_warning): Handle FIXED_CST.
(overflow_warning): Likewise.
(warnings_for_convert_and_check): Likewise.
(c_common_fixed_point_type_for_size): New.
(c_common_type_for_mode): Handle fixed-point modes to
return various saturating/non-saturating, signed/unsigned types.
(c_common_signed_or_unsigned_type): Support fixed-point types.
(shorten_compare): Check fixed-point zero.
Handle FIXED_POINT_TYPE.
(c_common_truthvalue_conversion): Handle FIXED_CST.
Handle FIXED_POINT_TYPE.
(c_common_nodes_and_builtins): Record builtin types for fixed-point
types.
(handle_mode_attribute): Handle fixed-point modes. Need to check
if the signness of base type and fixed-point modes are consistent.
(handle_vector_size_attribute): Handle fixed-point modes.
(same_scalar_type_ignoring_signedness): Handle FIXED_POINT_TYPE.
(warn_for_div_by_zero): Check fixed-point zero.
* c-typeck.c (c_common_type): Check FIXED_POINT_TYPE. Build
a common fixed-point type based on fbit, ibit, sign, and saturation.
(build_unary_op): Allow FIXED_POINT_TYPE for CONVERT_EXPR,
NEGATE_EXPR, TRUTH_NOT_EXPR, PREINCREMENT_EXPR, POSTINCREMENT_EXPR,
PREDECREMENT_EXPR, and POSTDECREMENT_EXPR.
(convert_for_assignment): Support FIXED_POINT_TYPE.
(digest_init): Handle FIXED_POINT_TYPE.
(build_binary_op): Support FIXED_POINT_TYPE in *_DIV_EXPR,
TRUTH_ANDIF_EXPR, TRUTH_ORIF_EXPR, TRUTH_AND_EXPR, TRUTH_OR_EXPR,
TRUTH_XOR_EXPR, RSHIFT_EXPR, LSHIFT_EXPR, EQ_EXPR, NE_EXPR, LE_EXPR,
GE_EXPR, LT_EXPR, GT_EXPR.
* target-def.h (TARGET_FIXED_POINT_SUPPORTED_P): New.
(TARGET_INITIALIZER): Add TARGET_FIXED_POINT_SUPPORTED_P.
* target.h (gcc_target): Add fixed_point_supported_p.
* targhooks.c (default_scalar_mode_supported_p): Handle MODE_FRACT,
MODE_UFRACT, MODE_ACCUM, and MODE_UACCUM.
(default_fixed_point_supported_p): Define.
* targhooks.h (default_fixed_point_supported_p): Declare.
* doc/tm.texi (TARGET_FIXED_POINT_SUPPORTED_P): Add.
* doc/install.texi (Configuration): Add --enable-fixed-point.
* configure.ac (--enable-fixed-point): New to enable fixed-point
arithmetic extension to C. For mips targets, we enable it by default.
* configure, config.in: Regenerate.
2007-08-20 Pawel Sikora <pluto@pld-linux.org> 2007-08-20 Pawel Sikora <pluto@pld-linux.org>
* doc/invoke.texi (-Wnon-virtual-dtor): Update documentation. * doc/invoke.texi (-Wnon-virtual-dtor): Update documentation.
......
...@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
#include "real.h" #include "real.h"
#include "cgraph.h" #include "cgraph.h"
#include "target-def.h" #include "target-def.h"
#include "fixed-value.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */ cpp_reader *parse_in; /* Declared in c-pragma.h. */
...@@ -929,6 +930,7 @@ void ...@@ -929,6 +930,7 @@ void
constant_expression_warning (tree value) constant_expression_warning (tree value)
{ {
if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST
|| TREE_CODE (value) == FIXED_CST
|| TREE_CODE (value) == VECTOR_CST || TREE_CODE (value) == VECTOR_CST
|| TREE_CODE (value) == COMPLEX_CST) || TREE_CODE (value) == COMPLEX_CST)
&& TREE_OVERFLOW (value) && TREE_OVERFLOW (value)
...@@ -963,6 +965,10 @@ overflow_warning (tree value) ...@@ -963,6 +965,10 @@ overflow_warning (tree value)
warning (OPT_Woverflow, "floating point overflow in expression"); warning (OPT_Woverflow, "floating point overflow in expression");
break; break;
case FIXED_CST:
warning (OPT_Woverflow, "fixed-point overflow in expression");
break;
case VECTOR_CST: case VECTOR_CST:
warning (OPT_Woverflow, "vector overflow in expression"); warning (OPT_Woverflow, "vector overflow in expression");
break; break;
...@@ -1360,7 +1366,8 @@ warnings_for_convert_and_check (tree type, tree expr, tree result) ...@@ -1360,7 +1366,8 @@ warnings_for_convert_and_check (tree type, tree expr, tree result)
else else
conversion_warning (type, expr); conversion_warning (type, expr);
} }
else if (TREE_CODE (result) == INTEGER_CST && TREE_OVERFLOW (result)) else if ((TREE_CODE (result) == INTEGER_CST
|| TREE_CODE (result) == FIXED_CST) && TREE_OVERFLOW (result))
warning (OPT_Woverflow, warning (OPT_Woverflow,
"overflow in implicit constant conversion"); "overflow in implicit constant conversion");
else else
...@@ -1928,13 +1935,44 @@ c_common_type_for_size (unsigned int bits, int unsignedp) ...@@ -1928,13 +1935,44 @@ c_common_type_for_size (unsigned int bits, int unsignedp)
return 0; return 0;
} }
/* Return a fixed-point type that has at least IBIT ibits and FBIT fbits
that is unsigned if UNSIGNEDP is nonzero, otherwise signed;
and saturating if SATP is nonzero, otherwise not saturating. */
tree
c_common_fixed_point_type_for_size (unsigned int ibit, unsigned int fbit,
int unsignedp, int satp)
{
enum machine_mode mode;
if (ibit == 0)
mode = unsignedp ? UQQmode : QQmode;
else
mode = unsignedp ? UHAmode : HAmode;
for (; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode))
if (GET_MODE_IBIT (mode) >= ibit && GET_MODE_FBIT (mode) >= fbit)
break;
if (mode == VOIDmode || !targetm.scalar_mode_supported_p (mode))
{
sorry ("GCC cannot support operators with integer types and "
"fixed-point types that have too many integral and "
"fractional bits together");
return 0;
}
return c_common_type_for_mode (mode, satp);
}
/* Used for communication between c_common_type_for_mode and /* Used for communication between c_common_type_for_mode and
c_register_builtin_type. */ c_register_builtin_type. */
static GTY(()) tree registered_builtin_types; static GTY(()) tree registered_builtin_types;
/* Return a data type that has machine mode MODE. /* Return a data type that has machine mode MODE.
If the mode is an integer, If the mode is an integer,
then UNSIGNEDP selects between signed and unsigned types. */ then UNSIGNEDP selects between signed and unsigned types.
If the mode is a fixed-point mode,
then UNSIGNEDP selects between saturating and nonsaturating types. */
tree tree
c_common_type_for_mode (enum machine_mode mode, int unsignedp) c_common_type_for_mode (enum machine_mode mode, int unsignedp)
...@@ -2034,6 +2072,95 @@ c_common_type_for_mode (enum machine_mode mode, int unsignedp) ...@@ -2034,6 +2072,95 @@ c_common_type_for_mode (enum machine_mode mode, int unsignedp)
if (mode == TYPE_MODE (dfloat128_type_node)) if (mode == TYPE_MODE (dfloat128_type_node))
return dfloat128_type_node; return dfloat128_type_node;
if (ALL_SCALAR_FIXED_POINT_MODE_P (mode))
{
if (mode == TYPE_MODE (short_fract_type_node))
return unsignedp ? sat_short_fract_type_node : short_fract_type_node;
if (mode == TYPE_MODE (fract_type_node))
return unsignedp ? sat_fract_type_node : fract_type_node;
if (mode == TYPE_MODE (long_fract_type_node))
return unsignedp ? sat_long_fract_type_node : long_fract_type_node;
if (mode == TYPE_MODE (long_long_fract_type_node))
return unsignedp ? sat_long_long_fract_type_node
: long_long_fract_type_node;
if (mode == TYPE_MODE (unsigned_short_fract_type_node))
return unsignedp ? sat_unsigned_short_fract_type_node
: unsigned_short_fract_type_node;
if (mode == TYPE_MODE (unsigned_fract_type_node))
return unsignedp ? sat_unsigned_fract_type_node
: unsigned_fract_type_node;
if (mode == TYPE_MODE (unsigned_long_fract_type_node))
return unsignedp ? sat_unsigned_long_fract_type_node
: unsigned_long_fract_type_node;
if (mode == TYPE_MODE (unsigned_long_long_fract_type_node))
return unsignedp ? sat_unsigned_long_long_fract_type_node
: unsigned_long_long_fract_type_node;
if (mode == TYPE_MODE (short_accum_type_node))
return unsignedp ? sat_short_accum_type_node : short_accum_type_node;
if (mode == TYPE_MODE (accum_type_node))
return unsignedp ? sat_accum_type_node : accum_type_node;
if (mode == TYPE_MODE (long_accum_type_node))
return unsignedp ? sat_long_accum_type_node : long_accum_type_node;
if (mode == TYPE_MODE (long_long_accum_type_node))
return unsignedp ? sat_long_long_accum_type_node
: long_long_accum_type_node;
if (mode == TYPE_MODE (unsigned_short_accum_type_node))
return unsignedp ? sat_unsigned_short_accum_type_node
: unsigned_short_accum_type_node;
if (mode == TYPE_MODE (unsigned_accum_type_node))
return unsignedp ? sat_unsigned_accum_type_node
: unsigned_accum_type_node;
if (mode == TYPE_MODE (unsigned_long_accum_type_node))
return unsignedp ? sat_unsigned_long_accum_type_node
: unsigned_long_accum_type_node;
if (mode == TYPE_MODE (unsigned_long_long_accum_type_node))
return unsignedp ? sat_unsigned_long_long_accum_type_node
: unsigned_long_long_accum_type_node;
if (mode == QQmode)
return unsignedp ? sat_qq_type_node : qq_type_node;
if (mode == HQmode)
return unsignedp ? sat_hq_type_node : hq_type_node;
if (mode == SQmode)
return unsignedp ? sat_sq_type_node : sq_type_node;
if (mode == DQmode)
return unsignedp ? sat_dq_type_node : dq_type_node;
if (mode == TQmode)
return unsignedp ? sat_tq_type_node : tq_type_node;
if (mode == UQQmode)
return unsignedp ? sat_uqq_type_node : uqq_type_node;
if (mode == UHQmode)
return unsignedp ? sat_uhq_type_node : uhq_type_node;
if (mode == USQmode)
return unsignedp ? sat_usq_type_node : usq_type_node;
if (mode == UDQmode)
return unsignedp ? sat_udq_type_node : udq_type_node;
if (mode == UTQmode)
return unsignedp ? sat_utq_type_node : utq_type_node;
if (mode == HAmode)
return unsignedp ? sat_ha_type_node : ha_type_node;
if (mode == SAmode)
return unsignedp ? sat_sa_type_node : sa_type_node;
if (mode == DAmode)
return unsignedp ? sat_da_type_node : da_type_node;
if (mode == TAmode)
return unsignedp ? sat_ta_type_node : ta_type_node;
if (mode == UHAmode)
return unsignedp ? sat_uha_type_node : uha_type_node;
if (mode == USAmode)
return unsignedp ? sat_usa_type_node : usa_type_node;
if (mode == UDAmode)
return unsignedp ? sat_uda_type_node : uda_type_node;
if (mode == UTAmode)
return unsignedp ? sat_uta_type_node : uta_type_node;
}
for (t = registered_builtin_types; t; t = TREE_CHAIN (t)) for (t = registered_builtin_types; t; t = TREE_CHAIN (t))
if (TYPE_MODE (TREE_VALUE (t)) == mode) if (TYPE_MODE (TREE_VALUE (t)) == mode)
return TREE_VALUE (t); return TREE_VALUE (t);
...@@ -2095,6 +2222,54 @@ c_common_signed_or_unsigned_type (int unsignedp, tree type) ...@@ -2095,6 +2222,54 @@ c_common_signed_or_unsigned_type (int unsignedp, tree type)
if (type1 == intQI_type_node || type1 == unsigned_intQI_type_node) if (type1 == intQI_type_node || type1 == unsigned_intQI_type_node)
return unsignedp ? unsigned_intQI_type_node : intQI_type_node; return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
#define C_COMMON_FIXED_TYPES(SAT,NAME) \
if (type1 == SAT ## short_ ## NAME ## _type_node \
|| type1 == SAT ## unsigned_short_ ## NAME ## _type_node) \
return unsignedp ? SAT ## unsigned_short_ ## NAME ## _type_node \
: SAT ## short_ ## NAME ## _type_node; \
if (type1 == SAT ## NAME ## _type_node \
|| type1 == SAT ## unsigned_ ## NAME ## _type_node) \
return unsignedp ? SAT ## unsigned_ ## NAME ## _type_node \
: SAT ## NAME ## _type_node; \
if (type1 == SAT ## long_ ## NAME ## _type_node \
|| type1 == SAT ## unsigned_long_ ## NAME ## _type_node) \
return unsignedp ? SAT ## unsigned_long_ ## NAME ## _type_node \
: SAT ## long_ ## NAME ## _type_node; \
if (type1 == SAT ## long_long_ ## NAME ## _type_node \
|| type1 == SAT ## unsigned_long_long_ ## NAME ## _type_node) \
return unsignedp ? SAT ## unsigned_long_long_ ## NAME ## _type_node \
: SAT ## long_long_ ## NAME ## _type_node;
#define C_COMMON_FIXED_MODE_TYPES(SAT,NAME) \
if (type1 == SAT ## NAME ## _type_node \
|| type1 == SAT ## u ## NAME ## _type_node) \
return unsignedp ? SAT ## u ## NAME ## _type_node \
: SAT ## NAME ## _type_node;
C_COMMON_FIXED_TYPES (, fract);
C_COMMON_FIXED_TYPES (sat_, fract);
C_COMMON_FIXED_TYPES (, accum);
C_COMMON_FIXED_TYPES (sat_, accum);
C_COMMON_FIXED_MODE_TYPES (, qq);
C_COMMON_FIXED_MODE_TYPES (, hq);
C_COMMON_FIXED_MODE_TYPES (, sq);
C_COMMON_FIXED_MODE_TYPES (, dq);
C_COMMON_FIXED_MODE_TYPES (, tq);
C_COMMON_FIXED_MODE_TYPES (sat_, qq);
C_COMMON_FIXED_MODE_TYPES (sat_, hq);
C_COMMON_FIXED_MODE_TYPES (sat_, sq);
C_COMMON_FIXED_MODE_TYPES (sat_, dq);
C_COMMON_FIXED_MODE_TYPES (sat_, tq);
C_COMMON_FIXED_MODE_TYPES (, ha);
C_COMMON_FIXED_MODE_TYPES (, sa);
C_COMMON_FIXED_MODE_TYPES (, da);
C_COMMON_FIXED_MODE_TYPES (, ta);
C_COMMON_FIXED_MODE_TYPES (sat_, ha);
C_COMMON_FIXED_MODE_TYPES (sat_, sa);
C_COMMON_FIXED_MODE_TYPES (sat_, da);
C_COMMON_FIXED_MODE_TYPES (sat_, ta);
/* For ENUMERAL_TYPEs in C++, must check the mode of the types, not /* For ENUMERAL_TYPEs in C++, must check the mode of the types, not
the precision; they have precision set to match their range, but the precision; they have precision set to match their range, but
may use a wider mode to match an ABI. If we change modes, we may may use a wider mode to match an ABI. If we change modes, we may
...@@ -2323,7 +2498,8 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, ...@@ -2323,7 +2498,8 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
the second arg is 0. */ the second arg is 0. */
if (TREE_CONSTANT (primop0) if (TREE_CONSTANT (primop0)
&& !integer_zerop (primop1) && !real_zerop (primop1)) && !integer_zerop (primop1) && !real_zerop (primop1)
&& !fixed_zerop (primop1))
{ {
tree tem = primop0; tree tem = primop0;
int temi = unsignedp0; int temi = unsignedp0;
...@@ -2378,6 +2554,7 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr, ...@@ -2378,6 +2554,7 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
and see if that preserves the constant's value. */ and see if that preserves the constant's value. */
if (!real1 && !real2 if (!real1 && !real2
&& TREE_CODE (TREE_TYPE (primop0)) != FIXED_POINT_TYPE
&& TREE_CODE (primop1) == INTEGER_CST && TREE_CODE (primop1) == INTEGER_CST
&& TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)) && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr))
{ {
...@@ -2783,6 +2960,12 @@ c_common_truthvalue_conversion (tree expr) ...@@ -2783,6 +2960,12 @@ c_common_truthvalue_conversion (tree expr)
? truthvalue_true_node ? truthvalue_true_node
: truthvalue_false_node; : truthvalue_false_node;
case FIXED_CST:
return fixed_compare (NE_EXPR, &TREE_FIXED_CST (expr),
&FCONST0 (TYPE_MODE (TREE_TYPE (expr))))
? truthvalue_true_node
: truthvalue_false_node;
case FUNCTION_DECL: case FUNCTION_DECL:
expr = build_unary_op (ADDR_EXPR, expr, 0); expr = build_unary_op (ADDR_EXPR, expr, 0);
/* Fall through. */ /* Fall through. */
...@@ -2883,6 +3066,14 @@ c_common_truthvalue_conversion (tree expr) ...@@ -2883,6 +3066,14 @@ c_common_truthvalue_conversion (tree expr)
0)); 0));
} }
if (TREE_CODE (TREE_TYPE (expr)) == FIXED_POINT_TYPE)
{
tree fixed_zero_node = build_fixed (TREE_TYPE (expr),
FCONST0 (TYPE_MODE
(TREE_TYPE (expr))));
return build_binary_op (NE_EXPR, expr, fixed_zero_node, 1);
}
return build_binary_op (NE_EXPR, expr, integer_zero_node, 1); return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
} }
...@@ -3594,6 +3785,67 @@ c_common_nodes_and_builtins (void) ...@@ -3594,6 +3785,67 @@ c_common_nodes_and_builtins (void)
record_builtin_type (RID_DFLOAT128, NULL, dfloat128_type_node); record_builtin_type (RID_DFLOAT128, NULL, dfloat128_type_node);
} }
if (targetm.fixed_point_supported_p ())
{
record_builtin_type (RID_MAX, "short _Fract", short_fract_type_node);
record_builtin_type (RID_FRACT, NULL, fract_type_node);
record_builtin_type (RID_MAX, "long _Fract", long_fract_type_node);
record_builtin_type (RID_MAX, "long long _Fract",
long_long_fract_type_node);
record_builtin_type (RID_MAX, "unsigned short _Fract",
unsigned_short_fract_type_node);
record_builtin_type (RID_MAX, "unsigned _Fract",
unsigned_fract_type_node);
record_builtin_type (RID_MAX, "unsigned long _Fract",
unsigned_long_fract_type_node);
record_builtin_type (RID_MAX, "unsigned long long _Fract",
unsigned_long_long_fract_type_node);
record_builtin_type (RID_MAX, "_Sat short _Fract",
sat_short_fract_type_node);
record_builtin_type (RID_MAX, "_Sat _Fract", sat_fract_type_node);
record_builtin_type (RID_MAX, "_Sat long _Fract",
sat_long_fract_type_node);
record_builtin_type (RID_MAX, "_Sat long long _Fract",
sat_long_long_fract_type_node);
record_builtin_type (RID_MAX, "_Sat unsigned short _Fract",
sat_unsigned_short_fract_type_node);
record_builtin_type (RID_MAX, "_Sat unsigned _Fract",
sat_unsigned_fract_type_node);
record_builtin_type (RID_MAX, "_Sat unsigned long _Fract",
sat_unsigned_long_fract_type_node);
record_builtin_type (RID_MAX, "_Sat unsigned long long _Fract",
sat_unsigned_long_long_fract_type_node);
record_builtin_type (RID_MAX, "short _Accum", short_accum_type_node);
record_builtin_type (RID_ACCUM, NULL, accum_type_node);
record_builtin_type (RID_MAX, "long _Accum", long_accum_type_node);
record_builtin_type (RID_MAX, "long long _Accum",
long_long_accum_type_node);
record_builtin_type (RID_MAX, "unsigned short _Accum",
unsigned_short_accum_type_node);
record_builtin_type (RID_MAX, "unsigned _Accum",
unsigned_accum_type_node);
record_builtin_type (RID_MAX, "unsigned long _Accum",
unsigned_long_accum_type_node);
record_builtin_type (RID_MAX, "unsigned long long _Accum",
unsigned_long_long_accum_type_node);
record_builtin_type (RID_MAX, "_Sat short _Accum",
sat_short_accum_type_node);
record_builtin_type (RID_MAX, "_Sat _Accum", sat_accum_type_node);
record_builtin_type (RID_MAX, "_Sat long _Accum",
sat_long_accum_type_node);
record_builtin_type (RID_MAX, "_Sat long long _Accum",
sat_long_long_accum_type_node);
record_builtin_type (RID_MAX, "_Sat unsigned short _Accum",
sat_unsigned_short_accum_type_node);
record_builtin_type (RID_MAX, "_Sat unsigned _Accum",
sat_unsigned_accum_type_node);
record_builtin_type (RID_MAX, "_Sat unsigned long _Accum",
sat_unsigned_long_accum_type_node);
record_builtin_type (RID_MAX, "_Sat unsigned long long _Accum",
sat_unsigned_long_long_accum_type_node);
}
lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
get_identifier ("complex int"), get_identifier ("complex int"),
complex_integer_type_node)); complex_integer_type_node));
...@@ -5013,6 +5265,10 @@ handle_mode_attribute (tree *node, tree name, tree args, ...@@ -5013,6 +5265,10 @@ handle_mode_attribute (tree *node, tree name, tree args,
case MODE_PARTIAL_INT: case MODE_PARTIAL_INT:
case MODE_FLOAT: case MODE_FLOAT:
case MODE_DECIMAL_FLOAT: case MODE_DECIMAL_FLOAT:
case MODE_FRACT:
case MODE_UFRACT:
case MODE_ACCUM:
case MODE_UACCUM:
valid_mode = targetm.scalar_mode_supported_p (mode); valid_mode = targetm.scalar_mode_supported_p (mode);
break; break;
...@@ -5023,6 +5279,10 @@ handle_mode_attribute (tree *node, tree name, tree args, ...@@ -5023,6 +5279,10 @@ handle_mode_attribute (tree *node, tree name, tree args,
case MODE_VECTOR_INT: case MODE_VECTOR_INT:
case MODE_VECTOR_FLOAT: case MODE_VECTOR_FLOAT:
case MODE_VECTOR_FRACT:
case MODE_VECTOR_UFRACT:
case MODE_VECTOR_ACCUM:
case MODE_VECTOR_UACCUM:
warning (OPT_Wattributes, "specifying vector types with " warning (OPT_Wattributes, "specifying vector types with "
"__attribute__ ((mode)) is deprecated"); "__attribute__ ((mode)) is deprecated");
warning (OPT_Wattributes, warning (OPT_Wattributes,
...@@ -5056,7 +5316,20 @@ handle_mode_attribute (tree *node, tree name, tree args, ...@@ -5056,7 +5316,20 @@ handle_mode_attribute (tree *node, tree name, tree args,
typefm = fn (TREE_TYPE (type), mode, false); typefm = fn (TREE_TYPE (type), mode, false);
} }
else else
typefm = lang_hooks.types.type_for_mode (mode, TYPE_UNSIGNED (type)); {
/* For fixed-point modes, we need to test if the signness of type
and the machine mode are consistent. */
if (ALL_FIXED_POINT_MODE_P (mode)
&& TYPE_UNSIGNED (type) != UNSIGNED_FIXED_POINT_MODE_P (mode))
{
error ("signness of type and machine mode %qs don't match", p);
return NULL_TREE;
}
/* For fixed-point modes, we need to pass saturating info. */
typefm = lang_hooks.types.type_for_mode (mode,
ALL_FIXED_POINT_MODE_P (mode) ? TYPE_SATURATING (type)
: TYPE_UNSIGNED (type));
}
if (typefm == NULL_TREE) if (typefm == NULL_TREE)
{ {
...@@ -5805,7 +6078,8 @@ handle_vector_size_attribute (tree *node, tree name, tree args, ...@@ -5805,7 +6078,8 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
|| TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == VECTOR_TYPE || TREE_CODE (type) == VECTOR_TYPE
|| (!SCALAR_FLOAT_MODE_P (orig_mode) || (!SCALAR_FLOAT_MODE_P (orig_mode)
&& GET_MODE_CLASS (orig_mode) != MODE_INT) && GET_MODE_CLASS (orig_mode) != MODE_INT
&& !ALL_SCALAR_FIXED_POINT_MODE_P (orig_mode))
|| !host_integerp (TYPE_SIZE_UNIT (type), 1)) || !host_integerp (TYPE_SIZE_UNIT (type), 1))
{ {
error ("invalid vector type for attribute %qE", name); error ("invalid vector type for attribute %qE", name);
...@@ -6938,8 +7212,9 @@ same_scalar_type_ignoring_signedness (tree t1, tree t2) ...@@ -6938,8 +7212,9 @@ same_scalar_type_ignoring_signedness (tree t1, tree t2)
{ {
enum tree_code c1 = TREE_CODE (t1), c2 = TREE_CODE (t2); enum tree_code c1 = TREE_CODE (t1), c2 = TREE_CODE (t2);
gcc_assert ((c1 == INTEGER_TYPE || c1 == REAL_TYPE) gcc_assert ((c1 == INTEGER_TYPE || c1 == REAL_TYPE || c1 == FIXED_POINT_TYPE)
&& (c2 == INTEGER_TYPE || c2 == REAL_TYPE)); && (c2 == INTEGER_TYPE || c2 == REAL_TYPE
|| c2 == FIXED_POINT_TYPE));
/* Equality works here because c_common_signed_type uses /* Equality works here because c_common_signed_type uses
TYPE_MAIN_VARIANT. */ TYPE_MAIN_VARIANT. */
...@@ -7104,11 +7379,12 @@ struct gcc_targetcm targetcm = TARGETCM_INITIALIZER; ...@@ -7104,11 +7379,12 @@ struct gcc_targetcm targetcm = TARGETCM_INITIALIZER;
void void
warn_for_div_by_zero (tree divisor) warn_for_div_by_zero (tree divisor)
{ {
/* If DIVISOR is zero, and has integral type, issue a warning about /* If DIVISOR is zero, and has integral or fixed-point type, issue a warning
division by zero. Do not issue a warning if DIVISOR has a about division by zero. Do not issue a warning if DIVISOR has a
floating-point type, since we consider 0.0/0.0 a valid way of floating-point type, since we consider 0.0/0.0 a valid way of
generating a NaN. */ generating a NaN. */
if (skip_evaluation == 0 && integer_zerop (divisor)) if (skip_evaluation == 0
&& (integer_zerop (divisor) || fixed_zerop (divisor)))
warning (OPT_Wdiv_by_zero, "division by zero"); warning (OPT_Wdiv_by_zero, "division by zero");
} }
......
...@@ -52,7 +52,7 @@ enum rid ...@@ -52,7 +52,7 @@ enum rid
RID_VOLATILE, RID_SIGNED, RID_AUTO, RID_RESTRICT, RID_VOLATILE, RID_SIGNED, RID_AUTO, RID_RESTRICT,
/* C extensions */ /* C extensions */
RID_COMPLEX, RID_THREAD, RID_COMPLEX, RID_THREAD, RID_SAT,
/* C++ */ /* C++ */
RID_FRIEND, RID_VIRTUAL, RID_EXPLICIT, RID_EXPORT, RID_MUTABLE, RID_FRIEND, RID_VIRTUAL, RID_EXPLICIT, RID_EXPORT, RID_MUTABLE,
...@@ -72,6 +72,7 @@ enum rid ...@@ -72,6 +72,7 @@ enum rid
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR, RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
RID_TYPES_COMPATIBLE_P, RID_TYPES_COMPATIBLE_P,
RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
RID_FRACT, RID_ACCUM,
/* Too many ways of getting the name of a function as a string */ /* Too many ways of getting the name of a function as a string */
RID_FUNCTION_NAME, RID_PRETTY_FUNCTION_NAME, RID_C99_FUNCTION_NAME, RID_FUNCTION_NAME, RID_PRETTY_FUNCTION_NAME, RID_C99_FUNCTION_NAME,
...@@ -670,6 +671,8 @@ extern int c_common_handle_option (size_t code, const char *arg, int value); ...@@ -670,6 +671,8 @@ extern int c_common_handle_option (size_t code, const char *arg, int value);
extern bool c_common_missing_argument (const char *opt, size_t code); extern bool c_common_missing_argument (const char *opt, size_t code);
extern tree c_common_type_for_mode (enum machine_mode, int); extern tree c_common_type_for_mode (enum machine_mode, int);
extern tree c_common_type_for_size (unsigned int, int); extern tree c_common_type_for_size (unsigned int, int);
extern tree c_common_fixed_point_type_for_size (unsigned int, unsigned int,
int, int);
extern tree c_common_unsigned_type (tree); extern tree c_common_unsigned_type (tree);
extern tree c_common_signed_type (tree); extern tree c_common_signed_type (tree);
extern tree c_common_signed_or_unsigned_type (int, tree); extern tree c_common_signed_or_unsigned_type (int, tree);
......
...@@ -7134,6 +7134,7 @@ build_null_declspecs (void) ...@@ -7134,6 +7134,7 @@ build_null_declspecs (void)
ret->const_p = false; ret->const_p = false;
ret->volatile_p = false; ret->volatile_p = false;
ret->restrict_p = false; ret->restrict_p = false;
ret->saturating_p = false;
return ret; return ret;
} }
...@@ -7196,7 +7197,7 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) ...@@ -7196,7 +7197,7 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
} }
if ((int) i <= (int) RID_LAST_MODIFIER) if ((int) i <= (int) RID_LAST_MODIFIER)
{ {
/* "long", "short", "signed", "unsigned" or "_Complex". */ /* "long", "short", "signed", "unsigned", "_Complex" or "_Sat". */
bool dupe = false; bool dupe = false;
switch (i) switch (i)
{ {
...@@ -7356,9 +7357,55 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) ...@@ -7356,9 +7357,55 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
else if (specs->typespec_word == cts_dfloat128) else if (specs->typespec_word == cts_dfloat128)
error ("both %<complex%> and %<_Decimal128%> in " error ("both %<complex%> and %<_Decimal128%> in "
"declaration specifiers"); "declaration specifiers");
else if (specs->typespec_word == cts_fract)
error ("both %<complex%> and %<_Fract%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_accum)
error ("both %<complex%> and %<_Accum%> in "
"declaration specifiers");
else if (specs->saturating_p)
error ("both %<complex%> and %<_Sat%> in "
"declaration specifiers");
else else
specs->complex_p = true; specs->complex_p = true;
break; break;
case RID_SAT:
dupe = specs->saturating_p;
if (pedantic)
pedwarn ("ISO C does not support saturating types");
if (specs->typespec_word == cts_void)
error ("both %<_Sat%> and %<void%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_bool)
error ("both %<_Sat%> and %<_Bool%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_char)
error ("both %<_Sat%> and %<char%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_int)
error ("both %<_Sat%> and %<int%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_float)
error ("both %<_Sat%> and %<float%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_double)
error ("both %<_Sat%> and %<double%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_dfloat32)
error ("both %<_Sat%> and %<_Decimal32%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_dfloat64)
error ("both %<_Sat%> and %<_Decimal64%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_dfloat128)
error ("both %<_Sat%> and %<_Decimal128%> in "
"declaration specifiers");
else if (specs->complex_p)
error ("both %<_Sat%> and %<complex%> in "
"declaration specifiers");
else
specs->saturating_p = true;
break;
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
...@@ -7370,7 +7417,8 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) ...@@ -7370,7 +7417,8 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
} }
else else
{ {
/* "void", "_Bool", "char", "int", "float" or "double". */ /* "void", "_Bool", "char", "int", "float", "double", "_Decimal32",
"_Decimal64", "_Decimal128", "_Fract" or "_Accum". */
if (specs->typespec_word != cts_none) if (specs->typespec_word != cts_none)
{ {
error ("two or more data types in declaration specifiers"); error ("two or more data types in declaration specifiers");
...@@ -7394,6 +7442,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) ...@@ -7394,6 +7442,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
else if (specs->complex_p) else if (specs->complex_p)
error ("both %<complex%> and %<void%> in " error ("both %<complex%> and %<void%> in "
"declaration specifiers"); "declaration specifiers");
else if (specs->saturating_p)
error ("both %<_Sat%> and %<void%> in "
"declaration specifiers");
else else
specs->typespec_word = cts_void; specs->typespec_word = cts_void;
return specs; return specs;
...@@ -7413,6 +7464,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) ...@@ -7413,6 +7464,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
else if (specs->complex_p) else if (specs->complex_p)
error ("both %<complex%> and %<_Bool%> in " error ("both %<complex%> and %<_Bool%> in "
"declaration specifiers"); "declaration specifiers");
else if (specs->saturating_p)
error ("both %<_Sat%> and %<_Bool%> in "
"declaration specifiers");
else else
specs->typespec_word = cts_bool; specs->typespec_word = cts_bool;
return specs; return specs;
...@@ -7423,11 +7477,18 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) ...@@ -7423,11 +7477,18 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
else if (specs->short_p) else if (specs->short_p)
error ("both %<short%> and %<char%> in " error ("both %<short%> and %<char%> in "
"declaration specifiers"); "declaration specifiers");
else if (specs->saturating_p)
error ("both %<_Sat%> and %<char%> in "
"declaration specifiers");
else else
specs->typespec_word = cts_char; specs->typespec_word = cts_char;
return specs; return specs;
case RID_INT: case RID_INT:
specs->typespec_word = cts_int; if (specs->saturating_p)
error ("both %<_Sat%> and %<int%> in "
"declaration specifiers");
else
specs->typespec_word = cts_int;
return specs; return specs;
case RID_FLOAT: case RID_FLOAT:
if (specs->long_p) if (specs->long_p)
...@@ -7442,6 +7503,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) ...@@ -7442,6 +7503,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
else if (specs->unsigned_p) else if (specs->unsigned_p)
error ("both %<unsigned%> and %<float%> in " error ("both %<unsigned%> and %<float%> in "
"declaration specifiers"); "declaration specifiers");
else if (specs->saturating_p)
error ("both %<_Sat%> and %<float%> in "
"declaration specifiers");
else else
specs->typespec_word = cts_float; specs->typespec_word = cts_float;
return specs; return specs;
...@@ -7458,6 +7522,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) ...@@ -7458,6 +7522,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
else if (specs->unsigned_p) else if (specs->unsigned_p)
error ("both %<unsigned%> and %<double%> in " error ("both %<unsigned%> and %<double%> in "
"declaration specifiers"); "declaration specifiers");
else if (specs->saturating_p)
error ("both %<_Sat%> and %<double%> in "
"declaration specifiers");
else else
specs->typespec_word = cts_double; specs->typespec_word = cts_double;
return specs; return specs;
...@@ -7490,6 +7557,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) ...@@ -7490,6 +7557,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
else if (specs->complex_p) else if (specs->complex_p)
error ("both %<complex%> and %<%s%> in " error ("both %<complex%> and %<%s%> in "
"declaration specifiers", str); "declaration specifiers", str);
else if (specs->saturating_p)
error ("both %<_Sat%> and %<%s%> in "
"declaration specifiers", str);
else if (i == RID_DFLOAT32) else if (i == RID_DFLOAT32)
specs->typespec_word = cts_dfloat32; specs->typespec_word = cts_dfloat32;
else if (i == RID_DFLOAT64) else if (i == RID_DFLOAT64)
...@@ -7502,6 +7572,27 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) ...@@ -7502,6 +7572,27 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
if (pedantic) if (pedantic)
pedwarn ("ISO C does not support decimal floating point"); pedwarn ("ISO C does not support decimal floating point");
return specs; return specs;
case RID_FRACT:
case RID_ACCUM:
{
const char *str;
if (i == RID_FRACT)
str = "_Fract";
else
str = "_Accum";
if (specs->complex_p)
error ("both %<complex%> and %<%s%> in "
"declaration specifiers", str);
else if (i == RID_FRACT)
specs->typespec_word = cts_fract;
else
specs->typespec_word = cts_accum;
}
if (!targetm.fixed_point_supported_p ())
error ("fixed-point types not supported for this target");
if (pedantic)
pedwarn ("ISO C does not support fixed-point types");
return specs;
default: default:
/* ObjC reserved word "id", handled below. */ /* ObjC reserved word "id", handled below. */
break; break;
...@@ -7673,6 +7764,8 @@ finish_declspecs (struct c_declspecs *specs) ...@@ -7673,6 +7764,8 @@ finish_declspecs (struct c_declspecs *specs)
"_Complex short" is equivalent to "_Complex short int". */ "_Complex short" is equivalent to "_Complex short int". */
if (specs->typespec_word == cts_none) if (specs->typespec_word == cts_none)
{ {
if (specs->saturating_p)
error ("%<_Sat%> is used without %<_Fract%> or %<_Accum%>");
if (specs->long_p || specs->short_p if (specs->long_p || specs->short_p
|| specs->signed_p || specs->unsigned_p) || specs->signed_p || specs->unsigned_p)
{ {
...@@ -7792,6 +7885,88 @@ finish_declspecs (struct c_declspecs *specs) ...@@ -7792,6 +7885,88 @@ finish_declspecs (struct c_declspecs *specs)
else else
specs->type = dfloat128_type_node; specs->type = dfloat128_type_node;
break; break;
case cts_fract:
gcc_assert (!specs->complex_p);
if (specs->saturating_p)
{
if (specs->long_long_p)
specs->type = specs->unsigned_p
? sat_unsigned_long_long_fract_type_node
: sat_long_long_fract_type_node;
else if (specs->long_p)
specs->type = specs->unsigned_p
? sat_unsigned_long_fract_type_node
: sat_long_fract_type_node;
else if (specs->short_p)
specs->type = specs->unsigned_p
? sat_unsigned_short_fract_type_node
: sat_short_fract_type_node;
else
specs->type = specs->unsigned_p
? sat_unsigned_fract_type_node
: sat_fract_type_node;
}
else
{
if (specs->long_long_p)
specs->type = specs->unsigned_p
? unsigned_long_long_fract_type_node
: long_long_fract_type_node;
else if (specs->long_p)
specs->type = specs->unsigned_p
? unsigned_long_fract_type_node
: long_fract_type_node;
else if (specs->short_p)
specs->type = specs->unsigned_p
? unsigned_short_fract_type_node
: short_fract_type_node;
else
specs->type = specs->unsigned_p
? unsigned_fract_type_node
: fract_type_node;
}
break;
case cts_accum:
gcc_assert (!specs->complex_p);
if (specs->saturating_p)
{
if (specs->long_long_p)
specs->type = specs->unsigned_p
? sat_unsigned_long_long_accum_type_node
: sat_long_long_accum_type_node;
else if (specs->long_p)
specs->type = specs->unsigned_p
? sat_unsigned_long_accum_type_node
: sat_long_accum_type_node;
else if (specs->short_p)
specs->type = specs->unsigned_p
? sat_unsigned_short_accum_type_node
: sat_short_accum_type_node;
else
specs->type = specs->unsigned_p
? sat_unsigned_accum_type_node
: sat_accum_type_node;
}
else
{
if (specs->long_long_p)
specs->type = specs->unsigned_p
? unsigned_long_long_accum_type_node
: long_long_accum_type_node;
else if (specs->long_p)
specs->type = specs->unsigned_p
? unsigned_long_accum_type_node
: long_accum_type_node;
else if (specs->short_p)
specs->type = specs->unsigned_p
? unsigned_short_accum_type_node
: short_accum_type_node;
else
specs->type = specs->unsigned_p
? unsigned_accum_type_node
: accum_type_node;
}
break;
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
......
...@@ -80,6 +80,9 @@ static const struct resword reswords[] = ...@@ -80,6 +80,9 @@ static const struct resword reswords[] =
{ "_Decimal32", RID_DFLOAT32, D_EXT }, { "_Decimal32", RID_DFLOAT32, D_EXT },
{ "_Decimal64", RID_DFLOAT64, D_EXT }, { "_Decimal64", RID_DFLOAT64, D_EXT },
{ "_Decimal128", RID_DFLOAT128, D_EXT }, { "_Decimal128", RID_DFLOAT128, D_EXT },
{ "_Fract", RID_FRACT, D_EXT },
{ "_Accum", RID_ACCUM, D_EXT },
{ "_Sat", RID_SAT, D_EXT },
{ "__FUNCTION__", RID_FUNCTION_NAME, 0 }, { "__FUNCTION__", RID_FUNCTION_NAME, 0 },
{ "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 }, { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
{ "__alignof", RID_ALIGNOF, 0 }, { "__alignof", RID_ALIGNOF, 0 },
...@@ -486,6 +489,9 @@ c_token_starts_typename (c_token *token) ...@@ -486,6 +489,9 @@ c_token_starts_typename (c_token *token)
case RID_VOLATILE: case RID_VOLATILE:
case RID_RESTRICT: case RID_RESTRICT:
case RID_ATTRIBUTE: case RID_ATTRIBUTE:
case RID_FRACT:
case RID_ACCUM:
case RID_SAT:
return true; return true;
default: default:
return false; return false;
...@@ -560,6 +566,9 @@ c_token_starts_declspecs (c_token *token) ...@@ -560,6 +566,9 @@ c_token_starts_declspecs (c_token *token)
case RID_VOLATILE: case RID_VOLATILE:
case RID_RESTRICT: case RID_RESTRICT:
case RID_ATTRIBUTE: case RID_ATTRIBUTE:
case RID_FRACT:
case RID_ACCUM:
case RID_SAT:
return true; return true;
default: default:
return false; return false;
...@@ -1493,6 +1502,12 @@ c_parser_asm_definition (c_parser *parser) ...@@ -1493,6 +1502,12 @@ c_parser_asm_definition (c_parser *parser)
_Decimal32 _Decimal32
_Decimal64 _Decimal64
_Decimal128 _Decimal128
_Fract
_Accum
_Sat
(_Fract, _Accum, and _Sat are new from ISO/IEC DTR 18037:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf)
Objective-C: Objective-C:
...@@ -1595,6 +1610,9 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, ...@@ -1595,6 +1610,9 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
case RID_DFLOAT64: case RID_DFLOAT64:
case RID_DFLOAT128: case RID_DFLOAT128:
case RID_BOOL: case RID_BOOL:
case RID_FRACT:
case RID_ACCUM:
case RID_SAT:
if (!typespec_ok) if (!typespec_ok)
goto out; goto out;
attrs_ok = true; attrs_ok = true;
...@@ -2857,6 +2875,9 @@ c_parser_attributes (c_parser *parser) ...@@ -2857,6 +2875,9 @@ c_parser_attributes (c_parser *parser)
case RID_DFLOAT64: case RID_DFLOAT64:
case RID_DFLOAT128: case RID_DFLOAT128:
case RID_BOOL: case RID_BOOL:
case RID_FRACT:
case RID_ACCUM:
case RID_SAT:
ok = true; ok = true;
break; break;
default: default:
......
...@@ -202,7 +202,8 @@ enum c_storage_class { ...@@ -202,7 +202,8 @@ enum c_storage_class {
}; };
/* A type specifier keyword "void", "_Bool", "char", "int", "float", /* A type specifier keyword "void", "_Bool", "char", "int", "float",
"double", or none of these. */ "double", "_Decimal32", "_Decimal64", "_Decimal128", "_Fract", "_Accum",
or none of these. */
enum c_typespec_keyword { enum c_typespec_keyword {
cts_none, cts_none,
cts_void, cts_void,
...@@ -213,7 +214,9 @@ enum c_typespec_keyword { ...@@ -213,7 +214,9 @@ enum c_typespec_keyword {
cts_double, cts_double,
cts_dfloat32, cts_dfloat32,
cts_dfloat64, cts_dfloat64,
cts_dfloat128 cts_dfloat128,
cts_fract,
cts_accum
}; };
/* A sequence of declaration specifiers in C. */ /* A sequence of declaration specifiers in C. */
...@@ -281,6 +284,8 @@ struct c_declspecs { ...@@ -281,6 +284,8 @@ struct c_declspecs {
BOOL_BITFIELD volatile_p : 1; BOOL_BITFIELD volatile_p : 1;
/* Whether "restrict" was specified. */ /* Whether "restrict" was specified. */
BOOL_BITFIELD restrict_p : 1; BOOL_BITFIELD restrict_p : 1;
/* Whether "_Sat" was specified. */
BOOL_BITFIELD saturating_p : 1;
}; };
/* The various kinds of declarators in C. */ /* The various kinds of declarators in C. */
......
...@@ -604,9 +604,11 @@ c_common_type (tree t1, tree t2) ...@@ -604,9 +604,11 @@ c_common_type (tree t1, tree t2)
code2 = TREE_CODE (t2); code2 = TREE_CODE (t2);
gcc_assert (code1 == VECTOR_TYPE || code1 == COMPLEX_TYPE gcc_assert (code1 == VECTOR_TYPE || code1 == COMPLEX_TYPE
|| code1 == REAL_TYPE || code1 == INTEGER_TYPE); || code1 == FIXED_POINT_TYPE || code1 == REAL_TYPE
|| code1 == INTEGER_TYPE);
gcc_assert (code2 == VECTOR_TYPE || code2 == COMPLEX_TYPE gcc_assert (code2 == VECTOR_TYPE || code2 == COMPLEX_TYPE
|| code2 == REAL_TYPE || code2 == INTEGER_TYPE); || code2 == FIXED_POINT_TYPE || code2 == REAL_TYPE
|| code2 == INTEGER_TYPE);
/* When one operand is a decimal float type, the other operand cannot be /* When one operand is a decimal float type, the other operand cannot be
a generic float type or a complex type. We also disallow vector types a generic float type or a complex type. We also disallow vector types
...@@ -681,6 +683,91 @@ c_common_type (tree t1, tree t2) ...@@ -681,6 +683,91 @@ c_common_type (tree t1, tree t2)
return dfloat32_type_node; return dfloat32_type_node;
} }
/* Deal with fixed-point types. */
if (code1 == FIXED_POINT_TYPE || code2 == FIXED_POINT_TYPE)
{
unsigned int unsignedp = 0, satp = 0;
enum machine_mode m1, m2;
unsigned int fbit1, ibit1, fbit2, ibit2, max_fbit, max_ibit;
m1 = TYPE_MODE (t1);
m2 = TYPE_MODE (t2);
/* If one input type is saturating, the result type is saturating. */
if (TYPE_SATURATING (t1) || TYPE_SATURATING (t2))
satp = 1;
/* If both fixed-point types are unsigned, the result type is unsigned.
When mixing fixed-point and integer types, follow the sign of the
fixed-point type.
Otherwise, the result type is signed. */
if ((TYPE_UNSIGNED (t1) && TYPE_UNSIGNED (t2)
&& code1 == FIXED_POINT_TYPE && code2 == FIXED_POINT_TYPE)
|| (code1 == FIXED_POINT_TYPE && code2 != FIXED_POINT_TYPE
&& TYPE_UNSIGNED (t1))
|| (code1 != FIXED_POINT_TYPE && code2 == FIXED_POINT_TYPE
&& TYPE_UNSIGNED (t2)))
unsignedp = 1;
/* The result type is signed. */
if (unsignedp == 0)
{
/* If the input type is unsigned, we need to convert to the
signed type. */
if (code1 == FIXED_POINT_TYPE && TYPE_UNSIGNED (t1))
{
unsigned char mclass = 0;
if (GET_MODE_CLASS (m1) == MODE_UFRACT)
mclass = MODE_FRACT;
else if (GET_MODE_CLASS (m1) == MODE_UACCUM)
mclass = MODE_ACCUM;
else
gcc_unreachable ();
m1 = mode_for_size (GET_MODE_PRECISION (m1), mclass, 0);
}
if (code2 == FIXED_POINT_TYPE && TYPE_UNSIGNED (t2))
{
unsigned char mclass = 0;
if (GET_MODE_CLASS (m2) == MODE_UFRACT)
mclass = MODE_FRACT;
else if (GET_MODE_CLASS (m2) == MODE_UACCUM)
mclass = MODE_ACCUM;
else
gcc_unreachable ();
m2 = mode_for_size (GET_MODE_PRECISION (m2), mclass, 0);
}
}
if (code1 == FIXED_POINT_TYPE)
{
fbit1 = GET_MODE_FBIT (m1);
ibit1 = GET_MODE_IBIT (m1);
}
else
{
fbit1 = 0;
/* Signed integers need to subtract one sign bit. */
ibit1 = TYPE_PRECISION (t1) - (!TYPE_UNSIGNED (t1));
}
if (code2 == FIXED_POINT_TYPE)
{
fbit2 = GET_MODE_FBIT (m2);
ibit2 = GET_MODE_IBIT (m2);
}
else
{
fbit2 = 0;
/* Signed integers need to subtract one sign bit. */
ibit2 = TYPE_PRECISION (t2) - (!TYPE_UNSIGNED (t2));
}
max_ibit = ibit1 >= ibit2 ? ibit1 : ibit2;
max_fbit = fbit1 >= fbit2 ? fbit1 : fbit2;
return c_common_fixed_point_type_for_size (max_ibit, max_fbit, unsignedp,
satp);
}
/* Both real or both integers; use the one with greater precision. */ /* Both real or both integers; use the one with greater precision. */
if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2)) if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
...@@ -2808,7 +2895,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag) ...@@ -2808,7 +2895,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
is enough to prevent anybody from looking inside for is enough to prevent anybody from looking inside for
associativity, but won't generate any code. */ associativity, but won't generate any code. */
if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
|| typecode == COMPLEX_TYPE || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE
|| typecode == VECTOR_TYPE)) || typecode == VECTOR_TYPE))
{ {
error ("wrong type argument to unary plus"); error ("wrong type argument to unary plus");
...@@ -2821,7 +2908,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag) ...@@ -2821,7 +2908,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
case NEGATE_EXPR: case NEGATE_EXPR:
if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
|| typecode == COMPLEX_TYPE || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE
|| typecode == VECTOR_TYPE)) || typecode == VECTOR_TYPE))
{ {
error ("wrong type argument to unary minus"); error ("wrong type argument to unary minus");
...@@ -2878,7 +2965,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag) ...@@ -2878,7 +2965,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
break; break;
case TRUTH_NOT_EXPR: case TRUTH_NOT_EXPR:
if (typecode != INTEGER_TYPE if (typecode != INTEGER_TYPE && typecode != FIXED_POINT_TYPE
&& typecode != REAL_TYPE && typecode != POINTER_TYPE && typecode != REAL_TYPE && typecode != POINTER_TYPE
&& typecode != COMPLEX_TYPE) && typecode != COMPLEX_TYPE)
{ {
...@@ -2931,7 +3018,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag) ...@@ -2931,7 +3018,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
/* Report invalid types. */ /* Report invalid types. */
if (typecode != POINTER_TYPE if (typecode != POINTER_TYPE && typecode != FIXED_POINT_TYPE
&& typecode != INTEGER_TYPE && typecode != REAL_TYPE) && typecode != INTEGER_TYPE && typecode != REAL_TYPE)
{ {
if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
...@@ -2975,6 +3062,25 @@ build_unary_op (enum tree_code code, tree xarg, int flag) ...@@ -2975,6 +3062,25 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
inc = c_size_in_bytes (TREE_TYPE (result_type)); inc = c_size_in_bytes (TREE_TYPE (result_type));
inc = fold_convert (sizetype, inc); inc = fold_convert (sizetype, inc);
} }
else if (FRACT_MODE_P (TYPE_MODE (result_type)))
{
/* For signed fract types, we invert ++ to -- or
-- to ++, and change inc from 1 to -1, because
it is not possible to represent 1 in signed fract constants.
For unsigned fract types, the result always overflows and
we get an undefined (original) or the maximum value. */
if (code == PREINCREMENT_EXPR)
code = PREDECREMENT_EXPR;
else if (code == PREDECREMENT_EXPR)
code = PREINCREMENT_EXPR;
else if (code == POSTINCREMENT_EXPR)
code = POSTDECREMENT_EXPR;
else /* code == POSTDECREMENT_EXPR */
code = POSTINCREMENT_EXPR;
inc = integer_minus_one_node;
inc = convert (argtype, inc);
}
else else
{ {
inc = integer_one_node; inc = integer_one_node;
...@@ -3924,9 +4030,11 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype, ...@@ -3924,9 +4030,11 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
return convert (type, rhs); return convert (type, rhs);
/* Arithmetic types all interconvert, and enum is treated like int. */ /* Arithmetic types all interconvert, and enum is treated like int. */
else if ((codel == INTEGER_TYPE || codel == REAL_TYPE else if ((codel == INTEGER_TYPE || codel == REAL_TYPE
|| codel == FIXED_POINT_TYPE
|| codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE
|| codel == BOOLEAN_TYPE) || codel == BOOLEAN_TYPE)
&& (coder == INTEGER_TYPE || coder == REAL_TYPE && (coder == INTEGER_TYPE || coder == REAL_TYPE
|| coder == FIXED_POINT_TYPE
|| coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE
|| coder == BOOLEAN_TYPE)) || coder == BOOLEAN_TYPE))
return convert_and_check (type, rhs); return convert_and_check (type, rhs);
...@@ -4746,9 +4854,9 @@ digest_init (tree type, tree init, bool strict_string, int require_constant) ...@@ -4746,9 +4854,9 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
/* Handle scalar types, including conversions. */ /* Handle scalar types, including conversions. */
if (code == INTEGER_TYPE || code == REAL_TYPE || code == POINTER_TYPE if (code == INTEGER_TYPE || code == REAL_TYPE || code == FIXED_POINT_TYPE
|| code == ENUMERAL_TYPE || code == BOOLEAN_TYPE || code == COMPLEX_TYPE || code == POINTER_TYPE || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE
|| code == VECTOR_TYPE) || code == COMPLEX_TYPE || code == VECTOR_TYPE)
{ {
if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE
&& (TREE_CODE (init) == STRING_CST && (TREE_CODE (init) == STRING_CST
...@@ -7862,8 +7970,10 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, ...@@ -7862,8 +7970,10 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
warn_for_div_by_zero (op1); warn_for_div_by_zero (op1);
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|| code0 == FIXED_POINT_TYPE
|| code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE) || code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
|| code1 == FIXED_POINT_TYPE
|| code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)) || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
{ {
enum tree_code tcode0 = code0, tcode1 = code1; enum tree_code tcode0 = code0, tcode1 = code1;
...@@ -7873,7 +7983,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, ...@@ -7873,7 +7983,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE) if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)
tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1))); tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
if (!(tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE)) if (!((tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE)
|| (tcode0 == FIXED_POINT_TYPE && tcode1 == FIXED_POINT_TYPE)))
resultcode = RDIV_EXPR; resultcode = RDIV_EXPR;
else else
/* Although it would be tempting to shorten always here, that /* Although it would be tempting to shorten always here, that
...@@ -7924,9 +8035,11 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, ...@@ -7924,9 +8035,11 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
case TRUTH_OR_EXPR: case TRUTH_OR_EXPR:
case TRUTH_XOR_EXPR: case TRUTH_XOR_EXPR:
if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE
|| code0 == REAL_TYPE || code0 == COMPLEX_TYPE) || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
|| code0 == FIXED_POINT_TYPE)
&& (code1 == INTEGER_TYPE || code1 == POINTER_TYPE && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE
|| code1 == REAL_TYPE || code1 == COMPLEX_TYPE)) || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
|| code1 == FIXED_POINT_TYPE))
{ {
/* Result of these operations is always an int, /* Result of these operations is always an int,
but that does not mean the operands should be but that does not mean the operands should be
...@@ -7943,7 +8056,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, ...@@ -7943,7 +8056,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
Also set SHORT_SHIFT if shifting rightward. */ Also set SHORT_SHIFT if shifting rightward. */
case RSHIFT_EXPR: case RSHIFT_EXPR:
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
&& code1 == INTEGER_TYPE)
{ {
if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0) if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
{ {
...@@ -7971,7 +8085,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, ...@@ -7971,7 +8085,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
break; break;
case LSHIFT_EXPR: case LSHIFT_EXPR:
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
&& code1 == INTEGER_TYPE)
{ {
if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0) if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
{ {
...@@ -8002,9 +8117,9 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, ...@@ -8002,9 +8117,9 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
but don't convert the args to int! */ but don't convert the args to int! */
build_type = integer_type_node; build_type = integer_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|| code0 == COMPLEX_TYPE) || code0 == FIXED_POINT_TYPE || code0 == COMPLEX_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
|| code1 == COMPLEX_TYPE)) || code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE))
short_compare = 1; short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{ {
...@@ -8072,8 +8187,10 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, ...@@ -8072,8 +8187,10 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
case LT_EXPR: case LT_EXPR:
case GT_EXPR: case GT_EXPR:
build_type = integer_type_node; build_type = integer_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE) if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE)) || code0 == FIXED_POINT_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
|| code1 == FIXED_POINT_TYPE))
short_compare = 1; short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{ {
...@@ -8134,10 +8251,10 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, ...@@ -8134,10 +8251,10 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
} }
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
|| code0 == VECTOR_TYPE) || code0 == FIXED_POINT_TYPE || code0 == VECTOR_TYPE)
&& &&
(code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
|| code1 == VECTOR_TYPE)) || code1 == FIXED_POINT_TYPE || code1 == VECTOR_TYPE))
{ {
int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE); int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
......
...@@ -65,6 +65,12 @@ ...@@ -65,6 +65,12 @@
#endif #endif
/* Define to 1 to enable fixed-point arithmetic extension to C. */
#ifndef USED_FOR_TARGET
#undef ENABLE_FIXED_POINT
#endif
/* Define if you want fold checked that it never destructs its argument. This /* Define if you want fold checked that it never destructs its argument. This
is quite expensive. */ is quite expensive. */
#ifndef USED_FOR_TARGET #ifndef USED_FOR_TARGET
...@@ -1363,37 +1369,37 @@ ...@@ -1363,37 +1369,37 @@
#endif #endif
/* The size of a `int', as computed by sizeof. */ /* The size of `int', as computed by sizeof. */
#ifndef USED_FOR_TARGET #ifndef USED_FOR_TARGET
#undef SIZEOF_INT #undef SIZEOF_INT
#endif #endif
/* The size of a `long', as computed by sizeof. */ /* The size of `long', as computed by sizeof. */
#ifndef USED_FOR_TARGET #ifndef USED_FOR_TARGET
#undef SIZEOF_LONG #undef SIZEOF_LONG
#endif #endif
/* The size of a `long long', as computed by sizeof. */ /* The size of `long long', as computed by sizeof. */
#ifndef USED_FOR_TARGET #ifndef USED_FOR_TARGET
#undef SIZEOF_LONG_LONG #undef SIZEOF_LONG_LONG
#endif #endif
/* The size of a `short', as computed by sizeof. */ /* The size of `short', as computed by sizeof. */
#ifndef USED_FOR_TARGET #ifndef USED_FOR_TARGET
#undef SIZEOF_SHORT #undef SIZEOF_SHORT
#endif #endif
/* The size of a `void *', as computed by sizeof. */ /* The size of `void *', as computed by sizeof. */
#ifndef USED_FOR_TARGET #ifndef USED_FOR_TARGET
#undef SIZEOF_VOID_P #undef SIZEOF_VOID_P
#endif #endif
/* The size of a `__int64', as computed by sizeof. */ /* The size of `__int64', as computed by sizeof. */
#ifndef USED_FOR_TARGET #ifndef USED_FOR_TARGET
#undef SIZEOF___INT64 #undef SIZEOF___INT64
#endif #endif
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -641,6 +641,28 @@ AC_DEFINE_UNQUOTED(ENABLE_DECIMAL_BID_FORMAT, $bid, ...@@ -641,6 +641,28 @@ AC_DEFINE_UNQUOTED(ENABLE_DECIMAL_BID_FORMAT, $bid,
[Define to 1 to specify that we are using the BID decimal floating [Define to 1 to specify that we are using the BID decimal floating
point format instead of DPD]) point format instead of DPD])
# Enable C extension for fixed-point arithmetic.
AC_ARG_ENABLE(fixed-point,
[ --enable-fixed-point enable fixed-point arithmetic extension to C],
[
],
[
case $target in
mips*-*-*)
enable_fixed_point=yes
;;
*)
AC_MSG_WARN(fixed-point is not supported for this target, ignored)
enable_fixed_point=no
;;
esac
])
AC_SUBST(enable_fixed_point)
fixedpoint=`if test $enable_fixed_point = yes; then echo 1; else echo 0; fi`
AC_DEFINE_UNQUOTED(ENABLE_FIXED_POINT, $fixedpoint,
[Define to 1 to enable fixed-point arithmetic extension to C.])
# Enable threads # Enable threads
# Pass with no value to take the default # Pass with no value to take the default
# Pass with a value to specify a thread package # Pass with a value to specify a thread package
......
...@@ -1317,6 +1317,13 @@ or @samp{dpd}). The @samp{bid} (binary integer decimal) format is ...@@ -1317,6 +1317,13 @@ or @samp{dpd}). The @samp{bid} (binary integer decimal) format is
default on i386 and x86_64 systems, and the @samp{dpd} (densely packed default on i386 and x86_64 systems, and the @samp{dpd} (densely packed
decimal) format is default on PowerPC systems. decimal) format is default on PowerPC systems.
@item --enable-fixed-point
@itemx --disable-fixed-point
Enable (or disable) support for C fixed-point arithmetic.
This option is enabled by default for some targets (such as MIPS) which
have hardware-support for fixed-point operations. On other targets, you
may enable this option manually.
@item --with-long-double-128 @item --with-long-double-128
Specify if @code{long double} type should be 128-bit by default on selected Specify if @code{long double} type should be 128-bit by default on selected
GNU/Linux architectures. If using @code{--without-long-double-128}, GNU/Linux architectures. If using @code{--without-long-double-128},
......
...@@ -1502,6 +1502,10 @@ may affect its placement. ...@@ -1502,6 +1502,10 @@ may affect its placement.
Returns true if the target supports decimal floating point. Returns true if the target supports decimal floating point.
@end deftypefn @end deftypefn
@deftypefn {Target Hook} {bool} TARGET_FIXED_POINT_SUPPORTED_P (void)
Returns true if the target supports fixed-point arithmetic.
@end deftypefn
@deftypefn {Target Hook} {const char *} TARGET_MANGLE_TYPE (tree @var{type}) @deftypefn {Target Hook} {const char *} TARGET_MANGLE_TYPE (tree @var{type})
If your target defines any fundamental types, or any types your target If your target defines any fundamental types, or any types your target
uses should be mangled differently from the default, define this hook uses should be mangled differently from the default, define this hook
......
...@@ -437,6 +437,10 @@ ...@@ -437,6 +437,10 @@
#define TARGET_DECIMAL_FLOAT_SUPPORTED_P default_decimal_float_supported_p #define TARGET_DECIMAL_FLOAT_SUPPORTED_P default_decimal_float_supported_p
#endif #endif
#ifndef TARGET_FIXED_POINT_SUPPORTED_P
#define TARGET_FIXED_POINT_SUPPORTED_P default_fixed_point_supported_p
#endif
#ifndef TARGET_VECTOR_MODE_SUPPORTED_P #ifndef TARGET_VECTOR_MODE_SUPPORTED_P
#define TARGET_VECTOR_MODE_SUPPORTED_P hook_bool_mode_false #define TARGET_VECTOR_MODE_SUPPORTED_P hook_bool_mode_false
#endif #endif
...@@ -689,6 +693,7 @@ ...@@ -689,6 +693,7 @@
TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P, \ TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P, \
TARGET_MS_BITFIELD_LAYOUT_P, \ TARGET_MS_BITFIELD_LAYOUT_P, \
TARGET_DECIMAL_FLOAT_SUPPORTED_P, \ TARGET_DECIMAL_FLOAT_SUPPORTED_P, \
TARGET_FIXED_POINT_SUPPORTED_P, \
TARGET_ALIGN_ANON_BITFIELD, \ TARGET_ALIGN_ANON_BITFIELD, \
TARGET_NARROW_VOLATILE_BITFIELD, \ TARGET_NARROW_VOLATILE_BITFIELD, \
TARGET_INIT_BUILTINS, \ TARGET_INIT_BUILTINS, \
......
...@@ -479,6 +479,9 @@ struct gcc_target ...@@ -479,6 +479,9 @@ struct gcc_target
/* True if the target supports decimal floating point. */ /* True if the target supports decimal floating point. */
bool (* decimal_float_supported_p) (void); bool (* decimal_float_supported_p) (void);
/* True if the target supports fixed-point. */
bool (* fixed_point_supported_p) (void);
/* Return true if anonymous bitfields affect structure alignment. */ /* Return true if anonymous bitfields affect structure alignment. */
bool (* align_anon_bitfield) (void); bool (* align_anon_bitfield) (void);
......
...@@ -298,6 +298,10 @@ default_scalar_mode_supported_p (enum machine_mode mode) ...@@ -298,6 +298,10 @@ default_scalar_mode_supported_p (enum machine_mode mode)
return false; return false;
case MODE_DECIMAL_FLOAT: case MODE_DECIMAL_FLOAT:
case MODE_FRACT:
case MODE_UFRACT:
case MODE_ACCUM:
case MODE_UACCUM:
return false; return false;
default: default:
...@@ -313,6 +317,14 @@ default_decimal_float_supported_p (void) ...@@ -313,6 +317,14 @@ default_decimal_float_supported_p (void)
return ENABLE_DECIMAL_FLOAT; return ENABLE_DECIMAL_FLOAT;
} }
/* True if the target supports fixed-point arithmetic. */
bool
default_fixed_point_supported_p (void)
{
return ENABLE_FIXED_POINT;
}
/* NULL if INSN insn is valid within a low-overhead loop, otherwise returns /* NULL if INSN insn is valid within a low-overhead loop, otherwise returns
an error message. an error message.
......
...@@ -55,6 +55,7 @@ extern void default_unwind_emit (FILE *, rtx); ...@@ -55,6 +55,7 @@ extern void default_unwind_emit (FILE *, rtx);
extern bool default_scalar_mode_supported_p (enum machine_mode); extern bool default_scalar_mode_supported_p (enum machine_mode);
extern bool default_decimal_float_supported_p (void); extern bool default_decimal_float_supported_p (void);
extern bool default_fixed_point_supported_p (void);
extern const char * default_invalid_within_doloop (rtx); extern const char * default_invalid_within_doloop (rtx);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment