+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
#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
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;
}
(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")])
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; \
" 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. */
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];
UNSPEC_COPYSIGN
UNSPEC_IDENTITY
UNSPEC_INSERT_BITS
+ UNSPEC_ROUND
])
(define_c_enum "unspecv"
/* 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)
#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
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;
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 */
+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
--- /dev/null
+/* { 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;
+}
+
--- /dev/null
+/* { 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;
+}
+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.
\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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#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 */
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__
--- /dev/null
+# 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
--- /dev/null
+/* 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 */
_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,
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 \