summaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorgjl <gjl@138bc75d-0d04-0410-961f-82ee72b054a4>2011-04-14 09:24:34 +0000
committergjl <gjl@138bc75d-0d04-0410-961f-82ee72b054a4>2011-04-14 09:24:34 +0000
commitc5be380ef78eb5f072c340edacbdc3e92a284182 (patch)
tree5490af92bda644c89eb84d5abad156f8a08034a8 /gcc/config
parentcb7c66a8669f76f5d70afb4afb7a4ad612119517 (diff)
downloadgcc-c5be380ef78eb5f072c340edacbdc3e92a284182.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@172416 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/avr/avr-c.c188
-rw-r--r--gcc/config/avr/avr.c339
-rw-r--r--gcc/config/avr/avr.md184
3 files changed, 605 insertions, 106 deletions
diff --git a/gcc/config/avr/avr-c.c b/gcc/config/avr/avr-c.c
index 05e8e8b30e6..ec314d2a139 100644
--- a/gcc/config/avr/avr-c.c
+++ b/gcc/config/avr/avr-c.c
@@ -1,85 +1,103 @@
-/* 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__");
-}
-
+/* 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");
+ }
+}
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
index ca06431aa83..500a5b287ae 100644
--- a/gcc/config/avr/avr.c
+++ b/gcc/config/avr/avr.c
@@ -29,6 +29,7 @@
#include "insn-config.h"
#include "conditions.h"
#include "insn-attr.h"
+#include "insn-codes.h"
#include "flags.h"
#include "reload.h"
#include "tree.h"
@@ -38,7 +39,9 @@
#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"
@@ -91,6 +94,8 @@ static bool avr_rtx_costs (rtx, int, int, int *, bool);
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);
@@ -253,6 +258,13 @@ static const struct default_options avr_option_optimization_table[] =
#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;
static void
@@ -6432,4 +6444,331 @@ unsigned int avr_case_values_threshold (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"
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 9c375e4c4ba..86e052aa08a 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -35,9 +35,6 @@
;; ~ 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)
@@ -50,17 +47,29 @@
(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")
@@ -1489,7 +1498,7 @@
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)))]
@@ -3130,21 +3139,19 @@
;; 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"
@@ -3246,3 +3253,138 @@
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")])