diff mbox

[AVR] : Initial builtins support

Message ID 4D9C747B.1020303@gjlay.de
State New
Headers show

Commit Message

Georg-Johann Lay April 6, 2011, 2:11 p.m. UTC
This patch adds builtin support for some RTL builtins to avr backend.
One builtin implements loop for delay of specific number of ticks
(under the assumption IRQs are off), others simply map to machine
instructions like SEI, CLI, NOP, SLEEP, WDR, FMUL, FMAULS, FMULSU.

In addition, builtin macros are introduced so that use can easily
query if or if not a specific builtin is available. This might be
useful as builtin support evolves, because #ifdef is easier then to
twiddle out which version brings what builtin.

2011-04-06  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.

Comments

Georg-Johann Lay April 6, 2011, 6:51 p.m. UTC | #1
Added Anatoly and Eric to changelog entry

Johann


2011-04-06  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 static 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 to named insn "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.
Georg-Johann Lay April 11, 2011, 11:18 a.m. UTC | #2
Georg-Johann Lay schrieb:
> This patch adds builtin support for some RTL builtins to avr backend.
> One builtin implements loop for delay of specific number of ticks
> (under the assumption IRQs are off), others simply map to machine
> instructions like SEI, CLI, NOP, SLEEP, WDR, FMUL, FMAULS, FMULSU.
> 
> In addition, builtin macros are introduced so that use can easily
> query if or if not a specific builtin is available. This might be
> useful as builtin support evolves, because #ifdef is easier then to
> twiddle out which version brings what builtin.
> 
> 2011-04-06  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.
>
Denis Chertykov April 12, 2011, 5:38 a.m. UTC | #3
2011/4/11 Georg-Johann Lay <avr@gjlay.de>:
> Georg-Johann Lay schrieb:
>> This patch adds builtin support for some RTL builtins to avr backend.
>> One builtin implements loop for delay of specific number of ticks
>> (under the assumption IRQs are off), others simply map to machine
>> instructions like SEI, CLI, NOP, SLEEP, WDR, FMUL, FMAULS, FMULSU.
>>
>> In addition, builtin macros are introduced so that use can easily
>> query if or if not a specific builtin is available. This might be
>> useful as builtin support evolves, because #ifdef is easier then to
>> twiddle out which version brings what builtin.
>>
>> 2011-04-06  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.
>>

Approved.

Denis.
diff mbox

Patch

Index: config/avr/avr.c
===================================================================
--- config/avr/avr.c	(Revision 172036)
+++ config/avr/avr.c	(Arbeitskopie)
@@ -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
 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_
 #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
@@ -6426,4 +6438,331 @@  unsigned int avr_case_values_threshold (
   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"
Index: config/avr/avr.md
===================================================================
--- config/avr/avr.md	(Revision 172036)
+++ config/avr/avr.md	(Arbeitskopie)
@@ -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 @@  (define_constants
    
    (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 @@  (define_expand "rotlqi3"
     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 @@  (define_insn "popqi"
 
 ;; 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 @@  (define_expand "sibcall_epilogue"
     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")])
Index: config/avr/avr-c.c
===================================================================
--- config/avr/avr-c.c	(Revision 172036)
+++ config/avr/avr-c.c	(Arbeitskopie)
@@ -1,85 +1,104 @@ 
-/* 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");
+    }
+}
+