#include "real.h"
#include "cgraph.h"
#include "target-def.h"
+#include "fixed-value.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
constant_expression_warning (tree value)
{
if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST
+ || TREE_CODE (value) == FIXED_CST
|| TREE_CODE (value) == VECTOR_CST
|| TREE_CODE (value) == COMPLEX_CST)
&& TREE_OVERFLOW (value)
warning (OPT_Woverflow, "floating point overflow in expression");
break;
+ case FIXED_CST:
+ warning (OPT_Woverflow, "fixed-point overflow in expression");
+ break;
+
case VECTOR_CST:
warning (OPT_Woverflow, "vector overflow in expression");
break;
{
/* warn_strict_aliasing >= 3. This includes the default (3).
Only warn if the cast is dereferenced immediately. */
- HOST_WIDE_INT set1 =
+ alias_set_type set1 =
get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0)));
- HOST_WIDE_INT set2 = get_alias_set (TREE_TYPE (type));
+ alias_set_type set2 = get_alias_set (TREE_TYPE (type));
if (!alias_sets_conflict_p (set1, set2))
{
not taken in the same statement. This will likely produce many
false positives, but could be useful to pinpoint problems that
are not revealed at higher levels. */
- HOST_WIDE_INT set1 = get_alias_set (TREE_TYPE (otype));
- HOST_WIDE_INT set2 = get_alias_set (TREE_TYPE (type));
- if (!COMPLETE_TYPE_P(type)
+ alias_set_type set1 = get_alias_set (TREE_TYPE (otype));
+ alias_set_type set2 = get_alias_set (TREE_TYPE (type));
+ if (!COMPLETE_TYPE_P (type)
|| !alias_sets_must_conflict_p (set1, set2))
{
warning (OPT_Wstrict_aliasing, "dereferencing type-punned "
in effect, emit a note telling the user about that option if such
a note has not previously been emitted. */
bool
-vector_types_convertible_p (tree t1, tree t2, bool emit_lax_note)
+vector_types_convertible_p (const_tree t1, const_tree t2, bool emit_lax_note)
{
static bool emitted_lax_note = false;
bool convertible_lax;
else
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,
"overflow in implicit constant conversion");
else
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
c_register_builtin_type. */
static GTY(()) tree registered_builtin_types;
/* Return a data type that has machine mode MODE.
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
c_common_type_for_mode (enum machine_mode mode, int unsignedp)
if (mode == TYPE_MODE (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))
if (TYPE_MODE (TREE_VALUE (t)) == mode)
return TREE_VALUE (t);
if (type1 == intQI_type_node || type1 == unsigned_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
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
the second arg is 0. */
if (TREE_CONSTANT (primop0)
- && !integer_zerop (primop1) && !real_zerop (primop1))
+ && !integer_zerop (primop1) && !real_zerop (primop1)
+ && !fixed_zerop (primop1))
{
tree tem = primop0;
int temi = unsignedp0;
and see if that preserves the constant's value. */
if (!real1 && !real2
+ && TREE_CODE (TREE_TYPE (primop0)) != FIXED_POINT_TYPE
&& TREE_CODE (primop1) == INTEGER_CST
&& TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr))
{
NULL. */
bool
-decl_with_nonnull_addr_p (tree expr)
+decl_with_nonnull_addr_p (const_tree expr)
{
return (DECL_P (expr)
&& (TREE_CODE (expr) == PARM_DECL
? truthvalue_true_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:
expr = build_unary_op (ADDR_EXPR, expr, 0);
/* Fall through. */
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);
}
\f
/* Return the typed-based alias set for T, which may be an expression
or a type. Return -1 if we don't do anything special. */
-HOST_WIDE_INT
+alias_set_type
c_common_get_alias_set (tree t)
{
tree u;
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,
get_identifier ("complex int"),
complex_integer_type_node));
integral promotions defined in ISO C99 6.3.1.1/2. */
bool
-c_promoting_integer_type_p (tree t)
+c_promoting_integer_type_p (const_tree t)
{
switch (TREE_CODE (t))
{
and none of their types is affected by default promotions. */
int
-self_promoting_args_p (tree parms)
+self_promoting_args_p (const_tree parms)
{
- tree t;
+ const_tree t;
for (t = parms; t; t = TREE_CHAIN (t))
{
tree type = TREE_VALUE (t);
return type;
}
+const_tree
+const_strip_array_types (const_tree type)
+{
+ while (TREE_CODE (type) == ARRAY_TYPE)
+ type = TREE_TYPE (type);
+
+ return type;
+}
+
/* Recursively remove any '*' or '&' operator from TYPE. */
tree
strip_pointer_operator (tree t)
case MODE_PARTIAL_INT:
case MODE_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);
break;
case MODE_VECTOR_INT:
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 "
"__attribute__ ((mode)) is deprecated");
warning (OPT_Wattributes,
typefm = fn (TREE_TYPE (type), mode, false);
}
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)
{
|| TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == VECTOR_TYPE
|| (!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))
{
error ("invalid vector type for attribute %qE", name);
{
enum tree_code c1 = TREE_CODE (t1), c2 = TREE_CODE (t2);
- gcc_assert ((c1 == INTEGER_TYPE || c1 == REAL_TYPE)
- && (c2 == INTEGER_TYPE || c2 == REAL_TYPE));
+ gcc_assert ((c1 == INTEGER_TYPE || c1 == REAL_TYPE || c1 == FIXED_POINT_TYPE)
+ && (c2 == INTEGER_TYPE || c2 == REAL_TYPE
+ || c2 == FIXED_POINT_TYPE));
/* Equality works here because c_common_signed_type uses
TYPE_MAIN_VARIANT. */
void
warn_for_div_by_zero (tree divisor)
{
- /* If DIVISOR is zero, and has integral type, issue a warning about
- division by zero. Do not issue a warning if DIVISOR has a
+ /* If DIVISOR is zero, and has integral or fixed-point type, issue a warning
+ 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
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");
}