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:
parent
8a9b55f326
commit
43ea65025f
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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")])
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user