+2011-04-14 Anatoly Sokolov <aesok@post.ru>
+ Eric Weddington <eric.weddington@atmel.com>
+ Georg-Johann Lay <avr@gjlay.de>
+
+ * config/avr/avr.c: ("insn-codes.h", "optabs.h", "langhooks.h"):
+ New Includes
+ (avr_init_builtins, avr_expand_builtin,
+ avr_expand_delay_cycles, avr_expand_unop_builtin,
+ avr_expand_binop_builtin ): New functions.
+ (avr_builtin_id): New enum
+ (struct avr_builtin_description): New struct
+ (bdesc_1arg, bdesc_2arg): New arrays describing some RTL builtins.
+ (TARGET_INIT_BUILTINS, TARGET_EXPAND_BUILTIN): Define.
+
+ * config/avr/avr.md (UNSPEC_FMUL, UNSPEC_FMULS, UNSPEC_FMULSU,
+ UNSPECV_ENABLE_IRQS, UNSPECV_NOP, UNSPECV_SLEEP, UNSPECV_WDR,
+ UNSPECV_DELAY_CYCLES): new enumeration values
+ (UNSPEC_SEI, UNSPEC_CLI): Remove enumeration values
+ ("enable_interrupt"): Use UNSPECV_ENABLE_IRQS
+ ("disable_interrupt"): Use UNSPECV_ENABLE_IRQS
+ ("*rotlqi3_4"): rename insn to "rotlqi3_4"
+ ("delay_cycles_1", "delay_cycles_2", "delay_cycles_3",
+ "delay_cycles_4", "nopv", "sleep", "wdr", "fmul", "fmuls",
+ "fmulsu"): New insns
+
+ * config/avr/avr-c.c: fix line endings
+ (avr_cpu_cpp_builtins): New builtin defines: __BUILTIN_AVR_NOP,
+ __BUILTIN_AVR_SEI, __BUILTIN_AVR_CLI, __BUILTIN_AVR_WDR,
+ __BUILTIN_AVR_SLEEP, __BUILTIN_AVR_SWAP,
+ __BUILTIN_AVR_DELAY_CYCLES, __BUILTIN_AVR_FMUL,
+ __BUILTIN_AVR_FMULS, __BUILTIN_AVR_FMULSU.
+
+ * doc/extend.texi (AVR Built-in Functions): New node
+ (Target Builtins): Add documentation of AVR
+ built-in functions.
+
2011-04-14 Georg-Johann Lay <avr@gjlay.de>
PR target/44643
-/* Copyright (C) 2009, 2010\r
- Free Software Foundation, Inc.\r
- Contributed by Anatoly Sokolov (aesok@post.ru)\r
-\r
- This file is part of GCC.\r
-\r
- GCC is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU General Public License as published by\r
- the Free Software Foundation; either version 3, or (at your option)\r
- any later version.\r
- \r
- GCC is distributed in the hope that it will be useful,\r
- but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
- \r
- You should have received a copy of the GNU General Public License\r
- along with GCC; see the file COPYING3. If not see\r
- <http://www.gnu.org/licenses/>. */\r
-\r
-\r
-#include "config.h"\r
-#include "system.h"\r
-#include "coretypes.h"\r
-#include "tm.h"\r
-#include "tm_p.h"\r
-#include "cpplib.h"\r
-#include "tree.h"\r
-#include "c-family/c-common.h"\r
-\r
-/* Not included in avr.c since this requires C front end. */\r
-\r
-/* Worker function for TARGET_CPU_CPP_BUILTINS. */\r
-\r
-void\r
-avr_cpu_cpp_builtins (struct cpp_reader *pfile)\r
-{\r
- builtin_define_std ("AVR");\r
-\r
- if (avr_current_arch->macro)\r
- cpp_define (pfile, avr_current_arch->macro);\r
- if (avr_extra_arch_macro)\r
- cpp_define (pfile, avr_extra_arch_macro);\r
- if (avr_current_arch->have_elpm)\r
- cpp_define (pfile, "__AVR_HAVE_RAMPZ__");\r
- if (avr_current_arch->have_elpm)\r
- cpp_define (pfile, "__AVR_HAVE_ELPM__");\r
- if (avr_current_arch->have_elpmx)\r
- cpp_define (pfile, "__AVR_HAVE_ELPMX__");\r
- if (avr_current_arch->have_movw_lpmx)\r
- {\r
- cpp_define (pfile, "__AVR_HAVE_MOVW__");\r
- cpp_define (pfile, "__AVR_HAVE_LPMX__");\r
- }\r
- if (avr_current_arch->asm_only)\r
- cpp_define (pfile, "__AVR_ASM_ONLY__");\r
- if (avr_current_arch->have_mul)\r
- {\r
- cpp_define (pfile, "__AVR_ENHANCED__");\r
- cpp_define (pfile, "__AVR_HAVE_MUL__");\r
- }\r
- if (avr_current_arch->have_jmp_call)\r
- {\r
- cpp_define (pfile, "__AVR_MEGA__");\r
- cpp_define (pfile, "__AVR_HAVE_JMP_CALL__");\r
- }\r
- if (avr_current_arch->have_eijmp_eicall)\r
- {\r
- cpp_define (pfile, "__AVR_HAVE_EIJMP_EICALL__");\r
- cpp_define (pfile, "__AVR_3_BYTE_PC__");\r
- }\r
- else\r
- {\r
- cpp_define (pfile, "__AVR_2_BYTE_PC__");\r
- }\r
-\r
- if (avr_current_device->short_sp)\r
- cpp_define (pfile, "__AVR_HAVE_8BIT_SP__");\r
- else\r
- cpp_define (pfile, "__AVR_HAVE_16BIT_SP__");\r
-\r
- if (TARGET_NO_INTERRUPTS)\r
- cpp_define (pfile, "__NO_INTERRUPTS__");\r
-}\r
-\r
+/* Copyright (C) 2009, 2010
+ Free Software Foundation, Inc.
+ Contributed by Anatoly Sokolov (aesok@post.ru)
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tm_p.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "c-family/c-common.h"
+
+/* Not included in avr.c since this requires C front end. */
+
+/* Worker function for TARGET_CPU_CPP_BUILTINS. */
+
+void
+avr_cpu_cpp_builtins (struct cpp_reader *pfile)
+{
+ builtin_define_std ("AVR");
+
+ if (avr_current_arch->macro)
+ cpp_define (pfile, avr_current_arch->macro);
+ if (avr_extra_arch_macro)
+ cpp_define (pfile, avr_extra_arch_macro);
+ if (avr_current_arch->have_elpm)
+ cpp_define (pfile, "__AVR_HAVE_RAMPZ__");
+ if (avr_current_arch->have_elpm)
+ cpp_define (pfile, "__AVR_HAVE_ELPM__");
+ if (avr_current_arch->have_elpmx)
+ cpp_define (pfile, "__AVR_HAVE_ELPMX__");
+ if (avr_current_arch->have_movw_lpmx)
+ {
+ cpp_define (pfile, "__AVR_HAVE_MOVW__");
+ cpp_define (pfile, "__AVR_HAVE_LPMX__");
+ }
+ if (avr_current_arch->asm_only)
+ cpp_define (pfile, "__AVR_ASM_ONLY__");
+ if (avr_current_arch->have_mul)
+ {
+ cpp_define (pfile, "__AVR_ENHANCED__");
+ cpp_define (pfile, "__AVR_HAVE_MUL__");
+ }
+ if (avr_current_arch->have_jmp_call)
+ {
+ cpp_define (pfile, "__AVR_MEGA__");
+ cpp_define (pfile, "__AVR_HAVE_JMP_CALL__");
+ }
+ if (avr_current_arch->have_eijmp_eicall)
+ {
+ cpp_define (pfile, "__AVR_HAVE_EIJMP_EICALL__");
+ cpp_define (pfile, "__AVR_3_BYTE_PC__");
+ }
+ else
+ {
+ cpp_define (pfile, "__AVR_2_BYTE_PC__");
+ }
+
+ if (avr_current_device->short_sp)
+ cpp_define (pfile, "__AVR_HAVE_8BIT_SP__");
+ else
+ cpp_define (pfile, "__AVR_HAVE_16BIT_SP__");
+
+ if (TARGET_NO_INTERRUPTS)
+ cpp_define (pfile, "__NO_INTERRUPTS__");
+
+ /* Define builtin macros so that the user can
+ easily query if or if not a specific builtin
+ is available. */
+
+ cpp_define (pfile, "__BUILTIN_AVR_NOP");
+ cpp_define (pfile, "__BUILTIN_AVR_SEI");
+ cpp_define (pfile, "__BUILTIN_AVR_CLI");
+ cpp_define (pfile, "__BUILTIN_AVR_WDR");
+ cpp_define (pfile, "__BUILTIN_AVR_SLEEP");
+ cpp_define (pfile, "__BUILTIN_AVR_SWAP");
+ cpp_define (pfile, "__BUILTIN_AVR_DELAY_CYCLES");
+
+ if (AVR_HAVE_MUL)
+ {
+ cpp_define (pfile, "__BUILTIN_AVR_FMUL");
+ cpp_define (pfile, "__BUILTIN_AVR_FMULS");
+ cpp_define (pfile, "__BUILTIN_AVR_FMULSU");
+ }
+}
#include "insn-config.h"
#include "conditions.h"
#include "insn-attr.h"
+#include "insn-codes.h"
#include "flags.h"
#include "reload.h"
#include "tree.h"
#include "obstack.h"
#include "function.h"
#include "recog.h"
+#include "optabs.h"
#include "ggc.h"
+#include "langhooks.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
static int avr_address_cost (rtx, bool);
static bool avr_return_in_memory (const_tree, const_tree);
static struct machine_function * avr_init_machine_status (void);
+static void avr_init_builtins (void);
+static rtx avr_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
static rtx avr_builtin_setjmp_frame_value (void);
static bool avr_hard_regno_scratch_ok (unsigned int);
static unsigned int avr_case_values_threshold (void);
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
#define TARGET_FUNCTION_OK_FOR_SIBCALL avr_function_ok_for_sibcall
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS avr_init_builtins
+
+#undef TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN avr_expand_builtin
+
+
struct gcc_target targetm = TARGET_INITIALIZER;
\f
static void
return (!AVR_HAVE_JMP_CALL || TARGET_CALL_PROLOGUES) ? 8 : 17;
}
+/* Helper for __builtin_avr_delay_cycles */
+
+static void
+avr_expand_delay_cycles (rtx operands0)
+{
+ unsigned HOST_WIDE_INT cycles = UINTVAL (operands0);
+ unsigned HOST_WIDE_INT cycles_used;
+ unsigned HOST_WIDE_INT loop_count;
+
+ if (IN_RANGE (cycles, 83886082, 0xFFFFFFFF))
+ {
+ loop_count = ((cycles - 9) / 6) + 1;
+ cycles_used = ((loop_count - 1) * 6) + 9;
+ emit_insn (gen_delay_cycles_4 (gen_int_mode (loop_count, SImode)));
+ cycles -= cycles_used;
+ }
+
+ if (IN_RANGE (cycles, 262145, 83886081))
+ {
+ loop_count = ((cycles - 7) / 5) + 1;
+ if (loop_count > 0xFFFFFF)
+ loop_count = 0xFFFFFF;
+ cycles_used = ((loop_count - 1) * 5) + 7;
+ emit_insn (gen_delay_cycles_3 (gen_int_mode (loop_count, SImode)));
+ cycles -= cycles_used;
+ }
+
+ if (IN_RANGE (cycles, 768, 262144))
+ {
+ loop_count = ((cycles - 5) / 4) + 1;
+ if (loop_count > 0xFFFF)
+ loop_count = 0xFFFF;
+ cycles_used = ((loop_count - 1) * 4) + 5;
+ emit_insn (gen_delay_cycles_2 (gen_int_mode (loop_count, HImode)));
+ cycles -= cycles_used;
+ }
+
+ if (IN_RANGE (cycles, 6, 767))
+ {
+ loop_count = cycles / 3;
+ if (loop_count > 255)
+ loop_count = 255;
+ cycles_used = loop_count * 3;
+ emit_insn (gen_delay_cycles_1 (gen_int_mode (loop_count, QImode)));
+ cycles -= cycles_used;
+ }
+
+ while (cycles >= 2)
+ {
+ emit_insn (gen_nopv (GEN_INT(2)));
+ cycles -= 2;
+ }
+
+ if (cycles == 1)
+ {
+ emit_insn (gen_nopv (GEN_INT(1)));
+ cycles--;
+ }
+}
+
+/* IDs for all the AVR builtins. */
+
+enum avr_builtin_id
+ {
+ AVR_BUILTIN_NOP,
+ AVR_BUILTIN_SEI,
+ AVR_BUILTIN_CLI,
+ AVR_BUILTIN_WDR,
+ AVR_BUILTIN_SLEEP,
+ AVR_BUILTIN_SWAP,
+ AVR_BUILTIN_FMUL,
+ AVR_BUILTIN_FMULS,
+ AVR_BUILTIN_FMULSU,
+ AVR_BUILTIN_DELAY_CYCLES
+ };
+
+#define DEF_BUILTIN(NAME, TYPE, CODE) \
+ do \
+ { \
+ add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
+ NULL, NULL_TREE); \
+ } while (0)
+
+
+/* Implement `TARGET_INIT_BUILTINS' */
+/* Set up all builtin functions for this target. */
+
+static void
+avr_init_builtins (void)
+{
+ tree void_ftype_void
+ = build_function_type (void_type_node, void_list_node);
+ tree uchar_ftype_uchar
+ = build_function_type_list (unsigned_char_type_node,
+ unsigned_char_type_node,
+ NULL_TREE);
+ tree uint_ftype_uchar_uchar
+ = build_function_type_list (unsigned_type_node,
+ unsigned_char_type_node,
+ unsigned_char_type_node,
+ NULL_TREE);
+ tree int_ftype_char_char
+ = build_function_type_list (integer_type_node,
+ char_type_node,
+ char_type_node,
+ NULL_TREE);
+ tree int_ftype_char_uchar
+ = build_function_type_list (integer_type_node,
+ char_type_node,
+ unsigned_char_type_node,
+ NULL_TREE);
+ tree void_ftype_ulong
+ = build_function_type_list (void_type_node,
+ long_unsigned_type_node,
+ NULL_TREE);
+
+ DEF_BUILTIN ("__builtin_avr_nop", void_ftype_void, AVR_BUILTIN_NOP);
+ DEF_BUILTIN ("__builtin_avr_sei", void_ftype_void, AVR_BUILTIN_SEI);
+ DEF_BUILTIN ("__builtin_avr_cli", void_ftype_void, AVR_BUILTIN_CLI);
+ DEF_BUILTIN ("__builtin_avr_wdr", void_ftype_void, AVR_BUILTIN_WDR);
+ DEF_BUILTIN ("__builtin_avr_sleep", void_ftype_void, AVR_BUILTIN_SLEEP);
+ DEF_BUILTIN ("__builtin_avr_swap", uchar_ftype_uchar, AVR_BUILTIN_SWAP);
+ DEF_BUILTIN ("__builtin_avr_delay_cycles", void_ftype_ulong,
+ AVR_BUILTIN_DELAY_CYCLES);
+
+ if (AVR_HAVE_MUL)
+ {
+ /* FIXME: If !AVR_HAVE_MUL, make respective functions available
+ in libgcc. For fmul and fmuls this is straight forward with
+ upcoming fixed point support. */
+
+ DEF_BUILTIN ("__builtin_avr_fmul", uint_ftype_uchar_uchar,
+ AVR_BUILTIN_FMUL);
+ DEF_BUILTIN ("__builtin_avr_fmuls", int_ftype_char_char,
+ AVR_BUILTIN_FMULS);
+ DEF_BUILTIN ("__builtin_avr_fmulsu", int_ftype_char_uchar,
+ AVR_BUILTIN_FMULSU);
+ }
+}
+
+#undef DEF_BUILTIN
+
+struct avr_builtin_description
+{
+ const enum insn_code icode;
+ const char *const name;
+ const enum avr_builtin_id id;
+};
+
+static const struct avr_builtin_description
+bdesc_1arg[] =
+ {
+ { CODE_FOR_rotlqi3_4, "__builtin_avr_swap", AVR_BUILTIN_SWAP }
+ };
+
+static const struct avr_builtin_description
+bdesc_2arg[] =
+ {
+ { CODE_FOR_fmul, "__builtin_avr_fmul", AVR_BUILTIN_FMUL },
+ { CODE_FOR_fmuls, "__builtin_avr_fmuls", AVR_BUILTIN_FMULS },
+ { CODE_FOR_fmulsu, "__builtin_avr_fmulsu", AVR_BUILTIN_FMULSU }
+ };
+
+/* Subroutine of avr_expand_builtin to take care of unop insns. */
+
+static rtx
+avr_expand_unop_builtin (enum insn_code icode, tree exp,
+ rtx target)
+{
+ rtx pat;
+ tree arg0 = CALL_EXPR_ARG (exp, 0);
+ rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ enum machine_mode op0mode = GET_MODE (op0);
+ enum machine_mode tmode = insn_data[icode].operand[0].mode;
+ enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+
+ if (! target
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+ {
+ target = gen_reg_rtx (tmode);
+ }
+
+ if (op0mode == SImode && mode0 == HImode)
+ {
+ op0mode = HImode;
+ op0 = gen_lowpart (HImode, op0);
+ }
+
+ gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
+
+ if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+ op0 = copy_to_mode_reg (mode0, op0);
+
+ pat = GEN_FCN (icode) (target, op0);
+ if (! pat)
+ return 0;
+
+ emit_insn (pat);
+
+ return target;
+}
+
+
+/* Subroutine of avr_expand_builtin to take care of binop insns. */
+
+static rtx
+avr_expand_binop_builtin (enum insn_code icode, tree exp, rtx target)
+{
+ rtx pat;
+ tree arg0 = CALL_EXPR_ARG (exp, 0);
+ tree arg1 = CALL_EXPR_ARG (exp, 1);
+ rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ enum machine_mode op0mode = GET_MODE (op0);
+ enum machine_mode op1mode = GET_MODE (op1);
+ enum machine_mode tmode = insn_data[icode].operand[0].mode;
+ enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+ enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+
+ if (! target
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+ {
+ target = gen_reg_rtx (tmode);
+ }
+
+ if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode)
+ {
+ op0mode = HImode;
+ op0 = gen_lowpart (HImode, op0);
+ }
+
+ if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode)
+ {
+ op1mode = HImode;
+ op1 = gen_lowpart (HImode, op1);
+ }
+
+ /* In case the insn wants input operands in modes different from
+ the result, abort. */
+
+ gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
+ && (op1mode == mode1 || op1mode == VOIDmode));
+
+ if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+ op0 = copy_to_mode_reg (mode0, op0);
+
+ if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
+ op1 = copy_to_mode_reg (mode1, op1);
+
+ pat = GEN_FCN (icode) (target, op0, op1);
+
+ if (! pat)
+ return 0;
+
+ emit_insn (pat);
+ return target;
+}
+
+
+/* Expand an expression EXP that calls a built-in function,
+ with result going to TARGET if that's convenient
+ (and in mode MODE if that's convenient).
+ SUBTARGET may be used as the target for computing one of EXP's operands.
+ IGNORE is nonzero if the value is to be ignored. */
+
+static rtx
+avr_expand_builtin (tree exp, rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ size_t i;
+ const struct avr_builtin_description *d;
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ unsigned int id = DECL_FUNCTION_CODE (fndecl);
+ tree arg0;
+ rtx op0;
+
+ switch (id)
+ {
+ case AVR_BUILTIN_NOP:
+ emit_insn (gen_nopv (GEN_INT(1)));
+ return 0;
+
+ case AVR_BUILTIN_SEI:
+ emit_insn (gen_enable_interrupt ());
+ return 0;
+
+ case AVR_BUILTIN_CLI:
+ emit_insn (gen_disable_interrupt ());
+ return 0;
+
+ case AVR_BUILTIN_WDR:
+ emit_insn (gen_wdr ());
+ return 0;
+
+ case AVR_BUILTIN_SLEEP:
+ emit_insn (gen_sleep ());
+ return 0;
+
+ case AVR_BUILTIN_DELAY_CYCLES:
+ {
+ arg0 = CALL_EXPR_ARG (exp, 0);
+ op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+
+ if (! CONST_INT_P (op0))
+ error ("__builtin_avr_delay_cycles expects a compile time integer constant.");
+
+ avr_expand_delay_cycles (op0);
+ return 0;
+ }
+ }
+
+ for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
+ if (d->id == id)
+ return avr_expand_unop_builtin (d->icode, exp, target);
+
+ for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
+ if (d->id == id)
+ return avr_expand_binop_builtin (d->icode, exp, target);
+
+ gcc_unreachable ();
+}
+
+
#include "gt-avr.h"
;; ~ Output 'r' if not AVR_HAVE_JMP_CALL.
;; ! Output 'e' if AVR_HAVE_EIJMP_EICALL.
-;; UNSPEC usage:
-;; 0 Length of a string, see "strlenhi".
-;; 1 Jump by register pair Z or by table addressed by Z, see "casesi".
(define_constants
[(REG_X 26)
(SREG_ADDR 0x5F)
(RAMPZ_ADDR 0x5B)
-
- (UNSPEC_STRLEN 0)
- (UNSPEC_INDEX_JMP 1)
- (UNSPEC_SEI 2)
- (UNSPEC_CLI 3)
-
- (UNSPECV_PROLOGUE_SAVES 0)
- (UNSPECV_EPILOGUE_RESTORES 1)
- (UNSPECV_WRITE_SP_IRQ_ON 2)
- (UNSPECV_WRITE_SP_IRQ_OFF 3)
- (UNSPECV_GOTO_RECEIVER 4)])
+ ])
+
+(define_c_enum "unspec"
+ [UNSPEC_STRLEN
+ UNSPEC_INDEX_JMP
+ UNSPEC_FMUL
+ UNSPEC_FMULS
+ UNSPEC_FMULSU
+ ])
+
+(define_c_enum "unspecv"
+ [UNSPECV_PROLOGUE_SAVES
+ UNSPECV_EPILOGUE_RESTORES
+ UNSPECV_WRITE_SP_IRQ_ON
+ UNSPECV_WRITE_SP_IRQ_OFF
+ UNSPECV_GOTO_RECEIVER
+ UNSPECV_ENABLE_IRQS
+ UNSPECV_NOP
+ UNSPECV_SLEEP
+ UNSPECV_WDR
+ UNSPECV_DELAY_CYCLES
+ ])
+
(include "predicates.md")
(include "constraints.md")
FAIL;
}")
-(define_insn "*rotlqi3_4"
+(define_insn "rotlqi3_4"
[(set (match_operand:QI 0 "register_operand" "=r")
(rotate:QI (match_operand:QI 1 "register_operand" "0")
(const_int 4)))]
;; Enable Interrupts
(define_insn "enable_interrupt"
- [(unspec [(const_int 0)] UNSPEC_SEI)]
+ [(unspec_volatile [(const_int 1)] UNSPECV_ENABLE_IRQS)]
""
"sei"
[(set_attr "length" "1")
- (set_attr "cc" "none")
- ])
+ (set_attr "cc" "none")])
;; Disable Interrupts
(define_insn "disable_interrupt"
- [(unspec [(const_int 0)] UNSPEC_CLI)]
+ [(unspec_volatile [(const_int 0)] UNSPECV_ENABLE_IRQS)]
""
"cli"
[(set_attr "length" "1")
- (set_attr "cc" "none")
- ])
+ (set_attr "cc" "none")])
;; Library prologue saves
(define_insn "call_prologue_saves"
expand_epilogue (true /* sibcall_p */);
DONE;
})
+
+;; Some instructions resp. instruction sequences available
+;; via builtins.
+
+(define_insn "delay_cycles_1"
+ [(unspec_volatile [(match_operand:QI 0 "const_int_operand" "n")
+ (const_int 1)]
+ UNSPECV_DELAY_CYCLES)
+ (clobber (match_scratch:QI 1 "=&d"))]
+ ""
+ "ldi %1,lo8(%0)
+ 1: dec %1
+ brne 1b"
+ [(set_attr "length" "3")
+ (set_attr "cc" "clobber")])
+
+(define_insn "delay_cycles_2"
+ [(unspec_volatile [(match_operand:HI 0 "const_int_operand" "n")
+ (const_int 2)]
+ UNSPECV_DELAY_CYCLES)
+ (clobber (match_scratch:HI 1 "=&w"))]
+ ""
+ "ldi %A1,lo8(%0)
+ ldi %B1,hi8(%0)
+ 1: sbiw %A1,1
+ brne 1b"
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")])
+
+(define_insn "delay_cycles_3"
+ [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "n")
+ (const_int 3)]
+ UNSPECV_DELAY_CYCLES)
+ (clobber (match_scratch:QI 1 "=&d"))
+ (clobber (match_scratch:QI 2 "=&d"))
+ (clobber (match_scratch:QI 3 "=&d"))]
+ ""
+ "ldi %1,lo8(%0)
+ ldi %2,hi8(%0)
+ ldi %3,hlo8(%0)
+ 1: subi %1,1
+ sbci %2,0
+ sbci %3,0
+ brne 1b"
+ [(set_attr "length" "7")
+ (set_attr "cc" "clobber")])
+
+(define_insn "delay_cycles_4"
+ [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "n")
+ (const_int 4)]
+ UNSPECV_DELAY_CYCLES)
+ (clobber (match_scratch:QI 1 "=&d"))
+ (clobber (match_scratch:QI 2 "=&d"))
+ (clobber (match_scratch:QI 3 "=&d"))
+ (clobber (match_scratch:QI 4 "=&d"))]
+ ""
+ "ldi %1,lo8(%0)
+ ldi %2,hi8(%0)
+ ldi %3,hlo8(%0)
+ ldi %4,hhi8(%0)
+ 1: subi %1,1
+ sbci %2,0
+ sbci %3,0
+ sbci %4,0
+ brne 1b"
+ [(set_attr "length" "9")
+ (set_attr "cc" "clobber")])
+
+;; CPU instructions
+
+;; NOP taking 1 or 2 Ticks
+(define_insn "nopv"
+ [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "P,K")]
+ UNSPECV_NOP)]
+ ""
+ "@
+ nop
+ rjmp ."
+ [(set_attr "length" "1")
+ (set_attr "cc" "none")])
+
+;; SLEEP
+(define_insn "sleep"
+ [(unspec_volatile [(const_int 0)] UNSPECV_SLEEP)]
+ ""
+ "sleep"
+ [(set_attr "length" "1")
+ (set_attr "cc" "none")])
+
+;; WDR
+(define_insn "wdr"
+ [(unspec_volatile [(const_int 0)] UNSPECV_WDR)]
+ ""
+ "wdr"
+ [(set_attr "length" "1")
+ (set_attr "cc" "none")])
+
+;; FMUL
+(define_insn "fmul"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (unspec:HI [(match_operand:QI 1 "register_operand" "a")
+ (match_operand:QI 2 "register_operand" "a")]
+ UNSPEC_FMUL))]
+ "AVR_HAVE_MUL"
+ "fmul %1,%2
+ movw %0,r0
+ clr __zero_reg__"
+ [(set_attr "length" "3")
+ (set_attr "cc" "clobber")])
+
+;; FMULS
+(define_insn "fmuls"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (unspec:HI [(match_operand:QI 1 "register_operand" "a")
+ (match_operand:QI 2 "register_operand" "a")]
+ UNSPEC_FMULS))]
+ "AVR_HAVE_MUL"
+ "fmuls %1,%2
+ movw %0,r0
+ clr __zero_reg__"
+ [(set_attr "length" "3")
+ (set_attr "cc" "clobber")])
+
+;; FMULSU
+(define_insn "fmulsu"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (unspec:HI [(match_operand:QI 1 "register_operand" "a")
+ (match_operand:QI 2 "register_operand" "a")]
+ UNSPEC_FMULSU))]
+ "AVR_HAVE_MUL"
+ "fmulsu %1,%2
+ movw %0,r0
+ clr __zero_reg__"
+ [(set_attr "length" "3")
+ (set_attr "cc" "clobber")])
* Alpha Built-in Functions::
* ARM iWMMXt Built-in Functions::
* ARM NEON Intrinsics::
+* AVR Built-in Functions::
* Blackfin Built-in Functions::
* FR-V Built-in Functions::
* X86 Built-in Functions::
@include arm-neon-intrinsics.texi
+@node AVR Built-in Functions
+@subsection AVR Built-in Functions
+
+For each built-in function for AVR, there is an equally named,
+uppercase built-in macro defined. That way users can easily query if
+or if not a specific built-in is implemented or not. For example, if
+@code{__builtin_avr_nop} is available the macro
+@code{__BUILTIN_AVR_NOP} is defined to @code{1} and undefined otherwise.
+
+The following built-in functions map to the respective machine
+instruction, i.e. @code{nop}, @code{sei}, @code{cli}, @code{sleep},
+@code{wdr}, @code{swap}, @code{fmul}, @code{fmuls}
+resp. @code{fmulsu}. The latter three are only available if the AVR
+device actually supports multiplication.
+
+@smallexample
+void __builtin_avr_nop (void)
+void __builtin_avr_sei (void)
+void __builtin_avr_cli (void)
+void __builtin_avr_sleep (void)
+void __builtin_avr_wdr (void)
+unsigned char __builtin_avr_swap (unsigned char)
+unsigned int __builtin_avr_fmul (unsigned char, unsigned char)
+int __builtin_avr_fmuls (char, char)
+int __builtin_avr_fmulsu (char, unsigned char)
+@end smallexample
+
+In order to delay execution for a specific number of cycles, GCC
+implements
+@smallexample
+void __builtin_avr_delay_cycles (unsigned long ticks)
+@end smallexample
+
+@code{ticks} is the number of ticks to delay execution. Note that this
+built-in does not take into account the effect of interrupts which
+might increase delay time. @code{ticks} must be a compile time
+integer constant; delays with a variable number of cycles are not supported.
+
@node Blackfin Built-in Functions
@subsection Blackfin Built-in Functions