avr.c: ("insn-codes.h"...

* 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.
	
	* doc/extend.texi (AVR Built-in Functions): New node
	(Target Builtins): Add documentation of AVR
	built-in functions.


Co-Authored-By: Eric Weddington <eric.weddington@atmel.com>
Co-Authored-By: Georg-Johann Lay <avr@gjlay.de>

From-SVN: r172416
This commit is contained in:
Anatoly Sokolov 2011-04-14 13:24:34 +04:00 committed by Georg-Johann Lay
parent 8a9b55f326
commit 43ea65025f
5 changed files with 679 additions and 105 deletions

View File

@ -1,3 +1,39 @@
2011-04-14 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 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.
* doc/extend.texi (AVR Built-in Functions): New node
(Target Builtins): Add documentation of AVR
built-in functions.
2011-04-14 Georg-Johann Lay <avr@gjlay.de>
PR target/44643

View File

@ -1,85 +1,103 @@
/* 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");
}
}

View File

@ -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, int *, bool);
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_option_optimization_table[] =
#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
@ -6432,4 +6444,331 @@ unsigned int avr_case_values_threshold (void)
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"

View File

@ -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 @@
(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 @@
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 @@
;; 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 @@
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")])

View File

@ -7924,6 +7924,7 @@ instructions, but allow the compiler to schedule those calls.
* Alpha Built-in Functions::
* ARM iWMMXt Built-in Functions::
* ARM NEON Intrinsics::
* AVR Built-in Functions::
* Blackfin Built-in Functions::
* FR-V Built-in Functions::
* X86 Built-in Functions::
@ -8175,6 +8176,44 @@ when the @option{-mfpu=neon} switch is used:
@include arm-neon-intrinsics.texi
@node AVR Built-in Functions
@subsection AVR Built-in Functions
For each built-in function for AVR, there is an equally named,
uppercase built-in macro defined. That way users can easily query if
or if not a specific built-in is implemented or not. For example, if
@code{__builtin_avr_nop} is available the macro
@code{__BUILTIN_AVR_NOP} is defined to @code{1} and undefined otherwise.
The following built-in functions map to the respective machine
instruction, i.e. @code{nop}, @code{sei}, @code{cli}, @code{sleep},
@code{wdr}, @code{swap}, @code{fmul}, @code{fmuls}
resp. @code{fmulsu}. The latter three are only available if the AVR
device actually supports multiplication.
@smallexample
void __builtin_avr_nop (void)
void __builtin_avr_sei (void)
void __builtin_avr_cli (void)
void __builtin_avr_sleep (void)
void __builtin_avr_wdr (void)
unsigned char __builtin_avr_swap (unsigned char)
unsigned int __builtin_avr_fmul (unsigned char, unsigned char)
int __builtin_avr_fmuls (char, char)
int __builtin_avr_fmulsu (char, unsigned char)
@end smallexample
In order to delay execution for a specific number of cycles, GCC
implements
@smallexample
void __builtin_avr_delay_cycles (unsigned long ticks)
@end smallexample
@code{ticks} is the number of ticks to delay execution. Note that this
built-in does not take into account the effect of interrupts which
might increase delay time. @code{ticks} must be a compile time
integer constant; delays with a variable number of cycles are not supported.
@node Blackfin Built-in Functions
@subsection Blackfin Built-in Functions