* ginclude/stdfix.h: New file.
authorchaoyingfu <chaoyingfu@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 7 Sep 2007 01:24:09 +0000 (01:24 +0000)
committerchaoyingfu <chaoyingfu@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 7 Sep 2007 01:24:09 +0000 (01:24 +0000)
* Makefile.in (USER_H): Add $(srcdir)/ginclude/stdfix.h.
(convert.o): Add dependence on fixed-value.h.
* c-convert.c (convert): Support FIXED_POINT_TYPE.
* c-cppbuiltin.c (builtin_define_fixed_point_constants): New function
to define fixed-point constants.
(c_cpp_builtins): Define fixed-point constants.
* convert.c (fixed-value.h): New include.
(convert_to_real): Update comment to include fixed-point.
Support FIXED_POINT_TYPE.
(convert_to_integer): Update comment to include fixed-point.
Support FIXED_POINT_TYPE.
(convert_to_complex): Support FIXED_POINT_TYPE.
(convert_to_fixed): New function.
* convert.h (convert_to_fixed): Declare.
* genopinit.c: Add comment about $Q for only fixed-point modes.
(optabs): Add fract_optab, fractuns_optab, satfract_optab,
satfractuns_optab, add_optab, ssadd_optab, usadd_optab, sub_optab,
sssub_optab, ussub_optab, smul_optab, ssmul_optab, usmul_optab,
ssmadd_widen_optab, usmadd_widen_optab, ssdiv_optab, udiv_optab,
usdiv_optab, ssashl_optab, usashl_optab, neg_optab, ssneg_optab,
usneg_optab for fixed-point modes.
(gen_insn): Add force_fixed to track the $Q format for all fixed-point
modes.
* optabs.c (optab_for_tree_code): For *DIV_EXPR, LSHIFT_EXPR,
PLUS_EXPR, MINUS_EXPR, MULT_EXPR, NEGATE_EXPR, return signed or
unsigned saturation optabs, when type is saturating.
(shift_optab_p): Return true for SS_ASHIFT or US_ASHIFT.
(expand_fixed_convert): New function.
(gen_fixed_libfunc, gen_signed_fixed_libfunc,
gen_unsigned_fixed_libfunc, gen_int_fp_fixed_libfunc,
gen_int_fp_signed_fixed_libfunc, gen_int_fixed_libfunc,
gen_int_signed_fixed_libfunc, gen_int_unsigned_fixed_libfunc,
gen_fract_conv_libfunc, gen_fractuns_conv_libfunc,
gen_satfract_conv_libfunc, gen_satfractuns_conv_libfunc): New
functions.
(init_optabs): Initialize ssadd_optab, usadd_optab, sssub_optab,
ussub_optab, ssmul_optab, usmul_optab, ssmadd_widen_optab,
usmadd_widen_optab, ssmsub_widen_optab, usmsub_widen_optab,
ssdiv_optab, usdiv_optab, ssashl_optab, usashl_optab, ssneg_optab,
usneg_optab, fract_optab, fractuns_optab, satfract_optab,
satfractuns_optab.
Initialize fixed-point libraries, including add, ssadd, usadd, sub,
sssub, ussub, mul, ssmul, usmul, div, ssdiv, udiv, usdiv, ashl,
ssashl, usashl, ashr, lshr, neg, ssneg, usneg, cmp, fract, satfract,
fractuns, satfractuns.
* optabs.h (enum optab_index): Add OTI_ssadd, OTI_usadd, OTI_sssub,
OTI_ussub, OTI_ssmul, OTI_usmul, OTI_ssdiv, OTI_usdiv, OTI_ssneg,
OTI_usneg, OTI_ssashl, OTI_usashl, OTI_ssmadd_widen, OTI_usmadd_widen,
OTI_ssmsub_widen,  OTI_usmsub_widen.
(ssadd_optab, usadd_optab, sssub_optab, ussub_optab, ssmul_optab,
usmul_optab, ssdiv_optab, usdiv_optab, ssneg_optab, usneg_optab,
ssashl_optab, usashl_optab, ssmadd_widen_optab, usmadd_widen_optab,
umsub_widen_optab, usmsub_widen_optab): Define.
(enum convert_optab_index): Add COI_fract, COI_fractuns, COI_satfract,
COI_satfractuns.
(fract_optab, fractuns_optab, satfract_optab, satfractuns_optab):
Define.
(expand_fixed_convert): Declare.
* expr.c (convert_move): Support the move of fixed-point modes.
(emit_move_insn_1): Handle fixed-point mode to move via integer.
(categorize_ctor_elements_1): Handle FIXED_CST.
(count_type_elements): Handle FIXED_POINT_TYPE.
(expand_expr_real_1): For VECTOR_CST, check MODE_VECTOR_FRACT,
MODE_VECTOR_UFRACT, MODE_VECTOR_ACCUM, MODE_VECTOR_UACCUM.
Support FIXED_CST.
For PLUS_EXPR and MINUS_EXPR, support saturating and non-saturating
multiply and add/subtract for fixed-point types.
For MULT_EXPR, *DIV_EXPR, *SHIFT_EXPR, if the mode if a fixed-point
mode, we jump to binop directly.
Support FIXED_CONVERT_EXPR.
(do_store_flag): Check FIXED_CST to put a constant second.
(vector_mode_valid_p): Handle MODE_VECTOR_FRACT,
MODE_VECTOR_UFRACT, MODE_VECTOR_ACCUM, MODE_VECTOR_UACCUM.
(const_vector_from_tree): Support FIXED_CST.
* doc/extend.texi (Fixed-Point): New node.
* doc/md.texi (ssadd, usadd, sssub, ussub, ssmul, usmul, ssdiv, usdiv,
ssmadd, usmadd, ssmsub, usmsub, ssashl, usashl, ssneg, usneg, fract,
satfract, fractuns, satfractuns): Document them.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@128218 138bc75d-0d04-0410-961f-82ee72b054a4

13 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/c-convert.c
gcc/c-cppbuiltin.c
gcc/convert.c
gcc/convert.h
gcc/doc/extend.texi
gcc/doc/md.texi
gcc/expr.c
gcc/genopinit.c
gcc/ginclude/stdfix.h [new file with mode: 0644]
gcc/optabs.c
gcc/optabs.h

index 7cc1ad9..b93723a 100644 (file)
@@ -1,3 +1,85 @@
+2007-09-06  Chao-ying Fu  <fu@mips.com>
+
+       * ginclude/stdfix.h: New file.
+       * Makefile.in (USER_H): Add $(srcdir)/ginclude/stdfix.h.
+       (convert.o): Add dependence on fixed-value.h.
+       * c-convert.c (convert): Support FIXED_POINT_TYPE.
+       * c-cppbuiltin.c (builtin_define_fixed_point_constants): New function
+       to define fixed-point constants.
+       (c_cpp_builtins): Define fixed-point constants.
+       * convert.c (fixed-value.h): New include.
+       (convert_to_real): Update comment to include fixed-point.
+       Support FIXED_POINT_TYPE.
+       (convert_to_integer): Update comment to include fixed-point.
+       Support FIXED_POINT_TYPE.
+       (convert_to_complex): Support FIXED_POINT_TYPE.
+       (convert_to_fixed): New function.
+       * convert.h (convert_to_fixed): Declare.
+       * genopinit.c: Add comment about $Q for only fixed-point modes.
+       (optabs): Add fract_optab, fractuns_optab, satfract_optab,
+       satfractuns_optab, add_optab, ssadd_optab, usadd_optab, sub_optab,
+       sssub_optab, ussub_optab, smul_optab, ssmul_optab, usmul_optab,
+       ssmadd_widen_optab, usmadd_widen_optab, ssdiv_optab, udiv_optab,
+       usdiv_optab, ssashl_optab, usashl_optab, neg_optab, ssneg_optab,
+       usneg_optab for fixed-point modes.
+       (gen_insn): Add force_fixed to track the $Q format for all fixed-point
+       modes.
+       * optabs.c (optab_for_tree_code): For *DIV_EXPR, LSHIFT_EXPR,
+       PLUS_EXPR, MINUS_EXPR, MULT_EXPR, NEGATE_EXPR, return signed or
+       unsigned saturation optabs, when type is saturating.
+       (shift_optab_p): Return true for SS_ASHIFT or US_ASHIFT.
+       (expand_fixed_convert): New function.
+       (gen_fixed_libfunc, gen_signed_fixed_libfunc,
+       gen_unsigned_fixed_libfunc, gen_int_fp_fixed_libfunc,
+       gen_int_fp_signed_fixed_libfunc, gen_int_fixed_libfunc,
+       gen_int_signed_fixed_libfunc, gen_int_unsigned_fixed_libfunc,
+       gen_fract_conv_libfunc, gen_fractuns_conv_libfunc,
+       gen_satfract_conv_libfunc, gen_satfractuns_conv_libfunc): New
+       functions.
+       (init_optabs): Initialize ssadd_optab, usadd_optab, sssub_optab,
+       ussub_optab, ssmul_optab, usmul_optab, ssmadd_widen_optab,
+       usmadd_widen_optab, ssmsub_widen_optab, usmsub_widen_optab,
+       ssdiv_optab, usdiv_optab, ssashl_optab, usashl_optab, ssneg_optab,
+       usneg_optab, fract_optab, fractuns_optab, satfract_optab,
+       satfractuns_optab.
+       Initialize fixed-point libraries, including add, ssadd, usadd, sub,
+       sssub, ussub, mul, ssmul, usmul, div, ssdiv, udiv, usdiv, ashl,
+       ssashl, usashl, ashr, lshr, neg, ssneg, usneg, cmp, fract, satfract,
+       fractuns, satfractuns.
+       * optabs.h (enum optab_index): Add OTI_ssadd, OTI_usadd, OTI_sssub,
+       OTI_ussub, OTI_ssmul, OTI_usmul, OTI_ssdiv, OTI_usdiv, OTI_ssneg,
+       OTI_usneg, OTI_ssashl, OTI_usashl, OTI_ssmadd_widen, OTI_usmadd_widen,
+       OTI_ssmsub_widen,  OTI_usmsub_widen.
+       (ssadd_optab, usadd_optab, sssub_optab, ussub_optab, ssmul_optab,
+       usmul_optab, ssdiv_optab, usdiv_optab, ssneg_optab, usneg_optab,
+       ssashl_optab, usashl_optab, ssmadd_widen_optab, usmadd_widen_optab,
+       umsub_widen_optab, usmsub_widen_optab): Define.
+       (enum convert_optab_index): Add COI_fract, COI_fractuns, COI_satfract,
+       COI_satfractuns.
+       (fract_optab, fractuns_optab, satfract_optab, satfractuns_optab):
+       Define.
+       (expand_fixed_convert): Declare.
+       * expr.c (convert_move): Support the move of fixed-point modes.
+       (emit_move_insn_1): Handle fixed-point mode to move via integer.
+       (categorize_ctor_elements_1): Handle FIXED_CST.
+       (count_type_elements): Handle FIXED_POINT_TYPE.
+       (expand_expr_real_1): For VECTOR_CST, check MODE_VECTOR_FRACT,
+       MODE_VECTOR_UFRACT, MODE_VECTOR_ACCUM, MODE_VECTOR_UACCUM.
+       Support FIXED_CST.
+       For PLUS_EXPR and MINUS_EXPR, support saturating and non-saturating
+       multiply and add/subtract for fixed-point types.
+       For MULT_EXPR, *DIV_EXPR, *SHIFT_EXPR, if the mode if a fixed-point
+       mode, we jump to binop directly.
+       Support FIXED_CONVERT_EXPR.
+       (do_store_flag): Check FIXED_CST to put a constant second.
+       (vector_mode_valid_p): Handle MODE_VECTOR_FRACT,
+       MODE_VECTOR_UFRACT, MODE_VECTOR_ACCUM, MODE_VECTOR_UACCUM.
+       (const_vector_from_tree): Support FIXED_CST.
+       * doc/extend.texi (Fixed-Point): New node.
+       * doc/md.texi (ssadd, usadd, sssub, ussub, ssmul, usmul, ssdiv, usdiv,
+       ssmadd, usmadd, ssmsub, usmsub, ssashl, usashl, ssneg, usneg, fract,
+       satfract, fractuns, satfractuns): Document them.
+
 2007-09-07  Bernd Schmidt  <bernd.schmidt@analog.com>
 
        * config/bfin/bfin.h (PREFERRED_RELOAD_CLASS): Don't reload autoinc
index b010a09..1030d8e 100644 (file)
@@ -302,6 +302,7 @@ USER_H = $(srcdir)/ginclude/float.h \
         $(srcdir)/ginclude/stdbool.h \
         $(srcdir)/ginclude/stddef.h \
         $(srcdir)/ginclude/varargs.h \
+        $(srcdir)/ginclude/stdfix.h \
         $(EXTRA_HEADERS)
 
 UNWIND_H = $(srcdir)/unwind-generic.h
@@ -1942,7 +1943,7 @@ prefix.o: prefix.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) prefix.h \
          -c $(srcdir)/prefix.c $(OUTPUT_OPTION)
 
 convert.o: convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
-   $(FLAGS_H) convert.h toplev.h langhooks.h $(REAL_H)
+   $(FLAGS_H) convert.h toplev.h langhooks.h $(REAL_H) fixed-value.h
 
 double-int.o: double-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
 
index c5f7080..8fa68a1 100644 (file)
@@ -105,6 +105,8 @@ convert (tree type, tree expr)
     return fold (convert_to_pointer (type, e));
   if (code == REAL_TYPE)
     return fold (convert_to_real (type, e));
+  if (code == FIXED_POINT_TYPE)
+    return fold (convert_to_fixed (type, e));
   if (code == COMPLEX_TYPE)
     return fold (convert_to_complex (type, e));
   if (code == VECTOR_TYPE)
index efb40c3..e201b05 100644 (file)
@@ -317,6 +317,60 @@ builtin_define_decimal_float_constants (const char *name_prefix,
   builtin_define_with_value (name, buf, 0);
 }
 
+/* Define fixed-point constants for TYPE using NAME_PREFIX and SUFFIX.  */
+
+static void
+builtin_define_fixed_point_constants (const char *name_prefix,
+                                     const char *suffix,
+                                     tree type)
+{
+  char name[64], buf[256], *new_buf;
+  int i, mod;
+
+  sprintf (name, "__%s_FBIT__", name_prefix);
+  builtin_define_with_int_value (name, TYPE_FBIT (type));
+
+  sprintf (name, "__%s_IBIT__", name_prefix);
+  builtin_define_with_int_value (name, TYPE_IBIT (type));
+
+  /* If there is no suffix, defines are for fixed-point modes.
+     We just return.  */
+  if (strcmp (suffix, "") == 0)
+    return;
+
+  if (TYPE_UNSIGNED (type))
+    {
+      sprintf (name, "__%s_MIN__", name_prefix);
+      sprintf (buf, "0.0%s", suffix);
+      builtin_define_with_value (name, buf, 0);
+    }
+  else
+    {
+      sprintf (name, "__%s_MIN__", name_prefix);
+      if (ALL_ACCUM_MODE_P (TYPE_MODE (type)))
+       sprintf (buf, "(-0X1P%d%s-0X1P%d%s)", TYPE_IBIT (type) - 1, suffix,
+                TYPE_IBIT (type) - 1, suffix);
+      else
+       sprintf (buf, "(-0.5%s-0.5%s)", suffix, suffix);
+      builtin_define_with_value (name, buf, 0);
+    }
+
+  sprintf (name, "__%s_MAX__", name_prefix);
+  sprintf (buf, "0X");
+  new_buf = buf + 2;
+  mod = (TYPE_FBIT (type) + TYPE_IBIT (type)) % 4;
+  if (mod)
+    sprintf (new_buf++, "%x", (1 << mod) - 1);
+  for (i = 0; i < (TYPE_FBIT (type) + TYPE_IBIT (type)) / 4; i++)
+    sprintf (new_buf++, "F");
+  sprintf (new_buf, "P-%d%s", TYPE_FBIT (type), suffix);
+  builtin_define_with_value (name, buf, 0);
+
+  sprintf (name, "__%s_EPSILON__", name_prefix);
+  sprintf (buf, "0x1P-%d%s", TYPE_FBIT (type), suffix);
+  builtin_define_with_value (name, buf, 0);
+}
+
 /* Define __GNUC__, __GNUC_MINOR__ and __GNUC_PATCHLEVEL__.  */
 static void
 define__GNUC__ (void)
@@ -465,6 +519,62 @@ c_cpp_builtins (cpp_reader *pfile)
   builtin_define_decimal_float_constants ("DEC64", "DD", dfloat64_type_node);
   builtin_define_decimal_float_constants ("DEC128", "DL", dfloat128_type_node);
 
+  /* For fixed-point fibt, ibit, max, min, and epsilon.  */
+  if (targetm.fixed_point_supported_p ())
+    {
+      builtin_define_fixed_point_constants ("SFRACT", "HR",
+                                           short_fract_type_node);
+      builtin_define_fixed_point_constants ("USFRACT", "UHR",
+                                           unsigned_short_fract_type_node);
+      builtin_define_fixed_point_constants ("FRACT", "R",
+                                           fract_type_node);
+      builtin_define_fixed_point_constants ("UFRACT", "UR",
+                                           unsigned_fract_type_node);
+      builtin_define_fixed_point_constants ("LFRACT", "LR",
+                                           long_fract_type_node);
+      builtin_define_fixed_point_constants ("ULFRACT", "ULR",
+                                           unsigned_long_fract_type_node);
+      builtin_define_fixed_point_constants ("LLFRACT", "LLR",
+                                           long_long_fract_type_node);
+      builtin_define_fixed_point_constants ("ULLFRACT", "ULLR",
+                                           unsigned_long_long_fract_type_node);
+      builtin_define_fixed_point_constants ("SACCUM", "HK",
+                                           short_accum_type_node);
+      builtin_define_fixed_point_constants ("USACCUM", "UHK",
+                                           unsigned_short_accum_type_node);
+      builtin_define_fixed_point_constants ("ACCUM", "K",
+                                           accum_type_node);
+      builtin_define_fixed_point_constants ("UACCUM", "UK",
+                                           unsigned_accum_type_node);
+      builtin_define_fixed_point_constants ("LACCUM", "LK",
+                                           long_accum_type_node);
+      builtin_define_fixed_point_constants ("ULACCUM", "ULK",
+                                           unsigned_long_accum_type_node);
+      builtin_define_fixed_point_constants ("LLACCUM", "LLK",
+                                           long_long_accum_type_node);
+      builtin_define_fixed_point_constants ("ULLACCUM", "ULLK",
+                                           unsigned_long_long_accum_type_node);
+
+      builtin_define_fixed_point_constants ("QQ", "", qq_type_node);
+      builtin_define_fixed_point_constants ("HQ", "", hq_type_node);
+      builtin_define_fixed_point_constants ("SQ", "", sq_type_node);
+      builtin_define_fixed_point_constants ("DQ", "", dq_type_node);
+      builtin_define_fixed_point_constants ("TQ", "", tq_type_node);
+      builtin_define_fixed_point_constants ("UQQ", "", uqq_type_node);
+      builtin_define_fixed_point_constants ("UHQ", "", uhq_type_node);
+      builtin_define_fixed_point_constants ("USQ", "", usq_type_node);
+      builtin_define_fixed_point_constants ("UDQ", "", udq_type_node);
+      builtin_define_fixed_point_constants ("UTQ", "", utq_type_node);
+      builtin_define_fixed_point_constants ("HA", "", ha_type_node);
+      builtin_define_fixed_point_constants ("SA", "", sa_type_node);
+      builtin_define_fixed_point_constants ("DA", "", da_type_node);
+      builtin_define_fixed_point_constants ("TA", "", ta_type_node);
+      builtin_define_fixed_point_constants ("UHA", "", uha_type_node);
+      builtin_define_fixed_point_constants ("USA", "", usa_type_node);
+      builtin_define_fixed_point_constants ("UDA", "", uda_type_node);
+      builtin_define_fixed_point_constants ("UTA", "", uta_type_node);
+    }
+
   /* For use in assembly language.  */
   builtin_define_with_value ("__REGISTER_PREFIX__", REGISTER_PREFIX, 0);
   builtin_define_with_value ("__USER_LABEL_PREFIX__", user_label_prefix, 0);
index 97641cf..f82604e 100644 (file)
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "langhooks.h"
 #include "real.h"
+#include "fixed-value.h"
 
 /* Convert EXPR to some pointer or reference type TYPE.
    EXPR must be pointer, reference, integer, enumeral, or literal zero;
@@ -117,7 +118,7 @@ strip_float_extensions (tree exp)
 
 /* Convert EXPR to some floating-point type TYPE.
 
-   EXPR must be float, integer, or enumeral;
+   EXPR must be float, fixed-point, integer, or enumeral;
    in other cases error is called.  */
 
 tree
@@ -319,6 +320,9 @@ convert_to_real (tree type, tree expr)
     case BOOLEAN_TYPE:
       return build1 (FLOAT_EXPR, type, expr);
 
+    case FIXED_POINT_TYPE:
+      return build1 (FIXED_CONVERT_EXPR, type, expr);
+
     case COMPLEX_TYPE:
       return convert (type,
                      fold_build1 (REALPART_EXPR,
@@ -337,8 +341,8 @@ convert_to_real (tree type, tree expr)
 
 /* Convert EXPR to some integer (or enum) type TYPE.
 
-   EXPR must be pointer, integer, discrete (enum, char, or bool), float, or
-   vector; in other cases error is called.
+   EXPR must be pointer, integer, discrete (enum, char, or bool), float,
+   fixed-point or vector; in other cases error is called.
 
    The result of this is always supposed to be a newly created tree node
    not in use in any existing structure.  */
@@ -713,6 +717,9 @@ convert_to_integer (tree type, tree expr)
     case REAL_TYPE:
       return build1 (FIX_TRUNC_EXPR, type, expr);
 
+    case FIXED_POINT_TYPE:
+      return build1 (FIXED_CONVERT_EXPR, type, expr);
+
     case COMPLEX_TYPE:
       return convert (type,
                      fold_build1 (REALPART_EXPR,
@@ -742,6 +749,7 @@ convert_to_complex (tree type, tree expr)
   switch (TREE_CODE (TREE_TYPE (expr)))
     {
     case REAL_TYPE:
+    case FIXED_POINT_TYPE:
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
@@ -806,3 +814,42 @@ convert_to_vector (tree type, tree expr)
       return error_mark_node;
     }
 }
+
+/* Convert EXPR to some fixed-point type TYPE.
+
+   EXPR must be fixed-point, float, integer, or enumeral;
+   in other cases error is called.  */
+
+tree
+convert_to_fixed (tree type, tree expr)
+{
+  if (integer_zerop (expr))
+    {
+      tree fixed_zero_node = build_fixed (type, FCONST0 (TYPE_MODE (type)));
+      return fixed_zero_node;
+    }
+  else if (integer_onep (expr) && ALL_SCALAR_ACCUM_MODE_P (TYPE_MODE (type)))
+    {
+      tree fixed_one_node = build_fixed (type, FCONST1 (TYPE_MODE (type)));
+      return fixed_one_node;
+    }
+
+  switch (TREE_CODE (TREE_TYPE (expr)))
+    {
+    case FIXED_POINT_TYPE:
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+    case REAL_TYPE:
+      return build1 (FIXED_CONVERT_EXPR, type, expr);
+
+    case COMPLEX_TYPE:
+      return convert (type,
+                     fold_build1 (REALPART_EXPR,
+                                  TREE_TYPE (TREE_TYPE (expr)), expr));
+
+    default:
+      error ("aggregate value used where a fixed-point was expected");
+      return error_mark_node;
+    }
+}
index cd15fe0..fad3882 100644 (file)
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 extern tree convert_to_integer (tree, tree);
 extern tree convert_to_pointer (tree, tree);
 extern tree convert_to_real (tree, tree);
+extern tree convert_to_fixed (tree, tree);
 extern tree convert_to_complex (tree, tree);
 extern tree convert_to_vector (tree, tree);
 
index 9f306a4..730940a 100644 (file)
@@ -36,6 +36,7 @@ extensions, accepted by GCC in C89 mode and in C++.
 * Floating Types::      Additional Floating Types.
 * 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.
@@ -949,6 +950,134 @@ would not be able to resolve the ambiguity of, e.g., @code{0x1.f}.  This
 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 51da432..1b0d766 100644 (file)
@@ -3587,10 +3587,18 @@ Add operand 2 and operand 1, storing the result in operand 0.  All operands
 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
@@ -3598,8 +3606,11 @@ means of constraints requiring operands 1 and 0 to be the same location.
 @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}
@@ -3772,7 +3783,7 @@ Similar, but the multiplication is unsigned.
 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
@@ -3785,12 +3796,22 @@ These instructions are not allowed to @code{FAIL}.
 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
@@ -3804,6 +3825,16 @@ These instructions are not allowed to @code{FAIL}.
 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.
@@ -3828,7 +3859,9 @@ Similar, but does unsigned division.
 
 @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
@@ -3846,7 +3879,9 @@ Other shift and rotate instructions, analogous to the
 @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
@@ -4274,6 +4309,39 @@ Zero-extend operand 1 (valid for mode @var{m}) to mode @var{n} and
 store in operand 0 (which has mode @var{n}).  Both modes must be fixed
 point.
 
+@cindex @code{fract@var{mn}2} instruction pattern
+@item @samp{fract@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{satfract@var{mn}2} instruction pattern
+@item @samp{satfract@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{fractuns@var{mn}2} instruction pattern
+@item @samp{fractuns@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{satfractuns@var{mn}2} instruction pattern
+@item @samp{satfractuns@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
index 054f4f1..554d72a 100644 (file)
@@ -347,7 +347,8 @@ init_expr (void)
 }
 \f
 /* Copy data from FROM to TO, where the machine modes are not the same.
-   Both modes may be integer, or both may be floating.
+   Both modes may be integer, or both may be floating, or both may be
+   fixed-point.
    UNSIGNEDP should be nonzero if FROM is an unsigned type.
    This causes zero-extension instead of sign-extension.  */
 
@@ -502,6 +503,22 @@ convert_move (rtx to, rtx from, int unsignedp)
       from = new_from;
     }
 
+   /* Make sure both are fixed-point modes or both are not.  */
+   gcc_assert (ALL_SCALAR_FIXED_POINT_MODE_P (from_mode) ==
+              ALL_SCALAR_FIXED_POINT_MODE_P (to_mode));
+   if (ALL_SCALAR_FIXED_POINT_MODE_P (from_mode))
+    {
+      /* If we widen from_mode to to_mode and they are in the same class,
+        we won't saturate the result.
+        Otherwise, always saturate the result to play safe.  */
+      if (GET_MODE_CLASS (from_mode) == GET_MODE_CLASS (to_mode)
+         && GET_MODE_SIZE (from_mode) < GET_MODE_SIZE (to_mode))
+       expand_fixed_convert (to, from, 0, 0);
+      else
+       expand_fixed_convert (to, from, 0, 1);
+      return;
+    }
+
   /* Now both modes are integers.  */
 
   /* Handle expanding beyond a word.  */
@@ -3284,7 +3301,8 @@ emit_move_insn_1 (rtx x, rtx y)
   if (COMPLEX_MODE_P (mode))
     return emit_move_complex (mode, x, y);
 
-  if (GET_MODE_CLASS (mode) == MODE_DECIMAL_FLOAT)
+  if (GET_MODE_CLASS (mode) == MODE_DECIMAL_FLOAT
+      || ALL_FIXED_POINT_MODE_P (mode))
     {
       rtx result = emit_move_via_integer (mode, x, y, true);
 
@@ -4763,6 +4781,7 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
 
        case INTEGER_CST:
        case REAL_CST:
+       case FIXED_CST:
          if (!initializer_zerop (value))
            nz_elts += mult;
          elt_count += mult;
@@ -4945,6 +4964,7 @@ count_type_elements (const_tree type, bool allow_flexarr)
 
     case INTEGER_TYPE:
     case REAL_TYPE:
+    case FIXED_POINT_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
     case POINTER_TYPE:
@@ -7231,7 +7251,11 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       {
        tree tmp = NULL_TREE;
        if (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)
          return const_vector_from_tree (exp);
        if (GET_MODE_CLASS (mode) == MODE_INT)
          {
@@ -7263,6 +7287,10 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (exp),
                                           TYPE_MODE (TREE_TYPE (exp)));
 
+    case FIXED_CST:
+      return CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (exp),
+                                          TYPE_MODE (TREE_TYPE (exp)));
+
     case COMPLEX_CST:
       /* Handle evaluating a complex constant in a CONCAT target.  */
       if (original_target && GET_CODE (original_target) == CONCAT)
@@ -8152,18 +8180,21 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case PLUS_EXPR:
 
       /* Check if this is a case for multiplication and addition.  */
-      if (TREE_CODE (type) == INTEGER_TYPE
+      if ((TREE_CODE (type) == INTEGER_TYPE
+          || TREE_CODE (type) == FIXED_POINT_TYPE)
          && TREE_CODE (TREE_OPERAND (exp, 0)) == MULT_EXPR)
        {
          tree subsubexp0, subsubexp1;
-         enum tree_code code0, code1;
+         enum tree_code code0, code1, this_code;
 
          subexp0 = TREE_OPERAND (exp, 0);
          subsubexp0 = TREE_OPERAND (subexp0, 0);
          subsubexp1 = TREE_OPERAND (subexp0, 1);
          code0 = TREE_CODE (subsubexp0);
          code1 = TREE_CODE (subsubexp1);
-         if (code0 == NOP_EXPR && code1 == NOP_EXPR
+         this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
+                                                      : FIXED_CONVERT_EXPR;
+         if (code0 == this_code && code1 == this_code
              && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
                  < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
              && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
@@ -8174,7 +8205,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
              tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
              enum machine_mode innermode = TYPE_MODE (op0type);
              bool zextend_p = TYPE_UNSIGNED (op0type);
-             this_optab = zextend_p ? umadd_widen_optab : smadd_widen_optab;
+             bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
+             if (sat_p == 0)
+               this_optab = zextend_p ? umadd_widen_optab : smadd_widen_optab;
+             else
+               this_optab = zextend_p ? usmadd_widen_optab
+                                      : ssmadd_widen_optab;
              if (mode == GET_MODE_2XWIDER_MODE (innermode)
                  && (optab_handler (this_optab, mode)->insn_code
                      != CODE_FOR_nothing))
@@ -8307,18 +8343,21 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
     case MINUS_EXPR:
       /* Check if this is a case for multiplication and subtraction.  */
-      if (TREE_CODE (type) == INTEGER_TYPE
+      if ((TREE_CODE (type) == INTEGER_TYPE
+          || TREE_CODE (type) == FIXED_POINT_TYPE)
          && TREE_CODE (TREE_OPERAND (exp, 1)) == MULT_EXPR)
        {
          tree subsubexp0, subsubexp1;
-         enum tree_code code0, code1;
+         enum tree_code code0, code1, this_code;
 
          subexp1 = TREE_OPERAND (exp, 1);
          subsubexp0 = TREE_OPERAND (subexp1, 0);
          subsubexp1 = TREE_OPERAND (subexp1, 1);
          code0 = TREE_CODE (subsubexp0);
          code1 = TREE_CODE (subsubexp1);
-         if (code0 == NOP_EXPR && code1 == NOP_EXPR
+         this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
+                                                      : FIXED_CONVERT_EXPR;
+         if (code0 == this_code && code1 == this_code
              && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
                  < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
              && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
@@ -8329,7 +8368,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
              tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
              enum machine_mode innermode = TYPE_MODE (op0type);
              bool zextend_p = TYPE_UNSIGNED (op0type);
-             this_optab = zextend_p ? umsub_widen_optab : smsub_widen_optab;
+             bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
+             if (sat_p == 0)
+               this_optab = zextend_p ? umsub_widen_optab : smsub_widen_optab;
+             else
+               this_optab = zextend_p ? usmsub_widen_optab
+                                      : ssmsub_widen_optab;
              if (mode == GET_MODE_2XWIDER_MODE (innermode)
                  && (optab_handler (this_optab, mode)->insn_code
                      != CODE_FOR_nothing))
@@ -8388,6 +8432,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       goto binop2;
 
     case MULT_EXPR:
+      /* If this is a fixed-point operation, then we cannot use the code
+        below because "expand_mult" doesn't support sat/no-sat fixed-point
+         multiplications.   */
+      if (ALL_FIXED_POINT_MODE_P (mode))
+       goto binop;
+
       /* If first operand is constant, swap them.
         Thus the following special case checks need only
         check the second operand.  */
@@ -8540,6 +8590,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case CEIL_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case EXACT_DIV_EXPR:
+      /* If this is a fixed-point operation, then we cannot use the code
+        below because "expand_divmod" doesn't support sat/no-sat fixed-point
+         divisions.   */
+      if (ALL_FIXED_POINT_MODE_P (mode))
+       goto binop;
+
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
       /* Possible optimization: compute the dividend with EXPAND_SUM
@@ -8562,6 +8618,19 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                       subtarget, &op0, &op1, 0);
       return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
 
+    case FIXED_CONVERT_EXPR:
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
+      if (target == 0 || modifier == EXPAND_STACK_PARM)
+       target = gen_reg_rtx (mode);
+
+      if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == INTEGER_TYPE
+          && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))))
+          || (TREE_CODE (type) == INTEGER_TYPE && TYPE_UNSIGNED (type)))
+       expand_fixed_convert (target, op0, 1, TYPE_SATURATING (type));
+      else
+       expand_fixed_convert (target, op0, 0, TYPE_SATURATING (type));
+      return target;
+
     case FIX_TRUNC_EXPR:
       op0 = expand_normal (TREE_OPERAND (exp, 0));
       if (target == 0 || modifier == EXPAND_STACK_PARM)
@@ -8767,6 +8836,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case RSHIFT_EXPR:
     case LROTATE_EXPR:
     case RROTATE_EXPR:
+      /* If this is a fixed-point operation, then we cannot use the code
+        below because "expand_shift" doesn't support sat/no-sat fixed-point
+         shifts.   */
+      if (ALL_FIXED_POINT_MODE_P (mode))
+       goto binop;
+
       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
        subtarget = 0;
       if (modifier == EXPAND_STACK_PARM)
@@ -9583,7 +9658,8 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
     }
 
   /* Put a constant second.  */
-  if (TREE_CODE (arg0) == REAL_CST || TREE_CODE (arg0) == INTEGER_CST)
+  if (TREE_CODE (arg0) == REAL_CST || TREE_CODE (arg0) == INTEGER_CST
+      || TREE_CODE (arg0) == FIXED_CST)
     {
       tem = arg0; arg0 = arg1; arg1 = tem;
       code = swap_condition (code);
@@ -9887,7 +9963,11 @@ vector_mode_valid_p (enum machine_mode mode)
 
   /* Doh!  What's going on?  */
   if (class != MODE_VECTOR_INT
-      && class != MODE_VECTOR_FLOAT)
+      && class != MODE_VECTOR_FLOAT
+      && class != MODE_VECTOR_FRACT
+      && class != MODE_VECTOR_UFRACT
+      && class != MODE_VECTOR_ACCUM
+      && class != MODE_VECTOR_UACCUM)
     return 0;
 
   /* Hardware support.  Woo hoo!  */
@@ -9931,6 +10011,9 @@ const_vector_from_tree (tree exp)
       if (TREE_CODE (elt) == REAL_CST)
        RTVEC_ELT (v, i) = CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (elt),
                                                         inner);
+      else if (TREE_CODE (elt) == FIXED_CST)
+       RTVEC_ELT (v, i) = CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (elt),
+                                                        inner);
       else
        RTVEC_ELT (v, i) = immed_double_const (TREE_INT_CST_LOW (elt),
                                               TREE_INT_CST_HIGH (elt),
index 44c48c7..c5d0df2 100644 (file)
@@ -50,6 +50,7 @@ along with GCC; see the file COPYING3.  If not see
    only full integer modes should be considered for the next mode, and $F
    means that only float modes should be considered.
    $P means that both full and partial integer modes should be considered.
+   $Q means that only fixed-point modes should be considered.
 
    $V means to emit 'v' if the first mode is a MODE_FLOAT mode.
 
@@ -67,14 +68,28 @@ static const char * const optabs[] =
   "convert_optab_handler (sfloat_optab, $B, $A)->insn_code = CODE_FOR_$(float$I$a$F$b2$)",
   "convert_optab_handler (ufloat_optab, $B, $A)->insn_code = CODE_FOR_$(floatuns$I$a$F$b2$)",
   "convert_optab_handler (trunc_optab, $B, $A)->insn_code = CODE_FOR_$(trunc$a$b2$)",
+  "convert_optab_handler (fract_optab, $B, $A)->insn_code = CODE_FOR_$(fract$a$b2$)",
+  "convert_optab_handler (fractuns_optab, $B, $A)->insn_code = CODE_FOR_$(fractuns$I$a$Q$b2$)",
+  "convert_optab_handler (fractuns_optab, $B, $A)->insn_code = CODE_FOR_$(fractuns$Q$a$I$b2$)",
+  "convert_optab_handler (satfract_optab, $B, $A)->insn_code = CODE_FOR_$(satfract$a$Q$b2$)",
+  "convert_optab_handler (satfractuns_optab, $B, $A)->insn_code = CODE_FOR_$(satfractuns$I$a$Q$b2$)",
   "optab_handler (add_optab, $A)->insn_code = CODE_FOR_$(add$P$a3$)",
   "optab_handler (addv_optab, $A)->insn_code =\n\
     optab_handler (add_optab, $A)->insn_code = CODE_FOR_$(add$F$a3$)",
   "optab_handler (addv_optab, $A)->insn_code = CODE_FOR_$(addv$I$a3$)",
+  "optab_handler (add_optab, $A)->insn_code = CODE_FOR_$(add$Q$a3$)",
+  "optab_handler (ssadd_optab, $A)->insn_code = CODE_FOR_$(ssadd$Q$a3$)",
+  "optab_handler (usadd_optab, $A)->insn_code = CODE_FOR_$(usadd$Q$a3$)",
   "optab_handler (sub_optab, $A)->insn_code = CODE_FOR_$(sub$P$a3$)",
   "optab_handler (subv_optab, $A)->insn_code =\n\
     optab_handler (sub_optab, $A)->insn_code = CODE_FOR_$(sub$F$a3$)",
   "optab_handler (subv_optab, $A)->insn_code = CODE_FOR_$(subv$I$a3$)",
+  "optab_handler (sub_optab, $A)->insn_code = CODE_FOR_$(sub$Q$a3$)",
+  "optab_handler (sssub_optab, $A)->insn_code = CODE_FOR_$(sssub$Q$a3$)",
+  "optab_handler (ussub_optab, $A)->insn_code = CODE_FOR_$(ussub$Q$a3$)",
+  "optab_handler (smul_optab, $A)->insn_code = CODE_FOR_$(mul$Q$a3$)",
+  "optab_handler (ssmul_optab, $A)->insn_code = CODE_FOR_$(ssmul$Q$a3$)",
+  "optab_handler (usmul_optab, $A)->insn_code = CODE_FOR_$(usmul$Q$a3$)",
   "optab_handler (smul_optab, $A)->insn_code = CODE_FOR_$(mul$P$a3$)",
   "optab_handler (smulv_optab, $A)->insn_code =\n\
     optab_handler (smul_optab, $A)->insn_code = CODE_FOR_$(mul$F$a3$)",
@@ -86,11 +101,18 @@ static const char * const optabs[] =
   "optab_handler (usmul_widen_optab, $B)->insn_code = CODE_FOR_$(usmul$a$b3$)$N",
   "optab_handler (smadd_widen_optab, $B)->insn_code = CODE_FOR_$(madd$a$b4$)$N",
   "optab_handler (umadd_widen_optab, $B)->insn_code = CODE_FOR_$(umadd$a$b4$)$N",
+  "optab_handler (ssmadd_widen_optab, $B)->insn_code = CODE_FOR_$(ssmadd$a$b4$)$N",
+  "optab_handler (usmadd_widen_optab, $B)->insn_code = CODE_FOR_$(usmadd$a$b4$)$N",
   "optab_handler (smsub_widen_optab, $B)->insn_code = CODE_FOR_$(msub$a$b4$)$N",
   "optab_handler (umsub_widen_optab, $B)->insn_code = CODE_FOR_$(umsub$a$b4$)$N",
+  "optab_handler (ssmsub_widen_optab, $B)->insn_code = CODE_FOR_$(ssmsub$a$b4$)$N",
+  "optab_handler (usmsub_widen_optab, $B)->insn_code = CODE_FOR_$(usmsub$a$b4$)$N",
   "optab_handler (sdiv_optab, $A)->insn_code = CODE_FOR_$(div$a3$)",
+  "optab_handler (ssdiv_optab, $A)->insn_code = CODE_FOR_$(ssdiv$Q$a3$)",
   "optab_handler (sdivv_optab, $A)->insn_code = CODE_FOR_$(div$V$I$a3$)",
   "optab_handler (udiv_optab, $A)->insn_code = CODE_FOR_$(udiv$I$a3$)",
+  "optab_handler (udiv_optab, $A)->insn_code = CODE_FOR_$(udiv$Q$a3$)",
+  "optab_handler (usdiv_optab, $A)->insn_code = CODE_FOR_$(usdiv$Q$a3$)",
   "optab_handler (sdivmod_optab, $A)->insn_code = CODE_FOR_$(divmod$a4$)",
   "optab_handler (udivmod_optab, $A)->insn_code = CODE_FOR_$(udivmod$a4$)",
   "optab_handler (smod_optab, $A)->insn_code = CODE_FOR_$(mod$a3$)",
@@ -102,6 +124,8 @@ static const char * const optabs[] =
   "optab_handler (ior_optab, $A)->insn_code = CODE_FOR_$(ior$a3$)",
   "optab_handler (xor_optab, $A)->insn_code = CODE_FOR_$(xor$a3$)",
   "optab_handler (ashl_optab, $A)->insn_code = CODE_FOR_$(ashl$a3$)",
+  "optab_handler (ssashl_optab, $A)->insn_code = CODE_FOR_$(ssashl$Q$a3$)",
+  "optab_handler (usashl_optab, $A)->insn_code = CODE_FOR_$(usashl$Q$a3$)",
   "optab_handler (ashr_optab, $A)->insn_code = CODE_FOR_$(ashr$a3$)",
   "optab_handler (lshr_optab, $A)->insn_code = CODE_FOR_$(lshr$a3$)",
   "optab_handler (rotl_optab, $A)->insn_code = CODE_FOR_$(rotl$a3$)",
@@ -116,6 +140,9 @@ static const char * const optabs[] =
   "optab_handler (negv_optab, $A)->insn_code =\n\
     optab_handler (neg_optab, $A)->insn_code = CODE_FOR_$(neg$F$a2$)",
   "optab_handler (negv_optab, $A)->insn_code = CODE_FOR_$(negv$I$a2$)",
+  "optab_handler (neg_optab, $A)->insn_code = CODE_FOR_$(neg$Q$a2$)",
+  "optab_handler (ssneg_optab, $A)->insn_code = CODE_FOR_$(ssneg$Q$a2$)",
+  "optab_handler (usneg_optab, $A)->insn_code = CODE_FOR_$(usneg$Q$a2$)",
   "optab_handler (abs_optab, $A)->insn_code = CODE_FOR_$(abs$P$a2$)",
   "optab_handler (absv_optab, $A)->insn_code =\n\
     optab_handler (abs_optab, $A)->insn_code = CODE_FOR_$(abs$F$a2$)",
@@ -267,6 +294,7 @@ gen_insn (rtx insn)
   for (pindex = 0; pindex < ARRAY_SIZE (optabs); pindex++)
     {
       int force_float = 0, force_int = 0, force_partial_int = 0;
+      int force_fixed = 0;
       int force_consec = 0;
       int matches = 1;
 
@@ -296,6 +324,9 @@ gen_insn (rtx insn)
              case 'F':
                force_float = 1;
                break;
+             case 'Q':
+               force_fixed = 1;
+               break;
              case 'V':
                 break;
              case 'c':
@@ -342,7 +373,16 @@ gen_insn (rtx insn)
                            || mode_class[i] == MODE_FLOAT 
                            || mode_class[i] == MODE_DECIMAL_FLOAT
                            || mode_class[i] == MODE_COMPLEX_FLOAT
-                           || mode_class[i] == MODE_VECTOR_FLOAT))
+                           || mode_class[i] == MODE_VECTOR_FLOAT)
+                       && (! force_fixed
+                           || mode_class[i] == MODE_FRACT
+                           || mode_class[i] == MODE_UFRACT
+                           || mode_class[i] == MODE_ACCUM
+                           || mode_class[i] == MODE_UACCUM
+                           || mode_class[i] == MODE_VECTOR_FRACT
+                           || mode_class[i] == MODE_VECTOR_UFRACT
+                           || mode_class[i] == MODE_VECTOR_ACCUM
+                           || mode_class[i] == MODE_VECTOR_UACCUM))
                      break;
                  }
 
@@ -353,7 +393,7 @@ gen_insn (rtx insn)
                else
                  m2 = i, np += strlen (GET_MODE_NAME(i));
 
-               force_int = force_partial_int = force_float = 0;
+               force_int = force_partial_int = force_float = force_fixed = 0;
                break;
 
              default:
diff --git a/gcc/ginclude/stdfix.h b/gcc/ginclude/stdfix.h
new file mode 100644 (file)
index 0000000..5e7cb2e
--- /dev/null
@@ -0,0 +1,207 @@
+/* Copyright (C) 2007 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.  */
+
+/* As a special exception, if you include this header file into source
+   files compiled by GCC, this header file does not by itself cause
+   the resulting executable to be covered by the GNU General Public
+   License.  This exception does not however invalidate any other
+   reasons why the executable file might be covered by the GNU General
+   Public License.  */
+
+/* ISO/IEC JTC1 SC22 WG14 N1169
+ * Date: 2006-04-04
+ * ISO/IEC TR 18037
+ * Programming languages - C - Extensions to support embedded processors
+ */
+
+#ifndef _STDFIX_H
+#define _STDFIX_H
+
+/* 7.18a.1 Introduction.  */
+
+#undef fract
+#undef accum
+#undef sat
+#define fract          _Fract
+#define accum          _Accum
+#define sat            _Sat
+
+/* 7.18a.3 Precision macros.  */
+
+#undef SFRACT_FBIT
+#undef SFRACT_MIN
+#undef SFRACT_MAX
+#undef SFRACT_EPSILON
+#define SFRACT_FBIT    __SFRACT_FBIT__
+#define SFRACT_MIN     __SFRACT_MIN__
+#define SFRACT_MAX     __SFRACT_MAX__
+#define SFRACT_EPSILON __SFRACT_EPSILON__
+
+#undef USFRACT_FBIT
+#undef USFRACT_MIN
+#undef USFRACT_MAX
+#undef USFRACT_EPSILON
+#define USFRACT_FBIT   __USFRACT_FBIT__
+#define USFRACT_MIN    __USFRACT_MIN__         /* GCC extension.  */
+#define USFRACT_MAX    __USFRACT_MAX__
+#define USFRACT_EPSILON        __USFRACT_EPSILON__
+
+#undef FRACT_FBIT
+#undef FRACT_MIN
+#undef FRACT_MAX
+#undef FRACT_EPSILON
+#define FRACT_FBIT     __FRACT_FBIT__
+#define FRACT_MIN      __FRACT_MIN__
+#define FRACT_MAX      __FRACT_MAX__
+#define FRACT_EPSILON  __FRACT_EPSILON__
+
+#undef UFRACT_FBIT
+#undef UFRACT_MIN
+#undef UFRACT_MAX
+#undef UFRACT_EPSILON
+#define UFRACT_FBIT    __UFRACT_FBIT__
+#define UFRACT_MIN     __UFRACT_MIN__          /* GCC extension.  */
+#define UFRACT_MAX     __UFRACT_MAX__
+#define UFRACT_EPSILON __UFRACT_EPSILON__
+
+#undef LFRACT_FBIT
+#undef LFRACT_MIN
+#undef LFRACT_MAX
+#undef LFRACT_EPSILON
+#define LFRACT_FBIT    __LFRACT_FBIT__
+#define LFRACT_MIN     __LFRACT_MIN__
+#define LFRACT_MAX     __LFRACT_MAX__
+#define LFRACT_EPSILON __LFRACT_EPSILON__
+
+#undef ULFRACT_FBIT
+#undef ULFRACT_MIN
+#undef ULFRACT_MAX
+#undef ULFRACT_EPSILON
+#define ULFRACT_FBIT   __ULFRACT_FBIT__
+#define ULFRACT_MIN    __ULFRACT_MIN__         /* GCC extension.  */
+#define ULFRACT_MAX    __ULFRACT_MAX__
+#define ULFRACT_EPSILON        __ULFRACT_EPSILON__
+
+#undef LLFRACT_FBIT
+#undef LLFRACT_MIN
+#undef LLFRACT_MAX
+#undef LLFRACT_EPSILON
+#define LLFRACT_FBIT   __LLFRACT_FBIT__        /* GCC extension.  */
+#define LLFRACT_MIN    __LLFRACT_MIN__         /* GCC extension.  */
+#define LLFRACT_MAX    __LLFRACT_MAX__         /* GCC extension.  */
+#define LLFRACT_EPSILON        __LLFRACT_EPSILON__     /* GCC extension.  */
+
+#undef ULLFRACT_FBIT
+#undef ULLFRACT_MIN
+#undef ULLFRACT_MAX
+#undef ULLFRACT_EPSILON
+#define ULLFRACT_FBIT  __ULLFRACT_FBIT__       /* GCC extension.  */
+#define ULLFRACT_MIN   __ULLFRACT_MIN__        /* GCC extension.  */
+#define ULLFRACT_MAX   __ULLFRACT_MAX__        /* GCC extension.  */
+#define ULLFRACT_EPSILON       __ULLFRACT_EPSILON__    /* GCC extension.  */
+
+#undef SACCUM_FBIT
+#undef SACCUM_IBIT
+#undef SACCUM_MIN
+#undef SACCUM_MAX
+#undef SACCUM_EPSILON
+#define SACCUM_FBIT    __SACCUM_FBIT__
+#define SACCUM_IBIT    __SACCUM_IBIT__
+#define SACCUM_MIN     __SACCUM_MIN__
+#define SACCUM_MAX     __SACCUM_MAX__
+#define SACCUM_EPSILON __SACCUM_EPSILON__
+
+#undef USACCUM_FBIT
+#undef USACCUM_IBIT
+#undef USACCUM_MIN
+#undef USACCUM_MAX
+#undef USACCUM_EPSILON
+#define USACCUM_FBIT   __USACCUM_FBIT__
+#define USACCUM_IBIT   __USACCUM_IBIT__
+#define USACCUM_MIN    __USACCUM_MIN__         /* GCC extension.  */
+#define USACCUM_MAX    __USACCUM_MAX__
+#define USACCUM_EPSILON        __USACCUM_EPSILON__
+
+#undef ACCUM_FBIT
+#undef ACCUM_IBIT
+#undef ACCUM_MIN
+#undef ACCUM_MAX
+#undef ACCUM_EPSILON
+#define ACCUM_FBIT     __ACCUM_FBIT__
+#define ACCUM_IBIT     __ACCUM_IBIT__
+#define ACCUM_MIN      __ACCUM_MIN__
+#define ACCUM_MAX      __ACCUM_MAX__
+#define ACCUM_EPSILON  __ACCUM_EPSILON__
+
+#undef UACCUM_FBIT
+#undef UACCUM_IBIT
+#undef UACCUM_MIN
+#undef UACCUM_MAX
+#undef UACCUM_EPSILON
+#define UACCUM_FBIT    __UACCUM_FBIT__
+#define UACCUM_IBIT    __UACCUM_IBIT__
+#define UACCUM_MIN     __UACCUM_MIN__          /* GCC extension.  */
+#define UACCUM_MAX     __UACCUM_MAX__
+#define UACCUM_EPSILON __UACCUM_EPSILON__
+
+#undef LACCUM_FBIT
+#undef LACCUM_IBIT
+#undef LACCUM_MIN
+#undef LACCUM_MAX
+#undef LACCUM_EPSILON
+#define LACCUM_FBIT    __LACCUM_FBIT__
+#define LACCUM_IBIT    __LACCUM_IBIT__
+#define LACCUM_MIN     __LACCUM_MIN__
+#define LACCUM_MAX     __LACCUM_MAX__
+#define LACCUM_EPSILON __LACCUM_EPSILON__
+
+#undef ULACCUM_FBIT
+#undef ULACCUM_IBIT
+#undef ULACCUM_MIN
+#undef ULACCUM_MAX
+#undef ULACCUM_EPSILON
+#define ULACCUM_FBIT   __ULACCUM_FBIT__
+#define ULACCUM_IBIT   __ULACCUM_IBIT__
+#define ULACCUM_MIN    __ULACCUM_MIN__         /* GCC extension.  */
+#define ULACCUM_MAX    __ULACCUM_MAX__
+#define ULACCUM_EPSILON        __ULACCUM_EPSILON__
+
+#undef LLACCUM_FBIT
+#undef LLACCUM_IBIT
+#undef LLACCUM_MIN
+#undef LLACCUM_MAX
+#undef LLACCUM_EPSILON
+#define LLACCUM_FBIT   __LLACCUM_FBIT__        /* GCC extension.  */
+#define LLACCUM_IBIT   __LLACCUM_IBIT__        /* GCC extension.  */
+#define LLACCUM_MIN    __LLACCUM_MIN__         /* GCC extension.  */
+#define LLACCUM_MAX    __LLACCUM_MAX__         /* GCC extension.  */
+#define LLACCUM_EPSILON        __LLACCUM_EPSILON__     /* GCC extension.  */
+
+#undef ULLACCUM_FBIT
+#undef ULLACCUM_IBIT
+#undef ULLACCUM_MIN
+#undef ULLACCUM_MAX
+#undef ULLACCUM_EPSILON
+#define ULLACCUM_FBIT  __ULLACCUM_FBIT__       /* GCC extension.  */
+#define ULLACCUM_IBIT  __ULLACCUM_IBIT__       /* GCC extension.  */
+#define ULLACCUM_MIN   __ULLACCUM_MIN__        /* GCC extension.  */
+#define ULLACCUM_MAX   __ULLACCUM_MAX__        /* GCC extension.  */
+#define ULLACCUM_EPSILON       __ULLACCUM_EPSILON__    /* GCC extension.  */
+
+#endif /* _STDFIX_H */
index ff4c3dd..b1b32ef 100644 (file)
@@ -358,9 +358,13 @@ optab_for_tree_code (enum tree_code code, const_tree type)
     case FLOOR_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case EXACT_DIV_EXPR:
+      if (TYPE_SATURATING(type))
+       return TYPE_UNSIGNED(type) ? usdiv_optab : ssdiv_optab;
       return TYPE_UNSIGNED (type) ? udiv_optab : sdiv_optab;
 
     case LSHIFT_EXPR:
+      if (TYPE_SATURATING(type))
+       return TYPE_UNSIGNED(type) ? usashl_optab : ssashl_optab;
       return ashl_optab;
 
     case RSHIFT_EXPR:
@@ -448,15 +452,23 @@ optab_for_tree_code (enum tree_code code, const_tree type)
     {
     case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
+      if (TYPE_SATURATING(type))
+       return TYPE_UNSIGNED(type) ? usadd_optab : ssadd_optab;
       return trapv ? addv_optab : add_optab;
 
     case MINUS_EXPR:
+      if (TYPE_SATURATING(type))
+       return TYPE_UNSIGNED(type) ? ussub_optab : sssub_optab;
       return trapv ? subv_optab : sub_optab;
 
     case MULT_EXPR:
+      if (TYPE_SATURATING(type))
+       return TYPE_UNSIGNED(type) ? usmul_optab : ssmul_optab;
       return trapv ? smulv_optab : smul_optab;
 
     case NEGATE_EXPR:
+      if (TYPE_SATURATING(type))
+       return TYPE_UNSIGNED(type) ? usneg_optab : ssneg_optab;
       return trapv ? negv_optab : neg_optab;
 
     case ABS_EXPR:
@@ -1327,6 +1339,8 @@ shift_optab_p (optab binoptab)
   switch (binoptab->code)
     {
     case ASHIFT:
+    case SS_ASHIFT:
+    case US_ASHIFT:
     case ASHIFTRT:
     case LSHIFTRT:
     case ROTATE:
@@ -5442,6 +5456,57 @@ expand_fix (rtx to, rtx from, int unsignedp)
     }
 }
 
+/* Generate code to convert FROM or TO a fixed-point.
+   If UINTP is true, either TO or FROM is an unsigned integer.
+   If SATP is true, we need to saturate the result.  */
+
+void
+expand_fixed_convert (rtx to, rtx from, int uintp, int satp)
+{
+  enum machine_mode to_mode = GET_MODE (to);
+  enum machine_mode from_mode = GET_MODE (from);
+  convert_optab tab;
+  enum rtx_code this_code;
+  enum insn_code code;
+  rtx insns, value;
+  rtx libfunc;
+
+  if (to_mode == from_mode)
+    {
+      emit_move_insn (to, from);
+      return;
+    }
+
+  if (uintp)
+    {
+      tab = satp ? satfractuns_optab : fractuns_optab;
+      this_code = satp ? UNSIGNED_SAT_FRACT : UNSIGNED_FRACT_CONVERT;
+    }
+  else
+    {
+      tab = satp ? satfract_optab : fract_optab;
+      this_code = satp ? SAT_FRACT : FRACT_CONVERT;
+    }
+  code = tab->handlers[to_mode][from_mode].insn_code;
+  if (code != CODE_FOR_nothing)
+    {
+      emit_unop_insn (code, to, from, this_code);
+      return;
+    }
+
+  libfunc = convert_optab_libfunc (tab, to_mode, from_mode);
+  gcc_assert (libfunc);
+
+  start_sequence ();
+  value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST, to_mode,
+                                  1, from, from_mode);
+  insns = get_insns ();
+  end_sequence ();
+
+  emit_libcall_block (insns, to, value,
+                     gen_rtx_fmt_e (tab->code, to_mode, from));
+}
+
 /* Generate code to convert FROM to fixed point and store in TO.  FROM
    must be floating point, TO must be signed.  Use the conversion optab
    TAB to do the conversion.  */
@@ -5625,6 +5690,41 @@ gen_fp_libfunc (optab optable, const char *opname, char suffix,
     }
 }
 
+/* Like gen_libfunc, but verify that fixed-point operation is involved.  */
+
+static void
+gen_fixed_libfunc (optab optable, const char *opname, char suffix,
+                  enum machine_mode mode)
+{
+  if (!ALL_FIXED_POINT_MODE_P (mode))
+    return;
+  gen_libfunc (optable, opname, suffix, mode);
+}
+
+/* Like gen_libfunc, but verify that signed fixed-point operation is
+   involved.  */
+
+static void
+gen_signed_fixed_libfunc (optab optable, const char *opname, char suffix,
+                         enum machine_mode mode)
+{
+  if (!SIGNED_FIXED_POINT_MODE_P (mode))
+    return;
+  gen_libfunc (optable, opname, suffix, mode);
+}
+
+/* Like gen_libfunc, but verify that unsigned fixed-point operation is
+   involved.  */
+
+static void
+gen_unsigned_fixed_libfunc (optab optable, const char *opname, char suffix,
+                           enum machine_mode mode)
+{
+  if (!UNSIGNED_FIXED_POINT_MODE_P (mode))
+    return;
+  gen_libfunc (optable, opname, suffix, mode);
+}
+
 /* Like gen_libfunc, but verify that FP or INT operation is involved.  */
 
 static void
@@ -5657,6 +5757,75 @@ gen_intv_fp_libfunc (optab optable, const char *name, char suffix,
     }
 }
 
+/* Like gen_libfunc, but verify that FP or INT or FIXED operation is
+   involved.  */
+
+static void
+gen_int_fp_fixed_libfunc (optab optable, const char *name, char suffix,
+                         enum machine_mode mode)
+{
+  if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
+    gen_fp_libfunc (optable, name, suffix, mode);
+  if (INTEGRAL_MODE_P (mode))
+    gen_int_libfunc (optable, name, suffix, mode);
+  if (ALL_FIXED_POINT_MODE_P (mode))
+    gen_fixed_libfunc (optable, name, suffix, mode);
+}
+
+/* Like gen_libfunc, but verify that FP or INT or signed FIXED operation is
+   involved.  */
+
+static void
+gen_int_fp_signed_fixed_libfunc (optab optable, const char *name, char suffix,
+                                enum machine_mode mode)
+{
+  if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
+    gen_fp_libfunc (optable, name, suffix, mode);
+  if (INTEGRAL_MODE_P (mode))
+    gen_int_libfunc (optable, name, suffix, mode);
+  if (SIGNED_FIXED_POINT_MODE_P (mode))
+    gen_signed_fixed_libfunc (optable, name, suffix, mode);
+}
+
+/* Like gen_libfunc, but verify that INT or FIXED operation is
+   involved.  */
+
+static void
+gen_int_fixed_libfunc (optab optable, const char *name, char suffix,
+                      enum machine_mode mode)
+{
+  if (INTEGRAL_MODE_P (mode))
+    gen_int_libfunc (optable, name, suffix, mode);
+  if (ALL_FIXED_POINT_MODE_P (mode))
+    gen_fixed_libfunc (optable, name, suffix, mode);
+}
+
+/* Like gen_libfunc, but verify that INT or signed FIXED operation is
+   involved.  */
+
+static void
+gen_int_signed_fixed_libfunc (optab optable, const char *name, char suffix,
+                             enum machine_mode mode)
+{
+  if (INTEGRAL_MODE_P (mode))
+    gen_int_libfunc (optable, name, suffix, mode);
+  if (SIGNED_FIXED_POINT_MODE_P (mode))
+    gen_signed_fixed_libfunc (optable, name, suffix, mode);
+}
+
+/* Like gen_libfunc, but verify that INT or unsigned FIXED operation is
+   involved.  */
+
+static void
+gen_int_unsigned_fixed_libfunc (optab optable, const char *name, char suffix,
+                               enum machine_mode mode)
+{
+  if (INTEGRAL_MODE_P (mode))
+    gen_int_libfunc (optable, name, suffix, mode);
+  if (UNSIGNED_FIXED_POINT_MODE_P (mode))
+    gen_unsigned_fixed_libfunc (optable, name, suffix, mode);
+}
+
 /* Initialize the libfunc fields of an entire group of entries of an
    inter-mode-class conversion optab.  The string formation rules are
    similar to the ones for init_libfuncs, above, but instead of having
@@ -5907,6 +6076,84 @@ gen_extend_conv_libfunc (convert_optab tab,
     gen_intraclass_conv_libfunc (tab, opname, tmode, fmode);
 }
 
+/* Pick proper libcall for fract_optab.  We need to chose if we do
+   interclass or intraclass.  */
+
+static void
+gen_fract_conv_libfunc (convert_optab tab,
+                       const char *opname,
+                       enum machine_mode tmode,
+                       enum machine_mode fmode)
+{
+  if (tmode == fmode)
+    return;
+  if (!(ALL_FIXED_POINT_MODE_P (tmode) || ALL_FIXED_POINT_MODE_P (fmode)))
+    return;
+
+  if (GET_MODE_CLASS (tmode) == GET_MODE_CLASS (fmode))
+    gen_intraclass_conv_libfunc (tab, opname, tmode, fmode);
+  else
+    gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
+}
+
+/* Pick proper libcall for fractuns_optab.  */
+
+static void
+gen_fractuns_conv_libfunc (convert_optab tab,
+                          const char *opname,
+                          enum machine_mode tmode,
+                          enum machine_mode fmode)
+{
+  if (tmode == fmode)
+    return;
+  /* One mode must be a fixed-point mode, and the other must be an integer
+     mode. */
+  if (!((ALL_FIXED_POINT_MODE_P (tmode) && GET_MODE_CLASS (fmode) == MODE_INT)
+       || (ALL_FIXED_POINT_MODE_P (fmode)
+           && GET_MODE_CLASS (tmode) == MODE_INT)))
+    return;
+
+  gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
+}
+
+/* Pick proper libcall for satfract_optab.  We need to chose if we do
+   interclass or intraclass.  */
+
+static void
+gen_satfract_conv_libfunc (convert_optab tab,
+                          const char *opname,
+                          enum machine_mode tmode,
+                          enum machine_mode fmode)
+{
+  if (tmode == fmode)
+    return;
+  /* TMODE must be a fixed-point mode.  */
+  if (!ALL_FIXED_POINT_MODE_P (tmode))
+    return;
+
+  if (GET_MODE_CLASS (tmode) == GET_MODE_CLASS (fmode))
+    gen_intraclass_conv_libfunc (tab, opname, tmode, fmode);
+  else
+    gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
+}
+
+/* Pick proper libcall for satfractuns_optab.  */
+
+static void
+gen_satfractuns_conv_libfunc (convert_optab tab,
+                             const char *opname,
+                             enum machine_mode tmode,
+                             enum machine_mode fmode)
+{
+  if (tmode == fmode)
+    return;
+  /* TMODE must be a fixed-point mode, and FMODE must be an integer mode. */
+  if (!(ALL_FIXED_POINT_MODE_P (tmode) && GET_MODE_CLASS (fmode) == MODE_INT))
+    return;
+
+  gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
+}
+
 rtx
 init_one_libfunc (const char *name)
 {
@@ -6013,7 +6260,13 @@ init_optabs (void)
   addv_optab = init_optabv (PLUS);
   sub_optab = init_optab (MINUS);
   subv_optab = init_optabv (MINUS);
+  ssadd_optab = init_optab (SS_PLUS);
+  usadd_optab = init_optab (US_PLUS);
+  sssub_optab = init_optab (SS_MINUS);
+  ussub_optab = init_optab (US_MINUS);
   smul_optab = init_optab (MULT);
+  ssmul_optab = init_optab (SS_MULT);
+  usmul_optab = init_optab (US_MULT);
   smulv_optab = init_optabv (MULT);
   smul_highpart_optab = init_optab (UNKNOWN);
   umul_highpart_optab = init_optab (UNKNOWN);
@@ -6022,9 +6275,15 @@ init_optabs (void)
   usmul_widen_optab = init_optab (UNKNOWN);
   smadd_widen_optab = init_optab (UNKNOWN);
   umadd_widen_optab = init_optab (UNKNOWN);
+  ssmadd_widen_optab = init_optab (UNKNOWN);
+  usmadd_widen_optab = init_optab (UNKNOWN);
   smsub_widen_optab = init_optab (UNKNOWN);
   umsub_widen_optab = init_optab (UNKNOWN);
+  ssmsub_widen_optab = init_optab (UNKNOWN);
+  usmsub_widen_optab = init_optab (UNKNOWN);
   sdiv_optab = init_optab (DIV);
+  ssdiv_optab = init_optab (SS_DIV);
+  usdiv_optab = init_optab (US_DIV);
   sdivv_optab = init_optabv (DIV);
   sdivmod_optab = init_optab (UNKNOWN);
   udiv_optab = init_optab (UDIV);
@@ -6038,6 +6297,8 @@ init_optabs (void)
   ior_optab = init_optab (IOR);
   xor_optab = init_optab (XOR);
   ashl_optab = init_optab (ASHIFT);
+  ssashl_optab = init_optab (SS_ASHIFT);
+  usashl_optab = init_optab (US_ASHIFT);
   ashr_optab = init_optab (ASHIFTRT);
   lshr_optab = init_optab (LSHIFTRT);
   rotl_optab = init_optab (ROTATE);
@@ -6069,6 +6330,8 @@ init_optabs (void)
   unord_optab = init_optab (UNORDERED);
 
   neg_optab = init_optab (NEG);
+  ssneg_optab = init_optab (SS_NEG);
+  usneg_optab = init_optab (US_NEG);
   negv_optab = init_optabv (NEG);
   abs_optab = init_optab (ABS);
   absv_optab = init_optabv (ABS);
@@ -6175,6 +6438,11 @@ init_optabs (void)
   lfloor_optab = init_convert_optab (UNKNOWN);
   lceil_optab = init_convert_optab (UNKNOWN);
 
+  fract_optab = init_convert_optab (FRACT_CONVERT);
+  fractuns_optab = init_convert_optab (UNSIGNED_FRACT_CONVERT);
+  satfract_optab = init_convert_optab (SAT_FRACT);
+  satfractuns_optab = init_convert_optab (UNSIGNED_SAT_FRACT);
+
   for (i = 0; i < NUM_MACHINE_MODES; i++)
     {
       movmem_optab[i] = CODE_FOR_nothing;
@@ -6215,31 +6483,55 @@ init_optabs (void)
   /* Initialize the optabs with the names of the library functions.  */
   add_optab->libcall_basename = "add";
   add_optab->libcall_suffix = '3';
-  add_optab->libcall_gen = gen_int_fp_libfunc;
+  add_optab->libcall_gen = gen_int_fp_fixed_libfunc;
   addv_optab->libcall_basename = "add";
   addv_optab->libcall_suffix = '3';
   addv_optab->libcall_gen = gen_intv_fp_libfunc;
+  ssadd_optab->libcall_basename = "ssadd";
+  ssadd_optab->libcall_suffix = '3';
+  ssadd_optab->libcall_gen = gen_signed_fixed_libfunc;
+  usadd_optab->libcall_basename = "usadd";
+  usadd_optab->libcall_suffix = '3';
+  usadd_optab->libcall_gen = gen_unsigned_fixed_libfunc;
   sub_optab->libcall_basename = "sub";
   sub_optab->libcall_suffix = '3';
-  sub_optab->libcall_gen = gen_int_fp_libfunc;
+  sub_optab->libcall_gen = gen_int_fp_fixed_libfunc;
   subv_optab->libcall_basename = "sub";
   subv_optab->libcall_suffix = '3';
   subv_optab->libcall_gen = gen_intv_fp_libfunc;
+  sssub_optab->libcall_basename = "sssub";
+  sssub_optab->libcall_suffix = '3';
+  sssub_optab->libcall_gen = gen_signed_fixed_libfunc;
+  ussub_optab->libcall_basename = "ussub";
+  ussub_optab->libcall_suffix = '3';
+  ussub_optab->libcall_gen = gen_unsigned_fixed_libfunc;
   smul_optab->libcall_basename = "mul";
   smul_optab->libcall_suffix = '3';
-  smul_optab->libcall_gen = gen_int_fp_libfunc;
+  smul_optab->libcall_gen = gen_int_fp_fixed_libfunc;
   smulv_optab->libcall_basename = "mul";
   smulv_optab->libcall_suffix = '3';
   smulv_optab->libcall_gen = gen_intv_fp_libfunc;
+  ssmul_optab->libcall_basename = "ssmul";
+  ssmul_optab->libcall_suffix = '3';
+  ssmul_optab->libcall_gen = gen_signed_fixed_libfunc;
+  usmul_optab->libcall_basename = "usmul";
+  usmul_optab->libcall_suffix = '3';
+  usmul_optab->libcall_gen = gen_unsigned_fixed_libfunc;
   sdiv_optab->libcall_basename = "div";
   sdiv_optab->libcall_suffix = '3';
-  sdiv_optab->libcall_gen = gen_int_fp_libfunc;
+  sdiv_optab->libcall_gen = gen_int_fp_signed_fixed_libfunc;
   sdivv_optab->libcall_basename = "divv";
   sdivv_optab->libcall_suffix = '3';
   sdivv_optab->libcall_gen = gen_int_libfunc;
+  ssdiv_optab->libcall_basename = "ssdiv";
+  ssdiv_optab->libcall_suffix = '3';
+  ssdiv_optab->libcall_gen = gen_signed_fixed_libfunc;
   udiv_optab->libcall_basename = "udiv";
   udiv_optab->libcall_suffix = '3';
-  udiv_optab->libcall_gen = gen_int_libfunc;
+  udiv_optab->libcall_gen = gen_int_unsigned_fixed_libfunc;
+  usdiv_optab->libcall_basename = "usdiv";
+  usdiv_optab->libcall_suffix = '3';
+  usdiv_optab->libcall_gen = gen_unsigned_fixed_libfunc;
   sdivmod_optab->libcall_basename = "divmod";
   sdivmod_optab->libcall_suffix = '4';
   sdivmod_optab->libcall_gen = gen_int_libfunc;
@@ -6266,13 +6558,19 @@ init_optabs (void)
   xor_optab->libcall_gen = gen_int_libfunc;
   ashl_optab->libcall_basename = "ashl";
   ashl_optab->libcall_suffix = '3';
-  ashl_optab->libcall_gen = gen_int_libfunc;
+  ashl_optab->libcall_gen = gen_int_fixed_libfunc;
+  ssashl_optab->libcall_basename = "ssashl";
+  ssashl_optab->libcall_suffix = '3';
+  ssashl_optab->libcall_gen = gen_signed_fixed_libfunc;
+  usashl_optab->libcall_basename = "usashl";
+  usashl_optab->libcall_suffix = '3';
+  usashl_optab->libcall_gen = gen_unsigned_fixed_libfunc;
   ashr_optab->libcall_basename = "ashr";
   ashr_optab->libcall_suffix = '3';
-  ashr_optab->libcall_gen = gen_int_libfunc;
+  ashr_optab->libcall_gen = gen_int_signed_fixed_libfunc;
   lshr_optab->libcall_basename = "lshr";
   lshr_optab->libcall_suffix = '3';
-  lshr_optab->libcall_gen = gen_int_libfunc;
+  lshr_optab->libcall_gen = gen_int_unsigned_fixed_libfunc;
   smin_optab->libcall_basename = "min";
   smin_optab->libcall_suffix = '3';
   smin_optab->libcall_gen = gen_int_fp_libfunc;
@@ -6287,7 +6585,13 @@ init_optabs (void)
   umax_optab->libcall_gen = gen_int_libfunc;
   neg_optab->libcall_basename = "neg";
   neg_optab->libcall_suffix = '2';
-  neg_optab->libcall_gen = gen_int_fp_libfunc;
+  neg_optab->libcall_gen = gen_int_fp_fixed_libfunc;
+  ssneg_optab->libcall_basename = "ssneg";
+  ssneg_optab->libcall_suffix = '2';
+  ssneg_optab->libcall_gen = gen_signed_fixed_libfunc;
+  usneg_optab->libcall_basename = "usneg";
+  usneg_optab->libcall_suffix = '2';
+  usneg_optab->libcall_gen = gen_unsigned_fixed_libfunc;
   negv_optab->libcall_basename = "neg";
   negv_optab->libcall_suffix = '2';
   negv_optab->libcall_gen = gen_intv_fp_libfunc;
@@ -6314,7 +6618,7 @@ init_optabs (void)
      signed/unsigned.  */
   cmp_optab->libcall_basename = "cmp";
   cmp_optab->libcall_suffix = '2';
-  cmp_optab->libcall_gen = gen_int_fp_libfunc;
+  cmp_optab->libcall_gen = gen_int_fp_fixed_libfunc;
   ucmp_optab->libcall_basename = "ucmp";
   ucmp_optab->libcall_suffix = '2';
   ucmp_optab->libcall_gen = gen_int_libfunc;
@@ -6369,6 +6673,16 @@ init_optabs (void)
   trunc_optab->libcall_basename = "trunc";
   trunc_optab->libcall_gen = gen_trunc_conv_libfunc;
 
+  /* Conversions for fixed-point modes and other modes.  */
+  fract_optab->libcall_basename = "fract";
+  fract_optab->libcall_gen = gen_fract_conv_libfunc;
+  satfract_optab->libcall_basename = "satfract";
+  satfract_optab->libcall_gen = gen_satfract_conv_libfunc;
+  fractuns_optab->libcall_basename = "fractuns";
+  fractuns_optab->libcall_gen = gen_fractuns_conv_libfunc;
+  satfractuns_optab->libcall_basename = "satfractuns";
+  satfractuns_optab->libcall_gen = gen_satfractuns_conv_libfunc;
+
   /* The ffs function operates on `int'.  Fall back on it if we do not
      have a libgcc2 function for that width.  */
   if (INT_TYPE_SIZE < BITS_PER_WORD)
index a85b3f3..9dd9813 100644 (file)
@@ -75,6 +75,20 @@ typedef struct convert_optab *convert_optab;
 /* Enumeration of valid indexes into optab_table.  */
 enum optab_index
 {
+  /* Fixed-point operators with signed/unsigned saturation */
+  OTI_ssadd,
+  OTI_usadd,
+  OTI_sssub,
+  OTI_ussub,
+  OTI_ssmul,
+  OTI_usmul,
+  OTI_ssdiv,
+  OTI_usdiv,
+  OTI_ssneg,
+  OTI_usneg,
+  OTI_ssashl,
+  OTI_usashl,
+
   OTI_add,
   OTI_addv,
   OTI_sub,
@@ -97,12 +111,28 @@ enum optab_index
   /* Unsigned multiply and add with the result and addend one machine mode
      wider than the multiplicand and multiplier.  */
   OTI_umadd_widen,
+  /* Signed multiply and add with the result and addend one machine mode
+     wider than the multiplicand and multiplier.
+     All involved operations are saturating.  */
+  OTI_ssmadd_widen,
+  /* Unigned multiply and add with the result and addend one machine mode
+     wider than the multiplicand and multiplier.
+     All involved operations are saturating.  */
+  OTI_usmadd_widen,
   /* Signed multiply and subtract the result and minuend one machine mode
      wider than the multiplicand and multiplier.  */
   OTI_smsub_widen,
   /* Unsigned multiply and subtract the result and minuend one machine mode
      wider than the multiplicand and multiplier.  */
   OTI_umsub_widen,
+  /* Signed multiply and subtract the result and minuend one machine mode
+     wider than the multiplicand and multiplier.
+     All involved operations are saturating.  */
+  OTI_ssmsub_widen,
+  /* Unigned multiply and subtract the result and minuend one machine mode
+     wider than the multiplicand and multiplier.
+     All involved operations are saturating.  */
+  OTI_usmsub_widen,
 
   /* Signed divide */
   OTI_sdiv,
@@ -332,6 +362,19 @@ enum optab_index
 
 extern optab optab_table[OTI_MAX];
 
+#define ssadd_optab (optab_table[OTI_ssadd])
+#define usadd_optab (optab_table[OTI_usadd])
+#define sssub_optab (optab_table[OTI_sssub])
+#define ussub_optab (optab_table[OTI_ussub])
+#define ssmul_optab (optab_table[OTI_ssmul])
+#define usmul_optab (optab_table[OTI_usmul])
+#define ssdiv_optab (optab_table[OTI_ssdiv])
+#define usdiv_optab (optab_table[OTI_usdiv])
+#define ssneg_optab (optab_table[OTI_ssneg])
+#define usneg_optab (optab_table[OTI_usneg])
+#define ssashl_optab (optab_table[OTI_ssashl])
+#define usashl_optab (optab_table[OTI_usashl])
+
 #define add_optab (optab_table[OTI_add])
 #define sub_optab (optab_table[OTI_sub])
 #define smul_optab (optab_table[OTI_smul])
@@ -344,8 +387,12 @@ extern optab optab_table[OTI_MAX];
 #define usmul_widen_optab (optab_table[OTI_usmul_widen])
 #define smadd_widen_optab (optab_table[OTI_smadd_widen])
 #define umadd_widen_optab (optab_table[OTI_umadd_widen])
+#define ssmadd_widen_optab (optab_table[OTI_ssmadd_widen])
+#define usmadd_widen_optab (optab_table[OTI_usmadd_widen])
 #define smsub_widen_optab (optab_table[OTI_smsub_widen])
 #define umsub_widen_optab (optab_table[OTI_umsub_widen])
+#define ssmsub_widen_optab (optab_table[OTI_ssmsub_widen])
+#define usmsub_widen_optab (optab_table[OTI_usmsub_widen])
 #define sdiv_optab (optab_table[OTI_sdiv])
 #define smulv_optab (optab_table[OTI_smulv])
 #define sdivv_optab (optab_table[OTI_sdivv])
@@ -501,6 +548,11 @@ enum convert_optab_index
   COI_lfloor,
   COI_lceil,
 
+  COI_fract,
+  COI_fractuns,
+  COI_satfract,
+  COI_satfractuns,
+
   COI_MAX
 };
 
@@ -519,6 +571,10 @@ extern convert_optab convert_optab_table[COI_MAX];
 #define lround_optab (convert_optab_table[COI_lround])
 #define lfloor_optab (convert_optab_table[COI_lfloor])
 #define lceil_optab (convert_optab_table[COI_lceil])
+#define fract_optab (convert_optab_table[COI_fract])
+#define fractuns_optab (convert_optab_table[COI_fractuns])
+#define satfract_optab (convert_optab_table[COI_satfract])
+#define satfractuns_optab (convert_optab_table[COI_satfractuns])
 
 /* These arrays record the insn_code of insns that may be needed to
    perform input and output reloads of special objects.  They provide a
@@ -693,6 +749,9 @@ extern void set_optab_libfunc (optab, enum machine_mode, const char *);
 extern void set_conv_libfunc (convert_optab, enum machine_mode,
                              enum machine_mode, const char *);
 
+/* Generate code for a FIXED_CONVERT_EXPR.  */
+extern void expand_fixed_convert (rtx, rtx, int, int);
+
 /* Generate code for a FLOAT_EXPR.  */
 extern void expand_float (rtx, rtx, int);