ports/devel/avr-gcc/files/patch-304-gcc-4.5.1-builtins-v6
Joerg Wunsch 0c19ecdca8 Upgrade to GCC 4.5.1.
Completely reorganize the patches for this port.

Patches for new devices are now synchronized with the Atmel AVR tools.
The main difference is the naming scheme, as FreeBSD patches start
with "patch-", while the Atmel AVR Tools patches end up in ".patch".
2011-12-17 09:56:31 +00:00

585 lines
16 KiB
Text

diff -Naurp gcc/config/avr/avr.c gcc/config/avr/avr.c
--- gcc/config/avr/avr.c 2011-01-19 13:48:07.000000000 -0600
+++ gcc/config/avr/avr.c 2011-01-19 13:49:37.000000000 -0600
@@ -30,6 +30,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"
@@ -39,7 +40,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"
@@ -87,6 +90,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);
@@ -197,6 +202,13 @@ static const struct attribute_spec avr_a
#undef TARGET_SCALAR_MODE_SUPPORTED_P
#define TARGET_SCALAR_MODE_SUPPORTED_P avr_scalar_mode_supported_p
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS avr_init_builtins
+
+#undef TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN avr_expand_builtin
+
+
/* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
static bool
avr_scalar_mode_supported_p (enum machine_mode mode)
@@ -7286,4 +7298,237 @@ unsigned int avr_case_values_threshold (
return (!AVR_HAVE_JMP_CALL || TARGET_CALL_PROLOGUES) ? 8 : 17;
}
+/* Codes for all the AVR builtins. */
+
+enum avr_builtins
+{
+ 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)
+
+/* 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_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);
+
+ if (AVR_HAVE_MUL)
+ {
+ 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);
+ }
+
+ def_builtin ("__builtin_avr_swap", uchar_ftype_uchar, AVR_BUILTIN_SWAP);
+ def_builtin ("__builtin_avr_delay_cycles", void_ftype_ulong,
+ AVR_BUILTIN_DELAY_CYCLES);
+}
+
+struct builtin_description
+{
+ const enum insn_code icode;
+ const char *const name;
+ const enum avr_builtins code;
+};
+
+static const struct builtin_description bdesc_1arg[] =
+{
+ { CODE_FOR_swap, "__builtin_avr_swap", AVR_BUILTIN_SWAP }
+};
+
+static const struct 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 builtin_description *d;
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+ rtx pat;
+ tree arg0;
+ rtx op0;
+
+ switch (fcode)
+ {
+ 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 (!CONSTANT_P (op0))
+ error ("__builtin_avr_delay_cycles expects an integer constant.");
+
+ emit_insn (gen_delay_cycles (op0));
+ return 0;
+ }
+ }
+
+ for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
+ if (d->code == fcode)
+ return avr_expand_unop_builtin (d->icode, exp, target);
+
+ for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
+ if (d->code == fcode)
+ return avr_expand_binop_builtin (d->icode, exp, target);
+
+ gcc_unreachable ();
+}
+
#include "gt-avr.h"
diff -Naurp gcc/config/avr/avr.md gcc/config/avr/avr.md
--- gcc/config/avr/avr.md 2011-01-19 13:45:00.000000000 -0600
+++ gcc/config/avr/avr.md 2011-01-19 13:49:37.000000000 -0600
@@ -51,14 +51,29 @@
(UNSPEC_STRLEN 0)
(UNSPEC_INDEX_JMP 1)
- (UNSPEC_SEI 2)
- (UNSPEC_CLI 3)
+ (UNSPEC_SWAP 2)
+ (UNSPEC_FMUL 3)
+ (UNSPEC_FMULS 4)
+ (UNSPEC_FMULSU 5)
+
(UNSPECV_PROLOGUE_SAVES 0)
(UNSPECV_EPILOGUE_RESTORES 1)
(UNSPECV_WRITE_SP_IRQ_ON 2)
(UNSPECV_WRITE_SP_IRQ_OFF 3)
- (UNSPECV_GOTO_RECEIVER 4)])
+ (UNSPECV_GOTO_RECEIVER 4)
+ (UNSPECV_SEI 5)
+ (UNSPECV_CLI 6)
+ (UNSPECV_NOP 7)
+ (UNSPECV_NOP2 8)
+ (UNSPECV_SLEEP 9)
+ (UNSPECV_WDR 10)
+
+ (UNSPECV_DELAY_CYCLES 100)
+ (UNSPECV_DELAY_CYCLES_1 101)
+ (UNSPECV_DELAY_CYCLES_2 102)
+ (UNSPECV_DELAY_CYCLES_3 103)
+ (UNSPECV_DELAY_CYCLES_4 104)])
(include "predicates.md")
(include "constraints.md")
@@ -2813,13 +2828,6 @@
(const_int 1))
(const_int 3)])])
-(define_insn "nop"
- [(const_int 0)]
- ""
- "nop"
- [(set_attr "cc" "none")
- (set_attr "length" "1")])
-
; indirect jump
(define_expand "indirect_jump"
@@ -3221,7 +3229,7 @@
;; Enable Interrupts
(define_insn "enable_interrupt"
- [(unspec [(const_int 0)] UNSPEC_SEI)]
+ [(unspec_volatile [(const_int 0)] UNSPECV_SEI)]
""
"sei"
[(set_attr "length" "1")
@@ -3230,7 +3238,7 @@
;; Disable Interrupts
(define_insn "disable_interrupt"
- [(unspec [(const_int 0)] UNSPEC_CLI)]
+ [(unspec_volatile [(const_int 0)] UNSPECV_CLI)]
""
"cli"
[(set_attr "length" "1")
@@ -3330,3 +3338,219 @@
expand_epilogue ();
DONE;
}")
+
+;;delay_cycles_delay_cycles_delay_cycles_delay_cycles_delay_cycles_delay
+;; delay_cycles
+
+(define_expand "delay_cycles"
+ [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "i")]
+ UNSPECV_DELAY_CYCLES)]
+ ""
+ "
+ rtx loop_reg;
+ unsigned int cycles = INTVAL (operands[0]);
+ if (IN_RANGE(cycles, 83886082, 0xFFFFFFFF))
+ {
+ unsigned int loop_count = ((cycles - 9) / 6) + 1;
+ unsigned int 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))
+ {
+ unsigned int loop_count = ((cycles - 7) / 5) + 1;
+ if (loop_count > 0xFFFFFF)
+ loop_count = 0xFFFFFF;
+ unsigned int 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))
+ {
+ unsigned int loop_count = ((cycles - 5) / 4) + 1;
+ if (loop_count > 0xFFFF)
+ loop_count = 0xFFFF;
+ unsigned int 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))
+ {
+ unsigned int loop_count = (cycles/ 3);
+ if (loop_count > 255)
+ loop_count = 255;
+ unsigned int 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_nop2 ());
+ cycles -= 2;
+ }
+ if (cycles == 1)
+ {
+ emit_insn (gen_nop ());
+ cycles--;
+ }
+ DONE;
+ ")
+
+(define_insn "delay_cycles_1"
+[(unspec_volatile [(const_int 0)] UNSPECV_DELAY_CYCLES_1)
+ (match_operand:QI 0 "immediate_operand" "")
+ (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 [(const_int 0)] UNSPECV_DELAY_CYCLES_2)
+ (match_operand:HI 0 "immediate_operand" "")
+ (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 [(const_int 0)] UNSPECV_DELAY_CYCLES_3)
+ (match_operand:SI 0 "immediate_operand" "")
+ (clobber (match_scratch:SI 1 "=&d"))]
+ ""
+ " ldi %A1,lo8(%0)
+ ldi %B1,hi8(%0)
+ ldi %C1,hlo8(%0)
+ 1:subi %A1,1
+ sbci %B1,0
+ sbci %C1,0
+ brne 1b"
+ [(set_attr "length" "7")
+ (set_attr "cc" "clobber")])
+
+(define_insn "delay_cycles_4"
+ [(unspec_volatile [(const_int 0)] UNSPECV_DELAY_CYCLES_4)
+ (match_operand:SI 0 "immediate_operand" "")
+ (clobber (match_scratch:SI 1 "=&d"))]
+ ""
+ " ldi %A1,lo8(%0)
+ ldi %B1,hi8(%0)
+ ldi %C1,hlo8(%0)
+ ldi %D1,hhi8(%0)
+ 1:subi %A1,1
+ sbci %B1,0
+ sbci %C1,0
+ sbci %D1,0
+ brne 1b"
+ [(set_attr "length" "9")
+ (set_attr "cc" "clobber")])
+
+;; CPU instructions
+
+;; NOP
+(define_insn "nop"
+ [(unspec_volatile [(const_int 0)] UNSPECV_NOP)]
+ ""
+ "nop"
+ [(set_attr "length" "1")
+ (set_attr "cc" "none")])
+
+;; NOP2
+(define_insn "nop2"
+ [(unspec_volatile [(const_int 0)] UNSPECV_NOP2)]
+ ""
+ "rjmp ."
+ [(set_attr "length" "1")
+ (set_attr "cc" "none")])
+
+;; SEI, Enable Interrupts
+;(define_insn "sei"
+; [(unspec_volatile [(const_int 0)] UNSPECV_SEI)]
+; ""
+; "sei"
+; [(set_attr "length" "1")
+; (set_attr "cc" "none")
+; ])
+
+;; CLI, Disable Interrupts
+;(define_insn "cli"
+; [(unspec_volatile [(const_int 0)] UNSPECV_CLI)]
+; ""
+; "cli"
+; [(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")
+ ])
+
+;; SWAP
+(define_insn "swap"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (unspec:QI [(match_operand:QI 1 "register_operand" "0")]
+ UNSPEC_SWAP))]
+ ""
+ "swap %0"
+ [(set_attr "length" "1")
+ (set_attr "cc" "none")])
+
+;; FMUL
+(define_insn "fmul"
+ [(set (match_operand:HI 0 "a_register_operand" "=r")
+ (unspec:HI [(match_operand:QI 1 "a_register_operand" "r")
+ (match_operand:QI 2 "a_register_operand" "r")]
+ UNSPEC_FMUL))]
+ "AVR_HAVE_MUL"
+ "fmul %1,%2
+ movw %0,r0
+ clr r1"
+ [(set_attr "length" "3")
+ (set_attr "cc" "clobber")])
+
+;; FMULS
+(define_insn "fmuls"
+ [(set (match_operand:HI 0 "a_register_operand" "=r")
+ (unspec:HI [(match_operand:QI 1 "a_register_operand" "r")
+ (match_operand:QI 2 "a_register_operand" "r")]
+ UNSPEC_FMULS))]
+ "AVR_HAVE_MUL"
+ "fmuls %1,%2
+ movw %0,r0
+ clr r1"
+ [(set_attr "length" "3")
+ (set_attr "cc" "clobber")])
+
+;; FMULSU
+(define_insn "fmulsu"
+ [(set (match_operand:HI 0 "a_register_operand" "=r")
+ (unspec:HI [(match_operand:QI 1 "a_register_operand" "r")
+ (match_operand:QI 2 "a_register_operand" "r")]
+ UNSPEC_FMULSU))]
+ "AVR_HAVE_MUL"
+ "fmulsu %1,%2
+ movw %0,r0
+ clr r1"
+ [(set_attr "length" "3")
+ (set_attr "cc" "clobber")])
+
diff -Naurp gcc/config/avr/predicates.md gcc/config/avr/predicates.md
--- gcc/config/avr/predicates.md 2011-01-19 13:03:59.000000000 -0600
+++ gcc/config/avr/predicates.md 2011-01-19 13:49:37.000000000 -0600
@@ -27,6 +27,11 @@
(and (match_code "reg")
(match_test "REGNO (op) >= 16 && REGNO (op) <= 31")))
+;; Registers from r16 to 24.
+(define_predicate "a_register_operand"
+ (and (match_code "reg")
+ (match_test "REGNO (op) >= 16 && REGNO (op) <= 24")))
+
(define_predicate "even_register_operand"
(and (match_code "reg")
(and (match_test "REGNO (op) <= 31")