Index: gcc/config/avr/predicates.md =================================================================== --- gcc/config/avr/predicates.md (revision 134489) +++ gcc/config/avr/predicates.md (working copy) @@ -27,6 +27,11 @@ (and (match_code "reg") (match_test "REGNO (op) >= 16 && REGNO (op) <= 31"))) +;; Registers from r16 to 24. +(define_predicate "fmul_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") Index: gcc/config/avr/avr.md =================================================================== --- gcc/config/avr/avr.md (revision 134489) +++ gcc/config/avr/avr.md (working copy) @@ -52,12 +52,26 @@ (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_EPILOGUE_RESTORES 1) + (UNSPECV_SEI 2) + (UNSPECV_CLI 3) + (UNSPECV_NOP 4) + (UNSPECV_NOP2 5) + (UNSPECV_SLEEP 6) + (UNSPECV_WDR 7) + (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") @@ -2367,13 +2381,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_insn "indirect_jump" [(set (pc) (match_operand:HI 0 "register_operand" "!z,*r"))] @@ -2751,7 +2758,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 +2767,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 +2867,230 @@ 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; + + if (IN_RANGE((INTVAL (operands[0])), 0, 6)) + { + switch (INTVAL (operands[0])) + { + case 0: + break; + case 1: + emit_insn (gen_nop ()); + break; + case 2: + emit_insn (gen_nop2 ()); + break; + case 3: + emit_insn (gen_nop ()); + emit_insn (gen_nop2 ()); + break; + case 4: + emit_insn (gen_nop2 ()); + emit_insn (gen_nop2 ()); + break; + case 5: + emit_insn (gen_nop ()); + emit_insn (gen_nop2 ()); + emit_insn (gen_nop2 ()); + break; + case 6: + emit_insn (gen_nop2 ()); + emit_insn (gen_nop2 ()); + emit_insn (gen_nop2 ()); + break; + } + + DONE; + } + else if (IN_RANGE((INTVAL (operands[0])), 7, 765)) + { + + loop_reg = + copy_to_mode_reg (QImode, + gen_int_mode ((INTVAL (operands[0]) + 2) / 3, + QImode)); + emit_insn (gen_delay_cycles_1 (loop_reg)); + + DONE; + } + else if (IN_RANGE((INTVAL (operands[0])), 767, 196605)) + { + loop_reg = + copy_to_mode_reg (HImode, + gen_int_mode ((INTVAL (operands[0]) + 2) / 3, + HImode)); + emit_insn (gen_delay_cycles_2 (loop_reg)); + + DONE; + } + else if (IN_RANGE((INTVAL (operands[0])), 196606, 83886075)) + { + loop_reg = + copy_to_mode_reg (SImode, + gen_int_mode ((INTVAL (operands[1]) + 4) / 5, + SImode)); + emit_insn (gen_delay_cycles_3 (loop_reg)); + + DONE; + } + else if (IN_RANGE((INTVAL (operands[0])), 83886076, 0xFFFFFFFF)) + { + loop_reg = + copy_to_mode_reg (SImode, + gen_int_mode ((INTVAL (operands[0]) + 5) / 6, + SImode)); + emit_insn (gen_delay_cycles_4 (loop_reg)); + + DONE; + } + ") + +(define_insn "delay_cycles_1" + [(unspec_volatile [(const_int 0)] UNSPECV_DELAY_CYCLES_1) + (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")]) + +;; 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 "fmul_register_operand" "=r") + (unspec:HI [(match_operand:QI 1 "fmul_register_operand" "r") + (match_operand:QI 2 "fmul_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 "fmul_register_operand" "=r") + (unspec:HI [(match_operand:QI 1 "fmul_register_operand" "r") + (match_operand:QI 2 "fmul_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 "fmul_register_operand" "=r") + (unspec:HI [(match_operand:QI 1 "fmul_register_operand" "r") + (match_operand:QI 2 "fmul_register_operand" "r")] + UNSPEC_FMULSU))] + "AVR_HAVE_MUL" + "fmulsu %1,%2 + movw %0,r0 + clr r1" + [(set_attr "length" "3") + (set_attr "cc" "clobber")]) + \ No newline at end of file Index: gcc/config/avr/avr.c =================================================================== --- gcc/config/avr/avr.c (revision 134489) +++ 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,237 @@ 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_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 literal."); + + 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"