Index: genmodes.c =================================================================== --- genmodes.c (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/genmodes.c) (revision 125345) +++ genmodes.c (.../genmodes.c) (working copy) @@ -73,6 +73,8 @@ const char *file; /* file and line of definition, */ unsigned int line; /* for error reporting */ unsigned int counter; /* Rank ordering of modes */ + unsigned int ibit; /* the number of integral bits */ + unsigned int fbit; /* the number of fractional bits */ }; static struct mode_data *modes[MAX_MODE_CLASS]; @@ -83,7 +85,7 @@ 0, "", MAX_MODE_CLASS, -1U, -1U, -1U, -1U, 0, 0, 0, 0, 0, 0, - "", 0, 0 + "", 0, 0, 0, 0 }; static htab_t modes_by_name; @@ -104,6 +106,8 @@ static struct mode_adjust *adj_bytesize; static struct mode_adjust *adj_alignment; static struct mode_adjust *adj_format; +static struct mode_adjust *adj_ibit; +static struct mode_adjust *adj_fbit; /* Mode class operations. */ static enum mode_class @@ -126,6 +130,10 @@ { case MODE_INT: return MODE_VECTOR_INT; case MODE_FLOAT: return MODE_VECTOR_FLOAT; + case MODE_FRACT: return MODE_VECTOR_FRACT; + case MODE_UFRACT: return MODE_VECTOR_UFRACT; + case MODE_ACCUM: return MODE_VECTOR_ACCUM; + case MODE_UACCUM: return MODE_VECTOR_UACCUM; default: error ("no vector class for class %s", mode_class_names[cl]); return MODE_RANDOM; @@ -200,7 +208,8 @@ new_adjust (const char *name, struct mode_adjust **category, const char *catname, const char *adjustment, - enum mode_class required_class, + enum mode_class required_class_from, + enum mode_class required_class_to, const char *file, unsigned int line) { struct mode_data *mode = find_mode (name); @@ -214,10 +223,12 @@ return; } - if (required_class != MODE_RANDOM && mode->cl != required_class) + if (required_class_from != MODE_RANDOM + && (mode->cl < required_class_from || mode->cl > required_class_to)) { - error ("%s:%d: mode \"%s\" is not class %s", - file, line, name, mode_class_names[required_class] + 5); + error ("%s:%d: mode \"%s\" is not among class {%s, %s}", + file, line, name, mode_class_names[required_class_from] + 5, + mode_class_names[required_class_to] + 5); return; } @@ -327,11 +338,16 @@ case MODE_INT: case MODE_FLOAT: case MODE_DECIMAL_FLOAT: + case MODE_FRACT: + case MODE_UFRACT: + case MODE_ACCUM: + case MODE_UACCUM: /* A scalar mode must have a byte size, may have a bit size, and must not have components. A float mode must have a format. */ validate_mode (m, OPTIONAL, SET, UNSET, UNSET, - m->cl != MODE_INT ? SET : UNSET); + (m->cl == MODE_FLOAT || m->cl == MODE_DECIMAL_FLOAT) + ? SET : UNSET); m->ncomponents = 1; m->component = 0; @@ -361,6 +377,10 @@ case MODE_VECTOR_INT: case MODE_VECTOR_FLOAT: + case MODE_VECTOR_FRACT: + case MODE_VECTOR_UFRACT: + case MODE_VECTOR_ACCUM: + case MODE_VECTOR_UACCUM: /* Vector modes should have a component and a number of components. */ validate_mode (m, UNSET, UNSET, SET, SET, UNSET); if (m->component->precision != (unsigned int)-1) @@ -533,6 +553,32 @@ m->precision = precision; } +#define FRACT_MODE(N, Y, F) \ + make_fixed_point_mode (MODE_FRACT, #N, Y, 0, F, __FILE__, __LINE__) + +#define UFRACT_MODE(N, Y, F) \ + make_fixed_point_mode (MODE_UFRACT, #N, Y, 0, F, __FILE__, __LINE__) + +#define ACCUM_MODE(N, Y, I, F) \ + make_fixed_point_mode (MODE_ACCUM, #N, Y, I, F, __FILE__, __LINE__) + +#define UACCUM_MODE(N, Y, I, F) \ + make_fixed_point_mode (MODE_UACCUM, #N, Y, I, F, __FILE__, __LINE__) + +static void +make_fixed_point_mode (enum mode_class cl, + const char *name, + unsigned int bytesize, + unsigned int ibit, + unsigned int fbit, + const char *file, unsigned int line) +{ + struct mode_data *m = new_mode (cl, name, file, line); + m->bytesize = bytesize; + m->ibit = ibit; + m->fbit = fbit; +} + #define FLOAT_MODE(N, Y, F) FRACTIONAL_FLOAT_MODE (N, -1U, Y, F) #define FRACTIONAL_FLOAT_MODE(N, B, Y, F) \ make_float_mode (#N, B, Y, #F, __FILE__, __LINE__) @@ -658,12 +704,14 @@ } /* Adjustability. */ -#define _ADD_ADJUST(A, M, X, C) \ - new_adjust (#M, &adj_##A, #A, #X, MODE_##C, __FILE__, __LINE__) +#define _ADD_ADJUST(A, M, X, C1, C2) \ + new_adjust (#M, &adj_##A, #A, #X, MODE_##C1, MODE_##C2, __FILE__, __LINE__) -#define ADJUST_BYTESIZE(M, X) _ADD_ADJUST(bytesize, M, X, RANDOM) -#define ADJUST_ALIGNMENT(M, X) _ADD_ADJUST(alignment, M, X, RANDOM) -#define ADJUST_FLOAT_FORMAT(M, X) _ADD_ADJUST(format, M, X, FLOAT) +#define ADJUST_BYTESIZE(M, X) _ADD_ADJUST(bytesize, M, X, RANDOM, RANDOM) +#define ADJUST_ALIGNMENT(M, X) _ADD_ADJUST(alignment, M, X, RANDOM, RANDOM) +#define ADJUST_FLOAT_FORMAT(M, X) _ADD_ADJUST(format, M, X, FLOAT, FLOAT) +#define ADJUST_IBIT(M, X) _ADD_ADJUST(ibit, M, X, ACCUM, UACCUM) +#define ADJUST_FBIT(M, X) _ADD_ADJUST(fbit, M, X, FRACT, UACCUM) static void create_modes (void) @@ -863,6 +911,8 @@ #if 0 /* disabled for backward compatibility, temporary */ printf ("#define CONST_REAL_FORMAT_FOR_MODE%s\n", adj_format ? "" :" const"); #endif + printf ("#define CONST_MODE_IBIT%s\n", adj_ibit ? "" : " const"); + printf ("#define CONST_MODE_FBIT%s\n", adj_fbit ? "" : " const"); puts ("\ \n\ #endif /* insn-modes.h */"); @@ -1175,6 +1225,10 @@ case MODE_VECTOR_INT: case MODE_VECTOR_FLOAT: + case MODE_VECTOR_FRACT: + case MODE_VECTOR_UFRACT: + case MODE_VECTOR_ACCUM: + case MODE_VECTOR_UACCUM: printf (" mode_size[%smode] = %d*s;\n", m->name, m->ncomponents); printf (" mode_base_align[%smode] = (%d*s) & (~(%d*s)+1);\n", @@ -1209,6 +1263,10 @@ case MODE_VECTOR_INT: case MODE_VECTOR_FLOAT: + case MODE_VECTOR_FRACT: + case MODE_VECTOR_UFRACT: + case MODE_VECTOR_ACCUM: + case MODE_VECTOR_UACCUM: printf (" mode_base_align[%smode] = %d*s;\n", m->name, m->ncomponents); break; @@ -1221,6 +1279,22 @@ } } } + + /* Ibit adjustments don't have to propagate. */ + for (a = adj_ibit; a; a = a->next) + { + printf ("\n /* %s:%d */\n s = %s;\n", + a->file, a->line, a->adjustment); + printf (" mode_ibit[%smode] = s;\n", a->mode->name); + } + + /* Fbit adjustments don't have to propagate. */ + for (a = adj_fbit; a; a = a->next) + { + printf ("\n /* %s:%d */\n s = %s;\n", + a->file, a->line, a->adjustment); + printf (" mode_fbit[%smode] = s;\n", a->mode->name); + } /* Real mode formats don't have to propagate anywhere. */ for (a = adj_format; a; a = a->next) @@ -1231,6 +1305,39 @@ } static void +emit_mode_ibit (void) +{ + int c; + struct mode_data *m; + + print_maybe_const_decl ("%sunsigned char", + "mode_ibit", "NUM_MACHINE_MODES", + ibit); + + for_all_modes (c, m) + tagged_printf ("%u", m->ibit, m->name); + + print_closer (); +} + +static void +emit_mode_fbit (void) +{ + int c; + struct mode_data *m; + + print_maybe_const_decl ("%sunsigned char", + "mode_fbit", "NUM_MACHINE_MODES", + fbit); + + for_all_modes (c, m) + tagged_printf ("%u", m->fbit, m->name); + + print_closer (); +} + + +static void emit_insn_modes_c (void) { emit_insn_modes_c_header (); @@ -1246,6 +1353,8 @@ emit_class_narrowest_mode (); emit_real_format_for_mode (); emit_mode_adjustments (); + emit_mode_ibit (); + emit_mode_fbit (); } static void Index: mode-classes.def =================================================================== --- mode-classes.def (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/mode-classes.def) (revision 125345) +++ mode-classes.def (.../mode-classes.def) (working copy) @@ -23,10 +23,18 @@ DEF_MODE_CLASS (MODE_RANDOM), /* other */ \ DEF_MODE_CLASS (MODE_CC), /* condition code in a register */ \ DEF_MODE_CLASS (MODE_INT), /* integer */ \ - DEF_MODE_CLASS (MODE_PARTIAL_INT), /* integer with padding bits */ \ + DEF_MODE_CLASS (MODE_PARTIAL_INT), /* integer with padding bits */ \ + DEF_MODE_CLASS (MODE_FRACT), /* signed fractional number */ \ + DEF_MODE_CLASS (MODE_UFRACT), /* unsigned fractional number */ \ + DEF_MODE_CLASS (MODE_ACCUM), /* signed accumulator */ \ + DEF_MODE_CLASS (MODE_UACCUM), /* unsigned accumulator */ \ DEF_MODE_CLASS (MODE_FLOAT), /* floating point */ \ DEF_MODE_CLASS (MODE_DECIMAL_FLOAT), /* decimal floating point */ \ DEF_MODE_CLASS (MODE_COMPLEX_INT), /* complex numbers */ \ DEF_MODE_CLASS (MODE_COMPLEX_FLOAT), \ DEF_MODE_CLASS (MODE_VECTOR_INT), /* SIMD vectors */ \ + DEF_MODE_CLASS (MODE_VECTOR_FRACT), /* SIMD vectors */ \ + DEF_MODE_CLASS (MODE_VECTOR_UFRACT), /* SIMD vectors */ \ + DEF_MODE_CLASS (MODE_VECTOR_ACCUM), /* SIMD vectors */ \ + DEF_MODE_CLASS (MODE_VECTOR_UACCUM), /* SIMD vectors */ \ DEF_MODE_CLASS (MODE_VECTOR_FLOAT) Index: machmode.def =================================================================== --- machmode.def (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/machmode.def) (revision 125345) +++ machmode.def (.../machmode.def) (working copy) @@ -96,6 +96,24 @@ storage, but with only PRECISION significant bits, using floating point format FORMAT. + FRACT_MODE (MODE, BYTESIZE, FBIT); + declares MODE to be of class FRACT and BYTESIZE bytes wide + with FBIT fractional bits. There may be padding bits. + + UFRACT_MODE (MODE, BYTESIZE, FBIT); + declares MODE to be of class UFRACT and BYTESIZE bytes wide + with FBIT fractional bits. There may be padding bits. + + ACCUM_MODE (MODE, BYTESIZE, IBIT, FBIT); + declares MODE to be of class ACCUM and BYTESIZE bytes wide + with IBIT integral bits and FBIT fractional bits. + There may be padding bits. + + UACCUM_MODE (MODE, BYTESIZE, FBIT); + declares MODE to be of class UACCUM and BYTESIZE bytes wide + with IBIT integral bits and FBIT fractional bits. + There may be padding bits. + RESET_FLOAT_FORMAT (MODE, FORMAT); changes the format of MODE, which must be class FLOAT, to FORMAT. Use in an ARCH-modes.def to reset the format @@ -133,10 +151,12 @@ ADJUST_BYTESIZE (MODE, EXPR); ADJUST_ALIGNMENT (MODE, EXPR); ADJUST_FLOAT_FORMAT (MODE, EXPR); - Arrange for the byte size, alignment, or floating point format - of MODE to be adjustable at run time. EXPR will be executed + ADJUST_IBIT (MODE, EXPR); + ADJUST_FBIT (MODE, EXPR); + Arrange for the byte size, alignment, floating point format, ibit, + or fbit of MODE to be adjustable at run time. EXPR will be executed once after processing all command line options, and should - evaluate to the desired byte size, alignment, or format. + evaluate to the desired byte size, alignment, format, ibit or fbit. Unlike a FORMAT argument, if you are adjusting a float format you must put an & in front of the name of each format structure. @@ -181,6 +201,29 @@ FIXME define this only for targets that need it. */ CC_MODE (CC); +/* Fixed-point modes. */ +FRACT_MODE (QQ, 1, 7); /* s.7 */ +FRACT_MODE (HQ, 2, 15); /* s.15 */ +FRACT_MODE (SQ, 4, 31); /* s.31 */ +FRACT_MODE (DQ, 8, 63); /* s.63 */ +FRACT_MODE (TQ, 16, 127); /* s.127 */ + +UFRACT_MODE (UQQ, 1, 8); /* .8 */ +UFRACT_MODE (UHQ, 2, 16); /* .16 */ +UFRACT_MODE (USQ, 4, 32); /* .32 */ +UFRACT_MODE (UDQ, 8, 64); /* .64 */ +UFRACT_MODE (UTQ, 16, 128); /* .128 */ + +ACCUM_MODE (HA, 2, 8, 7); /* s8.7 */ +ACCUM_MODE (SA, 4, 16, 15); /* s16.15 */ +ACCUM_MODE (DA, 8, 32, 31); /* s32.31 */ +ACCUM_MODE (TA, 16, 64, 63); /* s64.63 */ + +UACCUM_MODE (UHA, 2, 8, 8); /* 8.8 */ +UACCUM_MODE (USA, 4, 16, 16); /* 16.16 */ +UACCUM_MODE (UDA, 8, 32, 32); /* 32.32 */ +UACCUM_MODE (UTA, 16, 64, 64); /* 64.64 */ + /* Allow the target to specify additional modes of various kinds. */ #if HAVE_EXTRA_MODES # include EXTRA_MODES_FILE Index: machmode.h =================================================================== --- machmode.h (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/machmode.h) (revision 125345) +++ machmode.h (.../machmode.h) (working copy) @@ -66,7 +66,11 @@ /* Nonzero if MODE is a vector mode. */ #define VECTOR_MODE_P(MODE) \ (GET_MODE_CLASS (MODE) == MODE_VECTOR_INT \ - || GET_MODE_CLASS (MODE) == MODE_VECTOR_FLOAT) + || GET_MODE_CLASS (MODE) == MODE_VECTOR_FLOAT \ + || GET_MODE_CLASS (MODE) == MODE_VECTOR_FRACT \ + || GET_MODE_CLASS (MODE) == MODE_VECTOR_UFRACT \ + || GET_MODE_CLASS (MODE) == MODE_VECTOR_ACCUM \ + || GET_MODE_CLASS (MODE) == MODE_VECTOR_UACCUM) /* Nonzero if MODE is a scalar integral mode. */ #define SCALAR_INT_MODE_P(MODE) \ @@ -82,12 +86,94 @@ #define DECIMAL_FLOAT_MODE_P(MODE) \ (GET_MODE_CLASS (MODE) == MODE_DECIMAL_FLOAT) +/* Nonzero if MODE is a scalar fract mode. */ +#define SCALAR_FRACT_MODE_P(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_FRACT) + +/* Nonzero if MODE is a scalar ufract mode. */ +#define SCALAR_UFRACT_MODE_P(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_UFRACT) + +/* Nonzero if MODE is a scalar fract or ufract mode. */ +#define ALL_SCALAR_FRACT_MODE_P(MODE) \ + (SCALAR_FRACT_MODE_P (MODE) || SCALAR_UFRACT_MODE_P (MODE)) + +/* Nonzero if MODE is a scalar accum mode. */ +#define SCALAR_ACCUM_MODE_P(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_ACCUM) + +/* Nonzero if MODE is a scalar uaccum mode. */ +#define SCALAR_UACCUM_MODE_P(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_UACCUM) + +/* Nonzero if MODE is a scalar accum or uaccum mode. */ +#define ALL_SCALAR_ACCUM_MODE_P(MODE) \ + (SCALAR_ACCUM_MODE_P (MODE) || SCALAR_UACCUM_MODE_P (MODE)) + +/* Nonzero if MODE is a scalar fract or accum mode. */ +#define SIGNED_SCALAR_FIXED_POINT_MODE_P(MODE) \ + (SCALAR_FRACT_MODE_P (MODE) || SCALAR_ACCUM_MODE_P (MODE)) + +/* Nonzero if MODE is a scalar ufract or uaccum mode. */ +#define UNSIGNED_SCALAR_FIXED_POINT_MODE_P(MODE) \ + (SCALAR_UFRACT_MODE_P (MODE) || SCALAR_UACCUM_MODE_P (MODE)) + +/* Nonzero if MODE is a scalar fract, ufract, accum or uaccum mode. */ +#define ALL_SCALAR_FIXED_POINT_MODE_P(MODE) \ + (SIGNED_SCALAR_FIXED_POINT_MODE_P (MODE) \ + || UNSIGNED_SCALAR_FIXED_POINT_MODE_P (MODE)) + +/* Nonzero if MODE is a scalar/vector fract mode. */ +#define FRACT_MODE_P(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_FRACT \ + || GET_MODE_CLASS (MODE) == MODE_VECTOR_FRACT) + +/* Nonzero if MODE is a scalar/vector ufract mode. */ +#define UFRACT_MODE_P(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_UFRACT \ + || GET_MODE_CLASS (MODE) == MODE_VECTOR_UFRACT) + +/* Nonzero if MODE is a scalar/vector fract or ufract mode. */ +#define ALL_FRACT_MODE_P(MODE) \ + (FRACT_MODE_P (MODE) || UFRACT_MODE_P (MODE)) + +/* Nonzero if MODE is a scalar/vector accum mode. */ +#define ACCUM_MODE_P(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_ACCUM \ + || GET_MODE_CLASS (MODE) == MODE_VECTOR_ACCUM) + +/* Nonzero if MODE is a scalar/vector uaccum mode. */ +#define UACCUM_MODE_P(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_UACCUM \ + || GET_MODE_CLASS (MODE) == MODE_VECTOR_UACCUM) + +/* Nonzero if MODE is a scalar/vector accum or uaccum mode. */ +#define ALL_ACCUM_MODE_P(MODE) \ + (ACCUM_MODE_P (MODE) || UACCUM_MODE_P (MODE)) + +/* Nonzero if MODE is a scalar/vector fract or accum mode. */ +#define SIGNED_FIXED_POINT_MODE_P(MODE) \ + (FRACT_MODE_P (MODE) || ACCUM_MODE_P (MODE)) + +/* Nonzero if MODE is a scalar/vector ufract or uaccum mode. */ +#define UNSIGNED_FIXED_POINT_MODE_P(MODE) \ + (UFRACT_MODE_P (MODE) || UACCUM_MODE_P (MODE)) + +/* Nonzero if MODE is a scalar/vector fract, ufract, accum or uaccum mode. */ +#define ALL_FIXED_POINT_MODE_P(MODE) \ + (SIGNED_FIXED_POINT_MODE_P (MODE) \ + || UNSIGNED_FIXED_POINT_MODE_P (MODE)) + /* Nonzero if CLASS modes can be widened. */ #define CLASS_HAS_WIDER_MODES_P(CLASS) \ (CLASS == MODE_INT \ || CLASS == MODE_FLOAT \ || CLASS == MODE_DECIMAL_FLOAT \ - || CLASS == MODE_COMPLEX_FLOAT) + || CLASS == MODE_COMPLEX_FLOAT \ + || CLASS == MODE_FRACT \ + || CLASS == MODE_UFRACT \ + || CLASS == MODE_ACCUM \ + || CLASS == MODE_UACCUM) /* Get the size in bytes and bits of an object of mode MODE. */ @@ -99,6 +185,14 @@ extern const unsigned short mode_precision[NUM_MACHINE_MODES]; #define GET_MODE_PRECISION(MODE) mode_precision[MODE] +/* Get the number of integral bits of an object of mode MODE. */ +extern CONST_MODE_IBIT unsigned char mode_ibit[NUM_MACHINE_MODES]; +#define GET_MODE_IBIT(MODE) mode_ibit[MODE] + +/* Get the number of fractional bits of an object of mode MODE. */ +extern CONST_MODE_FBIT unsigned char mode_fbit[NUM_MACHINE_MODES]; +#define GET_MODE_FBIT(MODE) mode_fbit[MODE] + /* Get a bitmask containing 1 for all bits in a word that fit within mode MODE. */ Index: tree.def =================================================================== --- tree.def (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/tree.def) (revision 125345) +++ tree.def (.../tree.def) (working copy) @@ -173,6 +173,11 @@ The TREE_TYPE points to the node for the type pointed to. */ DEFTREECODE (POINTER_TYPE, "pointer_type", tcc_type, 0) +/* _Fract and _Accum types in Embedded-C. Different fixed-point types + are distinguished by machine mode and by the TYPE_SIZE and the + TYPE_PRECISION. */ +DEFTREECODE (FIXED_POINT_TYPE, "fixed_point_type", tcc_type, 0) + /* A reference is like a pointer except that it is coerced automatically to the value it points to. Used in C++. */ DEFTREECODE (REFERENCE_TYPE, "reference_type", tcc_type, 0) @@ -273,6 +278,9 @@ /* Contents are in TREE_REAL_CST field. */ DEFTREECODE (REAL_CST, "real_cst", tcc_constant, 0) +/* Contents are in TREE_FIXED_CST field. */ +DEFTREECODE (FIXED_CST, "fixed_cst", tcc_constant, 0) + /* Contents are in TREE_REALPART and TREE_IMAGPART fields, whose contents are other constant nodes. */ DEFTREECODE (COMPLEX_CST, "complex_cst", tcc_constant, 0) @@ -726,6 +734,11 @@ represented by CONVERT_EXPR or NOP_EXPR nodes. */ DEFTREECODE (CONVERT_EXPR, "convert_expr", tcc_unary, 1) +/* Conversion of a fixed-point value to an integer, a real, or a fixed-point + value. Or conversion of a fixed-point value from an integer, a real, or + a fixed-point value. */ +DEFTREECODE (FIXED_CONVERT_EXPR, "fixed_convert_expr", tcc_unary, 1) + /* Represents a conversion expected to require no code to be generated. */ DEFTREECODE (NOP_EXPR, "nop_expr", tcc_unary, 1) Index: tree.h =================================================================== --- tree.h (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/tree.h) (revision 125345) +++ tree.h (.../tree.h) (working copy) @@ -384,7 +384,8 @@ unsigned protected_flag : 1; unsigned deprecated_flag : 1; unsigned invariant_flag : 1; - + unsigned saturating_flag : 1; /* FIXME. This new flag increases the size of + tree_common by a full word. */ unsigned lang_flag_0 : 1; unsigned lang_flag_1 : 1; unsigned lang_flag_2 : 1; @@ -570,6 +571,11 @@ TREE_INVARIANT in all expressions. + saturating_flag: + + TYPE_SATURATING in + all types + nowarning_flag: TREE_NO_WARNING in @@ -946,7 +952,8 @@ TREE_NOT_CHECK3 (T, RECORD_TYPE, UNION_TYPE, QUAL_UNION_TYPE) #define NUMERICAL_TYPE_CHECK(T) \ - TREE_CHECK4 (T, INTEGER_TYPE, ENUMERAL_TYPE, BOOLEAN_TYPE, REAL_TYPE) + TREE_CHECK5 (T, INTEGER_TYPE, ENUMERAL_TYPE, BOOLEAN_TYPE, REAL_TYPE, \ + FIXED_POINT_TYPE) /* Nonzero if NODE is a GIMPLE statement. */ #define GIMPLE_STMT_P(NODE) \ @@ -1034,6 +1041,20 @@ || TREE_CODE (TYPE) == BOOLEAN_TYPE \ || TREE_CODE (TYPE) == INTEGER_TYPE) +/* Nonzero if TYPE represents a non-saturating fixed-point type. */ + +#define NON_SAT_FIXED_POINT_TYPE_P(TYPE) \ + (TREE_CODE (TYPE) == FIXED_POINT_TYPE && !TYPE_SATURATING (TYPE)) + +/* Nonzero if TYPE represents a saturating fixed-point type. */ + +#define SAT_FIXED_POINT_TYPE_P(TYPE) \ + (TREE_CODE (TYPE) == FIXED_POINT_TYPE && TYPE_SATURATING (TYPE)) + +/* Nonzero if TYPE represents a fixed-point type. */ + +#define FIXED_POINT_TYPE_P(TYPE) (TREE_CODE (TYPE) == FIXED_POINT_TYPE) + /* Nonzero if TYPE represents a scalar floating-point type. */ #define SCALAR_FLOAT_TYPE_P(TYPE) (TREE_CODE (TYPE) == REAL_TYPE) @@ -1324,6 +1345,9 @@ any expression node. */ #define TREE_INVARIANT(NODE) ((NODE)->base.invariant_flag) +/* In fixed-point types, means a saturating type. */ +#define TYPE_SATURATING(NODE) ((NODE)->base.saturating_flag) + /* These flags are available for each language front end to use internally. */ #define TREE_LANG_FLAG_0(NODE) ((NODE)->base.lang_flag_0) #define TREE_LANG_FLAG_1(NODE) ((NODE)->base.lang_flag_1) @@ -1375,6 +1399,18 @@ struct real_value * real_cst_ptr; }; +/* In a FIXED_CST node. */ +struct fixed_value; + +#define TREE_FIXED_CST_PTR(NODE) (FIXED_CST_CHECK (NODE)->fixed_cst.fixed_cst_ptr) +#define TREE_FIXED_CST(NODE) (*TREE_FIXED_CST_PTR (NODE)) + +struct tree_fixed_cst GTY(()) +{ + struct tree_common common; + struct fixed_value * fixed_cst_ptr; +}; + /* In a STRING_CST */ #define TREE_STRING_LENGTH(NODE) (STRING_CST_CHECK (NODE)->string.length) #define TREE_STRING_POINTER(NODE) \ @@ -2065,6 +2101,8 @@ type node requires structural equality. */ #define SET_TYPE_STRUCTURAL_EQUALITY(NODE) (TYPE_CANONICAL (NODE) = NULL_TREE) #define TYPE_LANG_SPECIFIC(NODE) (TYPE_CHECK (NODE)->type.lang_specific) +#define TYPE_IBIT(NODE) (GET_MODE_IBIT (TYPE_MODE (NODE))) +#define TYPE_FBIT(NODE) (GET_MODE_FBIT (TYPE_MODE (NODE))) /* For a VECTOR_TYPE node, this describes a different type which is emitted in the debugging output. We use this to describe a vector as a @@ -3346,6 +3384,7 @@ struct tree_common GTY ((tag ("TS_COMMON"))) common; struct tree_int_cst GTY ((tag ("TS_INT_CST"))) int_cst; struct tree_real_cst GTY ((tag ("TS_REAL_CST"))) real_cst; + struct tree_fixed_cst GTY ((tag ("TS_FIXED_CST"))) fixed_cst; struct tree_vector GTY ((tag ("TS_VECTOR"))) vector; struct tree_string GTY ((tag ("TS_STRING"))) string; struct tree_complex GTY ((tag ("TS_COMPLEX"))) complex; @@ -3457,6 +3496,75 @@ TI_MAIN_IDENTIFIER, + TI_SAT_SFRACT_TYPE, + TI_SAT_FRACT_TYPE, + TI_SAT_LFRACT_TYPE, + TI_SAT_LLFRACT_TYPE, + TI_SAT_USFRACT_TYPE, + TI_SAT_UFRACT_TYPE, + TI_SAT_ULFRACT_TYPE, + TI_SAT_ULLFRACT_TYPE, + TI_SFRACT_TYPE, + TI_FRACT_TYPE, + TI_LFRACT_TYPE, + TI_LLFRACT_TYPE, + TI_USFRACT_TYPE, + TI_UFRACT_TYPE, + TI_ULFRACT_TYPE, + TI_ULLFRACT_TYPE, + TI_SAT_SACCUM_TYPE, + TI_SAT_ACCUM_TYPE, + TI_SAT_LACCUM_TYPE, + TI_SAT_LLACCUM_TYPE, + TI_SAT_USACCUM_TYPE, + TI_SAT_UACCUM_TYPE, + TI_SAT_ULACCUM_TYPE, + TI_SAT_ULLACCUM_TYPE, + TI_SACCUM_TYPE, + TI_ACCUM_TYPE, + TI_LACCUM_TYPE, + TI_LLACCUM_TYPE, + TI_USACCUM_TYPE, + TI_UACCUM_TYPE, + TI_ULACCUM_TYPE, + TI_ULLACCUM_TYPE, + TI_QQ_TYPE, + TI_HQ_TYPE, + TI_SQ_TYPE, + TI_DQ_TYPE, + TI_TQ_TYPE, + TI_UQQ_TYPE, + TI_UHQ_TYPE, + TI_USQ_TYPE, + TI_UDQ_TYPE, + TI_UTQ_TYPE, + TI_SAT_QQ_TYPE, + TI_SAT_HQ_TYPE, + TI_SAT_SQ_TYPE, + TI_SAT_DQ_TYPE, + TI_SAT_TQ_TYPE, + TI_SAT_UQQ_TYPE, + TI_SAT_UHQ_TYPE, + TI_SAT_USQ_TYPE, + TI_SAT_UDQ_TYPE, + TI_SAT_UTQ_TYPE, + TI_HA_TYPE, + TI_SA_TYPE, + TI_DA_TYPE, + TI_TA_TYPE, + TI_UHA_TYPE, + TI_USA_TYPE, + TI_UDA_TYPE, + TI_UTA_TYPE, + TI_SAT_HA_TYPE, + TI_SAT_SA_TYPE, + TI_SAT_DA_TYPE, + TI_SAT_TA_TYPE, + TI_SAT_UHA_TYPE, + TI_SAT_USA_TYPE, + TI_SAT_UDA_TYPE, + TI_SAT_UTA_TYPE, + TI_MAX }; @@ -3536,6 +3644,84 @@ #define dfloat64_ptr_type_node global_trees[TI_DFLOAT64_PTR_TYPE] #define dfloat128_ptr_type_node global_trees[TI_DFLOAT128_PTR_TYPE] +/* The fixed-point types. */ +#define sat_short_fract_type_node global_trees[TI_SAT_SFRACT_TYPE] +#define sat_fract_type_node global_trees[TI_SAT_FRACT_TYPE] +#define sat_long_fract_type_node global_trees[TI_SAT_LFRACT_TYPE] +#define sat_long_long_fract_type_node global_trees[TI_SAT_LLFRACT_TYPE] +#define sat_unsigned_short_fract_type_node \ + global_trees[TI_SAT_USFRACT_TYPE] +#define sat_unsigned_fract_type_node global_trees[TI_SAT_UFRACT_TYPE] +#define sat_unsigned_long_fract_type_node \ + global_trees[TI_SAT_ULFRACT_TYPE] +#define sat_unsigned_long_long_fract_type_node \ + global_trees[TI_SAT_ULLFRACT_TYPE] +#define short_fract_type_node global_trees[TI_SFRACT_TYPE] +#define fract_type_node global_trees[TI_FRACT_TYPE] +#define long_fract_type_node global_trees[TI_LFRACT_TYPE] +#define long_long_fract_type_node global_trees[TI_LLFRACT_TYPE] +#define unsigned_short_fract_type_node global_trees[TI_USFRACT_TYPE] +#define unsigned_fract_type_node global_trees[TI_UFRACT_TYPE] +#define unsigned_long_fract_type_node global_trees[TI_ULFRACT_TYPE] +#define unsigned_long_long_fract_type_node \ + global_trees[TI_ULLFRACT_TYPE] +#define sat_short_accum_type_node global_trees[TI_SAT_SACCUM_TYPE] +#define sat_accum_type_node global_trees[TI_SAT_ACCUM_TYPE] +#define sat_long_accum_type_node global_trees[TI_SAT_LACCUM_TYPE] +#define sat_long_long_accum_type_node global_trees[TI_SAT_LLACCUM_TYPE] +#define sat_unsigned_short_accum_type_node \ + global_trees[TI_SAT_USACCUM_TYPE] +#define sat_unsigned_accum_type_node global_trees[TI_SAT_UACCUM_TYPE] +#define sat_unsigned_long_accum_type_node \ + global_trees[TI_SAT_ULACCUM_TYPE] +#define sat_unsigned_long_long_accum_type_node \ + global_trees[TI_SAT_ULLACCUM_TYPE] +#define short_accum_type_node global_trees[TI_SACCUM_TYPE] +#define accum_type_node global_trees[TI_ACCUM_TYPE] +#define long_accum_type_node global_trees[TI_LACCUM_TYPE] +#define long_long_accum_type_node global_trees[TI_LLACCUM_TYPE] +#define unsigned_short_accum_type_node global_trees[TI_USACCUM_TYPE] +#define unsigned_accum_type_node global_trees[TI_UACCUM_TYPE] +#define unsigned_long_accum_type_node global_trees[TI_ULACCUM_TYPE] +#define unsigned_long_long_accum_type_node \ + global_trees[TI_ULLACCUM_TYPE] +#define qq_type_node global_trees[TI_QQ_TYPE] +#define hq_type_node global_trees[TI_HQ_TYPE] +#define sq_type_node global_trees[TI_SQ_TYPE] +#define dq_type_node global_trees[TI_DQ_TYPE] +#define tq_type_node global_trees[TI_TQ_TYPE] +#define uqq_type_node global_trees[TI_UQQ_TYPE] +#define uhq_type_node global_trees[TI_UHQ_TYPE] +#define usq_type_node global_trees[TI_USQ_TYPE] +#define udq_type_node global_trees[TI_UDQ_TYPE] +#define utq_type_node global_trees[TI_UTQ_TYPE] +#define sat_qq_type_node global_trees[TI_SAT_QQ_TYPE] +#define sat_hq_type_node global_trees[TI_SAT_HQ_TYPE] +#define sat_sq_type_node global_trees[TI_SAT_SQ_TYPE] +#define sat_dq_type_node global_trees[TI_SAT_DQ_TYPE] +#define sat_tq_type_node global_trees[TI_SAT_TQ_TYPE] +#define sat_uqq_type_node global_trees[TI_SAT_UQQ_TYPE] +#define sat_uhq_type_node global_trees[TI_SAT_UHQ_TYPE] +#define sat_usq_type_node global_trees[TI_SAT_USQ_TYPE] +#define sat_udq_type_node global_trees[TI_SAT_UDQ_TYPE] +#define sat_utq_type_node global_trees[TI_SAT_UTQ_TYPE] +#define ha_type_node global_trees[TI_HA_TYPE] +#define sa_type_node global_trees[TI_SA_TYPE] +#define da_type_node global_trees[TI_DA_TYPE] +#define ta_type_node global_trees[TI_TA_TYPE] +#define uha_type_node global_trees[TI_UHA_TYPE] +#define usa_type_node global_trees[TI_USA_TYPE] +#define uda_type_node global_trees[TI_UDA_TYPE] +#define uta_type_node global_trees[TI_UTA_TYPE] +#define sat_ha_type_node global_trees[TI_SAT_HA_TYPE] +#define sat_sa_type_node global_trees[TI_SAT_SA_TYPE] +#define sat_da_type_node global_trees[TI_SAT_DA_TYPE] +#define sat_ta_type_node global_trees[TI_SAT_TA_TYPE] +#define sat_uha_type_node global_trees[TI_SAT_UHA_TYPE] +#define sat_usa_type_node global_trees[TI_SAT_USA_TYPE] +#define sat_uda_type_node global_trees[TI_SAT_UDA_TYPE] +#define sat_uta_type_node global_trees[TI_SAT_UTA_TYPE] + /* The node that should be placed at the end of a parameter list to indicate that the function does not take a variable number of arguments. The TREE_VALUE will be void_type_node and there will be @@ -3814,6 +4000,37 @@ extern bool may_negate_without_overflow_p (tree); extern tree get_inner_array_type (tree); +/* Construct various nodes representing fract or accum data types. */ + +extern tree make_fract_type (int, int, int); +extern tree make_accum_type (int, int, int); + +#define make_signed_fract_type(P) make_fract_type (P, 0, 0) +#define make_unsigned_fract_type(P) make_fract_type (P, 1, 0) +#define make_sat_signed_fract_type(P) make_fract_type (P, 0, 1) +#define make_sat_unsigned_fract_type(P) make_fract_type (P, 1, 1) +#define make_signed_accum_type(P) make_accum_type (P, 0, 0) +#define make_unsigned_accum_type(P) make_accum_type (P, 1, 0) +#define make_sat_signed_accum_type(P) make_accum_type (P, 0, 1) +#define make_sat_unsigned_accum_type(P) make_accum_type (P, 1, 1) + +#define make_or_reuse_signed_fract_type(P) \ + make_or_reuse_fract_type (P, 0, 0) +#define make_or_reuse_unsigned_fract_type(P) \ + make_or_reuse_fract_type (P, 1, 0) +#define make_or_reuse_sat_signed_fract_type(P) \ + make_or_reuse_fract_type (P, 0, 1) +#define make_or_reuse_sat_unsigned_fract_type(P) \ + make_or_reuse_fract_type (P, 1, 1) +#define make_or_reuse_signed_accum_type(P) \ + make_or_reuse_accum_type (P, 0, 0) +#define make_or_reuse_unsigned_accum_type(P) \ + make_or_reuse_accum_type (P, 1, 0) +#define make_or_reuse_sat_signed_accum_type(P) \ + make_or_reuse_accum_type (P, 0, 1) +#define make_or_reuse_sat_unsigned_accum_type(P) \ + make_or_reuse_accum_type (P, 1, 1) + extern tree get_signed_or_unsigned_type (int unsignedp, tree type); /* From expmed.c. Since rtl.h is included after tree.h, we can't @@ -4191,6 +4408,11 @@ extern bool cst_and_fits_in_hwi (tree); extern tree num_ending_zeros (tree); +/* fixed_zerop (tree x) is nonzero if X is a fixed-point constant of + value 0. */ + +extern int fixed_zerop (tree); + /* staticp (tree x) is nonzero if X is a reference to data allocated at a fixed address in memory. Returns the outermost data. */ Index: tree.c =================================================================== --- tree.c (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/tree.c) (revision 125345) +++ tree.c (.../tree.c) (working copy) @@ -51,6 +51,7 @@ #include "tree-flow.h" #include "params.h" #include "pointer-set.h" +#include "fixed-value.h" /* Each tree code class has an associated string representation. These must correspond to the tree_code_class entries. */ @@ -400,6 +401,7 @@ { case INTEGER_CST: return sizeof (struct tree_int_cst); case REAL_CST: return sizeof (struct tree_real_cst); + case FIXED_CST: return sizeof (struct tree_fixed_cst); case COMPLEX_CST: return sizeof (struct tree_complex); case VECTOR_CST: return sizeof (struct tree_vector); case STRING_CST: gcc_unreachable (); @@ -1092,7 +1094,23 @@ return t; } +/* Return a new FIXED_CST node whose type is TYPE and value is F. */ +tree +build_fixed (tree type, FIXED_VALUE_TYPE f) +{ + tree v; + FIXED_VALUE_TYPE *fp; + + v = make_node (FIXED_CST); + fp = ggc_alloc (sizeof (FIXED_VALUE_TYPE)); + memcpy (fp, &f, sizeof (FIXED_VALUE_TYPE)); + + TREE_TYPE (v) = type; + TREE_FIXED_CST_PTR (v) = fp; + return v; +} + /* Return a new REAL_CST node whose type is TYPE and value is D. */ tree @@ -1212,6 +1230,11 @@ case REAL_TYPE: return build_real (type, dconst1); + case FIXED_POINT_TYPE: + /* We can only generate 1 for accum types. */ + gcc_assert (ALL_SCALAR_ACCUM_MODE_P (TYPE_MODE (type))); + return build_fixed (type, fconst1[TYPE_MODE (type)]); + case VECTOR_TYPE: { tree scalar, cst; @@ -1431,6 +1454,15 @@ || integer_nonzerop (TREE_IMAGPART (expr))))); } +/* Return 1 if EXPR is the fixed-point constant zero. */ + +int +fixed_zerop (tree expr) +{ + return TREE_CODE (expr) == FIXED_CST + && double_int_zero_p (TREE_FIXED_CST (expr).data); +} + /* Return the power of two represented by a tree node known to be a power of two. */ @@ -2182,6 +2214,7 @@ /* tcc_constant cases. */ case INTEGER_CST: return TS_INT_CST; case REAL_CST: return TS_REAL_CST; + case FIXED_CST: return TS_FIXED_CST; case COMPLEX_CST: return TS_COMPLEX; case VECTOR_CST: return TS_VECTOR; case STRING_CST: return TS_STRING; @@ -3668,6 +3701,7 @@ (TREE_INT_CST_HIGH (TYPE_MAX_VALUE (ntype)), hashcode); break; case REAL_TYPE: + case FIXED_POINT_TYPE: { unsigned int precision = TYPE_PRECISION (ntype); hashcode = iterative_hash_object (precision, hashcode); @@ -4511,6 +4545,7 @@ case INTEGER_TYPE: case REAL_TYPE: + case FIXED_POINT_TYPE: case BOOLEAN_TYPE: return ((TYPE_MAX_VALUE (a->type) == TYPE_MAX_VALUE (b->type) || tree_int_cst_equal (TYPE_MAX_VALUE (a->type), @@ -4979,6 +5014,9 @@ case REAL_CST: return REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2)); + case FIXED_CST: + return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1), TREE_FIXED_CST (t2)); + case STRING_CST: return (TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2) && ! memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2), @@ -5202,6 +5240,12 @@ return iterative_hash_hashval_t (val2, val); } + case FIXED_CST: + { + unsigned int val2 = fixed_hash (TREE_FIXED_CST_PTR (t)); + + return iterative_hash_hashval_t (val2, val); + } case STRING_CST: return iterative_hash (TREE_STRING_POINTER (t), TREE_STRING_LENGTH (t), val); @@ -6247,6 +6291,7 @@ case INTEGER_TYPE: case REAL_TYPE: + case FIXED_POINT_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: /* Scalar types are variably modified if their end points @@ -6916,6 +6961,76 @@ return make_signed_type (size); } +static tree +make_or_reuse_fract_type (unsigned size, int unsignedp, int satp) +{ + if (satp) + { + if (size == SHORT_FRACT_TYPE_SIZE) + return unsignedp ? sat_unsigned_short_fract_type_node + : sat_short_fract_type_node; + if (size == FRACT_TYPE_SIZE) + return unsignedp ? sat_unsigned_fract_type_node : sat_fract_type_node; + if (size == LONG_FRACT_TYPE_SIZE) + return unsignedp ? sat_unsigned_long_fract_type_node + : sat_long_fract_type_node; + if (size == LONG_LONG_FRACT_TYPE_SIZE) + return unsignedp ? sat_unsigned_long_long_fract_type_node + : sat_long_long_fract_type_node; + } + else + { + if (size == SHORT_FRACT_TYPE_SIZE) + return unsignedp ? unsigned_short_fract_type_node + : short_fract_type_node; + if (size == FRACT_TYPE_SIZE) + return unsignedp ? unsigned_fract_type_node : fract_type_node; + if (size == LONG_FRACT_TYPE_SIZE) + return unsignedp ? unsigned_long_fract_type_node + : long_fract_type_node; + if (size == LONG_LONG_FRACT_TYPE_SIZE) + return unsignedp ? unsigned_long_long_fract_type_node + : long_long_fract_type_node; + } + + return make_fract_type (size, unsignedp, satp); +} + +static tree +make_or_reuse_accum_type (unsigned size, int unsignedp, int satp) +{ + if (satp) + { + if (size == SHORT_ACCUM_TYPE_SIZE) + return unsignedp ? sat_unsigned_short_accum_type_node + : sat_short_accum_type_node; + if (size == ACCUM_TYPE_SIZE) + return unsignedp ? sat_unsigned_accum_type_node : sat_accum_type_node; + if (size == LONG_ACCUM_TYPE_SIZE) + return unsignedp ? sat_unsigned_long_accum_type_node + : sat_long_accum_type_node; + if (size == LONG_LONG_ACCUM_TYPE_SIZE) + return unsignedp ? sat_unsigned_long_long_accum_type_node + : sat_long_long_accum_type_node; + } + else + { + if (size == SHORT_ACCUM_TYPE_SIZE) + return unsignedp ? unsigned_short_accum_type_node + : short_accum_type_node; + if (size == ACCUM_TYPE_SIZE) + return unsignedp ? unsigned_accum_type_node : accum_type_node; + if (size == LONG_ACCUM_TYPE_SIZE) + return unsignedp ? unsigned_long_accum_type_node + : long_accum_type_node; + if (size == LONG_LONG_ACCUM_TYPE_SIZE) + return unsignedp ? unsigned_long_long_accum_type_node + : long_long_accum_type_node; + } + + return make_accum_type (size, unsignedp, satp); +} + /* Create nodes for all integer types (and error_mark_node) using the sizes of C datatypes. The caller should call set_sizetype soon after calling this function to select one of the types as sizetype. */ @@ -7063,6 +7178,90 @@ complex_double_type_node = build_complex_type (double_type_node); complex_long_double_type_node = build_complex_type (long_double_type_node); + /* Fixed-point types. */ + if (targetm.fixed_point_supported_p ()) + { + sat_short_fract_type_node = make_sat_signed_fract_type (SHORT_FRACT_TYPE_SIZE); + sat_fract_type_node = make_sat_signed_fract_type (FRACT_TYPE_SIZE); + sat_long_fract_type_node = make_sat_signed_fract_type (LONG_FRACT_TYPE_SIZE); + sat_long_long_fract_type_node = make_sat_signed_fract_type (LONG_LONG_FRACT_TYPE_SIZE); + sat_unsigned_short_fract_type_node = make_sat_unsigned_fract_type (SHORT_FRACT_TYPE_SIZE); + sat_unsigned_fract_type_node = make_sat_unsigned_fract_type (FRACT_TYPE_SIZE); + sat_unsigned_long_fract_type_node = make_sat_unsigned_fract_type (LONG_FRACT_TYPE_SIZE); + sat_unsigned_long_long_fract_type_node = make_sat_unsigned_fract_type (LONG_LONG_FRACT_TYPE_SIZE); + + short_fract_type_node = make_signed_fract_type (SHORT_FRACT_TYPE_SIZE); + fract_type_node = make_signed_fract_type (FRACT_TYPE_SIZE); + long_fract_type_node = make_signed_fract_type (LONG_FRACT_TYPE_SIZE); + long_long_fract_type_node = make_signed_fract_type (LONG_LONG_FRACT_TYPE_SIZE); + unsigned_short_fract_type_node = make_unsigned_fract_type (SHORT_FRACT_TYPE_SIZE); + unsigned_fract_type_node = make_unsigned_fract_type (FRACT_TYPE_SIZE); + unsigned_long_fract_type_node = make_unsigned_fract_type (LONG_FRACT_TYPE_SIZE); + unsigned_long_long_fract_type_node = make_unsigned_fract_type (LONG_LONG_FRACT_TYPE_SIZE); + + sat_short_accum_type_node = make_sat_signed_accum_type (SHORT_ACCUM_TYPE_SIZE); + sat_accum_type_node = make_sat_signed_accum_type (ACCUM_TYPE_SIZE); + sat_long_accum_type_node = make_sat_signed_accum_type (LONG_ACCUM_TYPE_SIZE); + sat_long_long_accum_type_node = make_sat_signed_accum_type (LONG_LONG_ACCUM_TYPE_SIZE); + sat_unsigned_short_accum_type_node = make_sat_unsigned_accum_type (SHORT_ACCUM_TYPE_SIZE); + sat_unsigned_accum_type_node = make_sat_unsigned_accum_type (ACCUM_TYPE_SIZE); + sat_unsigned_long_accum_type_node = make_sat_unsigned_accum_type (LONG_ACCUM_TYPE_SIZE); + sat_unsigned_long_long_accum_type_node = make_sat_unsigned_accum_type (LONG_LONG_ACCUM_TYPE_SIZE); + + short_accum_type_node = make_signed_accum_type (SHORT_ACCUM_TYPE_SIZE); + accum_type_node = make_signed_accum_type (ACCUM_TYPE_SIZE); + long_accum_type_node = make_signed_accum_type (LONG_ACCUM_TYPE_SIZE); + long_long_accum_type_node = make_signed_accum_type (LONG_LONG_ACCUM_TYPE_SIZE); + unsigned_short_accum_type_node = make_unsigned_accum_type (SHORT_ACCUM_TYPE_SIZE); + unsigned_accum_type_node = make_unsigned_accum_type (ACCUM_TYPE_SIZE); + unsigned_long_accum_type_node = make_unsigned_accum_type (LONG_ACCUM_TYPE_SIZE); + unsigned_long_long_accum_type_node = make_unsigned_accum_type (LONG_LONG_ACCUM_TYPE_SIZE); + + qq_type_node = make_or_reuse_signed_fract_type (GET_MODE_BITSIZE (QQmode)); + hq_type_node = make_or_reuse_signed_fract_type (GET_MODE_BITSIZE (HQmode)); + sq_type_node = make_or_reuse_signed_fract_type (GET_MODE_BITSIZE (SQmode)); + dq_type_node = make_or_reuse_signed_fract_type (GET_MODE_BITSIZE (DQmode)); + tq_type_node = make_or_reuse_signed_fract_type (GET_MODE_BITSIZE (TQmode)); + + uqq_type_node = make_or_reuse_unsigned_fract_type (GET_MODE_BITSIZE (UQQmode)); + uhq_type_node = make_or_reuse_unsigned_fract_type (GET_MODE_BITSIZE (UHQmode)); + usq_type_node = make_or_reuse_unsigned_fract_type (GET_MODE_BITSIZE (USQmode)); + udq_type_node = make_or_reuse_unsigned_fract_type (GET_MODE_BITSIZE (UDQmode)); + utq_type_node = make_or_reuse_unsigned_fract_type (GET_MODE_BITSIZE (UTQmode)); + + sat_qq_type_node = make_or_reuse_sat_signed_fract_type (GET_MODE_BITSIZE (QQmode)); + sat_hq_type_node = make_or_reuse_sat_signed_fract_type (GET_MODE_BITSIZE (HQmode)); + sat_sq_type_node = make_or_reuse_sat_signed_fract_type (GET_MODE_BITSIZE (SQmode)); + sat_dq_type_node = make_or_reuse_sat_signed_fract_type (GET_MODE_BITSIZE (DQmode)); + sat_tq_type_node = make_or_reuse_sat_signed_fract_type (GET_MODE_BITSIZE (TQmode)); + + sat_uqq_type_node = make_or_reuse_sat_unsigned_fract_type (GET_MODE_BITSIZE (UQQmode)); + sat_uhq_type_node = make_or_reuse_sat_unsigned_fract_type (GET_MODE_BITSIZE (UHQmode)); + sat_usq_type_node = make_or_reuse_sat_unsigned_fract_type (GET_MODE_BITSIZE (USQmode)); + sat_udq_type_node = make_or_reuse_sat_unsigned_fract_type (GET_MODE_BITSIZE (UDQmode)); + sat_utq_type_node = make_or_reuse_sat_unsigned_fract_type (GET_MODE_BITSIZE (UTQmode)); + + ha_type_node = make_or_reuse_signed_accum_type (GET_MODE_BITSIZE (HAmode)); + sa_type_node = make_or_reuse_signed_accum_type (GET_MODE_BITSIZE (SAmode)); + da_type_node = make_or_reuse_signed_accum_type (GET_MODE_BITSIZE (DAmode)); + ta_type_node = make_or_reuse_signed_accum_type (GET_MODE_BITSIZE (TAmode)); + + uha_type_node = make_or_reuse_unsigned_accum_type (GET_MODE_BITSIZE (UHAmode)); + usa_type_node = make_or_reuse_unsigned_accum_type (GET_MODE_BITSIZE (USAmode)); + uda_type_node = make_or_reuse_unsigned_accum_type (GET_MODE_BITSIZE (UDAmode)); + uta_type_node = make_or_reuse_unsigned_accum_type (GET_MODE_BITSIZE (UTAmode)); + + sat_ha_type_node = make_or_reuse_sat_signed_accum_type (GET_MODE_BITSIZE (HAmode)); + sat_sa_type_node = make_or_reuse_sat_signed_accum_type (GET_MODE_BITSIZE (SAmode)); + sat_da_type_node = make_or_reuse_sat_signed_accum_type (GET_MODE_BITSIZE (DAmode)); + sat_ta_type_node = make_or_reuse_sat_signed_accum_type (GET_MODE_BITSIZE (TAmode)); + + sat_uha_type_node = make_or_reuse_sat_unsigned_accum_type (GET_MODE_BITSIZE (UHAmode)); + sat_usa_type_node = make_or_reuse_sat_unsigned_accum_type (GET_MODE_BITSIZE (USAmode)); + sat_uda_type_node = make_or_reuse_sat_unsigned_accum_type (GET_MODE_BITSIZE (UDAmode)); + sat_uta_type_node = make_or_reuse_sat_unsigned_accum_type (GET_MODE_BITSIZE (UTAmode)); + } + { tree t = targetm.build_builtin_va_list (); @@ -7327,6 +7526,10 @@ { case MODE_VECTOR_INT: case MODE_VECTOR_FLOAT: + case MODE_VECTOR_FRACT: + case MODE_VECTOR_UFRACT: + case MODE_VECTOR_ACCUM: + case MODE_VECTOR_UACCUM: nunits = GET_MODE_NUNITS (mode); break; @@ -7387,6 +7590,9 @@ return real_zerop (init) && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init)); + case FIXED_CST: + return fixed_zerop (init); + case COMPLEX_CST: return integer_zerop (init) || (real_zerop (init) @@ -8076,6 +8282,7 @@ case IDENTIFIER_NODE: case INTEGER_CST: case REAL_CST: + case FIXED_CST: case VECTOR_CST: case STRING_CST: case BLOCK: @@ -8254,6 +8461,7 @@ else if (TREE_CODE (*type_p) == BOOLEAN_TYPE || TREE_CODE (*type_p) == ENUMERAL_TYPE || TREE_CODE (*type_p) == INTEGER_TYPE + || TREE_CODE (*type_p) == FIXED_POINT_TYPE || TREE_CODE (*type_p) == REAL_TYPE) { WALK_SUBTREE (TYPE_MIN_VALUE (*type_p)); Index: rtl.def =================================================================== --- rtl.def (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/rtl.def) (revision 125345) +++ rtl.def (.../rtl.def) (working copy) @@ -309,6 +309,9 @@ /* numeric integer constant */ DEF_RTL_EXPR(CONST_INT, "const_int", "w", RTX_CONST_OBJ) +/* fixed-point constant */ +DEF_RTL_EXPR(CONST_FIXED, "const_fixed", "www", RTX_CONST_OBJ) + /* numeric floating point constant. Operands hold the value. They are all 'w' and there may be from 2 to 6; see real.h. */ @@ -438,8 +441,18 @@ DEF_RTL_EXPR(MULT, "mult", "ee", RTX_COMM_ARITH) +/* Multiplication with signed saturation */ +DEF_RTL_EXPR(SS_MULT, "ss_mult", "ee", RTX_COMM_ARITH) +/* Multiplication with unsigned saturation */ +DEF_RTL_EXPR(US_MULT, "us_mult", "ee", RTX_COMM_ARITH) + /* Operand 0 divided by operand 1. */ DEF_RTL_EXPR(DIV, "div", "ee", RTX_BIN_ARITH) +/* Division with signed saturation */ +DEF_RTL_EXPR(SS_DIV, "ss_div", "ee", RTX_BIN_ARITH) +/* Division with unsigned saturation */ +DEF_RTL_EXPR(US_DIV, "us_div", "ee", RTX_BIN_ARITH) + /* Remainder of operand 0 divided by operand 1. */ DEF_RTL_EXPR(MOD, "mod", "ee", RTX_BIN_ARITH) @@ -562,6 +575,30 @@ Value is defined only when the operand's value is an integer. */ DEF_RTL_EXPR(UNSIGNED_FIX, "unsigned_fix", "e", RTX_UNARY) +/* Conversions involve fixed-point types without saturation, including + fixed-point <- fixed-point, + fixed-point <- signed integer, + fixed-point <- real, + signed integer <- fixed-point, + real <- fixed-point. */ +DEF_RTL_EXPR(FIXED_ALL, "fixed_all", "e", RTX_UNARY) + +/* Conversions involve fixed-point types and unsigned integer without + saturation, including + fixed-point <- unsigned integer, + unsigned integer <- fixed-point. */ +DEF_RTL_EXPR(FIXED_UINT, "fixed_uint", "e", RTX_UNARY) + +/* Conversions involve fixed-point types with saturation, including + fixed-point <- fixed-point, + fixed-point <- signed integer, + fixed-point <- real. */ +DEF_RTL_EXPR(SAT_FIXED_ALL, "sat_fixed_all", "e", RTX_UNARY) + +/* Conversions involve fixed-point types and unsigned integer with saturation, + including fixed-point <- unsigned integer. */ +DEF_RTL_EXPR(SAT_FIXED_UINT, "sat_fixed_uint", "e", RTX_UNARY) + /* Absolute value */ DEF_RTL_EXPR(ABS, "abs", "e", RTX_UNARY) @@ -648,6 +685,8 @@ /* Negation with signed saturation. */ DEF_RTL_EXPR(SS_NEG, "ss_neg", "e", RTX_UNARY) +/* Negation with unsigned saturation. */ +DEF_RTL_EXPR(US_NEG, "us_neg", "e", RTX_UNARY) /* Absolute value with signed saturation. */ DEF_RTL_EXPR(SS_ABS, "ss_abs", "e", RTX_UNARY) @@ -655,6 +694,9 @@ /* Shift left with signed saturation. */ DEF_RTL_EXPR(SS_ASHIFT, "ss_ashift", "ee", RTX_BIN_ARITH) +/* Shift left with unsigned saturation. */ +DEF_RTL_EXPR(US_ASHIFT, "us_ashift", "ee", RTX_BIN_ARITH) + /* Operand 0 minus operand 1, with unsigned saturation. */ DEF_RTL_EXPR(US_MINUS, "us_minus", "ee", RTX_BIN_ARITH) Index: rtl.h =================================================================== --- rtl.h (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/rtl.h) (revision 125345) +++ rtl.h (.../rtl.h) (working copy) @@ -28,6 +28,7 @@ #include "input.h" #include "real.h" #include "vec.h" +#include "fixed-value.h" #undef FFS /* Some systems predefine this symbol; don't let it interfere. */ #undef FLOAT /* Likewise. */ @@ -308,6 +309,7 @@ HOST_WIDE_INT hwint[1]; struct block_symbol block_sym; struct real_value rv; + struct fixed_value fv; } GTY ((special ("rtx_def"), desc ("GET_CODE (&%0)"))) u; }; @@ -530,6 +532,13 @@ __LINE__, __FUNCTION__); \ &_rtx->u.rv; }) +#define XCNMPFV(RTX, C, M) __extension__ \ +({ rtx const _rtx = (RTX); \ + if (GET_CODE (_rtx) != (C) || GET_MODE (_rtx) == (M)) \ + rtl_check_failed_code_mode (_rtx, (C), (M), true, __FILE__, \ + __LINE__, __FUNCTION__); \ + &_rtx->u.fv; }) + #define BLOCK_SYMBOL_CHECK(RTX) __extension__ \ ({ rtx const _symbol = (RTX); \ unsigned int flags = RTL_CHECKC1 (_symbol, 1, SYMBOL_REF).rt_int; \ @@ -574,6 +583,7 @@ #define XCMWINT(RTX, N, C, M) ((RTX)->u.hwint[N]) #define XCNMWINT(RTX, N, C, M) ((RTX)->u.hwint[N]) #define XCNMPRV(RTX, C, M) (&(RTX)->u.rv) +#define XCNMPFV(RTX, C, M) (&(RTX)->u.fv) #define BLOCK_SYMBOL_CHECK(RTX) (&(RTX)->u.block_sym) #endif @@ -998,6 +1008,13 @@ #define CONST_DOUBLE_REAL_VALUE(r) \ ((const struct real_value *) XCNMPRV (r, CONST_DOUBLE, VOIDmode)) +#define CONST_FIXED_VALUE(r) \ + ((const struct fixed_value *) XCNMPFV (r, CONST_FIXED, VOIDmode)) +#define CONST_FIXED_VALUE_HIGH(r) \ + ((HOST_WIDE_INT) (CONST_FIXED_VALUE(r)->data.high)) +#define CONST_FIXED_VALUE_LOW(r) \ + ((HOST_WIDE_INT) (CONST_FIXED_VALUE(r)->data.low)) + /* For a CONST_VECTOR, return element #n. */ #define CONST_VECTOR_ELT(RTX, N) XCVECEXP (RTX, 0, N, CONST_VECTOR) Index: rtl.c =================================================================== --- rtl.c (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/rtl.c) (revision 125345) +++ rtl.c (.../rtl.c) (working copy) @@ -111,7 +111,7 @@ const unsigned char rtx_code_size[NUM_RTX_CODE] = { #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) \ - ((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE \ + ((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE || (ENUM) == CONST_FIXED\ ? RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (HOST_WIDE_INT) \ : RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (rtunion)), @@ -220,6 +220,7 @@ case REG: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case SYMBOL_REF: case CODE_LABEL: @@ -368,6 +369,7 @@ case SCRATCH: case CONST_DOUBLE: case CONST_INT: + case CONST_FIXED: return 0; default: Index: fixed-value.h =================================================================== --- fixed-value.h (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/fixed-value.h) (revision 0) +++ fixed-value.h (.../fixed-value.h) (revision 125345) @@ -0,0 +1,92 @@ +/* Fixed-point arithmetic support. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GCC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +#ifndef GCC_FIXED_VALUE_H +#define GCC_FIXED_VALUE_H + +#include "machmode.h" +#include "real.h" +#include "double-int.h" + +struct fixed_value GTY(()) +{ + double_int data; /* Store data up to 2 wide integers. */ + unsigned int mode; /* Use machine mode to know IBIT and FBIT. */ +}; + +#define FIXED_VALUE_TYPE struct fixed_value + +/* Constant fixed-point values 0 and 1. */ +extern FIXED_VALUE_TYPE fconst0[]; +extern FIXED_VALUE_TYPE fconst1[]; + +/* Return a CONST_FIXED with value R and mode M. */ +#define CONST_FIXED_FROM_FIXED_VALUE(r, m) \ + const_fixed_from_fixed_value (r, m) +extern rtx const_fixed_from_fixed_value (FIXED_VALUE_TYPE, enum machine_mode); + +/* Initialize from a decimal or hexadecimal string. */ +extern void fixed_from_string (FIXED_VALUE_TYPE *, const char *, tree); + +/* In tree.c: wrap up a FIXED_VALUE_TYPE in a tree node. */ +extern tree build_fixed (tree, FIXED_VALUE_TYPE); + +/* Extend or truncate to a new mode. */ +extern bool fixed_convert (FIXED_VALUE_TYPE *, enum machine_mode, + const FIXED_VALUE_TYPE *, int); + +/* Convert to a fixed-point mode from an integer. */ +extern bool fixed_convert_from_int (FIXED_VALUE_TYPE *, enum machine_mode, + double_int, int, int); + +/* Convert to a fixed-point mode from a real. */ +extern bool fixed_convert_from_real (FIXED_VALUE_TYPE *, enum machine_mode, + const REAL_VALUE_TYPE *, int); + +/* Convert to a real mode from a fixed-point. */ +extern void real_convert_from_fixed (REAL_VALUE_TYPE *, enum machine_mode, + const FIXED_VALUE_TYPE *); + +/* Compare two fixed-point objects for bitwise identity. */ +extern bool fixed_identical (const FIXED_VALUE_TYPE *, const FIXED_VALUE_TYPE *); + +/* Calculate a hash value. */ +extern unsigned int fixed_hash (const FIXED_VALUE_TYPE *); + +#define FIXED_VALUES_IDENTICAL(x, y) fixed_identical (&(x), &(y)) + +/* Determine whether a fixed-point value X is negative. */ +#define FIXED_VALUE_NEGATIVE(x) fixed_isneg (&(x)) + +/* Render F as a decimal floating point constant. */ +extern void fixed_to_decimal (char *str, const FIXED_VALUE_TYPE *, size_t); + +/* Binary or unary arithmetic on tree_code. */ +extern bool fixed_arithmetic (FIXED_VALUE_TYPE *, int, const FIXED_VALUE_TYPE *, + const FIXED_VALUE_TYPE *, int); + +/* Compare fixed-point values by tree_code. */ +extern bool fixed_compare (int, const FIXED_VALUE_TYPE *, + const FIXED_VALUE_TYPE *); + +/* Determine whether a fixed-point value X is negative. */ +extern bool fixed_isneg (const FIXED_VALUE_TYPE *); + +#endif /* GCC_FIXED_VALUE_H */ Index: fixed-value.c =================================================================== --- fixed-value.c (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/fixed-value.c) (revision 0) +++ fixed-value.c (.../fixed-value.c) (revision 125345) @@ -0,0 +1,1143 @@ +/* Fixed-point arithmetic support. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GCC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "toplev.h" +#include "fixed-value.h" + +static int check_real_for_fixed_mode (REAL_VALUE_TYPE *, unsigned int); +static int get_fixed_sign_bit (double_int, int); +static bool do_fixed_add (FIXED_VALUE_TYPE *, const FIXED_VALUE_TYPE *, + const FIXED_VALUE_TYPE *, int, int); +static bool do_fixed_multiply (FIXED_VALUE_TYPE *, const FIXED_VALUE_TYPE *, + const FIXED_VALUE_TYPE *, int); +static bool do_fixed_divide (FIXED_VALUE_TYPE *, const FIXED_VALUE_TYPE *, + const FIXED_VALUE_TYPE *, int); +static bool do_fixed_shift (FIXED_VALUE_TYPE *, const FIXED_VALUE_TYPE *, + const FIXED_VALUE_TYPE *, int, int); +static bool do_fixed_neg (FIXED_VALUE_TYPE *, const FIXED_VALUE_TYPE *, int); +static bool fixed_saturate1 (unsigned int, double_int, double_int *, int); +static bool fixed_saturate2 (unsigned int, double_int, double_int, + double_int *, int); + +/* Compare two fixed objects for bitwise identity. */ + +bool +fixed_identical (const FIXED_VALUE_TYPE *a, const FIXED_VALUE_TYPE *b) +{ + return a->mode == b->mode && a->data.high == b->data.high + && a->data.low == b->data.low; +} + +/* Calculate a hash value. */ + +unsigned int +fixed_hash (const FIXED_VALUE_TYPE *f) +{ + return (unsigned int) (f->data.low ^ f->data.high); +} + +/* Check REAL_VALUE against the range of the fixed-point mode. + Return 0, if it is within the range. + 1, if it is less than the minimum. + 2, if it is greater than the maximum, but not equal to + the maximum + the epsilon. + 3, if it is equal to the maximum + the epsilon. */ + +int +check_real_for_fixed_mode (REAL_VALUE_TYPE *real_value, unsigned int mode) +{ + REAL_VALUE_TYPE max_value, min_value, epsilon_value; + char max_string[20], min_string[20], epsilon_string[20]; + + sprintf (max_string, "0x1.0p%d", GET_MODE_IBIT (mode)); + sprintf (epsilon_string, "0x1.0p-%d", GET_MODE_FBIT (mode)); + real_from_string (&max_value, max_string); + real_from_string (&epsilon_value, epsilon_string); + + if (SIGNED_FIXED_POINT_MODE_P (mode)) + { + sprintf (min_string, "-0x1.0p%d", GET_MODE_IBIT (mode)); + real_from_string (&min_value, min_string); + } + else + real_from_string (&min_value, "0.0"); + + if (real_compare (LT_EXPR, real_value, &min_value)) + return 1; + if (real_compare (EQ_EXPR, real_value, &max_value)) + return 3; + real_arithmetic (&max_value, MINUS_EXPR, &max_value, &epsilon_value); + if (real_compare (GT_EXPR, real_value, &max_value)) + return 2; + return 0; +} + +/* Initialize from a decimal or hexadecimal string. */ + +void +fixed_from_string (FIXED_VALUE_TYPE *f, const char *str, tree type) +{ + REAL_VALUE_TYPE real_value, fixed_value, base_value; + char base_string[20]; + unsigned int fbit; + int temp; + + f->mode = TYPE_MODE (type); + fbit = TYPE_FBIT (type); + + sprintf (base_string, "0x1.0p%d", fbit); + real_from_string (&real_value, str); + temp = check_real_for_fixed_mode (&real_value, f->mode); + /* We don't want to warn the case when the _Fract value is 1.0. */ + if (temp == 1 || temp == 2 || (temp == 3 && ALL_ACCUM_MODE_P (f->mode))) + warning (OPT_Woverflow, + "large fixed-point constant implicitly truncated to fixed-point type"); + real_from_string (&base_value, base_string); + real_arithmetic (&fixed_value, MULT_EXPR, &real_value, &base_value); + real_to_integer2 (&f->data.low, &f->data.high, &fixed_value); + + if (temp == 3 && ALL_FRACT_MODE_P (f->mode)) + { + /* From the spec, we need to evaluate 1 to the maximal value. */ + f->data.low = -1; + f->data.high = -1; + f->data = double_int_ext (f->data, + GET_MODE_FBIT (f->mode) + + GET_MODE_IBIT (f->mode), 1); + } + else + f->data = double_int_ext (f->data, + SIGNED_FIXED_POINT_MODE_P (f->mode) + + GET_MODE_FBIT (f->mode) + + GET_MODE_IBIT (f->mode), + UNSIGNED_FIXED_POINT_MODE_P (f->mode)); +} + +/* Render F as a decimal floating point constant. */ + +void fixed_to_decimal (char *str, const FIXED_VALUE_TYPE *f_orig, + size_t buf_size) +{ + char base_string[20]; + REAL_VALUE_TYPE real_value, base_value, fixed_value; + + sprintf (base_string, "0x1.0p%d", GET_MODE_FBIT (f_orig->mode)); + real_from_string (&base_value, base_string); + real_from_integer (&real_value, VOIDmode, f_orig->data.low, f_orig->data.high, + UNSIGNED_FIXED_POINT_MODE_P (f_orig->mode)); + real_arithmetic (&fixed_value, RDIV_EXPR, &real_value, &base_value); + real_to_decimal (str, &fixed_value, buf_size, 0, 1); +} + +/* If SATP, saturate A to the maximum or the minimum, and save to *F based on + the machine mode MODE. + This function assumes the width of double_int is greater than the width + of the fixed-point value at the fixed-point mode. + Return true, if !SATP and overflow. */ + +static bool +fixed_saturate1 (unsigned int mode, double_int a, double_int *f, int satp) +{ + bool overflow = false; + int unsignedp = UNSIGNED_FIXED_POINT_MODE_P (mode); + int i_f_bits = GET_MODE_IBIT (mode) + GET_MODE_FBIT (mode); + + if (unsignedp) /* Unsigned type. */ + { + double_int max; + max.low = -1; + max.high = -1; + max = double_int_ext (max, i_f_bits, 1); + if (double_int_cmp (a, max, 1) == 1) + { + if (satp) + *f = max; + else + overflow = true; + } + } + else /* Signed type. */ + { + double_int max, min; + max.high = -1; + max.low = -1; + max = double_int_ext (max, i_f_bits, 1); + min.high = 0; + min.low = 1; + lshift_double (min.low, min.high, i_f_bits, + 2 * HOST_BITS_PER_WIDE_INT, + &min.low, &min.high, 1); + min = double_int_ext (min, 1 + i_f_bits, 0); + if (double_int_cmp (a, max, 0) == 1) + { + if (satp) + *f = max; + else + overflow = true; + } + else if (double_int_cmp (a, min, 0) == -1) + { + if (satp) + *f = min; + else + overflow = true; + } + } + return overflow; +} + +/* If SATP, saturate {A_HIGH, A_LOW} to the maximum or the minimum, and + save to *F based on the machine mode MODE. + This function assumes the width of two double_int is greater than the width + of the fixed-point value at the fixed-point mode. + Return true, if !SATP and overflow. */ + +static bool +fixed_saturate2 (unsigned int mode, double_int a_high, double_int a_low, + double_int *f, int satp) +{ + bool overflow = false; + int unsignedp = UNSIGNED_FIXED_POINT_MODE_P (mode); + int i_f_bits = GET_MODE_IBIT (mode) + GET_MODE_FBIT (mode); + + if (unsignedp) /* Unsigned type. */ + { + double_int max_r, max_s; + max_r.high = 0; + max_r.low = 0; + max_s.high = -1; + max_s.low = -1; + max_s = double_int_ext (max_s, i_f_bits, 1); + if (double_int_cmp (a_high, max_r, 1) == 1 + || (double_int_equal_p (a_high, max_r) && + double_int_cmp (a_low, max_s, 1) == 1)) + { + if (satp) + *f = max_s; + else + overflow = true; + } + } + else /* Signed type. */ + { + double_int max_r, max_s, min_r, min_s; + max_r.high = 0; + max_r.low = 0; + max_s.high = -1; + max_s.low = -1; + max_s = double_int_ext (max_s, i_f_bits, 1); + min_r.high = -1; + min_r.low = -1; + min_s.high = 0; + min_s.low = 1; + lshift_double (min_s.low, min_s.high, i_f_bits, + 2 * HOST_BITS_PER_WIDE_INT, + &min_s.low, &min_s.high, 1); + min_s = double_int_ext (min_s, 1 + i_f_bits, 0); + if (double_int_cmp (a_high, max_r, 0) == 1 + || (double_int_equal_p (a_high, max_r) && + double_int_cmp (a_low, max_s, 1) == 1)) + { + if (satp) + *f = max_s; + else + overflow = true; + } + else if (double_int_cmp (a_high, min_r, 0) == -1 + || (double_int_equal_p (a_high, min_r) && + double_int_cmp (a_low, min_s, 1) == -1)) + { + if (satp) + *f = min_s; + else + overflow = true; + } + } + return overflow; +} + +/* Return the sign bit based on I_F_BITS. */ + +inline int get_fixed_sign_bit (double_int a, int i_f_bits) +{ + if (i_f_bits < HOST_BITS_PER_WIDE_INT) + return (a.low >> i_f_bits) & 1; + else + return (a.high >> (i_f_bits - HOST_BITS_PER_WIDE_INT)) & 1; +} + +/* Calculate F = A + (SUBTRACT_P ? -B : B). + If SATP, saturate the result to the max or the min. + Return true, if !SATP and overflow. */ + +static bool +do_fixed_add (FIXED_VALUE_TYPE *f, const FIXED_VALUE_TYPE *a, + const FIXED_VALUE_TYPE *b, int subtract_p, int satp) +{ + bool overflow = false; + double_int temp = subtract_p ? double_int_neg (b->data) : b->data; + int unsignedp = UNSIGNED_FIXED_POINT_MODE_P (a->mode); + int i_f_bits = GET_MODE_IBIT (a->mode) + GET_MODE_FBIT (a->mode); + f->mode = a->mode; + f->data = double_int_add (a->data, temp); + if (unsignedp) /* Unsigned type. */ + { + if (subtract_p) /* Unsigned subtraction. */ + { + if (double_int_cmp (a->data, b->data, 1) == -1) + { + if (satp) + { + f->data.high = 0; + f->data.low = 0; + } + else + overflow = true; + } + } + else /* Unsigned addition. */ + { + f->data = double_int_ext (f->data, i_f_bits, 1); + if (double_int_cmp (f->data, a->data, 1) == -1 + || double_int_cmp (f->data, b->data, 1) == -1) + { + if (satp) + { + f->data.high = -1; + f->data.low = -1; + } + else + overflow = true; + } + } + } + else /* Signed type. */ + { + if (((!subtract_p) + && get_fixed_sign_bit (a->data, i_f_bits) + == get_fixed_sign_bit (b->data, i_f_bits) + && get_fixed_sign_bit (a->data, i_f_bits) + != get_fixed_sign_bit (f->data, i_f_bits)) + || (subtract_p + && get_fixed_sign_bit (a->data, i_f_bits) + != get_fixed_sign_bit (b->data, i_f_bits) + && get_fixed_sign_bit (a->data, i_f_bits) + != get_fixed_sign_bit (f->data, i_f_bits))) + { + if (satp) + { + f->data.low = 1; + f->data.high = 0; + lshift_double (f->data.low, f->data.high, i_f_bits, + 2 * HOST_BITS_PER_WIDE_INT, + &f->data.low, &f->data.high, 1); + if (get_fixed_sign_bit (a->data, i_f_bits) == 0) + { + double_int one; + one.low = 1; + one.high = 0; + f->data = double_int_add (f->data, double_int_neg (one)); + } + } + else + overflow = true; + } + } + f->data = double_int_ext (f->data, (!unsignedp) + i_f_bits, unsignedp); + return overflow; +} + +/* Calculate F = A * B. + If SATP, saturate the result to the max or the min. + Return true, if !SATP and overflow. */ + +static bool +do_fixed_multiply (FIXED_VALUE_TYPE *f, const FIXED_VALUE_TYPE *a, + const FIXED_VALUE_TYPE *b, int satp) +{ + bool overflow = false; + int unsignedp = UNSIGNED_FIXED_POINT_MODE_P (a->mode); + int i_f_bits = GET_MODE_IBIT (a->mode) + GET_MODE_FBIT (a->mode); + f->mode = a->mode; + if (GET_MODE_PRECISION (f->mode) <= HOST_BITS_PER_WIDE_INT) + { + f->data = double_int_mul (a->data, b->data); + lshift_double (f->data.low, f->data.high, + (-GET_MODE_FBIT (f->mode)), + 2 * HOST_BITS_PER_WIDE_INT, + &f->data.low, &f->data.high, !unsignedp); + overflow = fixed_saturate1 (f->mode, f->data, &f->data, satp); + } + else + { + /* The result of multiplication expands to two double_int. */ + double_int a_high, a_low, b_high, b_low; + double_int high_high, high_low, low_high, low_low; + double_int r, s, temp1, temp2; + int carry = 0; + + /* Decompose a and b to four double_int. */ + a_high.low = a->data.high; + a_high.high = 0; + a_low.low = a->data.low; + a_low.high = 0; + b_high.low = b->data.high; + b_high.high = 0; + b_low.low = b->data.low; + b_low.high = 0; + + /* Perform four multiplications. */ + low_low = double_int_mul (a_low, b_low); + low_high = double_int_mul (a_low, b_high); + high_low = double_int_mul (a_high, b_low); + high_high = double_int_mul (a_high, b_high); + + /* Accumulate four results to {r, s}. */ + temp1.high = high_low.low; + temp1.low = 0; + s = double_int_add (low_low, temp1); + if (double_int_cmp (s, low_low, 1) == -1 + || double_int_cmp (s, temp1, 1) == -1) + carry ++; /* Carry */ + temp1.high = s.high; + temp1.low = s.low; + temp2.high = low_high.low; + temp2.low = 0; + s = double_int_add (temp1, temp2); + if (double_int_cmp (s, temp1, 1) == -1 + || double_int_cmp (s, temp2, 1) == -1) + carry ++; /* Carry */ + + temp1.low = high_low.high; + temp1.high = 0; + r = double_int_add (high_high, temp1); + temp1.low = low_high.high; + temp1.high = 0; + r = double_int_add (r, temp1); + temp1.low = carry; + temp1.high = 0; + r = double_int_add (r, temp1); + + /* We need to add neg(b) to r, if a < 0. */ + if (!unsignedp && a->data.high < 0) + r = double_int_add (r, double_int_neg (b->data)); + /* We need to add neg(a) to r, if b < 0. */ + if (!unsignedp && b->data.high < 0) + r = double_int_add (r, double_int_neg (a->data)); + + /* Shift right the result by FBIT. */ + if (GET_MODE_FBIT (f->mode) == 2 * HOST_BITS_PER_WIDE_INT) + { + s.low = r.low; + s.high = r.high; + if (unsignedp) + { + r.low = 0; + r.high = 0; + } + else + { + r.low = -1; + r.high = -1; + } + f->data.low = s.low; + f->data.high = s.high; + } + else + { + lshift_double (s.low, s.high, + (-GET_MODE_FBIT (f->mode)), + 2 * HOST_BITS_PER_WIDE_INT, + &s.low, &s.high, 0); + lshift_double (r.low, r.high, + (2 * HOST_BITS_PER_WIDE_INT - GET_MODE_FBIT (f->mode)), + 2 * HOST_BITS_PER_WIDE_INT, + &f->data.low, &f->data.high, 0); + f->data.low = f->data.low | s.low; + f->data.high = f->data.high | s.high; + s.low = f->data.low; + s.high = f->data.high; + lshift_double (r.low, r.high, + (-GET_MODE_FBIT (f->mode)), + 2 * HOST_BITS_PER_WIDE_INT, + &r.low, &r.high, !unsignedp); + } + + overflow = fixed_saturate2 (f->mode, r, s, &f->data, satp); + } + + f->data = double_int_ext (f->data, (!unsignedp) + i_f_bits, unsignedp); + return false; +} + +/* Calculate F = A / B. + If SATP, saturate the result to the max or the min. + Return true, if !SATP and overflow. */ + +static bool +do_fixed_divide (FIXED_VALUE_TYPE *f, const FIXED_VALUE_TYPE *a, + const FIXED_VALUE_TYPE *b, int satp) +{ + bool overflow = false; + int unsignedp = UNSIGNED_FIXED_POINT_MODE_P (a->mode); + int i_f_bits = GET_MODE_IBIT (a->mode) + GET_MODE_FBIT (a->mode); + f->mode = a->mode; + if (GET_MODE_PRECISION (f->mode) <= HOST_BITS_PER_WIDE_INT) + { + lshift_double (a->data.low, a->data.high, + GET_MODE_FBIT (f->mode), + 2 * HOST_BITS_PER_WIDE_INT, + &f->data.low, &f->data.high, !unsignedp); + f->data = double_int_div (f->data, b->data, unsignedp, TRUNC_DIV_EXPR); + overflow = fixed_saturate1 (f->mode, f->data, &f->data, satp); + } + else + { + double_int pos_a, pos_b, r, s; + double_int quo_r, quo_s, mod, temp; + int num_of_neg = 0; + int i; + + /* If a < 0, negate a. */ + if (!unsignedp && a->data.high < 0) + { + pos_a = double_int_neg (a->data); + num_of_neg ++; + } + else + pos_a = a->data; + + /* If b < 0, negate b. */ + if (!unsignedp && b->data.high < 0) + { + pos_b = double_int_neg (b->data); + num_of_neg ++; + } + else + pos_b = b->data; + + /* Left shift pos_a to {r, s} by FBIT. */ + if (GET_MODE_FBIT (f->mode) == 2 * HOST_BITS_PER_WIDE_INT) + { + r = pos_a; + s.high = 0; + s.low = 0; + } + else + { + lshift_double (pos_a.low, pos_a.high, + GET_MODE_FBIT (f->mode), + 2 * HOST_BITS_PER_WIDE_INT, + &s.low, &s.high, 0); + lshift_double (pos_a.low, pos_a.high, + - (2 * HOST_BITS_PER_WIDE_INT - GET_MODE_FBIT (f->mode)), + 2 * HOST_BITS_PER_WIDE_INT, + &r.low, &r.high, 0); + } + + /* Divide r by pos_b to quo_r. The remanider is in mod. */ + div_and_round_double (TRUNC_DIV_EXPR, 1, r.low, r.high, pos_b.low, + pos_b.high, &quo_r.low, &quo_r.high, &mod.low, + &mod.high); + + quo_s.high = 0; + quo_s.low = 0; + + for (i = 0; i < 2 * HOST_BITS_PER_WIDE_INT; i++) + { + /* Record the leftmost bit of mod. */ + int leftmost_mod = (mod.high < 0); + + /* Shift left mod by 1 bit. */ + lshift_double (mod.low, mod.high, 1, 2 * HOST_BITS_PER_WIDE_INT, + &mod.low, &mod.high, 0); + + /* Test the leftmost bit of s to add to mod. */ + if (s.high < 0) + mod.low += 1; + + /* Shift left quo_s by 1 bit. */ + lshift_double (quo_s.low, quo_s.high, 1, 2 * HOST_BITS_PER_WIDE_INT, + &quo_s.low, &quo_s.high, 0); + + /* Try to calculate (mod - pos_b). */ + temp = double_int_add (mod, double_int_neg (pos_b)); + + if (leftmost_mod == 1 || double_int_cmp (mod, pos_b, 1) != -1) + { + quo_s.low += 1; + mod = temp; + } + + /* Shift left s by 1 bit. */ + lshift_double (s.low, s.high, 1, 2 * HOST_BITS_PER_WIDE_INT, + &s.low, &s.high, 0); + + } + + if (num_of_neg == 1) + { + quo_s = double_int_neg (quo_s); + if (quo_s.high == 0 && quo_s.low == 0) + quo_r = double_int_neg (quo_r); + else + { + quo_r.low = ~quo_r.low; + quo_r.high = ~quo_r.high; + } + } + + f->data = quo_s; + overflow = fixed_saturate2 (f->mode, quo_r, quo_s, &f->data, satp); + } + + f->data = double_int_ext (f->data, (!unsignedp) + i_f_bits, unsignedp); + return overflow; +} + +/* Calculate F = A << B if LEFT_P. Otherwies, F = A >> B. + If SATP, saturate the result to the max or the min. + Return true, if !SATP and overflow. */ + +static bool +do_fixed_shift (FIXED_VALUE_TYPE *f, const FIXED_VALUE_TYPE *a, + const FIXED_VALUE_TYPE *b, int left_p, int satp) +{ + bool overflow = false; + int unsignedp = UNSIGNED_FIXED_POINT_MODE_P (a->mode); + int i_f_bits = GET_MODE_IBIT (a->mode) + GET_MODE_FBIT (a->mode); + f->mode = a->mode; + + if (b->data.low == 0) + { + f->data = a->data; + return overflow; + } + + if (GET_MODE_PRECISION (f->mode) <= HOST_BITS_PER_WIDE_INT || (!left_p)) + { + lshift_double (a->data.low, a->data.high, + left_p ? b->data.low : (-b->data.low), + 2 * HOST_BITS_PER_WIDE_INT, + &f->data.low, &f->data.high, !unsignedp); + if (left_p) /* Only left shift saturates. */ + overflow = fixed_saturate1 (f->mode, f->data, &f->data, satp); + } + else /* We need two double_int to store the left-shift result. */ + { + double_int temp_high, temp_low; + if (b->data.low == 2 * HOST_BITS_PER_WIDE_INT) + { + temp_high = a->data; + temp_low.high = 0; + temp_low.low = 0; + } + else + { + lshift_double (a->data.low, a->data.high, + b->data.low, + 2 * HOST_BITS_PER_WIDE_INT, + &temp_low.low, &temp_low.high, !unsignedp); + /* Logical shift right to temp_high. */ + lshift_double (a->data.low, a->data.high, + b->data.low - 2 * HOST_BITS_PER_WIDE_INT, + 2 * HOST_BITS_PER_WIDE_INT, + &temp_high.low, &temp_high.high, 0); + } + if (!unsignedp && a->data.high < 0) /* Signed-extend temp_high. */ + temp_high = double_int_ext (temp_high, b->data.low, unsignedp); + f->data = temp_low; + overflow = fixed_saturate2 (f->mode, temp_high, temp_low, &f->data, satp); + } + f->data = double_int_ext (f->data, (!unsignedp) + i_f_bits, unsignedp); + return overflow; +} + +/* Calculate F = -A. + If SATP, saturate the result to the max or the min. + Return true, if !SATP and overflow. */ + +static bool +do_fixed_neg (FIXED_VALUE_TYPE *f, const FIXED_VALUE_TYPE *a, int satp) +{ + bool overflow = false; + int unsignedp = UNSIGNED_FIXED_POINT_MODE_P (a->mode); + int i_f_bits = GET_MODE_IBIT (a->mode) + GET_MODE_FBIT (a->mode); + f->mode = a->mode; + f->data = double_int_neg (a->data); + f->data = double_int_ext (f->data, (!unsignedp) + i_f_bits, unsignedp); + + if (unsignedp) /* Unsigned type. */ + { + if (f->data.low != 0 || f->data.high != 0) + { + if (satp) + { + f->data.low = 0; + f->data.high = 0; + } + else + overflow = true; + } + } + else /* Signed type. */ + { + if (!(f->data.high == 0 && f->data.low == 0) + && f->data.high == a->data.high && f->data.low == a->data.low ) + { + if (satp) + { + /* Saturate to the maximum by subtracting f->data by one. */ + f->data.low = -1; + f->data.high = -1; + f->data = double_int_ext (f->data, i_f_bits, 1); + } + else + overflow = true; + } + } + return overflow; +} + +/* Perform the binary or unary operation described by CODE. + For a unary operation, leave OP1 NULL. + Return true, if !SATP and overflow. */ + +bool +fixed_arithmetic (FIXED_VALUE_TYPE *f, int icode, const FIXED_VALUE_TYPE *op0, + const FIXED_VALUE_TYPE *op1, int satp) +{ + switch (icode) + { + case NEGATE_EXPR: + return do_fixed_neg (f, op0, satp); + break; + + case PLUS_EXPR: + return do_fixed_add (f, op0, op1, 0, satp); + break; + + case MINUS_EXPR: + return do_fixed_add (f, op0, op1, 1, satp); + break; + + case MULT_EXPR: + return do_fixed_multiply (f, op0, op1, satp); + break; + + case TRUNC_DIV_EXPR: + return do_fixed_divide (f, op0, op1, satp); + break; + + case LSHIFT_EXPR: + return do_fixed_shift (f, op0, op1, 1, satp); + break; + + case RSHIFT_EXPR: + return do_fixed_shift (f, op0, op1, 0, satp); + break; + + default: + gcc_unreachable (); + } + return false; +} + +/* Compare fixed-point values by tree_code. */ + +bool +fixed_compare (int icode, const FIXED_VALUE_TYPE *op0, + const FIXED_VALUE_TYPE *op1) +{ + enum tree_code code = icode; + + switch (code) + { + case NE_EXPR: + return op0->mode != op1->mode + || !double_int_equal_p (op0->data, op1->data); + + case EQ_EXPR: + return op0->mode == op1->mode + && double_int_equal_p (op0->data, op1->data); + + case LT_EXPR: + return op0->mode == op1->mode + && double_int_cmp (op0->data, op1->data, + UNSIGNED_FIXED_POINT_MODE_P (op0->mode)) == -1; + + case LE_EXPR: + return op0->mode == op1->mode + && double_int_cmp (op0->data, op1->data, + UNSIGNED_FIXED_POINT_MODE_P (op0->mode)) != 1; + + case GT_EXPR: + return op0->mode == op1->mode + && double_int_cmp (op0->data, op1->data, + UNSIGNED_FIXED_POINT_MODE_P (op0->mode)) == 1; + + case GE_EXPR: + return op0->mode == op1->mode + && double_int_cmp (op0->data, op1->data, + UNSIGNED_FIXED_POINT_MODE_P (op0->mode)) != -1; + + default: + gcc_unreachable (); + } +} + +/* Extend or truncate to a new mode. + If SATP, saturate the result to the max or the min. + Return true, if !SATP and overflow. */ + +bool +fixed_convert (FIXED_VALUE_TYPE *f, enum machine_mode mode, + const FIXED_VALUE_TYPE *a, int satp) +{ + bool overflow = false; + if (mode == a->mode) + { + *f = *a; + return overflow; + } + + if (GET_MODE_FBIT (mode) > GET_MODE_FBIT (a->mode)) + { + /* Left shift a to temp_high, temp_low based on a->mode. */ + double_int temp_high, temp_low; + int amount = GET_MODE_FBIT (mode) - GET_MODE_FBIT (a->mode); + lshift_double (a->data.low, a->data.high, + amount, + 2 * HOST_BITS_PER_WIDE_INT, + &temp_low.low, &temp_low.high, + SIGNED_FIXED_POINT_MODE_P (a->mode)); + /* Logical shift right to temp_high. */ + lshift_double (a->data.low, a->data.high, + amount - 2 * HOST_BITS_PER_WIDE_INT, + 2 * HOST_BITS_PER_WIDE_INT, + &temp_high.low, &temp_high.high, 0); + if (SIGNED_FIXED_POINT_MODE_P (a->mode) + && a->data.high < 0) /* Signed-extend temp_high. */ + temp_high = double_int_ext (temp_high, amount, 0); + f->mode = mode; + f->data = temp_low; + if (SIGNED_FIXED_POINT_MODE_P (a->mode) == + SIGNED_FIXED_POINT_MODE_P (f->mode)) + overflow = fixed_saturate2 (f->mode, temp_high, temp_low, &f->data, + satp); + else + { + /* Take care of the cases when converting between signed and + unsigned. */ + if (SIGNED_FIXED_POINT_MODE_P (a->mode)) + { + /* Signed -> Unsigned. */ + if (a->data.high < 0) + { + if (satp) + { + f->data.low = 0; /* Set to zero. */ + f->data.high = 0; /* Set to zero. */ + } + else + overflow = true; + } + else + overflow = fixed_saturate2 (f->mode, temp_high, temp_low, + &f->data, satp); + } + else + { + /* Unsigned -> Signed. */ + if (temp_high.high < 0) + { + if (satp) + { + /* Set to maximum. */ + f->data.low = -1; /* Set to all ones. */ + f->data.high = -1; /* Set to all ones. */ + f->data = double_int_ext (f->data, + GET_MODE_FBIT (f->mode) + + GET_MODE_IBIT (f->mode), + 1); /* Clear the sign. */ + } + else + overflow = true; + } + else + overflow = fixed_saturate2 (f->mode, temp_high, temp_low, + &f->data, satp); + } + } + } + else + { + /* Right shift a to temp based on a->mode. */ + double_int temp; + lshift_double (a->data.low, a->data.high, + GET_MODE_FBIT (mode) - GET_MODE_FBIT (a->mode), + 2 * HOST_BITS_PER_WIDE_INT, + &temp.low, &temp.high, + SIGNED_FIXED_POINT_MODE_P (a->mode)); + f->mode = mode; + f->data = temp; + if (SIGNED_FIXED_POINT_MODE_P (a->mode) == + SIGNED_FIXED_POINT_MODE_P (f->mode)) + overflow = fixed_saturate1 (f->mode, f->data, &f->data, satp); + else + { + /* Take care of the cases when converting between signed and + unsigned. */ + if (SIGNED_FIXED_POINT_MODE_P (a->mode)) + { + /* Signed -> Unsigned. */ + if (a->data.high < 0) + { + if (satp) + { + f->data.low = 0; /* Set to zero. */ + f->data.high = 0; /* Set to zero. */ + } + else + overflow = true; + } + else + overflow = fixed_saturate1 (f->mode, f->data, &f->data, satp); + } + else + { + /* Unsigned -> Signed. */ + if (temp.high < 0) + { + if (satp) + { + /* Set to maximum. */ + f->data.low = -1; /* Set to all ones. */ + f->data.high = -1; /* Set to all ones. */ + f->data = double_int_ext (f->data, + GET_MODE_FBIT (f->mode) + + GET_MODE_IBIT (f->mode), + 1); /* Clear the sign. */ + } + else + overflow = true; + } + else + overflow = fixed_saturate1 (f->mode, f->data, &f->data, satp); + } + } + } + + f->data = double_int_ext (f->data, + SIGNED_FIXED_POINT_MODE_P (f->mode) + + GET_MODE_FBIT (f->mode) + + GET_MODE_IBIT (f->mode), + UNSIGNED_FIXED_POINT_MODE_P (f->mode)); + return overflow; +} + +/* Convert to a new fixed-point mode from an integer. + If UNSIGNEDP, this integer is unsigned. + If SATP, saturate the result to the max or the min. + Return true, if !SATP and overflow. */ + +bool +fixed_convert_from_int (FIXED_VALUE_TYPE *f, enum machine_mode mode, + double_int a, int unsignedp, int satp) +{ + bool overflow = false; + /* Left shift a to temp_high, temp_low. */ + double_int temp_high, temp_low; + int amount = GET_MODE_FBIT (mode); + if (amount == 2 * HOST_BITS_PER_WIDE_INT) + { + temp_high = a; + temp_low.low = 0; + temp_low.high = 0; + } + else + { + lshift_double (a.low, a.high, + amount, + 2 * HOST_BITS_PER_WIDE_INT, + &temp_low.low, &temp_low.high, 0); + + /* Logical shift right to temp_high. */ + lshift_double (a.low, a.high, + amount - 2 * HOST_BITS_PER_WIDE_INT, + 2 * HOST_BITS_PER_WIDE_INT, + &temp_high.low, &temp_high.high, 0); + } + if (!unsignedp && a.high < 0) /* Signed-extend temp_high. */ + temp_high = double_int_ext (temp_high, amount, 0); + + f->mode = mode; + f->data = temp_low; + + if (unsignedp == UNSIGNED_FIXED_POINT_MODE_P (f->mode)) + overflow = fixed_saturate2 (f->mode, temp_high, temp_low, &f->data, satp); + else + { + /* Take care of the cases when converting between signed and unsigned. */ + if (!unsignedp) + { + /* Signed -> Unsigned. */ + if (a.high < 0) + { + if (satp) + { + f->data.low = 0; /* Set to zero. */ + f->data.high = 0; /* Set to zero. */ + } + else + overflow = true; + } + else + overflow = fixed_saturate2 (f->mode, temp_high, temp_low, &f->data, + satp); + } + else + { + /* Unsigned -> Signed. */ + if (temp_high.high < 0) + { + if (satp) + { + /* Set to maximum. */ + f->data.low = -1; /* Set to all ones. */ + f->data.high = -1; /* Set to all ones. */ + f->data = double_int_ext (f->data, + GET_MODE_FBIT (f->mode) + + GET_MODE_IBIT (f->mode), + 1); /* Clear the sign. */ + } + else + overflow = true; + } + else + overflow = fixed_saturate2 (f->mode, temp_high, temp_low, + &f->data, satp); + } + } + f->data = double_int_ext (f->data, + SIGNED_FIXED_POINT_MODE_P (f->mode) + + GET_MODE_FBIT (f->mode) + + GET_MODE_IBIT (f->mode), + UNSIGNED_FIXED_POINT_MODE_P (f->mode)); + return overflow; +} + +/* Convert to a new fixed-point mode from a real. + If SATP, saturate the result to the max or the min. + Return true, if !SATP and overflow. */ + +bool +fixed_convert_from_real (FIXED_VALUE_TYPE *f, enum machine_mode mode, + const REAL_VALUE_TYPE *a, int satp) +{ + bool overflow = false; + REAL_VALUE_TYPE real_value, fixed_value, base_value; + char base_string[20]; + int unsignedp = UNSIGNED_FIXED_POINT_MODE_P (mode); + int i_f_bits = GET_MODE_IBIT (mode) + GET_MODE_FBIT (mode); + unsigned int fbit = GET_MODE_FBIT (mode); + int temp; + + real_value = *a; + f->mode = mode; + sprintf (base_string, "0x1.0p%d", fbit); + real_from_string (&base_value, base_string); + real_arithmetic (&fixed_value, MULT_EXPR, &real_value, &base_value); + real_to_integer2 (&f->data.low, &f->data.high, &fixed_value); + temp = check_real_for_fixed_mode (&real_value, mode); + if (temp == 1) /* Minimum. */ + { + if (satp) + { + if (unsignedp) + { + f->data.low = 0; + f->data.high = 0; + } + else + { + f->data.low = 1; + f->data.high = 0; + lshift_double (f->data.low, f->data.high, i_f_bits, + 2 * HOST_BITS_PER_WIDE_INT, + &f->data.low, &f->data.high, 1); + f->data = double_int_ext (f->data, 1 + i_f_bits, 0); + } + } + else + overflow = true; + } + else if (temp == 2 || temp == 3) /* Maximum. */ + { + if (satp) + { + f->data.low = -1; + f->data.high = -1; + f->data = double_int_ext (f->data, i_f_bits, 1); + } + else + overflow = true; + } + f->data = double_int_ext (f->data, (!unsignedp) + i_f_bits, unsignedp); + return overflow; +} + +/* Convert to a new real mode from a fixed-point. */ + +void +real_convert_from_fixed (REAL_VALUE_TYPE *r, enum machine_mode mode, + const FIXED_VALUE_TYPE *f) +{ + char base_string[20]; + REAL_VALUE_TYPE base_value, fixed_value, real_value; + + sprintf (base_string, "0x1.0p%d", GET_MODE_FBIT (f->mode)); + real_from_string (&base_value, base_string); + real_from_integer (&fixed_value, VOIDmode, f->data.low, f->data.high, + UNSIGNED_FIXED_POINT_MODE_P (f->mode)); + real_arithmetic (&real_value, RDIV_EXPR, &fixed_value, &base_value); + real_convert (r, mode, &real_value); +} + +/* Determine whether a fixed-point value F is negative. */ + +bool +fixed_isneg (const FIXED_VALUE_TYPE *f) +{ + if (SIGNED_FIXED_POINT_MODE_P (f->mode)) + { + int i_f_bits = GET_MODE_IBIT (f->mode) + GET_MODE_FBIT (f->mode); + int sign_bit = get_fixed_sign_bit (f->data, i_f_bits); + if (sign_bit == 1) + return true; + } + + return false; +} Index: doc/extend.texi =================================================================== --- doc/extend.texi (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/doc/extend.texi) (revision 125345) +++ doc/extend.texi (.../doc/extend.texi) (working copy) @@ -35,6 +35,7 @@ * Complex:: Data types for complex numbers. * Decimal Float:: Decimal Floating Types. * Hex Floats:: Hexadecimal floating-point constants. +* Fixed-Point:: Fixed-Point Types. * Zero Length:: Zero-length arrays. * Variable Length:: Arrays whose length is computed at run time. * Empty Structures:: Structures with no members. @@ -890,6 +891,134 @@ could mean @code{1.0f} or @code{1.9375} since @samp{f} is also the extension for floating-point constants of type @code{float}. +@node Fixed-Point +@section Fixed-Point Types +@cindex fixed-point types +@cindex @code{_Fract} data type +@cindex @code{_Accum} data type +@cindex @code{_Sat} data type +@cindex @code{hr} fixed-suffix +@cindex @code{r} fixed-suffix +@cindex @code{lr} fixed-suffix +@cindex @code{llr} fixed-suffix +@cindex @code{uhr} fixed-suffix +@cindex @code{ur} fixed-suffix +@cindex @code{ulr} fixed-suffix +@cindex @code{ullr} fixed-suffix +@cindex @code{hk} fixed-suffix +@cindex @code{k} fixed-suffix +@cindex @code{lk} fixed-suffix +@cindex @code{llk} fixed-suffix +@cindex @code{uhk} fixed-suffix +@cindex @code{uk} fixed-suffix +@cindex @code{ulk} fixed-suffix +@cindex @code{ullk} fixed-suffix +@cindex @code{HR} fixed-suffix +@cindex @code{R} fixed-suffix +@cindex @code{LR} fixed-suffix +@cindex @code{LLR} fixed-suffix +@cindex @code{UHR} fixed-suffix +@cindex @code{UR} fixed-suffix +@cindex @code{ULR} fixed-suffix +@cindex @code{ULLR} fixed-suffix +@cindex @code{HK} fixed-suffix +@cindex @code{K} fixed-suffix +@cindex @code{LK} fixed-suffix +@cindex @code{LLK} fixed-suffix +@cindex @code{UHK} fixed-suffix +@cindex @code{UK} fixed-suffix +@cindex @code{ULK} fixed-suffix +@cindex @code{ULLK} fixed-suffix + +As an extension, the GNU C compiler supports fixed-point types as +defined in the N1169 draft of ISO/IEC DTR 18037. Support for fixed-point +types in GCC will evolve as the draft technical report changes. +Calling conventions for any target might also change. Not all targets +support fixed-point types. + +The fixed-point types are +@code{short _Fract}, +@code{_Fract}, +@code{long _Fract}, +@code{long long _Fract}, +@code{unsigned short _Fract}, +@code{unsigned _Fract}, +@code{unsigned long _Fract}, +@code{unsigned long long _Fract}, +@code{_Sat short _Fract}, +@code{_Sat _Fract}, +@code{_Sat long _Fract}, +@code{_Sat long long _Fract}, +@code{_Sat unsigned short _Fract}, +@code{_Sat unsigned _Fract}, +@code{_Sat unsigned long _Fract}, +@code{_Sat unsigned long long _Fract}, +@code{short _Accum}, +@code{_Accum}, +@code{long _Accum}, +@code{long long _Accum}, +@code{unsigned short _Accum}, +@code{unsigned _Accum}, +@code{unsigned long _Accum}, +@code{unsigned long long _Accum}, +@code{_Sat short _Accum}, +@code{_Sat _Accum}, +@code{_Sat long _Accum}, +@code{_Sat long long _Accum}, +@code{_Sat unsigned short _Accum}, +@code{_Sat unsigned _Accum}, +@code{_Sat unsigned long _Accum}, +@code{_Sat unsigned long long _Accum}. +Fixed-point data values contain fractional and optional integral parts. +The format of fixed-point data varies and depends on the target machine. + +Support for fixed-point types includes prefix and postfix increment +and decrement operators (@code{++}, @code{--}); unary arithmetic operators +(@code{+}, @code{-}, @code{!}); binary arithmetic operators (@code{+}, +@code{-}, @code{*}, @code{/}); binary shift operators (@code{<<}, @code{>>}); +relational operators (@code{<}, @code{<=}, @code{>=}, @code{>}); +equality operators (@code{==}, @code{!=}); assignment operators +(@code{+=}, @code{-=}, @code{*=}, @code{/=}, @code{<<=}, @code{>>=}); +and conversions to and from integer, floating-point, or fixed-point types. + +Use a suffix @samp{hr} or @samp{HR} in a literal constant of type +@code{short _Fract} and @code{_Sat short _Fract}, +@samp{r} or @samp{R} for @code{_Fract} and @code{_Sat _Fract}, +@samp{lr} or @samp{LR} for @code{long _Fract} and @code{_Sat long _Fract}, +@samp{llr} or @samp{LLR} for @code{long long _Fract} and +@code{_Sat long long _Fract}, +@samp{uhr} or @samp{UHR} for @code{unsigned short _Fract} and +@code{_Sat unsigned short _Fract}, +@samp{ur} or @samp{UR} for @code{unsigned _Fract} and +@code{_Sat unsigned _Fract}, +@samp{ulr} or @samp{ULR} for @code{unsigned long _Fract} and +@code{_Sat unsigned long _Fract}, +@samp{ullr} or @samp{ULLR} for @code{unsigned long long _Fract} +and @code{_Sat unsigned long long _Fract}, +@samp{hk} or @samp{HK} for @code{short _Accum} and @code{_Sat short _Accum}, +@samp{k} or @samp{K} for @code{_Accum} and @code{_Sat _Accum}, +@samp{lk} or @samp{LK} for @code{long _Accum} and @code{_Sat long _Accum}, +@samp{llk} or @samp{LLK} for @code{long long _Accum} and +@code{_Sat long long _Accum}, +@samp{uhk} or @samp{UHK} for @code{unsigned short _Accum} and +@code{_Sat unsigned short _Accum}, +@samp{uk} or @samp{UK} for @code{unsigned _Accum} and +@code{_Sat unsigned _Accum}, +@samp{ulk} or @samp{ULK} for @code{unsigned long _Accum} and +@code{_Sat unsigned long _Accum}, +and @samp{ullk} or @samp{ULLK} for @code{unsigned long long _Accum} +and @code{_Sat unsigned long long _Accum}. + +GCC support of fixed-point types as specified by the draft technical report +is incomplete: + +@itemize @bullet +@item +Pragmas to control overflow and rounding behaviors are not implemented. +@end itemize + +Fixed-point types are supported by the DWARF2 debug information format. + @node Zero Length @section Arrays of Length Zero @cindex arrays of length zero Index: doc/rtl.texi =================================================================== --- doc/rtl.texi (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/doc/rtl.texi) (revision 125345) +++ doc/rtl.texi (.../doc/rtl.texi) (working copy) @@ -1135,6 +1135,96 @@ all 128 of whose bits are meaningful. One common use is the IEEE quad-precision format. +@findex QQmode +@item QQmode +``Quarter-Fractional'' mode represents a single byte treated as a signed +fractional number. The default format is ``s.7''. + +@findex HQmode +@item HQmode +``Half-Fractional'' mode represents a two-byte signed fractional number. +The default format is ``s.15''. + +@findex SQmode +@item SQmode +``Single Fractional'' mode represents a four-byte signed fractional number. +The default format is ``s.31''. + +@findex DQmode +@item DQmode +``Double Fractional'' mode represents an eight-byte signed fractional number. +The default format is ``s.63''. + +@findex TQmode +@item TQmode +``Tetra Fractional'' mode represents a sixteen-byte signed fractional number. +The default format is ``s.127''. + +@findex UQQmode +@item UQQmode +``Unsigned Quarter-Fractional'' mode represents a single byte treated as an +unsigned fractional number. The default format is ``.8''. + +@findex UHQmode +@item UHQmode +``Unsigned Half-Fractional'' mode represents a two-byte unsigned fractional +number. The default format is ``.16''. + +@findex USQmode +@item USQmode +``Unsigned Single Fractional'' mode represents a four-byte unsigned fractional +number. The default format is ``.32''. + +@findex UDQmode +@item UDQmode +``Unsigned Double Fractional'' mode represents an eight-byte unsigned +fractional number. The default format is ``.64''. + +@findex UTQmode +@item UTQmode +``Unsigned Tetra Fractional'' mode represents a sixteen-byte unsigned +fractional number. The default format is ``.128''. + +@findex HAmode +@item HAmode +``Half-Accumulator'' mode represents a two-byte signed accumulator. +The default format is ``s8.7''. + +@findex SAmode +@item SAmode +``Single Accumulator'' mode represents a four-byte signed accumulator. +The default format is ``s16.15''. + +@findex DAmode +@item DAmode +``Double Accumulator'' mode represents an eight-byte signed accumulator. +The default format is ``s32.31''. + +@findex TAmode +@item TAmode +``Tetra Accumulator'' mode represents a sixteen-byte signed accumulator. +The default format is ``s64.63''. + +@findex UHAmode +@item UHAmode +``Unsigned Half-Accumulator'' mode represents a two-byte unsigned accumulator. +The default format is ``8.8''. + +@findex USAmode +@item USAmode +``Unsigned Single Accumulator'' mode represents a four-byte unsigned +accumulator. The default format is ``16.16''. + +@findex UDAmode +@item UDAmode +``Unsigned Double Accumulator'' mode represents an eight-byte unsigned +accumulator. The default format is ``32.32''. + +@findex UTAmode +@item UTAmode +``Unsigned Tetra Accumulator'' mode represents a sixteen-byte unsigned +accumulator. The default format is ``64.64''. + @findex CCmode @item CCmode ``Condition Code'' mode represents the value of a condition code, which @@ -1226,6 +1316,26 @@ Decimal floating point modes. By default these are @code{SDmode}, @code{DDmode} and @code{TDmode}. +@findex MODE_FRACT +@item MODE_FRACT +Signed fractional modes. By default these are @code{QQmode}, @code{HQmode}, +@code{SQmode}, @code{DQmode} and @code{TQmode}. + +@findex MODE_UFRACT +@item MODE_UFRACT +Unsigned fractional modes. By default these are @code{UQQmode}, @code{UHQmode}, +@code{USQmode}, @code{UDQmode} and @code{UTQmode}. + +@findex MODE_ACCUM +@item MODE_ACCUM +Signed accumulator modes. By default these are @code{HAmode}, +@code{SAmode}, @code{DAmode} and @code{TAmode}. + +@findex MODE_UACCUM +@item MODE_UACCUM +Unsigned accumulator modes. By default these are @code{UHAmode}, +@code{USAmode}, @code{UDAmode} and @code{UTAmode}. + @findex MODE_COMPLEX_INT @item MODE_COMPLEX_INT Complex integer modes. (These are not currently implemented). @@ -1293,6 +1403,14 @@ @item GET_MODE_BITSIZE (@var{m}) Returns the size in bits of a datum of mode @var{m}. +@findex GET_MODE_IBIT +@item GET_MODE_IBIT (@var{m}) +Returns the number of integral bits of a datum of fixed-point mode @var{m}. + +@findex GET_MODE_FBIT +@item GET_MODE_FBIT (@var{m}) +Returns the number of fractional bits of a datum of fixed-point mode @var{m}. + @findex GET_MODE_MASK @item GET_MODE_MASK (@var{m}) Returns a bitmask containing 1 for all bits in a word that fit within @@ -1374,6 +1492,15 @@ does not provide a mechanism to represent even larger constants). In the latter case, @var{m} will be @code{VOIDmode}. +@findex const_fixed +@item (const_fixed:@var{m} @var{addr}) +Represents a fixed-point constant of mode @var{m}. +The data structure, which contains data with the size of two +@code{HOST_BITS_PER_WIDE_INT} and the associated fixed-point mode, +is access with the macro @code{CONST_FIXED_VALUE}. The high part of data +is accessed with @code{CONST_FIXED_VALUE_HIGH}; the low part is accessed +with @code{CONST_FIXED_VALUE_LOW}. + @findex const_vector @item (const_vector:@var{m} [@var{x0} @var{x1} @dots{}]) Represents a vector constant. The square brackets stand for the vector @@ -1895,24 +2022,35 @@ @findex neg @findex ss_neg +@findex us_neg @cindex negation @cindex negation with signed saturation +@cindex negation with unsigned saturation @item (neg:@var{m} @var{x}) @itemx (ss_neg:@var{m} @var{x}) +@itemx (us_neg:@var{m} @var{x}) These two expressions represent the negation (subtraction from zero) of the value represented by @var{x}, carried out in mode @var{m}. They differ in the behavior on overflow of integer modes. In the case of @code{neg}, the negation of the operand may be a number not representable in mode @var{m}, in which case it is truncated to @var{m}. @code{ss_neg} -ensures that an out-of-bounds result saturates to the maximum or minimum -representable value. +and @code{us_neg} ensure that an out-of-bounds result saturates to the +maximum or minimum signed or unsigned value. @findex mult +@findex ss_mult +@findex us_mult @cindex multiplication @cindex product +@cindex multiplication with signed saturation +@cindex multiplication with unsigned saturation @item (mult:@var{m} @var{x} @var{y}) +@itemx (ss_mult:@var{m} @var{x} @var{y}) +@itemx (us_mult:@var{m} @var{x} @var{y}) Represents the signed product of the values represented by @var{x} and @var{y} carried out in machine mode @var{m}. +@code{ss_mult} and @code{us_mult} ensure that an out-of-bounds result +saturates to the maximum or minimum signed or unsigned value. Some machines support a multiplication that generates a product wider than the operands. Write the pattern for this as @@ -1928,14 +2066,19 @@ @code{zero_extend} instead of @code{sign_extend}. @findex div +@findex ss_div @cindex division @cindex signed division +@cindex signed division with signed saturation @cindex quotient @item (div:@var{m} @var{x} @var{y}) +@itemx (ss_div:@var{m} @var{x} @var{y}) Represents the quotient in signed division of @var{x} by @var{y}, carried out in machine mode @var{m}. If @var{m} is a floating point mode, it represents the exact quotient; otherwise, the integerized quotient. +@code{ss_div} ensures that an out-of-bounds result saturates to the maximum +or minimum signed value. Some machines have division instructions in which the operands and quotient widths are not all the same; you should represent @@ -1947,9 +2090,13 @@ @findex udiv @cindex unsigned division +@cindex unsigned division with unsigned saturation @cindex division @item (udiv:@var{m} @var{x} @var{y}) +@itemx (us_div:@var{m} @var{x} @var{y}) Like @code{div} but represents unsigned division. +@code{us_div} ensures that an out-of-bounds result saturates to the maximum +or minimum unsigned value. @findex mod @findex umod @@ -2411,6 +2558,38 @@ converting floating point value @var{x} (valid for mode @var{m}) to an integer, still represented in floating point mode @var{m}, by rounding towards zero. + +@findex fixed_all +@item (fixed_all:@var{m} @var{x}) +Represents the result of converting fixed-point value @var{x} to +fixed-point mode @var{m}, signed integer value @var{x} to +fixed-point mode @var{m}, floating-point value @var{x} to +fixed-point mode @var{m}, fixed-point value @var{x} to integer mode @var{m} +regarded as signed, or fixed-point value @var{x} to floating-point mode @var{m}. +When overflows or underflows happen, the results are undefined. + +@findex sat_fixed_all +@item (sat_fixed_all:@var{m} @var{x}) +Represents the result of converting fixed-point value @var{x} to +fixed-point mode @var{m}, signed integer value @var{x} to +fixed-point mode @var{m}, or floating-point value @var{x} to +fixed-point mode @var{m}. +When overflows or underflows happen, the results are saturated to the +maximum or the minimum. + +@findex fixed_uint +@item (fixed_uint:@var{m} @var{x}) +Represents the result of converting fixed-point value @var{x} to +integer mode @var{m} regarded as unsigned, or unsigned integer value @var{x} to +fixed-point mode @var{m}. +When overflows or underflows happen, the results are undefined. + +@findex sat_fixed_uint +@item (sat_fixed_uint:@var{m} @var{x}) +Represents the result of converting unsigned integer value @var{x} to +fixed-point mode @var{m}. +When overflows or underflows happen, the results are saturated to the +maximum or the minimum. @end table @node RTL Declarations Index: doc/c-tree.texi =================================================================== --- doc/c-tree.texi (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/doc/c-tree.texi) (revision 125345) +++ doc/c-tree.texi (.../doc/c-tree.texi) (working copy) @@ -271,6 +271,7 @@ @tindex TYPE_MIN_VALUE @tindex TYPE_MAX_VALUE @tindex REAL_TYPE +@tindex FIXED_POINT_TYPE @tindex COMPLEX_TYPE @tindex ENUMERAL_TYPE @tindex BOOLEAN_TYPE @@ -498,6 +499,19 @@ double} types. The number of bits in the floating-point representation is given by @code{TYPE_PRECISION}, as in the @code{INTEGER_TYPE} case. +@item FIXED_POINT_TYPE +Used to represent the @code{short _Fract}, @code{_Fract}, @code{long +_Fract}, @code{long long _Fract}, @code{short _Accum}, @code{_Accum}, +@code{long _Accum}, and @code{long long _Accum} types. The number of bits +in the fixed-point representation is given by @code{TYPE_PRECISION}, +as in the @code{INTEGER_TYPE} case. There may be padding bits, fractional +bits and integral bits. The number of fractional bits is given by +@code{TYPE_FBIT}, and the number of integral bits is given by @code{TYPE_IBIT}. +The fixed-point type is unsigned if @code{TYPE_UNSIGNED} holds; otherwise, +it is signed. +The fixed-point type is saturating if @code{TYPE_SATURATING} holds; otherwise, +it is not saturating. + @item COMPLEX_TYPE Used to represent GCC built-in @code{__complex__} data types. The @code{TREE_TYPE} is the type of the real and imaginary parts. @@ -1879,6 +1893,7 @@ @findex tree_int_cst_lt @findex tree_int_cst_equal @tindex REAL_CST +@tindex FIXED_CST @tindex COMPLEX_CST @tindex VECTOR_CST @tindex STRING_CST @@ -1907,6 +1922,7 @@ @tindex NON_LVALUE_EXPR @tindex NOP_EXPR @tindex CONVERT_EXPR +@tindex FIXED_CONVERT_EXPR @tindex THROW_EXPR @tindex LSHIFT_EXPR @tindex RSHIFT_EXPR @@ -2078,6 +2094,15 @@ FIXME: Talk about how to obtain representations of this constant, do comparisons, and so forth. +@item FIXED_CST + +These nodes represent fixed-point constants. The type of these constants +is obtained with @code{TREE_TYPE}. @code{TREE_FIXED_CST_PTR} points to +to struct fixed_value; @code{TREE_FIXED_CST} returns the structure itself. +Struct fixed_value contains @code{data} with the size of two +HOST_BITS_PER_WIDE_INT and @code{mode} as the associated fixed-point +machine mode for @code{data}. + @item COMPLEX_CST These nodes are used to represent complex number constants, that is a @code{__complex__} whose parts are constant nodes. The @@ -2244,6 +2269,13 @@ conversion is never represented by a @code{CONVERT_EXPR}; instead, the function calls are made explicit. +@item FIXED_CONVERT_EXPR +These nodes are used to represent conversions that involve fixed-point +values. For example, from a fixed-point value to another fixed-point value, +from an integer to a fixed-point value, from a fixed-point value to an +integer, from a floating-point value to a fixed-point value, or from +a fixed-point value to a floating-point value. + @item THROW_EXPR These nodes represent @code{throw} expressions. The single operand is an expression for the code that should be executed to throw the Index: doc/md.texi =================================================================== --- doc/md.texi (.../svn+ssh://chaoyingfu@sources.redhat.com/svn/gcc/trunk/gcc/doc/md.texi) (revision 125345) +++ doc/md.texi (.../doc/md.texi) (working copy) @@ -3581,10 +3581,18 @@ must have mode @var{m}. This can be used even on two-address machines, by means of constraints requiring operands 1 and 0 to be the same location. +@cindex @code{ssadd@var{m}3} instruction pattern +@cindex @code{usadd@var{m}3} instruction pattern @cindex @code{sub@var{m}3} instruction pattern +@cindex @code{sssub@var{m}3} instruction pattern +@cindex @code{ussub@var{m}3} instruction pattern @cindex @code{mul@var{m}3} instruction pattern +@cindex @code{ssmul@var{m}3} instruction pattern +@cindex @code{usmul@var{m}3} instruction pattern @cindex @code{div@var{m}3} instruction pattern +@cindex @code{ssdiv@var{m}3} instruction pattern @cindex @code{udiv@var{m}3} instruction pattern +@cindex @code{usdiv@var{m}3} instruction pattern @cindex @code{mod@var{m}3} instruction pattern @cindex @code{umod@var{m}3} instruction pattern @cindex @code{umin@var{m}3} instruction pattern @@ -3592,8 +3600,11 @@ @cindex @code{and@var{m}3} instruction pattern @cindex @code{ior@var{m}3} instruction pattern @cindex @code{xor@var{m}3} instruction pattern -@item @samp{sub@var{m}3}, @samp{mul@var{m}3} -@itemx @samp{div@var{m}3}, @samp{udiv@var{m}3} +@item @samp{ssadd@var{m}3}, @samp{usadd@var{m}3} +@item @samp{sub@var{m}3}, @samp{sssub@var{m}3}, @samp{ussub@var{m}3} +@item @samp{mul@var{m}3}, @samp{ssmul@var{m}3}, @samp{usmul@var{m}3} +@itemx @samp{div@var{m}3}, @samp{ssdiv@var{m}3} +@itemx @samp{udiv@var{m}3}, @samp{usdiv@var{m}3} @itemx @samp{mod@var{m}3}, @samp{umod@var{m}3} @itemx @samp{umin@var{m}3}, @samp{umax@var{m}3} @itemx @samp{and@var{m}3}, @samp{ior@var{m}3}, @samp{xor@var{m}3} @@ -3766,7 +3777,7 @@ Multiply operands 1 and 2, sign-extend them to mode @var{n}, add operand 3, and store the result in operand 0. Operands 1 and 2 have mode @var{m} and operands 0 and 3 have mode @var{n}. -Both modes must be integer modes and @var{n} must be twice +Both modes must be integer or fixed-point modes and @var{n} must be twice the size of @var{m}. In other words, @code{madd@var{m}@var{n}4} is like @@ -3779,12 +3790,22 @@ Like @code{madd@var{m}@var{n}4}, but zero-extend the multiplication operands instead of sign-extending them. +@cindex @code{ssmadd@var{m}@var{n}4} instruction pattern +@item @samp{ssmadd@var{m}@var{n}4} +Like @code{madd@var{m}@var{n}4}, but all involved operations must be +signed-saturating. + +@cindex @code{usmadd@var{m}@var{n}4} instruction pattern +@item @samp{usmadd@var{m}@var{n}4} +Like @code{umadd@var{m}@var{n}4}, but all involved operations must be +unsigned-saturating. + @cindex @code{msub@var{m}@var{n}4} instruction pattern @item @samp{msub@var{m}@var{n}4} Multiply operands 1 and 2, sign-extend them to mode @var{n}, subtract the result from operand 3, and store the result in operand 0. Operands 1 and 2 have mode @var{m} and operands 0 and 3 have mode @var{n}. -Both modes must be integer modes and @var{n} must be twice +Both modes must be integer or fixed-point modes and @var{n} must be twice the size of @var{m}. In other words, @code{msub@var{m}@var{n}4} is like @@ -3798,6 +3819,16 @@ Like @code{msub@var{m}@var{n}4}, but zero-extend the multiplication operands instead of sign-extending them. +@cindex @code{ssmsub@var{m}@var{n}4} instruction pattern +@item @samp{ssmsub@var{m}@var{n}4} +Like @code{msub@var{m}@var{n}4}, but all involved operations must be +signed-saturating. + +@cindex @code{usmsub@var{m}@var{n}4} instruction pattern +@item @samp{usmsub@var{m}@var{n}4} +Like @code{umsub@var{m}@var{n}4}, but all involved operations must be +unsigned-saturating. + @cindex @code{divmod@var{m}4} instruction pattern @item @samp{divmod@var{m}4} Signed division that produces both a quotient and a remainder. @@ -3822,7 +3853,9 @@ @anchor{shift patterns} @cindex @code{ashl@var{m}3} instruction pattern -@item @samp{ashl@var{m}3} +@cindex @code{ssashl@var{m}3} instruction pattern +@cindex @code{usashl@var{m}3} instruction pattern +@item @samp{ashl@var{m}3}, @samp{ssashl@var{m}3}, @samp{usashl@var{m}3} Arithmetic-shift operand 1 left by a number of bits specified by operand 2, and store the result in operand 0. Here @var{m} is the mode of operand 0 and operand 1; operand 2's mode is specified by the @@ -3840,7 +3873,9 @@ @code{ashl@var{m}3} instructions. @cindex @code{neg@var{m}2} instruction pattern -@item @samp{neg@var{m}2} +@cindex @code{ssneg@var{m}2} instruction pattern +@cindex @code{usneg@var{m}2} instruction pattern +@item @samp{neg@var{m}2}, @samp{ssneg@var{m}2}, @samp{usneg@var{m}2} Negate operand 1 and store the result in operand 0. @cindex @code{abs@var{m}2} instruction pattern @@ -4268,6 +4303,39 @@ store in operand 0 (which has mode @var{n}). Both modes must be fixed point. +@cindex @code{fixed_all@var{mn}2} instruction pattern +@item @samp{fixed_all@var{m}@var{n}2} +Convert operand 1 of mode @var{m} to mode @var{n} and store in +operand 0 (which has mode @var{n}). Mode @var{m} and mode @var{n} +could be fixed-point to fixed-point, signed integer to fixed-point, +fixed-point to signed integer, floating-point to fixed-point, +or fixed-point to floating-point. +When overflows or underflows happen, the results are undefined. + +@cindex @code{sat_fixed_all@var{mn}2} instruction pattern +@item @samp{sat_fixed_all@var{m}@var{n}2} +Convert operand 1 of mode @var{m} to mode @var{n} and store in +operand 0 (which has mode @var{n}). Mode @var{m} and mode @var{n} +could be fixed-point to fixed-point, signed integer to fixed-point, +or floating-point to fixed-point. +When overflows or underflows happen, the instruction saturates the +results to the maximum or the minimum. + +@cindex @code{fixed_uint@var{mn}2} instruction pattern +@item @samp{fixed_uint@var{m}@var{n}2} +Convert operand 1 of mode @var{m} to mode @var{n} and store in +operand 0 (which has mode @var{n}). Mode @var{m} and mode @var{n} +could be unsigned integer to fixed-point, or +fixed-point to unsigned integer. +When overflows or underflows happen, the results are undefined. + +@cindex @code{sat_fixed_uint@var{mn}2} instruction pattern +@item @samp{sat_fixed_uint@var{m}@var{n}2} +Convert unsigned integer operand 1 of mode @var{m} to fixed-point mode +@var{n} and store in operand 0 (which has mode @var{n}). +When overflows or underflows happen, the instruction saturates the +results to the maximum or the minimum. + @cindex @code{extv} instruction pattern @item @samp{extv} Extract a bit-field from operand 1 (a register or memory operand), where