From patchwork Tue Jul 23 20:19:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Georg-Johann Lay X-Patchwork-Id: 1964021 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gjlay.de header.i=@gjlay.de header.a=rsa-sha256 header.s=strato-dkim-0002 header.b=VoihKY0p; dkim=pass header.d=gjlay.de header.i=@gjlay.de header.a=ed25519-sha256 header.s=strato-dkim-0003 header.b=+m80mIo9; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WT7n56kf3z20Cs for ; Wed, 24 Jul 2024 06:20:25 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 004B03858CD9 for ; Tue, 23 Jul 2024 20:20:24 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mo4-p00-ob.smtp.rzone.de (mo4-p00-ob.smtp.rzone.de [85.215.255.20]) by sourceware.org (Postfix) with ESMTPS id C8C213858D28 for ; Tue, 23 Jul 2024 20:19:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C8C213858D28 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gjlay.de Authentication-Results: sourceware.org; spf=none smtp.mailfrom=gjlay.de ARC-Filter: OpenARC Filter v1.0.0 sourceware.org C8C213858D28 Authentication-Results: server2.sourceware.org; arc=pass smtp.remote-ip=85.215.255.20 ARC-Seal: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1721766003; cv=pass; b=BLhJwTXl+KkCz45GQRKOY+5sxBmStbIvVQLycKSLytcLlIoT/qe75z4r8OAedvJhqKXEq6ZoybjEBgoBnvZXpQF1lDOPaEBQUTd3hSE6cfX8lThTVYGpeFAp5NRqol4cI/8ovgS/QJerEqc35Ds/Ya2WWxjkFh+t2HmlNM7QxF8= ARC-Message-Signature: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1721766003; c=relaxed/simple; bh=ifa3sNW5j1dUjvknX+01TkU1nnr2Ohx+e+hYG9pDWRg=; h=DKIM-Signature:DKIM-Signature:Message-ID:Date:MIME-Version:From: To:Subject; b=Cqs1jzyKq44751pnlP0D7zR6c4LK8yr9UIShx/1IIruaGU3MfTLiYVw2smM7qeeM90r6tvbEAdBiOYc2WgwsYeLNYhDP95LwPgYnxix7TzuMGUeQi1+fQkURn0StFBD8ieFyRnla6t4YiimQ6FvsxXaIQg1TdnHSRg/t95b5Y+g= ARC-Authentication-Results: i=2; server2.sourceware.org ARC-Seal: i=1; a=rsa-sha256; t=1721765997; cv=none; d=strato.com; s=strato-dkim-0002; b=O+t8OWQFyb01wCCuxZKnAIU95Jqg3UvZUSlE54u0beRVnx00K+lePgHYsZz58gYSBl T8tF1XS6ZYStoq4GfmyZ/kAnM0hcqJwCqNdiNTqlVJv2Vb3zknD628mrfsDW9eqSmeWl hy4zwGo1ZZlbIzaNqF7YSTee87ti6N356A4cBZLx3IVDmmgrLdcvSECUyqqrixgKU9uD NNgF6aNpOjkR4voj2B9xh0NUnWxyjm4XA6/JYqmVsaAlXAmN4PvyezpAUFekBRhzzmzs jF28aEf2rbxO5e50iASKGTQBQMCwrpdUv/TH0cCn6ZeMXRvoXzRF4XwQiEev/9iWFcBd Re5w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1721765997; s=strato-dkim-0002; d=strato.com; h=Subject:To:From:Date:Message-ID:Cc:Date:From:Subject:Sender; bh=dMaLcldJHSgXjVElKc8PUyrU4Mt4Qb3nQpRSfLZu7uI=; b=QAuCDgoSikENXS5c39cf4PtRQk0EfZNZL96rS/ipBPezQ4Aih6nEU+uLh8abnrZbGw EE6CoCZQ7I0SmgqhCom2vNK7KUPKVgN+1QoDeKJYHMgn123O91nEgtE4G4XuxZEZk02J qVlF+oXX6pw1yvmSq9q4k+KvbzCbHzrBjG+NNhDRV4AXOMvrhuX/DE6kl3ZkFdjxiYy3 /yy+c3geeh7uDby6fFCRR7DzgwojZxrJOuwxvwAqF1WYlJLvdwx7FBAmJRreZ+W8D02g uViv/qWcBhFTwOWONXmLHPhG0ibhAm91U05GR9X4Js8jQ41iD9DOWrAe9WOJsDudLLFD BnFg== ARC-Authentication-Results: i=1; strato.com; arc=none; dkim=none X-RZG-CLASS-ID: mo00 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1721765997; s=strato-dkim-0002; d=gjlay.de; h=Subject:To:From:Date:Message-ID:Cc:Date:From:Subject:Sender; bh=dMaLcldJHSgXjVElKc8PUyrU4Mt4Qb3nQpRSfLZu7uI=; b=VoihKY0pd/BneWEMK6aJJmR4AFB+FykCfAevBmq2oKhLaPfGreI3IgGZVhJNiWoEN4 DA33SxF3uixOT6aYGfznCsIpbbdUCUtgsASWZPcpi3WEewlzjmpOUddq+jfe4v/ns0uq b/w1UL/XcIWJgjJ9pcqr0OIM2V3aSYaj10Blj/NaME8DrhpVgnJRFMjYqOQlbYY9leXN FJrVureeXkJQtRNF4PUP7EtDFgA77/hHsgIGiq4PDGMaGp4KWmnHuraTYrLvbB9h5qBF GvgxQyJZUI+FxD8PAdPCteBPjklS4Rfgv4hUdRrC6RPtofP35hxs0059zAF6G3Vfhner Lsdg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1721765997; s=strato-dkim-0003; d=gjlay.de; h=Subject:To:From:Date:Message-ID:Cc:Date:From:Subject:Sender; bh=dMaLcldJHSgXjVElKc8PUyrU4Mt4Qb3nQpRSfLZu7uI=; b=+m80mIo91JXhe6ohSW+UrnzSRtE8lIJhGbhAsHagEbCsTaET5iH+Kj6hc9p3u6uiOc cgZPPeI5kSVw87mLr6DA== X-RZG-AUTH: ":LXoWVUeid/7A29J/hMvvT3koxZnKT7Qq0xotTetVnKkbjtK7q2y9LkX3jYYP" Received: from [192.168.2.102] by smtp.strato.de (RZmta 51.1.0 DYNA|AUTH) with ESMTPSA id xa21ea06NKJvJhG (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Tue, 23 Jul 2024 22:19:57 +0200 (CEST) Message-ID: <68252709-ae72-46d4-b787-b650051e7f22@gjlay.de> Date: Tue, 23 Jul 2024 22:19:56 +0200 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird From: Georg-Johann Lay Content-Language: en-US To: "gcc-patches@gcc.gnu.org" , Jeff Law Subject: [patch,avr] Implement PR116056: attribute signal(n) and interrupt(n) X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org This patch adds support for arguments to the signal and interrupt function attributes. It allows to specify the ISR by means of the associated IRQ number, in extension to the current attributes that require to specify the ISR name like "__vector_1" as (assembly) name for the function. The new feature is more convenient, e.g. when the ISR is implemented by a class method or in a namespace. There is no requirement that the ISR is externally visible. The syntax is like: __attribute__((signal(1, 2, ...), signal(3, 4, ...))) [static] void isr_function (void) { // Code } Ok for trunk? Johann --- AVR target 116056 - Support attribute signal(n) and interrupt(n). This patch adds support for arguments to the signal and interrupt function attributes. It allows to specify the ISR by means of the associated IRQ number, in extension to the current attributes that require to specify the ISR name like "__vector_1" as (assembly) name for the function. The new feature is more convenient, e.g. when the ISR is implemented by a class method or in a namespace. There is no requirement that the ISR is externally visible. The syntax is like: __attribute__((signal(1, 2, ...), signal(3, 4, ...))) [static] void isr_function (void) { // Code } PR target/116056 gcc/ * config/avr/avr.h (ASM_DECLARE_FUNCTION_NAME): New define. * config/avr/avr-protos.h (avr_declare_function_name): New proto. * config/avr/avr-c.cc (avr_cpu_cpp_builtins) <__HAVE_SIGNAL_N__>: New built-in macro. * config/avr/avr.cc (avr_declare_function_name): New function. (avr_attribute_table) : Allow any number of args. (avr_insert_attributes): Check validity of "signal" and "interrupt" arguments. (avr_foreach_function_attribute, avr_interrupt_signal_function) (avr_isr_number, avr_asm_isr_alias, avr_handle_isr_attribute): New static functions. (avr_interrupt_function): New from avr_interrupt_function_p. Adjust callers. (avr_signal_function): New from avr_signal_function_p. Adjust callers. (avr_set_current_function): Only diagnose non-__vector ISR names when "signal" or "interrupt" attribute has no args. (struct avr_fun_cookie): New. * doc/extend.texi (AVR Function Attributes): Document signal(num) and interrupt(num). * doc/invoke.texi (AVR Built-in Macros) <__HAVE_SIGNAL_N__>: Document. gcc/testsuite/ * gcc.target/avr/torture/signal_n-1.c: New test. * gcc.target/avr/torture/signal_n-2.c: New test. * gcc.target/avr/torture/signal_n-3.c: New test. * gcc.target/avr/torture/signal_n-4.cpp: New test. diff --git a/gcc/config/avr/avr-c.cc b/gcc/config/avr/avr-c.cc index 5e7f759ed73..2c5cfb34df6 100644 --- a/gcc/config/avr/avr-c.cc +++ b/gcc/config/avr/avr-c.cc @@ -391,6 +391,9 @@ avr_cpu_cpp_builtins (struct cpp_reader *pfile) cpp_define (pfile, "__WITH_AVRLIBC__"); #endif /* WITH_AVRLIBC */ + // We support __attribute__((signal (n1, n2, ...))). + cpp_define (pfile, "__HAVE_SIGNAL_N__"); + // From configure --with-libf7={|libgcc|math|math-symbols|yes|no} #ifdef WITH_LIBF7_LIBGCC diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index 5fdb1305757..7b666f17718 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -35,6 +35,7 @@ extern void avr_init_expanders (void); #ifdef TREE_CODE extern void avr_asm_output_aligned_decl_common (FILE*, tree, const char*, unsigned HOST_WIDE_INT, unsigned int, bool); extern void avr_asm_asm_output_aligned_bss (FILE *, tree, const char *, unsigned HOST_WIDE_INT, int, void (*) (FILE *, tree, const char *, unsigned HOST_WIDE_INT, int)); +extern void avr_declare_function_name (FILE *, const char *, tree); extern void asm_output_external (FILE *file, tree decl, char *name); extern int avr_progmem_p (tree decl, tree attributes); extern bool avr_addr_space_supported_p (addr_space_t, location_t loc = UNKNOWN_LOCATION); diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index e941730452e..7f82858659f 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -1356,6 +1356,33 @@ avr_lookup_function_attribute1 (const_tree func, const char *name) return NULL_TREE != lookup_attribute (name, TYPE_ATTRIBUTES (func)); } + +/* Call WORKER on all NAME attributes of function FUNC. */ + +static void +avr_foreach_function_attribute (tree func, const char *name, + void (*worker) (tree, tree, void *), + void *cookie) +{ + tree attrs = NULL_TREE; + + if (TREE_CODE (func) == FUNCTION_DECL) + attrs = DECL_ATTRIBUTES (func); + else if (FUNC_OR_METHOD_TYPE_P (func)) + attrs = TYPE_ATTRIBUTES (TREE_TYPE (func)); + + while (attrs) + { + attrs = lookup_attribute (name, attrs); + if (attrs) + { + worker (func, attrs, cookie); + attrs = TREE_CHAIN (attrs); + } + } +} + + /* Return nonzero if FUNC is a naked function. */ static bool @@ -1364,22 +1391,48 @@ avr_naked_function_p (tree func) return avr_lookup_function_attribute1 (func, "naked"); } -/* Return nonzero if FUNC is an interrupt function as specified - by the "interrupt" attribute. */ +/* Return 1 if FUNC is a function that has a "ATTR_NAME" attribute + (and perhaps also "ATTR_NAME(num)" attributes. Return -1 if FUNC has + "ATTR_NAME(num)" attribute(s) but no "ATTR_NAME" attribute. + When no form of ATTR_NAME is present, return 0. */ -static bool -avr_interrupt_function_p (tree func) +static int +avr_interrupt_signal_function (tree func, const char *attr_name) { - return avr_lookup_function_attribute1 (func, "interrupt"); + int res = 0; + + avr_foreach_function_attribute (func, attr_name, + [] (tree, tree attr, void *cookie) + { + int *pcook = (int*) cookie; + + *pcook = TREE_VALUE (attr) + ? *pcook ? *pcook : -1 + : 1; + }, &res); + + return res; } -/* Return nonzero if FUNC is a signal function as specified - by the "signal" attribute. */ -static bool -avr_signal_function_p (tree func) +/* Return 1 if FUNC is an interrupt function that has an "interrupt" attribute + (and perhaps also "interrupt(num)" attributes. Return -1 if FUNC has + "interrupt(num)" attribute(s) but no "interrupt" attribute. */ + +static int +avr_interrupt_function (tree func) +{ + return avr_interrupt_signal_function (func, "interrupt"); +} + +/* Return 1 if FUNC is a signal function that has a "signal" attribute + (and perhaps also "signal(num)" attributes. Return -1 if FUNC has + "signal(num)" attribute(s) but no "signal" attribute. */ + +static int +avr_signal_function (tree func) { - return avr_lookup_function_attribute1 (func, "signal"); + return avr_interrupt_signal_function (func, "signal"); } /* Return nonzero if FUNC is an OS_task function. */ @@ -1437,8 +1490,8 @@ avr_set_current_function (tree decl) location_t loc = DECL_SOURCE_LOCATION (decl); cfun->machine->is_naked = avr_naked_function_p (decl); - cfun->machine->is_signal = avr_signal_function_p (decl); - cfun->machine->is_interrupt = avr_interrupt_function_p (decl); + cfun->machine->is_signal = avr_signal_function (decl); + cfun->machine->is_interrupt = avr_interrupt_function (decl); cfun->machine->is_OS_task = avr_OS_task_function_p (decl); cfun->machine->is_OS_main = avr_OS_main_function_p (decl); cfun->machine->is_no_gccisr = avr_no_gccisr_function_p (decl); @@ -1475,23 +1528,25 @@ avr_set_current_function (tree decl) /* Interrupt handlers must be void __vector (void) functions. */ if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE) - error_at (loc, "%qs function cannot have arguments", isr); + { + error_at (loc, "%qs function cannot have arguments", isr); + if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) + inform (loc, "method %qs has an inplicit % argument", name); + } if (TREE_CODE (ret) != VOID_TYPE) error_at (loc, "%qs function cannot return a value", isr); #if defined WITH_AVRLIBC - /* Silently ignore 'signal' if 'interrupt' is present. AVR-LibC startet - using this when it switched from SIGNAL and INTERRUPT to ISR. */ - - if (cfun->machine->is_interrupt) - cfun->machine->is_signal = 0; - /* If the function has the 'signal' or 'interrupt' attribute, ensure that the name of the function is "__vector_NN" so as to catch - when the user misspells the vector name. */ + when the user misspells the vector name. This check is only + required when the "interrupt" resp. "signal" attribute does not + have an IRQ-number argument. */ - if (!startswith (name, "__vector")) + if (!startswith (name, "__vector") + && (cfun->machine->is_interrupt == 1 + || cfun->machine->is_signal == 1)) warning_at (loc, OPT_Wmisspelled_isr, "%qs appears to be a misspelled " "%qs handler, missing %<__vector%> prefix", name, isr); #endif // AVR-LibC naming conventions @@ -2976,6 +3031,70 @@ avr_expand_prologue (void) } +/* Turn TVAL into an integer that represents an ISR number. When no such + conversion is possible, then return 0. Unfortunately, we don't know + how many IRQs the device actually has. */ + +static int +avr_isr_number (tree tval) +{ + return (TREE_CODE (tval) == INTEGER_CST + && tree_fits_shwi_p (tval) + && tree_to_shwi (tval) > 0) + ? (int) tree_to_shwi (tval) + : 0; +} + + +struct avr_fun_cookie +{ + FILE *file; + const char *name; + tree decl; +}; + +/* A helper for `avr_declare_function_name' below. When the function has + attributes like signal(N) or interrupt(N), then define __vector_N as + a global alias for the function name. */ + +static void +avr_asm_isr_alias (tree /*func*/, tree attr, void *pv) +{ + avr_fun_cookie *cookie = (avr_fun_cookie*) pv; + + for (tree v = TREE_VALUE (attr); v; v = TREE_CHAIN (v)) + { + int ival = avr_isr_number (TREE_VALUE (v)); + + if (ival) + { + fprintf (cookie->file, ".global __vector_%d\n", ival); + fprintf (cookie->file, "__vector_%d = ", ival); + assemble_name (cookie->file, cookie->name); + fprintf (cookie->file, "\n"); + } + } +} + + +/* Worker for `ASM_DECLARE_FUNCTION_NAME'. */ + +void +avr_declare_function_name (FILE *file, const char *name, tree decl) +{ + // Default action without ASM_DECLARE_FUNCTION_NAME. + ASM_OUTPUT_FUNCTION_LABEL (file, name, decl); + + avr_fun_cookie fc = { file, name, decl }; + + if (cfun->machine->is_signal) + avr_foreach_function_attribute (decl, "signal", avr_asm_isr_alias, &fc); + + if (cfun->machine->is_interrupt) + avr_foreach_function_attribute (decl, "interrupt", avr_asm_isr_alias, &fc); +} + + /* Implement `TARGET_ASM_FUNCTION_END_PROLOGUE'. */ /* Output summary at end of function prologue. */ @@ -4366,8 +4485,8 @@ avr_xload_libgcc_p (machine_mode mode) static rtx avr_find_unused_d_reg (rtx_insn *insn, rtx exclude) { - bool isr_p = (avr_interrupt_function_p (current_function_decl) - || avr_signal_function_p (current_function_decl)); + bool isr_p = (avr_interrupt_function (current_function_decl) + || avr_signal_function (current_function_decl)); for (int regno = REG_16; regno < REG_32; regno++) { @@ -11583,9 +11702,9 @@ TARGET_GNU_ATTRIBUTES (avr_attribute_table, affects_type_identity, handler, exclude } */ { "progmem", 0, 0, false, false, false, false, avr_handle_progmem_attribute, NULL }, - { "signal", 0, 0, true, false, false, false, + { "signal", 0, -1, true, false, false, false, avr_handle_fndecl_attribute, NULL }, - { "interrupt", 0, 0, true, false, false, false, + { "interrupt", 0, -1, true, false, false, false, avr_handle_fndecl_attribute, NULL }, { "no_gccisr", 0, 0, true, false, false, false, avr_handle_fndecl_attribute, NULL }, @@ -11815,6 +11934,33 @@ avr_pgm_check_var_decl (tree node) } +/* Helper for `avr_insert_attributes'. Print an error when there are invalid + attributes named NAME, where NAME is in { "signal", "interrupt" }. */ + +static void +avr_handle_isr_attribute (tree, tree *attrs, const char *name) +{ + bool seen = false; + + for (tree list = lookup_attribute (name, *attrs); list; + list = lookup_attribute (name, TREE_CHAIN (list))) + { + seen = true; + for (tree v = TREE_VALUE (list); v; v = TREE_CHAIN (v)) + { + if (! avr_isr_number (TREE_VALUE (v))) + error ("attribute %qs expects a constant positive integer argument", + name); + } + } + + if (seen + && ! lookup_attribute ("used", *attrs)) + { + *attrs = tree_cons (get_identifier ("used"), NULL, *attrs); + } +} + /* Implement `TARGET_INSERT_ATTRIBUTES'. */ static void @@ -11847,6 +11993,9 @@ avr_insert_attributes (tree node, tree *attributes) NULL, *attributes); } + avr_handle_isr_attribute (node, attributes, "signal"); + avr_handle_isr_attribute (node, attributes, "interrupt"); + /* Add the section attribute if the variable is in progmem. */ if (VAR_P (node) diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h index 4977e15eeed..bd22398a4a1 100644 --- a/gcc/config/avr/avr.h +++ b/gcc/config/avr/avr.h @@ -424,6 +424,10 @@ typedef struct avr_args #define ASM_OUTPUT_ALIGNED_DECL_LOCAL(STREAM, DECL, NAME, SIZE, ALIGN) \ avr_asm_output_aligned_decl_common (STREAM, DECL, NAME, SIZE, ALIGN, true) +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \ + avr_declare_function_name (STREAM, NAME, DECL) + /* Globalizing directive for a label. */ #define GLOBAL_ASM_OP ".global\t" @@ -548,12 +552,18 @@ struct GTY(()) machine_function /* 'true' - if current function is a naked function. */ int is_naked; - /* 'true' - if current function is an interrupt function - as specified by the "interrupt" attribute. */ + /* 0 when no "interrupt" attribute is present. + 1 when an "interrupt" attribute without arguments is present (and + perhaps also "interrupt" attributes with argument(s)). + -1 when "interrupt" attribute(s) with arguments are present but none + without argument. */ int is_interrupt; - /* 'true' - if current function is a signal function - as specified by the "signal" attribute. */ + /* 0 when no "signal" attribute is present. + 1 when a "signal" attribute without arguments is present (and + perhaps also "signal" attributes with argument(s)). + -1 when "signal" attribute(s) with arguments are present but none + without argument. */ int is_signal; /* 'true' - if current function is a 'task' function diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 4b77599380b..3936f469d21 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -5136,6 +5136,34 @@ ISR (ADC_vect, ISR_NOBLOCK) // Uses the "interrupt" attribute. When both @code{signal} and @code{interrupt} are specified for the same function, then @code{signal} is silently ignored. +@cindex @code{signal(@var{num})} function attribute, AVR +@cindex @code{interrupt(@var{num})} function attribute, AVR +@item signal(@var{num}) +@itemx interrupt(@var{num}) + +Similar to the @code{signal} resp. @code{interrupt} attribute without +argument, but the IRQ number is supplied as an argument @var{num} to +the attribute, rather than providing the ISR name itself as the function name: + +@example +__attribute__((signal(1))) +void my_handler (void) +@{ + // Code for __vector_1 +@} + +#include + +__attribute__((__signal__(PCINT0_vect_num, PCINT1_vect_num))) +static void my_pcint0_1_handler (void) +@{ + // Code for PCINT0 and PCINT1 (__vector_3 and __vector_4 + // on ATmega328). +@} +@end example + +Notice that the handler function needs not to be externally visible. + @cindex @code{naked} function attribute, AVR @item naked This attribute allows the compiler to construct the diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index f052128e2a5..729795618eb 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -24564,6 +24564,13 @@ and defined to@tie{}0, otherwise. The compiler is configured to be used together with AVR-Libc. See the @option{--with-avrlibc} configure option. +@item __HAVE_SIGNAL_N__ +The compiler supports the @code{signal(@var{num})} and +@code{interrupt(@var{num})} +@ref{AVR Function Attributes,,function attributes} +with an argument @var{num} that specifies the number of the +interrupt service routine. + @item __HAVE_DOUBLE_MULTILIB__ Defined if @option{-mdouble=} acts as a multilib option. diff --git a/gcc/testsuite/gcc.target/avr/torture/signal_n-1.c b/gcc/testsuite/gcc.target/avr/torture/signal_n-1.c new file mode 100644 index 00000000000..0e4c109fe9e --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/signal_n-1.c @@ -0,0 +1,32 @@ +/* { dg-do run } */ + +volatile int i; + +__attribute__((signal(1,2))) +static void fun12 (void) +{ + __asm goto ("brie %x0" ::: "memory" : l_abort); + i += 1234; + return; + + l_abort: + __asm ("%~jmp abort" ::: "memory"); +} + +extern void isr1 (void) __asm("__vector_1"); +extern void isr2 (void) __asm("__vector_2"); + +int main (void) +{ + __asm ("cli" ::: "memory"); + isr1(); + if (i != 1234) + __builtin_abort (); + + __asm ("cli" ::: "memory"); + isr2(); + if (i != 2468) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/avr/torture/signal_n-2.c b/gcc/testsuite/gcc.target/avr/torture/signal_n-2.c new file mode 100644 index 00000000000..f6cc19d9842 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/signal_n-2.c @@ -0,0 +1,32 @@ +/* { dg-do run } */ + +volatile int i; + +__attribute__((interrupt(1),interrupt(2))) +static void fun12 (void) +{ + __asm goto ("brid %x0" ::: "memory" : l_abort); + i += 1234; + return; + + l_abort: + __asm ("%~jmp abort" ::: "memory"); +} + +extern void isr1 (void) __asm("__vector_1"); +extern void isr2 (void) __asm("__vector_2"); + +int main (void) +{ + __asm ("cli" ::: "memory"); + isr1(); + if (i != 1234) + __builtin_abort (); + + __asm ("cli" ::: "memory"); + isr2(); + if (i != 2468) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/avr/torture/signal_n-3.c b/gcc/testsuite/gcc.target/avr/torture/signal_n-3.c new file mode 100644 index 00000000000..379056a110f --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/signal_n-3.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ + +__attribute__((signal(0))) static void fun1 (void); /* { dg-error "expects a constant positive integer" } */ + +__attribute__((signal("1"))) static void fun2 (void); /* { dg-error "expects a constant positive integer" } */ + +__attribute__((interrupt(-1))) void fun3 (void); /* { dg-error "expects a constant positive integer" } */ + +__attribute__((interrupt("2"))) void fun4 (void); /* { dg-error "expects a constant positive integer" } */ + diff --git a/gcc/testsuite/gcc.target/avr/torture/signal_n-4.cpp b/gcc/testsuite/gcc.target/avr/torture/signal_n-4.cpp new file mode 100644 index 00000000000..749fe3cce78 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/signal_n-4.cpp @@ -0,0 +1,53 @@ +/* { dg-do run } */ + +class IRQS +{ +public: + void test (int x) const + { + if (i != x) + __builtin_abort (); + } + +private: + static volatile int i; + + __attribute__((signal(1,2))) + static void fun12 () + { + i += 1234; + } +}; + +extern void isr1 () __asm("__vector_1"); +extern void isr2 () __asm("__vector_2"); +extern void isr3 () __asm("__vector_3"); + +IRQS irqs; + +volatile int IRQS::i; + +namespace +{ + int j; + __attribute__((signal(3))) + void handle3 () + { + j = 444; + } +} + +int main (void) +{ + isr1(); + irqs.test (1234); + + isr2(); + irqs.test (2468); + + isr3 (); + if (j != 444) + __builtin_abort(); + + return 0; +}