From patchwork Sun Jan 14 13:05:11 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: 84056 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A15C13858C54 for ; Sun, 14 Jan 2024 13:05:46 +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 [81.169.146.218]) by sourceware.org (Postfix) with ESMTPS id CD9353858D1E for ; Sun, 14 Jan 2024 13:05:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CD9353858D1E 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 CD9353858D1E Authentication-Results: server2.sourceware.org; arc=pass smtp.remote-ip=81.169.146.218 ARC-Seal: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1705237521; cv=pass; b=cbNH6I655F8zMBoE1RFxzDWc0KixNv/rClGisMPBbGF+WPbQjAcHsf+ZGsaDpe0TDuHyD+HRdMxNzlM8b66CbtcqW/wmANje7qvZLNdSbyu45UmLxWwKSllSDRx050/ZCGgPCp7sSemPD2pk5JqtlUn66IJJ2gb4PbHygn6fEOs= ARC-Message-Signature: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1705237521; c=relaxed/simple; bh=RYdH7vYajBYmKTfSgBkZY/TbamqFow6fJULD79QttCI=; h=DKIM-Signature:DKIM-Signature:Message-ID:Date:MIME-Version:From: To:Subject; b=HBvYhYkTgpN6TGCTv7Nr9/WD9aWRlIpavC7yNmYj2McQcyEKP2x7nY8Dp9vBfxGkVFYAnhMi3w/1Px/Jt1Az48LY5z+R317PnJjSYMrhB74cUv2sAqPsdVrjiuXw44Iuf5JR6OfVgh1zb53jWlf/XL3kqGDG4IlkCXlx4kPE3rE= ARC-Authentication-Results: i=2; server2.sourceware.org ARC-Seal: i=1; a=rsa-sha256; t=1705237513; cv=none; d=strato.com; s=strato-dkim-0002; b=ihMJOW4ZJ3Y8CQaMZ41/qYebn/JQDvOCmDO3VNTxUC4tMdAd/kAU/51+SfvVifFyDE PYX+PCc8sT3ndE3BsvrsfejP9p4ngHnQEhqDFHuYB73twCrrUT5rGU1jHlMtiKTDY+Ty NwT34y5a6FUGCh2M3WiOk0dhEt+flXLKUpr1tbe89wISAQx7hR60RARAUuyzOFyMtNrl 6DSQ448r8W/5u1ptn7RzF/jqN9gEIieAn7j2SmvW7d5LEox9DvhaHtPorxI+Zpy/OhDH YZlqHUeZH1Rmdh5o/Gzvo+cUeZ6goEDQZ8m/Y/rz32DI4Rz5EoicN/RxA5+IIe2ppTBs tIIg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1705237513; s=strato-dkim-0002; d=strato.com; h=Subject:To:From:Date:Message-ID:Cc:Date:From:Subject:Sender; bh=8I0k/NweZWX4aHohqaF+98OHb0HuRARr+UH4C9MNMic=; b=RkKUvcGA5Ind5nWBculIx79+8w+YKThxKMDxsoiO9vCuEFTgBsOMjtoUEa00k+Pnlu h4yIj1MDFVgn2feQlfHJG5TgwL4ROJiCSIV2d9BHOkdgckHJYuBgT6z7txgEFaxmOknB gs3H9IqvZ6GpKfiaKuNjYzTD6VbipMdW4fmqpcLwUYe82msrwkxLAkfYmZPCsqLfuSX4 PGxyYA1XaKmuNiIPOBWCHDWGdjn+lHHPZpzmFFFo+cq+6Ovlc7HdAcTNOjyu+c85nFfy 8WwQRrxep5yzLMnscSWaexGkFhbJfO/P+dzeAZokxRYj7zQPhGfzKrCCSKRkSHIy4pqY W5Cw== 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=1705237513; s=strato-dkim-0002; d=gjlay.de; h=Subject:To:From:Date:Message-ID:Cc:Date:From:Subject:Sender; bh=8I0k/NweZWX4aHohqaF+98OHb0HuRARr+UH4C9MNMic=; b=q0SOLVnosHgggJRn4w3MssNT2HfgyorbzzldaKEE5y53erJp7eC4X4Ajm1hZ8FDGNW ZBs34lQyJEZGDyjiQl44uPM+ounBV3OGbIp7HzLkkCsqrS1/9oXrkd4v/03MY6noEGwm XP6DXDjRjEIu7W9MWsra0PkqXjT12MTVc4B7uRxWt+vBNSOVZbD8PtxRpDc90kHBUjdw x8xzN9S41CyXMIP4OxeJiGjVo6Htq5/Pl10cAZjTCMGlTCmJ50qt8Oh/ol1mGSdbaU1x qYGeeK2mxXhN2bFNemvp12RfS4MjcuTpd9FhGQsQH8yhdGMUds2qfZ1sz94tBMryj5J5 04UA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1705237513; s=strato-dkim-0003; d=gjlay.de; h=Subject:To:From:Date:Message-ID:Cc:Date:From:Subject:Sender; bh=8I0k/NweZWX4aHohqaF+98OHb0HuRARr+UH4C9MNMic=; b=U5Q2lXmtv0GkubWfD4QEBHOP/FCovVWmoimA/pPaF+k3XsF+EGcPjNhFUNxGvcP9oV pbbW1+Dl7kjZRfXHeGDg== X-RZG-AUTH: ":LXoWVUeid/7A29J/hMvvT3koxZnKT7Qq0xotTetVnKkSjsSjq3WhKPVxx3mY" Received: from [192.168.2.102] by smtp.strato.de (RZmta 49.10.2 DYNA|AUTH) with ESMTPSA id g5de8600ED5CTvM (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Sun, 14 Jan 2024 14:05:12 +0100 (CET) Message-ID: <3f4dc44a-95ba-42c7-bba2-eb6bfde6482d@gjlay.de> Date: Sun, 14 Jan 2024 14:05:11 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Content-Language: en-US From: Georg-Johann Lay To: gcc-patches@gcc.gnu.org, Denis Chertykov Subject: [patch,avr,ping #3] PR target/112944: Support .rodata in RAM for AVR64* and AVR128* devices X-Spam-Status: No, score=-10.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE 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+patchwork=sourceware.org@gcc.gnu.org Ping #3 RFA: https://gcc.gnu.org/pipermail/gcc-patches/2023-December/640140.html Ping #1 https://gcc.gnu.org/pipermail/gcc-patches/2023-December/640981.html Ping #2 https://gcc.gnu.org/pipermail/gcc-patches/2024-January/641912.html This is a patch that locates .rodata in flash for some AVR devices that can support it. All new functionality depends on Binutils PR31124 and is switched on by configure checks for the new emulations. https://sourceware.org/PR31124 is already upstream. For explanation of the gcc part see commit message below. Most of the patch is adjusting device-specs generation. When there are no objections, I would apply this in the next week or so, so that it is part of v14. Johann --- AVR: Support .rodata in Flash for AVR64* and AVR128* Devices. These devices see a 32 KiB block of their program memory (flash) in the RAM address space. This can be used to support .rodata in flash provided Binutils support PR31124 (Add new emulations which locate .rodata in flash). This patch does the following: * configure checks availability of Binutils PR31124. * Add new command line options -mrodata-in-ram and -flmap. While -flmap is for internal usage (communicate hardware properties from device-specs to the compiler proper), -mrodata-in-ram is a user space option that allows to return to the current rodata-in-ram layout. * Adjust gen-avr-mmcu-specs.cc so that device-specs are generated that sanity check options, and that translate -m[no-]rodata-in-ram to its emulation. * Objects in .rodata don't drag __do_copy_data. * Document new options and built-in macros. PR target/112944 gcc/ * configure.ac [target=avr]: Check availability of emulations avrxmega2_flmap and avrxmega4_flmap, resulting in new config vars HAVE_LD_AVR_AVRXMEGA2_FLMAP and HAVE_LD_AVR_AVRXMEGA4_FLMAP. * configure: Regenerate. * config.in: Regenerate. * doc/invoke.texi (AVR Options): Document -mflmap, -mrodata-in-ram, __AVR_HAVE_FLMAP__, __AVR_RODATA_IN_RAM__. * doc/avr-mmcu.texi: Regenerate. * gcc/config/avr/avr.opt (-mflmap, -mrodata-in-ram): New options. * config/avr/avr-arch.h (enum avr_device_specific_features): Add AVR_ISA_FLMAP. * config/avr/avr-mcus.def (AVR_MCU) [avr64*, avr128*]: Set isa flag AVR_ISA_FLMAP. * gcc/config/avr/avr.cc (avr_arch_index, avr_has_rodata_p): New vars. (avr_set_core_architecture): Set avr_arch_index. (have_avrxmega2_flmap, have_avrxmega4_flmap) (have_avrxmega3_rodata_in_flash): Set new static const bool according to configure results. (avr_rodata_in_flash_p): New function using them. (avr_asm_init_sections): Let readonly_data_section->unnamed.callback track avr_need_copy_data_p only if not avr_rodata_in_flash_p(). (avr_asm_named_section): Track avr_has_rodata_p. (avr_file_end): Emit __do_copy_data also when avr_has_rodata_p and not avr_rodata_in_flash_p (). * config/avr/specs.h (CC1_SPEC): Add %(cc1_rodata_in_ram). (LINK_SPEC): Add %(link_rodata_in_ram). (LINK_ARCH_SPEC): Remove. * gcc/config/avr/gen-avr-mmcu-specs.cc (have_avrxmega3_rodata_in_flash) (have_avrxmega2_flmap, have_avrxmega4_flmap): Set new static const bool according to configure results. (diagnose_mrodata_in_ram): New function. (print_mcu): Generate specs with the following changes: <*cc1_misc, *asm_misc, *link_misc>: New specs so that we don't need to extend avr/specs.h each time we add a new bell or whistle. <*cc1_rodata_in_ram, *link_rodata_in_ram>: New specs to diagnose -m[no-]rodata-in-ram. <*cpp_rodata_in_ram>: New. Does -D__AVR_RODATA_IN_RAM__=0/1. <*cpp_mcu>: Add -D__AVR_AVR_FLMAP__ if it applies. <*cpp>: Add %(cpp_rodata_in_ram). <*link_arch>: Use emulation avrxmega2_flmap, avrxmega4_flmap as requested. <*self_spec>: Add -mflmap or %/ld/scripttempl/avr.sc. */ enum avr_device_specific_features { @@ -175,9 +203,12 @@ enum avr_device_specific_features AVR_SHORT_SP = 0x2, /* Stack Pointer has 8 bits width. */ AVR_ERRATA_SKIP = 0x4, /* device has a core erratum. */ AVR_ISA_LDS = 0x8, /* whether LDS / STS is valid for all data in static - storage. Only useful for reduced Tiny. */ - AVR_ISA_RCALL = 0x10 /* Use RJMP / RCALL even though JMP / CALL - are available (-mshort-calls). */ + storage. Only useful for reduced Tiny. */ + AVR_ISA_RCALL = 0x10, /* Use RJMP / RCALL even though JMP / CALL + are available (-mshort-calls). */ + AVR_ISA_FLMAP = 0x20 /* Has NVMCTRL_CTRLB.FLMAP to select which 32 KiB + block of program memory is visible in the RAM + address space. */ }; /* Map architecture to its texinfo string. */ diff --git a/gcc/config/avr/avr-mcus.def b/gcc/config/avr/avr-mcus.def index 87b59245e3c..9fb23776d39 100644 --- a/gcc/config/avr/avr-mcus.def +++ b/gcc/config/avr/avr-mcus.def @@ -306,21 +306,21 @@ AVR_MCU ("atxmega16c4", ARCH_AVRXMEGA2, AVR_ISA_RMW, "__AVR_ATxmega16C4__" AVR_MCU ("atxmega32a4u", ARCH_AVRXMEGA2, AVR_ISA_RMW, "__AVR_ATxmega32A4U__", 0x2000, 0x0, 0x9000, 0) AVR_MCU ("atxmega32c4", ARCH_AVRXMEGA2, AVR_ISA_RMW, "__AVR_ATxmega32C4__", 0x2000, 0x0, 0x9000, 0) AVR_MCU ("atxmega32e5", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_ATxmega32E5__", 0x2000, 0x0, 0x9000, 0) -AVR_MCU ("avr64da28", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DA28__", 0x6000, 0x0, 0x10000, 0) -AVR_MCU ("avr64da32", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DA32__", 0x6000, 0x0, 0x10000, 0) -AVR_MCU ("avr64da48", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DA48__", 0x6000, 0x0, 0x10000, 0) -AVR_MCU ("avr64da64", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DA64__", 0x6000, 0x0, 0x10000, 0) -AVR_MCU ("avr64db28", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DB28__", 0x6000, 0x0, 0x10000, 0) -AVR_MCU ("avr64db32", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DB32__", 0x6000, 0x0, 0x10000, 0) -AVR_MCU ("avr64db48", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DB48__", 0x6000, 0x0, 0x10000, 0) -AVR_MCU ("avr64db64", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DB64__", 0x6000, 0x0, 0x10000, 0) -AVR_MCU ("avr64dd14", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DD14__", 0x6000, 0x0, 0x10000, 0) -AVR_MCU ("avr64dd20", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DD20__", 0x6000, 0x0, 0x10000, 0) -AVR_MCU ("avr64dd28", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DD28__", 0x6000, 0x0, 0x10000, 0) -AVR_MCU ("avr64dd32", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DD32__", 0x6000, 0x0, 0x10000, 0) -AVR_MCU ("avr64ea28", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64EA28__", 0x6800, 0x0, 0x10000, 0) -AVR_MCU ("avr64ea32", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64EA32__", 0x6800, 0x0, 0x10000, 0) -AVR_MCU ("avr64ea48", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64EA48__", 0x6800, 0x0, 0x10000, 0) +AVR_MCU ("avr64da28", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DA28__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64da32", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DA32__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64da48", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DA48__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64da64", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DA64__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64db28", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DB28__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64db32", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DB32__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64db48", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DB48__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64db64", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DB64__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64dd14", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD14__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64dd20", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD20__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64dd28", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD28__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64dd32", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD32__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64ea28", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64EA28__", 0x6800, 0x0, 0x10000, 0) +AVR_MCU ("avr64ea32", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64EA32__", 0x6800, 0x0, 0x10000, 0) +AVR_MCU ("avr64ea48", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64EA48__", 0x6800, 0x0, 0x10000, 0) /* Xmega, Flash + RAM < 64K, flash visible in RAM address space */ AVR_MCU ("avrxmega3", ARCH_AVRXMEGA3, AVR_ISA_NONE, NULL, 0x3f00, 0x0, 0x8000, 0) AVR_MCU ("attiny202", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny202__", 0x3f80, 0x0, 0x800, 0x8000) @@ -393,14 +393,14 @@ AVR_MCU ("atxmega64b1", ARCH_AVRXMEGA4, AVR_ISA_RMW, "__AVR_ATxmega64B1__" AVR_MCU ("atxmega64b3", ARCH_AVRXMEGA4, AVR_ISA_RMW, "__AVR_ATxmega64B3__", 0x2000, 0x0, 0x11000, 0) AVR_MCU ("atxmega64c3", ARCH_AVRXMEGA4, AVR_ISA_RMW, "__AVR_ATxmega64C3__", 0x2000, 0x0, 0x11000, 0) AVR_MCU ("atxmega64d4", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_ATxmega64D4__", 0x2000, 0x0, 0x11000, 0) -AVR_MCU ("avr128da28", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DA28__", 0x4000, 0x0, 0x20000, 0) -AVR_MCU ("avr128da32", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DA32__", 0x4000, 0x0, 0x20000, 0) -AVR_MCU ("avr128da48", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DA48__", 0x4000, 0x0, 0x20000, 0) -AVR_MCU ("avr128da64", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DA64__", 0x4000, 0x0, 0x20000, 0) -AVR_MCU ("avr128db28", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DB28__", 0x4000, 0x0, 0x20000, 0) -AVR_MCU ("avr128db32", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DB32__", 0x4000, 0x0, 0x20000, 0) -AVR_MCU ("avr128db48", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DB48__", 0x4000, 0x0, 0x20000, 0) -AVR_MCU ("avr128db64", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DB64__", 0x4000, 0x0, 0x20000, 0) +AVR_MCU ("avr128da28", ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DA28__", 0x4000, 0x0, 0x20000, 0) +AVR_MCU ("avr128da32", ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DA32__", 0x4000, 0x0, 0x20000, 0) +AVR_MCU ("avr128da48", ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DA48__", 0x4000, 0x0, 0x20000, 0) +AVR_MCU ("avr128da64", ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DA64__", 0x4000, 0x0, 0x20000, 0) +AVR_MCU ("avr128db28", ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DB28__", 0x4000, 0x0, 0x20000, 0) +AVR_MCU ("avr128db32", ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DB32__", 0x4000, 0x0, 0x20000, 0) +AVR_MCU ("avr128db48", ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DB48__", 0x4000, 0x0, 0x20000, 0) +AVR_MCU ("avr128db64", ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DB64__", 0x4000, 0x0, 0x20000, 0) /* Xmega, 64K < Flash <= 128K, RAM > 64K */ AVR_MCU ("avrxmega5", ARCH_AVRXMEGA5, AVR_ISA_NONE, NULL, 0x2000, 0x0, 0x11000, 0) AVR_MCU ("atxmega64a1", ARCH_AVRXMEGA5, AVR_ISA_NONE, "__AVR_ATxmega64A1__", 0x2000, 0x0, 0x11000, 0) diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 4bc3cf929de..d77e1aad5cd 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -220,6 +220,7 @@ static GTY(()) rtx xstring_e; /* Current architecture. */ const avr_arch_t *avr_arch; +enum avr_arch_id avr_arch_index; /* Unnamed sections associated to __attribute__((progmem)) aka. PROGMEM or to address space __flash* or __memx. Only used as singletons inside @@ -229,9 +230,10 @@ static GTY(()) section *progmem_section[ADDR_SPACE_COUNT]; /* Condition for insns/expanders from avr-dimode.md. */ bool avr_have_dimode = true; -/* To track if code will use .bss and/or .data. */ +/* To track if code will use .bss, .data, .rodata. */ bool avr_need_clear_bss_p = false; bool avr_need_copy_data_p = false; +bool avr_has_rodata_p = false; /* Transform UP into lowercase and write the result to LO. @@ -1059,6 +1061,7 @@ avr_set_core_architecture (void) && mcu->macro == NULL) { avr_arch = &avr_arch_types[mcu->arch_id]; + avr_arch_index = mcu->arch_id; if (avr_n_flash < 0) avr_n_flash = 1 + (mcu->flash_size - 1) / 0x10000; @@ -10758,6 +10761,49 @@ avr_insert_attributes (tree node, tree *attributes) } } +#ifdef HAVE_LD_AVR_AVRXMEGA2_FLMAP +static const bool have_avrxmega2_flmap = true; +#else +static const bool have_avrxmega2_flmap = false; +#endif + +#ifdef HAVE_LD_AVR_AVRXMEGA4_FLMAP +static const bool have_avrxmega4_flmap = true; +#else +static const bool have_avrxmega4_flmap = false; +#endif + +#ifdef HAVE_LD_AVR_AVRXMEGA3_RODATA_IN_FLASH +static const bool have_avrxmega3_rodata_in_flash = true; +#else +static const bool have_avrxmega3_rodata_in_flash = false; +#endif + + +static bool +avr_rodata_in_flash_p () +{ + switch (avr_arch_index) + { + default: + break; + + case ARCH_AVRTINY: + return true; + + case ARCH_AVRXMEGA3: + return have_avrxmega3_rodata_in_flash; + + case ARCH_AVRXMEGA2: + return avr_flmap && have_avrxmega2_flmap && avr_rodata_in_ram != 1; + + case ARCH_AVRXMEGA4: + return avr_flmap && have_avrxmega4_flmap && avr_rodata_in_ram != 1; + } + + return false; +} + /* Implement `ASM_OUTPUT_ALIGNED_DECL_LOCAL'. */ /* Implement `ASM_OUTPUT_ALIGNED_DECL_COMMON'. */ @@ -10890,13 +10936,11 @@ avr_output_addr_attrib (tree decl, const char *name, static void avr_asm_init_sections (void) { - /* Override section callbacks to keep track of `avr_need_clear_bss_p' - resp. `avr_need_copy_data_p'. If flash is not mapped to RAM then - we have also to track .rodata because it is located in RAM then. */ + /* Override section callbacks to keep track of `avr_need_clear_bss_p', + `avr_need_copy_data_p' and `avr_has_rodata_p'. + Track also .rodata for the case when .rodata is located in RAM. */ -#if defined HAVE_LD_AVR_AVRXMEGA3_RODATA_IN_FLASH - if (avr_arch->flash_pm_offset == 0) -#endif + if (! avr_rodata_in_flash_p ()) readonly_data_section->unnamed.callback = avr_output_data_section_asm_op; data_section->unnamed.callback = avr_output_data_section_asm_op; bss_section->unnamed.callback = avr_output_bss_section_asm_op; @@ -10937,13 +10981,9 @@ avr_asm_named_section (const char *name, unsigned int flags, tree decl) avr_need_copy_data_p = (startswith (name, ".data") || startswith (name, ".gnu.linkonce.d")); - if (!avr_need_copy_data_p -#if defined HAVE_LD_AVR_AVRXMEGA3_RODATA_IN_FLASH - && avr_arch->flash_pm_offset == 0 -#endif - ) - avr_need_copy_data_p = (startswith (name, ".rodata") - || startswith (name, ".gnu.linkonce.r")); + if (!avr_has_rodata_p) + avr_has_rodata_p = (startswith (name, ".rodata") + || startswith (name, ".gnu.linkonce.r")); if (!avr_need_clear_bss_p) avr_need_clear_bss_p = startswith (name, ".bss"); @@ -11273,7 +11313,8 @@ avr_file_end (void) linking in the initialization code from libgcc if resp. sections are empty, see PR18145. */ - if (avr_need_copy_data_p) + if (avr_need_copy_data_p + || (avr_has_rodata_p && ! avr_rodata_in_flash_p ())) fputs (".global __do_copy_data\n", asm_out_file); if (avr_need_clear_bss_p) diff --git a/gcc/config/avr/avr.opt b/gcc/config/avr/avr.opt index e75730857f5..ee0b40603f0 100644 --- a/gcc/config/avr/avr.opt +++ b/gcc/config/avr/avr.opt @@ -94,6 +94,14 @@ mstrict-X Target Var(avr_strict_X) Init(0) When accessing RAM, use X as imposed by the hardware, i.e. just use pre-decrement, post-increment and indirect addressing with the X register. Without this option, the compiler may assume that there is an addressing mode X+const similar to Y+const and Z+const and emit instructions to emulate such an addressing mode for X. +mflmap +Target Var(avr_flmap) Init(0) +The device has the bitfield NVMCTRL_CTRLB.FLMAP. This option is used internally. + +mrodata-in-ram +Target Var(avr_rodata_in_ram) Init(-1) +The device has the .rodata section located in the RAM area. + ;; For rationale behind -msp8 see explanation in avr.h. msp8 Target RejectNegative Var(avr_sp8) Init(0) diff --git a/gcc/config/avr/gen-avr-mmcu-specs.cc b/gcc/config/avr/gen-avr-mmcu-specs.cc index 89f8680e244..eb9ab8854d8 100644 --- a/gcc/config/avr/gen-avr-mmcu-specs.cc +++ b/gcc/config/avr/gen-avr-mmcu-specs.cc @@ -50,6 +50,8 @@ #define SPECFILE_USAGE_URL \ "https://gcc.gnu.org/gcc-5/changes.html" +#define WIKI_URL \ + "https://gcc.gnu.org/wiki/avr-gcc#spec-files" static const char header[] = "#\n" @@ -68,9 +70,13 @@ static const char header[] = static const char help_copy_paste[] = "# If you intend to use an existing device specs file as a starting point\n" - "# for a new device spec file, make sure you are copying from a specs\n" - "# file for a device from the same core architecture and SP width.\n" - "# See <" SPECFILE_USAGE_URL "> for a description\n" + "# for a new device spec file, make sure you are copying from a specs file\n" + "# for a device from the same or compatible:\n" + "# compiler version, compiler vendor, core architecture, SP width,\n" + "# short-calls and FLMAP.\n" + "# Otherwise, errors and wrong or sub-optimal code may likely occur.\n" + "# See <" WIKI_URL ">\n" + "# and <" SPECFILE_USAGE_URL "> for a description\n" "# of how to use such own spec files.\n"; #if defined (WITH_AVRLIBC) @@ -103,6 +109,60 @@ static const char help_dev_lib_name[] = "\n"; #endif // WITH_AVRLIBC + +#ifdef HAVE_LD_AVR_AVRXMEGA2_FLMAP +static const bool have_avrxmega2_flmap = true; +#else +static const bool have_avrxmega2_flmap = false; +#endif + +#ifdef HAVE_LD_AVR_AVRXMEGA4_FLMAP +static const bool have_avrxmega4_flmap = true; +#else +static const bool have_avrxmega4_flmap = false; +#endif + +#ifdef HAVE_LD_AVR_AVRXMEGA3_RODATA_IN_FLASH +static const bool have_avrxmega3_rodata_in_flash = true; +#else +static const bool have_avrxmega3_rodata_in_flash = false; +#endif + + +static void +diagnose_mrodata_in_ram (FILE *f, const char *spec, const avr_mcu_t *mcu) +{ + enum avr_arch_id arch_id = mcu->arch_id; + const avr_arch_t *arch = &avr_arch_types[arch_id]; + const bool is_arch = mcu->macro == NULL; + const bool flmap = (mcu->dev_attribute & AVR_ISA_FLMAP); + const bool have_flmap2 = have_avrxmega2_flmap && arch_id == ARCH_AVRXMEGA2; + const bool have_flmap4 = have_avrxmega4_flmap && arch_id == ARCH_AVRXMEGA4; + const bool have_flmap = flmap && (have_flmap2 || have_flmap4); + + const bool rodata_in_flash = (arch_id == ARCH_AVRTINY + || (arch_id == ARCH_AVRXMEGA3 + && have_avrxmega3_rodata_in_flash)); + fprintf (f, "%s:\n", spec); + if (rodata_in_flash && is_arch) + fprintf (f, "\t%%{mrodata-in-ram: %%e-mrodata-in-ram not supported" + " for %s}", mcu->name); + else if (rodata_in_flash) + fprintf (f, "\t%%{mrodata-in-ram: %%e-mrodata-in-ram not supported" + " for %s (arch=%s)}", mcu->name, arch->name); + else if (is_arch) + { + if (! have_flmap2 && ! have_flmap4) + fprintf (f, "\t%%{mno-rodata-in-ram: %%e-mno-rodata-in-ram not" + " supported for %s}", mcu->name); + } + else if (! have_flmap) + fprintf (f, "\t%%{mno-rodata-in-ram: %%e-mno-rodata-in-ram not supported" + " for %s (arch=%s)}", mcu->name, arch->name); + fprintf (f, "\n\n"); +} + + static void print_mcu (const avr_mcu_t *mcu) { @@ -130,6 +190,7 @@ print_mcu (const avr_mcu_t *mcu) bool rmw = (mcu->dev_attribute & AVR_ISA_RMW) != 0; bool sp8 = (mcu->dev_attribute & AVR_SHORT_SP) != 0; bool rcall = (mcu->dev_attribute & AVR_ISA_RCALL); + bool flmap = (mcu->dev_attribute & AVR_ISA_FLMAP); bool is_arch = mcu->macro == NULL; bool is_device = ! is_arch; int flash_pm_offset = 0; @@ -166,13 +227,24 @@ print_mcu (const avr_mcu_t *mcu) rcall_spec = rcall ? "-mshort-calls" : "%name); else - fprintf (f, "device %s (core %s, %d-bit SP%s)\n", mcu->name, - arch->name, sp8 ? 8 : 16, rcall ? ", short-calls" : ""); + fprintf (f, "device %s (core %s, %d-bit SP%s%s)\n", mcu->name, + arch->name, sp8 ? 8 : 16, rcall ? ", short-calls" : "", + have_flmap ? ", FLMAP" : ""); fprintf (f, "%s\n", header); if (is_device) @@ -212,6 +284,11 @@ print_mcu (const avr_mcu_t *mcu) ? "\t%{!mno-absdata: -mabsdata}" : "\t%{mabsdata}"); + // -m[no-]rodata-in-ram basically affects linking, but sanity-check early. + diagnose_mrodata_in_ram (f, "*cc1_rodata_in_ram", mcu); + + fprintf (f, "*cc1_misc:\n\t%%(cc1_rodata_in_ram)\n\n"); + // avr-gcc specific specs for assembling / the assembler. fprintf (f, "*asm_arch:\n\t-mmcu=%s\n\n", arch->name); @@ -235,6 +312,8 @@ print_mcu (const avr_mcu_t *mcu) ? "\t%{mno-skip-bug}" : "\t%{!mskip-bug: -mno-skip-bug}"); + fprintf (f, "*asm_misc:\n" /* empty */ "\n\n"); + // avr-specific specs for linking / the linker. int wrap_k = @@ -253,7 +332,10 @@ print_mcu (const avr_mcu_t *mcu) fprintf (f, "*link_relax:\n\t%s\n\n", LINK_RELAX_SPEC); - fprintf (f, "*link_arch:\n\t%s", LINK_ARCH_SPEC); + // -m[no-]rodata-in-ram affects linking. Sanity check its usage. + diagnose_mrodata_in_ram (f, "*link_rodata_in_ram", mcu); + + fprintf (f, "*link_arch:\n\t%s", link_arch_spec); if (is_device && flash_pm_offset) fprintf (f, " --defsym=__RODATA_PM_OFFSET__=0x%x", flash_pm_offset); @@ -274,12 +356,15 @@ print_mcu (const avr_mcu_t *mcu) fprintf (f, "\n\n"); } + fprintf (f, "*link_misc:\n\t%%(link_rodata_in_ram)\n\n"); + // Specs known to GCC. if (is_device) { fprintf (f, "*self_spec:\n"); fprintf (f, "\t%%name); + fprintf (f, "%s ", flmap_spec); fprintf (f, "%s ", rcall_spec); fprintf (f, "%s\n\n", sp8_spec); @@ -298,10 +383,26 @@ print_mcu (const avr_mcu_t *mcu) fprintf (f, " -U__AVR_PM_BASE_ADDRESS__"); fprintf (f, " -D__AVR_PM_BASE_ADDRESS__=0x%x", flash_pm_offset); } + if (have_flmap) + fprintf (f, " -D__AVR_HAVE_FLMAP__"); + + fprintf (f, "\n\n"); // *cpp_mcu + + const bool rodata_in_flash = (arch_id == ARCH_AVRTINY + || (arch_id == ARCH_AVRXMEGA3 + && have_avrxmega3_rodata_in_flash)); + fprintf (f, "*cpp_rodata_in_ram:\n\t-D__AVR_RODATA_IN_RAM__="); + if (rodata_in_flash) + fprintf (f, "0"); + else if (! have_flmap) + fprintf (f, "1"); + else + fprintf (f, "%%{!mrodata-in-ram:%%{!mno-rodata-in-ram:0}}" + "%%{mrodata-in-ram:1}" "%%{mno-rodata-in-ram:0}"); fprintf (f, "\n\n"); fprintf (f, "*cpp:\n"); - fprintf (f, "\t%%(cpp_mcu)"); + fprintf (f, "\t%%(cpp_mcu) %%(cpp_rodata_in_ram)"); #if defined (WITH_AVRLIBC) fprintf (f, " %%(cpp_avrlibc)"); #endif // WITH_AVRLIBC diff --git a/gcc/config/avr/specs.h b/gcc/config/avr/specs.h index 433231fb6a9..574402035bc 100644 --- a/gcc/config/avr/specs.h +++ b/gcc/config/avr/specs.h @@ -35,7 +35,8 @@ along with GCC; see the file COPYING3. If not see "%(cc1_n_flash) " \ "%(cc1_errata_skip) " \ "%(cc1_rmw) " \ - "%(cc1_absdata) " + "%(cc1_absdata) " \ + "%(cc1_misc) " #undef CC1PLUS_SPEC #define CC1PLUS_SPEC \ @@ -53,10 +54,8 @@ along with GCC; see the file COPYING3. If not see "%(asm_relax) " \ "%(asm_rmw) " \ "%(asm_gccisr) " \ - "%(asm_errata_skip) " - -#define LINK_ARCH_SPEC \ - "%{mmcu=*:-m%*} " + "%(asm_errata_skip) " \ + "%(asm_misc) " #define LINK_RELAX_SPEC \ "%{mrelax:--relax} " @@ -68,6 +67,7 @@ along with GCC; see the file COPYING3. If not see "%(link_text_start) " \ "%(link_relax) " \ "%(link_pmem_wrap) " \ + "%(link_misc) " \ "%{shared:%eshared is not supported} " #undef LIB_SPEC diff --git a/gcc/configure b/gcc/configure index 996046f5198..4acb254d830 100755 --- a/gcc/configure +++ b/gcc/configure @@ -28455,6 +28455,7 @@ $as_echo "#define HAVE_AS_AVR_MGCCISR_OPTION 1" >>confdefs.h fi + avr_ld_ver="`$gcc_cv_ld -v | sed -e 's:^.* ::'`" # Check how default linker description file implements .rodata for # avrxmega3 (PR21472). avr-gcc assumes .rodata is *not* loaded to # RAM so avr-gcc skips __do_copy_data for .rodata objects. @@ -28499,7 +28500,6 @@ $as_echo "#define HAVE_LD_AVR_AVRXMEGA3_RODATA_IN_FLASH 1" >>confdefs.h $as_echo "no: avrxmega3 .rodata located in RAM" >&6; } echo "$as_me: nm output was" >&5 cat conftest.nm >&5 - avr_ld_ver="`$gcc_cv_ld -v | sed -e 's:^.* ::'`" { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: support for avrxmega3 .rodata in flash needs Binutils 2.29 or higher (have $avr_ld_ver)" >&5 $as_echo "$as_me: WARNING: support for avrxmega3 .rodata in flash needs Binutils 2.29 or higher (have $avr_ld_ver)" >&2;} fi @@ -28512,6 +28512,74 @@ $as_echo "test failed" >&6; } $as_echo "$as_me: WARNING: see \`config.log' for details" >&2;} fi rm -f conftest.s conftest.o conftest.elf conftest.nm + + # Check for emulation avrxmega2_flmap. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking binutils for avrxmega2_flmap support (PR31124)" >&5 +$as_echo_n "checking binutils for avrxmega2_flmap support (PR31124)... " >&6; } + cat > conftest.s <&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + { ac_try='$gcc_cv_ld -mavrxmega2_flmap conftest.o -o conftest.elf' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + if test -s conftest.elf + then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_LD_AVR_AVRXMEGA2_FLMAP 1" >>confdefs.h + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: support for avrxmega2_flmap requires Binutils 2.42 or higher (have $avr_ld_ver)" >&5 +$as_echo "$as_me: WARNING: support for avrxmega2_flmap requires Binutils 2.42 or higher (have $avr_ld_ver)" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: see \`config.log' for details" >&5 +$as_echo "$as_me: WARNING: see \`config.log' for details" >&2;} + fi + rm -f conftest.o conftest.elf + + # Check for emulation avrxmega4_flmap. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking binutils for avrxmega4_flmap support (PR31124)" >&5 +$as_echo_n "checking binutils for avrxmega4_flmap support (PR31124)... " >&6; } + { ac_try='$gcc_cv_as -mmcu=avrxmega4 conftest.s -o conftest.o' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + { ac_try='$gcc_cv_ld -mavrxmega4_flmap conftest.o -o conftest.elf' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + if test -s conftest.elf + then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_LD_AVR_AVRXMEGA4_FLMAP 1" >>confdefs.h + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: support for avrxmega4_flmap requires Binutils 2.42 or higher (have $avr_ld_ver)" >&5 +$as_echo "$as_me: WARNING: support for avrxmega4_flmap requires Binutils 2.42 or higher (have $avr_ld_ver)" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: see \`config.log' for details" >&5 +$as_echo "$as_me: WARNING: see \`config.log' for details" >&2;} + fi + rm -f conftest.s conftest.o conftest.elf ;; cris-*-*) diff --git a/gcc/configure.ac b/gcc/configure.ac index 596e5f22f4f..d2ed14496c1 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -4549,6 +4549,7 @@ AS_HELP_STRING([--disable-fix-cortex-a53-843419], [AC_DEFINE(HAVE_AS_AVR_MGCCISR_OPTION, 1, [Define if your avr assembler supports -mgcc-isr option.])]) + avr_ld_ver="`$gcc_cv_ld -v | sed -e 's:^.* ::'`" # Check how default linker description file implements .rodata for # avrxmega3 (PR21472). avr-gcc assumes .rodata is *not* loaded to # RAM so avr-gcc skips __do_copy_data for .rodata objects. @@ -4574,7 +4575,6 @@ EOF AC_MSG_RESULT(no: avrxmega3 .rodata located in RAM) echo "$as_me: nm output was" >&AS_MESSAGE_LOG_FD cat conftest.nm >&AS_MESSAGE_LOG_FD - avr_ld_ver="`$gcc_cv_ld -v | sed -e 's:^.* ::'`" AC_MSG_WARN([[support for avrxmega3 .rodata in flash needs Binutils 2.29 or higher (have $avr_ld_ver)]]) fi else @@ -4584,6 +4584,42 @@ EOF AC_MSG_WARN([[see `config.log' for details]]) fi rm -f conftest.s conftest.o conftest.elf conftest.nm + + # Check for emulation avrxmega2_flmap. + AC_MSG_CHECKING(binutils for avrxmega2_flmap support (PR31124)) + cat > conftest.s < +__attribute__((naked, section(".init2"))) +__attribute__((used, unused, no_instrument_function)) +static void init_flmap (void) +{ + uint8_t ctrlb = NVMCTRL_CTRLB; + ctrlb &= ~ NVMCTRL_FLMAP_gm; + ctrlb |= 0 << NVMCTRL_FLMAP_gp; + NVMCTRL_CTRLB = ctrlb; +} +#endif + +int main (void) +{ + const int *p = & val; + __asm ("" : "+r" (p)); + + if (*p != 1234) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/avr/torture/pr112944-flmap-1.c b/gcc/testsuite/gcc.target/avr/torture/pr112944-flmap-1.c new file mode 100644 index 00000000000..f18078d2e2c --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/pr112944-flmap-1.c @@ -0,0 +1,29 @@ +/* { dg-do run } */ +/* { dg-additional-options "-Wl,--defsym,__flmap=1" } */ + +const int val = 1234; + +#ifdef __AVR_HAVE_FLMAP__ +/* Initialize NVMCTRL_CTRLB.FLMAP to __flmap. */ +#include +__attribute__((naked, section(".init2"))) +__attribute__((used, unused, no_instrument_function)) +static void init_flmap (void) +{ + uint8_t ctrlb = NVMCTRL_CTRLB; + ctrlb &= ~ NVMCTRL_FLMAP_gm; + ctrlb |= 1 << NVMCTRL_FLMAP_gp; + NVMCTRL_CTRLB = ctrlb; +} +#endif + +int main (void) +{ + const int *p = & val; + __asm ("" : "+r" (p)); + + if (*p != 1234) + __builtin_abort (); + + return 0; +}