From patchwork Wed Aug 5 10:02:09 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Silva X-Patchwork-Id: 140639 X-Patchwork-Delegate: jlaw@ventanamicro.com Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CFFD84BB1C3D for ; Wed, 5 Aug 2026 10:03:36 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CFFD84BB1C3D Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=outlook.com header.i=@outlook.com header.a=rsa-sha256 header.s=selector1 header.b=cj5cQgVR X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from LO2P265CU024.outbound.protection.outlook.com (mail-uksouthazolkn19011072.outbound.protection.outlook.com [52.103.37.72]) by sourceware.org (Postfix) with ESMTPS id 83DDB4BAE7E8 for ; Wed, 5 Aug 2026 10:02:42 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 83DDB4BAE7E8 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=outlook.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=outlook.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 83DDB4BAE7E8 Authentication-Results: sourceware.org; arc=pass smtp.remote-ip=52.103.37.72 ARC-Seal: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1785924162; cv=pass; b=sCBt+1sLcG9xhOuukPRPTOSJfCHBLFQyrufEZrTrhXGfsGO0rjEVix157+8LMyVComdudQT03GBqoVPBlMg7W+CxPOANqURcUXtnECwtD4abTT7LqNYjCnzB8I5+S+tvdULwGi5uq53l1Zoh7Me1nA896lPsNviYQIocIcd0RYY= ARC-Message-Signature: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1785924162; c=relaxed/simple; bh=ciTMgXc7yOeS1VbGI2oloD7KESSTjZ75DO2wu0tZfRE=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=lMYP1C41iQmjv8oHlJtoPbdtN5z/ns5lt0NAgj7xqy+qpZVai9q7+e99Re9T0QdlfjS5MPEsUGHeb+y8jQh3Zy8fgmujfuGFfP5dL1P8+b8zozHZJABddsS4SwZaDJj8ngk9Go5k2cZpxkB0OVwX0dVBa4ZD/UoXWUsYNimXKuM= ARC-Authentication-Results: i=2; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=outlook.com header.i=@outlook.com header.a=rsa-sha256 header.s=selector1 header.b=cj5cQgVR DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 83DDB4BAE7E8 ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=uTTKEkc98WQnQZ8uNJcjDufsFjj3clh/aIXqfPLT6saOvUEJw8loh5UnS3WkqU96YDbAyUiVZ1XC5ms3SB39OWNZZOKLDPMcrBt9F+VY7VrE/IXOTbAiuro6cTtPwNoHcFF82HFT4JJVrsUztXiRgwiwKUaiB1T/gGlCdEY0/GE+Tp804pM4QPk9LrJ6LnrL1suDqOw2wIHLaekXU56Jm107UFjCKROVPjzwB0jmdexU08+DagtOvBeWruWoBMdVhe4us9Kb/z3QuaR5zcqWOYxTYtCJV3L3vzR9fvTqByTfwqOYGAD72OxSTEQ8XF/QT7gf3sSpSDbCHwueZwodKQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=GgucMZ02QSFDvxil1HJEG9v108Y9/1dUOGmI4BB6emg=; b=KTa+T9tVeLUl/2IWrDoxdCvkNQfAYy7yR1g0IkewdhsK9bt8eiK827Bc2o7m7iA5u+4d4upPRrj96bpTmR/iN6rqq8AHh9JrOGjtuFcg+zI4KTP+5tYcZkXHU1GQmluY09oDrsWR2KWmjCOzyaD/a8d1dToXao9q2vLaGGeeoKWgV53y15MWnhTvaMxXGzbLMJDzpwHo8DwBGIZISLZAK95FD8G1B1X054iT2YL8fZ8KBb6GpqDzjoJxnb2mDE2nXJ7LFr9hF9bNgirhFuleng6tJ/kYh9+x3DRq32ol3MpPrYjNfwuEq1fHHb5Us9ZavPuUR86AZYK7CneoiKVfQw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=outlook.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=GgucMZ02QSFDvxil1HJEG9v108Y9/1dUOGmI4BB6emg=; b=cj5cQgVR/CxkVQtc3v7iT0clGjx7Rp2ku6BWPSX5y2LXDdEFQT8DzvnsgT0jh6hsd0fuSuQwRaHIP8j0w/9xS7ZjCBTyq3y4AYqaktUEpmPtPwN8C9tKmF0bfFPlKp4jHl71f2H1sqcLEhQDkJu3GwBdjzZ00OvJSxPUOPbb2JSWIWerIc6hgeBvh7YLnZl+8fw7soPBUMP0p3OpYmHTAjSwUoutECtX8rvurrkhZitjqRiNCxfuPjsleuR8NrfY6xkEf3OGEOMhjH0TEY8EeM7/wiIVgGDjsqNJwy99ZF2ttOOI+nXw51xnVjsB5Vpgf5vku2BCkHboroi9/0wQdw== Received: from LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2b1::6) by CWLP265MB5868.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:1b0::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.270.19; Wed, 5 Aug 2026 10:02:37 +0000 Received: from LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM ([fe80::839:df74:7f0e:b82a]) by LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM ([fe80::839:df74:7f0e:b82a%2]) with mapi id 15.21.0292.015; Wed, 5 Aug 2026 10:02:37 +0000 From: Luis Silva To: gcc-patches@gcc.gnu.org Cc: Jeff Law , Kito Cheng , Palmer Dabbelt , Robin Dapp , Luis Silva , Artemiy Volkov , Michiel Derhaeg , Loeka Rogge , Alex Turjan , Luis Silva Subject: [PATCH v2 1/4] RISC-V: Implement riscv_macro_fusion_pair_p for ARC-V RHX-100 series Date: Wed, 5 Aug 2026 11:02:09 +0100 Message-ID: X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260805100212.10852-1-luismgsilva@outlook.com> References: <20260805100212.10852-1-luismgsilva@outlook.com> X-ClientProxiedBy: MA4P292CA0012.ESPP292.PROD.OUTLOOK.COM (2603:10a6:250:2d::9) To LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2b1::6) X-Microsoft-Original-Message-ID: <20260805100212.10852-2-luismgsilva@outlook.com> MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: LO6P265MB6224:EE_|CWLP265MB5868:EE_ X-MS-Office365-Filtering-Correlation-Id: 0c3b66c4-3ee3-4407-a391-08def2d8ac22 X-Microsoft-Antispam: BCL:0; ARA:14566002|41001999006|5072599009|4140399003|19110799012|8060799015|25010399006|15080799012|23021999003|12121999013|19101099003|440099028|3412199025|2607281247196008|10035399007|52005399003|40105399003|1710799026; X-Microsoft-Antispam-Message-Info: ce+Jn8z3wjNALAFM8rOOlu0Is8RGkKtjJPxWXQ84dVUJ+LrYtEhgZNJuJ6n3WqQENw3kmWaBnPIWTlaMW3zXkwVotNTUh8A1PE4fJerWp4xAEPIAeQE2ApyiGarsYM6JMf0eO5BeO6O3x8n0T6V4CSrxah5NJjz48kf/bEN6Hr7MKikatJRONFctu0TLbIGZdskaX+YFH8dF29DT6PgcbDcRZr1mjteDO37iaRpST2l1+zluWMJ2uet+aXl3MLJC3UWBUkZ33BeeXjglTdl9gjWBmKdsNwYJILXUhGuS5DjKCCufjK/weky76lxlJPC98qC0z0y3CEPMQqqjNicJjYvUziHgdevQASfoGSsv79xSw7x09iWITE4If3pxnCntNbUNa7eNDAK1PLeLvZo5iYvNhLtlbFtPEJZRBGdK1XB+R/usJ5S/YYd6QRR6Gz4/RCPR8yI08LmzK8fdJoe+LlHxo1fhAFMLwH+ektohn3rBBJvHwG+raRwDuSIpSaPQpPBIS+hgjOqX5ZjVuE3RRJ2sDNegjFozT1hFG9k61/Z5Vp5ecEv4lAspoTqoZ4i0S4vjDtclON3PAWsvXGYPBMBOBGTG3kLA6PHsxTHpYsrIFwEgzfTWgLV51xgvtmQh2ln5K5Sz56Hq+ROdC7GM7+ygB+fzDh3F3tb6I3ecoYmT07c+nJhAxKN3pNojj887OJsgxGh466AW9/W8m04GsK3HtLqaQxc6UKuMXSzwY0ad4OuH8Lh2hglx1uQypItduF3L1XJp9rt5T08nYM4jcuzRosYAmeISA/5ntzSlA2LO3r+xP3xduujrrNYC37oib7kUANTZo2/bce/oFRS1K9oYeoHzASOTTH/XZ7zsnAFpVZ7/ZyKvzynBn+1+TUxwNQ2COwLuoTaB9/EySM/EDUPZPvHKDvPaJSINydZaCIDkQbk/FTDho2sV2NJHQZWnBfoHfITFt9WyblEYS8L2gXrn3k2+roJabW6BeYVEm2lUKwYNtOHeY2gJ5TsdFtlsfRgRMUKPswW8iqNmrVhDGg== X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: V0i018eb6eUG6u4qn8+ulI+exvTFUMoJbqh4V0n5FdTxQEW9o7TB/DV38IgWSN/vvcRpHw3tFkG8yI1gh0GqAbY2WHzfgI/E2GX/dVAfOe7fMtnUTsUiDlfMc3896w4U6wfOxEBJhr8RJnVQzyd12w+Y4iFvY40k4JkOfeniarCh50S3i6l7Iy+Gy6l6BUBoZDlKL2t/wyz6HsflgcXTfEA6KTfzBPAF6LF93Kcku62EG1lVyuvu8O9ox3i5NlRapJ6G1kYg4C38jW28xzOG2S2LgiqxQikkDUbDgJ/oZU4+wA/OspXJTV1/lgVmuLzRT9uB52Cinwfev1tc+6/4RcCUwPdcc/DDKf1cIg4Y12hV8HumG0mCPz10clWTlayDM2usuqEK6tH/6NHbxg4Hwn0MWT/9uYl6NfmTMH/6AI/uOnUVZ7fG0Ikl9JoDUi+cLPER6587pnh5iiGbEMj3H8q4JKgLzbiAkDrQ9ihdehzi3CQpY0R25AZfZEpIFYYz2bGOybMirNVZw5z7pKJoZntJY8/JD0HoWXzXKRb41TgHKm70Uivb5G4qaZ9GRQH0iqAx1PrDXcHxJV1PTJOzKiLgRIGiI8H5FdDbYyfINkHA2jWmE9DfSKiZVOOw1+XPfAaPC1rUjxpVrpNCzyJ+MrHtkVvVDKbaZDJS7vHMxrdgFxm4fqmyc246D7EzlkNkZ5F6zMsefnpSFRIcb1UlK5ughO/YlrsLDIUtDHITYXkJe7e42oI4fJxquFA8ta3QN2F0v21FVDyyUbyp+Aw7Ureh2DLZdoINqYGwx5mGmZ2M76qL8BuUFQOs+osXLOpiJesE+i0apySAsRW9AVArdoCtEZcF4IvRhdLePKWdUfzEMNd8cnSAcpXQx1f7TcR4jkNzOv7WbwDqyS7JiCmlYavhvx+WPoKdNmHZivSH9soO1lxrNEaYP+fqFIOYA2dRz3zJDLzGcXuyZVs6R0vETJ1nVk7+2B3N4IdJCmwdd7hroaMMHdKXWK2DQNwg/Cufcd9m3gqQXL+wbMTywB3NMkMDvNDaSX7lptvT2qxYBqq+KVM10HVo72U69JH5fX5m3Xn2CbdzC941g9covyH4+e6A1bYMGtGzrqw0zXEv+oayeyOm18Dztu7gBTPcOQ2Mrxf76ysTTrS5N7OZ5LQ75xqMk5+aOe284bGjoc5J+fUfTMwtM6jWKxfSYKToVL4t6YH0Gz8UBZor+XniXoZ2wPpZBr+Z6urNMVrompTtsT3Npb89EWfL0OWinXtfxR2aXj2cCw10IBeDnQiGakW9jbjHeF6ZXIq8pEpMG2bDmlWPTifpQgoSyqC5IwHjH++ijUn2zgBvviUL0jIYKYRRuZak5/3dZIB8LeippBDPSVieygk7Ta0dxTNeuhtKPww7U9t+dyDM7cPT1rU7CdJLqg== X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 0c3b66c4-3ee3-4407-a391-08def2d8ac22 X-MS-Exchange-CrossTenant-AuthSource: LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 05 Aug 2026 10:02:35.3650 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: CWLP265MB5868 X-Spam-Status: No, score=-7.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, LIKELY_SPAM_BODY, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SCC_5_SHORT_WORD_LINES, SPF_HELO_PASS, SPF_PASS, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 From: Luis Silva Add the RHX-100 macro-op fusion cases to the table in riscv-fusion.cc and enable them from the tune's fusible_ops field. Also split BFEXT into SRLI / SRAI. Pairs that compete with adjacent load/store (ls-update, lui-st, li-store) bail out when the next insn is a better adjacent memop candidate. Those, plus adjacent load/store themselves, wait until after reload. Fused_MAC only matches when the product is rs1 of the add: mul rd,...; add rd,rd,rs I1->I2 means fusion only in that order; I1<->I2 means the two instructions are interchangeable with regards to order. RHX-100 enables: RISCV_FUSE_MULT_ADD (riscv_fuse_mult_add, I1->I2) I1: mul rd,...; I2: add rd,rd,rs3 reading the mul result in rd (on RV64, mulw+addw with the result sign-extended to DImode). RISCV_FUSE_LI_BRANCH (riscv_fuse_li_branch, I1->I2) I1: li rd; I2: conditional branch that uses rd. RISCV_FUSE_LI_STORE (riscv_fuse_li_store, I1->I2) I1: li rt; I2: store of rt. RISCV_FUSE_LUI_ST (riscv_fuse_lui_st, I1<->I2) I1/I2: lui and store. RISCV_FUSE_LUI_LD_REV (riscv_fuse_lui_ld_reversible, I1<->I2) I1/I2: independent load and lui with distinct destinations. RISCV_FUSE_LS_UPDATE (riscv_fuse_ls_update, I1<->I2) I1/I2: load or store with an addi that updates the access base. RISCV_FUSE_BFEXT_SRLI (riscv_fuse_bfext_srli, I1->I2) I1: slli rd,rs; I2: srli rd,rd (bitfield extract). RISCV_FUSE_ADJACENT_LOAD (riscv_fuse_adjacent_load, I1<->I2) I1/I2: two loads, same base, offsets adjacent by GET_MODE_SIZE. RISCV_FUSE_ADJACENT_STORE (riscv_fuse_adjacent_store, I1<->I2) I1/I2: two stores, same base, offsets adjacent by GET_MODE_SIZE. Also rename RISCV_FUSE_BFEXT to RISCV_FUSE_BFEXT_SRLI and add RISCV_FUSE_BFEXT_SRAI for other tunes. gcc/ChangeLog: * config/riscv/riscv-fusion.cc (LUI_NONZERO_OPERAND): New macro. (riscv_fusion_enabled_p): Make non-static. (riscv_adjacent_memops_p): New function. (riscv_defer_for_adjacent_memop_p): New function. (riscv_ls_update_pair_p): New function. (riscv_fuse_lui_ld_pair_p): New function. (riscv_fuse_lui_ld): Use riscv_fuse_lui_ld_pair_p. (riscv_fuse_bfext_shift_p): New function. (riscv_fuse_bfext_srli): New function. (riscv_fuse_bfext_srai): New function. (riscv_fuse_mult_add): New function. (riscv_fuse_li_branch): New function. (riscv_fuse_adjacent_load): New function. (riscv_fuse_adjacent_store): New function. (riscv_fuse_ls_update): New function. (riscv_lui_st_pair_p): New function. (riscv_fuse_lui_st): New function. (riscv_fuse_li_store): New function. (riscv_fuse_lui_ld_reversible): New function. * config/riscv/riscv-protos.h (enum riscv_fusion_pairs): Rename RISCV_FUSE_BFEXT to RISCV_FUSE_BFEXT_SRLI; add the RHX-100 fusion bits and RISCV_FUSE_BFEXT_SRAI. (riscv_fusion_enabled_p): Declare. * config/riscv/riscv.cc (arcv_rhx100_tune_info): Set fusible_ops. * config/riscv/riscv.h (TARGET_ARCV_RHX100): New. gcc/testsuite/ChangeLog: * gcc.target/riscv/fusion-adjacent-load.c: New test. * gcc.target/riscv/fusion-adjacent-store.c: New test. * gcc.target/riscv/fusion-bfext-srai.c: New test. * gcc.target/riscv/fusion-bfext.c: New test. * gcc.target/riscv/fusion-li-branch.c: New test. * gcc.target/riscv/fusion-li-store.c: New test. * gcc.target/riscv/fusion-ls-update-2.c: New test. * gcc.target/riscv/fusion-ls-update-3.c: New test. * gcc.target/riscv/fusion-ls-update-4.c: New test. * gcc.target/riscv/fusion-ls-update-5.c: New test. * gcc.target/riscv/fusion-ls-update.c: New test. * gcc.target/riscv/fusion-lui-ld.c: New test. * gcc.target/riscv/fusion-lui-st.c: New test. * gcc.target/riscv/fusion-mult-add.c: New test. Co-authored-by: Artemiy Volkov Co-authored-by: Michiel Derhaeg Co-authored-by: Loeka Rogge Signed-off-by: Luis Silva --- gcc/config/riscv/riscv-fusion.cc | 582 +++++++++++++++++- gcc/config/riscv/riscv-protos.h | 12 +- gcc/config/riscv/riscv.cc | 6 +- gcc/config/riscv/riscv.h | 4 + .../gcc.target/riscv/fusion-adjacent-load.c | 12 + .../gcc.target/riscv/fusion-adjacent-store.c | 13 + .../gcc.target/riscv/fusion-bfext-srai.c | 18 + gcc/testsuite/gcc.target/riscv/fusion-bfext.c | 15 + .../gcc.target/riscv/fusion-li-branch.c | 14 + .../gcc.target/riscv/fusion-li-store.c | 12 + .../gcc.target/riscv/fusion-ls-update-2.c | 17 + .../gcc.target/riscv/fusion-ls-update-3.c | 81 +++ .../gcc.target/riscv/fusion-ls-update-4.c | 53 ++ .../gcc.target/riscv/fusion-ls-update-5.c | 13 + .../gcc.target/riscv/fusion-ls-update.c | 16 + .../gcc.target/riscv/fusion-lui-ld.c | 25 + .../gcc.target/riscv/fusion-lui-st.c | 19 + .../gcc.target/riscv/fusion-mult-add.c | 13 + 18 files changed, 905 insertions(+), 20 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-adjacent-load.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-adjacent-store.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-bfext-srai.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-bfext.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-li-branch.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-li-store.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-ls-update-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-ls-update-3.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-ls-update-4.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-ls-update-5.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-ls-update.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-lui-ld.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-lui-st.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-mult-add.c diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc index 4846dc0dfa2..98df3521029 100644 --- a/gcc/config/riscv/riscv-fusion.cc +++ b/gcc/config/riscv/riscv-fusion.cc @@ -32,8 +32,17 @@ along with GCC; see the file COPYING3. If not see #include "memmodel.h" #include "emit-rtl.h" #include "tm_p.h" +#include "regset.h" +#include "basic-block.h" +#include "insn-attr.h" +#include "sched-int.h" #include "riscv-protos.h" +/* A LUI_OPERAND accepts (const_int 0), but we won't emit that as LUI. + Reject that case explicitly. */ + +#define LUI_NONZERO_OPERAND(value) ((value) != 0 && LUI_OPERAND (value)) + /* Implement TARGET_SCHED_MACRO_FUSION_P. Return true if target supports instruction fusion of some sort. */ @@ -45,7 +54,7 @@ riscv_macro_fusion_p (void) /* Return true iff the instruction fusion described by OP is enabled. */ -static bool +bool riscv_fusion_enabled_p (enum riscv_fusion_pairs op) { return riscv_get_fusible_ops () & op; @@ -147,6 +156,247 @@ riscv_set_is_shNadduw_p (rtx set) && REG_P (SET_DEST (set))); } +/* Return TRUE if two memory operands can be fused based on their addresses. + Checks if MEM0 and MEM1 have the same base register with adjacent offsets, + making them suitable for fusion (e.g., adjacent load/store pairs). */ + +static bool +riscv_adjacent_memops_p (rtx mem0, rtx mem1, bool is_load) +{ + rtx base0, base1, tmp; + HOST_WIDE_INT off0 = 0, off1 = 0; + + if (GET_CODE (mem0) == SIGN_EXTEND || GET_CODE (mem0) == ZERO_EXTEND) + mem0 = XEXP (mem0, 0); + + if (GET_CODE (mem1) == SIGN_EXTEND || GET_CODE (mem1) == ZERO_EXTEND) + mem1 = XEXP (mem1, 0); + + if (!MEM_P (mem0) || !MEM_P (mem1)) + return false; + + if (GET_MODE (mem0) != GET_MODE (mem1)) + return false; + + /* Check if the mode is allowed for ARC-V fusion restrictions. + Loads: allow SI, HI, and QI modes. + Stores: allow only SI mode. */ + if (TARGET_ARCV_RHX100) + { + machine_mode mode = GET_MODE (mem0); + bool mode_allowed = ((is_load + && (mode == SImode + || mode == HImode + || mode == QImode)) + || (!is_load && mode == SImode)); + + if (!mode_allowed) + return false; + } + + rtx mem_addr0 = XEXP (mem0, 0); + rtx mem_addr1 = XEXP (mem1, 0); + + if (GET_CODE (mem_addr0) == PLUS) + { + base0 = XEXP (mem_addr0, 0); + tmp = XEXP (mem_addr0, 1); + if (!REG_P (base0) || !CONST_INT_P (tmp)) + return false; + off0 = INTVAL (tmp); + } + else if (REG_P (mem_addr0)) + base0 = mem_addr0; + else + return false; + + if (GET_CODE (mem_addr1) == PLUS) + { + base1 = XEXP (mem_addr1, 0); + tmp = XEXP (mem_addr1, 1); + if (!REG_P (base1) || !CONST_INT_P (tmp)) + return false; + off1 = INTVAL (tmp); + } + else if (REG_P (mem_addr1)) + base1 = mem_addr1; + else + return false; + + /* Check if we have the same base. */ + if (REGNO (base0) != REGNO (base1)) + return false; + + /* Fuse adjacent aligned addresses. */ + if ((off0 % GET_MODE_SIZE (GET_MODE (mem0)).to_constant () == 0) + && (abs (off1 - off0) == GET_MODE_SIZE (GET_MODE (mem0)).to_constant ())) + return true; + + return false; +} + +/* Return true if CURR should not be fused with PREV because CURR and the + next fusible insn form a better adjacent load/store pair. */ + +static bool +riscv_defer_for_adjacent_memop_p (rtx_insn *curr) +{ + rtx_insn *next = next_nonnote_nondebug_insn_bb (curr); + if (!next) + return false; + + rtx curr_set = single_set (curr); + rtx next_set = single_set (next); + if (!curr_set || !next_set) + return false; + + if (riscv_fusion_enabled_p (RISCV_FUSE_ADJACENT_LOAD) + && get_attr_type (curr) == TYPE_LOAD + && get_attr_type (next) == TYPE_LOAD + && riscv_adjacent_memops_p (SET_SRC (curr_set), SET_SRC (next_set), true)) + return true; + + return riscv_fusion_enabled_p (RISCV_FUSE_ADJACENT_STORE) + && get_attr_type (curr) == TYPE_STORE + && get_attr_type (next) == TYPE_STORE + && riscv_adjacent_memops_p (SET_DEST (curr_set), + SET_DEST (next_set), false); +} + +/* Return true if PREV and CURR constitute an ordered load/store + op/opimm + pair, for the purposes of macro-op fusion. + This is a more general form that combines load+arith and store+arith. */ + +static bool +riscv_ls_update_pair_p (rtx_insn *prev, rtx_insn *curr) +{ + rtx prev_set = single_set (prev); + rtx curr_set = single_set (curr); + if (!prev_set || !curr_set) + return false; + + enum attr_type p_type = get_attr_type (prev); + if (!(p_type == TYPE_LOAD || p_type == TYPE_STORE)) + return false; + + enum attr_type c_type = get_attr_type (curr); + if (!(c_type == TYPE_ARITH + || c_type == TYPE_LOGICAL + || c_type == TYPE_SHIFT + || c_type == TYPE_SLT + || c_type == TYPE_BITMANIP + || c_type == TYPE_MIN + || c_type == TYPE_MAX + || c_type == TYPE_MINU + || c_type == TYPE_MAXU + || c_type == TYPE_CLZ + || c_type == TYPE_CTZ + || c_type == TYPE_MOVE)) + return false; + + rtx c_src = SET_SRC (curr_set); + rtx c_dest = SET_DEST (curr_set); + + if (CONSTANT_P (c_src)) + return false; + + int c_rs1 = INVALID_REGNUM; + int c_rs2 = INVALID_REGNUM; + + if (REG_P (c_src)) + c_rs1 = REGNO (c_src); + else + { + rtx op = c_src; + if (GET_CODE (op) == NOT && BINARY_P (XEXP (op, 0))) + op = XEXP (op, 0); + + const char *fmt = GET_RTX_FORMAT (GET_CODE (op)); + for (int i = 0; i < GET_RTX_LENGTH (GET_CODE (op)); i++) + { + if (fmt[i] != 'e') + continue; + + rtx x = XEXP (op, i); + if (GET_CODE (x) == NOT) + x = XEXP (x, 0); + if (SUBREG_P (x)) + x = SUBREG_REG (x); + if (!REG_P (x)) + continue; + + if (c_rs1 == (int) INVALID_REGNUM) + c_rs1 = REGNO (x); + else + { + c_rs2 = REGNO (x); + break; + } + } + + if (c_rs1 == (int) INVALID_REGNUM) + return false; + } + + switch (p_type) + { + case TYPE_LOAD: + { + if (!REG_P (c_dest)) + return false; + int c_rd = REGNO (c_dest); + + rtx p_mem = SET_SRC (prev_set); + + if (!MEM_P (p_mem)) + return false; + + rtx p_dest = SET_DEST (prev_set); + rtx base, offset; + if (!extract_base_offset_in_addr (p_mem, &base, &offset) + || !REG_P (p_dest)) + return false; + + int p_rs = REGNO (base); + int p_rd = REGNO (p_dest); + + return (p_rs == c_rs1 + && p_rs != p_rd + && p_rd != c_rd + && !reg_overlap_mentioned_p (p_dest, c_src)); + } + + case TYPE_STORE: + { + rtx p_mem = SET_DEST (prev_set); + if (!MEM_P (p_mem)) + return false; + + rtx base, offset; + if (!extract_base_offset_in_addr (p_mem, &base, &offset)) + return false; + + int p_rs = REGNO (base); + + if (p_rs != c_rs1) + return false; + + if (c_rs2 == (int) INVALID_REGNUM) + return true; + + rtx data = SET_SRC (prev_set); + if (!REG_P (data)) + return false; + + int p_rs2 = REGNO (data); + return p_rs2 == c_rs2; + } + + default: + return false; + } +} + /* Check for RISCV_FUSE_ZEXTW and RISCV_FUSE_ZEXTWS fusion. prev (slli) == (set (reg:DI rD) (ashift:DI (reg:DI rS) (const_int 32))) curr (srli) == (set (reg:DI rD) (lshiftrt:DI (reg:DI rD) (const_int N))) @@ -406,26 +656,38 @@ riscv_fuse_auipc_addi (rtx_insn *prev, rtx_insn *curr) return false; } -/* Check for RISCV_FUSE_LUI_LD fusion. - prev (lui) == (set (reg:DI rD) (const_int UPPER_IMM_20)) - curr (ld) == (set (reg:DI rD) (mem:DI (plus:DI (reg:DI rD) ...))) */ +/* Common lui+ld fusion matcher. + SAME_DEST_REGS: if true, require same dest (via same_dest_p); if false, + require different dests via REGNO (same_dest_p is always true before reload). + MATCH_INPUT_REG: if true, load must use the lui dest as base; if false, + any load after a lui is enough (Fused_LD_LUI). */ static bool -riscv_fuse_lui_ld (rtx_insn *prev, rtx_insn *curr) +riscv_fuse_lui_ld_pair_p (rtx_insn *prev, rtx_insn *curr, + bool same_dest_regs, bool match_input_reg) { rtx prev_set = single_set (prev); rtx curr_set = single_set (curr); if (!prev_set || !curr_set || any_condjump_p (curr)) return false; - if (!riscv_fusion_same_dest_p (prev_set, curr_set)) + if (same_dest_regs) + { + if (!riscv_fusion_same_dest_p (prev_set, curr_set)) + return false; + } + else if (!REG_P (SET_DEST (prev_set)) || !REG_P (SET_DEST (curr_set)) + || REGNO (SET_DEST (prev_set)) == REGNO (SET_DEST (curr_set))) return false; - /* A LUI_OPERAND accepts (const_int 0), but we won't emit that as LUI. - Reject that case explicitly. */ + if (!match_input_reg) + return ((GET_CODE (SET_SRC (prev_set)) == HIGH + || (CONST_INT_P (SET_SRC (prev_set)) + && LUI_NONZERO_OPERAND (INTVAL (SET_SRC (prev_set))))) + && get_attr_type (curr) == TYPE_LOAD); + if (CONST_INT_P (SET_SRC (prev_set)) - && SET_SRC (prev_set) != CONST0_RTX (GET_MODE (SET_DEST (prev_set))) - && LUI_OPERAND (INTVAL (SET_SRC (prev_set))) + && LUI_NONZERO_OPERAND (INTVAL (SET_SRC (prev_set))) && MEM_P (SET_SRC (curr_set)) && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set))) && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == PLUS @@ -457,6 +719,18 @@ riscv_fuse_lui_ld (rtx_insn *prev, rtx_insn *curr) return false; } +/* Check for RISCV_FUSE_LUI_LD fusion. + prev (lui) == (set (reg:DI rD) (const_int UPPER_IMM_20)) + curr (ld) == (set (reg:DI rD) (mem:DI (plus:DI (reg:DI rD) ...))) */ + +static bool +riscv_fuse_lui_ld (rtx_insn *prev, rtx_insn *curr) +{ + return riscv_fuse_lui_ld_pair_p (prev, curr, + /* same_dest_regs */ true, + /* match_input_reg */ true); +} + /* Check for RISCV_FUSE_AUIPC_LD fusion. prev (auipc) == (set (reg:DI rD) (unspec:DI UNSPEC_AUIPC)) curr (ld) == (set (reg:DI rD) (mem:DI (plus:DI (reg:DI rD) ...))) */ @@ -597,12 +871,13 @@ riscv_fuse_aligned_std (rtx_insn *prev, rtx_insn *curr) return false; } -/* Check for RISCV_FUSE_BFEXT fusion. - prev (slli) == (set (reg:DI rD) (ashift:DI (reg:DI rS) (const_int))) - curr (srli) == (set (reg:DI rD) (lshiftrt:DI (reg:DI rD) (const_int))) */ +/* Check for RISCV_FUSE_BFEXT_SRLI / RISCV_FUSE_BFEXT_SRAI fusion. + prev (slli) == (set (reg rD) (ashift (reg rS) (const_int))) + curr (srli/srai) == (set (reg rD) + (lshiftrt/ashiftrt (reg rD) (const_int))) */ static bool -riscv_fuse_bfext (rtx_insn *prev, rtx_insn *curr) +riscv_fuse_bfext_shift_p (rtx_insn *prev, rtx_insn *curr, enum rtx_code shift) { rtx prev_set = single_set (prev); rtx curr_set = single_set (curr); @@ -613,10 +888,10 @@ riscv_fuse_bfext (rtx_insn *prev, rtx_insn *curr) return false; if (GET_CODE (SET_SRC (prev_set)) == ASHIFT - && (GET_CODE (SET_SRC (curr_set)) == LSHIFTRT - || GET_CODE (SET_SRC (curr_set)) == ASHIFTRT) + && GET_CODE (SET_SRC (curr_set)) == shift && REG_P (SET_DEST (prev_set)) && REG_P (SET_DEST (curr_set)) + && REG_P (XEXP (SET_SRC (curr_set), 0)) && REGNO (XEXP (SET_SRC (curr_set), 0)) == REGNO (SET_DEST (prev_set)) && CONST_INT_P (XEXP (SET_SRC (prev_set), 1)) && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))) @@ -625,6 +900,26 @@ riscv_fuse_bfext (rtx_insn *prev, rtx_insn *curr) return false; } +/* Check for RISCV_FUSE_BFEXT_SRLI fusion. + prev (slli) == (set (reg rD) (ashift (reg rS) (const_int))) + curr (srli) == (set (reg rD) (lshiftrt (reg rD) (const_int))) */ + +static bool +riscv_fuse_bfext_srli (rtx_insn *prev, rtx_insn *curr) +{ + return riscv_fuse_bfext_shift_p (prev, curr, LSHIFTRT); +} + +/* Check for RISCV_FUSE_BFEXT_SRAI fusion. + prev (slli) == (set (reg rD) (ashift (reg rS) (const_int))) + curr (srai) == (set (reg rD) (ashiftrt (reg rD) (const_int))) */ + +static bool +riscv_fuse_bfext_srai (rtx_insn *prev, rtx_insn *curr) +{ + return riscv_fuse_bfext_shift_p (prev, curr, ASHIFTRT); +} + /* Check for RISCV_FUSE_B_ALUI fusion. Covers orc.b+not, ctz+andi, sub+smax, neg+smax patterns. */ @@ -691,6 +986,239 @@ riscv_fuse_b_alui (rtx_insn *prev, rtx_insn *curr) return false; } +/* Check for RISCV_FUSE_MULT_ADD fusion. + On RV32: + prev (mul) == (set (reg rD) (mult:SI (reg:SI rS1) (reg:SI rS2))) + curr (add) == (set (reg rD) (plus:SI (reg:SI rD) (reg:SI rS3))) + + Matches mulw+addw for RV64, not mul+add: + prev (mul) == (set (reg:DI rD) (sign_extend:DI (mult:SI ...))) + curr (add) == (set (reg:DI rD) (sign_extend:DI (plus:SI ...))) */ + +static bool +riscv_fuse_mult_add (rtx_insn *prev, rtx_insn *curr) +{ + rtx prev_set = single_set (prev); + rtx curr_set = single_set (curr); + if (!prev_set || !curr_set) + return false; + + if (!riscv_fusion_same_dest_p (prev_set, curr_set)) + return false; + + rtx prev_src = SET_SRC (prev_set); + rtx curr_src = SET_SRC (curr_set); + if (GET_CODE (prev_src) == SIGN_EXTEND + && GET_MODE (prev_src) == DImode) + prev_src = XEXP (prev_src, 0); + if (GET_CODE (curr_src) == SIGN_EXTEND + && GET_MODE (curr_src) == DImode) + curr_src = XEXP (curr_src, 0); + + if (GET_CODE (prev_src) != MULT || GET_MODE (prev_src) != SImode + || GET_CODE (curr_src) != PLUS || GET_MODE (curr_src) != SImode) + return false; + + rtx mult_dest = SET_DEST (prev_set); + if (!REG_P (mult_dest)) + return false; + unsigned int mult_dest_regno = REGNO (mult_dest); + + if (REG_P (XEXP (curr_src, 0)) + && REGNO (XEXP (curr_src, 0)) == mult_dest_regno) + return true; + + return false; +} + +/* Check for RISCV_FUSE_LI_BRANCH fusion. + prev (li) == (set (reg:DI rD) (const_int N)) + curr (branch) == conditional branch using rD */ + +static bool +riscv_fuse_li_branch (rtx_insn *prev, rtx_insn *curr) +{ + rtx prev_set = single_set (prev); + rtx curr_set = single_set (curr); + if (!prev_set || !curr_set) + return false; + + if (get_attr_type (prev) != TYPE_MOVE + || get_attr_move_type (prev) != MOVE_TYPE_CONST) + return false; + + if (!any_condjump_p (curr)) + return false; + + rtx prev_dest = SET_DEST (prev_set); + if (!REG_P (prev_dest)) + return false; + + /* Check if the loaded register is used in the branch condition. */ + rtx cond = XEXP (SET_SRC (curr_set), 0); + unsigned int prev_dest_regno = REGNO (prev_dest); + if ((REG_P (XEXP (cond, 0)) && REGNO (XEXP (cond, 0)) == prev_dest_regno) + || (REG_P (XEXP (cond, 1)) && REGNO (XEXP (cond, 1)) == prev_dest_regno)) + return true; + + return false; +} + +/* Check for RISCV_FUSE_ADJACENT_LOAD fusion. + prev (ld) == (set (reg:SI rD1) + (mem:SI (plus:DI (reg:DI rB) (const_int OFF1)))) + curr (ld) == (set (reg:SI rD2) + (mem:SI (plus:DI (reg:DI rB) (const_int OFF2)))) + where OFF2 == OFF1 + 4 or OFF2 == OFF1 - 4 */ + +static bool +riscv_fuse_adjacent_load (rtx_insn *prev, rtx_insn *curr) +{ + /* Do not fuse loads/stores before sched2. */ + if (!reload_completed || sched_fusion) + return false; + + rtx prev_set = single_set (prev); + rtx curr_set = single_set (curr); + if (!prev_set || !curr_set || any_condjump_p (curr)) + return false; + + if (get_attr_type (prev) != TYPE_LOAD + || get_attr_type (curr) != TYPE_LOAD) + return false; + + return riscv_adjacent_memops_p (SET_SRC (prev_set), SET_SRC (curr_set), true); +} + +/* Check for RISCV_FUSE_ADJACENT_STORE fusion. + prev (st) == (set (mem:SI (plus:DI (reg:DI rB) (const_int OFF1))) + (reg:SI rS1)) + curr (st) == (set (mem:SI (plus:DI (reg:DI rB) (const_int OFF2))) + (reg:SI rS2)) + where OFF2 == OFF1 + MODE_SIZE or OFF2 == OFF1 - MODE_SIZE */ + +static bool +riscv_fuse_adjacent_store (rtx_insn *prev, rtx_insn *curr) +{ + /* Do not fuse loads/stores before sched2. */ + if (!reload_completed || sched_fusion) + return false; + + rtx prev_set = single_set (prev); + rtx curr_set = single_set (curr); + if (!prev_set || !curr_set || any_condjump_p (curr)) + return false; + + if (get_attr_type (prev) != TYPE_STORE + || get_attr_type (curr) != TYPE_STORE) + return false; + + return riscv_adjacent_memops_p (SET_DEST (prev_set), + SET_DEST (curr_set), false); +} + +/* Check for RISCV_FUSE_LS_UPDATE fusion (load/store with address update). + prev (ld) == (set (reg:DI rD) (mem:DI (reg:DI rA))) + curr (addi) == (set (reg:DI rA) (plus:DI (reg:DI rA) (const_int))) + OR + prev (addi) == (set (reg:DI rA) (plus:DI (reg:DI rA) (const_int))) + curr (st) == (set (mem:DI (reg:DI rA)) (reg:DI rS)) */ + +static bool +riscv_fuse_ls_update (rtx_insn *prev, rtx_insn *curr) +{ + if (!reload_completed || sched_fusion) + return false; + + rtx prev_set = single_set (prev); + rtx curr_set = single_set (curr); + if (!prev_set || !curr_set || any_condjump_p (curr)) + return false; + + if (riscv_defer_for_adjacent_memop_p (curr)) + return false; + + return (riscv_ls_update_pair_p (prev, curr) + || riscv_ls_update_pair_p (curr, prev)); +} + +static bool +riscv_lui_st_pair_p (rtx_insn *lui, rtx_insn *store, rtx lui_set) +{ + return (get_attr_type (store) == TYPE_STORE + && REG_P (SET_DEST (lui_set)) + && ((get_attr_type (lui) == TYPE_MOVE + && GET_CODE (SET_SRC (lui_set)) == HIGH) + || (CONST_INT_P (SET_SRC (lui_set)) + && LUI_NONZERO_OPERAND (INTVAL (SET_SRC (lui_set)))))); +} + +/* Check for RISCV_FUSE_LUI_ST fusion. + prev (lui) == (set (reg:DI rD) (const_int UPPER_IMM_20)) + curr (st) == (set (mem:DI (plus:DI (reg:DI rX) (const_int))) (reg:DI rS)) + OR (reversed) + prev (st) == (set (mem:DI (plus:DI (reg:DI rX) (const_int))) (reg:DI rS)) + curr (lui) == (set (reg:DI rD) (const_int UPPER_IMM_20)) */ + +static bool +riscv_fuse_lui_st (rtx_insn *prev, rtx_insn *curr) +{ + if (!reload_completed || sched_fusion) + return false; + + rtx prev_set = single_set (prev); + rtx curr_set = single_set (curr); + if (!prev_set || !curr_set || any_condjump_p (curr)) + return false; + + if (riscv_defer_for_adjacent_memop_p (curr)) + return false; + + return (riscv_lui_st_pair_p (prev, curr, prev_set) + || riscv_lui_st_pair_p (curr, prev, curr_set)); +} + +/* Check for RISCV_FUSE_LI_STORE fusion. + prev (li) == (set (reg:DI rT) (const_int IMM)) + curr (st) == (set (mem:DI (plus:DI (reg:DI rB) (const_int))) (reg:DI rT)) */ + +static bool +riscv_fuse_li_store (rtx_insn *prev, rtx_insn *curr) +{ + if (!reload_completed || sched_fusion) + return false; + + rtx prev_set = single_set (prev); + rtx curr_set = single_set (curr); + if (!prev_set || !curr_set || any_condjump_p (curr)) + return false; + + if (riscv_defer_for_adjacent_memop_p (curr)) + return false; + + if (get_attr_type (prev) == TYPE_MOVE + && get_attr_move_type (prev) == MOVE_TYPE_CONST + && get_attr_type (curr) == TYPE_STORE + && REG_P (SET_SRC (curr_set)) && REG_P (SET_DEST (prev_set)) + && REGNO (SET_SRC (curr_set)) == REGNO (SET_DEST (prev_set))) + return true; + + return false; +} + +/* Check for RISCV_FUSE_LUI_LD_REV fusion (reversible). */ + +static bool +riscv_fuse_lui_ld_reversible (rtx_insn *prev, rtx_insn *curr) +{ + return (riscv_fuse_lui_ld_pair_p (prev, curr, + /* same_dest_regs */ false, + /* match_input_reg */ false) + || riscv_fuse_lui_ld_pair_p (curr, prev, + /* same_dest_regs */ false, + /* match_input_reg */ false)); +} + /* Type for a fusion checker function. Takes the two candidate insns and returns true if they should be fused. */ @@ -737,10 +1265,28 @@ static const struct riscv_fusion_entry riscv_fusion_table[] = riscv_fuse_cache_aligned_std, "RISCV_FUSE_CACHE_ALIGNED_STD" }, { RISCV_FUSE_ALIGNED_STD, riscv_fuse_aligned_std, "RISCV_FUSE_ALIGNED_STD" }, - { RISCV_FUSE_BFEXT, - riscv_fuse_bfext, "RISCV_FUSE_BFEXT" }, + { RISCV_FUSE_BFEXT_SRLI, + riscv_fuse_bfext_srli, "RISCV_FUSE_BFEXT_SRLI" }, + { RISCV_FUSE_BFEXT_SRAI, + riscv_fuse_bfext_srai, "RISCV_FUSE_BFEXT_SRAI" }, { RISCV_FUSE_B_ALUI, riscv_fuse_b_alui, "RISCV_FUSE_B_ALUI" }, + { RISCV_FUSE_MULT_ADD, + riscv_fuse_mult_add, "RISCV_FUSE_MULT_ADD" }, + { RISCV_FUSE_LI_BRANCH, + riscv_fuse_li_branch, "RISCV_FUSE_LI_BRANCH" }, + { RISCV_FUSE_ADJACENT_LOAD, + riscv_fuse_adjacent_load, "RISCV_FUSE_ADJACENT_LOAD" }, + { RISCV_FUSE_ADJACENT_STORE, + riscv_fuse_adjacent_store, "RISCV_FUSE_ADJACENT_STORE" }, + { RISCV_FUSE_LS_UPDATE, + riscv_fuse_ls_update, "RISCV_FUSE_LS_UPDATE" }, + { RISCV_FUSE_LUI_ST, + riscv_fuse_lui_st, "RISCV_FUSE_LUI_ST" }, + { RISCV_FUSE_LI_STORE, + riscv_fuse_li_store, "RISCV_FUSE_LI_STORE" }, + { RISCV_FUSE_LUI_LD_REV, + riscv_fuse_lui_ld_reversible, "RISCV_FUSE_LUI_LD_REV" }, }; /* Implement TARGET_SCHED_MACRO_FUSION_PAIR_P. Return true if PREV and CURR diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 3843110ab6c..a94c37fa052 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -864,13 +864,23 @@ enum riscv_fusion_pairs RISCV_FUSE_LDPREINCREMENT = (1 << 8), RISCV_FUSE_ALIGNED_STD = (1 << 9), RISCV_FUSE_CACHE_ALIGNED_STD = (1 << 10), - RISCV_FUSE_BFEXT = (1 << 11), + RISCV_FUSE_BFEXT_SRLI = (1 << 11), RISCV_FUSE_EXPANDED_LD = (1 << 12), RISCV_FUSE_B_ALUI = (1 << 13), + RISCV_FUSE_MULT_ADD = (1 << 14), + RISCV_FUSE_LI_BRANCH = (1 << 15), + RISCV_FUSE_ADJACENT_LOAD = (1 << 16), + RISCV_FUSE_ADJACENT_STORE = (1 << 17), + RISCV_FUSE_LS_UPDATE = (1 << 18), + RISCV_FUSE_LUI_ST = (1 << 19), + RISCV_FUSE_LI_STORE = (1 << 20), + RISCV_FUSE_LUI_LD_REV = (1 << 21), + RISCV_FUSE_BFEXT_SRAI = (1 << 22), }; extern bool riscv_macro_fusion_p (void); extern bool riscv_macro_fusion_pair_p (rtx_insn *, rtx_insn *); +extern bool riscv_fusion_enabled_p (enum riscv_fusion_pairs); extern unsigned int riscv_get_fusible_ops (void); /* Routines implemented in thead.cc. */ diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index e319ccaecad..aabd12aa040 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -980,7 +980,11 @@ static const struct riscv_tune_param arcv_rhx100_tune_info = { false, /* overlap_op_by_pieces */ true, /* use_zero_stride_load */ false, /* speculative_sched_vsetvl */ - RISCV_FUSE_NOTHING, /* fusible_ops */ + (RISCV_FUSE_MULT_ADD | RISCV_FUSE_LI_BRANCH + | RISCV_FUSE_ADJACENT_LOAD | RISCV_FUSE_ADJACENT_STORE + | RISCV_FUSE_LS_UPDATE | RISCV_FUSE_LUI_ST + | RISCV_FUSE_LI_STORE | RISCV_FUSE_BFEXT_SRLI + | RISCV_FUSE_LUI_LD_REV), /* fusible_ops */ NULL, /* vector cost */ NULL, /* function_align */ NULL, /* jump_align */ diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index 4ba6ad260e5..b01301659e1 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -978,6 +978,10 @@ extern enum riscv_cc get_riscv_cc (const rtx use); || (riscv_microarchitecture == sifive_p600) \ || (riscv_microarchitecture == andes_45_series)) +/* True if the target is ARC-V RHX100. */ +#define TARGET_ARCV_RHX100 \ + (riscv_microarchitecture == arcv_rhx100) + /* True if the target supports misaligned vector loads and stores. */ #define TARGET_VECTOR_MISALIGN_SUPPORTED \ riscv_vector_unaligned_access_p diff --git a/gcc/testsuite/gcc.target/riscv/fusion-adjacent-load.c b/gcc/testsuite/gcc.target/riscv/fusion-adjacent-load.c new file mode 100644 index 00000000000..8dc2ec4b1b0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-adjacent-load.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target rv32 } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv32im -mabi=ilp32 -fdump-rtl-sched2" } */ + +int +fuse_adjacent_load (int *p) +{ + return p[0] + p[1]; +} + +/* { dg-final { scan-rtl-dump "RISCV_FUSE_ADJACENT_LOAD" "sched2" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-adjacent-store.c b/gcc/testsuite/gcc.target/riscv/fusion-adjacent-store.c new file mode 100644 index 00000000000..cf86ab271ae --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-adjacent-store.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target rv32 } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv32im -mabi=ilp32 -fdump-rtl-sched2" } */ + +void +fuse_adjacent_store (int *p, int x, int y) +{ + p[0] = x; + p[1] = y; +} + +/* { dg-final { scan-rtl-dump "RISCV_FUSE_ADJACENT_STORE" "sched2" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-bfext-srai.c b/gcc/testsuite/gcc.target/riscv/fusion-bfext-srai.c new file mode 100644 index 00000000000..df42e965926 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-bfext-srai.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target rv32 } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv32im -mabi=ilp32 -fdump-rtl-sched2" } */ + +/* RHX Fused_XBFU is slli+srli only; slli+srai must not fuse. */ + +int +fusion_shift_bitextract_srai (int x, int y, int z) +{ + int t = x << 8; + int a = y + z; + t = t >> 4; + return t + a; +} + +/* { dg-final { scan-rtl-dump-not "RISCV_FUSE_BFEXT_SRAI" "sched2" } } */ +/* { dg-final { scan-rtl-dump-not "RISCV_FUSE_BFEXT_SRLI" "sched2" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-bfext.c b/gcc/testsuite/gcc.target/riscv/fusion-bfext.c new file mode 100644 index 00000000000..48f006c46eb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-bfext.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target rv32 } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv32im -mabi=ilp32 -fdump-rtl-sched2" } */ + +unsigned int +fusion_shift_bitextract (unsigned int x, unsigned int y, unsigned int z) +{ + unsigned int t = x << 8; + unsigned int a = y + z; + t = t >> 4; + return t + a; +} + +/* { dg-final { scan-rtl-dump "RISCV_FUSE_BFEXT_SRLI" "sched2" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-li-branch.c b/gcc/testsuite/gcc.target/riscv/fusion-li-branch.c new file mode 100644 index 00000000000..793282395bc --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-li-branch.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target rv32 } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv32im -mabi=ilp32 -fdump-rtl-sched2" } */ + +int +fuse_li_branch (int x) +{ + while (x <= 3) + ; + return x; +} + +/* { dg-final { scan-rtl-dump "RISCV_FUSE_LI_BRANCH" "sched2" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-li-store.c b/gcc/testsuite/gcc.target/riscv/fusion-li-store.c new file mode 100644 index 00000000000..ea69cc5f5b5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-li-store.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target rv32 } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv32im -mabi=ilp32 -fdump-rtl-sched2" } */ + +void +fuse_li_store (int *p) +{ + *p = 42; +} + +/* { dg-final { scan-rtl-dump "RISCV_FUSE_LI_STORE" "sched2" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-ls-update-2.c b/gcc/testsuite/gcc.target/riscv/fusion-ls-update-2.c new file mode 100644 index 00000000000..5e4ba9bac21 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-ls-update-2.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target rv32 } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv32im -mabi=ilp32 -fdump-rtl-sched2" } */ + +void +fuse_ls_update_rev (int *p, int n, int val) +{ + for (int i = 0; i < n; i++) + { + p++; + *p = val; + } +} + +/* XFAIL until scheduling support for RHX-100 series is implemented. */ +/* { dg-final { scan-rtl-dump "RISCV_FUSE_LS_UPDATE)" "sched2" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-ls-update-3.c b/gcc/testsuite/gcc.target/riscv/fusion-ls-update-3.c new file mode 100644 index 00000000000..9731dedc4f3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-ls-update-3.c @@ -0,0 +1,81 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv32im_zbb -mabi=ilp32 -fdump-rtl-sched2" { target rv32 } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv64im_zbb -mabi=lp64 -fdump-rtl-sched2" { target rv64 } } */ + +#if __SIZEOF_LONG__ == 8 +# define BSWAPL __builtin_bswap64 +#else +# define BSWAPL __builtin_bswap32 +#endif + +#define ST(NAME, EXPR) \ + unsigned long NAME (long *p, long val) \ + { \ + *p = val; \ + return (EXPR); \ + } + +ST (st_addi, ((unsigned long) p + 8)) /* arith */ +ST (st_andi, ((unsigned long) p & 0xff)) /* logical */ +ST (st_ori, ((unsigned long) p | 0xff)) /* logical */ +ST (st_xori, ((unsigned long) p ^ 0xff)) /* logical */ +ST (st_slli, ((unsigned long) p << 3)) /* shift */ +ST (st_srli, ((unsigned long) p >> 3)) /* shift */ +ST (st_srai, ((unsigned long) ((long) p >> 3))) /* shift */ +ST (st_slti, ((unsigned long) ((long) p < 99))) /* slt */ +ST (st_sltiu, ((unsigned long) ((unsigned long) p < 99u))) /* slt */ +ST (st_clz, (__builtin_clzl ((unsigned long) p))) /* clz */ +ST (st_ctz, (__builtin_ctzl ((unsigned long) p))) /* ctz */ +ST (st_rev8, (BSWAPL ((unsigned long) p))) /* bitmanip */ + +#define LD(NAME, EXPR) \ + long NAME (long *p, unsigned long x, long *sink) \ + { \ + long v = *p; \ + unsigned long q = (EXPR); \ + *sink = v; \ + return (long) q; \ + } + +LD (ld_add, ((unsigned long) p + x)) /* arith */ +LD (ld_sub, ((unsigned long) p - x)) /* arith */ +LD (ld_and, ((unsigned long) p & x)) /* logical */ +LD (ld_or, ((unsigned long) p | x)) /* logical */ +LD (ld_xor, ((unsigned long) p ^ x)) /* logical */ +LD (ld_sll, ((unsigned long) p << (x & 31))) /* shift */ +LD (ld_srl, ((unsigned long) p >> (x & 31))) /* shift */ +LD (ld_sra, ((unsigned long) ((long) p >> (x & 31)))) /* shift */ +LD (ld_slt, ((unsigned long) ((long) p < (long) x))) /* slt */ +LD (ld_sltu, ((unsigned long) ((unsigned long) p < x))) /* slt */ +LD (ld_min, ((unsigned long) ((long) p < (long) x ? (long) p : (long) x))) /* min */ +LD (ld_max, ((unsigned long) ((long) p > (long) x ? (long) p : (long) x))) /* max */ +LD (ld_minu, ((unsigned long) p < x ? (unsigned long) p : x)) /* minu */ +LD (ld_maxu, ((unsigned long) p > x ? (unsigned long) p : x)) /* maxu */ + +/* { dg-final { scan-assembler {\madd\M} } } */ +/* { dg-final { scan-assembler {\maddi\M} } } */ +/* { dg-final { scan-assembler {\msub\M} } } */ +/* { dg-final { scan-assembler {\mand\M} } } */ +/* { dg-final { scan-assembler {\mandi\M} } } */ +/* { dg-final { scan-assembler {\mor\M} } } */ +/* { dg-final { scan-assembler {\mori\M} } } */ +/* { dg-final { scan-assembler {\mxor\M} } } */ +/* { dg-final { scan-assembler {\mxori\M} } } */ +/* { dg-final { scan-assembler {\msll\M} } } */ +/* { dg-final { scan-assembler {\mslli\M} } } */ +/* { dg-final { scan-assembler {\msrl\M} } } */ +/* { dg-final { scan-assembler {\msrli\M} } } */ +/* { dg-final { scan-assembler {\msra\M} } } */ +/* { dg-final { scan-assembler {\msrai\M} } } */ +/* { dg-final { scan-assembler {\mslt\M} } } */ +/* { dg-final { scan-assembler {\mslti\M} } } */ +/* { dg-final { scan-assembler {\msltu\M} } } */ +/* { dg-final { scan-assembler {\msltiu\M} } } */ +/* { dg-final { scan-assembler {\mmin\M} } } */ +/* { dg-final { scan-assembler {\mmax\M} } } */ +/* { dg-final { scan-assembler {\mminu\M} } } */ +/* { dg-final { scan-assembler {\mmaxu\M} } } */ +/* { dg-final { scan-assembler {\mclz\M} } } */ +/* { dg-final { scan-assembler {\mctz\M} } } */ +/* { dg-final { scan-assembler {\mrev8\M} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-ls-update-4.c b/gcc/testsuite/gcc.target/riscv/fusion-ls-update-4.c new file mode 100644 index 00000000000..49aef023dff --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-ls-update-4.c @@ -0,0 +1,53 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv32im_zbb -mabi=ilp32 -fdump-rtl-sched2" { target rv32 } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv64im_zbb -mabi=lp64 -fdump-rtl-sched2" { target rv64 } } */ + +long +ld_xnor (long *p, unsigned long x, long *sink) +{ + long v = *p; + unsigned long q = ~((unsigned long) p ^ x); + *sink = v; + return (long) q; +} + +long +ld_off (long *p, unsigned long x, long *sink) +{ + long v = p[1]; + unsigned long q = (unsigned long) p + x; + *sink = v; + return (long) q; +} + +unsigned long +st_off (long *p, long val) +{ + p[1] = val; + return (unsigned long) p + 8; +} + +unsigned long +st_op_add (long *p, long d) +{ + *p = d; + return (unsigned long) p + (unsigned long) d; +} + +unsigned long +st_op_sub (long *p, long d) +{ + *p = d; + return (unsigned long) p - (unsigned long) d; +} + +/* Must not fuse. */ +unsigned long +st_op_unrel (long *p, long d, unsigned long x) +{ + *p = d; + return (unsigned long) p + x; +} + +/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_LS_UPDATE" 5 "sched2" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-ls-update-5.c b/gcc/testsuite/gcc.target/riscv/fusion-ls-update-5.c new file mode 100644 index 00000000000..c0d64d77d67 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-ls-update-5.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv32im -mabi=ilp32 -fdump-rtl-sched2" { target { rv32 } } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv64im -mabi=lp64 -fdump-rtl-sched2" { target { rv64 } } } */ + +int * +fuse_ls_update_move (int *p, int *q, int x) +{ + *q = x; + return q; +} + +/* { dg-final { scan-rtl-dump "RISCV_FUSE_LS_UPDATE" "sched2" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-ls-update.c b/gcc/testsuite/gcc.target/riscv/fusion-ls-update.c new file mode 100644 index 00000000000..b71eab0fcd9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-ls-update.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target rv32 } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv32im -mabi=ilp32 -fdump-rtl-sched2" } */ + +int +fuse_ls_update (int *p, int n) +{ + int sum = 0; + for (int i = 0; i < n; i++) + sum += *p++; + return sum; +} + +/* XFAIL until scheduling support for RHX-100 series is implemented. */ +/* { dg-final { scan-rtl-dump "RISCV_FUSE_LS_UPDATE" "sched2" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-lui-ld.c b/gcc/testsuite/gcc.target/riscv/fusion-lui-ld.c new file mode 100644 index 00000000000..58dbe4393a1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-lui-ld.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target rv32 } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv32im -mabi=ilp32 -fdump-rtl-sched2" } */ + +extern int g1, g2; +extern volatile int g3, g4; + +int +fuse_lui_ld (void) +{ + return g1 + g2; +} + +int +fuse_lui_ld_rev (volatile int *p, int val) +{ + int a = *p; + int b = g3; + int c = p[1]; + int d = g4; + return a + b + c + d + val; +} + +/* { dg-final { scan-rtl-dump "RISCV_FUSE_LUI_LD_REV" "sched2" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-lui-st.c b/gcc/testsuite/gcc.target/riscv/fusion-lui-st.c new file mode 100644 index 00000000000..54c38d7fa33 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-lui-st.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target rv32 } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv32im -mabi=ilp32 -fdump-rtl-sched2" } */ + +volatile int g1, g2, g3; + +void +fuse_store_lui (volatile int *p, int val) +{ + *p = val; + g1 = val; + p[1] = val; + g2 = val; + p[2] = val; + g3 = val; +} + +/* { dg-final { scan-rtl-dump "RISCV_FUSE_LUI_ST" "sched2" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-mult-add.c b/gcc/testsuite/gcc.target/riscv/fusion-mult-add.c new file mode 100644 index 00000000000..d182a65aa46 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-mult-add.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv32im -mabi=ilp32 -fdump-rtl-sched2" { target { rv32 } } } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series -march=rv64im -mabi=lp64 -fdump-rtl-sched2" { target { rv64 } } } */ + +int +fuse_mult_add_op0 (int a, int b, int c) +{ + int m = a * b; + return m + c; +} + +/* { dg-final { scan-rtl-dump "RISCV_FUSE_MULT_ADD" "sched2" } } */ From patchwork Wed Aug 5 10:02:10 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Silva X-Patchwork-Id: 140641 X-Patchwork-Delegate: jlaw@ventanamicro.com Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 02D384BA2E1F for ; Wed, 5 Aug 2026 10:07:06 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 02D384BA2E1F Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=outlook.com header.i=@outlook.com header.a=rsa-sha256 header.s=selector1 header.b=plyiPqcU X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from LO2P265CU024.outbound.protection.outlook.com (mail-uksouthazolkn19011072.outbound.protection.outlook.com [52.103.37.72]) by sourceware.org (Postfix) with ESMTPS id 0C04A4BAE7CD for ; Wed, 5 Aug 2026 10:02:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0C04A4BAE7CD Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=outlook.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=outlook.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 0C04A4BAE7CD Authentication-Results: sourceware.org; arc=pass smtp.remote-ip=52.103.37.72 ARC-Seal: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1785924169; cv=pass; b=jgEoh4QpP35InRYQyLkVCVTS2767SRetCNDTJRwxw51qdYmQNpieT4O7SLeToHRXqjjhpWHvewoPcMxsIhA4Q8dtri9ThDXejAJvMiySxQZzdlw4BbDEzek46xQKeY8ilqgdZoxdYG/iNf971o8IrQINvLfvulL88+Rx3ta+ug4= ARC-Message-Signature: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1785924169; c=relaxed/simple; bh=zyeGXffkdC/8XvxFfktLShVvn1AaFIWtd17n7XB+dZc=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=EgWR5ePXQlG78bdFn978/kxz22CRiVPV2YrEGpT+yOQUWrjIFRIj7A1VbHIMxUQfrDuCOdYq4A5U2yH9sfTvYg9PbobVbWMYQAorkC8C/1RPl607Z/ZEzLybkcoC5oKjFQAl/XZPqkbC+tF3Ehm+YqE2jKI1J1miQvGHbWp3kTU= ARC-Authentication-Results: i=2; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=outlook.com header.i=@outlook.com header.a=rsa-sha256 header.s=selector1 header.b=plyiPqcU DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0C04A4BAE7CD ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=jCrObVKpus2WrvWEZqMtAUWMocMx9FvsstDS5qMbWlHf4PF4/2+XTuf6LqK5JBNCcdswDDw6HFeTCBRybO5x4wO7y54aDNe2Iush6njRc0gwittQRFIw1LU7k/ISZBw/T4JtbDGY/pWKG2ghWP+cGQKUreygs6AUiwo6NS3ENeMXaUFZe0xhwf10BHp2Zhvp+l3ucg31mcUX9h5NYVskhZjzI6GuLaLKz+NWE97SL1JoaO4r4flxOlmYkN673eiPcv/zim7PxDhExJJyRUMAwN7Vx5shFBYrBjc3paZinBfYgn0Ox49Im71PyDge7Ch4t2Tij3oTEHpBaFNutoY9uA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=atZCrlLiuntxCU4Qq3WJXVaU93PvEIU3op1P3exYgr8=; b=GdpQkY7jITK6bqKuG8CEi9jKu9aKiuVxMwPsZffhtBQGDXQODCb/SqDfN4fdq5KoL2uRkJd9Avj56xOgwCP20NgRqUxogVJkcz2IBtytPbPprbBc+Obtlq149ObFkrXcwCgKQj0asAKo3O4sL/btL7YoUllC2+iy5/wfsMhpFhf101HoN4NFGFz/8k6gRDeyFKA1qAygbf3RvCRLimRt0nxp2FIHAaoqqBhowk/p7ShBbcv6DUVIuay5Av4T/cwUvqAPtbgEAu0aW+xJlS9uWLfCkbNXYGT+1oOzfmMEKl/c4GsKHBCd71ktM+WWx8c3BZQPo9IuUlp5Lj9VuD+OSw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=outlook.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=atZCrlLiuntxCU4Qq3WJXVaU93PvEIU3op1P3exYgr8=; b=plyiPqcUtkV8FVYrgWIIXvpzK3iM5rT+MCMCSU6H95IpP4AGezdY9bBQu0bfZDfZadM9JJrgd73D3PYlkwrTlIw13GQASGVZ+V31nZJ3WyirT4rb8kbAQX0WxZFsyApvxCHnSn370mV5c3xlhyXv06CZ00JvVT2di+DimvPSTaQJA172TyfF4lsnOhALRWQLp+LKTcbxJRYJwrO9imA6ThPEDwpbxZx7cqtpFBeyhSaQcIqpQvhC8ujR4AhnLliPNzpnbRiVkH+MkMzfDQ2l4Yw3n6oT6VQLF+5crJZhdZQDIMA5Xwd88WXKd+okNmnNvOKjN/hKhK8VaXcQ6DbeTw== Received: from LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2b1::6) by CWLP265MB5868.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:1b0::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.270.19; Wed, 5 Aug 2026 10:02:39 +0000 Received: from LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM ([fe80::839:df74:7f0e:b82a]) by LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM ([fe80::839:df74:7f0e:b82a%2]) with mapi id 15.21.0292.015; Wed, 5 Aug 2026 10:02:39 +0000 From: Luis Silva To: gcc-patches@gcc.gnu.org Cc: Jeff Law , Kito Cheng , Palmer Dabbelt , Robin Dapp , Luis Silva , Artemiy Volkov , Michiel Derhaeg , Loeka Rogge , Alex Turjan , Luis Silva Subject: [PATCH v2 2/4] RISC-V: Implement TARGET_SCHED_FUSION_PRIORITY for ARC-V RHX-100 series Date: Wed, 5 Aug 2026 11:02:10 +0100 Message-ID: X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260805100212.10852-1-luismgsilva@outlook.com> References: <20260805100212.10852-1-luismgsilva@outlook.com> X-ClientProxiedBy: MA4P292CA0012.ESPP292.PROD.OUTLOOK.COM (2603:10a6:250:2d::9) To LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2b1::6) X-Microsoft-Original-Message-ID: <20260805100212.10852-3-luismgsilva@outlook.com> MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: LO6P265MB6224:EE_|CWLP265MB5868:EE_ X-MS-Office365-Filtering-Correlation-Id: d5dacc50-78b3-454c-d96e-08def2d8ad02 X-Microsoft-Antispam: BCL:0; ARA:14566002|7072599006|41001999006|5072599009|4140399003|19110799012|8060799015|25010399006|15080799012|23021999003|12121999013|19101099003|12091999003|440099028|3412199025|2607281247196008|10035399007|52005399003|40105399003|1710799026; X-Microsoft-Antispam-Message-Info: f2TIf8thmuEJla594u1Me2rAfIx9AqYTOg6z051PBQ4GaIau1ZQXyGksXe3kvN8Mow9RhCPFoLzwVSyOdTm1zzIxYJoMti0eozXcaDXnamepIU6D+mkZbwC/nYBCDHrvPBe9AW9PQCKn59wI1HMQhVewZx/DJ3w0yFps2B7NAIxWMWphc5ET4J4xqX/qnU4avXBoqaTf2OsSXjXV8kmRd7sWYCO60vjp7L7cfP42nz5YEA6dyJMekLAo764cztYhmMZDvTas7xObnPZdn4AHIM85eE8piGz+Ye2wImeQyOb9wx9qpdZ6SmTb+C3da9JuDyylAw2W2a372GZIY3QrvRwZtCsH0v3jqUqTg2ScadlmUwmk4rh4NbF4MrIHimMCfT7DsZW62kj0a+3MEVl6xJ9hai8bgi3pqiOHsObd2x3kcDg2EwRjrB57Zm8wCO0DKdxqKV8FD+7Xzw80qbCm2207guNDHmkrkWRAQdtnatYU3mjmBbL/0KJp2NzvEMFi7Cu0S1bwg0s0tntddeg7/w1cGSo1+CgkALGa/dXKv/9g9weUwORRp5VIrqgghVZfqIPPlJWhLCF0mzrbfBeKWkguS/UHt1eNjMk2RUamO45hGQsj0aUQGIN17sNCmUfchz9B2jGROqc8BuXBEoh52Ez7nZtD0HcZ/JjWfBRmv0mbbzJV3jccbfAiabkM2j8TS2OgAsxRjvgXxCam26LgvQVam2kceDXommLW3fJzfZfmsydeEhJWbn9Ae5rMjHhZIh52LdZ35PR9RIpV6kf9JMuv3k0ka49+wialr05exsLqJkbfzgNfbirEHdf0X9Z4icY5qshpdcZ02zRpukFsqhS86SGgxEztYhJOJRD2sXtRizHNT/xxxRFtQKIbx8bZgQr5ywHTU3A03Z5pt4K0UzJlobbzwNpIEYmlss31NvoavubGDzaLX2eLsW/p86s8Wkprdo+XOLgU+dfQkoM1+ofCSAvUcyMDFwBiA4dQWeZhxGkL7Y7oVrc6SdGW1wpiLEai0fkWLpah4gdmvF2bYbRNPi2pPpy4oZH6BwP6kwd4bXq4d570TMAQTuszqtOO+4isYzOGhmgTKLJN1BuRsRy2yD+gmZcD4WSaBvRnroELA2c6Pal8VgYiExW0T+K9 X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: U+9UbqBOH0/rNKQmV67uadhDfpjcK1au0oC7CHFC4NqG5NgWXfnM32NyKugoyiadNzw1eqvvdn3LIV5p2OtG1BnYXsc6SfYzGIaU9MQ7e6iTQajXiWPT8ljuNrZwY2+WGdsA7NpzFPquVpyDLVNrDkXaJDzROdK5GLSSWRoDQQKW3HruLDthxQmalT+4s38pW1zU07HbOmewAwZub6+/u3JbgBETUYtytzBFfr0CjzeT3m3jREGbwb8D77Xr4XtQH1SO8b3oP8/H1ft16VHa901nz07qDOM/K+cBbY6OAjUpt9lfGUnMDzfuTgk7AeXRmJclo55WlNX//xJF9oIGJYLU4yW4K6VJ2fkVkmGjs7hPFX7yK4to2ctBLIXDvQUJr3C4QvIrryYvTOw7rXqWZmwyEl8rER+Hia+35rCQ/8K6KrpGbCUowEkC119mqqtYI6BDnpNKRTRq1T1YT+3F1OJ/Z7vw0kF5cK14+shwVlVv4OSUsyVKwfxTB0nFoLhz8mrWkiT4nnYMjLkAKAiozE9EBPlgJ6xNUCshh14MPcEP16vqpnP3JWhdNbjVLuTZSxIuYFgx8izs2kpekBoRksk+OCwzImzn0kKoznIDTk96G/AdTIme6Vm4cXemrgURg5tztNW+EzbNQcdio9KokZT43ZtdjfazHkzkcJPrF9U9CnRqOKXxAn3VGT4DYrSNOjMg6EvnR1DkORgJu55IiWsuBHda9q1tAMogXjm7TI22OSqGsufGPuLF+xj7iBB8SgyhDPgkj5D49wQn49DjqFzP1GtxIgOQcPv3NkJH0HJXHVH1n17ZAMlspOnz0mjQnDqnGAV0HJS9B26qxonFVPp4WJVnWlqaayzn2/ikNZD6dwSVYqte4giLDTPxP/Sgk0dkpJ69XNnpeOWEUdNTclMFBUvRUI/uuwz2FF39+Uo4BiBUzm+u4iZd8ingPRJ/Tb+65SAZb3gxlG8BJCnX1k7pbDGVRM/QwWnQF6Y2Nqc3b43BKLYX6BoucSv7DLIzeAp+rbyCrDjVp7JLUmwMuE5qqOzJxQc7BoIdaFZJCYO5Ka5gsbSVKLbtf6KM9+FX0mfSMDs+bIFeMaxgEb/3qR0PT+MRBvCNomRGbU6M+ZIZP2QEhzhcSNOJumfdHZlk1wJTJR8UB5p7k+0pBuqTkRwKYCHpXydVZgBmF8QSuBP8nEMll5axC0OrpEOteV+X+QqOpq1Ap078eIx9x48cBw77j2XFbT12gclNlFGfgc6bXfAngYaUTrJmlhUNzDEEmcmY4gXPc3I2mzgpVgwdeHEZYOO2jUxdZpi8Ah11DxrmDUpY6eZNlPjI5t5SnjpAVMjSmRkzU7jLc0o6urPEk2X3yu/cVG2cS+9mF03mBGrxEJ+OCot62bzR3SXo82dWvy2cpLyiA3H3j4s3vra+EA== X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: d5dacc50-78b3-454c-d96e-08def2d8ad02 X-MS-Exchange-CrossTenant-AuthSource: LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 05 Aug 2026 10:02:37.0767 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: CWLP265MB5868 X-Spam-Status: No, score=-10.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_PASS, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 From: Luis Silva To take better advantage of double load/store fusion, make use of the sched_fusion pass that assigns unique "fusion priorities" to load/store instructions and schedules operations on adjacent addresses together. This maximizes the probability that loads/stores are fused with each other rather than with other instructions. The ARC-V specific helpers live in a new arcv.cc; the generic wrapper riscv_sched_fusion_priority in riscv-fusion.cc dispatches to it and falls back to a default priority for other tunes. gcc/ChangeLog: * config.gcc: Build arcv.o. * config/riscv/riscv-fusion.cc (riscv_sched_fusion_priority): New. (riscv_adjacent_memops_p): Call arcv_pair_fusion_mode_allowed_p. * config/riscv/riscv-protos.h (riscv_sched_fusion_priority): Declare. (arcv_pair_fusion_mode_allowed_p): Declare. (arcv_sched_fusion_priority): Declare. * config/riscv/riscv.cc (TARGET_SCHED_FUSION_PRIORITY): Define. * config/riscv/t-riscv: Build arcv.o. * config/riscv/arcv.cc: New file. Co-authored-by: Artemiy Volkov Co-authored-by: Michiel Derhaeg Signed-off-by: Luis Silva --- gcc/config.gcc | 2 +- gcc/config/riscv/arcv.cc | 162 +++++++++++++++++++++++++++++++ gcc/config/riscv/riscv-fusion.cc | 31 +++--- gcc/config/riscv/riscv-protos.h | 5 + gcc/config/riscv/riscv.cc | 3 + gcc/config/riscv/t-riscv | 6 ++ 6 files changed, 193 insertions(+), 16 deletions(-) create mode 100644 gcc/config/riscv/arcv.cc diff --git a/gcc/config.gcc b/gcc/config.gcc index 0477bf22c8a..89e2ba3cee7 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -574,7 +574,7 @@ riscv*) extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-string.o" extra_objs="${extra_objs} riscv-v.o riscv-vsetvl.o riscv-vector-costs.o riscv-avlprop.o riscv-vect-permconst.o" extra_objs="${extra_objs} riscv-vector-builtins.o riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o sifive-vector-builtins-bases.o andes-vector-builtins-bases.o" - extra_objs="${extra_objs} thead.o riscv-target-attr.o riscv-zicfilp.o riscv-bclr-lowest-set-bit.o riscv-opt-popretz.o riscv-fusion.o" + extra_objs="${extra_objs} thead.o riscv-target-attr.o riscv-zicfilp.o riscv-bclr-lowest-set-bit.o riscv-opt-popretz.o riscv-fusion.o arcv.o" d_target_objs="riscv-d.o" extra_headers="riscv_vector.h riscv_crypto.h riscv_bitmanip.h riscv_th_vector.h sifive_vector.h andes_vector.h" target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins.cc" diff --git a/gcc/config/riscv/arcv.cc b/gcc/config/riscv/arcv.cc new file mode 100644 index 00000000000..e29712ca2be --- /dev/null +++ b/gcc/config/riscv/arcv.cc @@ -0,0 +1,162 @@ +/* Subroutines used for code generation for ARC-V processors. + Copyright (C) 2026 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 +. */ + +#define IN_TARGET_CODE 1 + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "target.h" +#include "rtl.h" +#include "tree.h" +#include "memmodel.h" +#include "tm.h" +#include "optabs.h" +#include "regs.h" +#include "emit-rtl.h" +#include "recog.h" +#include "diagnostic-core.h" +#include "stor-layout.h" +#include "alias.h" +#include "fold-const.h" +#include "output.h" +#include "insn-attr.h" +#include "flags.h" +#include "explow.h" +#include "calls.h" +#include "varasm.h" +#include "expr.h" +#include "tm_p.h" +#include "df.h" +#include "reload.h" +#include "sched-int.h" +#include "tm-constrs.h" + +/* If INSN is a load or store of address in the form of [base+offset], + extract the two parts and set to BASE and OFFSET. IS_LOAD is set + to TRUE if it's a load. Return TRUE if INSN is such an instruction, + otherwise return FALSE. */ + +static bool +arcv_fusion_load_store (rtx_insn *insn, rtx *base, rtx *offset, + machine_mode *mode, bool *is_load) +{ + rtx x, dest, src; + + gcc_assert (INSN_P (insn)); + x = PATTERN (insn); + if (GET_CODE (x) != SET) + return false; + + src = SET_SRC (x); + dest = SET_DEST (x); + + if ((GET_CODE (src) == SIGN_EXTEND || GET_CODE (src) == ZERO_EXTEND) + && MEM_P (XEXP (src, 0))) + src = XEXP (src, 0); + + if (REG_P (src) && MEM_P (dest)) + { + *is_load = false; + if (extract_base_offset_in_addr (dest, base, offset)) + *mode = GET_MODE (dest); + } + else if (MEM_P (src) && REG_P (dest)) + { + *is_load = true; + if (extract_base_offset_in_addr (src, base, offset)) + *mode = GET_MODE (src); + } + else + return false; + + return (*base != NULL_RTX && *offset != NULL_RTX); +} + +/* Return TRUE if the target microarchitecture supports macro-op + fusion for two memory operations of mode MODE (the direction + of transfer is determined by the IS_LOAD parameter). */ + +bool +arcv_pair_fusion_mode_allowed_p (machine_mode mode, bool is_load) +{ + return ((is_load && (mode == SImode + || mode == HImode + || mode == QImode)) + || (!is_load && mode == SImode)); +} + +bool +arcv_sched_fusion_priority (rtx_insn *insn, int max_pri, int *fusion_pri, + int *pri) +{ + rtx base, offset; + machine_mode mode = SImode; + bool is_load; + + gcc_assert (INSN_P (insn)); + + /* Default priority for non-fusible instructions. */ + int default_pri = max_pri - 1; + + /* Check if this is a fusible load/store instruction. */ + if (!arcv_fusion_load_store (insn, &base, &offset, &mode, &is_load) + || !arcv_pair_fusion_mode_allowed_p (mode, is_load)) + return false; + + /* Start with half the default priority to distinguish fusible from + non-fusible instructions. */ + int priority = default_pri / 2; + + /* Scale priority by access width - narrower accesses get lower priority. + HImode: divide by 2, QImode: divide by 4. This encourages wider + accesses to be scheduled together. */ + if (mode == HImode) + priority /= 2; + else if (mode == QImode) + priority /= 4; + + /* Factor in base register: instructions with smaller register numbers + get higher priority. The shift by 20 bits ensures this is the most + significant component of the priority. */ + const int BASE_REG_SHIFT = 20; + const int BASE_REG_MASK = 0xff; + priority -= ((REGNO (base) & BASE_REG_MASK) << BASE_REG_SHIFT); + + /* Calculate fusion priority: group loads/stores with adjacent addresses + into the same scheduling group. We divide the offset by (mode_size * 2) + to group pairs of adjacent accesses, then shift left by 1 to make room + for the load/store bit. */ + int off_val = (int)(INTVAL (offset)); + int addr_group = off_val / (GET_MODE_SIZE (mode).to_constant () * 2); + *fusion_pri = priority - (addr_group << 1) + is_load; + + /* Factor in the actual offset value: instructions with smaller offsets + get higher priority. We use only the lower 20 bits to avoid overflow. */ + const int OFFSET_MASK = 0xfffff; + if (off_val >= 0) + priority -= (off_val & OFFSET_MASK); + else + priority += ((-off_val) & OFFSET_MASK); + + *pri = priority; + + return true; +} diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc index 98df3521029..a60d001d4d7 100644 --- a/gcc/config/riscv/riscv-fusion.cc +++ b/gcc/config/riscv/riscv-fusion.cc @@ -156,6 +156,19 @@ riscv_set_is_shNadduw_p (rtx set) && REG_P (SET_DEST (set))); } +void +riscv_sched_fusion_priority (rtx_insn *insn, int max_pri, int *fusion_pri, + int *pri) +{ + if (TARGET_ARCV_RHX100 + && arcv_sched_fusion_priority (insn, max_pri, fusion_pri, pri)) + return; + + /* Default priority. */ + *pri = max_pri - 1; + *fusion_pri = max_pri - 1; +} + /* Return TRUE if two memory operands can be fused based on their addresses. Checks if MEM0 and MEM1 have the same base register with adjacent offsets, making them suitable for fusion (e.g., adjacent load/store pairs). */ @@ -178,21 +191,9 @@ riscv_adjacent_memops_p (rtx mem0, rtx mem1, bool is_load) if (GET_MODE (mem0) != GET_MODE (mem1)) return false; - /* Check if the mode is allowed for ARC-V fusion restrictions. - Loads: allow SI, HI, and QI modes. - Stores: allow only SI mode. */ - if (TARGET_ARCV_RHX100) - { - machine_mode mode = GET_MODE (mem0); - bool mode_allowed = ((is_load - && (mode == SImode - || mode == HImode - || mode == QImode)) - || (!is_load && mode == SImode)); - - if (!mode_allowed) - return false; - } + if (TARGET_ARCV_RHX100 + && !arcv_pair_fusion_mode_allowed_p (GET_MODE (mem0), is_load)) + return false; rtx mem_addr0 = XEXP (mem0, 0); rtx mem_addr1 = XEXP (mem1, 0); diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index a94c37fa052..4158af2fd1a 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -882,6 +882,7 @@ extern bool riscv_macro_fusion_p (void); extern bool riscv_macro_fusion_pair_p (rtx_insn *, rtx_insn *); extern bool riscv_fusion_enabled_p (enum riscv_fusion_pairs); extern unsigned int riscv_get_fusible_ops (void); +extern void riscv_sched_fusion_priority (rtx_insn *, int, int *, int *); /* Routines implemented in thead.cc. */ extern bool extract_base_offset_in_addr (rtx, rtx *, rtx *); @@ -913,6 +914,10 @@ extern bool arcv_mpy_1c_bypass_p (rtx_insn *, rtx_insn *); extern bool arcv_mpy_2c_bypass_p (rtx_insn *, rtx_insn *); extern bool arcv_mpy_10c_bypass_p (rtx_insn *, rtx_insn *); +/* Routines implemented in arcv.cc. */ +extern bool arcv_pair_fusion_mode_allowed_p (machine_mode, bool); +extern bool arcv_sched_fusion_priority (rtx_insn *, int, int *, int *); + extern bool strided_load_broadcast_p (void); extern bool riscv_prefer_agnostic_p (void); extern bool riscv_use_divmod_expander (void); diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index aabd12aa040..d08a4539536 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -16590,6 +16590,9 @@ riscv_memtag_tag_bitsize () #undef TARGET_SCHED_MACRO_FUSION_PAIR_P #define TARGET_SCHED_MACRO_FUSION_PAIR_P riscv_macro_fusion_pair_p +#undef TARGET_SCHED_FUSION_PRIORITY +#define TARGET_SCHED_FUSION_PRIORITY riscv_sched_fusion_priority + #undef TARGET_SCHED_INIT #define TARGET_SCHED_INIT riscv_sched_init diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv index 2a4a2ccab50..0712833e219 100644 --- a/gcc/config/riscv/t-riscv +++ b/gcc/config/riscv/t-riscv @@ -194,6 +194,12 @@ riscv-zicfilp.o: $(srcdir)/config/riscv/riscv-zicfilp.cc \ $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/riscv/riscv-zicfilp.cc +arcv.o: $(srcdir)/config/riscv/arcv.cc \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TARGET_H) $(BACKEND_H) $(RTL_H) \ + memmodel.h $(EMIT_RTL_H) $(TM_H) output.h + $(COMPILE) $< + $(POSTCOMPILE) + PASSES_EXTRA += $(srcdir)/config/riscv/riscv-passes.def $(common_out_file): $(srcdir)/config/riscv/riscv-cores.def \ From patchwork Wed Aug 5 10:02:11 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Silva X-Patchwork-Id: 140638 X-Patchwork-Delegate: jlaw@ventanamicro.com Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id AD1664BAE7DE for ; Wed, 5 Aug 2026 10:03:35 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org AD1664BAE7DE Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=outlook.com header.i=@outlook.com header.a=rsa-sha256 header.s=selector1 header.b=tY5y40a1 X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazolkn190100000.outbound.protection.outlook.com [IPv6:2a01:111:f403:d204::]) by sourceware.org (Postfix) with ESMTPS id 426BB4B99F55 for ; Wed, 5 Aug 2026 10:02:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 426BB4B99F55 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=outlook.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=outlook.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 426BB4B99F55 Authentication-Results: sourceware.org; arc=pass smtp.remote-ip=2a01:111:f403:d204:: ARC-Seal: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1785924165; cv=pass; b=YJm+Dsc6mT14MhKnl7djP4IXrvpoAYoUNLnpIXOI5BgQFvtlwaYMjBbtXmn2h4Cq8Ppri003e34Ejycw+mGh/Y1rwDO2ipJxvABZ9evrel49kg9pAxLweVKMNglotj2RdM2V/nHdXVyfd2D9+LVWSa0mdx2aDpyf71DWuTXfNDw= ARC-Message-Signature: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1785924165; c=relaxed/simple; bh=7vJd/6GH3RTyAZdc6ZV8ZWkuQjrK9csmzPTVuoLuIjA=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=o38A2bWEedBfNSflmcXqqM1aFbquEtHDIog297YILH2lbiTm0FLMgNpjSE/6x+50w691Ne4FbQZWxWv/7xCLMzC8+ru9MhNzfbAUVOBRAQ7bMQRK7PtVyMFL/wKHfk8vc3SihlGMjN3rFOnU154ll4wComPTR5LdnaH6FQHgmbE= ARC-Authentication-Results: i=2; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=outlook.com header.i=@outlook.com header.a=rsa-sha256 header.s=selector1 header.b=tY5y40a1 DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 426BB4B99F55 ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=pFyDSu9qYCFzoDIaEPdA/PG77OThntaaQGAwME5VCocmI7a9g0ity3OT+MbMzztzo2nFOU5rXvXgPPgo/TC5JltwCH3uueMR3W4YDLsLdqnrH1XpUH09w1IiXTN+hNERa4AVUZKxZQK/He3tdjz9mpWEesXAB15vHxJYRIlYbyBQhpMo3aibbXoHtgSNGaWgOevBbkqkRCM4ktAA0anZXlMJSlhz1VQwQNfNFnqSGmJyHOs7LZFji8rh6h+kByV2FR0DRUR2gL0ybi3mko4GOmG/5sxqlRH/JQ6iQ/CzrwSFcV/3JWfM4aUViiN/W4zjUpoxfb/BMmfVoIWZoIZIBg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Bq7Hvrr8UTASVVxVSrQUtpUPDkbnuS9CkiIz4Cd2qNs=; b=mPMJmxwMO09+e2nFuadJCik8H9R0MRv1SXqor/Nk6xigRG8tyygee1VcYsIugz+diz7x4K2gUykzmBNY97TO3DcwgPBKtbzB7t82/940LVdOKOxfgpWCw/HTo8ca7bgebirblaTaqhxEjf0vHFw4agngo9vkQ0a6cFlPh5oL5ilhGrJtM1FXubf5RWj61C+wB3rDGjpjcBYfYKmvM3+a9CISMEbUeFhHmC7JoD5CWxwv86FlbAPOnIsmrIZC4c97Iuljc8UHioZy7mX0Q5FTMk/UYEiAWJji+LPHpBBglCuNR6hm5iC6eMCSmNYgB99wNxqeQ1XZVY6rZLHnmnlAow== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=outlook.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Bq7Hvrr8UTASVVxVSrQUtpUPDkbnuS9CkiIz4Cd2qNs=; b=tY5y40a1ZviJ5V/whf+1MfKWSC98JQeFi5hgHCLnAXa3+dhiD5HVayLDW1aGz3OVW9iXsiSpxgxul9e89LdhFbjl+99RpW1DaU2NMIx08oPBqLE/04RwyoW5ttG31O7PHZWDiwD+Oq2TCcX+77gOI2TgRD+aYyccRkQGwUkM5ygqAOE6rQTAJ9KX+mNnV9BGLOexHRHvKKse9y8g/Mqs+GcmDcvl1SMd7DKk6PEyNwFNioLag0aPT7LW4G/XgwHBFnFiz8zj8asUzL9dUFTrc68dP3RsH4CAw3sN8NXs1NX/yP3FrPeba2G5V/Am7GsUaksYQFo1d0heVDD84e/XSw== Received: from LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2b1::6) by LO8P265MB7547.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3b4::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.19; Wed, 5 Aug 2026 10:02:40 +0000 Received: from LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM ([fe80::839:df74:7f0e:b82a]) by LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM ([fe80::839:df74:7f0e:b82a%2]) with mapi id 15.21.0292.015; Wed, 5 Aug 2026 10:02:40 +0000 From: Luis Silva To: gcc-patches@gcc.gnu.org Cc: Jeff Law , Kito Cheng , Palmer Dabbelt , Robin Dapp , Luis Silva , Artemiy Volkov , Michiel Derhaeg , Loeka Rogge , Alex Turjan , Luis Silva Subject: [PATCH v2 3/4] RISC-V: Implement scheduling for ARC-V RHX-100 series Date: Wed, 5 Aug 2026 11:02:11 +0100 Message-ID: X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260805100212.10852-1-luismgsilva@outlook.com> References: <20260805100212.10852-1-luismgsilva@outlook.com> X-ClientProxiedBy: MA4P292CA0012.ESPP292.PROD.OUTLOOK.COM (2603:10a6:250:2d::9) To LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2b1::6) X-Microsoft-Original-Message-ID: <20260805100212.10852-4-luismgsilva@outlook.com> MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: LO6P265MB6224:EE_|LO8P265MB7547:EE_ X-MS-Office365-Filtering-Correlation-Id: eaecf1b9-d1d4-447d-3431-08def2d8adf8 X-Microsoft-Antispam: BCL:0; ARA:14566002|23021999003|5072599009|51005399006|25010399006|15080799012|19101099003|41001999006|19110799012|8060799015|440099028|3412199025|10035399007|40105399003|2607281247196008|1710799026; X-Microsoft-Antispam-Message-Info: Rr4/NP3mar34YRsB/OIGl0fWIKpb7H9fJAfbu4B/WTdwEk/bXmG5kNRkK/NC4EESmZIyP/eqjpRb8p4nYGEzHQ0nIM8muSaLwz9jHa7PKJQPfGbQcaNKRtiHTTEBplCKp4DTQqq5shiMxf6UDFyr0Gi2vwVTcOnqnzPSo2svmwIrllnMLvlR4/z0d9bhDm7X1S2CG93ZtxKEl7jDPSfKBHX1mj2l41C3c48MgxFTZlj6VOlAMc6x6qvYujgcH+TyGXe0h4gMNTgo6SHWUa4UBvtUTPZFVbp6dZSaNchbAmtNdZvffQcsfrFiHLdkgYThQauRIQaX7u67koTr+muWN97aSGzmJraN1Of7sPcBO5gEQgfUnor1Os1DKdTHONb/WnSJ1Lc7m/xVYRalwgybKL5TxBkCXOt04wpNhlaqu2dNkbLI7YGtTjn5dPcb/b3aZsttlTXA+Ra+6RQWRupFrPbhQKfyM3fGL9/eoUUCpkqGL9B+9wE2Tjch54jx3DjNJ4ATkxt6fVJn6CFnRC9ZDxoYGa1pdYlbcdzs1VDDEGjqEldtGc1j4mlsc7K8MwLNvll46963psmxI2OgZF5e1zf/6TBTAbtfzzvfNNJfOkV4WgM6XlOTkmXUSJUP73qeDomfuJts2pM2jPrYgULkm493s8w68PSUOZ58jVSa5Fp14K6ukanxmvzmACvc7l1EPgjE97z0Km8pIToEk9RkKUVKoxTAK5oJXpVT1CnI0uo+u9EmLiJef/KwMU8ehTn0iIHzu5UwwsE5mmWDm0ow6kaQAss69Ip8mOSm6LFKE6TnHKCKD9iOnTipFFzLJAAu/GVOXm5mFJocZJxnrFG7AoQ8VhQaY5LdCnsKXIJFztjgWe9M3kIEgYBEW5LjIM4Qy8y80DDk/rcS0RvTei/20ioTzaDgwThytfkQunxW/rHsDSz77XMdtd4Uif3Br37sZPvjOtw9bqxRkKTQrK+yYwXoYFOSDgEei9sbIzDvdac= X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: 2vXXFUZVCkXI3imYzSAHoXGDuEQq3tfXPJIK81tGeQg6PlEuk5E4RPPHtJpPsGsYME4AcDzyIjUF9aEqJfd+T2ht6K2SH9Yl1DPftTfAcFQ2Wn5A9AjyK6panHHW4/QjSERCrx3tvsYNJ78qJurUR2ITWwlKD2mq2hSUfd7ymRkCWzpOO+/ozSNyPBPAKMTW4ocwoS2p7jsnrCu2U0M8MQpRE7db0WucS2u3zhPkSs4HYp39T1LaSHZX0yo3dR3Dx6ROWNve9ebHT1BfCmO96oagJO1g8fk511FV0VaLM4rGuS0JIyCujqiOrB7lynJCl19jLo9TX42+o+o1WpyQq8DodvnitjXViKTXZWSVg/4Fvg7iQrScLF3UZ2C5wP+0W+262q5vwPITAkt4xwBwLi+7EvDIaBtiF88MPd3WLOwEVJdlhRx84AetIaoix3m1muZQzo2c/rxUbAZUnTZaydeZukChwuZ8tN7xv1H9JBJzTPEV50jPP/ZYFKMOtOEf35aex84TBHiep8CjNAENLofHmayanoKecTrqTVx+pOFNWk4zHvW5BpW0eHFgBAcngb6qmb791AMAo/1LVlCOQhJPhyYroItYRd3b+tlELxdhKKlMEZgfVmdgGC8V66hJO3+qbgub5vYZ9UvGrQtwizE6uGUU3HuRpkLsWCyTwbNnXVpauQeQ25Je2067do4L4aZtVTk9+gDcTXKTodfIoOm82N33BsqnsN7zeYSFSziRZmveRLPGHlGaGRZLOmeDvkkCYYZFMd4/M6NiUdJTzM6NKoHveI1Cu19EuhKt29iiGHkTjSLW5CVbBT7mb2BOdV00okL1WL9DYtS2JKeehHBbWlTRhkdYphxhQp8EXuPuROG1KPjx2yhJOsO6YebBAUEgpSww3KYmjRqZEg8N7is1yVPqIq93ltOa/9I0mjDavSF5RuVHzMD1+PVlgvnfcVdU5c89wu/aTRNQSOYJbEGQDP5+7uFuG1XBPGiA2+U4Yn0IrHQoDZ0I4KR1puq+tol64lGubUH1CCHEaLE7YAX/dahzepdk6Q6PY7AIDaJkSacWsuLqjf07Y94zT+ZdQ9pZKNlWjZX4gWyc6z7SMKkT+quCFFzQ6VTX40TX278l4MXmXE1wbC16mRewVnCQpd8fMIwr+iqkvqfWCcbDwgOeTpZTkRYblCUzENJShp7DOyJua6nrmtZfEhEBT4JQpCX57hkNhcsPawyUPJ10htbw4VDQSdGvwwz2Oz1NPsH1uKXIoE9mXjZhdVIx2B2D5YOyVBaBQ/3g/5/CwRe3MMLy807JFZI/X33ycRnyv0RpIsWqOHO+8pg29Lc18Rh3r7hJeAa0tIRDeD85Ux2ytkUSpHafK8AA+xK/t4lYBwZu+yMmHeJPQRw74GN3Q+gYxyuHXFIfYvVHZchDLROmjw== X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: eaecf1b9-d1d4-447d-3431-08def2d8adf8 X-MS-Exchange-CrossTenant-AuthSource: LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 05 Aug 2026 10:02:38.4575 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7547 X-Spam-Status: No, score=-10.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS, SPF_PASS, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 From: Luis Silva This patch implements instruction scheduling support for the dual-issue ARC-V RHX-100 processor by adding scheduler hooks and state tracking for the two execution pipes. These hooks address microarchitectural details not covered by the pipeline description. The riscv_sched_variable_issue () and riscv_sched_reorder2 () hooks work together to make sure that: - the critical path and the instruction priorities are respected; - both pipes are filled (taking advantage of parallel dispatch within the microarchitectural constraints); - there is as much fusion going on as possible; - the existing fusion pairs are not broken up. riscv_sched_adjust_priority () slightly bumps the priority of load/store pairs. As a result it becomes easier for riscv_sched_reorder2 () to schedule instructions in the memory pipe. TARGET_SCHED_REORDER2 is defined for all RISC-V tunes, so riscv_sched_reorder2 must preserve the remaining issue count for non-RHX (via cached_can_issue_more from riscv_sched_variable_issue). gcc/ChangeLog: * config/riscv/arcv.cc (struct arcv_sched_state): New. (arcv_sched_init): New function. (arcv_sched_reorder2): New function. (arcv_sched_adjust_priority): New function. (arcv_sched_adjust_cost): New function. (arcv_can_issue_more_p): New function. (arcv_sched_variable_issue): New function. * config/riscv/riscv-protos.h (arcv_sched_init): Declare. (arcv_sched_reorder2): Declare. (arcv_sched_adjust_priority): Declare. (arcv_sched_adjust_cost): Declare. (arcv_can_issue_more_p): Declare. (arcv_sched_variable_issue): Declare. * config/riscv/riscv.cc (cached_can_issue_more): New. (riscv_sched_init): Call arcv_sched_init. (riscv_sched_variable_issue): Handle RHX-100; cache the returned issue count. (riscv_sched_adjust_cost): Handle RHX-100. (riscv_sched_adjust_priority): New function. (riscv_sched_reorder2): New function; return cached_can_issue_more for non-RHX. (TARGET_SCHED_ADJUST_PRIORITY): Define. (TARGET_SCHED_REORDER2): Define. gcc/testsuite/ChangeLog: * gcc.target/riscv/fusion-ls-update-2.c: Remove XFAIL, and fix the scan pattern. * gcc.target/riscv/fusion-ls-update.c: Remove XFAIL. Co-authored-by: Artemiy Volkov Co-authored-by: Michiel Derhaeg Co-authored-by: Alex Turjan Co-authored-by: Loeka Rogge Signed-off-by: Luis Silva --- gcc/config/riscv/arcv.cc | 247 ++++++++++++++++++ gcc/config/riscv/riscv-protos.h | 6 + gcc/config/riscv/riscv.cc | 82 +++++- .../gcc.target/riscv/fusion-ls-update-2.c | 3 +- .../gcc.target/riscv/fusion-ls-update.c | 3 +- 5 files changed, 329 insertions(+), 12 deletions(-) diff --git a/gcc/config/riscv/arcv.cc b/gcc/config/riscv/arcv.cc index e29712ca2be..050c91401c4 100644 --- a/gcc/config/riscv/arcv.cc +++ b/gcc/config/riscv/arcv.cc @@ -49,6 +49,32 @@ along with GCC; see the file COPYING3. If not see #include "sched-int.h" #include "tm-constrs.h" +/* Scheduler state tracking for dual-pipe ARCV architectures. */ + +struct arcv_sched_state { + /* True if the ALU pipe has been scheduled for the current cycle. + The ALU pipe handles arithmetic, logical, and other computational + instructions. */ + int alu_pipe_scheduled_p; + + /* True if pipe B has been scheduled for the current cycle. + Pipe B is the second execution pipe, typically used for memory + operations (loads/stores) but can also handle other instructions. */ + int pipeB_scheduled_p; + + /* The last instruction that was scheduled. Used to detect fusion + opportunities by looking ahead at the next instruction to be + scheduled. */ + rtx_insn *last_scheduled_insn; + + /* Cached value of how many more instructions can be issued in the + current cycle. Updated as instructions are scheduled and pipes + become occupied. */ + short cached_can_issue_more; +}; + +static struct arcv_sched_state sched_state; + /* If INSN is a load or store of address in the form of [base+offset], extract the two parts and set to BASE and OFFSET. IS_LOAD is set to TRUE if it's a load. Return TRUE if INSN is such an instruction, @@ -160,3 +186,224 @@ arcv_sched_fusion_priority (rtx_insn *insn, int max_pri, int *fusion_pri, return true; } + +/* Initialize ARCV scheduler state at the beginning of scheduling. */ + +void +arcv_sched_init (void) +{ + sched_state.last_scheduled_insn = 0; +} + +/* Try to reorder ready queue to promote ARCV fusion opportunities. + Returns the number of instructions that can be issued this cycle. */ + +int +arcv_sched_reorder2 (rtx_insn **ready, int *n_readyp) +{ + if (sched_fusion) + return sched_state.cached_can_issue_more; + + if (!sched_state.cached_can_issue_more) + return 0; + + /* Fuse double load/store instances missed by sched_fusion. */ + if (!sched_state.pipeB_scheduled_p && sched_state.last_scheduled_insn + && ready && *n_readyp > 0 + && !SCHED_GROUP_P (sched_state.last_scheduled_insn) + && (get_attr_type (sched_state.last_scheduled_insn) == TYPE_LOAD + || get_attr_type (sched_state.last_scheduled_insn) == TYPE_STORE)) + { + for (int i = 1; i <= *n_readyp; i++) + { + rtx_insn *next_insn + = next_nonnote_nondebug_insn_bb (ready[*n_readyp - i]); + /* Try to fuse the last_scheduled_insn with. */ + /* Fuse only with nondebug insn. */ + if (NONDEBUG_INSN_P (ready[*n_readyp - i]) + /* Which have not been already fused. */ + && !SCHED_GROUP_P (ready[*n_readyp - i]) + && (!next_insn || !NONDEBUG_INSN_P (next_insn) + || !SCHED_GROUP_P (next_insn)) + && riscv_macro_fusion_pair_p (sched_state.last_scheduled_insn, + ready[*n_readyp - i])) + { + std::swap (ready[*n_readyp - 1], ready[*n_readyp - i]); + SCHED_GROUP_P (ready[*n_readyp - 1]) = 1; + sched_state.pipeB_scheduled_p = 1; + return sched_state.cached_can_issue_more; + } + } + sched_state.pipeB_scheduled_p = 1; + } + + /* Try to fuse a non-memory last_scheduled_insn. */ + if ((!sched_state.alu_pipe_scheduled_p || !sched_state.pipeB_scheduled_p) + && sched_state.last_scheduled_insn && ready && *n_readyp > 0 + && !SCHED_GROUP_P (sched_state.last_scheduled_insn) + && (get_attr_type (sched_state.last_scheduled_insn) != TYPE_LOAD + && get_attr_type (sched_state.last_scheduled_insn) != TYPE_STORE)) + { + for (int i = 1; i <= *n_readyp; i++) + { + rtx_insn* next_insn + = next_nonnote_nondebug_insn_bb (ready[*n_readyp - i]); + if (NONDEBUG_INSN_P (ready[*n_readyp - i]) + && !SCHED_GROUP_P (ready[*n_readyp - i]) + && active_insn_p (ready[*n_readyp - i]) + && (!next_insn || !NONDEBUG_INSN_P (next_insn) + || !SCHED_GROUP_P (next_insn)) + && riscv_macro_fusion_pair_p (sched_state.last_scheduled_insn, + ready[*n_readyp - i])) + { + if (get_attr_type (ready[*n_readyp - i]) == TYPE_LOAD + || get_attr_type (ready[*n_readyp - i]) == TYPE_STORE) + { + if (sched_state.pipeB_scheduled_p) + continue; + else + sched_state.pipeB_scheduled_p = 1; + } + else if (!sched_state.alu_pipe_scheduled_p) + sched_state.alu_pipe_scheduled_p = 1; + else + sched_state.pipeB_scheduled_p = 1; + + std::swap (ready[*n_readyp - 1], ready[*n_readyp - i]); + SCHED_GROUP_P (ready[*n_readyp - 1]) = 1; + return sched_state.cached_can_issue_more; + } + } + sched_state.alu_pipe_scheduled_p = 1; + } + /* When pipe B is scheduled, we can have no more memops this cycle. */ + if (sched_state.pipeB_scheduled_p && *n_readyp > 0 + && NONDEBUG_INSN_P (ready[*n_readyp - 1]) + && recog_memoized (ready[*n_readyp - 1]) >= 0 + && !SCHED_GROUP_P (ready[*n_readyp - 1])) + { + rtx_insn *head_next = next_nonnote_nondebug_insn_bb (ready[*n_readyp - 1]); + if (get_attr_type (ready[*n_readyp - 1]) == TYPE_LOAD + || get_attr_type (ready[*n_readyp - 1]) == TYPE_STORE + || (head_next && NONDEBUG_INSN_P (head_next) + && SCHED_GROUP_P (head_next) && recog_memoized (head_next) >= 0 + && (get_attr_type (head_next) == TYPE_LOAD + || get_attr_type (head_next) == TYPE_STORE))) + { + if (sched_state.alu_pipe_scheduled_p) + return 0; + + for (int i = 2; i <= *n_readyp; i++) + { + rtx_insn* next_insn + = next_nonnote_nondebug_insn_bb (ready[*n_readyp - i]); + if ((NONDEBUG_INSN_P (ready[*n_readyp - i]) + && recog_memoized (ready[*n_readyp - i]) >= 0 + && get_attr_type (ready[*n_readyp - i]) != TYPE_LOAD + && get_attr_type (ready[*n_readyp - i]) != TYPE_STORE + && !SCHED_GROUP_P (ready[*n_readyp - i]) + && (!next_insn || !NONDEBUG_INSN_P (next_insn) + || !SCHED_GROUP_P (next_insn))) + || (next_insn && NONDEBUG_INSN_P (next_insn) + && recog_memoized (next_insn) >= 0 + && get_attr_type (next_insn) != TYPE_LOAD + && get_attr_type (next_insn) != TYPE_STORE)) + { + std::swap (ready[*n_readyp - 1], ready[*n_readyp - i]); + sched_state.alu_pipe_scheduled_p = 1; + sched_state.cached_can_issue_more = 1; + return 1; + } + } + return 0; + } + } + + /* If all else fails, schedule a single (fused) instruction. */ + if (ready && *n_readyp > 0 + && NONDEBUG_INSN_P (ready[*n_readyp - 1]) + && recog_memoized (ready[*n_readyp - 1]) >= 0) + { + rtx_insn *next_insn = next_nonnote_nondebug_insn_bb (ready[*n_readyp - 1]); + + sched_state.cached_can_issue_more + = next_insn && NONDEBUG_INSN_P (next_insn) && SCHED_GROUP_P (next_insn) + ? 2 : 1; + } + + return sched_state.cached_can_issue_more; +} + +int +arcv_sched_adjust_priority (rtx_insn *insn, int priority) +{ + /* Bump the priority of fused load-store pairs for easier + scheduling of the memory pipe. The specific increase + value is determined empirically. */ + rtx_insn *next = next_nonnote_nondebug_insn_bb (insn); + if (next && single_set (insn) && single_set (next) + && SCHED_GROUP_P (next) + && ((get_attr_type (insn) == TYPE_STORE + && get_attr_type (next) == TYPE_STORE) + || (get_attr_type (insn) == TYPE_LOAD + && get_attr_type (next) == TYPE_LOAD))) + return priority + 1; + + return priority; +} + +/* Adjust scheduling cost for ARCV fusion. */ + +int +arcv_sched_adjust_cost (rtx_insn *insn, int dep_type, int cost) +{ + if (dep_type == REG_DEP_ANTI && !SCHED_GROUP_P (insn)) + return cost + 1; + + return cost; +} + +bool +arcv_can_issue_more_p (int issue_rate, int more, rtx_insn *insn) +{ + /* Beginning of cycle - reset variables. */ + if (more == issue_rate) + { + sched_state.alu_pipe_scheduled_p = 0; + sched_state.pipeB_scheduled_p = 0; + } + + if (!(insn && NONDEBUG_INSN_P (insn) && SCHED_GROUP_P (insn)) + && sched_state.alu_pipe_scheduled_p && sched_state.pipeB_scheduled_p) + { + sched_state.cached_can_issue_more = 0; + return false; + } + + sched_state.cached_can_issue_more = more; + + return true; +} + +int +arcv_sched_variable_issue (rtx_insn *insn, int more) +{ + rtx_insn *next = next_nonnote_nondebug_insn_bb (insn); + if (next && NONDEBUG_INSN_P (next) && SCHED_GROUP_P (next) + && single_set (insn) && single_set (next)) + { + if (get_attr_type (insn) == TYPE_LOAD + || get_attr_type (insn) == TYPE_STORE + || get_attr_type (next) == TYPE_LOAD + || get_attr_type (next) == TYPE_STORE + || sched_state.alu_pipe_scheduled_p) + sched_state.pipeB_scheduled_p = 1; + else + sched_state.alu_pipe_scheduled_p = 1; + } + + sched_state.last_scheduled_insn = insn; + sched_state.cached_can_issue_more = more - 1; + + return sched_state.cached_can_issue_more; +} diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 4158af2fd1a..8a39e7f59f3 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -917,6 +917,12 @@ extern bool arcv_mpy_10c_bypass_p (rtx_insn *, rtx_insn *); /* Routines implemented in arcv.cc. */ extern bool arcv_pair_fusion_mode_allowed_p (machine_mode, bool); extern bool arcv_sched_fusion_priority (rtx_insn *, int, int *, int *); +extern void arcv_sched_init (void); +extern int arcv_sched_reorder2 (rtx_insn **, int *); +extern int arcv_sched_adjust_priority (rtx_insn *, int); +extern int arcv_sched_adjust_cost (rtx_insn *, int, int); +extern bool arcv_can_issue_more_p (int, int, rtx_insn *); +extern int arcv_sched_variable_issue (rtx_insn *, int); extern bool strided_load_broadcast_p (void); extern bool riscv_prefer_agnostic_p (void); diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index d08a4539536..dd80da2d55a 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -11455,6 +11455,10 @@ struct last_vconfig rtx avl; } last_vconfig; +/* Cached value of can_issue_more. Set by riscv_sched_variable_issue and + returned from riscv_sched_reorder2. */ +static int cached_can_issue_more; + /* Clear LAST_VCONFIG so we have no known state. */ static void clear_vconfig (void) @@ -11507,23 +11511,42 @@ static void riscv_sched_init (FILE *, int, int) { clear_vconfig (); + + if (TARGET_ARCV_RHX100) + arcv_sched_init (); } /* Implement TARGET_SCHED_VARIABLE_ISSUE. */ static int riscv_sched_variable_issue (FILE *, int, rtx_insn *insn, int more) { + if (TARGET_ARCV_RHX100) + if (!arcv_can_issue_more_p (riscv_issue_rate (), more, insn)) + { + cached_can_issue_more = 0; + return 0; + } + if (DEBUG_INSN_P (insn)) - return more; + { + cached_can_issue_more = more; + return more; + } rtx_code code = GET_CODE (PATTERN (insn)); if (code == USE || code == CLOBBER) - return more; + { + cached_can_issue_more = more; + return more; + } /* GHOST insns are used for blockage and similar cases which effectively end a cycle. */ if (get_attr_type (insn) == TYPE_GHOST) - return 0; + { + cached_can_issue_more = 0; + return 0; + } /* If we ever encounter an insn with an unknown type, trip an assert so we can find and fix this problem. */ @@ -11558,6 +11581,14 @@ riscv_sched_variable_issue (FILE *, int, rtx_insn *insn, int more) } } + if (TARGET_ARCV_RHX100) + { + more = arcv_sched_variable_issue (insn, more); + cached_can_issue_more = more; + return more; + } + + cached_can_issue_more = more - 1; return more - 1; } @@ -11631,9 +11662,12 @@ riscv_get_fusible_ops (void) we currently only perform the adjustment when -madjust-lmul-cost is given. */ static int -riscv_sched_adjust_cost (rtx_insn *, int, rtx_insn *insn, int cost, - unsigned int) +riscv_sched_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, + int cost, unsigned int) { + /* Use ARCV-specific cost adjustment for RHX-100. */ + if (TARGET_ARCV_RHX100) + return arcv_sched_adjust_cost (insn, dep_type, cost); /* Only do adjustments for the generic out-of-order and spacemit_x60 scheduling model. */ @@ -11642,10 +11676,10 @@ riscv_sched_adjust_cost (rtx_insn *, int, rtx_insn *insn, int cost, && riscv_microarchitecture != spacemit_x60)) return cost; - if (recog_memoized (insn) < 0) + if (recog_memoized (dep_insn) < 0) return cost; - enum attr_type type = get_attr_type (insn); + enum attr_type type = get_attr_type (dep_insn); if (type == TYPE_VFREDO || type == TYPE_VFWREDO) { @@ -11663,7 +11697,7 @@ riscv_sched_adjust_cost (rtx_insn *, int, rtx_insn *insn, int cost, return cost; enum riscv_vector::vlmul_type lmul = - (riscv_vector::vlmul_type)get_attr_vlmul (insn); + (riscv_vector::vlmul_type)get_attr_vlmul (dep_insn); double factor = 1; switch (lmul) @@ -11696,6 +11730,32 @@ riscv_sched_adjust_cost (rtx_insn *, int, rtx_insn *insn, int cost, return new_cost; } +/* Implement TARGET_SCHED_ADJUST_PRIORITY hook. */ + +static int +riscv_sched_adjust_priority (rtx_insn *insn, int priority) +{ + if (TARGET_ARCV_RHX100) + return arcv_sched_adjust_priority (insn, priority); + + return priority; +} + +/* Implement TARGET_SCHED_REORDER2 hook. */ + +static int +riscv_sched_reorder2 (FILE *file ATTRIBUTE_UNUSED, + int verbose ATTRIBUTE_UNUSED, + rtx_insn **ready, + int *n_readyp, + int clock ATTRIBUTE_UNUSED) +{ + if (TARGET_ARCV_RHX100) + return arcv_sched_reorder2 (ready, n_readyp); + + return cached_can_issue_more; +} + /* Implement TARGET_SCHED_CAN_SPECULATE_INSN hook. Return true if insn can be scheduled for speculative execution. Reject vsetvl instructions to prevent the scheduler from hoisting them out of basic blocks without @@ -16605,6 +16665,12 @@ riscv_memtag_tag_bitsize () #undef TARGET_SCHED_ADJUST_COST #define TARGET_SCHED_ADJUST_COST riscv_sched_adjust_cost +#undef TARGET_SCHED_ADJUST_PRIORITY +#define TARGET_SCHED_ADJUST_PRIORITY riscv_sched_adjust_priority + +#undef TARGET_SCHED_REORDER2 +#define TARGET_SCHED_REORDER2 riscv_sched_reorder2 + #undef TARGET_SCHED_CAN_SPECULATE_INSN #define TARGET_SCHED_CAN_SPECULATE_INSN riscv_sched_can_speculate_insn diff --git a/gcc/testsuite/gcc.target/riscv/fusion-ls-update-2.c b/gcc/testsuite/gcc.target/riscv/fusion-ls-update-2.c index 5e4ba9bac21..8d3045cbf4d 100644 --- a/gcc/testsuite/gcc.target/riscv/fusion-ls-update-2.c +++ b/gcc/testsuite/gcc.target/riscv/fusion-ls-update-2.c @@ -13,5 +13,4 @@ fuse_ls_update_rev (int *p, int n, int val) } } -/* XFAIL until scheduling support for RHX-100 series is implemented. */ -/* { dg-final { scan-rtl-dump "RISCV_FUSE_LS_UPDATE)" "sched2" { xfail *-*-* } } } */ +/* { dg-final { scan-rtl-dump "RISCV_FUSE_LS_UPDATE" "sched2" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-ls-update.c b/gcc/testsuite/gcc.target/riscv/fusion-ls-update.c index b71eab0fcd9..5939fdd0de9 100644 --- a/gcc/testsuite/gcc.target/riscv/fusion-ls-update.c +++ b/gcc/testsuite/gcc.target/riscv/fusion-ls-update.c @@ -12,5 +12,4 @@ fuse_ls_update (int *p, int n) return sum; } -/* XFAIL until scheduling support for RHX-100 series is implemented. */ -/* { dg-final { scan-rtl-dump "RISCV_FUSE_LS_UPDATE" "sched2" { xfail *-*-* } } } */ +/* { dg-final { scan-rtl-dump "RISCV_FUSE_LS_UPDATE" "sched2" } } */ From patchwork Wed Aug 5 10:02:12 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Silva X-Patchwork-Id: 140640 X-Patchwork-Delegate: jlaw@ventanamicro.com Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 300294BB1C35 for ; Wed, 5 Aug 2026 10:05:40 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 300294BB1C35 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=outlook.com header.i=@outlook.com header.a=rsa-sha256 header.s=selector1 header.b=Ir598pPo X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazolkn190100000.outbound.protection.outlook.com [IPv6:2a01:111:f403:d204::]) by sourceware.org (Postfix) with ESMTPS id 1C04C4BB1C1C for ; Wed, 5 Aug 2026 10:02:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1C04C4BB1C1C Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=outlook.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=outlook.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 1C04C4BB1C1C Authentication-Results: sourceware.org; arc=pass smtp.remote-ip=2a01:111:f403:d204:: ARC-Seal: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1785924169; cv=pass; b=Zl6jZeJ6RUBQqc85vhOjSKYyG5tk39cKfMc2zK36J8TtubKiiECATrXQf8uBdHgLsGftBw7x1w/UL/hXT2vBx5Y9sm2XFd5FSLx2ABSTvatoTd3gtJWZ332mRfkbgZOspYjDIs9C9OObExZgoVHnmHFMnX8qKdT857fxB54Z0Sk= ARC-Message-Signature: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1785924169; c=relaxed/simple; bh=xAQQ9qcjZmhyv/Mn2O1BwbHwa4cQXLV5qv+kZLOz5TA=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=lCa6e2WrAqygVImkkuRR613zL6rWPO2XTBpgRhUMrNlt9V1lVJGJYc2ty2OdJUnp7cD3a4J2ahq+o9TvL0xOEPRgdjsymomtmg4O+7aoLVgOKOoFIy+AF8vJGMyMTOWC2lVc4EH4Qh+0wo1EIPhv54f8mIxSn5T81p2ViFqVu4k= ARC-Authentication-Results: i=2; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=outlook.com header.i=@outlook.com header.a=rsa-sha256 header.s=selector1 header.b=Ir598pPo DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1C04C4BB1C1C ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=HeVArdIpS6GZQv4qT94rvRgmEiJPiFY0AqzVIG9R200WehcH/8wx6+DHDnyIG0RmJz4pjHThWLwOqnXDA47Ft54go539jRBSdMhLp8rLtPpQcujlbbKtZDuWzgFID457WVrqxobf0n4dbNwZJD/LM4zTJ3S9JcZ2B3Kng7CH+R4oHk8wWywI84zEattym6IxNdl9r1vWH3fhHKP98f8xl0Xo1rYdLoEVmlus1PWARXXuhI7S65WnfojRb4arob9kJMIkMDjUAgC7TGT+EuQWWkHxfljlbOM/YBshY5FX9NJ9Zg9kjyotCpHl4mVekVuVLddKmaYKriWuPiWwjPGuPQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=maPQ/uQpIeoqwnbEv00Y42ZG8pcQg9TzWZDhcfQB7Xg=; b=Do5LxuLhCR7CtlEdQxCpqsgaUT+S7cgKFMrpIlzm9GkmnQXHgpN9RoWkhtChEVQ55EvxRNf2wgCTAfal0zBGo3NvOHWBrF2ZtXhnUdlikcklwqAiZco0MrXEq9T27+ii6lH027JzNFKPh70Luz/91WIGKzk3qeCNGyne1caSR5N0yZUQw5nLfyif6dHVs7Knp8s/7koxQ1MBJWbW3Gyv1KVul6cCVZNFV9k1cd+2kYKVnttVW6Rte1NI8/qH6G9dO1hZPQtWXsDY1RDi2vMDbogJ9YA/Aj6qZ95X0QmueAmJwDHY83kUsuTqnFmmXHikMV9nWTKvrg62KFBN/XFPwA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=outlook.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=maPQ/uQpIeoqwnbEv00Y42ZG8pcQg9TzWZDhcfQB7Xg=; b=Ir598pPoQ9eSQN/2Ku/Kf6LM4ohD7W6Zy3Yjtpe1/ZRQds77TdafPGL6jufS5EAILKLwvqitqVn0eBmLZeqCfqkmG9xqdX/YvtgLvHR9JbaUQ7Cfpq6KXfvfXvI2aG8Pp4Qo0cfmnqzfs8T5jEu3CoWzDcFP4jyJBVkImlHjHjb959IeCzmpzVlqgFKq2RlKOjGMrxM2lZbuTdw9QbhXEHWrOIO6pANvBxD78qU6iZVBfzCuy+z0lBCU0q7gHQJ2EwueSZuKeLAtQo/zDBzJCTAEAlKJtnnZf8AH+kzyOqvYfjQ3iVSn065GfgiptE04CkyPvANTOcScpHxu83gzOQ== Received: from LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2b1::6) by LO8P265MB7547.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:3b4::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.19; Wed, 5 Aug 2026 10:02:42 +0000 Received: from LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM ([fe80::839:df74:7f0e:b82a]) by LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM ([fe80::839:df74:7f0e:b82a%2]) with mapi id 15.21.0292.015; Wed, 5 Aug 2026 10:02:41 +0000 From: Luis Silva To: gcc-patches@gcc.gnu.org Cc: Jeff Law , Kito Cheng , Palmer Dabbelt , Robin Dapp , Luis Silva , Artemiy Volkov , Michiel Derhaeg , Loeka Rogge , Alex Turjan , Luis Silva Subject: [PATCH v2 4/4] RISC-V: define_insn_and_split for multiply-add and bit-extract fusion Date: Wed, 5 Aug 2026 11:02:12 +0100 Message-ID: X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260805100212.10852-1-luismgsilva@outlook.com> References: <20260805100212.10852-1-luismgsilva@outlook.com> X-ClientProxiedBy: MA4P292CA0012.ESPP292.PROD.OUTLOOK.COM (2603:10a6:250:2d::9) To LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2b1::6) X-Microsoft-Original-Message-ID: <20260805100212.10852-5-luismgsilva@outlook.com> MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: LO6P265MB6224:EE_|LO8P265MB7547:EE_ X-MS-Office365-Filtering-Correlation-Id: 8a2ac544-34e2-4d38-937c-08def2d8aed1 X-Microsoft-Antispam: BCL:0; ARA:14566002|23021999003|5072599009|51005399006|25010399006|15080799012|19101099003|41001999006|19110799012|8060799015|440099028|3412199025|10035399007|40105399003|2607281247196008|1710799026; X-Microsoft-Antispam-Message-Info: dEBQogQfsHei/Y1MjgHIz4ywEMxF/NjzAYeDQJICRPzb5VcShqagIBrbwy/xH5QfWsQAaiyAIZYJL0/U4PDPn4cpLxtncmfZbcittAKEbADiDBnQHljVGpqZf5LepJ/EZ36kZzoUdjTomWQ0Eb+5VY4wxTJVJvIdGEcrLVeIDjiCY6MulxwNjQyFnMtrs/O7o7JPUitu+K5Wy6/nZxY3hho+AcAyyFtuQ5ttu2OmvsL0EnmDyY2pa7WeE54TXuQgSiTIAyCJrhTOhf1BUvE9/u/Khw9EzKmz8Q9fQpxcCRYepDWidftb/wmvemSmK8SKCFSWt0LcUmZDa8pUv5llzNhBR8l+3Ft2cfwOa/AcWy43ruC6XxGNzFgCR+yqk9dbhE+wXa7ZDAQ5Qe/jvJlXLIgVYjhVpa+xpqRraO9y9nnkVn/mk3Ni3Eom2nj4K87Y0lG5BF4xxqozU58W3cfVu+juJtOrlfVr99lSEqNypNVkN3w/6qpH+8S9oOO9OmSqA+6nEldFh/NzdDvXxckJEpA5F0Cyvfsg6mKNDbuGzCMKZAyqDHQkfJhu4Z+rE8c0VTFDZCwtpCSjWaypNkMXC+jz/ASfthuSCv/Zyhtzxase4rO8HtV4FBaVVch2le4dkzZhqtQHXMf57i5IMHk0siOWqK3OOTbqM/RhxRs0rmmYto/KgLrRHtOGeKtIK2AhIyc2g//HmEbTNeVg8kEG+RHVhZQsiH1QngWht/BivIhc8tQkZedDJ176STKzgHomoYd6ts7bF8BxYrsTXQo4qQoYnk8D4CLDKxs7sLWguQLXbpokifaLNSZkHL83p1d7ZbxnC1Wxba/tJaVuwm47WaTPhrKrzbDtNPaVUTG/8W0kRruFN1B+7LSOY471MohdOS0dDIh9C4Il7p/ZoXAFh0you06ySJAp27WmP9L8UfnM2lyF/MNLz735YNkXdntpT3OIid+2qewLSRMu06jCIGFPdC2OKRvt6mzwAcI2Drs= X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: /za8aDuLrQFJec5AjrjrMuMFo0+ciiAphE978fwDtLHm34nCis+cm+V3sbYequkZrfys+9/filTOw1GvEtfb08o5BZ7GqWCVFF043KwzIu4WZahFbhSCaL4XBp1tAGSzM2hFT6vtd/hfAX0b6QEeJZfokDOt9aTgGGpMU+KlRW2X/hk5McZMKkVjIFQLsSEVt0r3K4sej5ooQ1LT0KSEjqJTApLdqEqSQdxMhqLAjCHJf/1XolZkcFolMNURddk754iSQB7w/PPygUqgDJ+kUBxQl2Ve4tkpxKu0pjuVF/tZPLqAgA7FJnuQWJ1tv4jvzz4LadelFrR5lzNcfdngR4j39uFaj/T/+Rqt/j4/TtbsH36s0FkvAkEWzPnTS/jz0IS3FzGOKOaz1g7DPHIfNexRavsirE23t8uAq1pSZD981aWFAiXPrlrjbq+QgVf6upZV+VT6OxNHx8K3N6Hi9KhPg1nc5M1lzVYeIGskuuaMd7mZeGoBXV4R3940BWHDEkbkYdlVgML8i88H+b1rT5DzbpOh5awk0G+kYDlSjMG3I4Y+ltvoEG3CVmXdv68Fdelr/mIIik83rFOnCDQ4RSYWJSsoXy28KZIT/ciC5X8n2Vxkch3wf6FDjcYu+RVZVUK3h0gJ7tZeXTOdhTqxs93oWMNsjzz0LnYLaMHdSQcKCJ+DB0MZLLsEeOppe0enG4+N7U+tBlhpwyDW6N69HHBWnCYU/MKAopwIVfDt5QyBzSSUOSzfBbC4c05JOb3D8SBaZUI1dJ9tfAR+xh0WzKhDhaxFwUoq2SPHCMLzvBgJhdN2Ty97wDfVTeZcZ6zUHjwml3IpTMZTtVnudMwxJfdFbIQFMzQFDw3bO12HObkOjhrE+O0FAV7qHSTFeWzUUSrz1UjHtjg4G7RfNrfEAVqi1xdxquGUJHsPh4Fdg97R44cjC28Wcs++6QQ2jBrXVFu9lalWEHTa7410e4c6UIOSVuzKeFSQqz3gbKrfhMp8KBRkhsRr8ehuRby+QjUFqpQnR1iFrfJJd8l6+vw5dSRetWctb0G3k8JKL58d6MiDQh8G71kygLGzF8aDoLHDiWurxuGxdaqF/YGR/effGzLFXnHRXpUB7r3ZOvXT8UCQ5DwOxsATjBCcBqe7WXrJEYGUakypxvCUg5wkkp+AqPKXa69/DsrUG5qEVPwHYbPHiqTZqAh6z6QiXocm23B0cSeaAn+ttL4l9SHrXNBYAaQV2JxXCcA4/p3GzpJKhBpnswn0H5J3/P0KDWXreIUI3dD2+7o0TGH6UzvUNffTb/5y9I/C3PdJ/vgav+ovYYFaiJO0uyyVREQoEjdb8R2WqExBZQ7y5K/z4EL1w0pWD8AFKxV/cgn40lCoXHDS1hc9BuMEQYZMNsqzLn3vZZYHx5plGR8MN20av+WTAJsB1w== X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 8a2ac544-34e2-4d38-937c-08def2d8aed1 X-MS-Exchange-CrossTenant-AuthSource: LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 05 Aug 2026 10:02:39.6767 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO8P265MB7547 X-Spam-Status: No, score=-9.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, LIKELY_SPAM_BODY, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS, SPF_PASS, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 From: Luis Silva Introduce RTL patterns for multiply-add fusion. On RV32 the expanders emit madd_fused (mul+add). On RV64 they emit madd_fused_extended (mulw+addw). Also cheapen zero_extract / sign_extract in riscv_rtx_costs when RISCV_FUSE_BFEXT_SRLI / RISCV_FUSE_BFEXT_SRAI is enabled. gcc/ChangeLog: * config/riscv/riscv.cc (riscv_rtx_costs): Cheapen zero_extract / sign_extract when BFEXT_SRLI / BFEXT_SRAI is enabled. * config/riscv/riscv.md (maddhisi4): Emit madd_fused / madd_fused_extended when RISCV_FUSE_MULT_ADD and not TARGET_XTHEADMAC. (umaddhisi4): New expand. On TARGET_64BIT, zero-extend HI operands to DI and pass SI lowparts to madd_fused_extended. (madd_fused): New insn_and_split. (madd_fused_extended): New insn_and_split. gcc/testsuite/ChangeLog: * gcc.target/riscv/fusion-bfext-2.c: New test. * gcc.target/riscv/fusion-limm-condbr.c: New test. * gcc.target/riscv/fusion-madd.c: New test. Co-authored-by: Artemiy Volkov Co-authored-by: Michiel Derhaeg Signed-off-by: Luis Silva --- gcc/config/riscv/riscv.cc | 15 ++- gcc/config/riscv/riscv.md | 122 +++++++++++++++++- .../gcc.target/riscv/fusion-bfext-2.c | 14 ++ .../gcc.target/riscv/fusion-limm-condbr.c | 12 ++ gcc/testsuite/gcc.target/riscv/fusion-madd.c | 13 ++ 5 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-bfext-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-limm-condbr.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-madd.c diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index dd80da2d55a..4a23c734bdf 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -4712,11 +4712,22 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); return true; } + if (riscv_fusion_enabled_p (RISCV_FUSE_BFEXT_SRLI) + && outer_code == SET + && CONST_INT_P (XEXP (x, 1)) + && CONST_INT_P (XEXP (x, 2))) + { + *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); + return true; + } gcc_fallthrough (); case SIGN_EXTRACT: - if (TARGET_XTHEADBB && outer_code == SET + if (outer_code == SET && CONST_INT_P (XEXP (x, 1)) - && CONST_INT_P (XEXP (x, 2))) + && CONST_INT_P (XEXP (x, 2)) + && ((GET_CODE (x) == SIGN_EXTRACT + && riscv_fusion_enabled_p (RISCV_FUSE_BFEXT_SRAI)) + || TARGET_XTHEADBB)) { *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); return true; diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 6f66f983d87..71d2ce09899 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -4792,8 +4792,69 @@ (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand")) (sign_extend:SI (match_operand:HI 2 "register_operand"))) (match_operand:SI 3 "register_operand")))] - "TARGET_XTHEADMAC" -) + "TARGET_XTHEADMAC || (riscv_fusion_enabled_p (RISCV_FUSE_MULT_ADD) + && (TARGET_ZMMUL || TARGET_MUL))" +{ + if (riscv_fusion_enabled_p (RISCV_FUSE_MULT_ADD) + && !TARGET_XTHEADMAC) + { + rtx tmp0 = gen_reg_rtx (SImode), tmp1 = gen_reg_rtx (SImode); + emit_insn (gen_extendhisi2 (tmp0, operands[1])); + emit_insn (gen_extendhisi2 (tmp1, operands[2])); + + if (TARGET_64BIT) + { + rtx op0 = gen_reg_rtx (DImode); + emit_insn (gen_madd_fused_extended (op0, tmp0, tmp1, operands[3])); + op0 = gen_lowpart (SImode, op0); + SUBREG_PROMOTED_VAR_P (op0) = 1; + SUBREG_PROMOTED_SET (op0, SRP_SIGNED); + emit_move_insn (operands[0], op0); + } + else + { + emit_insn (gen_madd_fused (operands[0], tmp0, tmp1, operands[3])); + } + + DONE; + } +}) + +(define_expand "umaddhisi4" + [(set (match_operand:SI 0 "register_operand") + (plus:SI + (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand")) + (zero_extend:SI (match_operand:HI 2 "register_operand"))) + (match_operand:SI 3 "register_operand")))] + "riscv_fusion_enabled_p (RISCV_FUSE_MULT_ADD) + && (TARGET_ZMMUL || TARGET_MUL)" +{ + if (TARGET_64BIT) + { + rtx tmp0 = gen_reg_rtx (DImode), tmp1 = gen_reg_rtx (DImode); + emit_insn (gen_zero_extendhidi2 (tmp0, operands[1])); + emit_insn (gen_zero_extendhidi2 (tmp1, operands[2])); + + rtx op0 = gen_reg_rtx (DImode); + emit_insn (gen_madd_fused_extended (op0, + gen_lowpart (SImode, tmp0), + gen_lowpart (SImode, tmp1), + operands[3])); + op0 = gen_lowpart (SImode, op0); + SUBREG_PROMOTED_VAR_P (op0) = 1; + SUBREG_PROMOTED_SET (op0, SRP_SIGNED); + emit_move_insn (operands[0], op0); + } + else + { + rtx tmp0 = gen_reg_rtx (SImode), tmp1 = gen_reg_rtx (SImode); + emit_insn (gen_zero_extendhisi2 (tmp0, operands[1])); + emit_insn (gen_zero_extendhisi2 (tmp1, operands[2])); + emit_insn (gen_madd_fused (operands[0], tmp0, tmp1, operands[3])); + } + + DONE; +}) (define_expand "msubhisi4" [(set (match_operand:SI 0 "register_operand") @@ -4804,6 +4865,63 @@ "TARGET_XTHEADMAC" ) +(define_insn_and_split "madd_fused" + [(set (match_operand:SI 0 "register_operand" "=&r") + (plus:SI + (mult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")) + (match_operand:SI 3 "register_operand" "r")))] + "riscv_fusion_enabled_p (RISCV_FUSE_MULT_ADD) + && !TARGET_XTHEADMAC + && !TARGET_64BIT && (TARGET_ZMMUL || TARGET_MUL)" + "#" + "&& 1" + [(const_int 0)] + "{ + rtx addend = operands[3]; + if (can_create_pseudo_p () + && reg_overlap_mentioned_p (operands[0], operands[3])) + { + addend = gen_reg_rtx (SImode); + emit_move_insn (addend, operands[3]); + } + + emit_insn (gen_mulsi3 (operands[0], operands[1], operands[2])); + emit_insn (gen_addsi3 (operands[0], operands[0], addend)); + DONE; + }" + [(set_attr "type" "imul")]) + +(define_insn_and_split "madd_fused_extended" + [(set (match_operand:DI 0 "register_operand" "=&r") + (sign_extend:DI + (plus:SI + (mult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")) + (match_operand:SI 3 "register_operand" "r"))))] + "riscv_fusion_enabled_p (RISCV_FUSE_MULT_ADD) + && !TARGET_XTHEADMAC + && TARGET_64BIT && (TARGET_ZMMUL || TARGET_MUL)" + "#" + "&& 1" + [(const_int 0)] + "{ + rtx addend = operands[3]; + if (can_create_pseudo_p () + && reg_overlap_mentioned_p (operands[0], operands[3])) + { + addend = gen_reg_rtx (SImode); + emit_move_insn (addend, operands[3]); + } + + emit_insn (gen_mulsi3_extended (operands[0], operands[1], operands[2])); + emit_insn (gen_addsi3_extended (operands[0], + gen_lowpart (SImode, operands[0]), + addend)); + DONE; + }" + [(set_attr "type" "imul")]) + ;; String compare with length insn. ;; Argument 0 is the target (result) ;; Argument 1 is the source1 diff --git a/gcc/testsuite/gcc.target/riscv/fusion-bfext-2.c b/gcc/testsuite/gcc.target/riscv/fusion-bfext-2.c new file mode 100644 index 00000000000..b471c20ae57 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-bfext-2.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target rv32 } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-Oz" "-Os" } } */ +/* { dg-options "-mtune=arc-v-rhx-100-series -march=rv32im_zbs -mabi=ilp32" } */ + +#define bit_extract(x,start,amt) (((x)>>(start)) & (~(0xffffffff << (amt)))) + +int +f (int x) +{ + return bit_extract(x,10,14) + bit_extract(x,1,1); +} + +/* { dg-final { scan-assembler {\sslli\s([ast][0-9]+),a0,8\n\ssrli\s([ast][0-9]+),\1,18\n\sbexti\sa0,a0,1.*\n\sadd\sa0,\2,a0.*\n} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-limm-condbr.c b/gcc/testsuite/gcc.target/riscv/fusion-limm-condbr.c new file mode 100644 index 00000000000..cc2a56a2e08 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-limm-condbr.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series" } */ + +int +f (int x) +{ + begin: + if (x <= 3) + goto begin; +} + +/* { dg-final { scan-assembler "\\sli\\sa5,3\n\\sble\\sa0,a5,.L\[0-9\]+\n" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-madd.c b/gcc/testsuite/gcc.target/riscv/fusion-madd.c new file mode 100644 index 00000000000..e58fc830e47 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-madd.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-mtune=arc-v-rhx-100-series -march=rv32im -mabi=ilp32" { target { rv32 } } } */ +/* { dg-options "-mtune=arc-v-rhx-100-series -march=rv64im -mabi=lp64" { target { rv64 } } } */ + +int +f (int x, short y, short z, short v, short w) +{ + return x + (int) y * (int) z + (int) v * (int) w; +} + +/* { dg-final { scan-assembler {\smul\s([ast][0-9]+),a1,a2\n\sadd\s\1,\1,a0\n\smul\sa0,a3,a4\n\sadd\sa0,a0,\1\n} { target rv32 } } } */ +/* { dg-final { scan-assembler {\smulw\sa2,a2,a1\n\saddw\sa2,a2,a0\n\smulw\sa0,a4,a3\n\saddw\sa0,a0,a2\n} { target rv64 } } } */