stdfix.h: New file.

* 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.

From-SVN: r128218
This commit is contained in:
Chao-ying Fu 2007-09-07 01:24:09 +00:00 committed by Chao-ying Fu
parent 58cfe6985b
commit 0f996086cb
13 changed files with 1178 additions and 35 deletions

View 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

View 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)

View 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)

View 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);

View 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;
}
}

View 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);

View 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

View 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

View File

@ -347,7 +347,8 @@ init_expr (void)
}
/* 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),

View 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:

207
gcc/ginclude/stdfix.h Normal file
View File

@ -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 */

View 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)

View 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);