Index: gcc/config/avr/avr.md =================================================================== --- gcc/config/avr/avr.md (revision 134368) +++ gcc/config/avr/avr.md (working copy) @@ -52,12 +52,25 @@ (UNSPEC_STRLEN 0) (UNSPEC_INDEX_JMP 1) - (UNSPEC_SEI 2) - (UNSPEC_CLI 3) + (UNSPEC_SWAP 2) + (UNSPEC_FMUL 3) + (UNSPEC_FMULU 4) + (UNSPEC_FMULSU 5) (UNSPECV_PROLOGUE_SAVES 0) - (UNSPECV_EPILOGUE_RESTORES 1)]) + (UNSPECV_EPILOGUE_RESTORES 1) + (UNSPECV_SEI 2) + (UNSPECV_CLI 3) + (UNSPECV_NOP 4) + (UNSPECV_SLEEP 5) + (UNSPECV_WDR 6) + (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") @@ -2751,7 +2764,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") @@ -2760,7 +2773,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") @@ -2860,3 +2873,158 @@ expand_epilogue (); DONE; }") + +;;delay_cycles_delay_cycles_delay_cycles_delay_cycles_delay_cycles_delay +;; delay_cycles + +(define_expand "delay_cycles" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "i")] + UNSPECV_DELAY_CYCLES))] + "" + " + rtx loop_reg; + + if (0 == (INTVAL (operands[1]))) + { + DONE; + } + else if (IN_RANGE((INTVAL (operands[1])), 1, 2)) + { + emit_insn (gen_nop ()); + if (2 == (INTVAL (operands[1]))) + emit_insn (gen_nop ()); + + DONE; + } + else if (IN_RANGE((INTVAL (operands[1])), 3, 756)) + { + + loop_reg = + copy_to_mode_reg (QImode, + gen_int_mode (INTVAL (operands[1]) / 3, QImode)); + emit_insn (gen_delay_cycles_1 (loop_reg)); + + DONE; + } + else if (IN_RANGE((INTVAL (operands[1])), 757, 196605)) + { + loop_reg = + copy_to_mode_reg (HImode, + gen_int_mode (INTVAL (operands[1]) / 3, HImode)); + emit_insn (gen_delay_cycles_2 (loop_reg)); + + DONE; + } + else if (IN_RANGE((INTVAL (operands[1])), 196606, 83886075)) + { + loop_reg = + copy_to_mode_reg (SImode, + gen_int_mode (INTVAL (operands[1]) / 5, SImode)); + emit_insn (gen_delay_cycles_3 (loop_reg)); + + DONE; + } + else if (IN_RANGE((INTVAL (operands[1])), 83886076, 0xFFFFFFFF)) + { + loop_reg = + copy_to_mode_reg (SImode, + gen_int_mode (INTVAL (operands[1]) / 6, SImode)); + emit_insn (gen_delay_cycles_4 (loop_reg)); + + DONE; + } + ") + +(define_insn "delay_cycles_1" + [(unspec_volatile [(const_int 0)] UNSPECV_DELAY_CYCLES) + (match_operand:QI 0 "register_operand" "r") + (clobber (match_dup 0))] + "" + "1:dec %0\;brne 1b" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + +(define_insn "delay_cycles_2" + [(unspec_volatile [(const_int 0)] UNSPECV_DELAY_CYCLES_2) + (match_operand:HI 0 "register_operand" "w") + (clobber (match_dup 0))] + "" + "1:sbiw %0,1\;brne 1b" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + +(define_insn "delay_cycles_3" + [(unspec_volatile [(const_int 0)] UNSPECV_DELAY_CYCLES_3) + (match_operand:SI 0 "register_operand" "d") + (clobber (match_dup 0))] + "" + "1:subi %0,1\;sbci %B0,0\;sbci %C0,0\;brne 1b" + [(set_attr "length" "4") + (set_attr "cc" "clobber")]) + +(define_insn "delay_cycles_4" + [(unspec_volatile [(const_int 0)] UNSPECV_DELAY_CYCLES_4) + (match_operand:SI 0 "register_operand" "d") + (clobber (match_dup 0))] + "" + "1:subi %0,1\;sbci %B0,0\;sbci %C0,0\;sbci %D0,0\;brne 1b" + [(set_attr "length" "5") + (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") +; ]) + +;; SEI, Enable Interrupts +;(define_insn "enable_interrupt" +; [(unspec_volatile [(const_int 0)] UNSPECV_SEI)] +; "" +; "sei" +; [(set_attr "length" "1") +; (set_attr "cc" "none") +; ]) + +;; CLI, Disable Interrupts +;(define_insn "disable_interrupt" +; [(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")]) Index: gcc/config/avr/avr.c =================================================================== --- gcc/config/avr/avr.c (revision 134368) +++ gcc/config/avr/avr.c (working copy) @@ -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" @@ -81,6 +85,9 @@ static int avr_address_cost (rtx); 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); + /* Allocate registers from r25 to r8 for parameters for function calls. */ #define FIRST_CUM_REG 26 @@ -331,6 +338,12 @@ #undef TARGET_STRICT_ARGUMENT_NAMING #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true +#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; void @@ -5944,4 +5980,136 @@ return false; } +/* 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_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 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); + + 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 }, + { CODE_FOR_delay_cycles, "__builtin_avr_delay_cycles", AVR_BUILTIN_DELAY_CYCLES } +}; + +/* Subroutine of bfin_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; +} + +/* 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 ATTRIBUTE_UNUSED, + 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); + + 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; + } + + 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); + + gcc_unreachable (); +} +