This patch introduces a new file builtins.def that is used as central registry to hold built-ins' information.
The file is used by defining DEF_BUILTIN macre and then including the file as described in the head comment of builtins.def. Up to here it's all code clean-up and no functional change. Moreover there are some minor changes and ICE fixes: * Fold __builtin_avr_swap to rotate <<< 4 * Don't fold __builtin_avr_insert_bits if first arg is non-const (was ICE) * Don't expand __builtin_avr_delay_cycles if arg is not-const (was ICE) Ok for trunk? Johann gcc/testsuite/ * gcc.target/avr/torture/builtins-1.c: New test. * gcc.target/avr/torture/builtins-error.c: New test. gcc/ * config/avr/builtins.def: New file. * config/avr/t-avr (avr.o, avr-c.o): Depend on it. * config/avr/avr.c (enum avr_builtin_id): Use it. (avr_init_builtins): Use it. And use avr_bdesc. (bdesc_1arg): Remove. (bdesc_2arg): Remove. (bdesc_3arg): Remove. (struct avr_builtin_description): Add field n_args. (avr_bdesc): New static variable using builtins.def. (avr_expand_builtin): Use it. Don't call avr_expand_delay_cycles if op0 is not CONST_INT. (avr_fold_builtin): Fold AVR_BUILTIN_SWAP. Don't fold AVR_BUILTIN_INSERT_BITS if arg0 is not INTEGER_CST.
Index: config/avr/builtins.def =================================================================== --- config/avr/builtins.def (revision 0) +++ config/avr/builtins.def (revision 0) @@ -0,0 +1,50 @@ +/* Copyright (C) 2012 Free Software Foundation, Inc. + + 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/>. */ + +/* This file contains the definitions and documentation for the + builtins defined in the AVR part of the GNU compiler. + Befor including this file, define a macro + + DEF_BUILTIN(NAME, N_ARGS, ID, TYPE, ICODE) + + NAME: The name as visible by the user as a C string. + ID: An integer to identify the built-in. + N_ARGS: Number of input arguments. If special treatment is needed, + set to -1 and handle it by hand, see avr.c:avr_expand_builtin(). + TYPE: A tree node describing the prototype of the built-in. + ICODE: Insn code number for the insn attached to the built-in. + If special treatment is needed to expand the built-in, set to -1. +*/ + +/* Mapped to respective instruction. */ +DEF_BUILTIN ("__builtin_avr_nop", -1, AVR_BUILTIN_NOP, void_ftype_void, -1) +DEF_BUILTIN ("__builtin_avr_sei", 0, AVR_BUILTIN_SEI, void_ftype_void, CODE_FOR_enable_interrupt) +DEF_BUILTIN ("__builtin_avr_cli", 0, AVR_BUILTIN_CLI, void_ftype_void, CODE_FOR_disable_interrupt) +DEF_BUILTIN ("__builtin_avr_wdr", 0, AVR_BUILTIN_WDR, void_ftype_void, CODE_FOR_wdr) +DEF_BUILTIN ("__builtin_avr_sleep", 0, AVR_BUILTIN_SLEEP, void_ftype_void, CODE_FOR_sleep) + +/* Mapped to respective instruction but might alse be folded away + or emit as libgcc call if ISA does not provide the instruction. */ +DEF_BUILTIN ("__builtin_avr_swap", 1, AVR_BUILTIN_SWAP, uchar_ftype_uchar, CODE_FOR_rotlqi3_4) +DEF_BUILTIN ("__builtin_avr_fmul", 2, AVR_BUILTIN_FMUL, uint_ftype_uchar_uchar, CODE_FOR_fmul) +DEF_BUILTIN ("__builtin_avr_fmuls", 2, AVR_BUILTIN_FMULS, int_ftype_char_char, CODE_FOR_fmuls) +DEF_BUILTIN ("__builtin_avr_fmulsu", 2, AVR_BUILTIN_FMULSU, int_ftype_char_uchar, CODE_FOR_fmulsu) + +/* More complex stuff that cannot be mapped 1:1 to an instruction. */ +DEF_BUILTIN ("__builtin_avr_delay_cycles", -1, AVR_BUILTIN_DELAY_CYCLES, void_ftype_ulong, -1) +DEF_BUILTIN ("__builtin_avr_insert_bits", 3, AVR_BUILTIN_INSERT_BITS, uchar_ftype_ulong_uchar_uchar, CODE_FOR_insert_bits) Index: config/avr/avr.c =================================================================== --- config/avr/avr.c (revision 184269) +++ config/avr/avr.c (working copy) @@ -10504,17 +10504,12 @@ avr_out_insert_bits (rtx *op, int *plen) enum avr_builtin_id { - AVR_BUILTIN_NOP, - AVR_BUILTIN_SEI, - AVR_BUILTIN_CLI, - AVR_BUILTIN_WDR, - AVR_BUILTIN_SLEEP, - AVR_BUILTIN_SWAP, - AVR_BUILTIN_INSERT_BITS, - AVR_BUILTIN_FMUL, - AVR_BUILTIN_FMULS, - AVR_BUILTIN_FMULSU, - AVR_BUILTIN_DELAY_CYCLES + +#define DEF_BUILTIN(NAME, N_ARGS, ID, TYPE, CODE) ID, +#include "builtins.def" +#undef DEF_BUILTIN + + AVR_BUILTIN_COUNT }; static void @@ -10527,14 +10522,6 @@ avr_init_builtin_int24 (void) (*lang_hooks.types.register_builtin_type) (uint24_type, "__uint24"); } -#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. */ @@ -10574,58 +10561,36 @@ avr_init_builtins (void) unsigned_char_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); - - 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_insert_bits", uchar_ftype_ulong_uchar_uchar, - AVR_BUILTIN_INSERT_BITS); - +#define DEF_BUILTIN(NAME, N_ARGS, ID, TYPE, CODE) \ + add_builtin_function (NAME, TYPE, ID, BUILT_IN_MD, NULL, NULL_TREE); +#include "builtins.def" +#undef DEF_BUILTIN + avr_init_builtin_int24 (); } -#undef DEF_BUILTIN struct avr_builtin_description { - const enum insn_code icode; - const char *const name; - const enum avr_builtin_id id; + enum insn_code icode; + const char *name; + enum avr_builtin_id id; + int n_args; }; static const struct avr_builtin_description -bdesc_1arg[] = +avr_bdesc[] = { - { 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 } - }; +#define DEF_BUILTIN(NAME, N_ARGS, ID, TYPE, ICODE) \ + { ICODE, NAME, ID, N_ARGS }, +#include "builtins.def" +#undef DEF_BUILTIN -static const struct avr_builtin_description -bdesc_3arg[] = - { - { CODE_FOR_insert_bits, "__builtin_avr_insert_bits", - AVR_BUILTIN_INSERT_BITS } + { CODE_FOR_nothing, NULL, 0, -1 } }; + /* Subroutine of avr_expand_builtin to take care of unop insns. */ static rtx @@ -10807,7 +10772,6 @@ avr_expand_builtin (tree exp, rtx target int ignore ATTRIBUTE_UNUSED) { size_t i; - const struct avr_builtin_description *d; tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); const char* bname = IDENTIFIER_POINTER (DECL_NAME (fndecl)); unsigned int id = DECL_FUNCTION_CODE (fndecl); @@ -10820,31 +10784,16 @@ avr_expand_builtin (tree exp, rtx target 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, EXPAND_NORMAL); - if (! CONST_INT_P (op0)) + if (!CONST_INT_P (op0)) error ("%s expects a compile time integer constant", bname); + else + avr_expand_delay_cycles (op0); - avr_expand_delay_cycles (op0); return 0; } @@ -10862,18 +10811,31 @@ avr_expand_builtin (tree exp, rtx target } } - 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); - - for (i = 0, d = bdesc_3arg; i < ARRAY_SIZE (bdesc_3arg); i++, d++) - if (d->id == id) - return avr_expand_triop_builtin (d->icode, exp, target); - + for (i = 0; avr_bdesc[i].name; i++) + { + const struct avr_builtin_description *d = &avr_bdesc[i]; + + if (d->id == id) + switch (d->n_args) + { + case 0: + emit_insn ((GEN_FCN (d->icode)) (target)); + return 0; + + case 1: + return avr_expand_unop_builtin (d->icode, exp, target); + + case 2: + return avr_expand_binop_builtin (d->icode, exp, target); + + case 3: + return avr_expand_triop_builtin (d->icode, exp, target); + + default: + gcc_unreachable(); + } + } + gcc_unreachable (); } @@ -10895,17 +10857,32 @@ avr_fold_builtin (tree fndecl, int n_arg default: break; + case AVR_BUILTIN_SWAP: + { + return fold_build2 (LROTATE_EXPR, val_type, arg[0], + build_int_cst (val_type, 4)); + } + case AVR_BUILTIN_INSERT_BITS: { tree tbits = arg[1]; tree tval = arg[2]; tree tmap; tree map_type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); - double_int map = tree_to_double_int (arg[0]); + double_int map; bool changed = false; unsigned i; avr_map_op_t best_g; + + if (TREE_CODE (arg[0]) != INTEGER_CST) + { + /* No constant as first argument: Don't fold this and run into + error in avr_expand_builtin. */ + + break; + } + map = tree_to_double_int (arg[0]); tmap = double_int_to_tree (map_type, map); if (TREE_CODE (tval) != INTEGER_CST Index: config/avr/avr-c.c =================================================================== --- config/avr/avr-c.c (revision 184269) +++ config/avr/avr-c.c (working copy) @@ -71,9 +71,19 @@ avr_toupper (char *up, const char *lo) /* Worker function for TARGET_CPU_CPP_BUILTINS. */ +static const char *const avr_builtin_name[] = + { +#define DEF_BUILTIN(NAME, N_ARGS, ID, TYPE, CODE) NAME, +#include "builtins.def" +#undef DEF_BUILTIN + NULL + }; + void avr_cpu_cpp_builtins (struct cpp_reader *pfile) { + int i; + builtin_define_std ("AVR"); if (avr_current_arch->macro) @@ -140,8 +150,6 @@ avr_cpu_cpp_builtins (struct cpp_reader if (!strcmp (lang_hooks.name, "GNU C")) { - int i; - for (i = 0; avr_addrspace[i].name; i++) if (!ADDR_SPACE_GENERIC_P (i)) { @@ -157,20 +165,11 @@ avr_cpu_cpp_builtins (struct cpp_reader 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_INSERT_BITS"); - cpp_define (pfile, "__BUILTIN_AVR_DELAY_CYCLES"); - - cpp_define (pfile, "__BUILTIN_AVR_FMUL"); - cpp_define (pfile, "__BUILTIN_AVR_FMULS"); - cpp_define (pfile, "__BUILTIN_AVR_FMULSU"); - - cpp_define (pfile, "__INT24_MAX__=8388607L"); - cpp_define (pfile, "__INT24_MIN__=(-__INT24_MAX__-1)"); - cpp_define (pfile, "__UINT24_MAX__=16777215UL"); + for (i = 0; avr_builtin_name[i]; i++) + { + const char *name = avr_builtin_name[i]; + char *Name = (char*) alloca (1 + strlen (name)); + + cpp_define (pfile, avr_toupper (Name, name)); + } } Index: config/avr/t-avr =================================================================== --- config/avr/t-avr (revision 184266) +++ config/avr/t-avr (working copy) @@ -34,6 +34,8 @@ avr-log.o: $(srcdir)/config/avr/avr-log. $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(INPUT_H) $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< +avr.o avr-c.o: $(srcdir)/config/avr/builtins.def + # Files and Variables auto-generated from avr-mcus.def AVR_MCUS = $(srcdir)/config/avr/avr-mcus.def
Index: testsuite/gcc.target/avr/torture/builtins-error.c =================================================================== --- testsuite/gcc.target/avr/torture/builtins-error.c (revision 0) +++ testsuite/gcc.target/avr/torture/builtins-error.c (revision 0) @@ -0,0 +1,11 @@ +/* { dg-do assemble } */ + +char insert (long a) +{ + return __builtin_avr_insert_bits (15.3f+a, 0, 0); /* { dg-error "expects a compile time" } */ +} + +void delay (long a) +{ + __builtin_avr_delay_cycles (a); /* { dg-error "expects a compile time" } */ +} Index: testsuite/gcc.target/avr/torture/builtins-1.c =================================================================== --- testsuite/gcc.target/avr/torture/builtins-1.c (revision 0) +++ testsuite/gcc.target/avr/torture/builtins-1.c (revision 0) @@ -0,0 +1,38 @@ +/* { dg-do compile } */ + +void nop (void) { __builtin_avr_nop (); } +void sei (void) { __builtin_avr_sei (); } +void cli (void) { __builtin_avr_cli (); } +void wdr (void) { __builtin_avr_wdr (); } +void sleep (void) { __builtin_avr_sleep (); } + +char fmul (char a, char b) { return __builtin_avr_fmul (a, b); } +char fmuls (char a, char b) { return __builtin_avr_fmuls (a, b); } +char fmulsu (char a, char b) { return __builtin_avr_fmulsu (a, b); } + +char swap1 (char a) +{ + return __builtin_avr_swap (a+1); +} + +char swap2 (char a) +{ + return __builtin_avr_swap (__builtin_avr_swap (a+1)); +} + +char swap15 (void) +{ + return __builtin_avr_swap (15); +} + +void delay0 (void) { __builtin_avr_delay_cycles (0); } +void delay1 (void) { __builtin_avr_delay_cycles (1); } +void delay2 (void) { __builtin_avr_delay_cycles (2); } +void delay3 (void) { __builtin_avr_delay_cycles (3); } + +void delay_1 (void) { __builtin_avr_delay_cycles (44); } +void delay_2 (void) { __builtin_avr_delay_cycles (0x1234); } +void delay_3 (void) { __builtin_avr_delay_cycles (0x123456); } +void delay_4 (void) { __builtin_avr_delay_cycles (-1ul); } + +/* { dg-final { scan-assembler-not "__builtin_avr_" } } */