re PR target/54222 ([avr] Implement fixed-point support)
authorGeorg-Johann Lay <avr@gjlay.de>
Fri, 8 Feb 2013 10:13:37 +0000 (10:13 +0000)
committerGeorg-Johann Lay <gjl@gcc.gnu.org>
Fri, 8 Feb 2013 10:13:37 +0000 (10:13 +0000)
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

16 files changed:
gcc/ChangeLog
gcc/config/avr/avr-c.c
gcc/config/avr/avr-fixed.md
gcc/config/avr/avr.c
gcc/config/avr/avr.md
gcc/config/avr/builtins.def
gcc/config/avr/stdfix.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/avr/torture/builtins-4-roundfx.c [new file with mode: 0644]
gcc/testsuite/gcc.target/avr/torture/builtins-5-countlsfx.c [new file with mode: 0644]
libgcc/ChangeLog
libgcc/config/avr/lib1funcs-fixed.S
libgcc/config/avr/lib1funcs.S
libgcc/config/avr/lib2-object.mk [new file with mode: 0644]
libgcc/config/avr/lib2funcs.c [new file with mode: 0644]
libgcc/config/avr/t-avr

index 787efb7..38173e9 100644 (file)
@@ -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
index ddcab54..4e64405 100644 (file)
 #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;
 }
 
 
index ce7f54d..7d9b525 100644 (file)
 (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
   "%~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")])
index c833bfb..0f1d2c1 100644 (file)
@@ -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];
index 6432d63..e9f5d03 100644 (file)
@@ -68,6 +68,7 @@
    UNSPEC_COPYSIGN
    UNSPEC_IDENTITY
    UNSPEC_INSERT_BITS
+   UNSPEC_ROUND
    ])
 
 (define_c_enum "unspecv"
index ecce186..ce444ab 100644 (file)
@@ -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)
index b86195a..afcacdf 100644 (file)
 
 #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 */
index c8ce975..c12303d 100644 (file)
@@ -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 (file)
index 0000000..6ad0775
--- /dev/null
@@ -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 (file)
index 0000000..b0ff5e3
--- /dev/null
@@ -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;
+}
index ed8c0a1..13fc01d 100644 (file)
@@ -1,3 +1,17 @@
+2013-02-08  Georg-Johann Lay  <avr@gjlay.de>
+
+       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.
+
 2013-02-04  Richard Sandiford  <rdsandiford@googlemail.com>
 
        Update copyright years.
index 731da44..92d8eaf 100644 (file)
@@ -959,6 +959,28 @@ ENDF __udivusa3
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Saturation, 1 Byte
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; First Argument and Return Register
+#define A0  24
+
+#if defined (L_ssabs_1)
+DEFUN __ssabs_1
+    sbrs    A0, 7
+    ret
+    neg     A0
+    sbrc    A0,7
+    dec     A0
+    ret
+ENDF __ssabs_1
+#endif /* L_ssabs_1 */
+
+#undef A0
+
+
+\f
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Saturation, 2 Bytes
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -1176,3 +1198,509 @@ ENDF __sssub_8
 #undef B5
 #undef B6
 #undef B7
+
+\f
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Rounding Helpers
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+#ifdef L_mask1
+
+#define AA 24
+#define CC 25
+
+;; R25 = 1 << (R24 & 7)
+;; CC  = 1 << (AA  & 7)
+;; Clobbers: None
+DEFUN __mask1
+    ;; CC = 2 ^ AA.1
+    ldi     CC, 1 << 2
+    sbrs    AA, 1
+    ldi     CC, 1 << 0
+    ;; CC *= 2 ^ AA.0
+    sbrc    AA, 0
+    lsl     CC
+    ;; CC *= 2 ^ AA.2
+    sbrc    AA, 2
+    swap    CC
+    ret
+ENDF __mask1
+
+#undef AA
+#undef CC
+#endif /* L_mask1 */
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; The rounding point. Any bits smaller than
+;; 2^{-RP} will be cleared.
+#define RP R24
+
+#define A0 22
+#define A1 A0 + 1
+
+#define C0 24
+#define C1 C0 + 1
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Rounding, 1 Byte
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+#ifdef L_roundqq3
+
+;; R24 = round (R22, R24)
+;; Clobbers: R22, __tmp_reg__
+DEFUN  __roundqq3
+    mov     __tmp_reg__, C1
+    subi    RP, __QQ_FBIT__ - 1
+    neg     RP
+    ;; R25 = 1 << RP  (Total offset is FBIT-1 - RP)
+    XCALL   __mask1
+    mov     C0, C1
+    ;; Add-Saturate 2^{-RP-1}
+    add     A0, C0
+    brvc 0f
+    ldi     A0, 0x7f
+0:  ;; Mask out bits beyond RP
+    lsl     C0
+    neg     C0
+    and     C0, A0
+    mov     C1, __tmp_reg__
+    ret
+ENDF  __roundqq3
+#endif /* L_roundqq3 */
+
+#ifdef L_rounduqq3
+
+;; R24 = round (R22, R24)
+;; Clobbers: R22, __tmp_reg__
+DEFUN  __rounduqq3
+    mov     __tmp_reg__, C1
+    subi    RP, __UQQ_FBIT__ - 1
+    neg     RP
+    ;; R25 = 1 << RP  (Total offset is FBIT-1 - RP)
+    XCALL   __mask1
+    mov     C0, C1
+    ;; Add-Saturate 2^{-RP-1}
+    add     A0, C0
+    brcc 0f
+    ldi     A0, 0xff
+0:  ;; Mask out bits beyond RP
+    lsl     C0
+    neg     C0
+    and     C0, A0
+    mov     C1, __tmp_reg__
+    ret
+ENDF  __rounduqq3
+#endif /* L_rounduqq3 */
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Rounding, 2 Bytes
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+#ifdef L_addmask_2
+
+;; [ R25:R24 =  1 << (R24 & 15)
+;;   R23:R22 += 1 << (R24 & 15) ]
+;; SREG is set according to the addition
+DEFUN __addmask_2
+    ;; R25 = 1 << (R24 & 7)
+    XCALL   __mask1
+    cpi     RP, 1 << 3
+    sbc     C0, C0
+    ;; Swap C0 and C1 if RP.3 was set
+    and     C0, C1
+    eor     C1, C0
+    ;; Finally, add the power-of-two:  A[] += C[]
+    add     A0, C0
+    adc     A1, C1
+    ret
+ENDF  __addmask_2
+#endif /* L_addmask_2 */
+
+#ifdef L_round_s2
+
+;; R25:R24 = round (R23:R22, R24)
+;; Clobbers: R23, R22
+DEFUN  __roundhq3
+    subi    RP, __HQ_FBIT__ - __HA_FBIT__
+ENDF   __roundhq3
+DEFUN  __roundha3
+    subi    RP, __HA_FBIT__ - 1
+    neg     RP
+    ;; [ R25:R24  = 1 << (FBIT-1 - RP)
+    ;;   R23:R22 += 1 << (FBIT-1 - RP) ]
+    XCALL   __addmask_2
+    XJMP    __round_s2_const
+ENDF  __roundha3
+
+#endif /* L_round_s2 */
+
+#ifdef L_round_u2
+
+;; R25:R24 = round (R23:R22, R24)
+;; Clobbers: R23, R22
+DEFUN  __rounduhq3
+    subi    RP, __UHQ_FBIT__ - __UHA_FBIT__
+ENDF   __rounduhq3
+DEFUN  __rounduha3
+    subi    RP, __UHA_FBIT__ - 1
+    neg     RP
+    ;; [ R25:R24  = 1 << (FBIT-1 - RP)
+    ;;   R23:R22 += 1 << (FBIT-1 - RP) ]
+    XCALL   __addmask_2
+    XJMP    __round_u2_const 
+ENDF  __rounduha3
+
+#endif /* L_round_u2 */
+
+
+#ifdef L_round_2_const
+
+;; Helpers for 2 byte wide rounding
+
+DEFUN  __round_s2_const
+    brvc 2f
+    ldi     A1, 0x7f
+    rjmp 1f
+    ;; FALLTHRU (Barrier)
+ENDF  __round_s2_const
+
+DEFUN __round_u2_const
+    brcc 2f
+    ldi     A1, 0xff
+1:
+    ldi     A0, 0xff
+2:
+    ;; Saturation is performed now.
+    ;; Currently, we have C[] = 2^{-RP-1}
+    ;; C[] = 2^{-RP}
+    lsl     C0
+    rol     C1
+    ;;      
+    NEG2    C0
+    ;; Clear the bits beyond the rounding point.
+    and     C0, A0
+    and     C1, A1
+    ret
+ENDF  __round_u2_const
+
+#endif /* L_round_2_const */
+
+#undef A0
+#undef A1
+#undef C0
+#undef C1
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Rounding, 4 Bytes
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+#define A0 18
+#define A1 A0 + 1
+#define A2 A0 + 2
+#define A3 A0 + 3
+
+#define C0 22
+#define C1 C0 + 1
+#define C2 C0 + 2
+#define C3 C0 + 3
+
+#ifdef L_addmask_4
+
+;; [ R25:R22 =  1 << (R24 & 31)
+;;   R21:R18 += 1 << (R24 & 31) ]
+;; SREG is set according to the addition
+DEFUN __addmask_4
+    ;; R25 = 1 << (R24 & 7)
+    XCALL   __mask1
+    cpi     RP, 1 << 4
+    sbc     C0, C0
+    sbc     C1, C1
+    ;; Swap C2 with C3 if RP.3 is not set
+    cpi     RP, 1 << 3
+    sbc     C2, C2
+    and     C2, C3
+    eor     C3, C2
+    ;; Swap C3:C2 with C1:C0 if RP.4 is not set
+    and     C0, C2  $  eor     C2, C0
+    and     C1, C3  $  eor     C3, C1
+    ;; Finally, add the power-of-two:  A[] += C[]
+    add     A0, C0
+    adc     A1, C1
+    adc     A2, C2
+    adc     A3, C3
+    ret
+ENDF  __addmask_4
+#endif /* L_addmask_4 */
+
+#ifdef L_round_s4
+
+;; R25:R22 = round (R21:R18, R24)
+;; Clobbers: R18...R21
+DEFUN  __roundsq3
+    subi    RP, __SQ_FBIT__ - __SA_FBIT__
+ENDF   __roundsq3
+DEFUN  __roundsa3
+    subi    RP, __SA_FBIT__ - 1
+    neg     RP
+    ;; [ R25:R22  = 1 << (FBIT-1 - RP)
+    ;;   R21:R18 += 1 << (FBIT-1 - RP) ]
+    XCALL   __addmask_4
+    XJMP    __round_s4_const
+ENDF  __roundsa3
+
+#endif /* L_round_s4 */
+
+#ifdef L_round_u4
+
+;; R25:R22 = round (R21:R18, R24)
+;; Clobbers: R18...R21
+DEFUN  __roundusq3
+    subi    RP, __USQ_FBIT__ - __USA_FBIT__
+ENDF   __roundusq3
+DEFUN  __roundusa3
+    subi    RP, __USA_FBIT__ - 1
+    neg     RP
+    ;; [ R25:R22  = 1 << (FBIT-1 - RP)
+    ;;   R21:R18 += 1 << (FBIT-1 - RP) ]
+    XCALL   __addmask_4
+    XJMP    __round_u4_const 
+ENDF  __roundusa3
+
+#endif /* L_round_u4 */
+
+
+#ifdef L_round_4_const
+
+;; Helpers for 4 byte wide rounding
+
+DEFUN  __round_s4_const
+    brvc 2f
+    ldi     A3, 0x7f
+    rjmp 1f
+    ;; FALLTHRU (Barrier)
+ENDF  __round_s4_const
+
+DEFUN __round_u4_const
+    brcc 2f
+    ldi     A3, 0xff
+1:
+    ldi     A2, 0xff
+    ldi     A1, 0xff
+    ldi     A0, 0xff
+2:
+    ;; Saturation is performed now.
+    ;; Currently, we have C[] = 2^{-RP-1}
+    ;; C[] = 2^{-RP}
+    lsl     C0
+    rol     C1
+    rol     C2
+    rol     C3
+    XCALL   __negsi2
+    ;; Clear the bits beyond the rounding point.
+    and     C0, A0
+    and     C1, A1
+    and     C2, A2
+    and     C3, A3
+    ret
+ENDF  __round_u4_const
+
+#endif /* L_round_4_const */
+
+#undef A0
+#undef A1
+#undef A2
+#undef A3
+#undef C0
+#undef C1
+#undef C2
+#undef C3
+
+#undef RP
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Rounding, 8 Bytes
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+#define RP     16
+#define FBITm1 31
+
+#define C0 18
+#define C1 C0 + 1
+#define C2 C0 + 2
+#define C3 C0 + 3
+#define C4 C0 + 4
+#define C5 C0 + 5
+#define C6 C0 + 6
+#define C7 C0 + 7
+
+#define A0 16
+#define A1 17
+#define A2 26
+#define A3 27
+#define A4 28
+#define A5 29
+#define A6 30
+#define A7 31
+
+
+#ifdef L_rounddq3
+;; R25:R18 = round (R25:R18, R16)
+;; Clobbers: ABI
+DEFUN  __rounddq3
+    ldi     FBITm1, __DQ_FBIT__ - 1
+    clt
+    XJMP    __round_x8
+ENDF  __rounddq3
+#endif /* L_rounddq3 */
+
+#ifdef L_roundudq3
+;; R25:R18 = round (R25:R18, R16)
+;; Clobbers: ABI
+DEFUN  __roundudq3
+    ldi     FBITm1, __UDQ_FBIT__ - 1
+    set
+    XJMP    __round_x8
+ENDF  __roundudq3
+#endif /* L_roundudq3 */
+
+#ifdef L_roundda3
+;; R25:R18 = round (R25:R18, R16)
+;; Clobbers: ABI
+DEFUN  __roundda3
+    ldi     FBITm1, __DA_FBIT__ - 1
+    clt
+    XJMP    __round_x8
+ENDF  __roundda3
+#endif /* L_roundda3 */
+
+#ifdef L_rounduda3
+;; R25:R18 = round (R25:R18, R16)
+;; Clobbers: ABI
+DEFUN  __rounduda3
+    ldi     FBITm1, __UDA_FBIT__ - 1
+    set
+    XJMP    __round_x8
+ENDF  __rounduda3
+#endif /* L_rounduda3 */
+
+#ifdef L_roundta3
+;; R25:R18 = round (R25:R18, R16)
+;; Clobbers: ABI
+DEFUN  __roundta3
+    ldi     FBITm1, __TA_FBIT__ - 1
+    clt
+    XJMP    __round_x8
+ENDF  __roundta3
+#endif /* L_roundta3 */
+
+#ifdef L_rounduta3
+;; R25:R18 = round (R25:R18, R16)
+;; Clobbers: ABI
+DEFUN  __rounduta3
+    ldi     FBITm1, __UTA_FBIT__ - 1
+    set
+    XJMP    __round_x8
+ENDF  __rounduta3
+#endif /* L_rounduta3 */
+
+
+#ifdef L_round_x8
+DEFUN __round_x8
+    push r16
+    push r17
+    push r28
+    push r29
+    ;; Compute log2 of addend from rounding point
+    sub     RP, FBITm1
+    neg     RP
+    ;; Move input to work register A[]
+    push    C0
+    mov     A1, C1
+    wmov    A2, C2
+    wmov    A4, C4
+    wmov    A6, C6
+    ;; C[] = 1 << (FBIT-1 - RP)
+    XCALL   __clr_8
+    inc     C0
+    XCALL   __ashldi3
+    pop     A0
+    ;; A[] += C[]
+    add     A0, C0
+    adc     A1, C1
+    adc     A2, C2
+    adc     A3, C3
+    adc     A4, C4
+    adc     A5, C5
+    adc     A6, C6
+    adc     A7, C7
+    brts    1f
+    ;; Signed
+    brvc    3f
+    ;; Signed overflow: A[] = 0x7f...
+    brvs    2f
+1:  ;; Unsigned
+    brcc    3f
+    ;; Unsigned overflow: A[] = 0xff...
+2:  ldi     A7, 0xff
+    ldi     A6, 0xff
+    wmov    A0, A6
+    wmov    A2, A6
+    wmov    A4, A6
+    bld     A7, 7
+3:
+    ;;  C[] = -C[] - C[]
+    push    A0
+    ldi     r16, 1
+    XCALL   __ashldi3
+    pop     A0
+    XCALL   __negdi2
+    ;; Clear the bits beyond the rounding point.
+    and     C0, A0
+    and     C1, A1
+    and     C2, A2
+    and     C3, A3
+    and     C4, A4
+    and     C5, A5
+    and     C6, A6
+    and     C7, A7
+    ;; Epilogue
+    pop r29
+    pop r28
+    pop r17
+    pop r16
+    ret
+ENDF  __round_x8
+
+#endif /* L_round_x8 */
+
+#undef A0
+#undef A1
+#undef A2
+#undef A3
+#undef A4
+#undef A5
+#undef A6
+#undef A7
+
+#undef C0
+#undef C1
+#undef C2
+#undef C3
+#undef C4
+#undef C5
+#undef C6
+#undef C7
+
+#undef RP
+#undef FBITm1
+
+
+;; Supply implementations / symbols for the bit-banging functions
+;; __builtin_avr_bitsfx and __builtin_avr_fxbits
+#ifdef L_ret
+DEFUN __ret
+    ret
+ENDF  __ret
+#endif /* L_ret */
index 9ca83a8..0a406d5 100644 (file)
@@ -1684,12 +1684,12 @@ DEFUN  __divdi3_moddi3
 
 ENDF __divdi3_moddi3
 
+#endif /* L_divdi3 */
+
 #undef R_cnt
 #undef SS
 #undef NN
 
-#endif /* L_divdi3 */
-
 .section .text.libgcc, "ax", @progbits
 
 #define TT __tmp_reg__
diff --git a/libgcc/config/avr/lib2-object.mk b/libgcc/config/avr/lib2-object.mk
new file mode 100644 (file)
index 0000000..6a9e04d
--- /dev/null
@@ -0,0 +1,23 @@
+# This file is included several times in a row, once for each element of
+# $(iter-items).  On each inclusion, we advance $o to the next element.
+# $(iter-labels) and $(iter-flags) are also advanced.
+# This works similar to $(srcdir)/siditi-object.mk.
+
+o := $(firstword $(iter-items))
+iter-items := $(filter-out $o,$(iter-items))
+
+$o-label := $(firstword $(iter-labels))
+iter-labels := $(wordlist 2,$(words $(iter-labels)),$(iter-labels))
+
+$o-flag := $(firstword $(iter-flags))
+iter-flags := $(wordlist 2,$(words $(iter-flags)),$(iter-flags))
+
+$o$(objext): %$(objext): $(srcdir)/config/avr/lib2funcs.c
+       $(gcc_compile) -DL_$($*-label) -DL_LABEL=$($*-label) $($*-flag) \
+               -c $< $(vis_hide)
+
+ifeq ($(enable_shared),yes)
+$(o)_s$(objext): %_s$(objext): $(srcdir)/config/avr/lib2funcs.c
+       $(gcc_s_compile) -DL_$($*-label) -DL_LABEL=$($*-label) $($*-flag) \
+               -c $<
+endif
diff --git a/libgcc/config/avr/lib2funcs.c b/libgcc/config/avr/lib2funcs.c
new file mode 100644 (file)
index 0000000..83f2e23
--- /dev/null
@@ -0,0 +1,226 @@
+/* Copyright (C) 2013 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 3, 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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+/* This file supplies implementations for some AVR-specific builtin
+   functions so that code like the following works as expected:
+
+   int (*f (void))(_Fract)
+   {
+       return __builtin_avr_countlsr;
+   }
+
+   In this specific case, the generated code is:
+
+   f:
+       ldi r24,lo8(gs(__countlsHI))
+       ldi r25,hi8(gs(__countlsHI))
+       ret
+*/
+
+/* Map fixed-point suffix to the corresponding fixed-point type.  */
+
+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;
+
+/* Map fixed-point suffix to the corresponding natural integer type.  */
+
+typedef char int_hr_t;
+typedef int int_r_t;
+typedef long int_lr_t;
+typedef long long int_llr_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 int int_hk_t;
+typedef long int_k_t;
+typedef long long int_lk_t;
+typedef long long int_llk_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;
+
+/* Map mode to the corresponding integer type.  */
+
+typedef char int_qi_t;
+typedef int int_hi_t;
+typedef long int_si_t;
+typedef long long int_di_t;
+
+typedef unsigned char uint_qi_t;
+typedef unsigned int uint_hi_t;
+typedef unsigned long uint_si_t;
+typedef unsigned long long uint_di_t;
+
+
+\f
+/************************************************************************/
+
+/* Supply implementations / symbols for __builtin_roundFX ASM_NAME.  */
+
+#ifdef L_round
+
+#define ROUND1(FX)                              \
+  ROUND2 (FX)
+
+#define ROUND2(FX)                                                      \
+  extern fx_## FX ##_t __round## FX (fx_## FX ##_t x, int rpoint);      \
+                                                                        \
+  fx_## FX ##_t                                                         \
+  __round## FX (fx_## FX ##_t x, int rpoint)                            \
+  {                                                                     \
+    return __builtin_avr_round ##FX (x, rpoint);                        \
+  }
+
+ROUND1(L_LABEL)
+
+#endif /* L_round */
+
+
+\f
+/*********************************************************************/
+
+/* Implement some count-leading-redundant-sign-bits to be used with
+   coundlsFX implementation.  */
+
+#ifdef L__clrsbqi
+extern int __clrsbqi2 (char x);
+
+int
+__clrsbqi2 (char x)
+{
+  int ret;
+
+  if (x < 0)
+    x = ~x;
+
+  if (x == 0)
+    return 8 * sizeof (x) -1;
+
+  ret = __builtin_clz (x << 8);
+  return ret - 1;
+}
+#endif /* L__clrsbqi */
+
+
+#ifdef L__clrsbdi
+extern int __clrsbdi2 (long long x);
+
+int
+__clrsbdi2 (long long x)
+{
+  int ret;
+
+  if (x < 0LL)
+    x = ~x;
+
+  if (x == 0LL)
+    return 8 * sizeof (x) -1;
+
+  ret = __builtin_clzll ((unsigned long long) x);
+  return ret - 1;
+}
+#endif /* L__clrsbdi */
+
+
+\f
+/*********************************************************************/
+
+/* Supply implementations / symbols for __builtin_avr_countlsFX.  */
+
+/* Signed */
+
+#ifdef L_countls
+
+#define COUNTLS1(MM)                            \
+  COUNTLS2 (MM)
+
+#define COUNTLS2(MM)                                                    \
+  extern int __countls## MM ##2 (int_## MM ##_t);                       \
+  extern int __clrsb## MM ##2 (int_## MM ##_t);                         \
+                                                                        \
+  int                                                                   \
+  __countls## MM ##2 (int_## MM ##_t x)                                 \
+  {                                                                     \
+    if (x == 0)                                                         \
+      return __INT8_MAX__;                                              \
+                                                                        \
+    return __clrsb## MM ##2 (x);                                        \
+  }
+
+COUNTLS1(L_LABEL)
+
+#endif /* L_countls */
+
+/* Unsigned */
+
+#ifdef L_countlsu
+
+#define clz_qi2 __builtin_clz /* unused, avoid warning */
+#define clz_hi2 __builtin_clz
+#define clz_si2 __builtin_clzl
+#define clz_di2 __builtin_clzll
+
+#define COUNTLS1(MM)                            \
+  COUNTLS2 (MM)
+
+#define COUNTLS2(MM)                                                    \
+  extern int __countlsu## MM ##2 (uint_## MM ##_t);                     \
+                                                                        \
+  int                                                                   \
+  __countlsu## MM ##2 (uint_## MM ##_t x)                               \
+  {                                                                     \
+    if (x == 0)                                                         \
+      return __INT8_MAX__;                                              \
+                                                                        \
+    if (sizeof (x) == 1)                                                \
+      return clz_hi2 (x << 8);                                          \
+    else                                                                \
+      return clz_## MM ##2 (x);                                         \
+  }
+
+COUNTLS1(L_LABEL)
+
+#endif /* L_countlsu */
index 3bc0718..a4b8113 100644 (file)
@@ -75,13 +75,24 @@ LIB1ASMFUNCS += \
        _divsa3 _udivusa3 \
        _clr_8 \
        _ssneg_2 _ssneg_4 _ssneg_8 \
-       _ssabs_2 _ssabs_4 _ssabs_8 \
+       _ssabs_1 _ssabs_2 _ssabs_4 _ssabs_8 \
        _ssadd_8 _sssub_8 \
-       _usadd_8 _ussub_8
+       _usadd_8 _ussub_8 \
+       _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 \
+
 
 LIB2FUNCS_EXCLUDE = \
        _moddi3 _umoddi3 \
-       _clz
+       _clz \
+       _clrsbdi2 \
+
 
 # We do not have the DF type.
 # Most of the C functions in libgcc2 use almost all registers,
@@ -106,13 +117,84 @@ ifeq ($(enable_shared),yes)
 libgcc-s-objects += $(patsubst %,%_s$(objext),$(hiintfuncs16))
 endif
 
-
-# Filter out supported conversions from fixed-bit.c
-# Also filter out TQ and UTQ.
+###
 
 conv_XY=$(conv)$(mode1)$(mode2)
 func_X=$(func)$(mode)
 
+# Compile C functions from lib2funcs.c and add them to libgcc.a.
+#
+# Some functions which are not performance.critical are more convenient
+# to implement in C than in assembler.  Most of them serve as implementation
+# for AVR-specific builtins in the case where the address of a builtin
+# function is taken or if there is no insn that implements the builtin.
+#
+# We don't use LIB2ADD because we want to iterate over the source for
+# different modes, fixed-point suffixes, etc.  See iter-labels and L_LABEL.
+# iter-label will get one more underscore in order to avoid too short
+# labels like -DLk and we use -DL_k instead.
+
+# Build roundFX functions from lib2funcs.c
+
+round_suffix :=  hr r lr uhr ur ulr  \
+                hk k    uhk uk 
+round_funcs  := $(foreach func,_round,\
+               $(foreach mode,$(round_suffix),$(func_X)))
+
+iter-items  := $(round_funcs)
+iter-labels := $(round_suffix)
+iter-flags  := $(patsubst %,-DL_round,$(iter-items))
+
+include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/config/avr/lib2-object.mk,$(iter-items))
+
+libgcc-objects += $(patsubst %,%$(objext),$(round_funcs))
+
+# Build clrsbXX functions from lib2funcs.c
+
+clrsb_modes := qi di
+clrsb_funcs := $(foreach func,_clrsb,\
+              $(foreach mode,$(clrsb_modes),$(func_X)))
+
+iter-items  := $(clrsb_funcs)
+iter-labels := $(clrsb_funcs)
+iter-flags  := $(patsubst %,-DL_clrsb,$(iter-items))
+
+include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/config/avr/lib2-object.mk,$(iter-items))
+
+libgcc-objects += $(patsubst %,%$(objext),$(clrsb_funcs))
+
+# Build signed countlsFX functions from lib2funcs.c
+
+countls_modes := qi hi si di
+countls_funcs := $(foreach func,_countls,\
+                $(foreach mode,$(countls_modes),$(func_X)))
+
+iter-items  := $(countls_funcs)
+iter-labels := $(countls_modes)
+iter-flags  := $(patsubst %,-DL_countls,$(iter-items))
+
+include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/config/avr/lib2-object.mk,$(iter-items))
+
+libgcc-objects += $(patsubst %,%$(objext),$(countls_funcs))
+
+# Build unsigned countlsFX functions from lib2funcs.c
+
+countlsu_modes := qi hi si di
+countlsu_funcs := $(foreach func,_countlsu,\
+                 $(foreach mode,$(countlsu_modes),$(func_X)))
+
+iter-items  := $(countlsu_funcs)
+iter-labels := $(countlsu_modes)
+iter-flags  := $(patsubst %,-DL_countlsu,$(iter-items))
+
+include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/config/avr/lib2-object.mk,$(iter-items))
+
+libgcc-objects += $(patsubst %,%$(objext),$(countlsu_funcs))
+
+
+# Filter out supported conversions from fixed-bit.c
+# Also filter out TQ and UTQ.
+
 # Conversions supported by the compiler
 
 convf_modes =   QI UQI QQ UQQ \