diff -Naurp gcc/config/avr/avr.c gcc/config/avr/avr.c --- gcc/config/avr/avr.c 2011-10-27 17:53:42.000000000 +0530 +++ gcc/config/avr/avr.c 2011-10-27 18:00:50.000000000 +0530 @@ -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" @@ -90,6 +93,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); @@ -241,6 +246,13 @@ static const struct default_options avr_ #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) @@ -7506,4 +7518,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-10-27 17:53:20.000000000 +0530 +++ gcc/config/avr/avr.md 2011-10-27 18:00:50.000000000 +0530 @@ -50,14 +50,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") @@ -2820,13 +2835,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" @@ -3220,7 +3228,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") @@ -3229,7 +3237,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") @@ -3329,3 +3337,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-10-27 17:53:20.000000000 +0530 +++ gcc/config/avr/predicates.md 2011-10-27 18:00:50.000000000 +0530 @@ -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")