aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2013-02-08 10:13:37 +0000
committerGeorg-Johann Lay <gjl@gcc.gnu.org>2013-02-08 10:13:37 +0000
commit85d768f349087f3766ff84054ec7b3403c52ac7a (patch)
treec41ab849c5ffa4c56a753d5d4502a23fdc14617d /gcc
parent661bc682bcb87f5faa709f9bcd1679874f6652f6 (diff)
downloadgcc-85d768f349087f3766ff84054ec7b3403c52ac7a.zip
gcc-85d768f349087f3766ff84054ec7b3403c52ac7a.tar.gz
gcc-85d768f349087f3766ff84054ec7b3403c52ac7a.tar.bz2
re PR target/54222 ([avr] Implement fixed-point support)
gcc/ PR target/54222 * config/avr/avr.md (unspec) <UNSPEC_ROUND>: Add. * config/avr/avr-fixed.md (ALL4QA, ALL124QA): New mode iterators. (round<mode>3, round<mode>3_const): New expanders for fixed-mode. (*round<mode>3.libgcc): New insns for fixed-modes. * config/avr/builtins.def (ABSxx): Use a non-NULL LIBNAME. (ROUNDxx, COUNTLSxx, BITSxx, xxBITS): New DEF_BUILTINs. (ROUNDFX, COUNTLSFX, ABSFX): New DEF_BUILTINs. * config/avr/stdfix.h (absFX, bitsFX, FXbits): Remove inline implementations. Define to __builtin_avr_absFX, __builtin_avr_bitsFX, __builtin_avr_FXbits, respectively. (roundFX, countlsFX): Define to __builtin_avr_roundFX, __builtin_avr_countlsFX, respectively. * config/avr/avr-c.c (target.h): Include it. (enum avr_builtin_id): New enum. (avr_resolve_overloaded_builtin): New static function. (avr_register_target_pragmas): Use it to set targetm.resolve_overloaded_builtin. * config/avr/avr.c (avr_init_builtins): Supply myriads of local tree nodes used by DEF_BUILTIN. (avr_expand_builtin) <AVR_BUILTIN_ROUNDxx>: Sanity-check them. (avr_fold_builtin) <AVR_BUILTIN_BITSxx>: Fold to VIEW_COVERT_EXPR. <AVR_BUILTIN_xxBITS>: Same. libgcc/ PR target/54222 * config/avr/lib2funcs.c: New C sources for modules for libgcc.a. * config/avr/lib2-object.mk: New iterator to build objects from it. * config/avr/t-avr: Iterate lib2-object.mk to build objects from lib2funcs.c. (LIB2FUNCS_EXCLUDE): Add _clrsbdi2. (LIB1ASMFUNCS): Add: _ssabs_1, _mask1, _ret, _roundqq3, _rounduqq3, _round_s2, _round_u2, _round_2_const, _addmask_2, _round_s4, _round_u4, _round_4_const, _addmask_4, _round_x8, _rounddq3 _roundudq3, _roundda3 _rounduda3, _roundta3 _rounduta3. * config/avr/lib1funcs-fixed.S: Implement them. gcc/testsuite/ PR target/54222 * gcc.target/avr/torture/builtins-4-roundfx.c: New test. * gcc.target/avr/torture/builtins-5-countlsfx.c: New test. From-SVN: r195878
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog26
-rw-r--r--gcc/config/avr/avr-c.c218
-rw-r--r--gcc/config/avr/avr-fixed.md138
-rw-r--r--gcc/config/avr/avr.c204
-rw-r--r--gcc/config/avr/avr.md1
-rw-r--r--gcc/config/avr/builtins.def115
-rw-r--r--gcc/config/avr/stdfix.h477
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.target/avr/torture/builtins-4-roundfx.c161
-rw-r--r--gcc/testsuite/gcc.target/avr/torture/builtins-5-countlsfx.c82
10 files changed, 1050 insertions, 378 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 787efb7..38173e9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,29 @@
+2013-02-08 Georg-Johann Lay <avr@gjlay.de>
+
+ PR target/54222
+ * config/avr/avr.md (unspec) <UNSPEC_ROUND>: Add.
+ * config/avr/avr-fixed.md (ALL4QA, ALL124QA): New mode iterators.
+ (round<mode>3, round<mode>3_const): New expanders for fixed-mode.
+ (*round<mode>3.libgcc): New insns for fixed-modes.
+ * config/avr/builtins.def (ABSxx): Use a non-NULL LIBNAME.
+ (ROUNDxx, COUNTLSxx, BITSxx, xxBITS): New DEF_BUILTINs.
+ (ROUNDFX, COUNTLSFX, ABSFX): New DEF_BUILTINs.
+ * config/avr/stdfix.h (absFX, bitsFX, FXbits): Remove inline
+ implementations. Define to __builtin_avr_absFX,
+ __builtin_avr_bitsFX, __builtin_avr_FXbits, respectively.
+ (roundFX, countlsFX): Define to __builtin_avr_roundFX,
+ __builtin_avr_countlsFX, respectively.
+ * config/avr/avr-c.c (target.h): Include it.
+ (enum avr_builtin_id): New enum.
+ (avr_resolve_overloaded_builtin): New static function.
+ (avr_register_target_pragmas): Use it to set
+ targetm.resolve_overloaded_builtin.
+ * config/avr/avr.c (avr_init_builtins): Supply myriads of local
+ tree nodes used by DEF_BUILTIN.
+ (avr_expand_builtin) <AVR_BUILTIN_ROUNDxx>: Sanity-check them.
+ (avr_fold_builtin) <AVR_BUILTIN_BITSxx>: Fold to VIEW_COVERT_EXPR.
+ <AVR_BUILTIN_xxBITS>: Same.
+
2013-02-08 Richard Biener <rguenther@suse.de>
* cfgloop.c (verify_loop_structure): Properly handle
diff --git a/gcc/config/avr/avr-c.c b/gcc/config/avr/avr-c.c
index ddcab54..4e64405 100644
--- a/gcc/config/avr/avr-c.c
+++ b/gcc/config/avr/avr-c.c
@@ -26,10 +26,226 @@
#include "tm_p.h"
#include "cpplib.h"
#include "tree.h"
+#include "target.h"
#include "c-family/c-common.h"
#include "langhooks.h"
+/* IDs for all the AVR builtins. */
+
+enum avr_builtin_id
+ {
+#define DEF_BUILTIN(NAME, N_ARGS, TYPE, CODE, LIBNAME) \
+ AVR_BUILTIN_ ## NAME,
+#include "builtins.def"
+#undef DEF_BUILTIN
+
+ AVR_BUILTIN_COUNT
+ };
+
+
+/* Implement `TARGET_RESOLVE_OVERLOADED_PLUGIN'. */
+
+static tree
+avr_resolve_overloaded_builtin (unsigned int iloc, tree fndecl, void *vargs)
+{
+ tree type0, type1, fold = NULL_TREE;
+ enum avr_builtin_id id = AVR_BUILTIN_COUNT;
+ location_t loc = (location_t) iloc;
+ vec<tree, va_gc> &args = * (vec<tree, va_gc>*) vargs;
+
+ switch (DECL_FUNCTION_CODE (fndecl))
+ {
+ default:
+ break;
+
+ case AVR_BUILTIN_ABSFX:
+ if (args.length() != 1)
+ {
+ error_at (loc, "%qs expects 1 argument but %d given",
+ "absfx", (int) args.length());
+
+ fold = error_mark_node;
+ break;
+ }
+
+ type0 = TREE_TYPE (args[0]);
+
+ if (!FIXED_POINT_TYPE_P (type0))
+ {
+ error_at (loc, "%qs expects a fixed-point value as argument",
+ "absfx");
+
+ fold = error_mark_node;
+ }
+
+ switch (TYPE_MODE (type0))
+ {
+ case QQmode: id = AVR_BUILTIN_ABSHR; break;
+ case HQmode: id = AVR_BUILTIN_ABSR; break;
+ case SQmode: id = AVR_BUILTIN_ABSLR; break;
+ case DQmode: id = AVR_BUILTIN_ABSLLR; break;
+
+ case HAmode: id = AVR_BUILTIN_ABSHK; break;
+ case SAmode: id = AVR_BUILTIN_ABSK; break;
+ case DAmode: id = AVR_BUILTIN_ABSLK; break;
+ case TAmode: id = AVR_BUILTIN_ABSLLK; break;
+
+ case UQQmode:
+ case UHQmode:
+ case USQmode:
+ case UDQmode:
+ case UHAmode:
+ case USAmode:
+ case UDAmode:
+ case UTAmode:
+ warning_at (loc, 0, "using %qs with unsigned type has no effect",
+ "absfx");
+ return args[0];
+
+ default:
+ error_at (loc, "no matching fixed-point overload found for %qs",
+ "absfx");
+
+ fold = error_mark_node;
+ break;
+ }
+
+ fold = targetm.builtin_decl (id, true);
+
+ if (fold != error_mark_node)
+ fold = build_function_call_vec (loc, fold, &args, NULL);
+
+ break; // absfx
+
+ case AVR_BUILTIN_ROUNDFX:
+ if (args.length() != 2)
+ {
+ error_at (loc, "%qs expects 2 arguments but %d given",
+ "roundfx", (int) args.length());
+
+ fold = error_mark_node;
+ break;
+ }
+
+ type0 = TREE_TYPE (args[0]);
+ type1 = TREE_TYPE (args[1]);
+
+ if (!FIXED_POINT_TYPE_P (type0))
+ {
+ error_at (loc, "%qs expects a fixed-point value as first argument",
+ "roundfx");
+
+ fold = error_mark_node;
+ }
+
+ if (!INTEGRAL_TYPE_P (type1))
+ {
+ error_at (loc, "%qs expects an integer value as second argument",
+ "roundfx");
+
+ fold = error_mark_node;
+ }
+
+ switch (TYPE_MODE (type0))
+ {
+ case QQmode: id = AVR_BUILTIN_ROUNDHR; break;
+ case HQmode: id = AVR_BUILTIN_ROUNDR; break;
+ case SQmode: id = AVR_BUILTIN_ROUNDLR; break;
+ case DQmode: id = AVR_BUILTIN_ROUNDLLR; break;
+
+ case UQQmode: id = AVR_BUILTIN_ROUNDUHR; break;
+ case UHQmode: id = AVR_BUILTIN_ROUNDUR; break;
+ case USQmode: id = AVR_BUILTIN_ROUNDULR; break;
+ case UDQmode: id = AVR_BUILTIN_ROUNDULLR; break;
+
+ case HAmode: id = AVR_BUILTIN_ROUNDHK; break;
+ case SAmode: id = AVR_BUILTIN_ROUNDK; break;
+ case DAmode: id = AVR_BUILTIN_ROUNDLK; break;
+ case TAmode: id = AVR_BUILTIN_ROUNDLLK; break;
+
+ case UHAmode: id = AVR_BUILTIN_ROUNDUHK; break;
+ case USAmode: id = AVR_BUILTIN_ROUNDUK; break;
+ case UDAmode: id = AVR_BUILTIN_ROUNDULK; break;
+ case UTAmode: id = AVR_BUILTIN_ROUNDULLK; break;
+
+ default:
+ error_at (loc, "no matching fixed-point overload found for %qs",
+ "roundfx");
+
+ fold = error_mark_node;
+ break;
+ }
+
+ fold = targetm.builtin_decl (id, true);
+
+ if (fold != error_mark_node)
+ fold = build_function_call_vec (loc, fold, &args, NULL);
+
+ break; // roundfx
+
+ case AVR_BUILTIN_COUNTLSFX:
+ if (args.length() != 1)
+ {
+ error_at (loc, "%qs expects 1 argument but %d given",
+ "countlsfx", (int) args.length());
+
+ fold = error_mark_node;
+ break;
+ }
+
+ type0 = TREE_TYPE (args[0]);
+
+ if (!FIXED_POINT_TYPE_P (type0))
+ {
+ error_at (loc, "%qs expects a fixed-point value as first argument",
+ "countlsfx");
+
+ fold = error_mark_node;
+ }
+
+ switch (TYPE_MODE (type0))
+ {
+ case QQmode: id = AVR_BUILTIN_COUNTLSHR; break;
+ case HQmode: id = AVR_BUILTIN_COUNTLSR; break;
+ case SQmode: id = AVR_BUILTIN_COUNTLSLR; break;
+ case DQmode: id = AVR_BUILTIN_COUNTLSLLR; break;
+
+ case UQQmode: id = AVR_BUILTIN_COUNTLSUHR; break;
+ case UHQmode: id = AVR_BUILTIN_COUNTLSUR; break;
+ case USQmode: id = AVR_BUILTIN_COUNTLSULR; break;
+ case UDQmode: id = AVR_BUILTIN_COUNTLSULLR; break;
+
+ case HAmode: id = AVR_BUILTIN_COUNTLSHK; break;
+ case SAmode: id = AVR_BUILTIN_COUNTLSK; break;
+ case DAmode: id = AVR_BUILTIN_COUNTLSLK; break;
+ case TAmode: id = AVR_BUILTIN_COUNTLSLLK; break;
+
+ case UHAmode: id = AVR_BUILTIN_COUNTLSUHK; break;
+ case USAmode: id = AVR_BUILTIN_COUNTLSUK; break;
+ case UDAmode: id = AVR_BUILTIN_COUNTLSULK; break;
+ case UTAmode: id = AVR_BUILTIN_COUNTLSULLK; break;
+
+ default:
+ error_at (loc, "no matching fixed-point overload found for %qs",
+ "countlsfx");
+
+ fold = error_mark_node;
+ break;
+ }
+
+ fold = targetm.builtin_decl (id, true);
+
+ if (fold != error_mark_node)
+ fold = build_function_call_vec (loc, fold, &args, NULL);
+
+ break; // countlsfx
+ }
+
+ return fold;
+}
+
+
/* Implement `REGISTER_TARGET_PRAGMAS'. */
void
@@ -49,6 +265,8 @@ avr_register_target_pragmas (void)
if (!ADDR_SPACE_GENERIC_P (i))
c_register_addr_space (avr_addrspace[i].name, avr_addrspace[i].id);
}
+
+ targetm.resolve_overloaded_builtin = avr_resolve_overloaded_builtin;
}
diff --git a/gcc/config/avr/avr-fixed.md b/gcc/config/avr/avr-fixed.md
index ce7f54d..7d9b525 100644
--- a/gcc/config/avr/avr-fixed.md
+++ b/gcc/config/avr/avr-fixed.md
@@ -24,14 +24,16 @@
(define_mode_iterator ALL1Q [QQ UQQ])
(define_mode_iterator ALL2Q [HQ UHQ])
(define_mode_iterator ALL2A [HA UHA])
-(define_mode_iterator ALL2QA [HQ UHQ
- HA UHA])
(define_mode_iterator ALL4A [SA USA])
+(define_mode_iterator ALL2QA [HQ UHQ HA UHA])
+(define_mode_iterator ALL4QA [SQ USQ SA USA])
+(define_mode_iterator ALL124QA [ QQ HQ HA SA SQ
+ UQQ UHQ UHA USA USQ])
(define_mode_iterator ALL2S [HQ HA])
(define_mode_iterator ALL4S [SA SQ])
-(define_mode_iterator ALL24S [ HQ HA SA SQ])
-(define_mode_iterator ALL124S [ QQ HQ HA SA SQ])
+(define_mode_iterator ALL24S [ HQ HA SA SQ])
+(define_mode_iterator ALL124S [ QQ HQ HA SA SQ])
(define_mode_iterator ALL124U [UQQ UHQ UHA USA USQ])
;;; Conversions
@@ -396,3 +398,131 @@
"%~call __<code><mode>3"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
+
+
+;******************************************************************************
+;** Rounding
+;******************************************************************************
+
+;; "roundqq3" "rounduqq3"
+;; "roundhq3" "rounduhq3" "roundha3" "rounduha3"
+;; "roundsq3" "roundusq3" "roundsa3" "roundusa3"
+(define_expand "round<mode>3"
+ [(set (match_dup 4)
+ (match_operand:ALL124QA 1 "register_operand" ""))
+ (set (reg:QI 24)
+ (match_dup 5))
+ (parallel [(set (match_dup 3)
+ (unspec:ALL124QA [(match_dup 4)
+ (reg:QI 24)] UNSPEC_ROUND))
+ (clobber (match_dup 4))])
+ (set (match_operand:ALL124QA 0 "register_operand" "")
+ (match_dup 3))
+ (use (match_operand:HI 2 "nonmemory_operand" ""))]
+ ""
+ {
+ if (CONST_INT_P (operands[2])
+ && !(optimize_size
+ && 4 == GET_MODE_SIZE (<MODE>mode)))
+ {
+ emit_insn (gen_round<mode>3_const (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+
+ // Input and output of the libgcc function
+ const unsigned int regno_in[] = { -1, 22, 22, -1, 18 };
+ const unsigned int regno_out[] = { -1, 24, 24, -1, 22 };
+
+ operands[3] = gen_rtx_REG (<MODE>mode, regno_out[(size_t) GET_MODE_SIZE (<MODE>mode)]);
+ operands[4] = gen_rtx_REG (<MODE>mode, regno_in[(size_t) GET_MODE_SIZE (<MODE>mode)]);
+ operands[5] = simplify_gen_subreg (QImode, force_reg (HImode, operands[2]), HImode, 0);
+ // $2 is no more needed, but is referenced for expand.
+ operands[2] = const0_rtx;
+ })
+
+;; Expand rounding with known rounding points inline so that the addend / mask
+;; will be consumed by operation with immediate operands and there is no
+;; need for a shift with variable offset.
+
+;; "roundqq3_const" "rounduqq3_const"
+;; "roundhq3_const" "rounduhq3_const" "roundha3_const" "rounduha3_const"
+;; "roundsq3_const" "roundusq3_const" "roundsa3_const" "roundusa3_const"
+(define_expand "round<mode>3_const"
+ [(parallel [(match_operand:ALL124QA 0 "register_operand" "")
+ (match_operand:ALL124QA 1 "register_operand" "")
+ (match_operand:HI 2 "const_int_operand" "")])]
+ ""
+ {
+ // The rounding point RP is $2. The smallest fractional
+ // bit that is not cleared by the rounding is 2^(-RP).
+
+ enum machine_mode imode = int_mode_for_mode (<MODE>mode);
+ int fbit = (int) GET_MODE_FBIT (<MODE>mode);
+
+ // Add-Saturate 1/2 * 2^(-RP)
+
+ double_int i_add = double_int_zero.set_bit (fbit-1 - INTVAL (operands[2]));
+ rtx x_add = const_fixed_from_double_int (i_add, <MODE>mode);
+
+ if (SIGNED_FIXED_POINT_MODE_P (<MODE>mode))
+ emit_move_insn (operands[0],
+ gen_rtx_SS_PLUS (<MODE>mode, operands[1], x_add));
+ else
+ emit_move_insn (operands[0],
+ gen_rtx_US_PLUS (<MODE>mode, operands[1], x_add));
+
+ // Keep all bits from RP and higher: ... 2^(-RP)
+ // Clear all bits from RP+1 and lower: 2^(-RP-1) ...
+ // Rounding point ^^^^^^^
+ // Added above ^^^^^^^^^
+
+ rtx xreg = simplify_gen_subreg (imode, operands[0], <MODE>mode, 0);
+ rtx xmask = immed_double_int_const (-i_add - i_add, imode);
+
+ if (SImode == imode)
+ emit_insn (gen_andsi3 (xreg, xreg, xmask));
+ else if (HImode == imode)
+ emit_insn (gen_andhi3 (xreg, xreg, xmask));
+ else if (QImode == imode)
+ emit_insn (gen_andqi3 (xreg, xreg, xmask));
+ else
+ gcc_unreachable();
+
+ DONE;
+ })
+
+
+;; "*roundqq3.libgcc" "*rounduqq3.libgcc"
+(define_insn "*round<mode>3.libgcc"
+ [(set (reg:ALL1Q 24)
+ (unspec:ALL1Q [(reg:ALL1Q 22)
+ (reg:QI 24)] UNSPEC_ROUND))
+ (clobber (reg:ALL1Q 22))]
+ ""
+ "%~call __round<mode>3"
+ [(set_attr "type" "xcall")
+ (set_attr "cc" "clobber")])
+
+;; "*roundhq3.libgcc" "*rounduhq3.libgcc"
+;; "*roundha3.libgcc" "*rounduha3.libgcc"
+(define_insn "*round<mode>3.libgcc"
+ [(set (reg:ALL2QA 24)
+ (unspec:ALL2QA [(reg:ALL2QA 22)
+ (reg:QI 24)] UNSPEC_ROUND))
+ (clobber (reg:ALL2QA 22))]
+ ""
+ "%~call __round<mode>3"
+ [(set_attr "type" "xcall")
+ (set_attr "cc" "clobber")])
+
+;; "*roundsq3.libgcc" "*roundusq3.libgcc"
+;; "*roundsa3.libgcc" "*roundusa3.libgcc"
+(define_insn "*round<mode>3.libgcc"
+ [(set (reg:ALL4QA 22)
+ (unspec:ALL4QA [(reg:ALL4QA 18)
+ (reg:QI 24)] UNSPEC_ROUND))
+ (clobber (reg:ALL4QA 18))]
+ ""
+ "%~call __round<mode>3"
+ [(set_attr "type" "xcall")
+ (set_attr "cc" "clobber")])
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
index c833bfb..0f1d2c1 100644
--- a/gcc/config/avr/avr.c
+++ b/gcc/config/avr/avr.c
@@ -11489,32 +11489,118 @@ avr_init_builtins (void)
const_memx_ptr_type_node,
NULL);
- tree hr_ftype_hr
- = build_function_type_list (short_fract_type_node,
- short_fract_type_node, NULL);
- tree r_ftype_r
- = build_function_type_list (fract_type_node,
- fract_type_node, NULL);
- tree lr_ftype_lr
- = build_function_type_list (long_fract_type_node,
- long_fract_type_node, NULL);
- tree llr_ftype_llr
- = build_function_type_list (long_long_fract_type_node,
- long_long_fract_type_node, NULL);
-
- tree hk_ftype_hk
- = build_function_type_list (short_accum_type_node,
- short_accum_type_node, NULL);
- tree k_ftype_k
- = build_function_type_list (accum_type_node,
- accum_type_node, NULL);
- tree lk_ftype_lk
- = build_function_type_list (long_accum_type_node,
- long_accum_type_node, NULL);
- tree llk_ftype_llk
- = build_function_type_list (long_long_accum_type_node,
- long_long_accum_type_node, NULL);
+#define ITYP(T) \
+ lang_hooks.types.type_for_size (TYPE_PRECISION (T), TYPE_UNSIGNED (T))
+#define FX_FTYPE_FX(fx) \
+ tree fx##r_ftype_##fx##r \
+ = build_function_type_list (node_##fx##r, node_##fx##r, NULL); \
+ tree fx##k_ftype_##fx##k \
+ = build_function_type_list (node_##fx##k, node_##fx##k, NULL)
+
+#define FX_FTYPE_FX_INT(fx) \
+ tree fx##r_ftype_##fx##r_int \
+ = build_function_type_list (node_##fx##r, node_##fx##r, \
+ integer_type_node, NULL); \
+ tree fx##k_ftype_##fx##k_int \
+ = build_function_type_list (node_##fx##k, node_##fx##k, \
+ integer_type_node, NULL)
+
+#define INT_FTYPE_FX(fx) \
+ tree int_ftype_##fx##r \
+ = build_function_type_list (integer_type_node, node_##fx##r, NULL); \
+ tree int_ftype_##fx##k \
+ = build_function_type_list (integer_type_node, node_##fx##k, NULL)
+
+#define INTX_FTYPE_FX(fx) \
+ tree int##fx##r_ftype_##fx##r \
+ = build_function_type_list (ITYP (node_##fx##r), node_##fx##r, NULL); \
+ tree int##fx##k_ftype_##fx##k \
+ = build_function_type_list (ITYP (node_##fx##k), node_##fx##k, NULL)
+
+#define FX_FTYPE_INTX(fx) \
+ tree fx##r_ftype_int##fx##r \
+ = build_function_type_list (node_##fx##r, ITYP (node_##fx##r), NULL); \
+ tree fx##k_ftype_int##fx##k \
+ = build_function_type_list (node_##fx##k, ITYP (node_##fx##k), NULL)
+
+ tree node_hr = short_fract_type_node;
+ tree node_r = fract_type_node;
+ tree node_lr = long_fract_type_node;
+ tree node_llr = long_long_fract_type_node;
+
+ tree node_uhr = unsigned_short_fract_type_node;
+ tree node_ur = unsigned_fract_type_node;
+ tree node_ulr = unsigned_long_fract_type_node;
+ tree node_ullr = unsigned_long_long_fract_type_node;
+
+ tree node_hk = short_accum_type_node;
+ tree node_k = accum_type_node;
+ tree node_lk = long_accum_type_node;
+ tree node_llk = long_long_accum_type_node;
+
+ tree node_uhk = unsigned_short_accum_type_node;
+ tree node_uk = unsigned_accum_type_node;
+ tree node_ulk = unsigned_long_accum_type_node;
+ tree node_ullk = unsigned_long_long_accum_type_node;
+
+
+ /* For absfx builtins. */
+
+ FX_FTYPE_FX (h);
+ FX_FTYPE_FX ();
+ FX_FTYPE_FX (l);
+ FX_FTYPE_FX (ll);
+
+ /* For roundfx builtins. */
+
+ FX_FTYPE_FX_INT (h);
+ FX_FTYPE_FX_INT ();
+ FX_FTYPE_FX_INT (l);
+ FX_FTYPE_FX_INT (ll);
+
+ FX_FTYPE_FX_INT (uh);
+ FX_FTYPE_FX_INT (u);
+ FX_FTYPE_FX_INT (ul);
+ FX_FTYPE_FX_INT (ull);
+
+ /* For countlsfx builtins. */
+
+ INT_FTYPE_FX (h);
+ INT_FTYPE_FX ();
+ INT_FTYPE_FX (l);
+ INT_FTYPE_FX (ll);
+
+ INT_FTYPE_FX (uh);
+ INT_FTYPE_FX (u);
+ INT_FTYPE_FX (ul);
+ INT_FTYPE_FX (ull);
+
+ /* For bitsfx builtins. */
+
+ INTX_FTYPE_FX (h);
+ INTX_FTYPE_FX ();
+ INTX_FTYPE_FX (l);
+ INTX_FTYPE_FX (ll);
+
+ INTX_FTYPE_FX (uh);
+ INTX_FTYPE_FX (u);
+ INTX_FTYPE_FX (ul);
+ INTX_FTYPE_FX (ull);
+
+ /* For fxbits builtins. */
+
+ FX_FTYPE_INTX (h);
+ FX_FTYPE_INTX ();
+ FX_FTYPE_INTX (l);
+ FX_FTYPE_INTX (ll);
+
+ FX_FTYPE_INTX (uh);
+ FX_FTYPE_INTX (u);
+ FX_FTYPE_INTX (ul);
+ FX_FTYPE_INTX (ull);
+
+
#define DEF_BUILTIN(NAME, N_ARGS, TYPE, CODE, LIBNAME) \
{ \
int id = AVR_BUILTIN_ ## NAME; \
@@ -11647,7 +11733,50 @@ avr_expand_builtin (tree exp, rtx target,
" as first argument", bname);
return target;
}
+
+ break;
}
+
+ case AVR_BUILTIN_ROUNDHR: case AVR_BUILTIN_ROUNDUHR:
+ case AVR_BUILTIN_ROUNDR: case AVR_BUILTIN_ROUNDUR:
+ case AVR_BUILTIN_ROUNDLR: case AVR_BUILTIN_ROUNDULR:
+ case AVR_BUILTIN_ROUNDLLR: case AVR_BUILTIN_ROUNDULLR:
+
+ case AVR_BUILTIN_ROUNDHK: case AVR_BUILTIN_ROUNDUHK:
+ case AVR_BUILTIN_ROUNDK: case AVR_BUILTIN_ROUNDUK:
+ case AVR_BUILTIN_ROUNDLK: case AVR_BUILTIN_ROUNDULK:
+ case AVR_BUILTIN_ROUNDLLK: case AVR_BUILTIN_ROUNDULLK:
+
+ /* Warn about odd rounding. Rounding points >= FBIT will have
+ no effect. */
+
+ if (TREE_CODE (CALL_EXPR_ARG (exp, 1)) != INTEGER_CST)
+ break;
+
+ int rbit = (int) TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 1));
+
+ if (rbit >= (int) GET_MODE_FBIT (mode))
+ {
+ warning (OPT_Wextra, "rounding to %d bits has no effect for "
+ "fixed-point value with %d fractional bits",
+ rbit, GET_MODE_FBIT (mode));
+
+ return expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, mode,
+ EXPAND_NORMAL);
+ }
+ else if (rbit <= - (int) GET_MODE_IBIT (mode))
+ {
+ warning (0, "rounding result will always be 0");
+ return CONST0_RTX (mode);
+ }
+
+ /* The rounding points RP satisfies now: -IBIT < RP < FBIT.
+
+ TR 18037 only specifies results for RP > 0. However, the
+ remaining cases of -IBIT < RP <= 0 can easily be supported
+ without any additional overhead. */
+
+ break; /* round */
}
/* No fold found and no insn: Call support function from libgcc. */
@@ -11736,6 +11865,31 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg,
return avr_fold_absfx (arg[0]);
+ case AVR_BUILTIN_BITSHR: case AVR_BUILTIN_HRBITS:
+ case AVR_BUILTIN_BITSHK: case AVR_BUILTIN_HKBITS:
+ case AVR_BUILTIN_BITSUHR: case AVR_BUILTIN_UHRBITS:
+ case AVR_BUILTIN_BITSUHK: case AVR_BUILTIN_UHKBITS:
+
+ case AVR_BUILTIN_BITSR: case AVR_BUILTIN_RBITS:
+ case AVR_BUILTIN_BITSK: case AVR_BUILTIN_KBITS:
+ case AVR_BUILTIN_BITSUR: case AVR_BUILTIN_URBITS:
+ case AVR_BUILTIN_BITSUK: case AVR_BUILTIN_UKBITS:
+
+ case AVR_BUILTIN_BITSLR: case AVR_BUILTIN_LRBITS:
+ case AVR_BUILTIN_BITSLK: case AVR_BUILTIN_LKBITS:
+ case AVR_BUILTIN_BITSULR: case AVR_BUILTIN_ULRBITS:
+ case AVR_BUILTIN_BITSULK: case AVR_BUILTIN_ULKBITS:
+
+ case AVR_BUILTIN_BITSLLR: case AVR_BUILTIN_LLRBITS:
+ case AVR_BUILTIN_BITSLLK: case AVR_BUILTIN_LLKBITS:
+ case AVR_BUILTIN_BITSULLR: case AVR_BUILTIN_ULLRBITS:
+ case AVR_BUILTIN_BITSULLK: case AVR_BUILTIN_ULLKBITS:
+
+ gcc_assert (TYPE_PRECISION (val_type)
+ == TYPE_PRECISION (TREE_TYPE (arg[0])));
+
+ return build1 (VIEW_CONVERT_EXPR, val_type, arg[0]);
+
case AVR_BUILTIN_INSERT_BITS:
{
tree tbits = arg[1];
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 6432d63..e9f5d03 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -68,6 +68,7 @@
UNSPEC_COPYSIGN
UNSPEC_IDENTITY
UNSPEC_INSERT_BITS
+ UNSPEC_ROUND
])
(define_c_enum "unspecv"
diff --git a/gcc/config/avr/builtins.def b/gcc/config/avr/builtins.def
index ecce186..ce444ab 100644
--- a/gcc/config/avr/builtins.def
+++ b/gcc/config/avr/builtins.def
@@ -61,12 +61,109 @@ DEF_BUILTIN (FLASH_SEGMENT, 1, char_ftype_const_memx_ptr, flash_segment, NULL)
/* 7.18a.6.2 The fixed-point absolute value functions. */
-DEF_BUILTIN (ABSHR, 1, hr_ftype_hr, ssabsqq2, NULL)
-DEF_BUILTIN (ABSR, 1, r_ftype_r, ssabshq2, NULL)
-DEF_BUILTIN (ABSLR, 1, lr_ftype_lr, ssabssq2, NULL)
-DEF_BUILTIN (ABSLLR, 1, llr_ftype_llr, nothing, "__ssabsdq2") // GCC extension
-
-DEF_BUILTIN (ABSHK, 1, hk_ftype_hk, ssabsha2, NULL)
-DEF_BUILTIN (ABSK, 1, k_ftype_k, ssabssa2, NULL)
-DEF_BUILTIN (ABSLK, -1, lk_ftype_lk, nothing, "__ssabsda2")
-DEF_BUILTIN (ABSLLK, -1, llk_ftype_llk, nothing, "__ssabsta2") // GCC extension
+DEF_BUILTIN (ABSHR, 1, hr_ftype_hr, ssabsqq2, "__ssabs_1")
+DEF_BUILTIN (ABSR, 1, r_ftype_r, ssabshq2, "__ssabs_2")
+DEF_BUILTIN (ABSLR, 1, lr_ftype_lr, ssabssq2, "__ssabs_4")
+DEF_BUILTIN (ABSLLR, -1, llr_ftype_llr, nothing, "__ssabsdq2") // GCC extension
+
+DEF_BUILTIN (ABSHK, 1, hk_ftype_hk, ssabsha2, "__ssabs_2")
+DEF_BUILTIN (ABSK, 1, k_ftype_k, ssabssa2, "__ssabs_4")
+DEF_BUILTIN (ABSLK, -1, lk_ftype_lk, nothing, "__ssabsda2")
+DEF_BUILTIN (ABSLLK, -1, llk_ftype_llk, nothing, "__ssabsta2") // GCC extension
+
+/* 7.18a.6.3 The fixed-point round functions. */
+
+DEF_BUILTIN (ROUNDHR, 2, hr_ftype_hr_int, roundqq3, "__roundhr")
+DEF_BUILTIN (ROUNDR, 2, r_ftype_r_int, roundhq3, "__roundr")
+DEF_BUILTIN (ROUNDLR, 2, lr_ftype_lr_int, roundsq3, "__roundlr")
+DEF_BUILTIN (ROUNDLLR, -1, llr_ftype_llr_int, nothing, "__rounddq3") // GCC extension
+
+DEF_BUILTIN (ROUNDUHR, 2, uhr_ftype_uhr_int, rounduqq3, "__rounduhr")
+DEF_BUILTIN (ROUNDUR, 2, ur_ftype_ur_int, rounduhq3, "__roundur")
+DEF_BUILTIN (ROUNDULR, 2, ulr_ftype_ulr_int, roundusq3, "__roundulr")
+DEF_BUILTIN (ROUNDULLR, -1, ullr_ftype_ullr_int, nothing, "__roundudq3") // GCC extension
+
+DEF_BUILTIN (ROUNDHK, 2, hk_ftype_hk_int, roundha3, "__roundhk")
+DEF_BUILTIN (ROUNDK, 2, k_ftype_k_int, roundsa3, "__roundk")
+DEF_BUILTIN (ROUNDLK, -1, lk_ftype_lk_int, nothing, "__roundda3")
+DEF_BUILTIN (ROUNDLLK, -1, llk_ftype_llk_int, nothing, "__roundta3") // GCC extension
+
+DEF_BUILTIN (ROUNDUHK, 2, uhk_ftype_uhk_int, rounduha3, "__rounduhk")
+DEF_BUILTIN (ROUNDUK, 2, uk_ftype_uk_int, roundusa3, "__rounduk")
+DEF_BUILTIN (ROUNDULK, -1, ulk_ftype_ulk_int, nothing, "__rounduda3")
+DEF_BUILTIN (ROUNDULLK, -1, ullk_ftype_ullk_int, nothing, "__rounduta3") // GCC extension
+
+/* 7.18a.6.4 The fixed-point bit countls functions. */
+
+DEF_BUILTIN (COUNTLSHR, -1, int_ftype_hr, nothing, "__countlsqi2")
+DEF_BUILTIN (COUNTLSR, -1, int_ftype_r, nothing, "__countlshi2")
+DEF_BUILTIN (COUNTLSLR, -1, int_ftype_lr, nothing, "__countlssi2")
+DEF_BUILTIN (COUNTLSLLR, -1, int_ftype_llr, nothing, "__countlsdi2") // GCC extension
+
+DEF_BUILTIN (COUNTLSUHR, -1, int_ftype_uhr, nothing, "__countlsuqi2")
+DEF_BUILTIN (COUNTLSUR, -1, int_ftype_ur, nothing, "__countlsuhi2")
+DEF_BUILTIN (COUNTLSULR, -1, int_ftype_ulr, nothing, "__countlsusi2")
+DEF_BUILTIN (COUNTLSULLR, -1, int_ftype_ullr, nothing, "__countlsudi2") // GCC extension
+
+DEF_BUILTIN (COUNTLSHK, -1, int_ftype_hk, nothing, "__countlshi2")
+DEF_BUILTIN (COUNTLSK, -1, int_ftype_k, nothing, "__countlssi2")
+DEF_BUILTIN (COUNTLSLK, -1, int_ftype_lk, nothing, "__countlsdi2")
+DEF_BUILTIN (COUNTLSLLK, -1, int_ftype_llk, nothing, "__countlsdi2") // GCC extension
+
+DEF_BUILTIN (COUNTLSUHK, -1, int_ftype_uhk, nothing, "__countlsuhi2")
+DEF_BUILTIN (COUNTLSUK, -1, int_ftype_uk, nothing, "__countlsusi2")
+DEF_BUILTIN (COUNTLSULK, -1, int_ftype_ulk, nothing, "__countlsudi2")
+DEF_BUILTIN (COUNTLSULLK, -1, int_ftype_ullk, nothing, "__countlsudi2") // GCC extension
+
+/* 7.18a.6.5 The bitwise fixed-point to integer conversion functions. */
+
+DEF_BUILTIN (BITSHR, -1, inthr_ftype_hr, nothing, "__ret")
+DEF_BUILTIN (BITSR, -1, intr_ftype_r, nothing, "__ret")
+DEF_BUILTIN (BITSLR, -1, intlr_ftype_lr, nothing, "__ret")
+DEF_BUILTIN (BITSLLR, -1, intllr_ftype_llr, nothing, "__ret") // GCC extension
+
+DEF_BUILTIN (BITSUHR, -1, intuhr_ftype_uhr, nothing, "__ret")
+DEF_BUILTIN (BITSUR, -1, intur_ftype_ur, nothing, "__ret")
+DEF_BUILTIN (BITSULR, -1, intulr_ftype_ulr, nothing, "__ret")
+DEF_BUILTIN (BITSULLR, -1, intullr_ftype_ullr, nothing, "__ret") // GCC extension
+
+DEF_BUILTIN (BITSHK, -1, inthk_ftype_hk, nothing, "__ret")
+DEF_BUILTIN (BITSK, -1, intk_ftype_k, nothing, "__ret")
+DEF_BUILTIN (BITSLK, -1, intlk_ftype_lk, nothing, "__ret")
+DEF_BUILTIN (BITSLLK, -1, intllk_ftype_llk, nothing, "__ret") // GCC extension
+
+DEF_BUILTIN (BITSUHK, -1, intuhk_ftype_uhk, nothing, "__ret")
+DEF_BUILTIN (BITSUK, -1, intuk_ftype_uk, nothing, "__ret")
+DEF_BUILTIN (BITSULK, -1, intulk_ftype_ulk, nothing, "__ret")
+DEF_BUILTIN (BITSULLK, -1, intullk_ftype_ullk, nothing, "__ret") // GCC extension
+
+
+/* 7.18a.6.6 The bitwise integer to fixed-point conversion functions. */
+
+DEF_BUILTIN ( HRBITS, -1, hr_ftype_inthr, nothing, "__ret")
+DEF_BUILTIN ( RBITS, -1, r_ftype_intr, nothing, "__ret")
+DEF_BUILTIN ( LRBITS, -1, lr_ftype_intlr, nothing, "__ret")
+DEF_BUILTIN ( LLRBITS, -1, llr_ftype_intllr, nothing, "__ret") // GCC extension
+
+DEF_BUILTIN ( UHRBITS, -1, uhr_ftype_intuhr, nothing, "__ret")
+DEF_BUILTIN ( URBITS, -1, ur_ftype_intur, nothing, "__ret")
+DEF_BUILTIN ( ULRBITS, -1, ulr_ftype_intulr, nothing, "__ret")
+DEF_BUILTIN (ULLRBITS, -1, ullr_ftype_intullr, nothing, "__ret") // GCC extension
+
+DEF_BUILTIN ( HKBITS, -1, hk_ftype_inthk, nothing, "__ret")
+DEF_BUILTIN ( KBITS, -1, k_ftype_intk, nothing, "__ret")
+DEF_BUILTIN ( LKBITS, -1, lk_ftype_intlk, nothing, "__ret")
+DEF_BUILTIN ( LLKBITS, -1, llk_ftype_intllk, nothing, "__ret") // GCC extension
+
+DEF_BUILTIN ( UHKBITS, -1, uhk_ftype_intuhk, nothing, "__ret")
+DEF_BUILTIN ( UKBITS, -1, uk_ftype_intuk, nothing, "__ret")
+DEF_BUILTIN ( ULKBITS, -1, ulk_ftype_intulk, nothing, "__ret")
+DEF_BUILTIN (ULLKBITS, -1, ullk_ftype_intullk, nothing, "__ret") // GCC extension
+
+/* Overloaded */
+
+/* 7.18a.6.7 Type-generic fixed-point functions. */
+
+DEF_BUILTIN (ABSFX, -1, void_ftype_void /* dummy */, nothing, NULL)
+DEF_BUILTIN (ROUNDFX, -1, void_ftype_void /* dummy */, nothing, NULL)
+DEF_BUILTIN (COUNTLSFX, -1, void_ftype_void /* dummy */, nothing, NULL)
diff --git a/gcc/config/avr/stdfix.h b/gcc/config/avr/stdfix.h
index b86195a..afcacdf 100644
--- a/gcc/config/avr/stdfix.h
+++ b/gcc/config/avr/stdfix.h
@@ -35,10 +35,6 @@
#include <stdfix-gcc.h>
-#define _GCC_TYPEPUN(A, B) \
- __builtin_memcpy (&A, &B, sizeof (A))
-
-/* 7.18a.6 The fixed-point intrinsic functions. */
#if __SIZEOF_INT__ == 2
@@ -66,8 +62,7 @@ typedef long long unsigned int uint_ulk_t;
typedef long long int int_llk_t;
typedef long long unsigned int uint_ullk_t;
-#else /* __SIZEOF_INT__ = 1 (for -mint8) */
-
+#elif __SIZEOF_INT__ == 1 /* -mint8 */
typedef signed char int_hr_t;
typedef unsigned char uint_uhr_t;
@@ -84,356 +79,158 @@ typedef long long unsigned int uint_ulr_t;
typedef long long int int_k_t;
typedef long long unsigned int uint_uk_t;
-#endif /* __SIZEOF_INT__ == 2 */
+#endif /* __SIZEOF_INT__ == 1, 2 */
+
+
+/* 7.18a.6 The fixed-point intrinsic functions. */
-/* 7.18a.6.2 The fixed-point absolute value functions. */
+/* 7.18a.6.2 The fixed-point absolute value functions. */
+
+#define abshr __builtin_avr_abshr
+#define absr __builtin_avr_absr
+#define abslr __builtin_avr_abslr
+
+#define abshk __builtin_avr_abshk
+#define absk __builtin_avr_absk
+
+#if __SIZEOF_INT__ == 2
+
+#define abslk __builtin_avr_abslk
+#define absllr __builtin_avr_absllr /* GCC Extension */
+#define absllk __builtin_avr_absllk /* GCC Extension */
-/* short fract (hr): abshr */
+#endif /* sizeof (int) == 2 */
-static __inline__ __attribute__((__always_inline__))
-short fract abshr (const short fract __q)
-{
- return __builtin_avr_abshr (__q);
-}
-/* fract (r): absr */
+/* 7.18a.6.3 The fixed-point round functions. */
-static __inline__ __attribute__((__always_inline__))
-fract absr (const fract __q)
-{
- return __builtin_avr_absr (__q);
-}
+/* The Embedded-C paper specifies results only for rounding points
-/* long fract (lr): abslr */
+ 0 < RP < FBIT
+
+ As an extension, the following functions work as expected
+ with rounding points
-static __inline__ __attribute__((__always_inline__))
-long fract abslr (const long fract __q)
-{
- return __builtin_avr_abslr (__q);
-}
+ -IBIT < RP < FBIT
+
+ For example, rounding an accum with a rounding point of -1 will
+ result in an even integer value. */
-/* short accum (hk): abshk */
+#define roundhr __builtin_avr_roundhr
+#define roundr __builtin_avr_roundr
+#define roundlr __builtin_avr_roundlr
-static __inline__ __attribute__((__always_inline__))
-short accum abshk (const short accum __q)
-{
- return __builtin_avr_abshk (__q);
-}
+#define rounduhr __builtin_avr_rounduhr
+#define roundur __builtin_avr_roundur
+#define roundulr __builtin_avr_roundulr
-/* accum (k): absk */
+#define roundhk __builtin_avr_roundhk
+#define roundk __builtin_avr_roundk
-static __inline__ __attribute__((__always_inline__))
-accum absk (const accum __q)
-{
- return __builtin_avr_absk (__q);
-}
+#define rounduhk __builtin_avr_rounduhk
+#define rounduk __builtin_avr_rounduk
#if __SIZEOF_INT__ == 2
-/* long long fract (llr): absllr */
-
-static __inline__ __attribute__((__always_inline__))
-long long fract absllr (const long long fract __q) /* GCC extension */
-{
- return __builtin_avr_absllr (__q);
-}
-
-/* long accum (lk): abslk */
-
-static __inline__ __attribute__((__always_inline__))
-long accum abslk (const long accum __q)
-{
- return __builtin_avr_abslk (__q);
-}
-
-/* long long accum (llk): absllk */
-
-static __inline__ __attribute__((__always_inline__))
-long long accum absllk (const long long accum __q) /* GCC extension */
-{
- return __builtin_avr_absllk (__q);
-}
-
-#endif /* __SIZEOF_INT__ == 2 */
-
-
-/* 7.18a.6.5 The bitwise fixed-point to integer conversion functions. */
-/* 7.18a.6.6 The bitwise integer to fixed-point conversion functions. */
-
-/* short fract (hr): bitshr, bitsuhr, hrbits, uhrbits */
-
-static __inline__ __attribute__((__always_inline__))
-int_hr_t bitshr (const short fract __q)
-{
- int_hr_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-uint_uhr_t bitsuhr (const unsigned short fract __q)
-{
- uint_uhr_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-short fract hrbits (const int_hr_t __i)
-{
- short fract __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-unsigned short fract uhrbits (const uint_uhr_t __i)
-{
- unsigned short fract __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-/* fract (r): bitsr, bitsur, rbits, urbits */
-
-static __inline__ __attribute__((__always_inline__))
-int_r_t bitsr (const fract __q)
-{
- int_r_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-uint_ur_t bitsur (const unsigned fract __q)
-{
- uint_ur_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-fract rbits (const int_r_t __i)
-{
- fract __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-unsigned fract urbits (const uint_ur_t __i)
-{
- unsigned fract __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-/* long fract (lr): bitslr, bitsulr, lrbits, ulrbits */
-
-static __inline__ __attribute__((__always_inline__))
-int_lr_t bitslr (const long fract __q)
-{
- int_lr_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-uint_ulr_t bitsulr (const unsigned long fract __q)
-{
- uint_ulr_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-long fract lrbits (const int_lr_t __i)
-{
- long fract __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-unsigned long fract ulrbits (const uint_ulr_t __i)
-{
- unsigned long fract __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-/* short accum (hk): bitshk, bitsuhk, hkbits, uhkbits */
-
-static __inline__ __attribute__((__always_inline__))
-int_hk_t bitshk (const short accum __q)
-{
- int_hk_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-uint_uhk_t bitsuhk (const unsigned short accum __q)
-{
- uint_uhk_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-short accum hkbits (const int_hk_t __i)
-{
- short accum __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-unsigned short accum uhkbits (const uint_uhk_t __i)
-{
- unsigned short accum __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-/* accum (k): bitsk, bitsuk, kbits, ukbits */
-
-static __inline__ __attribute__((__always_inline__))
-int_k_t bitsk (const accum __q)
-{
- int_k_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-uint_uk_t bitsuk (const unsigned accum __q)
-{
- uint_uk_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-accum kbits (const int_k_t __i)
-{
- accum __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-unsigned accum ukbits (const uint_uk_t __i)
-{
- unsigned accum __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
+#define roundlk __builtin_avr_roundlk
+#define roundulk __builtin_avr_roundulk
+#define roundllr __builtin_avr_roundllr /* GCC Extension */
+#define roundullr __builtin_avr_roundullr /* GCC Extension */
+#define roundllk __builtin_avr_roundllk /* GCC Extension */
+#define roundullk __builtin_avr_roundullk /* GCC Extension */
+
+#endif /* sizeof (int) == 2 */
+
+
+/* 7.18a.6.4 The fixed-point bit countls functions. */
+
+#define countlshr __builtin_avr_countlshr
+#define countlsr __builtin_avr_countlsr
+#define countlslr __builtin_avr_countlslr
+
+#define countlsuhr __builtin_avr_countlsuhr
+#define countlsur __builtin_avr_countlsur
+#define countlsulr __builtin_avr_countlsulr
+
+#define countlshk __builtin_avr_countlshk
+#define countlsk __builtin_avr_countlsk
+
+#define countlsuhk __builtin_avr_countlsuhk
+#define countlsuk __builtin_avr_countlsuk
#if __SIZEOF_INT__ == 2
-/* long long fract (llr): bitsllr, bitsullr, llrbits, ullrbits */
-
-static __inline__ __attribute__((__always_inline__))
-int_llr_t bitsllr (const long long fract __q)
-{
- int_llr_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-uint_ullr_t bitsullr (const unsigned long long fract __q)
-{
- uint_ullr_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-long long fract llrbits (const int_llr_t __i)
-{
- long long fract __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-unsigned long long fract ullrbits (const uint_ullr_t __i)
-{
- unsigned long long fract __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-/* long accum (lk): bitslk, bitsulk, lkbits, ulkbits */
-
-static __inline__ __attribute__((__always_inline__))
-int_lk_t bitslk (const long accum __q)
-{
- int_lk_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-uint_ulk_t bitsulk (const unsigned long accum __q)
-{
- uint_ulk_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-long accum lkbits (const int_lk_t __i)
-{
- long accum __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-unsigned long accum ulkbits (const uint_ulk_t __i)
-{
- unsigned long accum __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-/* long long accum (llk): bitsllk, bitsullk, llkbits, ullkbits */
-
-static __inline__ __attribute__((__always_inline__))
-int_llk_t bitsllk (const long long accum __q)
-{
- int_llk_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-uint_ullk_t bitsullk (const unsigned long long accum __q)
-{
- uint_ullk_t __result;
- _GCC_TYPEPUN (__result, __q);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-long long accum llkbits (const int_llk_t __i)
-{
- long long accum __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-static __inline__ __attribute__((__always_inline__))
-unsigned long long accum ullkbits (const uint_ullk_t __i)
-{
- unsigned long long accum __result;
- _GCC_TYPEPUN (__result, __i);
- return __result;
-}
-
-#endif /* __SIZEOF_INT__ == 2 */
+#define countlslk __builtin_avr_countlslk
+#define countlsulk __builtin_avr_countlsulk
+#define countlsllr __builtin_avr_countlsllr /* GCC Extension */
+#define countlsullr __builtin_avr_countlsullr /* GCC Extension */
+#define countlsllk __builtin_avr_countlsllk /* GCC Extension */
+#define countlsullk __builtin_avr_countlsullk /* GCC Extension */
+
+#endif /* sizeof (int) == 2 */
+
+
+/* 7.18a.6.5 The bitwise fixed-point to integer conversion functions. */
+
+#define bitshr __builtin_avr_bitshr
+#define bitsr __builtin_avr_bitsr
+#define bitslr __builtin_avr_bitslr
+
+#define bitsuhr __builtin_avr_bitsuhr
+#define bitsur __builtin_avr_bitsur
+#define bitsulr __builtin_avr_bitsulr
+
+#define bitshk __builtin_avr_bitshk
+#define bitsk __builtin_avr_bitsk
+
+#define bitsuhk __builtin_avr_bitsuhk
+#define bitsuk __builtin_avr_bitsuk
+
+#if __SIZEOF_INT__ == 2
+
+#define bitslk __builtin_avr_bitslk
+#define bitsulk __builtin_avr_bitsulk
+#define bitsllr __builtin_avr_bitsllr /* GCC Extension */
+#define bitsullr __builtin_avr_bitsullr /* GCC Extension */
+#define bitsllk __builtin_avr_bitsllk /* GCC Extension */
+#define bitsullk __builtin_avr_bitsullk /* GCC Extension */
+
+#endif /* sizeof (int) == 2 */
+
+
+/* 7.18a.6.6 The bitwise integer to fixed-point conversion functions. */
+
+#define hrbits __builtin_avr_hrbits
+#define rbits __builtin_avr_rbits
+#define lrbits __builtin_avr_lrbits
+
+#define uhrbits __builtin_avr_uhrbits
+#define urbits __builtin_avr_urbits
+#define ulrbits __builtin_avr_ulrbits
+
+#define hkbits __builtin_avr_hkbits
+#define kbits __builtin_avr_kbits
+
+#define uhkbits __builtin_avr_uhkbits
+#define ukbits __builtin_avr_ukbits
+
+#if __SIZEOF_INT__ == 2
+
+#define lkbits __builtin_avr_lkbits
+#define ulkbits __builtin_avr_ulkbits
+#define llrbits __builtin_avr_llrbits /* GCC Extension */
+#define ullrbits __builtin_avr_ullrbits /* GCC Extension */
+#define llkbits __builtin_avr_llkbits /* GCC Extension */
+#define ullkbits __builtin_avr_ullkbits /* GCC Extension */
+
+#endif /* sizeof (int) == 2 */
+
+
+/* 7.18a.6.7 Type-generic fixed-point functions. */
+
+#define absfx __builtin_avr_absfx
+#define roundfx __builtin_avr_roundfx
+#define countlsfx __builtin_avr_countlsfx
+
#endif /* _AVRGCC_STDFIX_H */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c8ce975..c12303d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2013-02-08 Georg-Johann Lay <avr@gjlay.de>
+
+ PR target/54222
+ * gcc.target/avr/torture/builtins-4-roundfx.c: New test.
+ * gcc.target/avr/torture/builtins-5-countlsfx.c: New test.
+
2013-02-07 Jakub Jelinek <jakub@redhat.com>
PR c++/56241
diff --git a/gcc/testsuite/gcc.target/avr/torture/builtins-4-roundfx.c b/gcc/testsuite/gcc.target/avr/torture/builtins-4-roundfx.c
new file mode 100644
index 0000000..6ad0775
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/builtins-4-roundfx.c
@@ -0,0 +1,161 @@
+/* { dg-options "-std=gnu99" } */
+/* { dg-do run } */
+
+#include <stdfix.h>
+
+extern void abort (void);
+
+typedef short _Fract fx_hr_t;
+typedef _Fract fx_r_t;
+typedef long _Fract fx_lr_t;
+typedef long long _Fract fx_llr_t;
+
+typedef unsigned short _Fract fx_uhr_t;
+typedef unsigned _Fract fx_ur_t;
+typedef unsigned long _Fract fx_ulr_t;
+typedef unsigned long long _Fract fx_ullr_t;
+
+typedef short _Accum fx_hk_t;
+typedef _Accum fx_k_t;
+typedef long _Accum fx_lk_t;
+typedef long long _Accum fx_llk_t;
+
+typedef unsigned short _Accum fx_uhk_t;
+typedef unsigned _Accum fx_uk_t;
+typedef unsigned long _Accum fx_ulk_t;
+typedef unsigned long long _Accum fx_ullk_t;
+
+
+typedef unsigned char int_uhr_t;
+typedef unsigned int int_ur_t;
+typedef unsigned long int_ulr_t;
+typedef unsigned long long int_ullr_t;
+
+typedef unsigned int int_uhk_t;
+typedef unsigned long int_uk_t;
+typedef unsigned long long int_ulk_t;
+typedef unsigned long long int_ullk_t;
+
+
+#define DEFTEST1(T,FX) \
+ T test1_##FX (T x, int rp) \
+ { \
+ return round##FX (x, rp); \
+ } \
+ \
+ unsigned T test1_u##FX (unsigned T x, int rp) \
+ { \
+ return roundu##FX (x, rp); \
+ }
+
+DEFTEST1 (short fract, hr)
+DEFTEST1 (fract, r)
+DEFTEST1 (long fract, lr)
+DEFTEST1 (long long fract, llr)
+
+DEFTEST1 (short accum, hk)
+DEFTEST1 (accum, k)
+
+DEFTEST1 (long accum, lk)
+DEFTEST1 (long long accum, llk)
+
+
+#define TEST2(FX, RP, VAL, ROUND) \
+ { \
+ if (round##FX (FX##bits (VAL), RP) != FX##bits (ROUND)) \
+ abort(); \
+ fx_##FX##_t (*f)(fx_##FX##_t,int) = round##FX; \
+ asm ("" : "+r" (f)); \
+ if (f (FX##bits (VAL), RP) != FX##bits (ROUND)) \
+ abort(); \
+ }
+
+static void test2hr (void)
+{
+ TEST2 (hr, 1, 0x7f, 0x40);
+ TEST2 (hr, 2, 0x7f, 0b1100000);
+ TEST2 (hr, 3, 0x7f, 0b1110000);
+ TEST2 (hr, 4, 0x7f, 0b1111000);
+
+ TEST2 (uhr, 1, 0x7f, 0x80);
+ TEST2 (uhr, 2, 0x7f, 0x80);
+ TEST2 (uhr, 3, 0x7f, 0x80);
+ TEST2 (uhr, 4, 0x7f, 0x80);
+}
+
+void test2k (void)
+{
+ TEST2 (k, 1, 0x7fffffff, 0x7fff8000 | 0b100000000000000);
+ TEST2 (k, 2, 0x7fffffff, 0x7fff8000 | 0b110000000000000);
+ TEST2 (k, 3, 0x7fffffff, 0x7fff8000 | 0b111000000000000);
+ TEST2 (k, 4, 0x7fffffff, 0x7fff8000 | 0b111100000000000);
+
+ TEST2 (uk, 1, 0x7fffffff, 1ul << 31);
+ TEST2 (uk, 2, 0x7fffffff, 1ul << 31);
+ TEST2 (uk, 3, 0x7fffffff, 1ul << 31);
+ TEST2 (uk, 4, 0x7fffffff, 1ul << 31);
+}
+
+#define DEFTEST3(FX, FBIT) \
+ void test3##FX (void) \
+ { \
+ TEST2 (FX, FBIT-1, 0b01100, 0b01100); \
+ TEST2 (FX, FBIT-2, 0b01100, 0b01100); \
+ TEST2 (FX, FBIT-3, 0b01100, 0b10000); \
+ TEST2 (FX, FBIT-4, 0b01100, 0b10000); \
+ TEST2 (FX, FBIT-5, 0b01100, 0); \
+ \
+ if (FX##bits ((int_##FX##_t) -1) > 0) \
+ return; \
+ \
+ TEST2 (FX, FBIT-1, -0b01100, -0b01100); \
+ TEST2 (FX, FBIT-2, -0b01100, -0b01100); \
+ TEST2 (FX, FBIT-3, -0b01100, -0b01000); \
+ TEST2 (FX, FBIT-4, -0b01100, -0b10000); \
+ TEST2 (FX, FBIT-5, -0b01100, -0b00000); \
+ }
+
+DEFTEST3 (hr, SFRACT_FBIT)
+DEFTEST3 (r, FRACT_FBIT)
+DEFTEST3 (lr, LFRACT_FBIT)
+
+DEFTEST3 (uhr, USFRACT_FBIT)
+DEFTEST3 (ur, UFRACT_FBIT)
+DEFTEST3 (ulr, ULFRACT_FBIT)
+
+DEFTEST3 (hk, SACCUM_FBIT)
+DEFTEST3 (k, ACCUM_FBIT)
+DEFTEST3 (lk, LACCUM_FBIT)
+DEFTEST3 (llk, LLACCUM_FBIT)
+
+DEFTEST3 (uhk, USACCUM_FBIT)
+DEFTEST3 (uk, UACCUM_FBIT)
+DEFTEST3 (ulk, ULACCUM_FBIT)
+DEFTEST3 (ullk, ULLACCUM_FBIT)
+
+int main (void)
+{
+ test2hr();
+ test2k();
+
+ test3hr();
+ test3r();
+ test3lr();
+
+ test3uhr();
+ test3ur();
+ test3ulr();
+
+ test3hk();
+ test3k();
+ test3lk();
+ test3llk();
+
+ test3uhk();
+ test3uk();
+ test3ulk();
+ test3ullk();
+
+ return 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/avr/torture/builtins-5-countlsfx.c b/gcc/testsuite/gcc.target/avr/torture/builtins-5-countlsfx.c
new file mode 100644
index 0000000..b0ff5e3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/builtins-5-countlsfx.c
@@ -0,0 +1,82 @@
+/* { dg-options "-std=gnu99" } */
+/* { dg-do run } */
+
+#include <stdfix.h>
+
+extern void abort (void);
+
+#define DEFTEST1(T,FX) \
+ int test1_##FX (T x) \
+ { \
+ return countls##FX (x); \
+ } \
+ \
+ int test1_u##FX (unsigned T x) \
+ { \
+ return countlsu##FX (x); \
+ }
+
+DEFTEST1 (short fract, hr)
+DEFTEST1 (fract, r)
+DEFTEST1 (long fract, lr)
+DEFTEST1 (long long fract, llr)
+
+DEFTEST1 (short accum, hk)
+DEFTEST1 (accum, k)
+DEFTEST1 (long accum, lk)
+DEFTEST1 (long long accum, llk)
+
+
+#define TEST2P(FX, VAL, DD) \
+ { \
+ if (countls##FX (FX##bits (VAL)) != 8 * sizeof (0##FX) - DD) \
+ abort(); \
+ \
+ if (countlsu##FX (u##FX##bits (VAL)) != 8 * sizeof (0u##FX) + 1 - DD) \
+ abort(); \
+ }
+
+
+#define TEST2M(FX, VAL, DD) \
+ { \
+ if (countls##FX (FX##bits (VAL)) != 8 * sizeof (0##FX) - (DD)) \
+ abort(); \
+ \
+ if (countlsu##FX (u##FX##bits (VAL)) != 0) \
+ abort(); \
+ }
+
+
+#define TEST2PX(VAL, DD) \
+ TEST2P (hr, VAL, DD); \
+ TEST2P (r, VAL, DD); \
+ TEST2P (lr, VAL, DD); \
+ \
+ TEST2P (hk, VAL, DD); \
+ TEST2P (k, VAL, DD); \
+ TEST2P (lk, VAL, DD); \
+ TEST2P (llk, VAL, DD)
+
+#define TEST2MX(VAL, DD) \
+ TEST2M (hr, VAL, DD); \
+ TEST2M (r, VAL, DD); \
+ TEST2M (lr, VAL, DD); \
+ \
+ TEST2M (hk, VAL, DD); \
+ TEST2M (k, VAL, DD); \
+ TEST2M (lk, VAL, DD); \
+ TEST2M (llk, VAL, DD)
+
+
+int main (void)
+{
+ TEST2PX (1, 2);
+ TEST2PX (2, 3);
+ TEST2PX (3, 3);
+
+ TEST2MX (-1, 1);
+ TEST2MX (-2, 2);
+ TEST2MX (-3, 3);
+
+ return 0;
+}